Merge changes I8533887c,I5b6dc7a6 into msm-3.4
* changes:
msm_rmnet: add ioctl to enable/disable flow on prio qdisc
net: sched: export an api to enable/disable flow on sch
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 6db1150..82e76fc 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -14,6 +14,16 @@
- qcom,mdss-pan-bpp: Specifies the panel bits per pixel. Default value is 24(rgb888).
18 = for rgb666
16 = for rgb565
+- qcom,panel-phy-regulatorSettings: An array of length 8 that specifies the PHY
+ regulator settings for the panel.
+- qcom,panel-phy-timingSettings: An array of length 12 that specifies the PHY
+ timing settings for the panel.
+- qcom,panel-phy-strengthCtrl: An array of length 2 that specifies the PHY
+ strengthCtrl settings for the panel.
+- qcom,panel-phy-bistCtrl: An array of length 6 that specifies the PHY
+ BIST ctrl settings for the panel.
+- qcom,panel-phy-laneConfig: An array of length 45 that specifies the PHY
+ lane configuration settings for the panel.
- qcom,mdss-panel-on-cmds: An array of variable length that lists the init commands
of the panel. Each command will have the format specified
as below:
@@ -42,9 +52,16 @@
Optional properties:
- label: A string used as a descriptive name of the panel
+- qcom,enable-gpio: Specifies the panel lcd/display enable gpio.
+- qcom,rst-gpio: Specifies the panel reset gpio.
- qcom,mdss-pan-porch-values: An array of size 6 that specifies the panel blanking values.
- qcom,mdss-pan-underflow-clr: Specifies the controller settings for the panel underflow clear
settings. Default value is 0xff.
+- qcom,mdss-pan-bl-ctrl: A string that specifies the implementation of backlight
+ control for this panel.
+ "bl_ctrl_pwm" = Backlight controlled by PWM gpio.
+ "bl_ctrl_wled" = Backlight controlled by WLED.
+ "bl_ctrl_dcs_cmds" = Backlight controlled by DCS commands.
- qcom,mdss-pan-bl-levels: Specifies the backlight levels supported by the panel.
Default range is 1 to 255.
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
new file mode 100644
index 0000000..478e335
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -0,0 +1,23 @@
+Qualcomm MDSS MDP
+
+MDSS is Mobile Display SubSystem which implements Linux framebuffer APIs to
+drive user interface to different panel interfaces. MDP driver is the core of
+MDSS which manage all data paths to different panel interfaces.
+
+Required properties
+- compatible : Must be "qcom,mdss_mdp"
+- reg : offset and length of the register set for the device.
+- reg-names : names to refer to register sets related to this device
+- interrupts : Interrupt associated with MDSS.
+- vdd-supply : Phandle for vdd regulator device node.
+
+Example:
+ qcom,mdss_mdp@fd900000 {
+ compatible = "qcom,mdss_mdp";
+ reg = <0xfd900000 0x22100>,
+ <0xfd924000 0x1000>;
+ reg-names = "mdp_phys", "vbif_phys";
+ interrupts = <0 72 0>;
+ vdd-supply = <&gdsc_mdss>;
+ };
+
diff --git a/Documentation/devicetree/bindings/gpio/qpnp-pin.txt b/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
index c58e073..31c3bc2 100644
--- a/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
+++ b/Documentation/devicetree/bindings/gpio/qpnp-pin.txt
@@ -94,7 +94,7 @@
QPNP_PIN_OUT_STRENGTH_MED = 2, (GPIO)
QPNP_PIN_OUT_STRENGTH_HIGH = 3, (GPIO)
- - qcom,select: select a function for the pin. Certain pins
+ - qcom,src-select: select a function for the pin. Certain pins
can be paired (shorted) with each other. Some gpio pins
can act as alternate functions.
In the context of gpio, this acts as a source select.
diff --git a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
new file mode 100644
index 0000000..a6c83d0
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
@@ -0,0 +1,128 @@
+Atmel touch controller
+
+Required properties:
+
+ - compatible : should be "atmel,mxt-ts"
+ - reg : i2c slave address of the device
+ - interrupt-parent : parent of interrupt
+ - interrupts : touch sample interrupt to indicate presense or release
+ of fingers on the panel.
+ - atmel,panel-coords : touch panel minimum x, minimum y, maximum x and
+ maximum y resolution
+ - atmel,display-coords : LCD display minimum x, minimum y, maximum x and
+ maximum y resolution
+ - vdd_ana-supply : Analog power supply needed to power device
+ - atmel,irq-gpio : irq gpio
+ - atmel,reset-gpio : reset gpio
+ - atmel,family-id : family identification of the controller
+ - atmel,variant-id : variant identification of the controller
+ - atmel,version : firmware version of the controller
+ - atmel,build i : firmware build number of the controller
+ - atmel,bootldr-id : bootloader identification of the controller
+ - atmel,fw-name : firmware name to used for flashing firmware
+
+Optional property:
+ - atmel,config : configuration parameter for the controller
+ - atmel,i2c-pull-up : specify to indicate pull up is needed
+ - vcc_i2c-supply : Power source required to pull up i2c bus
+ - atmel,dig-reg-support : specify to indicate digital regulator is
+ needed
+
+Example:
+ i2c@f9966000 {
+ cell-index = <3>;
+ compatible = "qcom,i2c-qup";
+ reg = <0xf9966000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 104 0>;
+ 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 = <48 0x0>;
+ vdd_ana-supply = <&pm8941_l18>;
+ vcc_i2c-supply = <&pm8941_lvs1>;
+ atmel,panel-coords = <0 0 479 799>;
+ atmel,display-coords = <0 0 479 799>;
+ atmel,i2c-pull-up = <1>;
+ atmel,dig-reg-support;
+ atmel,key-codes = <
+ 102 139 0 0 0 0 0 0
+ 0 158 217 0 0 0 0 0
+ 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 >;
+ atmel,irq-gpio = <&msmgpio 48 0>;
+ atmel,reset-gpio = <&msmgpio 26 0>;
+ atmel,cfg_1 {
+ atmel,family-id = <0x81>;
+ atmel,variant-id = <0x01>;
+ 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
+ ];
+ }
+
+ }
+ };
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
new file mode 100644
index 0000000..51bf9e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -0,0 +1,57 @@
+Qualcomm QPNP Leds
+
+QPNP (Qualcomm Plug N Play) LEDs driver is used for
+controlling LEDs that are part of PMIC on Qualcomm reference
+platforms. The PMIC is connected to Host processor via
+SPMI bus. This driver supports various LED modules such as
+WLED (white LED), RGB LED and flash LED. The first version of
+the driver supports WLED and other features are added in the
+next versions.
+
+Required Properties:
+- compatible : should be "qcom,leds-qpnp"
+
+Each LED module is represented as a node of "leds-qpnp". This
+node will furthur contain the type of LED supported and its
+properties.
+
+Required properties:
+- qcom,id : must be one of values supported in enum qpnp_led
+- qcom,label : type of led that will be used, ie "wled"
+- qcom,max-current : maximum current that the LED can sustain
+= qcom,name : name the led will be called by in sysfs entry
+
+WLED is primarily used as display backlight. Display subsystem uses
+LED triggers for WLED to control the brightness as needed.
+
+Optional properties for WLED:
+- qcom,num-strings: number of wled strings supported
+- qcom,ovp_val: over voltage protection threshold,
+ follows enum wled_ovp_threshold
+- qcom,boost_curr_lim: boot currnet limit, follows enum wled_current_bost_limit
+- qcom,ctrl_delay_us: delay in activation of led
+- qcom,dig_mod_gen_en: digital module generator
+- qcom,cs_out_en: current sink output enable
+- qcom,op_fdbck: selection of output as feedback for the boost
+- qcom,cp_select: high pole capacitance
+- linux,default-trigger: trigger the led from external modules such as display
+- qcom,default-state: default state of the led, should be "on" or "off"
+
+Example:
+
+ qcom,leds@d800 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xD800 0x100>;
+ linux,default-trigger = "bkl-trigger"
+ qcom,label = "wled";
+ qcom,cs-out-en;
+ qcom,op-fdbck;
+ qcom,default-state "off";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ }
diff --git a/Documentation/devicetree/bindings/media/video/msm-sensor.txt b/Documentation/devicetree/bindings/media/video/msm-sensor.txt
new file mode 100644
index 0000000..e242d51
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-sensor.txt
@@ -0,0 +1,137 @@
+* 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/platform/msm/qpnp-clkdiv.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-clkdiv.txt
new file mode 100644
index 0000000..67303eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-clkdiv.txt
@@ -0,0 +1,43 @@
+* qpnp-clkdiv
+
+clkdiv configures the clock frequency of a set of outputs on the PMIC.
+These clocks are typically wired through alternate functions on
+gpio pins.
+
+Required properties :
+ - reg : The address and size of the peripheral. Size should be 0x1000, and the
+ address may vary.
+ - qcom,cxo-freq : The frequency of the cxo clock in Hz.
+
+Optional properties :
+ - qcom,cxo-div : Integer to divide the CXO clock by when constructing the
+ output frequency. Please see the definitions in
+ include/linux/qpnp-clkdiv.h to choose the appropriate value.
+ - qcom,enable : 0 == disable clock output
+ 1 == enable clock output.
+
+Note: if an optional property is not specified, no device configuration will
+ occur at probe time.
+
+Client required properties :
+ - <consumer name>-clk : A phandle to the corresponding divclk device. The
+ consumer name refers to the name that will be
+ passed to qpnp_clkdiv_get(), and allows for a
+ client specific name to be associated with each
+ divclk.
+
+Clkdiv device example :
+
+...
+ pm8941_clkdiv1: clkdiv@5b00 {
+ reg = <0x5b00 0x1000>;
+ qcom,cxo-freq = <19200000>;
+ qcom,cxo-div = <1>;
+ qcom,enable = <1>;
+ };
+
+Client device example :
+...
+ client {
+ my-clk = &pm8941_clkdiv1;
+ };
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 2e7f9c3..46b39ec 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -2,38 +2,93 @@
The qpnp-power-on is a driver which supports the power-on(PON)
peripheral on Qualcomm PMICs. The supported functionality includes
-power on/off reason, power-key press/release detection and other PON
-features. This peripheral is connected to the host processor via the SPMI
-interface.
+power on/off reason, key press/release detection, PMIC reset configurations
+and other PON specifc features. The PON module supports multiple physical
+power-on (KPDPWR_N, CBLPWR) and reset (KPDPWR_N, RESIN, KPDPWR+RESIN) sources.
+This peripheral is connected to the host processor via the SPMI interface.
Required properties:
- compatible: Must be "qcom,qpnp-power-on"
- reg: Specifies the SPMI address and size for this PON (power-on) peripheral
-- interrupts: Specifies the interrupt associated with the power-key.
+- interrupts: Specifies the interrupt associated with PON.
Optional properties:
-- qcom,pon-key-enable: Enable power-key detection. It enables monitoring
- of the KPDPWR_N line (connected to the power-key).
-- qcom,pon-key-dbc-delay: The debouce delay for the power-key interrupt
+- qcom,pon-dbc-delay: The debouce delay for the power-key interrupt
specifed in us. The value ranges from 2 seconds
to 1/64 of a second. Possible values are -
- 2, 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64
- Intermediate value is rounded down to the
nearest valid value.
-- qcom,pon-key-pull-up: The intial state of the KPDPWR_N pin
- (connected to the power-key)
+- qcom,pon_1 ...pon_n These represent the child nodes which describe
+ the properties (reset, key) for each of the pon
+ reset source. All the child nodes are optional,
+ if none of them are specified the driver fails
+ to register.
+
+All the below properties are in the sub-node section (properties of the child
+node).
+
+- qcom,pull-up: The initial state of the reset pin under
+ consideration.
0 = No pull-up
1 = pull-up enabled
-
-If any of the above optional property is not defined, the driver will continue
-with the default hardware state.
+ This property is optional and is set to '0'
+ if not specified.
+- qcom,pon-type The type of PON/RESET source. The driver
+ currently supports KPDPWR(0) and RESIN(1)
+ pon/reset sources. This property must be
+ specified.
+- qcom,support-reset Indicates if this PON source supports
+ reset functionality.
+ 0 = Not supported
+ 1 = Supported
+ This property is optional and is set to '0'
+ if not specified.
+- qcom,s1-timer The debouce timer for the BARK interrupt for
+ that reset source. Value is specified in ms.
+ Supported values are -
+ - 0, 32, 56, 80, 128, 184, 272, 408, 608, 904
+ 1352, 2048, 3072, 4480, 6720, 10256
+ This property must be specified only if
+ 'support-reset' is set to 1.
+- qcom,s2-timer The debouce timer for the S2 reset specified
+ in ms. On the expiry of this timer, the PMIC
+ executes the reset sequence. Supoprted values -
+ - 0, 10, 50, 100, 250, 500, 1000, 2000
+ This property is required only if
+ 'support-reset' is set to 1.
+- qcom,s2-type The type of reset associated with this source.
+ The supported resets are -
+ SOFT(0), WARM(1), SHUTDOWN(4), HARD(7)
+ This property is required only if
+ 'support-reset' is set to 1.
+- linux,code The input key-code associated with the reset source.
+ The reset source in its default configuration can be
+ used to support standard keys. This property is optional.
Example:
qcom,power-on@800 {
compatible = "qcom,qpnp-power-on";
reg = <0x800 0x100>;
- interrupts = <0x0 0x8 0x1>;
- qcom,pon-key-enable= <true>;
- qcom,pon-key-pull-up = <true>;
- qcom,pon-key-dbc-delay = <15625>;
+ interrupts = <0x0 0x8 0x0>,
+ <0x0 0x8 0x1>,
+ <0x0 0x8 0x4>;
+ interrupt-names = "kpdpwr", "resin", "resin-bark";
+ qcom,pon-dbc-delay = <15625>;
+
+ qcom,pon_1 {
+ qcom,pon-type = <0>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+
+ qcom,pon_2 {
+ qcom,pon-type = <1>;
+ qcom,support-reset = <1>;
+ qcom,pull-up = <1>;
+ qcom,s1-timer = <3072>;
+ qcom,s2-timer = <2000>;
+ qcom,s2-type = <1>;
+ linux,code = <114>;
+ };
}
diff --git a/Documentation/devicetree/bindings/qdsp/adsp-loader.txt b/Documentation/devicetree/bindings/qdsp/adsp-loader.txt
new file mode 100644
index 0000000..74e58dc
--- /dev/null
+++ b/Documentation/devicetree/bindings/qdsp/adsp-loader.txt
@@ -0,0 +1,10 @@
+* MSM Application DSP loader binding
+
+Required properties:
+- compatible : "qcom,adsp-loader"
+
+Example:
+
+ qcom,msm-adsp-loader {
+ compatible = "qcom,adsp-loader";
+ };
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 84f0c24..f082a0f 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -30,6 +30,12 @@
- compatible : "qcom,msm-voip-dsp"
+* msm-pcm-voice
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-voice"
+
* msm-stub-codec
Required properties:
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 8a4b833..62258ca 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -57,11 +57,19 @@
Required properties:
- compatible: should be "qcom,usb-bam-msm"
-- regs: offset and length of the register set in the memory map
-- interrupts: IRQ line
+- reg : pairs of physical base addresses and region sizes
+ of all the memory mapped BAM devices present
+- reg-names : Register region name(s) referenced in reg above
+ SSUSB BAM expects "ssusb" and "hsusb" for HSSUB BAM.
+ Specify "qscratch_ram1_reg" to provide QSCRATCH's RAM1
+ register to control USB3 private memory for uses as BAM FIFOs.
+- interrupts: IRQ lines for BAM devices
+- interrupt-names: BAM interrupt name(s) referenced in interrupts above
+ SSUSB BAM expects "ssusb" and "hsusb" for HSSUB BAM
- qcom,usb-active-bam: active BAM type. Can be one of
- 0 - HSUSB_BAM
- 1 - HSIC_BAM
+ 0 - SSUSB_BAM
+ 1 - HSUSB_BAM
+ 2 - HSIC_BAM
- qcom,usb-total-bam-num: total number of BAMs that are supported
- qcom,usb-bam-num-pipes: max number of pipes that can be used
- qcom,usb-base-address: physical base address of the BAM
@@ -69,10 +77,15 @@
A number of USB BAM pipe parameters are represented as sub-nodes:
Subnode Required:
-- label: a string describing the pipe's direction and use
+- label: a string describing the pipe's direction and BAM instance under use
- qcom,usb-bam-type: BAM type. Can be one of
- 0 - HSUSB_BAM
- 1 - HSIC_BAM
+ 0 - SSUSB_BAM
+ 1 - HSUSB_BAM
+ 2 - HSIC_BAM
+- qcom,usb-bam-mem-type: Type of memory used by this PIPE. Can be one of
+ 0 - Uses SPS's dedicated pipe memory
+ 1 - USB's private memory residing @ 'qcom,usb-base-address'
+ 2 - System RAM allocated by driver
- qcom,src-bam-physical-address: source BAM physical address
- qcom,src-bam-pipe-index: source BAM pipe index
- qcom,dst-bam-physical-address: destination BAM physical address
@@ -86,16 +99,21 @@
qcom,usbbam@f9304000 {
compatible = "qcom,usb-bam-msm";
- reg = <0xf9304000 0x9000>;
- interrupts = <0 132 0>;
+ reg = <0xf9304000 0x5000>,
+ <0xf9a44000 0x11000>,
+ <0xf92f880c 0x4>;
+ reg-names = "ssusb", "hsusb", "qscratch_ram1_reg";
+ interrupts = <0 132 0 0 135 0>;
+ interrupt-names = "ssusb", "hsusb";
qcom,usb-active-bam = <0>;
- qcom,usb-total-bam-num = <1>;
+ qcom,usb-total-bam-num = <2>;
qcom,usb-bam-num-pipes = <16>;
qcom,usb-base-address = <0xf9200000>;
qcom,pipe1 {
label = "usb-to-peri-qdss-dwc3";
qcom,usb-bam-type = <0>;
+ qcom,usb-bam-mem-type = <1>;
qcom,src-bam-physical-address = <0>;
qcom,src-bam-pipe-index = <0>;
qcom,dst-bam-physical-address = <0>;
@@ -109,6 +127,7 @@
qcom,pipe2 {
label = "peri-to-usb-qdss-dwc3";
qcom,usb-bam-type = <0>;
+ qcom,usb-bam-mem-type = <1>;
qcom,src-bam-physical-address = <0xfc37C000>;
qcom,src-bam-pipe-index = <0>;
qcom,dst-bam-physical-address = <0xf9304000>;
@@ -118,4 +137,32 @@
qcom,descriptor-fifo-offset = <0xf4000>;
qcom,descriptor-fifo-size = <0x1400>;
};
+
+ qcom,pipe3 {
+ label = "usb-to-peri-qdss-hsusb";
+ qcom,usb-bam-type = <1>;
+ qcom,usb-bam-mem-type = <1>;
+ qcom,src-bam-physical-address = <0>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-physical-address = <0>;
+ qcom,dst-bam-pipe-index = <0>;
+ qcom,data-fifo-offset = <0>;
+ qcom,data-fifo-size = <0>;
+ qcom,descriptor-fifo-offset = <0>;
+ qcom,descriptor-fifo-size = <0>;
+ };
+
+ qcom,pipe4 {
+ label = "peri-to-usb-qdss-hsusb";
+ qcom,usb-bam-type = <1>;
+ qcom,usb-bam-mem-type = <1>;
+ qcom,src-bam-physical-address = <0xfc37c000>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-physical-address = <0xf9a44000>;
+ qcom,dst-bam-pipe-index = <2>;
+ qcom,data-fifo-offset = <0xf4000>;
+ qcom,data-fifo-size = <0x1000>;
+ qcom,descriptor-fifo-offset = <0xf5000>;
+ qcom,descriptor-fifo-size = <0x400>;
+ };
};
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 7930de5..d249f21 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -4,7 +4,7 @@
select HAVE_AOUT
select HAVE_DMA_API_DEBUG
select HAVE_IDE if PCI || ISA || PCMCIA
- select HAVE_DMA_CONTIGUOUS if (CPU_V6 || CPU_V6K || CPU_V7)
+ select HAVE_DMA_ATTRS
select HAVE_MEMBLOCK
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
@@ -46,6 +46,14 @@
config ARM_HAS_SG_CHAIN
bool
+config NEED_SG_DMA_LENGTH
+ bool
+
+config ARM_DMA_USE_IOMMU
+ select NEED_SG_DMA_LENGTH
+ select ARM_HAS_SG_CHAIN
+ bool
+
config HAVE_PWM
bool
diff --git a/arch/arm/boot/dts/msm-iommu.dtsi b/arch/arm/boot/dts/msm-iommu.dtsi
index 0e2ddce9..e907de8 100755
--- a/arch/arm/boot/dts/msm-iommu.dtsi
+++ b/arch/arm/boot/dts/msm-iommu.dtsi
@@ -23,7 +23,7 @@
qcom,iommu-ctx@fda6c000 {
reg = <0xfda6c000 0x1000>;
- interrupts = <0 69 0>;
+ interrupts = <0 70 0>;
qcom,iommu-ctx-sids = <0>;
label = "jpeg_enc0";
};
@@ -37,7 +37,7 @@
qcom,iommu-ctx@fda6e000 {
reg = <0xfda6e000 0x1000>;
- interrupts = <0 71 0>;
+ interrupts = <0 70 0>;
qcom,iommu-ctx-sids = <2>;
label = "jpeg_dec";
};
@@ -55,7 +55,7 @@
qcom,iommu-ctx@fd930000 {
reg = <0xfd930000 0x1000>;
- interrupts = <0 46 0>;
+ interrupts = <0 47 0>;
qcom,iommu-ctx-sids = <0>;
label = "mdp_0";
};
@@ -81,7 +81,7 @@
qcom,iommu-ctx@fdc8c000 {
reg = <0xfdc8c000 0x1000>;
- interrupts = <0 43 0>;
+ interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0 1 2 3 4 5>;
label = "venus_ns";
};
@@ -95,7 +95,7 @@
qcom,iommu-ctx@fdc8e000 {
reg = <0xfdc8e000 0x1000>;
- interrupts = <0 41 0>;
+ interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0xc0 0xc6>;
label = "venus_fw";
};
@@ -114,7 +114,7 @@
qcom,iommu-ctx@fdb18000 {
reg = <0xfdb18000 0x1000>;
- interrupts = <0 240 0>;
+ interrupts = <0 241 0>;
qcom,iommu-ctx-sids = <0>;
label = "gfx3d_user";
};
@@ -139,7 +139,7 @@
qcom,iommu-ctx@fda4c000 {
reg = <0xfda4c000 0x1000>;
- interrupts = <0 64 0>;
+ interrupts = <0 65 0>;
qcom,iommu-ctx-sids = <0>;
label = "vfe0";
};
@@ -153,7 +153,7 @@
qcom,iommu-ctx@fda4e000 {
reg = <0xfda4e000 0x1000>;
- interrupts = <0 66 0>;
+ interrupts = <0 65 0>;
qcom,iommu-ctx-sids = <2>;
label = "cpp";
};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index ee0a264..030d0e3 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -25,11 +25,45 @@
qcom,power-on@800 {
compatible = "qcom,qpnp-power-on";
reg = <0x800 0x100>;
- interrupts = <0x0 0x8 0x0>;
- interrupt-names = "power-key";
- qcom,pon-key-enable = <1>;
- qcom,pon-key-dbc-delay = <15625>;
- qcom,pon-key-pull-up = <1>;
+ interrupts = <0x0 0x8 0x0>,
+ <0x0 0x8 0x1>,
+ <0x0 0x8 0x4>;
+ interrupt-names = "kpdpwr", "resin", "resin-bark";
+ qcom,pon-dbc-delay = <15625>;
+
+ qcom,pon_1 {
+ qcom,pon-type = <0>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+
+ qcom,pon_2 {
+ qcom,pon-type = <1>;
+ qcom,support-reset = <1>;
+ qcom,pull-up = <1>;
+ qcom,s1-timer = <0>;
+ qcom,s2-timer = <2000>;
+ qcom,s2-type = <1>;
+ linux,code = <114>;
+ };
+ };
+
+ clkdiv@5b00 {
+ reg = <0x5b00 0x100>;
+ compatible = "qcom,qpnp-clkdiv";
+ qcom,cxo-freq = <19200000>;
+ };
+
+ clkdiv@5c00 {
+ reg = <0x5c00 0x100>;
+ compatible = "qcom,qpnp-clkdiv";
+ qcom,cxo-freq = <19200000>;
+ };
+
+ clkdiv@5d00 {
+ reg = <0x5d00 0x1000>;
+ compatible = "qcom,qpnp-clkdiv";
+ qcom,cxo-freq = <19200000>;
};
pm8941_gpios {
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-cdp.dts
index bfe24d2..8ae9583 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -23,3 +23,15 @@
status = "ok";
};
};
+
+&sdcc2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdcc2>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &msmgpio 62 0x3>;
+ interrupt-names = "core_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+};
diff --git a/arch/arm/boot/dts/msm8974-clock.dtsi b/arch/arm/boot/dts/msm8974-clock.dtsi
new file mode 100644
index 0000000..bdc5d9b
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-clock.dtsi
@@ -0,0 +1,26 @@
+/* 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.
+ */
+
+&spmi_bus {
+
+ qcom,pm8941@0 {
+
+ pm8941_clkdiv1: clkdiv@5b00 {
+ };
+
+ pm8941_clkdiv2: clkdiv@5c00 {
+ };
+
+ pm8941_clkdiv3: clkdiv@5d00 {
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
index 323fac4..b36859e 100644
--- a/arch/arm/boot/dts/msm8974-gpio.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpio.dtsi
@@ -25,14 +25,26 @@
};
gpio@c200 {
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
status = "ok";
};
gpio@c300 {
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
status = "ok";
};
gpio@c400 {
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
status = "ok";
};
@@ -193,6 +205,12 @@
mpp@a400 {
status = "ok";
+ /* SPI_ETH config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
};
mpp@a500 {
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
new file mode 100644
index 0000000..de9173c7
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -0,0 +1,34 @@
+/* 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.
+ */
+
+/ {
+ qcom,mdss_mdp@fd900000 {
+ compatible = "qcom,mdss_mdp";
+ reg = <0xfd900000 0x22100>,
+ <0xfd924000 0x1000>;
+ reg-names = "mdp_phys", "vbif_phys";
+ interrupts = <0 72 0>;
+ vdd-supply = <&gdsc_mdss>;
+ };
+
+ mdss_dsi: qcom,mdss_dsi@fd922800 {
+ compatible = "qcom,msm-mdss-dsi";
+ reg = <0xfd922800 0x5ac>,
+ <0xfd8c2000 0x01000>;
+ };
+
+ qcom,mdss_wb_panel {
+ compatible = "qcom,mdss_wb";
+ qcom,mdss_pan_res = <640 480>;
+ qcom,mdss_pan_bpp = <24>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index eb269eb..1fd96f9 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -10,38 +10,13 @@
* GNU General Public License for more details.
*/
+
+/* QPNP controlled regulators: */
+
&spmi_bus {
+
qcom,pm8941@1 {
- pm8941_s1: regulator@1400 {
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- qcom,enable-time = <500>;
- qcom,pull-down-enable = <1>;
- regulator-always-on;
- status = "okay";
- };
-
- regulator@1700 {
- regulator-min-microvolt = <2150000>;
- regulator-max-microvolt = <2150000>;
- qcom,enable-time = <500>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- regulator-name = "8941_s2_local";
- regulator-always-on;
- qcom,system-load = <100000>;
- };
-
- pm8941_s3: regulator@1a00 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,enable-time = <500>;
- qcom,pull-down-enable = <1>;
- regulator-always-on;
- status = "okay";
- };
-
pm8941_boost: regulator@a000 {
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
@@ -49,216 +24,6 @@
status = "okay";
};
- pm8941_l1: regulator@4000 {
- parent-supply = <&pm8941_s1>;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- regulator-always-on;
- status = "okay";
- };
-
- pm8941_l2: regulator@4100 {
- parent-supply = <&pm8941_s3>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l3: regulator@4200 {
- parent-supply = <&pm8941_s1>;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l4: regulator@4300 {
- parent-supply = <&pm8941_s1>;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l6: regulator@4500 {
- parent-supply = <&pm8941_s2>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l8: regulator@4700 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l9: regulator@4800 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l10: regulator@4900 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l11: regulator@4a00 {
- parent-supply = <&pm8941_s1>;
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- regulator@4b00 {
- parent-supply = <&pm8941_s2>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- regulator-name = "8941_l12_local";
- regulator-always-on;
- qcom,system-load = <100000>;
- };
-
- pm8941_l13: regulator@4c00 {
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l14: regulator@4d00 {
- parent-supply = <&pm8941_s2>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l15: regulator@4e00 {
- parent-supply = <&pm8941_s2>;
- regulator-min-microvolt = <2050000>;
- regulator-max-microvolt = <2050000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l16: regulator@4f00 {
- regulator-min-microvolt = <2700000>;
- regulator-max-microvolt = <2700000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l17: regulator@5000 {
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l18: regulator@5100 {
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l19: regulator@5200 {
- regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <2900000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l20: regulator@5300 {
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l21: regulator@5400 {
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l22: regulator@5500 {
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l23: regulator@5600 {
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_l24: regulator@5700 {
- regulator-min-microvolt = <3075000>;
- regulator-max-microvolt = <3075000>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_lvs1: regulator@8000 {
- parent-supply = <&pm8941_s3>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_lvs2: regulator@8100 {
- parent-supply = <&pm8941_s3>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
- pm8941_lvs3: regulator@8200 {
- parent-supply = <&pm8941_s3>;
- qcom,enable-time = <200>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
-
pm8941_mvs1: regulator@8300 {
parent-supply = <&pm8941_boost>;
qcom,enable-time = <200>;
@@ -273,48 +38,6 @@
status = "okay";
};
};
-
- qcom,pm8841@5 {
-
- regulator@1400 {
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- qcom,enable-time = <500>;
- qcom,pull-down-enable = <1>;
- regulator-always-on;
- status = "okay";
- regulator-name = "8841_s1_local";
- qcom,system-load = <100000>;
- };
-
- regulator@1700 {
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- qcom,enable-time = <500>;
- qcom,pull-down-enable = <1>;
- regulator-always-on;
- regulator-name = "8841_s2_local";
- qcom,system-load = <100000>;
- status = "okay";
- };
-
- pm8841_s3: regulator@1a00 {
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- qcom,enable-time = <500>;
- qcom,pull-down-enable = <1>;
- regulator-always-on;
- status = "okay";
- };
-
- pm8841_s4: regulator@1d00 {
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <900000>;
- qcom,enable-time = <500>;
- qcom,pull-down-enable = <1>;
- status = "okay";
- };
- };
};
/* RPM controlled regulators: */
@@ -364,6 +87,39 @@
};
};
+ rpm-regulator-smpb3 {
+ status = "okay";
+ pm8841_s3: regulator-s3 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,init-voltage = <1050000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpb4 {
+ status = "okay";
+ pm8841_s4: regulator-s4 {
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <900000>;
+ qcom,init-voltage = <900000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa1 {
+ status = "okay";
+ pm8941_s1: regulator-s1 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,init-voltage = <1300000>;
+ qcom,init-current = <100>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ status = "okay";
+ };
+ };
+
rpm-regulator-smpa2 {
status = "okay";
qcom,allow-atomic = <1>;
@@ -383,6 +139,140 @@
};
};
+ rpm-regulator-smpa3 {
+ status = "okay";
+ pm8941_s3: regulator-s3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-current = <100>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pm8941_l1: regulator-l1 {
+ parent-supply = <&pm8941_s1>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ qcom,init-current = <10>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pm8941_l2: regulator-l2 {
+ parent-supply = <&pm8941_s3>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pm8941_l3: regulator-l3 {
+ parent-supply = <&pm8941_s1>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ status = "okay";
+ pm8941_l4: regulator-l4 {
+ parent-supply = <&pm8941_s1>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pm8941_l5: regulator-l5 {
+ parent-supply = <&pm8941_s2>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pm8941_l6: regulator-l6 {
+ parent-supply = <&pm8941_s2>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pm8941_l7: regulator-l7 {
+ parent-supply = <&pm8941_s2>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pm8941_l8: regulator-l8 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pm8941_l9: regulator-l9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pm8941_l10: regulator-l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ status = "okay";
+ pm8941_l11: regulator-l11 {
+ parent-supply = <&pm8941_s1>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,init-voltage = <1300000>;
+ status = "okay";
+ };
+ };
+
rpm-regulator-ldoa12 {
status = "okay";
qcom,allow-atomic = <1>;
@@ -402,6 +292,152 @@
compatible = "qcom,rpm-regulator-smd";
};
};
+
+ rpm-regulator-ldoa13 {
+ status = "okay";
+ pm8941_l13: regulator-l13 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ status = "okay";
+ pm8941_l14: regulator-l14 {
+ parent-supply = <&pm8941_s2>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa15 {
+ status = "okay";
+ pm8941_l15: regulator-l15 {
+ parent-supply = <&pm8941_s2>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,init-voltage = <2050000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa16 {
+ status = "okay";
+ pm8941_l16: regulator-l16 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ qcom,init-voltage = <2700000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ status = "okay";
+ pm8941_l17: regulator-l17 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <2850000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa18 {
+ status = "okay";
+ pm8941_l18: regulator-l18 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <2850000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ status = "okay";
+ pm8941_l19: regulator-l19 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ qcom,init-voltage = <2900000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa20 {
+ status = "okay";
+ pm8941_l20: regulator-l20 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa21 {
+ status = "okay";
+ pm8941_l21: regulator-l21 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa22 {
+ status = "okay";
+ pm8941_l22: regulator-l22 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <3000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa23 {
+ status = "okay";
+ pm8941_l23: regulator-l23 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <3000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa24 {
+ status = "okay";
+ pm8941_l24: regulator-l24 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ qcom,init-voltage = <3075000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-vsa1 {
+ status = "okay";
+ pm8941_lvs1: regulator-lvs1 {
+ parent-supply = <&pm8941_s3>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-vsa2 {
+ status = "okay";
+ pm8941_lvs2: regulator-lvs2 {
+ parent-supply = <&pm8941_s3>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-vsa3 {
+ status = "okay";
+ pm8941_lvs3: regulator-lvs3 {
+ parent-supply = <&pm8941_s3>;
+ status = "okay";
+ };
+ };
};
/ {
@@ -436,4 +472,11 @@
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <1100000>;
};
+
+ spi_eth_vreg: spi_eth_phy_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "ethernet_phy";
+ gpio = <&pm8941_mpps 5 0>;
+ enable-active-high;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-sim.dts b/arch/arm/boot/dts/msm8974-sim.dts
index 8cd925e..d5368fa 100644
--- a/arch/arm/boot/dts/msm8974-sim.dts
+++ b/arch/arm/boot/dts/msm8974-sim.dts
@@ -34,3 +34,65 @@
status = "ok";
};
};
+
+&jpeg_iommu {
+ qcom,iommu-ctx@fda6c000 {
+ interrupts = <0 69 0>;
+ };
+
+ qcom,iommu-ctx@fda6d000 {
+ interrupts = <0 70 0>;
+ };
+
+ qcom,iommu-ctx@fda6e000 {
+ interrupts = <0 71 0>;
+ };
+};
+
+&mdp_iommu {
+ qcom,iommu-ctx@fd930000 {
+ interrupts = <0 46 0>;
+ };
+
+ qcom,iommu-ctx@fd931000 {
+ interrupts = <0 47 0>;
+ };
+};
+
+&venus_iommu {
+ qcom,iommu-ctx@fdc8c000 {
+ interrupts = <0 43 0>;
+ };
+
+ qcom,iommu-ctx@fdc8d000 {
+ interrupts = <0 42 0>;
+ };
+
+ qcom,iommu-ctx@fdc8e000 {
+ interrupts = <0 41 0>;
+ };
+};
+
+&kgsl_iommu {
+ qcom,iommu-ctx@fdb18000 {
+ interrupts = <0 240 0>;
+ };
+
+ qcom,iommu-ctx@fdb19000 {
+ interrupts = <0 241 0>;
+ };
+};
+
+&vfe_iommu {
+ qcom,iommu-ctx@fda4c000 {
+ interrupts = <0 64 0>;
+ };
+
+ qcom,iommu-ctx@fda4d000 {
+ interrupts = <0 65 0>;
+ };
+
+ qcom,iommu-ctx@fda4e000 {
+ interrupts = <0 66 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 0b7d2c5..1be0af9 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -18,6 +18,7 @@
/include/ "msm-gdsc.dtsi"
/include/ "msm8974-ion.dtsi"
/include/ "msm8974-gpu.dtsi"
+/include/ "msm8974-mdss.dtsi"
/ {
model = "Qualcomm MSM 8974";
@@ -85,7 +86,8 @@
usb@f9a55000 {
compatible = "qcom,hsusb-otg";
reg = <0xf9a55000 0x400>;
- interrupts = <0 134 0>;
+ interrupts = <0 134 0 0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
HSUSB_VDDCX-supply = <&pm8841_s2>;
HSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_3p3-supply = <&pm8941_l24>;
@@ -96,7 +98,7 @@
qcom,hsusb-otg-disable-reset;
};
- qcom,sdcc@f9824000 {
+ sdcc1: qcom,sdcc@f9824000 {
cell-index = <1>; /* SDC1 eMMC slot */
compatible = "qcom,msm-sdcc";
reg = <0xf9824000 0x1000>;
@@ -125,7 +127,7 @@
qcom,sdcc-bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
};
- qcom,sdcc@f98a4000 {
+ sdcc2: qcom,sdcc@f98a4000 {
cell-index = <2>; /* SDC2 SD card slot */
compatible = "qcom,msm-sdcc";
reg = <0xf98a4000 0x1000>;
@@ -156,7 +158,7 @@
qcom,sdcc-current-limit = <800>;
};
- qcom,sdcc@f9864000 {
+ sdcc3: qcom,sdcc@f9864000 {
cell-index = <3>; /* SDC3 SDIO slot */
compatible = "qcom,msm-sdcc";
reg = <0xf9864000 0x1000>;
@@ -179,7 +181,7 @@
status = "disable";
};
- qcom,sdcc@f98e4000 {
+ sdcc4: qcom,sdcc@f98e4000 {
cell-index = <4>; /* SDC4 SDIO slot */
compatible = "qcom,msm-sdcc";
reg = <0xf98e4000 0x1000>;
@@ -212,13 +214,6 @@
};
- spi@f9924000 {
- compatible = "qcom,spi-qup-v2";
- reg = <0xf9924000 0x1000>;
- interrupts = <0 96 0>;
- spi-max-frequency = <25000000>;
- };
-
slim@fe12f000 {
cell-index = <1>;
compatible = "qcom,slim-msm";
@@ -288,97 +283,142 @@
interrupts = <0 190 0 0 187 0>;
qcom,pmic-arb-ee = <0>;
qcom,pmic-arb-channel = <0>;
- qcom,pmic-arb-ppid-map = <0x13000000>, /* PM8941_LDO1 */
- <0x13100001>, /* PM8941_LDO2 */
- <0x13200002>, /* PM8941_LDO3 */
- <0x13300003>, /* PM8941_LDO4 */
- <0x13400004>, /* PM8941_LDO5 */
- <0x13500005>, /* PM8941_LDO6 */
- <0x13600006>, /* PM8941_LDO7 */
- <0x13700007>, /* PM8941_LDO8 */
- <0x13800008>, /* PM8941_LDO9 */
- <0x13900009>, /* PM8941_LDO10 */
- <0x13a0000a>, /* PM8941_LDO11 */
- <0x13b0000b>, /* PM8941_LDO12 */
- <0x13c0000c>, /* PM8941_LDO13 */
- <0x13d0000d>, /* PM8941_LDO14 */
- <0x13e0000e>, /* PM8941_LDO15 */
- <0x13f0000f>, /* PM8941_LDO16 */
- <0x14000010>, /* PM8941_LDO17 */
- <0x14100011>, /* PM8941_LDO18 */
- <0x14200012>, /* PM8941_LDO19 */
- <0x14300013>, /* PM8941_LDO20 */
- <0x14400014>, /* PM8941_LDO21 */
- <0x14500015>, /* PM8941_LDO22 */
- <0x14600016>, /* PM8941_LDO23 */
- <0x14700017>, /* PM8941_LDO24 */
- <0x14800018>, /* PM8941_LDO25 */
- <0x14900019>, /* PM8941_LDO26 */
- <0x0c00001a>, /* PM8941_GPIO1 */
- <0x0c10001b>, /* PM8941_GPIO2 */
- <0x0c20001c>, /* PM8941_GPIO3 */
- <0x0c30001d>, /* PM8941_GPIO4 */
- <0x0c40001e>, /* PM8941_GPIO5 */
- <0x0c50001f>, /* PM8941_GPIO6 */
- <0x0c600020>, /* PM8941_GPIO7 */
- <0x0c700021>, /* PM8941_GPIO8 */
- <0x0c800022>, /* PM8941_GPIO9 */
- <0x0c900023>, /* PM8941_GPIO10 */
- <0x0ca00024>, /* PM8941_GPIO11 */
- <0x0cb00025>, /* PM8941_GPIO12 */
- <0x0cc00026>, /* PM8941_GPIO13 */
- <0x0cd00027>, /* PM8941_GPIO14 */
- <0x0ce00028>, /* PM8941_GPIO15 */
- <0x0cf00029>, /* PM8941_GPIO16 */
- <0x0d00002a>, /* PM8941_GPIO17 */
- <0x0d10002b>, /* PM8941_GPIO18 */
- <0x0d20002c>, /* PM8941_GPIO19 */
- <0x0d30002d>, /* PM8941_GPIO20 */
- <0x0d40002e>, /* PM8941_GPIO21 */
- <0x0d50002f>, /* PM8941_GPIO22 */
- <0x0d600030>, /* PM8941_GPIO23 */
- <0x0d700031>, /* PM8941_GPIO24 */
- <0x0d800032>, /* PM8941_GPIO25 */
- <0x0d900033>, /* PM8941_GPIO26 */
- <0x0da00034>, /* PM8941_GPIO27 */
- <0x0db00035>, /* PM8941_GPIO28 */
- <0x0dc00036>, /* PM8941_GPIO29 */
- <0x0dd00037>, /* PM8941_GPIO30 */
- <0x0de00038>, /* PM8941_GPIO31 */
- <0x0df00039>, /* PM8941_GPIO32 */
- <0x0e00003a>, /* PM8941_GPIO33 */
- <0x0e10003b>, /* PM8941_GPIO34 */
- <0x0e20003c>, /* PM8941_GPIO35 */
- <0x0e30003d>, /* PM8941_GPIO36 */
- <0x0280003e>, /* COINCELL */
- <0x0100003f>, /* SMBC_OVP */
- <0x01100040>, /* SMBC_CHG */
- <0x01200041>, /* SMBC_BIF */
- <0x00500042>, /* INTERRUPT */
- <0x00100043>, /* PM8941_0 */
- <0x20100044>, /* PM8841_0 */
- <0x10100045>, /* PM8941_1 */
- <0x30100046>, /* PM8841_1 */
- <0x00800047>, /* PON0 */
- <0x20800048>, /* PON1 */
- <0x11000049>, /* PM8941_SMPS1 */
- <0x1110004a>, /* PM8941_SMPS2 */
- <0x1120004b>, /* PM8941_SMPS3 */
- <0x3100004c>, /* PM8841_SMPS1 */
- <0x3110004d>, /* PM8841_SMPS2 */
- <0x3120004e>, /* PM8841_SMPS3 */
- <0x3130004f>, /* PM8841_SMPS4 */
- <0x31400050>, /* PM8841_SMPS5 */
- <0x31500051>, /* PM8841_SMPS6 */
- <0x31600052>, /* PM8841_SMPS7 */
- <0x31700053>, /* PM8841_SMPS8 */
- <0x05000054>, /* SHARED_XO */
- <0x05100055>, /* BB_CLK1 */
- <0x05200056>, /* BB_CLK2 */
- <0x05900057>, /* SLEEP_CLK */
- <0x07000058>, /* PBS_CORE */
- <0x07100059>, /* PBS_CLIENT1 */
- <0x0720005a>; /* PBS_CLIENT2 */
+ qcom,pmic-arb-ppid-map = <0x40400000>, /* BUS */
+ <0x40500001>, /* INT */
+ <0x40600002>, /* SPMI */
+ <0x40800003>, /* PON */
+ <0x42400004>, /* TEMP_ALARM */
+ <0x47000005>, /* PBS_CORE */
+ <0x47100006>, /* PBS_CLIENT0 */
+ <0x47200007>, /* PBS_CLIENT1 */
+ <0x47300008>, /* PBS_CLIENT2 */
+ <0x47400009>, /* PBS_CLIENT3 */
+ <0x4750000a>, /* PBS_CLIENT4 */
+ <0x4760000b>, /* PBS_CLIENT5 */
+ <0x4770000c>, /* PBS_CLIENT6 */
+ <0x4780000d>, /* PBS_CLIENT7 */
+ <0x4a00000e>, /* MPP1 */
+ <0x4a100021>, /* MPP2 */
+ <0x4a20000f>, /* MPP3 */
+ <0x4a300010>, /* MPP4 */
+ <0x51000011>, /* BCLK_GEN_MAIN */
+ <0x51d00012>, /* S4_CTRL */
+ <0x51e00013>, /* S4_PS */
+ <0x51f00014>, /* S4_FREQ */
+ <0x52000015>, /* S5_CTRL */
+ <0x52100016>, /* S5_PS */
+ <0x52200017>, /* S5_FREQ */
+ <0x52300018>, /* S6_CTRL */
+ <0x52400019>, /* S6_PS */
+ <0x5250001a>, /* S6_FREQ */
+ <0x5260001b>, /* S7_CTRL */
+ <0x5270001c>, /* S7_PS */
+ <0x5280001d>, /* S7_FREQ */
+ <0x5290001e>, /* S8_CTRL */
+ <0x52a0001f>, /* S8_PS */
+ <0x52b00020>, /* S8_FREQ */
+ <0x00400022>, /* BUS */
+ <0x00500023>, /* INT */
+ <0x00600024>, /* SPMI */
+ <0x00800025>, /* PON */
+ <0x00b00027>, /* VREG_TFT */
+ <0x01000028>, /* SMBB_CHGR */
+ <0x01100029>, /* SMBB_BUCK */
+ <0x0120002a>, /* SMBB_BAT_IF */
+ <0x0130002b>, /* SMBB_USB_CHGPTH */
+ <0x0140002c>, /* SMBB_DC_CHGPTH */
+ <0x0150002d>, /* SMBB_BOOST */
+ <0x0160002e>, /* SMBB_MISC */
+ <0x0170002f>, /* SMBB_FREQ */
+ <0x02400030>, /* TEMP_ALARM */
+ <0x02800031>, /* COIN */
+ <0x03100032>, /* VADC1_USR */
+ <0x03300033>, /* VADC1_BMS */
+ <0x03400034>, /* VADC2_BTM */
+ <0x03600035>, /* IADC1_USR */
+ <0x03800036>, /* IADC1_BMS */
+ <0x04000037>, /* BMS1 */
+ <0x05700039>, /* DIFF_CLK1 */
+ <0x05c0003b>, /* DIV_CLK2 */
+ <0x0610003d>, /* RTC_ALARM */
+ <0x0620003e>, /* RTC_TIMER */
+ <0x07100040>, /* PBS_CLIENT0 */
+ <0x07200041>, /* PBS_CLIENT1 */
+ <0x07300042>, /* PBS_CLIENT2 */
+ <0x07400043>, /* PBS_CLIENT3 */
+ <0x07500044>, /* PBS_CLIENT4 */
+ <0x07600045>, /* PBS_CLIENT5 */
+ <0x07700046>, /* PBS_CLIENT6 */
+ <0x07800047>, /* PBS_CLIENT7 */
+ <0x07900048>, /* PBS_CLIENT8 */
+ <0x07a00049>, /* PBS_CLIENT9 */
+ <0x07b0004a>, /* PBS_CLIENT10 */
+ <0x07c0004b>, /* PBS_CLIENT11 */
+ <0x07d0004c>, /* PBS_CLIENT12 */
+ <0x07e0004d>, /* PBS_CLIENT13 */
+ <0x07f0004e>, /* PBS_CLIENT14 */
+ <0x0800004f>, /* PBS_CLIENT15 */
+ <0x0a100050>, /* MPP2 */
+ <0x0a300051>, /* MPP4 */
+ <0x0a400052>, /* MPP5 */
+ <0x0a500053>, /* MPP6 */
+ <0x0a600054>, /* MPP7 */
+ <0x0a700055>, /* MPP8 */
+ <0x0c000056>, /* GPIO1 */
+ <0x0c100057>, /* GPIO2 */
+ <0x0c200058>, /* GPIO3 */
+ <0x0c300059>, /* GPIO4 */
+ <0x0c40005a>, /* GPIO5 */
+ <0x0c50005b>, /* GPIO6 */
+ <0x0c60005c>, /* GPIO7 */
+ <0x0c70005d>, /* GPIO8 */
+ <0x0c80005e>, /* GPIO9 */
+ <0x0c90005f>, /* GPIO10 */
+ <0x0ca00060>, /* GPIO11 */
+ <0x0cb00061>, /* GPIO12 */
+ <0x0cc00062>, /* GPIO13 */
+ <0x0cd00063>, /* GPIO14 */
+ <0x0ce00064>, /* GPIO15 */
+ <0x0cf00065>, /* GPIO16 */
+ <0x0d200066>, /* GPIO19 */
+ <0x0d300067>, /* GPIO20 */
+ <0x0d500068>, /* GPIO22 */
+ <0x0d600069>, /* GPIO23 */
+ <0x0d70006a>, /* GPIO24 */
+ <0x0d80006b>, /* GPIO25 */
+ <0x0d90006c>, /* GPIO26 */
+ <0x0da0006d>, /* GPIO27 */
+ <0x0dc0006e>, /* GPIO29 */
+ <0x0dd0006f>, /* GPIO30 */
+ <0x0df00070>, /* GPIO32 */
+ <0x0e000071>, /* GPIO33 */
+ <0x0e100072>, /* GPIO34 */
+ <0x0e200073>, /* GPIO35 */
+ <0x0e300074>, /* GPIO36 */
+ <0x11000075>, /* BUCK_CMN */
+ <0x1a000076>, /* BOOST */
+ <0x1a100077>, /* BOOST_FREQ */
+ <0x1a800078>, /* KEYPAD1 */
+ <0x1b000079>, /* LPG_LUT */
+ <0x1b10007a>, /* LPG_CHAN1 */
+ <0x1b20007b>, /* LPG_CHAN2 */
+ <0x1b30007c>, /* LPG_CHAN3 */
+ <0x1b40007d>, /* LPG_CHAN4 */
+ <0x1b50007e>, /* LPG_CHAN5 */
+ <0x1b60007f>, /* LPG_CHAN6 */
+ <0x1b700080>, /* LPG_CHAN7 */
+ <0x1b800081>, /* LPG_CHAN8 */
+ <0x1bc00082>, /* PWM_3D */
+ <0x1c000083>, /* VIB1 */
+ <0x1d000084>, /* TRI_LED */
+ <0x1d300085>, /* FLASH1 */
+ <0x1d800086>, /* WLED1 */
+ <0x1e200087>, /* KPDBL_MAIN */
+ <0x1e300088>, /* KPDBL_LUT */
+ <0x1e400089>, /* LPG_CHAN9 */
+ <0x1e50008a>, /* LPG_CHAN10 */
+ <0x1e60008b>, /* LPG_CHAN11 */
+ <0x1e70008c>; /* LPG_CHAN12 */
};
i2c@f9966000 {
@@ -392,6 +432,97 @@
qcom,i2c-src-freq = <24000000>;
};
+ i2c@f9924000 {
+ cell-index = <2>;
+ compatible = "qcom,i2c-qup";
+ reg = <0xf9924000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 96 0>;
+ 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 {
compatible = "qcom,acpuclk-8974";
krait0-supply = <&krait0_vreg>;
@@ -443,6 +574,10 @@
qcom,firmware-name = "adsp";
};
+ qcom,msm-adsp-loader {
+ compatible = "qcom,adsp-loader";
+ };
+
qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
};
@@ -463,6 +598,10 @@
compatible = "qcom,msm-voip-dsp";
};
+ qcom,msm-pcm-voice {
+ compatible = "qcom,msm-pcm-voice";
+ };
+
qcom,msm-stub-codec {
compatible = "qcom,msm-stub-codec";
};
@@ -611,28 +750,6 @@
compatible = "qcom,qseecom";
};
- qcom,mdss_mdp@fd900000 {
- cell-index = <0>;
- compatible = "qcom,mdss_mdp";
- reg = <0xfd900000 0x22100>;
- interrupts = <0 72 0>;
- vdd-supply = <&gdsc_mdss>;
- };
-
- mdss_dsi: qcom,mdss_dsi@fd922800 {
- cell-index = <1>;
- compatible = "qcom,msm-mdss-dsi";
- reg = <0xfd922800 0x5ac>,
- <0xfd8c0000 0x01000>;
- };
-
- qcom,mdss_wb_panel {
- cell-index = <1>;
- compatible = "qcom,mdss_wb";
- qcom,mdss_pan_res = <640 480>;
- qcom,mdss_pan_bpp = <24>;
- };
-
qcom,wdt@f9017000 {
compatible = "qcom,msm-watchdog";
reg = <0xf9017000 0x1000>;
@@ -701,16 +818,21 @@
qcom,usbbam@f9304000 {
compatible = "qcom,usb-bam-msm";
- reg = <0xf9304000 0x9000>;
- interrupts = <0 132 0>;
+ reg = <0xf9304000 0x5000>,
+ <0xf9a44000 0x11000>,
+ <0xf92f880c 0x4>;
+ reg-names = "ssusb", "hsusb", "qscratch_ram1_reg";
+ interrupts = <0 132 0 0 135 0>;
+ interrupt-names = "ssusb", "hsusb";
qcom,usb-active-bam = <0>;
- qcom,usb-total-bam-num = <1>;
+ qcom,usb-total-bam-num = <2>;
qcom,usb-bam-num-pipes = <16>;
qcom,usb-base-address = <0xf9200000>;
qcom,pipe1 {
label = "usb-to-peri-qdss-dwc3";
qcom,usb-bam-type = <0>;
+ qcom,usb-bam-mem-type = <1>;
qcom,src-bam-physical-address = <0>;
qcom,src-bam-pipe-index = <0>;
qcom,dst-bam-physical-address = <0>;
@@ -724,6 +846,7 @@
qcom,pipe2 {
label = "peri-to-usb-qdss-dwc3";
qcom,usb-bam-type = <0>;
+ qcom,usb-bam-mem-type = <1>;
qcom,src-bam-physical-address = <0xfc37C000>;
qcom,src-bam-pipe-index = <0>;
qcom,dst-bam-physical-address = <0xf9304000>;
@@ -733,6 +856,34 @@
qcom,descriptor-fifo-offset = <0xf4000>;
qcom,descriptor-fifo-size = <0x1400>;
};
+
+ qcom,pipe3 {
+ label = "usb-to-peri-qdss-hsusb";
+ qcom,usb-bam-type = <1>;
+ qcom,usb-bam-mem-type = <1>;
+ qcom,src-bam-physical-address = <0>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-physical-address = <0>;
+ qcom,dst-bam-pipe-index = <0>;
+ qcom,data-fifo-offset = <0>;
+ qcom,data-fifo-size = <0>;
+ qcom,descriptor-fifo-offset = <0>;
+ qcom,descriptor-fifo-size = <0>;
+ };
+
+ qcom,pipe4 {
+ label = "peri-to-usb-qdss-hsusb";
+ qcom,usb-bam-type = <1>;
+ qcom,usb-bam-mem-type = <1>;
+ qcom,src-bam-physical-address = <0xfc37c000>;
+ qcom,src-bam-pipe-index = <0>;
+ qcom,dst-bam-physical-address = <0xf9a44000>;
+ qcom,dst-bam-pipe-index = <2>;
+ qcom,data-fifo-offset = <0xf4000>;
+ qcom,data-fifo-size = <0x1000>;
+ qcom,descriptor-fifo-offset = <0xf5000>;
+ qcom,descriptor-fifo-size = <0x400>;
+ };
};
qcom,msm-thermal {
@@ -743,6 +894,37 @@
qcom,temp-hysteresis = <10>;
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>;
+ };
+ };
};
/include/ "msm-pm8x41-rpm-regulator.dtsi"
@@ -750,3 +932,4 @@
/include/ "msm-pm8941.dtsi"
/include/ "msm8974-regulator.dtsi"
/include/ "msm8974-gpio.dtsi"
+/include/ "msm8974-clock.dtsi"
diff --git a/arch/arm/boot/dts/msm9625.dts b/arch/arm/boot/dts/msm9625.dts
index 42425ed..041b4dd 100644
--- a/arch/arm/boot/dts/msm9625.dts
+++ b/arch/arm/boot/dts/msm9625.dts
@@ -76,4 +76,26 @@
interrupts = <0 247 0>;
interrupt-names = "bam_irq";
};
+
+ spi@f9928000 {
+ compatible = "qcom,spi-qup-v2";
+ reg = <0xf9928000 0x1000>;
+ interrupts = <0 100 0>;
+ spi-max-frequency = <24000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&msmgpio 23 0>, /* CLK */
+ <&msmgpio 21 0>, /* MISO */
+ <&msmgpio 20 0>; /* MOSI */
+
+ cs-gpios = <&msmgpio 69 0>;
+
+ ethernet-switch@0 {
+ compatible = "simtec,ks8851";
+ reg = <0>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <75 0>;
+ spi-max-frequency = <5000000>;
+ };
+ };
};
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 595ecd29..9d7eb53 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -173,7 +173,8 @@
read_lock_irqsave(&device_info->lock, flags);
list_for_each_entry(b, &device_info->safe_buffers, node)
- if (b->safe_dma_addr == safe_dma_addr) {
+ if (b->safe_dma_addr <= safe_dma_addr &&
+ b->safe_dma_addr + b->size > safe_dma_addr) {
rb = b;
break;
}
@@ -254,7 +255,7 @@
if (buf == NULL) {
dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
__func__, ptr);
- return ~0;
+ return DMA_ERROR_CODE;
}
dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
@@ -307,8 +308,9 @@
* substitute the safe buffer for the unsafe one.
* (basically move the buffer from an unsafe area to a safe one)
*/
-dma_addr_t __dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size, enum dma_data_direction dir)
+static dma_addr_t dmabounce_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
{
dma_addr_t dma_addr;
int ret;
@@ -320,21 +322,20 @@
ret = needs_bounce(dev, dma_addr, size);
if (ret < 0)
- return ~0;
+ return DMA_ERROR_CODE;
if (ret == 0) {
- __dma_page_cpu_to_dev(page, offset, size, dir);
+ arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir);
return dma_addr;
}
if (PageHighMem(page)) {
dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n");
- return ~0;
+ return DMA_ERROR_CODE;
}
return map_single(dev, page_address(page) + offset, size, dir);
}
-EXPORT_SYMBOL(__dma_map_page);
/*
* see if a mapped address was really a "safe" buffer and if so, copy
@@ -342,8 +343,8 @@
* the safe buffer. (basically return things back to the way they
* should be)
*/
-void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
- enum dma_data_direction dir)
+static void dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
{
struct safe_buffer *buf;
@@ -352,19 +353,18 @@
buf = find_safe_buffer_dev(dev, dma_addr, __func__);
if (!buf) {
- __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)),
- dma_addr & ~PAGE_MASK, size, dir);
+ arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir);
return;
}
unmap_single(dev, buf, size, dir);
}
-EXPORT_SYMBOL(__dma_unmap_page);
-int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
- unsigned long off, size_t sz, enum dma_data_direction dir)
+static int __dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr,
+ size_t sz, enum dma_data_direction dir)
{
struct safe_buffer *buf;
+ unsigned long off;
dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n",
__func__, addr, off, sz, dir);
@@ -373,6 +373,8 @@
if (!buf)
return 1;
+ off = addr - buf->safe_dma_addr;
+
BUG_ON(buf->direction != dir);
dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
@@ -388,12 +390,21 @@
}
return 0;
}
-EXPORT_SYMBOL(dmabounce_sync_for_cpu);
-int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
- unsigned long off, size_t sz, enum dma_data_direction dir)
+static void dmabounce_sync_for_cpu(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ if (!__dmabounce_sync_for_cpu(dev, handle, size, dir))
+ return;
+
+ arm_dma_ops.sync_single_for_cpu(dev, handle, size, dir);
+}
+
+static int __dmabounce_sync_for_device(struct device *dev, dma_addr_t addr,
+ size_t sz, enum dma_data_direction dir)
{
struct safe_buffer *buf;
+ unsigned long off;
dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n",
__func__, addr, off, sz, dir);
@@ -402,6 +413,8 @@
if (!buf)
return 1;
+ off = addr - buf->safe_dma_addr;
+
BUG_ON(buf->direction != dir);
dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n",
@@ -417,7 +430,38 @@
}
return 0;
}
-EXPORT_SYMBOL(dmabounce_sync_for_device);
+
+static void dmabounce_sync_for_device(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ if (!__dmabounce_sync_for_device(dev, handle, size, dir))
+ return;
+
+ arm_dma_ops.sync_single_for_device(dev, handle, size, dir);
+}
+
+static int dmabounce_set_mask(struct device *dev, u64 dma_mask)
+{
+ if (dev->archdata.dmabounce)
+ return 0;
+
+ return arm_dma_ops.set_dma_mask(dev, dma_mask);
+}
+
+static struct dma_map_ops dmabounce_ops = {
+ .alloc = arm_dma_alloc,
+ .free = arm_dma_free,
+ .mmap = arm_dma_mmap,
+ .map_page = dmabounce_map_page,
+ .unmap_page = dmabounce_unmap_page,
+ .sync_single_for_cpu = dmabounce_sync_for_cpu,
+ .sync_single_for_device = dmabounce_sync_for_device,
+ .map_sg = arm_dma_map_sg,
+ .unmap_sg = arm_dma_unmap_sg,
+ .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
+ .sync_sg_for_device = arm_dma_sync_sg_for_device,
+ .set_dma_mask = dmabounce_set_mask,
+};
static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev,
const char *name, unsigned long size)
@@ -479,6 +523,7 @@
#endif
dev->archdata.dmabounce = device_info;
+ set_dma_ops(dev, &dmabounce_ops);
dev_info(dev, "dmabounce: registered device\n");
@@ -497,6 +542,7 @@
struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
dev->archdata.dmabounce = NULL;
+ set_dma_ops(dev, NULL);
if (!device_info) {
dev_warn(dev,
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index a8abb30..8363b7f 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -154,10 +154,14 @@
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
CONFIG_BT=y
CONFIG_BT_RFCOMM=y
CONFIG_BT_RFCOMM_TTY=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 00325c9..d7735f5 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -154,10 +154,14 @@
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
CONFIG_BT=y
CONFIG_BT_RFCOMM=y
CONFIG_BT_RFCOMM_TTY=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index a51b76d..c8f9212 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -181,12 +181,14 @@
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_PRIO=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 0efe658..2eba8ab 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -181,12 +181,14 @@
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_PRIO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 3854403..1ac8f02 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -59,7 +59,7 @@
CONFIG_MACH_MPQ8064_HRD=y
CONFIG_MACH_MPQ8064_DTV=y
# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_KERNEL_PMEM_EBI_REGION=y
+CONFIG_KERNEL_MSM_CONTIG_MEM_REGION=y
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
CONFIG_MSM_SMD=y
@@ -203,6 +203,7 @@
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
@@ -211,6 +212,7 @@
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_TARGET_REJECT=y
CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_PRIO=y
@@ -291,6 +293,7 @@
CONFIG_STM_LIS3DH=y
CONFIG_INPUT_MPU3050=y
# CONFIG_LEGACY_PTYS is not set
+CONFIG_MSM_IPC_LOGGING=y
CONFIG_N_SMUX=y
CONFIG_N_SMUX_LOOPBACK=y
CONFIG_SMUX_CTL=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 06501ba..8ac8f1a 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -58,7 +58,7 @@
CONFIG_MACH_MPQ8064_HRD=y
CONFIG_MACH_MPQ8064_DTV=y
# CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_KERNEL_PMEM_EBI_REGION=y
+CONFIG_KERNEL_MSM_CONTIG_MEM_REGION=y
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
CONFIG_MSM_SMD=y
@@ -207,6 +207,7 @@
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
@@ -215,6 +216,7 @@
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_TARGET_REJECT=y
CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_PRIO=y
@@ -295,6 +297,7 @@
CONFIG_STM_LIS3DH=y
CONFIG_INPUT_MPU3050=y
# CONFIG_LEGACY_PTYS is not set
+CONFIG_MSM_IPC_LOGGING=y
CONFIG_N_SMUX=y
CONFIG_N_SMUX_LOOPBACK=y
CONFIG_SMUX_CTL=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index c73c62e..719933f 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -55,10 +55,14 @@
CONFIG_MSM_OCMEM_DEBUG=y
CONFIG_MSM_OCMEM_POWER_DISABLE=y
CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_PANIC_TIMEOUT=5
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L1_ERR_PANIC=y
CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_ADSP_LOADER=m
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -104,6 +108,8 @@
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_QSEECOM=y
@@ -125,8 +131,11 @@
# CONFIG_MSM_RMNET is not set
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=n
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
CONFIG_SERIAL_MSM_HSL=y
@@ -225,6 +234,7 @@
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_POWER_ON=y
+CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
@@ -258,3 +268,19 @@
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
+
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+
+CONFIG_BT_HCISMD=y
+CONFIG_MSM_BT_POWER=y
+
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 9094db7..446734f 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -56,9 +56,28 @@
CONFIG_MTD_BLOCK=y
# CONFIG_MTD_MSM_NAND is not set
CONFIG_MTD_MSM_QPIC_NAND=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IPV6=y
+# CONFIG_WIRELESS is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
# CONFIG_ANDROID_PMEM is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_KS8851=y
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_MSM_RMNET is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
@@ -70,6 +89,9 @@
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_HW_RANDOM=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
diff --git a/arch/arm/include/asm/device.h b/arch/arm/include/asm/device.h
index 7aa3680..b69c0d3 100644
--- a/arch/arm/include/asm/device.h
+++ b/arch/arm/include/asm/device.h
@@ -7,12 +7,16 @@
#define ASMARM_DEVICE_H
struct dev_archdata {
+ struct dma_map_ops *dma_ops;
#ifdef CONFIG_DMABOUNCE
struct dmabounce_device_info *dmabounce;
#endif
#ifdef CONFIG_IOMMU_API
void *iommu; /* private IOMMU data */
#endif
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+ struct dma_iommu_mapping *mapping;
+#endif
};
struct omap_device;
diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
new file mode 100644
index 0000000..799b094
--- /dev/null
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -0,0 +1,34 @@
+#ifndef ASMARM_DMA_IOMMU_H
+#define ASMARM_DMA_IOMMU_H
+
+#ifdef __KERNEL__
+
+#include <linux/mm_types.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-debug.h>
+#include <linux/kmemcheck.h>
+
+struct dma_iommu_mapping {
+ /* iommu specific data */
+ struct iommu_domain *domain;
+
+ void *bitmap;
+ size_t bits;
+ unsigned int order;
+ dma_addr_t base;
+
+ spinlock_t lock;
+ struct kref kref;
+};
+
+struct dma_iommu_mapping *
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
+ int order);
+
+void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
+
+int arm_iommu_attach_device(struct device *dev,
+ struct dma_iommu_mapping *mapping);
+
+#endif /* __KERNEL__ */
+#endif
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index dc988ff..5f28327 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -5,11 +5,35 @@
#include <linux/mm_types.h>
#include <linux/scatterlist.h>
+#include <linux/dma-attrs.h>
#include <linux/dma-debug.h>
#include <asm-generic/dma-coherent.h>
#include <asm/memory.h>
+#define DMA_ERROR_CODE (~0)
+extern struct dma_map_ops arm_dma_ops;
+
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+ if (dev && dev->archdata.dma_ops)
+ return dev->archdata.dma_ops;
+ return &arm_dma_ops;
+}
+
+static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
+{
+ BUG_ON(!dev);
+ dev->archdata.dma_ops = ops;
+}
+
+#include <asm-generic/dma-mapping-common.h>
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+ return get_dma_ops(dev)->set_dma_mask(dev, mask);
+}
+
#ifdef __arch_page_to_dma
#error Please update to __arch_pfn_to_dma
#endif
@@ -62,68 +86,11 @@
#endif
/*
- * The DMA API is built upon the notion of "buffer ownership". A buffer
- * is either exclusively owned by the CPU (and therefore may be accessed
- * by it) or exclusively owned by the DMA device. These helper functions
- * represent the transitions between these two ownership states.
- *
- * Note, however, that on later ARMs, this notion does not work due to
- * speculative prefetches. We model our approach on the assumption that
- * the CPU does do speculative prefetches, which means we clean caches
- * before transfers and delay cache invalidation until transfer completion.
- *
- * Private support functions: these are not part of the API and are
- * liable to change. Drivers must not use these.
- */
-static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size,
- enum dma_data_direction dir)
-{
- extern void ___dma_single_cpu_to_dev(const void *, size_t,
- enum dma_data_direction);
-
- if (!arch_is_coherent())
- ___dma_single_cpu_to_dev(kaddr, size, dir);
-}
-
-static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size,
- enum dma_data_direction dir)
-{
- extern void ___dma_single_dev_to_cpu(const void *, size_t,
- enum dma_data_direction);
-
- if (!arch_is_coherent())
- ___dma_single_dev_to_cpu(kaddr, size, dir);
-}
-
-static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
- size_t size, enum dma_data_direction dir)
-{
- extern void ___dma_page_cpu_to_dev(struct page *, unsigned long,
- size_t, enum dma_data_direction);
-
- if (!arch_is_coherent())
- ___dma_page_cpu_to_dev(page, off, size, dir);
-}
-
-static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
- size_t size, enum dma_data_direction dir)
-{
- extern void ___dma_page_dev_to_cpu(struct page *, unsigned long,
- size_t, enum dma_data_direction);
-
- if (!arch_is_coherent())
- ___dma_page_dev_to_cpu(page, off, size, dir);
-}
-
-extern int dma_supported(struct device *, u64);
-extern int dma_set_mask(struct device *, u64);
-
-/*
* DMA errors are defined by all-bits-set in the DMA address.
*/
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
- return dma_addr == ~0;
+ return dma_addr == DMA_ERROR_CODE;
}
/*
@@ -181,69 +148,118 @@
#endif
}
+extern int dma_supported(struct device *dev, u64 mask);
+
/**
- * dma_alloc_coherent - allocate consistent memory for DMA
+ * arm_dma_alloc - allocate consistent memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @size: required memory size
* @handle: bus-specific DMA address
+ * @attrs: optinal attributes that specific mapping properties
*
- * Allocate some uncached, unbuffered memory for a device for
- * performing DMA. This function allocates pages, and will
- * return the CPU-viewed address, and sets @handle to be the
- * device-viewed address.
+ * Allocate some memory for a device for performing DMA. This function
+ * allocates pages, and will return the CPU-viewed address, and sets @handle
+ * to be the device-viewed address.
*/
-extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t);
+extern void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+ gfp_t gfp, struct dma_attrs *attrs);
+
+#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL)
+
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ void *cpu_addr;
+ BUG_ON(!ops);
+
+ cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs);
+ debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
+ return cpu_addr;
+}
/**
- * dma_free_coherent - free memory allocated by dma_alloc_coherent
+ * arm_dma_free - free memory allocated by arm_dma_alloc
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @size: size of memory originally requested in dma_alloc_coherent
* @cpu_addr: CPU-view address returned from dma_alloc_coherent
* @handle: device-view address returned from dma_alloc_coherent
+ * @attrs: optinal attributes that specific mapping properties
*
* Free (and unmap) a DMA buffer previously allocated by
- * dma_alloc_coherent().
+ * arm_dma_alloc().
*
* References to memory and mappings associated with cpu_addr/handle
* during and after this call executing are illegal.
*/
-extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t);
+extern void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, struct dma_attrs *attrs);
+
+#define dma_free_coherent(d, s, c, h) dma_free_attrs(d, s, c, h, NULL)
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle,
+ struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ BUG_ON(!ops);
+
+ debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
+ ops->free(dev, size, cpu_addr, dma_handle, attrs);
+}
/**
- * dma_mmap_coherent - map a coherent DMA allocation into user space
+ * arm_dma_mmap - map a coherent DMA allocation into user space
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @vma: vm_area_struct describing requested user mapping
* @cpu_addr: kernel CPU-view address returned from dma_alloc_coherent
* @handle: device-view address returned from dma_alloc_coherent
* @size: size of memory originally requested in dma_alloc_coherent
+ * @attrs: optinal attributes that specific mapping properties
*
* Map a coherent DMA buffer previously allocated by dma_alloc_coherent
* into user space. The coherent DMA buffer must not be freed by the
* driver until the user space mapping has been released.
*/
-int dma_mmap_coherent(struct device *, struct vm_area_struct *,
- void *, dma_addr_t, size_t);
+extern int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs);
+#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL)
-/**
- * dma_alloc_writecombine - allocate writecombining memory for DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @size: required memory size
- * @handle: bus-specific DMA address
- *
- * Allocate some uncached, buffered memory for a device for
- * performing DMA. This function allocates pages, and will
- * return the CPU-viewed address, and sets @handle to be the
- * device-viewed address.
- */
-extern void *dma_alloc_writecombine(struct device *, size_t, dma_addr_t *,
- gfp_t);
+static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr,
+ size_t size, struct dma_attrs *attrs)
+{
+ struct dma_map_ops *ops = get_dma_ops(dev);
+ BUG_ON(!ops);
+ return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
+}
-#define dma_free_writecombine(dev,size,cpu_addr,handle) \
- dma_free_coherent(dev,size,cpu_addr,handle)
+static inline void *dma_alloc_writecombine(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag)
+{
+ DEFINE_DMA_ATTRS(attrs);
+ dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+ return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs);
+}
-int dma_mmap_writecombine(struct device *, struct vm_area_struct *,
- void *, dma_addr_t, size_t);
+static inline void dma_free_writecombine(struct device *dev, size_t size,
+ void *cpu_addr, dma_addr_t dma_handle)
+{
+ DEFINE_DMA_ATTRS(attrs);
+ dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+ return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs);
+}
+
+static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ DEFINE_DMA_ATTRS(attrs);
+ dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+ return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs);
+}
/*
* This can be called during boot to increase the size of the consistent
@@ -252,8 +268,6 @@
*/
extern void __init init_consistent_dma_size(unsigned long size);
-
-#ifdef CONFIG_DMABOUNCE
/*
* For SA-1111, IXP425, and ADI systems the dma-mapping functions are "magic"
* and utilize bounce buffers as needed to work around limited DMA windows.
@@ -293,82 +307,7 @@
*/
extern void dmabounce_unregister_dev(struct device *);
-/*
- * The DMA API, implemented by dmabounce.c. See below for descriptions.
- */
-extern dma_addr_t __dma_map_page(struct device *, struct page *,
- unsigned long, size_t, enum dma_data_direction);
-extern void __dma_unmap_page(struct device *, dma_addr_t, size_t,
- enum dma_data_direction);
-/*
- * Private functions
- */
-int dmabounce_sync_for_cpu(struct device *, dma_addr_t, unsigned long,
- size_t, enum dma_data_direction);
-int dmabounce_sync_for_device(struct device *, dma_addr_t, unsigned long,
- size_t, enum dma_data_direction);
-#else
-static inline int dmabounce_sync_for_cpu(struct device *d, dma_addr_t addr,
- unsigned long offset, size_t size, enum dma_data_direction dir)
-{
- return 1;
-}
-
-static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr,
- unsigned long offset, size_t size, enum dma_data_direction dir)
-{
- return 1;
-}
-
-
-static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size, enum dma_data_direction dir)
-{
- __dma_page_cpu_to_dev(page, offset, size, dir);
- return pfn_to_dma(dev, page_to_pfn(page)) + offset;
-}
-
-static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle,
- size_t size, enum dma_data_direction dir)
-{
- __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
- handle & ~PAGE_MASK, size, dir);
-}
-#endif /* CONFIG_DMABOUNCE */
-
-/**
- * dma_map_single - map a single buffer for streaming DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @cpu_addr: CPU direct mapped address of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed. The CPU
- * can regain ownership by calling dma_unmap_single() or
- * dma_sync_single_for_cpu().
- */
-static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
- size_t size, enum dma_data_direction dir)
-{
- unsigned long offset;
- struct page *page;
- dma_addr_t addr;
-
- BUG_ON(!virt_addr_valid(cpu_addr));
- BUG_ON(!virt_addr_valid(cpu_addr + size - 1));
- BUG_ON(!valid_dma_direction(dir));
-
- page = virt_to_page(cpu_addr);
- offset = (unsigned long)cpu_addr & ~PAGE_MASK;
- addr = __dma_map_page(dev, page, offset, size, dir);
- debug_dma_map_page(dev, page, offset, size, dir, addr, true);
-
- return addr;
-}
/**
* dma_cache_pre_ops - clean or invalidate cache before dma transfer is
@@ -421,146 +360,17 @@
___dma_single_cpu_to_dev(virtual_addr,
size, DMA_FROM_DEVICE);
}
-
-/**
- * dma_map_page - map a portion of a page for streaming DMA
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @page: page that buffer resides in
- * @offset: offset into page for start of buffer
- * @size: size of buffer to map
- * @dir: DMA transfer direction
- *
- * Ensure that any data held in the cache is appropriately discarded
- * or written back.
- *
- * The device owns this memory once this call has completed. The CPU
- * can regain ownership by calling dma_unmap_page().
- */
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size, enum dma_data_direction dir)
-{
- dma_addr_t addr;
-
- BUG_ON(!valid_dma_direction(dir));
-
- addr = __dma_map_page(dev, page, offset, size, dir);
- debug_dma_map_page(dev, page, offset, size, dir, addr, false);
-
- return addr;
-}
-
-/**
- * dma_unmap_single - unmap a single buffer previously mapped
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer (same as passed to dma_map_single)
- * @dir: DMA transfer direction (same as passed to dma_map_single)
- *
- * Unmap a single streaming mode DMA translation. The handle and size
- * must match what was provided in the previous dma_map_single() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void dma_unmap_single(struct device *dev, dma_addr_t handle,
- size_t size, enum dma_data_direction dir)
-{
- debug_dma_unmap_page(dev, handle, size, dir, true);
- __dma_unmap_page(dev, handle, size, dir);
-}
-
-/**
- * dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @size: size of buffer (same as passed to dma_map_page)
- * @dir: DMA transfer direction (same as passed to dma_map_page)
- *
- * Unmap a page streaming mode DMA translation. The handle and size
- * must match what was provided in the previous dma_map_page() call.
- * All other usages are undefined.
- *
- * After this call, reads by the CPU to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
- size_t size, enum dma_data_direction dir)
-{
- debug_dma_unmap_page(dev, handle, size, dir, false);
- __dma_unmap_page(dev, handle, size, dir);
-}
-
-/**
- * dma_sync_single_range_for_cpu
- * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
- * @handle: DMA address of buffer
- * @offset: offset of region to start sync
- * @size: size of region to sync
- * @dir: DMA transfer direction (same as passed to dma_map_single)
- *
- * Make physical memory consistent for a single streaming mode DMA
- * translation after a transfer.
- *
- * If you perform a dma_map_single() but wish to interrogate the
- * buffer using the cpu, yet do not wish to teardown the PCI dma
- * mapping, you must call this function before doing so. At the
- * next point you give the PCI dma address back to the card, you
- * must first the perform a dma_sync_for_device, and then the
- * device again owns the buffer.
- */
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
- dma_addr_t handle, unsigned long offset, size_t size,
- enum dma_data_direction dir)
-{
- BUG_ON(!valid_dma_direction(dir));
-
- debug_dma_sync_single_for_cpu(dev, handle + offset, size, dir);
-
- if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir))
- return;
-
- __dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir);
-}
-
-static inline void dma_sync_single_range_for_device(struct device *dev,
- dma_addr_t handle, unsigned long offset, size_t size,
- enum dma_data_direction dir)
-{
- BUG_ON(!valid_dma_direction(dir));
-
- debug_dma_sync_single_for_device(dev, handle + offset, size, dir);
-
- if (!dmabounce_sync_for_device(dev, handle, offset, size, dir))
- return;
-
- __dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir);
-}
-
-static inline void dma_sync_single_for_cpu(struct device *dev,
- dma_addr_t handle, size_t size, enum dma_data_direction dir)
-{
- dma_sync_single_range_for_cpu(dev, handle, 0, size, dir);
-}
-
-static inline void dma_sync_single_for_device(struct device *dev,
- dma_addr_t handle, size_t size, enum dma_data_direction dir)
-{
- dma_sync_single_range_for_device(dev, handle, 0, size, dir);
-}
-
/*
* The scatter list versions of the above methods.
*/
-extern int dma_map_sg(struct device *, struct scatterlist *, int,
+extern int arm_dma_map_sg(struct device *, struct scatterlist *, int,
+ enum dma_data_direction, struct dma_attrs *attrs);
+extern void arm_dma_unmap_sg(struct device *, struct scatterlist *, int,
+ enum dma_data_direction, struct dma_attrs *attrs);
+extern void arm_dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
enum dma_data_direction);
-extern void dma_unmap_sg(struct device *, struct scatterlist *, int,
+extern void arm_dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
enum dma_data_direction);
-extern void dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int,
- enum dma_data_direction);
-extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
- enum dma_data_direction);
-
#endif /* __KERNEL__ */
#endif
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 7b6f42a..84560dc 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -313,7 +313,6 @@
* We provide our own arch_get_unmapped_area to cope with VIPT caches.
*/
#define HAVE_ARCH_UNMAPPED_AREA
-#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
/*
* remap a physical page `pfn' of size `size' with page protection `prot'
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 07209d7..8e2bb29 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -126,8 +126,6 @@
#endif
-#define HAVE_ARCH_PICK_MMAP_LAYOUT
-
#endif
#endif /* __ASM_ARM_PROCESSOR_H */
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 43c627d..23d310d 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -208,11 +208,11 @@
unsigned long ctrl;
ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
- ctrl |= ARCH_TIMER_CTRL_ENABLE;
- ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
-
+ ctrl &= ~(ARCH_TIMER_CTRL_ENABLE | 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/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5331f2c..e41ab0a 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -249,12 +249,14 @@
select MSM_PIL
select MSM_SPM_V2
select MSM_L2_SPM
+ select MSM_NATIVE_RESTART
+ select MSM_RESTART_V2
select MSM_PM8X60 if PM
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MSM_RPM_SMD
select REGULATOR
- select MSM_QDSP6_APR
+ select MSM_QDSP6_APRV2
select MSM_QDSP6V2_CODECS
select MSM_AUDIO_QDSP6V2 if SND_SOC
select MSM_RPM_REGULATOR_SMD
@@ -381,6 +383,9 @@
config MSM_KRAIT_WFE_FIXUP
bool
+config MSM_RESTART_V2
+ bool
+
config ARCH_MSM_CORTEX_A5
bool
select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
@@ -890,12 +895,15 @@
default "0x40200000" if ARCH_MSM8X60
default "0x10000000"
-config KERNEL_PMEM_EBI_REGION
- bool "Enable in-kernel PMEM region for EBI"
+config KERNEL_MSM_CONTIG_MEM_REGION
+ bool "Enable in-kernel contiguous memory region"
default y if ARCH_MSM8X60
depends on ANDROID_PMEM && (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM8974)
help
- Enable the in-kernel PMEM allocator to use EBI memory.
+ Enable the in-kernel contiguous memory allocator. Sets up a
+ region of physically contiguous memory. This memory is
+ reserved during initialization, and can be used
+ generically.
config KERNEL_PMEM_SMI_REGION
bool "Enable in-kernel PMEM region for SMI"
@@ -2107,7 +2115,7 @@
config MSM_DLOAD_MODE
bool "Enable download mode on crashes"
- depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615
+ depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM9615 || ARCH_MSM8974
default n
help
This makes the SoC enter download mode when it resets
@@ -2133,11 +2141,6 @@
help
Enables embedded trace collection on MSM8660
-config MSM_SLEEP_STATS
- bool "Enable exporting of MSM sleep stats to userspace"
- depends on CPU_IDLE
- default n
-
config MSM_SLEEP_STATS_DEVICE
bool "Enable exporting of MSM sleep device stats to userspace"
@@ -2204,6 +2207,16 @@
used by audio driver to configure QDSP6's
ASM, ADM and AFE.
+config MSM_QDSP6_APRV2
+ bool "Audio QDSP6 APRv2 support"
+ depends on MSM_SMD
+ default n
+ help
+ Enable APRv2 IPC protocol support between
+ application processor and QDSP6. APR is
+ used by audio driver to configure QDSP6's
+ ASM, ADM and AFE.
+
config MSM_QDSP6_CODECS
bool "Audio Codecs on QDSP6 APR "
depends on MSM_SMD
@@ -2241,6 +2254,16 @@
AAC, AMRNB, AMRWB, EVRC, MP3, QCELP among
others.
+config MSM_ADSP_LOADER
+ tristate "ADSP loader support"
+ select SND_SOC_MSM_APRV2_INTF
+ depends on MSM_AUDIO_QDSP6V2 && m
+ help
+ Enable ADSP image loader.
+ The ADSP loader brings ADSP out of reset
+ for the platforms that use APRv2.
+ Say M if you want to enable this module.
+
config MSM_ULTRASOUND
bool "MSM ultrasound support"
depends on MSM_AUDIO_QDSP6
@@ -2318,6 +2341,16 @@
Choosing one of these options allows debugging of each
individual subsystem separately.
+config MSM_OCMEM_NONSECURE
+ bool "OCMEM Non Secure Mode"
+ depends on MSM_OCMEM_DEBUG
+ help
+ Disable OCMEM interaction with secure processor.
+ By default OCMEM is secured and accesses for each master
+ is requested by the OCMEM driver. Selecting this option
+ causes the OCMEM memory to be in non-secure state unless
+ its locked down by the secure processor.
+
config MSM_OCMEM_POWER_DEBUG
bool "OCMEM Power Debug Support"
depends on MSM_OCMEM_DEBUG
@@ -2451,6 +2484,19 @@
algorithm and the algorithm returns a frequency for the core which is
passed to the frequency change driver.
+config MSM_CPR
+ tristate "Use MSM CPR in S/W mode"
+ help
+ Enable CPR (core power reduction) in S/W mode, where the processor
+ get's the notification from CPR block and programs the PMIC.
+
+config MSM_VP_REGULATOR
+ tristate "Use MSM PMIC8029 C2 regulator"
+ depends on ARCH_MSM8625
+ help
+ Enable MSM PMIC8029 C2 regulator support using APC_PLEVEL access
+ for MSMs like 8625.
+
config HAVE_ARCH_HAS_CURRENT_TIMER
bool
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 5e3a980..f27889b 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -264,7 +264,7 @@
obj-$(CONFIG_MACH_MSM7X25_FFA) += board-msm7x27.o devices-msm7x25.o
obj-$(CONFIG_ARCH_MSM8960) += clock-local.o clock-dss-8960.o clock-8960.o clock-rpm.o clock-pll.o
obj-$(CONFIG_ARCH_MSM8960) += footswitch-8x60.o
-obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o
+obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o acpuclock-8960ab.o
obj-$(CONFIG_ARCH_MSM8960) += memory_topology.o
obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o
obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o
@@ -289,7 +289,7 @@
obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-dt.o board-8974-gpiomux.o
obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
-obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o
+obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.o
obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
@@ -350,7 +350,6 @@
obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
-obj-$(CONFIG_MSM_SLEEP_STATS) += idle_stats.o
obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_dcvs_idle.o
obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o
@@ -379,3 +378,9 @@
obj-$(CONFIG_MSM_HSIC_SYSMON_TEST) += hsic_sysmon_test.o
obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o
+obj-$(CONFIG_MSM_CPR) += msm_cpr.o
+obj-$(CONFIG_MSM_VP_REGULATOR) += msm_vp.o
+
+ifdef CONFIG_MSM_CPR
+obj-$(CONFIG_DEBUG_FS) += msm_cpr-debug.o
+endif
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
new file mode 100644
index 0000000..1097907
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -0,0 +1,165 @@
+/*
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <mach/rpm-regulator.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+
+#include "acpuclock.h"
+#include "acpuclock-krait.h"
+
+static struct hfpll_data hfpll_data __initdata = {
+ .mode_offset = 0x00,
+ .l_offset = 0x08,
+ .m_offset = 0x0C,
+ .n_offset = 0x10,
+ .config_offset = 0x04,
+ .config_val = 0x7845C665,
+ .has_droop_ctl = true,
+ .droop_offset = 0x14,
+ .droop_val = 0x0108C000,
+ .low_vdd_l_max = 37,
+ .nom_vdd_l_max = 74,
+ .vdd[HFPLL_VDD_NONE] = 0,
+ .vdd[HFPLL_VDD_LOW] = 945000,
+ .vdd[HFPLL_VDD_NOM] = 1050000,
+ .vdd[HFPLL_VDD_HIGH] = 1150000,
+};
+
+static struct scalable scalable[] __initdata = {
+ [CPU0] = {
+ .hfpll_phys_base = 0x00903200,
+ .aux_clk_sel_phys = 0x02088014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x4501,
+ .vreg[VREG_CORE] = { "krait0", 1300000 },
+ .vreg[VREG_MEM] = { "krait0_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait0_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait0_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "krait0_l23", 1800000 },
+ },
+ [CPU1] = {
+ .hfpll_phys_base = 0x00903300,
+ .aux_clk_sel_phys = 0x02098014,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x5501,
+ .vreg[VREG_CORE] = { "krait1", 1300000 },
+ .vreg[VREG_MEM] = { "krait1_mem", 1150000 },
+ .vreg[VREG_DIG] = { "krait1_dig", 1150000 },
+ .vreg[VREG_HFPLL_A] = { "krait1_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "krait1_l23", 1800000 },
+ },
+ [L2] = {
+ .hfpll_phys_base = 0x00903400,
+ .aux_clk_sel_phys = 0x02011028,
+ .aux_clk_sel = 3,
+ .l2cpmr_iaddr = 0x0500,
+ .vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
+ .vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
+ },
+};
+
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
+ [0] = BW_MBPS(640), /* At least 80 MHz on bus. */
+ [1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
+ [2] = BW_MBPS(1600), /* At least 200 MHz on bus. */
+ [3] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+ [4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
+ [5] = BW_MBPS(4264), /* At least 533 MHz on bus. */
+};
+
+static struct msm_bus_scale_pdata bus_scale_data __initdata = {
+ .usecase = bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(bw_level_tbl),
+ .active_only = 1,
+ .name = "acpuclk-8960ab",
+};
+
+static struct l2_level l2_freq_tbl[] __initdata = {
+ [0] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+ [1] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
+ [2] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+ [3] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
+ [4] = { { 810000, HFPLL, 1, 0, 0x1E }, 1050000, 1050000, 4 },
+ [5] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 5 },
+ [6] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 5 },
+ [7] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 5 },
+ [8] = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 5 },
+ [9] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 5 },
+};
+
+static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 950000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(3), 975000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(3), 975000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(3), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(3), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(3), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(3), 1025000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(3), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(3), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(3), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(3), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(3), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(3), 1125000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(9), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(9), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(9), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(9), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(9), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(9), 1225000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(9), 1237500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(9), 1237500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(9), 1250000 },
+ { 0, { 0 } }
+};
+
+static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
+[PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+[PVS_NOMINAL] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+[PVS_FAST] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+};
+
+static struct acpuclk_krait_params acpuclk_8960ab_params __initdata = {
+ .scalable = scalable,
+ .scalable_size = sizeof(scalable),
+ .hfpll_data = &hfpll_data,
+ .pvs_tables = pvs_tables,
+ .l2_freq_tbl = l2_freq_tbl,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
+ .bus_scale = &bus_scale_data,
+ .qfprom_phys_base = 0x00700000,
+ .stby_khz = 384000,
+};
+
+static int __init acpuclk_8960ab_probe(struct platform_device *pdev)
+{
+ return acpuclk_krait_init(&pdev->dev, &acpuclk_8960ab_params);
+}
+
+static struct platform_driver acpuclk_8960ab_driver = {
+ .driver = {
+ .name = "acpuclk-8960ab",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init acpuclk_8960ab_init(void)
+{
+ return platform_driver_probe(&acpuclk_8960ab_driver,
+ acpuclk_8960ab_probe);
+}
+device_initcall(acpuclk_8960ab_init);
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 22275b4..f0b1231 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -148,12 +148,12 @@
{ 1, { 883200, HFPLL, 1, 0, 46 }, L2(7), 950000, 3200000 },
{ 1, { 960000, HFPLL, 1, 0, 50 }, L2(7), 950000, 3200000 },
{ 1, { 1036800, HFPLL, 1, 0, 54 }, L2(7), 950000, 3200000 },
- { 0, { 1113600, HFPLL, 1, 0, 58 }, L2(12), 1050000, 3200000 },
- { 0, { 1190400, HFPLL, 1, 0, 62 }, L2(12), 1050000, 3200000 },
- { 0, { 1267200, HFPLL, 1, 0, 66 }, L2(12), 1050000, 3200000 },
- { 0, { 1344000, HFPLL, 1, 0, 70 }, L2(15), 1050000, 3200000 },
- { 0, { 1420800, HFPLL, 1, 0, 74 }, L2(15), 1050000, 3200000 },
- { 0, { 1497600, HFPLL, 1, 0, 78 }, L2(15), 1050000, 3200000 },
+ { 1, { 1113600, HFPLL, 1, 0, 58 }, L2(12), 1050000, 3200000 },
+ { 1, { 1190400, HFPLL, 1, 0, 62 }, L2(12), 1050000, 3200000 },
+ { 1, { 1267200, HFPLL, 1, 0, 66 }, L2(12), 1050000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 0, 70 }, L2(15), 1050000, 3200000 },
+ { 1, { 1420800, HFPLL, 1, 0, 74 }, L2(15), 1050000, 3200000 },
+ { 1, { 1497600, HFPLL, 1, 0, 78 }, L2(16), 1050000, 3200000 },
{ 0, { 1574400, HFPLL, 1, 0, 82 }, L2(20), 1050000, 3200000 },
{ 0, { 1651200, HFPLL, 1, 0, 86 }, L2(20), 1050000, 3200000 },
{ 0, { 1728000, HFPLL, 1, 0, 90 }, L2(20), 1050000, 3200000 },
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
index be056e6..2b33c4c 100644
--- a/arch/arm/mach-msm/acpuclock.c
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,6 +13,7 @@
#include <linux/cpu.h>
#include <linux/smp.h>
#include "acpuclock.h"
+#include <trace/events/power.h>
static struct acpuclk_data *acpuclk_data;
@@ -26,10 +27,19 @@
int acpuclk_set_rate(int cpu, unsigned long rate, enum setrate_reason reason)
{
+ int ret;
+
if (!acpuclk_data->set_rate)
return 0;
- return acpuclk_data->set_rate(cpu, rate, reason);
+ trace_cpu_frequency_switch_start(acpuclk_get_rate(cpu), rate, cpu);
+ ret = acpuclk_data->set_rate(cpu, rate, reason);
+ if (!ret) {
+ trace_cpu_frequency_switch_end(cpu);
+ trace_cpu_frequency(rate, cpu);
+ }
+
+ return ret;
}
uint32_t acpuclk_get_switch_time(void)
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index b35e949..125094d 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -47,16 +47,29 @@
#define BAM_MUX_HDR_CMD_STATUS 3 /* unused */
#define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC 4
-#define POLLING_MIN_SLEEP 950 /* 0.95 ms */
-#define POLLING_MAX_SLEEP 1050 /* 1.05 ms */
-#define POLLING_INACTIVITY 40 /* cycles before switch to intr mode */
#define LOW_WATERMARK 2
#define HIGH_WATERMARK 4
+#define DEFAULT_POLLING_MIN_SLEEP (950)
+#define MAX_POLLING_SLEEP (6050)
+#define MIN_POLLING_SLEEP (950)
static int msm_bam_dmux_debug_enable;
module_param_named(debug_enable, msm_bam_dmux_debug_enable,
int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_MIN_SLEEP = 950;
+module_param_named(min_sleep, POLLING_MIN_SLEEP,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_MAX_SLEEP = 1050;
+module_param_named(max_sleep, POLLING_MAX_SLEEP,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int POLLING_INACTIVITY = 40;
+module_param_named(inactivity, POLLING_INACTIVITY,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+static int bam_adaptive_timer_enabled = 1;
+module_param_named(adaptive_timer_enabled,
+ bam_adaptive_timer_enabled,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
#if defined(DEBUG)
static uint32_t bam_dmux_read_cnt;
@@ -177,6 +190,7 @@
static int bam_mux_initialized;
static int polling_mode;
+static unsigned long rx_timer_interval;
static LIST_HEAD(bam_rx_pool);
static DEFINE_MUTEX(bam_rx_pool_mutexlock);
@@ -1116,6 +1130,7 @@
struct rx_pkt_info *info;
int inactive_cycles = 0;
int ret;
+ u32 buffs_unused, buffs_used;
while (bam_connection_is_active) { /* timer loop */
++inactive_cycles;
@@ -1162,12 +1177,47 @@
handle_bam_mux_cmd(&info->work);
}
- if (inactive_cycles == POLLING_INACTIVITY) {
+ if (inactive_cycles >= POLLING_INACTIVITY) {
rx_switch_to_interrupt_mode();
break;
}
- usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+ if (bam_adaptive_timer_enabled) {
+ usleep_range(rx_timer_interval, rx_timer_interval + 50);
+
+ ret = sps_get_unused_desc_num(bam_rx_pipe,
+ &buffs_unused);
+
+ if (ret) {
+ pr_err("%s: error getting num buffers unused after sleep\n",
+ __func__);
+
+ break;
+ }
+
+ buffs_used = NUM_BUFFERS - buffs_unused;
+
+ if (buffs_unused == 0) {
+ rx_timer_interval = MIN_POLLING_SLEEP;
+ } else {
+ if (buffs_used > 0) {
+ rx_timer_interval =
+ (2 * NUM_BUFFERS *
+ rx_timer_interval)/
+ (3 * buffs_used);
+ } else {
+ rx_timer_interval =
+ MAX_POLLING_SLEEP;
+ }
+ }
+
+ if (rx_timer_interval > MAX_POLLING_SLEEP)
+ rx_timer_interval = MAX_POLLING_SLEEP;
+ else if (rx_timer_interval < MIN_POLLING_SLEEP)
+ rx_timer_interval = MIN_POLLING_SLEEP;
+ } else {
+ usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
+ }
}
}
@@ -1826,12 +1876,18 @@
mutex_unlock(&dfab_status_lock);
return;
}
- rc = clk_prepare_enable(dfab_clk);
- if (rc)
- DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n", rc);
- rc = clk_prepare_enable(xo_clk);
- if (rc)
- DMUX_LOG_KERR("bam_dmux vote for xo failed rc = %d\n", rc);
+ if (dfab_clk) {
+ rc = clk_prepare_enable(dfab_clk);
+ if (rc)
+ DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n",
+ rc);
+ }
+ if (xo_clk) {
+ rc = clk_prepare_enable(xo_clk);
+ if (rc)
+ DMUX_LOG_KERR("bam_dmux vote for xo failed rc = %d\n",
+ rc);
+ }
dfab_is_on = 1;
mutex_unlock(&dfab_status_lock);
}
@@ -1846,8 +1902,10 @@
mutex_unlock(&dfab_status_lock);
return;
}
- clk_disable_unprepare(dfab_clk);
- clk_disable_unprepare(xo_clk);
+ if (dfab_clk)
+ clk_disable_unprepare(dfab_clk);
+ if (xo_clk)
+ clk_disable_unprepare(xo_clk);
dfab_is_on = 0;
mutex_unlock(&dfab_status_lock);
}
@@ -2270,19 +2328,19 @@
xo_clk = clk_get(&pdev->dev, "xo");
if (IS_ERR(xo_clk)) {
- pr_err("%s: did not get xo clock\n", __func__);
- return PTR_ERR(xo_clk);
+ bam_dmux_log("%s: did not get xo clock\n", __func__);
+ xo_clk = NULL;
}
dfab_clk = clk_get(&pdev->dev, "bus_clk");
if (IS_ERR(dfab_clk)) {
- pr_err("%s: did not get dfab clock\n", __func__);
- return -EFAULT;
+ bam_dmux_log("%s: did not get dfab clock\n", __func__);
+ dfab_clk = NULL;
+ } else {
+ rc = clk_set_rate(dfab_clk, 64000000);
+ if (rc)
+ pr_err("%s: unable to set dfab clock rate\n", __func__);
}
- rc = clk_set_rate(dfab_clk, 64000000);
- if (rc)
- pr_err("%s: unable to set dfab clock rate\n", __func__);
-
/*
* setup the workqueue so that it can be pinned to core 0 and not
* block the watchdog pet function, so that netif_rx() in rmnet
@@ -2379,6 +2437,8 @@
bam_dmux_state_logging_disabled = 1;
}
+ rx_timer_interval = DEFAULT_POLLING_MIN_SLEEP;
+
subsys_notif_register_notifier("modem", &restart_notifier);
return platform_driver_register(&bam_dmux_driver);
}
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 40995bb..722b8ea 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -16,7 +16,7 @@
#include <asm/mach-types.h>
-#include <mach/board.h>
+#include <mach/camera.h>
#include <mach/msm_bus_board.h>
#include <mach/gpiomux.h>
@@ -369,20 +369,13 @@
},
};
-static struct camera_vreg_t apq_8064_back_cam_vreg[] = {
+static struct camera_vreg_t apq_8064_cam_vreg[] = {
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
{"cam_vio", REG_VS, 0, 0, 0},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
};
-static struct camera_vreg_t apq_8064_front_cam_vreg[] = {
- {"cam_vio", REG_VS, 0, 0, 0},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
- {"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-};
-
#define CAML_RSTN PM8921_GPIO_PM_TO_SYS(28)
#define CAMR_RSTN 34
@@ -482,8 +475,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
.mount_angle = 90,
- .cam_vreg = apq_8064_back_cam_vreg,
- .num_vreg = ARRAY_SIZE(apq_8064_back_cam_vreg),
+ .cam_vreg = apq_8064_cam_vreg,
+ .num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
.gpio_conf = &apq8064_back_cam_gpio_conf,
.i2c_conf = &apq8064_back_cam_i2c_conf,
.csi_lane_params = &imx074_csi_lane_params,
@@ -515,21 +508,14 @@
.csi_lane_mask = 0xF,
};
-static struct camera_vreg_t apq_8064_imx091_vreg[] = {
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
- {"cam_vio", REG_VS, 0, 0, 0},
-};
-
static struct msm_camera_sensor_flash_data flash_imx091 = {
.flash_type = MSM_CAMERA_FLASH_NONE,
};
static struct msm_camera_sensor_platform_info sensor_board_info_imx091 = {
.mount_angle = 0,
- .cam_vreg = apq_8064_imx091_vreg,
- .num_vreg = ARRAY_SIZE(apq_8064_imx091_vreg),
+ .cam_vreg = apq_8064_cam_vreg,
+ .num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
.gpio_conf = &apq8064_back_cam_gpio_conf,
.i2c_conf = &apq8064_back_cam_i2c_conf,
.csi_lane_params = &imx091_csi_lane_params,
@@ -556,13 +542,6 @@
.eeprom_info = &imx091_eeprom_info,
};
-static struct camera_vreg_t apq_8064_s5k3l1yx_vreg[] = {
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vio", REG_VS, 0, 0, 0},
- {"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-};
-
static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
.flash_type = MSM_CAMERA_FLASH_NONE,
};
@@ -574,8 +553,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
.mount_angle = 90,
- .cam_vreg = apq_8064_s5k3l1yx_vreg,
- .num_vreg = ARRAY_SIZE(apq_8064_s5k3l1yx_vreg),
+ .cam_vreg = apq_8064_cam_vreg,
+ .num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
.gpio_conf = &apq8064_back_cam_gpio_conf,
.i2c_conf = &apq8064_back_cam_i2c_conf,
.csi_lane_params = &s5k3l1yx_csi_lane_params,
@@ -591,13 +570,6 @@
.sensor_type = BAYER_SENSOR,
};
-static struct camera_vreg_t apq_8064_mt9m114_vreg[] = {
- {"cam_vio", REG_VS, 0, 0, 0},
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-};
-
static struct msm_camera_sensor_flash_data flash_mt9m114 = {
.flash_type = MSM_CAMERA_FLASH_NONE
};
@@ -609,8 +581,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
.mount_angle = 90,
- .cam_vreg = apq_8064_mt9m114_vreg,
- .num_vreg = ARRAY_SIZE(apq_8064_mt9m114_vreg),
+ .cam_vreg = apq_8064_cam_vreg,
+ .num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
.gpio_conf = &apq8064_front_cam_gpio_conf,
.i2c_conf = &apq8064_front_cam_i2c_conf,
.csi_lane_params = &mt9m114_csi_lane_params,
@@ -637,8 +609,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
.mount_angle = 0,
- .cam_vreg = apq_8064_front_cam_vreg,
- .num_vreg = ARRAY_SIZE(apq_8064_front_cam_vreg),
+ .cam_vreg = apq_8064_cam_vreg,
+ .num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
.gpio_conf = &apq8064_front_cam_gpio_conf,
.i2c_conf = &apq8064_front_cam_i2c_conf,
.csi_lane_params = &ov2720_csi_lane_params,
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 330d7a8..d0f1e87 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -62,6 +62,7 @@
#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME "mipi_video_chimei_wxga"
#define HDMI_PANEL_NAME "hdmi_msm"
+#define MHL_PANEL_NAME "hdmi_msm,mhl_8334"
#define TVOUT_PANEL_NAME "tvout_msm"
#define LVDS_PIXEL_MAP_PATTERN_1 1
@@ -73,11 +74,18 @@
static unsigned char hdmi_is_primary;
#endif
+static unsigned char mhl_display_enabled;
+
unsigned char apq8064_hdmi_as_primary_selected(void)
{
return hdmi_is_primary;
}
+unsigned char apq8064_mhl_display_enabled(void)
+{
+ return mhl_display_enabled;
+}
+
static void set_mdp_clocks_for_wuxga(void);
static int msm_fb_detect_panel(const char *name)
@@ -236,18 +244,9 @@
.name = "mdp",
};
-static int mdp_core_clk_rate_table[] = {
- 59080000,
- 128000000,
- 160000000,
- 200000000,
-};
-
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
- .mdp_core_clk_rate = 59080000,
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+ .mdp_max_clk = 200000000,
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
.mdp_rev = MDP_REV_44,
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -469,7 +468,11 @@
gpio_set_value_cansleep(gpio36, 0);
gpio_set_value_cansleep(gpio25, 1);
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ gpio_set_value_cansleep(gpio26, 1);
} else {
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ gpio_set_value_cansleep(gpio26, 0);
gpio_set_value_cansleep(gpio25, 0);
gpio_set_value_cansleep(gpio36, 1);
@@ -600,7 +603,11 @@
gpio_set_value_cansleep(gpio36, 0);
gpio_set_value_cansleep(mpp3, 1);
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ gpio_set_value_cansleep(gpio26, 1);
} else {
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ gpio_set_value_cansleep(gpio26, 0);
gpio_set_value_cansleep(mpp3, 0);
gpio_set_value_cansleep(gpio36, 1);
@@ -626,14 +633,17 @@
static int lvds_pixel_remap(void)
{
+ u32 ver = socinfo_get_version();
+
if (machine_is_apq8064_cdp() ||
machine_is_apq8064_liquid()) {
- u32 ver = socinfo_get_version();
if ((SOCINFO_VERSION_MAJOR(ver) == 1) &&
(SOCINFO_VERSION_MINOR(ver) == 0))
return LVDS_PIXEL_MAP_PATTERN_1;
} else if (machine_is_mpq8064_dtv()) {
- return LVDS_PIXEL_MAP_PATTERN_2;
+ if ((SOCINFO_VERSION_MAJOR(ver) == 1) &&
+ (SOCINFO_VERSION_MINOR(ver) == 0))
+ return LVDS_PIXEL_MAP_PATTERN_2;
}
return 0;
}
@@ -1023,8 +1033,6 @@
*/
static void set_mdp_clocks_for_wuxga(void)
{
- int i;
-
mdp_ui_vectors[0].ab = 2000000000;
mdp_ui_vectors[0].ib = 2000000000;
mdp_vga_vectors[0].ab = 2000000000;
@@ -1034,11 +1042,6 @@
mdp_1080p_vectors[0].ab = 2000000000;
mdp_1080p_vectors[0].ib = 2000000000;
- mdp_pdata.mdp_core_clk_rate = 200000000;
-
- for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
- mdp_core_clk_rate_table[i] = 200000000;
-
if (apq8064_hdmi_as_primary_selected()) {
dtv_bus_def_vectors[0].ab = 2000000000;
dtv_bus_def_vectors[0].ib = 2000000000;
@@ -1080,7 +1083,15 @@
PANEL_NAME_MAX_LEN);
pr_debug("msm_fb_pdata.ext_panel_name %s\n",
msm_fb_pdata.ext_panel_name);
+
+ if (!strncmp((char *)msm_fb_pdata.ext_panel_name,
+ MHL_PANEL_NAME, strnlen(MHL_PANEL_NAME,
+ PANEL_NAME_MAX_LEN))) {
+ pr_debug("MHL is external display by boot parameter\n");
+ mhl_display_enabled = 1;
+ }
}
msm_fb_pdata.ext_resolution = resolution;
+ hdmi_msm_data.is_mhl_enabled = mhl_display_enabled;
}
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index e77e7c0..86bc6ba 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -26,6 +26,7 @@
#include <mach/board.h>
#include <mach/gpiomux.h>
#include <mach/restart.h>
+#include <mach/socinfo.h>
#include "devices.h"
#include "board-8064.h"
@@ -141,6 +142,31 @@
PM8921_GPIO_INPUT(17, PM_GPIO_PULL_UP_1P5), /* SD_WP */
};
+/* Initial PM8917 GPIO configurations */
+static struct pm8xxx_gpio_init pm8917_gpios[] __initdata = {
+ PM8921_GPIO_OUTPUT(14, 1, HIGH), /* HDMI Mux Selector */
+ PM8921_GPIO_OUTPUT(23, 0, HIGH), /* touchscreen power FET */
+ PM8921_GPIO_OUTPUT_BUFCONF(25, 0, LOW, CMOS), /* DISP_RESET_N */
+ PM8921_GPIO_OUTPUT(26, 1, HIGH), /* Backlight: on */
+ PM8921_GPIO_OUTPUT_BUFCONF(36, 1, LOW, OPEN_DRAIN),
+ PM8921_GPIO_OUTPUT_FUNC(38, 0, PM_GPIO_FUNC_2),
+ PM8921_GPIO_OUTPUT(33, 0, HIGH),
+ PM8921_GPIO_OUTPUT(20, 0, HIGH),
+ PM8921_GPIO_INPUT(35, PM_GPIO_PULL_UP_30),
+ PM8921_GPIO_INPUT(30, PM_GPIO_PULL_UP_30),
+ /* TABLA CODEC RESET */
+ PM8921_GPIO_OUTPUT(34, 1, MED),
+ PM8921_GPIO_OUTPUT(13, 0, HIGH), /* PCIE_CLK_PWR_EN */
+ PM8921_GPIO_INPUT(12, PM_GPIO_PULL_UP_30), /* PCIE_WAKE_N */
+};
+
+/* PM8921 GPIO 42 remaps to PM8917 GPIO 8 */
+static struct pm8xxx_gpio_init pm8917_cdp_kp_gpios[] __initdata = {
+ PM8921_GPIO_INPUT(27, PM_GPIO_PULL_UP_30),
+ PM8921_GPIO_INPUT(8, PM_GPIO_PULL_UP_30),
+ PM8921_GPIO_INPUT(17, PM_GPIO_PULL_UP_1P5), /* SD_WP */
+};
+
static struct pm8xxx_gpio_init pm8921_mpq_gpios[] __initdata = {
PM8921_GPIO_INIT(27, PM_GPIO_DIR_IN, PM_GPIO_OUT_BUF_CMOS, 0,
PM_GPIO_PULL_NO, PM_GPIO_VIN_VPH, PM_GPIO_STRENGTH_NO,
@@ -157,52 +183,45 @@
PM8921_MPP_INIT(1, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_HIGH),
};
+
+void __init apq8064_configure_gpios(struct pm8xxx_gpio_init *data, int len)
+{
+ int i, rc;
+
+ for (i = 0; i < len; i++) {
+ rc = pm8xxx_gpio_config(data[i].gpio, &data[i].config);
+ if (rc)
+ pr_err("%s: pm8xxx_gpio_config(%u) failed: rc=%d\n",
+ __func__, data[i].gpio, rc);
+ }
+}
+
void __init apq8064_pm8xxx_gpio_mpp_init(void)
{
int i, rc;
- for (i = 0; i < ARRAY_SIZE(pm8921_gpios); i++) {
- rc = pm8xxx_gpio_config(pm8921_gpios[i].gpio,
- &pm8921_gpios[i].config);
- if (rc) {
- pr_err("%s: pm8xxx_gpio_config: rc=%d\n", __func__, rc);
- break;
- }
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+ apq8064_configure_gpios(pm8921_gpios, ARRAY_SIZE(pm8921_gpios));
+ else
+ apq8064_configure_gpios(pm8917_gpios, ARRAY_SIZE(pm8917_gpios));
+
+ if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid()) {
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+ apq8064_configure_gpios(pm8921_cdp_kp_gpios,
+ ARRAY_SIZE(pm8921_cdp_kp_gpios));
+ else
+ apq8064_configure_gpios(pm8917_cdp_kp_gpios,
+ ARRAY_SIZE(pm8917_cdp_kp_gpios));
}
- if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
- for (i = 0; i < ARRAY_SIZE(pm8921_cdp_kp_gpios); i++) {
- rc = pm8xxx_gpio_config(pm8921_cdp_kp_gpios[i].gpio,
- &pm8921_cdp_kp_gpios[i].config);
- if (rc) {
- pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
- __func__, rc);
- break;
- }
- }
-
if (machine_is_apq8064_mtp())
- for (i = 0; i < ARRAY_SIZE(pm8921_mtp_kp_gpios); i++) {
- rc = pm8xxx_gpio_config(pm8921_mtp_kp_gpios[i].gpio,
- &pm8921_mtp_kp_gpios[i].config);
- if (rc) {
- pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
- __func__, rc);
- break;
- }
- }
+ apq8064_configure_gpios(pm8921_mtp_kp_gpios,
+ ARRAY_SIZE(pm8921_mtp_kp_gpios));
if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd()
- || machine_is_mpq8064_dtv())
- for (i = 0; i < ARRAY_SIZE(pm8921_mpq_gpios); i++) {
- rc = pm8xxx_gpio_config(pm8921_mpq_gpios[i].gpio,
- &pm8921_mpq_gpios[i].config);
- if (rc) {
- pr_err("%s: pm8xxx_gpio_config: rc=%d\n",
- __func__, rc);
- break;
- }
- }
+ || machine_is_mpq8064_dtv())
+ apq8064_configure_gpios(pm8921_mpq_gpios,
+ ARRAY_SIZE(pm8921_mpq_gpios));
for (i = 0; i < ARRAY_SIZE(pm8xxx_mpps); i++) {
rc = pm8xxx_mpp_config(pm8xxx_mpps[i].mpp,
@@ -360,6 +379,7 @@
};
#define MAX_VOLTAGE_MV 4200
+#define CHG_TERM_MA 100
static struct pm8921_charger_platform_data
apq8064_pm8921_chg_pdata __devinitdata = {
.safety_time = 180,
@@ -368,7 +388,7 @@
.min_voltage = 3200,
.uvd_thresh_voltage = 4050,
.resume_voltage_delta = 100,
- .term_current = 100,
+ .term_current = CHG_TERM_MA,
.cool_temp = 10,
.warm_temp = 40,
.temp_check_period = 1,
@@ -379,6 +399,7 @@
.warm_bat_voltage = 4100,
.thermal_mitigation = apq8064_pm8921_therm_mitigation,
.thermal_levels = ARRAY_SIZE(apq8064_pm8921_therm_mitigation),
+ .rconn_mohm = 18,
};
static struct pm8xxx_ccadc_platform_data
@@ -389,16 +410,18 @@
static struct pm8921_bms_platform_data
apq8064_pm8921_bms_pdata __devinitdata = {
- .battery_type = BATT_UNKNOWN,
- .r_sense = 10,
- .i_test = 2500,
- .v_failure = 3000,
- .max_voltage_uv = MAX_VOLTAGE_MV * 1000,
+ .battery_type = BATT_UNKNOWN,
+ .r_sense = 10,
+ .v_cutoff = 3400,
+ .max_voltage_uv = MAX_VOLTAGE_MV * 1000,
+ .rconn_mohm = 18,
+ .shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
+ .chg_term_ua = CHG_TERM_MA * 1000,
};
static struct pm8921_platform_data
apq8064_pm8921_platform_data __devinitdata = {
- .regulator_pdatas = msm8064_pm8921_regulator_pdata,
.irq_pdata = &apq8064_pm8921_irq_pdata,
.gpio_pdata = &apq8064_pm8921_gpio_pdata,
.mpp_pdata = &apq8064_pm8921_mpp_pdata,
@@ -455,8 +478,17 @@
&apq8064_ssbi_pm8921_pdata;
apq8064_device_ssbi_pmic2.dev.platform_data =
&apq8064_ssbi_pm8821_pdata;
- apq8064_pm8921_platform_data.num_regulators =
- msm8064_pm8921_regulator_pdata_len;
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917) {
+ apq8064_pm8921_platform_data.regulator_pdatas
+ = msm8064_pm8921_regulator_pdata;
+ apq8064_pm8921_platform_data.num_regulators
+ = msm8064_pm8921_regulator_pdata_len;
+ } else {
+ apq8064_pm8921_platform_data.regulator_pdatas
+ = msm8064_pm8917_regulator_pdata;
+ apq8064_pm8921_platform_data.num_regulators
+ = msm8064_pm8917_regulator_pdata_len;
+ }
if (machine_is_apq8064_mtp()) {
apq8064_pm8921_bms_pdata.battery_type = BATT_PALLADIUM;
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 10b7034..819f5d9 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -18,6 +18,7 @@
#define VREG_CONSUMERS(_id) \
static struct regulator_consumer_supply vreg_consumers_##_id[]
+/* Regulators that are present when using either PM8921 or PM8917 */
/*
* Consumer specific regulator names:
* regulator name consumer dev_name
@@ -143,9 +144,6 @@
VREG_CONSUMERS(L29) = {
REGULATOR_SUPPLY("8921_l29", NULL),
};
-VREG_CONSUMERS(S1) = {
- REGULATOR_SUPPLY("8921_s1", NULL),
-};
VREG_CONSUMERS(S2) = {
REGULATOR_SUPPLY("8921_s2", NULL),
REGULATOR_SUPPLY("iris_vddrfa", "wcnss_wlan.0"),
@@ -195,10 +193,6 @@
REGULATOR_SUPPLY("8921_lvs1", NULL),
REGULATOR_SUPPLY("iris_vddio", "wcnss_wlan.0"),
};
-VREG_CONSUMERS(LVS2) = {
- REGULATOR_SUPPLY("8921_lvs2", NULL),
- REGULATOR_SUPPLY("iris_vdddig", "wcnss_wlan.0"),
-};
VREG_CONSUMERS(LVS3) = {
REGULATOR_SUPPLY("8921_lvs3", NULL),
};
@@ -228,13 +222,6 @@
REGULATOR_SUPPLY("8921_usb_otg", NULL),
REGULATOR_SUPPLY("vbus_otg", "msm_otg"),
};
-VREG_CONSUMERS(HDMI_MVS) = {
- REGULATOR_SUPPLY("8921_hdmi_mvs", NULL),
- REGULATOR_SUPPLY("hdmi_mvs", "hdmi_msm.0"),
-};
-VREG_CONSUMERS(NCP) = {
- REGULATOR_SUPPLY("8921_ncp", NULL),
-};
VREG_CONSUMERS(8821_S0) = {
REGULATOR_SUPPLY("8821_s0", NULL),
REGULATOR_SUPPLY("krait2", "acpuclk-8064"),
@@ -243,11 +230,6 @@
REGULATOR_SUPPLY("8821_s1", NULL),
REGULATOR_SUPPLY("krait3", "acpuclk-8064"),
};
-VREG_CONSUMERS(EXT_5V) = {
- REGULATOR_SUPPLY("ext_5v", NULL),
- REGULATOR_SUPPLY("ext_ddr3", NULL),
- REGULATOR_SUPPLY("vbus", "msm_ehci_host.0"),
-};
VREG_CONSUMERS(EXT_MPP8) = {
REGULATOR_SUPPLY("ext_mpp8", NULL),
REGULATOR_SUPPLY("vbus", "msm_ehci_host.1"),
@@ -281,6 +263,60 @@
REGULATOR_SUPPLY("avc_3p3v", NULL),
};
+/* Regulators that are only present when using PM8921 */
+VREG_CONSUMERS(S1) = {
+ REGULATOR_SUPPLY("8921_s1", NULL),
+};
+VREG_CONSUMERS(LVS2) = {
+ REGULATOR_SUPPLY("8921_lvs2", NULL),
+ REGULATOR_SUPPLY("iris_vdddig", "wcnss_wlan.0"),
+};
+VREG_CONSUMERS(HDMI_MVS) = {
+ REGULATOR_SUPPLY("8921_hdmi_mvs", NULL),
+ REGULATOR_SUPPLY("hdmi_mvs", "hdmi_msm.0"),
+};
+VREG_CONSUMERS(NCP) = {
+ REGULATOR_SUPPLY("8921_ncp", NULL),
+};
+VREG_CONSUMERS(EXT_5V) = {
+ REGULATOR_SUPPLY("ext_5v", NULL),
+ REGULATOR_SUPPLY("ext_ddr3", NULL),
+ REGULATOR_SUPPLY("vbus", "msm_ehci_host.0"),
+};
+
+/* Regulators that are only present when using PM8917 */
+VREG_CONSUMERS(8917_S1) = {
+ REGULATOR_SUPPLY("8921_s1", NULL),
+ REGULATOR_SUPPLY("iris_vdddig", "wcnss_wlan.0"),
+};
+VREG_CONSUMERS(L30) = {
+ REGULATOR_SUPPLY("8917_l30", NULL),
+};
+VREG_CONSUMERS(L31) = {
+ REGULATOR_SUPPLY("8917_l31", NULL),
+};
+VREG_CONSUMERS(L32) = {
+ REGULATOR_SUPPLY("8917_l32", NULL),
+};
+VREG_CONSUMERS(L33) = {
+ REGULATOR_SUPPLY("8917_l33", NULL),
+};
+VREG_CONSUMERS(L34) = {
+ REGULATOR_SUPPLY("8917_l34", NULL),
+};
+VREG_CONSUMERS(L35) = {
+ REGULATOR_SUPPLY("8917_l35", NULL),
+};
+VREG_CONSUMERS(L36) = {
+ REGULATOR_SUPPLY("8917_l36", NULL),
+};
+VREG_CONSUMERS(BOOST) = {
+ REGULATOR_SUPPLY("8917_boost", NULL),
+ REGULATOR_SUPPLY("ext_ddr3", NULL),
+ REGULATOR_SUPPLY("vbus", "msm_ehci_host.0"),
+ REGULATOR_SUPPLY("hdmi_mvs", "hdmi_msm.0"),
+};
+
#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
_apply_uV, _pull_down, _always_on, _supply_regulator, \
_system_uA, _enable_time, _reg_id) \
@@ -356,6 +392,12 @@
REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
_always_on, _supply_regulator, 0, _enable_time, _reg_id)
+#define PM8XXX_BOOST(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+ _supply_regulator, _reg_id) \
+ PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+ REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+ _always_on, _supply_regulator, 0, _enable_time, _reg_id)
+
/* Pin control initialization */
#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
_supply_regulator, _reg_id) \
@@ -553,6 +595,39 @@
PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1, 0, "ext_5v", 3),
};
+/* PM8917 regulator constraints */
+struct pm8xxx_regulator_platform_data
+msm8064_pm8917_regulator_pdata[] __devinitdata = {
+ /*
+ * ID name always_on pd min_uV max_uV en_t supply
+ * system_uA reg_ID
+ */
+ PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 375000, 1050000, 200, "8921_s7",
+ 0, 1),
+ PM8XXX_LDO(L30, "8917_l30", 0, 1, 1800000, 1800000, 200, NULL,
+ 0, 2),
+ PM8XXX_LDO(L31, "8917_l31", 0, 1, 1800000, 1800000, 200, NULL,
+ 0, 3),
+ PM8XXX_LDO(L32, "8917_l32", 0, 1, 2800000, 2800000, 200, NULL,
+ 0, 4),
+ PM8XXX_LDO(L33, "8917_l33", 0, 1, 2800000, 2800000, 200, NULL,
+ 0, 5),
+ PM8XXX_LDO(L34, "8917_l34", 0, 1, 1800000, 1800000, 200, NULL,
+ 0, 6),
+ PM8XXX_LDO(L35, "8917_l35", 0, 1, 3000000, 3000000, 200, NULL,
+ 0, 7),
+ PM8XXX_LDO(L36, "8917_l36", 0, 1, 1800000, 1800000, 200, NULL,
+ 0, 8),
+
+ /*
+ * ID name always_on min_uV max_uV en_t supply reg_ID
+ */
+ PM8XXX_BOOST(BOOST, "8917_boost", 0, 5000000, 5000000, 500, NULL, 9),
+
+ /* ID name always_on pd en_t supply reg_ID */
+ PM8XXX_VS300(USB_OTG, "8921_usb_otg", 0, 1, 0, "8917_boost", 10),
+};
+
static struct rpm_regulator_init_data
apq8064_rpm_regulator_init_data[] __devinitdata = {
/* ID a_on pd ss min_uV max_uV supply sys_uA freq fm ss_fm */
@@ -592,12 +667,17 @@
/* ID a_on pd ss supply */
RPM_VS(LVS1, 0, 1, 0, "8921_s4"),
- RPM_VS(LVS2, 0, 1, 0, "8921_s1"),
RPM_VS(LVS3, 0, 1, 0, "8921_s4"),
RPM_VS(LVS4, 0, 1, 0, "8921_s4"),
RPM_VS(LVS5, 0, 1, 0, "8921_s4"),
RPM_VS(LVS6, 0, 1, 0, "8921_s4"),
RPM_VS(LVS7, 0, 1, 1, "8921_s4"),
+};
+
+static struct rpm_regulator_init_data
+apq8064_rpm_regulator_pm8921_init_data[] __devinitdata = {
+ /* ID a_on pd ss supply */
+ RPM_VS(LVS2, 0, 1, 0, "8921_s1"),
/* ID a_on ss min_uV max_uV supply freq */
RPM_NCP(NCP, 0, 0, 1800000, 1800000, "8921_l6", 1p60),
@@ -605,6 +685,8 @@
int msm8064_pm8921_regulator_pdata_len __devinitdata =
ARRAY_SIZE(msm8064_pm8921_regulator_pdata);
+int msm8064_pm8917_regulator_pdata_len __devinitdata =
+ ARRAY_SIZE(msm8064_pm8917_regulator_pdata);
#define RPM_REG_MAP(_id, _sleep_also, _voter, _supply, _dev_name) \
{ \
@@ -641,3 +723,34 @@
.consumer_map = msm_rpm_regulator_consumer_mapping,
.consumer_map_len = ARRAY_SIZE(msm_rpm_regulator_consumer_mapping),
};
+
+/* Regulators that are only present when using PM8921 */
+struct rpm_regulator_platform_data
+apq8064_rpm_regulator_pm8921_pdata __devinitdata = {
+ .init_data = apq8064_rpm_regulator_pm8921_init_data,
+ .num_regulators = ARRAY_SIZE(apq8064_rpm_regulator_pm8921_init_data),
+ .version = RPM_VREG_VERSION_8960,
+ .vreg_id_vdd_mem = RPM_VREG_ID_PM8921_L24,
+ .vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3,
+ .requires_tcxo_workaround = true,
+};
+
+/*
+ * Fix up regulator consumer data that moves to a different regulator when
+ * PM8917 is used.
+ */
+void __init configure_apq8064_pm8917_power_grid(void)
+{
+ static struct rpm_regulator_init_data *rpm_data;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(apq8064_rpm_regulator_init_data); i++) {
+ rpm_data = &apq8064_rpm_regulator_init_data[i];
+ if (rpm_data->id == RPM_VREG_ID_PM8921_S1) {
+ rpm_data->init_data.consumer_supplies
+ = vreg_consumers_8917_S1;
+ rpm_data->init_data.num_consumer_supplies
+ = ARRAY_SIZE(vreg_consumers_8917_S1);
+ }
+ }
+}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 665b861..7070b42 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -95,7 +95,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define HOLE_SIZE 0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
+#define MSM_CONTIG_MEM_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000
#define MSM_ION_SF_SIZE 0
@@ -111,7 +111,7 @@
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
#else
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
+#define MSM_CONTIG_MEM_SIZE 0x110C000
#define MSM_ION_HEAP_NUM 1
#endif
@@ -133,14 +133,14 @@
#define PCIE_PWR_EN_PMIC_GPIO 13
#define PCIE_RST_N_PMIC_MPP 1
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
{
- pmem_kernel_ebi1_size = memparse(p, NULL);
+ msm_contig_mem_size = memparse(p, NULL);
return 0;
}
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
#endif
#ifdef CONFIG_ANDROID_PMEM
@@ -263,7 +263,7 @@
reserve_memory_for(&android_pmem_pdata);
reserve_memory_for(&android_pmem_audio_pdata);
#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
- apq8064_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+ apq8064_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
#endif /*CONFIG_ANDROID_PMEM*/
}
@@ -1022,7 +1022,7 @@
.micbias = {
.ldoh_v = TABLA_LDOH_2P85_V,
.cfilt1_mv = 1800,
- .cfilt2_mv = 1800,
+ .cfilt2_mv = 2700,
.cfilt3_mv = 1800,
.bias1_cfilt_sel = TABLA_CFILT1_SEL,
.bias2_cfilt_sel = TABLA_CFILT2_SEL,
@@ -1089,7 +1089,7 @@
.micbias = {
.ldoh_v = TABLA_LDOH_2P85_V,
.cfilt1_mv = 1800,
- .cfilt2_mv = 1800,
+ .cfilt2_mv = 2700,
.cfilt3_mv = 1800,
.bias1_cfilt_sel = TABLA_CFILT1_SEL,
.bias2_cfilt_sel = TABLA_CFILT2_SEL,
@@ -1181,13 +1181,18 @@
#define HAP_SHIFT_LVL_OE_GPIO PM8921_MPP_PM_TO_SYS(8)
#define ISA1200_HAP_EN_GPIO PM8921_GPIO_PM_TO_SYS(33)
#define ISA1200_HAP_LEN_GPIO PM8921_GPIO_PM_TO_SYS(20)
-#define ISA1200_HAP_CLK PM8921_GPIO_PM_TO_SYS(44)
+#define ISA1200_HAP_CLK_PM8921 PM8921_GPIO_PM_TO_SYS(44)
+#define ISA1200_HAP_CLK_PM8917 PM8921_GPIO_PM_TO_SYS(38)
static int isa1200_clk_enable(bool on)
{
+ unsigned int gpio = ISA1200_HAP_CLK_PM8921;
int rc = 0;
- gpio_set_value_cansleep(ISA1200_HAP_CLK, on);
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ gpio = ISA1200_HAP_CLK_PM8917;
+
+ gpio_set_value_cansleep(gpio, on);
if (on) {
rc = pm8xxx_aux_clk_control(CLK_MP3_2, XO_DIV_1, true);
@@ -1206,25 +1211,29 @@
return rc;
err_gpio_dis:
- gpio_set_value_cansleep(ISA1200_HAP_CLK, !on);
+ gpio_set_value_cansleep(gpio, !on);
return rc;
}
static int isa1200_dev_setup(bool enable)
{
+ unsigned int gpio = ISA1200_HAP_CLK_PM8921;
int rc = 0;
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ gpio = ISA1200_HAP_CLK_PM8917;
+
if (!enable)
goto free_gpio;
- rc = gpio_request(ISA1200_HAP_CLK, "haptics_clk");
+ rc = gpio_request(gpio, "haptics_clk");
if (rc) {
pr_err("%s: unable to request gpio %d config(%d)\n",
- __func__, ISA1200_HAP_CLK, rc);
+ __func__, gpio, rc);
return rc;
}
- rc = gpio_direction_output(ISA1200_HAP_CLK, 0);
+ rc = gpio_direction_output(gpio, 0);
if (rc) {
pr_err("%s: unable to set direction\n", __func__);
goto free_gpio;
@@ -1233,7 +1242,7 @@
return 0;
free_gpio:
- gpio_free(ISA1200_HAP_CLK);
+ gpio_free(gpio);
return rc;
}
@@ -2147,12 +2156,21 @@
static struct platform_device apq8064_device_rpm_regulator __devinitdata = {
.name = "rpm-regulator",
- .id = -1,
+ .id = 0,
.dev = {
.platform_data = &apq8064_rpm_regulator_pdata,
},
};
+static struct platform_device
+apq8064_pm8921_device_rpm_regulator __devinitdata = {
+ .name = "rpm-regulator",
+ .id = 1,
+ .dev = {
+ .platform_data = &apq8064_rpm_regulator_pm8921_pdata,
+ },
+};
+
static struct gpio_ir_recv_platform_data gpio_ir_recv_pdata = {
.gpio_nr = 88,
.active_low = 1,
@@ -2171,16 +2189,30 @@
&apq8064_device_qup_i2c_gsbi4,
};
-static struct platform_device *common_devices[] __initdata = {
+static struct platform_device *early_common_devices[] __initdata = {
&apq8064_device_acpuclk,
&apq8064_device_dmov,
&apq8064_device_qup_spi_gsbi5,
+};
+
+static struct platform_device *pm8921_common_devices[] __initdata = {
&apq8064_device_ext_5v_vreg,
&apq8064_device_ext_mpp8_vreg,
&apq8064_device_ext_3p3v_vreg,
&apq8064_device_ssbi_pmic1,
&apq8064_device_ssbi_pmic2,
&apq8064_device_ext_ts_sw_vreg,
+};
+
+static struct platform_device *pm8917_common_devices[] __initdata = {
+ &apq8064_device_ext_mpp8_vreg,
+ &apq8064_device_ext_3p3v_vreg,
+ &apq8064_device_ssbi_pmic1,
+ &apq8064_device_ssbi_pmic2,
+ &apq8064_device_ext_ts_sw_vreg,
+};
+
+static struct platform_device *common_devices[] __initdata = {
&msm_device_smd_apq8064,
&apq8064_device_otg,
&apq8064_device_gadget_peripheral,
@@ -2242,6 +2274,7 @@
&apq_lpa_pcm,
&apq_compr_dsp,
&apq_multi_ch_pcm,
+ &apq_lowlatency_pcm,
&apq_pcm_hostless,
&apq_cpudai_afe_01_rx,
&apq_cpudai_afe_01_tx,
@@ -2292,6 +2325,7 @@
&apq8064_iommu_domain_device,
&msm_tsens_device,
&apq8064_cache_dump_device,
+ &msm_8064_device_tspp,
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -2504,14 +2538,16 @@
}
#endif
-#define GPIO_KEY_HOME PM8921_GPIO_PM_TO_SYS(27)
-#define GPIO_KEY_VOLUME_UP PM8921_GPIO_PM_TO_SYS(35)
-#define GPIO_KEY_VOLUME_DOWN PM8921_GPIO_PM_TO_SYS(38)
-#define GPIO_KEY_CAM_FOCUS PM8921_GPIO_PM_TO_SYS(3)
-#define GPIO_KEY_CAM_SNAP PM8921_GPIO_PM_TO_SYS(4)
-#define GPIO_KEY_ROTATION PM8921_GPIO_PM_TO_SYS(42)
+#define GPIO_KEY_HOME PM8921_GPIO_PM_TO_SYS(27)
+#define GPIO_KEY_VOLUME_UP PM8921_GPIO_PM_TO_SYS(35)
+#define GPIO_KEY_VOLUME_DOWN_PM8921 PM8921_GPIO_PM_TO_SYS(38)
+#define GPIO_KEY_VOLUME_DOWN_PM8917 PM8921_GPIO_PM_TO_SYS(30)
+#define GPIO_KEY_CAM_FOCUS PM8921_GPIO_PM_TO_SYS(3)
+#define GPIO_KEY_CAM_SNAP PM8921_GPIO_PM_TO_SYS(4)
+#define GPIO_KEY_ROTATION_PM8921 PM8921_GPIO_PM_TO_SYS(42)
+#define GPIO_KEY_ROTATION_PM8917 PM8921_GPIO_PM_TO_SYS(8)
-static struct gpio_keys_button cdp_keys[] = {
+static struct gpio_keys_button cdp_keys_pm8921[] = {
{
.code = KEY_HOME,
.gpio = GPIO_KEY_HOME,
@@ -2532,7 +2568,7 @@
},
{
.code = KEY_VOLUMEDOWN,
- .gpio = GPIO_KEY_VOLUME_DOWN,
+ .gpio = GPIO_KEY_VOLUME_DOWN_PM8921,
.desc = "volume_down_key",
.active_low = 1,
.type = EV_KEY,
@@ -2541,7 +2577,45 @@
},
{
.code = SW_ROTATE_LOCK,
- .gpio = GPIO_KEY_ROTATION,
+ .gpio = GPIO_KEY_ROTATION_PM8921,
+ .desc = "rotate_key",
+ .active_low = 1,
+ .type = EV_SW,
+ .debounce_interval = 15,
+ },
+};
+
+static struct gpio_keys_button cdp_keys_pm8917[] = {
+ {
+ .code = KEY_HOME,
+ .gpio = GPIO_KEY_HOME,
+ .desc = "home_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEUP,
+ .gpio = GPIO_KEY_VOLUME_UP,
+ .desc = "volume_up_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = KEY_VOLUMEDOWN,
+ .gpio = GPIO_KEY_VOLUME_DOWN_PM8917,
+ .desc = "volume_down_key",
+ .active_low = 1,
+ .type = EV_KEY,
+ .wakeup = 1,
+ .debounce_interval = 15,
+ },
+ {
+ .code = SW_ROTATE_LOCK,
+ .gpio = GPIO_KEY_ROTATION_PM8917,
.desc = "rotate_key",
.active_low = 1,
.type = EV_SW,
@@ -2550,8 +2624,8 @@
};
static struct gpio_keys_platform_data cdp_keys_data = {
- .buttons = cdp_keys,
- .nbuttons = ARRAY_SIZE(cdp_keys),
+ .buttons = cdp_keys_pm8921,
+ .nbuttons = ARRAY_SIZE(cdp_keys_pm8921),
};
static struct platform_device cdp_kp_pdev = {
@@ -2583,7 +2657,7 @@
},
{
.code = KEY_VOLUMEDOWN,
- .gpio = GPIO_KEY_VOLUME_DOWN,
+ .gpio = GPIO_KEY_VOLUME_DOWN_PM8921,
.desc = "volume_down_key",
.active_low = 1,
.type = EV_KEY,
@@ -2616,7 +2690,7 @@
static struct gpio_keys_button mpq_keys[] = {
{
.code = KEY_VOLUMEDOWN,
- .gpio = GPIO_KEY_VOLUME_DOWN,
+ .gpio = GPIO_KEY_VOLUME_DOWN_PM8921,
.desc = "volume_down_key",
.active_low = 1,
.type = EV_KEY,
@@ -2910,9 +2984,19 @@
gpio_set_value_cansleep(avc_i2c_en_mpp, 1);
}
+/* Modify platform data values to match requirements for PM8917. */
+static void __init apq8064_pm8917_pdata_fixup(void)
+{
+ cdp_keys_data.buttons = cdp_keys_pm8917;
+ cdp_keys_data.nbuttons = ARRAY_SIZE(cdp_keys_pm8917);
+}
+
static void __init apq8064_common_init(void)
{
u32 platform_version;
+
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ apq8064_pm8917_pdata_fixup();
platform_device_register(&msm_gpio_device);
msm_tsens_early_init(&apq_tsens_pdata);
msm_thermal_init(&msm_thermal_pdata);
@@ -2921,7 +3005,11 @@
BUG_ON(msm_rpm_init(&apq8064_rpm_data));
BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
regulator_suppress_info_printing();
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ configure_apq8064_pm8917_power_grid();
platform_device_register(&apq8064_device_rpm_regulator);
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+ platform_device_register(&apq8064_pm8921_device_rpm_regulator);
if (msm_xo_init())
pr_err("Failed to initialize XO votes\n");
msm_clock_init(&apq8064_clock_init_data);
@@ -2941,6 +3029,15 @@
apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
apq8064_ehci_host_init();
apq8064_init_buses();
+
+ platform_add_devices(early_common_devices,
+ ARRAY_SIZE(early_common_devices));
+ if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
+ platform_add_devices(pm8921_common_devices,
+ ARRAY_SIZE(pm8921_common_devices));
+ else
+ platform_add_devices(pm8917_common_devices,
+ ARRAY_SIZE(pm8917_common_devices));
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
machine_is_mpq8064_dtv()))
@@ -2948,6 +3045,7 @@
ARRAY_SIZE(common_not_mpq_devices));
enable_ddr3_regulator();
if (machine_is_apq8064_mtp()) {
+ msm_hsic_pdata.log2_irq_thresh = 5,
apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
device_initialize(&apq8064_device_hsic_host.dev);
}
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 2258b8d..1437b3b 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -40,6 +40,11 @@
extern int msm8064_pm8921_regulator_pdata_len __devinitdata;
+extern struct pm8xxx_regulator_platform_data
+ msm8064_pm8917_regulator_pdata[] __devinitdata;
+
+extern int msm8064_pm8917_regulator_pdata_len __devinitdata;
+
#define GPIO_VREG_ID_EXT_5V 0
#define GPIO_VREG_ID_EXT_3P3V 1
#define GPIO_VREG_ID_EXT_TS_SW 2
@@ -62,6 +67,9 @@
extern struct rpm_regulator_platform_data
apq8064_rpm_regulator_pdata __devinitdata;
+extern struct rpm_regulator_platform_data
+ apq8064_rpm_regulator_pm8921_pdata __devinitdata;
+
extern struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5;
extern struct regulator_init_data msm8064_saw_regulator_pdata_8921_s6;
extern struct regulator_init_data msm8064_saw_regulator_pdata_8821_s0;
@@ -84,6 +92,7 @@
#define APQ_8064_GSBI5_QUP_I2C_BUS_ID 5
unsigned char apq8064_hdmi_as_primary_selected(void);
+unsigned char apq8064_mhl_display_enabled(void);
void apq8064_init_fb(void);
void apq8064_allocate_fb_region(void);
void apq8064_mdp_writeback(struct memtype_reserve *reserve_table);
@@ -92,6 +101,7 @@
void apq8064_init_gpu(void);
void apq8064_pm8xxx_gpio_mpp_init(void);
+void __init configure_apq8064_pm8917_power_grid(void);
#define PLATFORM_IS_MPQ8064() \
(machine_is_mpq8064_hrd() || \
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index d3e37cd..1352928 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -13,7 +13,7 @@
#include <asm/mach-types.h>
#include <linux/gpio.h>
-#include <mach/board.h>
+#include <mach/camera.h>
#include <mach/msm_bus_board.h>
#include <mach/gpiomux.h>
#include "devices.h"
@@ -377,19 +377,13 @@
},
};
-static struct camera_vreg_t msm_8930_back_cam_vreg[] = {
+static struct camera_vreg_t msm_8930_cam_vreg[] = {
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
{"cam_vio", REG_VS, 0, 0, 0},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
{"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
};
-static struct camera_vreg_t msm_8930_front_cam_vreg[] = {
- {"cam_vio", REG_VS, 0, 0, 0},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-};
-
static struct gpio msm8930_common_cam_gpio[] = {
{20, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
{21, GPIOF_DIR_IN, "CAMIF_I2C_CLK"},
@@ -466,8 +460,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
.mount_angle = 90,
- .cam_vreg = msm_8930_back_cam_vreg,
- .num_vreg = ARRAY_SIZE(msm_8930_back_cam_vreg),
+ .cam_vreg = msm_8930_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8930_cam_vreg),
.gpio_conf = &msm_8930_back_cam_gpio_conf,
.csi_lane_params = &imx074_csi_lane_params,
};
@@ -484,13 +478,6 @@
.actuator_info = &msm_act_main_cam_0_info,
};
-static struct camera_vreg_t msm_8930_mt9m114_vreg[] = {
- {"cam_vio", REG_VS, 0, 0, 0},
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-};
-
static struct msm_camera_sensor_flash_data flash_mt9m114 = {
.flash_type = MSM_CAMERA_FLASH_NONE
};
@@ -502,8 +489,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
.mount_angle = 90,
- .cam_vreg = msm_8930_mt9m114_vreg,
- .num_vreg = ARRAY_SIZE(msm_8930_mt9m114_vreg),
+ .cam_vreg = msm_8930_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8930_cam_vreg),
.gpio_conf = &msm_8930_front_cam_gpio_conf,
.csi_lane_params = &mt9m114_csi_lane_params,
};
@@ -529,8 +516,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
.mount_angle = 0,
- .cam_vreg = msm_8930_front_cam_vreg,
- .num_vreg = ARRAY_SIZE(msm_8930_front_cam_vreg),
+ .cam_vreg = msm_8930_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8930_cam_vreg),
.gpio_conf = &msm_8930_front_cam_gpio_conf,
.csi_lane_params = &ov2720_csi_lane_params,
};
@@ -545,13 +532,6 @@
.sensor_type = BAYER_SENSOR,
};
-static struct camera_vreg_t msm_8930_s5k3l1yx_vreg[] = {
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vio", REG_VS, 0, 0, 0},
- {"cam_vaf", REG_LDO, 2800000, 2850000, 300000},
-};
-
static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
.flash_type = MSM_CAMERA_FLASH_LED,
.flash_src = &msm_flash_src
@@ -564,8 +544,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
.mount_angle = 90,
- .cam_vreg = msm_8930_s5k3l1yx_vreg,
- .num_vreg = ARRAY_SIZE(msm_8930_s5k3l1yx_vreg),
+ .cam_vreg = msm_8930_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8930_cam_vreg),
.gpio_conf = &msm_8930_back_cam_gpio_conf,
.csi_lane_params = &s5k3l1yx_csi_lane_params,
};
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index d975997..2a8e918 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -413,31 +413,9 @@
#endif
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static int mdp_core_clk_rate_table[] = {
- 200000000,
- 200000000,
- 200000000,
- 200000000,
-};
-#else
-static int mdp_core_clk_rate_table[] = {
- 85330000,
- 128000000,
- 160000000,
- 200000000,
-};
-#endif
-
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- .mdp_core_clk_rate = 200000000,
-#else
- .mdp_core_clk_rate = 85330000,
-#endif
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+ .mdp_max_clk = 200000000,
#ifdef CONFIG_MSM_BUS_SCALING
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
#endif
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index e0f012a..74dfca1 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -45,14 +45,14 @@
static struct gpiomux_setting gsbi5 = {
.func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting gsbi9 = {
.func = GPIOMUX_FUNC_2,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting gsbi10 = {
@@ -96,14 +96,20 @@
static struct gpiomux_setting audio_spkr_boost = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_NONE,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
};
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
-static struct gpiomux_setting gpio_eth_config = {
+static struct gpiomux_setting gpio_eth_suspend_1_cfg = {
+ .pull = GPIOMUX_PULL_DOWN,
+ .drv = GPIOMUX_DRV_2MA,
+ .func = GPIOMUX_FUNC_GPIO,
+};
+
+static struct gpiomux_setting gpio_eth_suspend_2_cfg = {
.pull = GPIOMUX_PULL_NONE,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_2MA,
.func = GPIOMUX_FUNC_GPIO,
};
#endif
@@ -277,15 +283,15 @@
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
{
- .gpio = 90,
+ .gpio = 89,
.settings = {
- [GPIOMUX_SUSPENDED] = &gpio_eth_config,
+ [GPIOMUX_SUSPENDED] = &gpio_eth_suspend_1_cfg,
}
},
{
- .gpio = 89,
+ .gpio = 90,
.settings = {
- [GPIOMUX_SUSPENDED] = &gpio_eth_config,
+ [GPIOMUX_SUSPENDED] = &gpio_eth_suspend_2_cfg,
}
},
};
@@ -688,6 +694,22 @@
},
};
+static struct gpiomux_setting gyro_int_line = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm8930_gyro_int_config[] __initdata = {
+ {
+ .gpio = 69, /* Gyro Interrupt Line */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gyro_int_line,
+ [GPIOMUX_ACTIVE] = &gyro_int_line,
+ },
+ },
+};
+
int __init msm8930_init_gpiomux(void)
{
int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -758,5 +780,9 @@
msm_gpiomux_install(msm8930_sd_det_config,
ARRAY_SIZE(msm8930_sd_det_config));
+ if (machine_is_msm8930_fluid() || machine_is_msm8930_mtp())
+ msm_gpiomux_install(msm8930_gyro_int_config,
+ ARRAY_SIZE(msm8930_gyro_int_config));
+
return 0;
}
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index a1a4b7c..e3479eb 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -207,6 +207,7 @@
};
#define MAX_VOLTAGE_MV 4200
+#define CHG_TERM_MA 100
static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
.safety_time = 180,
.update_time = 60000,
@@ -214,7 +215,7 @@
.min_voltage = 3200,
.uvd_thresh_voltage = 4050,
.resume_voltage_delta = 100,
- .term_current = 100,
+ .term_current = CHG_TERM_MA,
.cool_temp = 10,
.warm_temp = 40,
.temp_check_period = 1,
@@ -340,11 +341,13 @@
};
static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
- .battery_type = BATT_UNKNOWN,
- .r_sense = 10,
- .i_test = 2500,
- .v_failure = 3000,
- .max_voltage_uv = MAX_VOLTAGE_MV * 1000,
+ .battery_type = BATT_UNKNOWN,
+ .r_sense = 10,
+ .v_cutoff = 3400,
+ .max_voltage_uv = MAX_VOLTAGE_MV * 1000,
+ .shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
+ .chg_term_ua = CHG_TERM_MA * 1000,
};
static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index b80d62d..a7147b5 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -141,7 +141,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define HOLE_SIZE 0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
+#define MSM_CONTIG_MEM_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
#define MSM_ION_SF_SIZE 0x0
@@ -168,18 +168,18 @@
#define MSM8930_FW_START MSM8930_FIXED_AREA_START
#else
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
+#define MSM_CONTIG_MEM_SIZE 0x110C000
#define MSM_ION_HEAP_NUM 1
#endif
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
{
- pmem_kernel_ebi1_size = memparse(p, NULL);
+ msm_contig_mem_size = memparse(p, NULL);
return 0;
}
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
#endif
#ifdef CONFIG_ANDROID_PMEM
@@ -322,7 +322,7 @@
reserve_memory_for(&android_pmem_pdata);
reserve_memory_for(&android_pmem_audio_pdata);
#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
- msm8930_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+ msm8930_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
#endif /*CONFIG_ANDROID_PMEM*/
}
@@ -2297,6 +2297,8 @@
&msm_cpudai_incall_record_rx,
&msm_cpudai_incall_record_tx,
&msm_pcm_hostless,
+ &msm_multi_ch_pcm,
+ &msm_lowlatency_pcm,
};
static void __init msm8930_i2c_init(void)
@@ -2431,6 +2433,7 @@
static struct i2c_board_info __initdata mpu3050_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("mpu3050", 0x68),
+ .irq = MSM_GPIO_TO_INT(MPU3050_INT_GPIO),
.platform_data = &mpu3050_gyro,
},
};
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index a21c4c3..c00535b 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -13,7 +13,7 @@
#include <asm/mach-types.h>
#include <linux/gpio.h>
-#include <mach/board.h>
+#include <mach/camera.h>
#include <mach/msm_bus_board.h>
#include <mach/gpiomux.h>
#include "devices.h"
@@ -452,19 +452,13 @@
},
};
-static struct camera_vreg_t msm_8960_back_cam_vreg[] = {
+static struct camera_vreg_t msm_8960_cam_vreg[] = {
{"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
{"cam_vio", REG_VS, 0, 0, 0},
{"cam_vana", REG_LDO, 2800000, 2850000, 85600},
{"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
};
-static struct camera_vreg_t msm_8960_front_cam_vreg[] = {
- {"cam_vio", REG_VS, 0, 0, 0},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
-};
-
static struct gpio msm8960_common_cam_gpio[] = {
{5, GPIOF_DIR_IN, "CAMIF_MCLK"},
{20, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
@@ -549,8 +543,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
.mount_angle = 90,
- .cam_vreg = msm_8960_back_cam_vreg,
- .num_vreg = ARRAY_SIZE(msm_8960_back_cam_vreg),
+ .cam_vreg = msm_8960_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8960_cam_vreg),
.gpio_conf = &msm_8960_back_cam_gpio_conf,
.csi_lane_params = &imx074_csi_lane_params,
};
@@ -577,13 +571,6 @@
.eeprom_info = &imx074_eeprom_info,
};
-static struct camera_vreg_t msm_8960_mt9m114_vreg[] = {
- {"cam_vio", REG_VS, 0, 0, 0},
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
-};
-
static struct msm_camera_sensor_flash_data flash_mt9m114 = {
.flash_type = MSM_CAMERA_FLASH_NONE
};
@@ -593,10 +580,16 @@
.csi_lane_mask = 0x1,
};
+static struct camera_vreg_t mt9m114_cam_vreg[] = {
+ {"cam_vdig", REG_LDO, 1200000, 1200000, 105000, 50},
+ {"cam_vio", REG_VS, 0, 0, 0, 50},
+ {"cam_vana", REG_LDO, 2800000, 2850000, 85600, 50},
+};
+
static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
.mount_angle = 90,
- .cam_vreg = msm_8960_mt9m114_vreg,
- .num_vreg = ARRAY_SIZE(msm_8960_mt9m114_vreg),
+ .cam_vreg = mt9m114_cam_vreg,
+ .num_vreg = ARRAY_SIZE(mt9m114_cam_vreg),
.gpio_conf = &msm_8960_front_cam_gpio_conf,
.csi_lane_params = &mt9m114_csi_lane_params,
};
@@ -622,8 +615,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_ov2720 = {
.mount_angle = 0,
- .cam_vreg = msm_8960_front_cam_vreg,
- .num_vreg = ARRAY_SIZE(msm_8960_front_cam_vreg),
+ .cam_vreg = msm_8960_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8960_cam_vreg),
.gpio_conf = &msm_8960_front_cam_gpio_conf,
.csi_lane_params = &ov2720_csi_lane_params,
};
@@ -638,13 +631,6 @@
.sensor_type = BAYER_SENSOR,
};
-static struct camera_vreg_t msm_8960_s5k3l1yx_vreg[] = {
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vio", REG_VS, 0, 0, 0},
- {"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
-};
-
static struct msm_camera_sensor_flash_data flash_s5k3l1yx = {
.flash_type = MSM_CAMERA_FLASH_NONE,
};
@@ -656,8 +642,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
.mount_angle = 0,
- .cam_vreg = msm_8960_s5k3l1yx_vreg,
- .num_vreg = ARRAY_SIZE(msm_8960_s5k3l1yx_vreg),
+ .cam_vreg = msm_8960_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8960_cam_vreg),
.gpio_conf = &msm_8960_back_cam_gpio_conf,
.csi_lane_params = &s5k3l1yx_csi_lane_params,
};
@@ -686,13 +672,6 @@
.csi_lane_mask = 0xF,
};
-static struct camera_vreg_t msm_8960_imx091_vreg[] = {
- {"cam_vana", REG_LDO, 2800000, 2850000, 85600},
- {"cam_vaf", REG_LDO, 2800000, 2800000, 300000},
- {"cam_vdig", REG_LDO, 1200000, 1200000, 105000},
- {"cam_vio", REG_VS, 0, 0, 0},
-};
-
static struct msm_camera_sensor_flash_data flash_imx091 = {
.flash_type = MSM_CAMERA_FLASH_LED,
#ifdef CONFIG_MSM_CAMERA_FLASH
@@ -702,8 +681,8 @@
static struct msm_camera_sensor_platform_info sensor_board_info_imx091 = {
.mount_angle = 0,
- .cam_vreg = msm_8960_imx091_vreg,
- .num_vreg = ARRAY_SIZE(msm_8960_imx091_vreg),
+ .cam_vreg = msm_8960_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8960_cam_vreg),
.gpio_conf = &msm_8960_back_cam_gpio_conf,
.csi_lane_params = &imx091_csi_lane_params,
};
@@ -715,6 +694,9 @@
static struct msm_eeprom_info imx091_eeprom_info = {
.board_info = &imx091_eeprom_i2c_info,
.bus_id = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+ .eeprom_i2c_slave_addr = 0xA1,
+ .eeprom_reg_addr = 0x05,
+ .eeprom_read_length = 6,
};
static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index ddeba32..f993ed8 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -573,18 +573,9 @@
#endif
-static int mdp_core_clk_rate_table[] = {
- 85330000,
- 128000000,
- 160000000,
- 200000000,
-};
-
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
- .mdp_core_clk_rate = 85330000,
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+ .mdp_max_clk = 200000000,
#ifdef CONFIG_MSM_BUS_SCALING
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
#endif
@@ -1043,8 +1034,6 @@
*/
static void set_mdp_clocks_for_wuxga(void)
{
- int i;
-
mdp_ui_vectors[0].ab = 2000000000;
mdp_ui_vectors[0].ib = 2000000000;
mdp_vga_vectors[0].ab = 2000000000;
@@ -1054,11 +1043,6 @@
mdp_1080p_vectors[0].ab = 2000000000;
mdp_1080p_vectors[0].ib = 2000000000;
- mdp_pdata.mdp_core_clk_rate = 200000000;
-
- for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
- mdp_core_clk_rate_table[i] = 200000000;
-
if (hdmi_is_primary) {
dtv_bus_def_vectors[0].ab = 2000000000;
dtv_bus_def_vectors[0].ib = 2000000000;
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 5950026..8d75ee9 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -394,6 +394,7 @@
};
#define MAX_VOLTAGE_MV 4200
+#define CHG_TERM_MA 100
static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
.safety_time = 180,
.update_time = 60000,
@@ -401,7 +402,7 @@
.min_voltage = 3200,
.uvd_thresh_voltage = 4050,
.resume_voltage_delta = 100,
- .term_current = 100,
+ .term_current = CHG_TERM_MA,
.cool_temp = 10,
.warm_temp = 40,
.temp_check_period = 1,
@@ -420,12 +421,14 @@
};
static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
- .battery_type = BATT_UNKNOWN,
- .r_sense = 10,
- .i_test = 2500,
- .v_failure = 3000,
- .max_voltage_uv = MAX_VOLTAGE_MV * 1000,
- .rconn_mohm = 18,
+ .battery_type = BATT_UNKNOWN,
+ .r_sense = 10,
+ .v_cutoff = 3400,
+ .max_voltage_uv = MAX_VOLTAGE_MV * 1000,
+ .rconn_mohm = 18,
+ .shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
+ .chg_term_ua = CHG_TERM_MA * 1000,
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 6ad44d8..bcfd558 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -182,10 +182,12 @@
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8921_s5", NULL),
REGULATOR_SUPPLY("krait0", "acpuclk-8960"),
+ REGULATOR_SUPPLY("krait0", "acpuclk-8960ab"),
};
VREG_CONSUMERS(S6) = {
REGULATOR_SUPPLY("8921_s6", NULL),
REGULATOR_SUPPLY("krait1", "acpuclk-8960"),
+ REGULATOR_SUPPLY("krait1", "acpuclk-8960ab"),
};
VREG_CONSUMERS(S7) = {
REGULATOR_SUPPLY("8921_s7", NULL),
@@ -581,6 +583,17 @@
RPM_REG_MAP(S8, 0, 1, "krait0_s8", "acpuclk-8960"),
RPM_REG_MAP(S8, 0, 2, "krait1_s8", "acpuclk-8960"),
RPM_REG_MAP(S8, 0, 6, "l2_s8", "acpuclk-8960"),
+
+ RPM_REG_MAP(L23, 0, 1, "krait0_l23", "acpuclk-8960ab"),
+ RPM_REG_MAP(L23, 0, 2, "krait1_l23", "acpuclk-8960ab"),
+ RPM_REG_MAP(L23, 0, 6, "l2_l23", "acpuclk-8960ab"),
+ RPM_REG_MAP(L24, 0, 1, "krait0_mem", "acpuclk-8960ab"),
+ RPM_REG_MAP(L24, 0, 2, "krait1_mem", "acpuclk-8960ab"),
+ RPM_REG_MAP(S3, 0, 1, "krait0_dig", "acpuclk-8960ab"),
+ RPM_REG_MAP(S3, 0, 2, "krait1_dig", "acpuclk-8960ab"),
+ RPM_REG_MAP(S8, 0, 1, "krait0_s8", "acpuclk-8960ab"),
+ RPM_REG_MAP(S8, 0, 2, "krait1_s8", "acpuclk-8960ab"),
+ RPM_REG_MAP(S8, 0, 6, "l2_s8", "acpuclk-8960ab"),
};
struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index ad788bc..4263cd6 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -145,7 +145,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define HOLE_SIZE 0x20000
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
+#define MSM_CONTIG_MEM_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
#define MSM_ION_SF_SIZE 0x0
@@ -173,18 +173,18 @@
static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
#else
-#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
+#define MSM_CONTIG_MEM_SIZE 0x110C000
#define MSM_ION_HEAP_NUM 1
#endif
-#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
+#ifdef CONFIG_KERNEL_MSM_CONTIG_MEM_REGION
+static unsigned msm_contig_mem_size = MSM_CONTIG_MEM_SIZE;
+static int __init msm_contig_mem_size_setup(char *p)
{
- pmem_kernel_ebi1_size = memparse(p, NULL);
+ msm_contig_mem_size = memparse(p, NULL);
return 0;
}
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+early_param("msm_contig_mem_size", msm_contig_mem_size_setup);
#endif
#ifdef CONFIG_ANDROID_PMEM
@@ -336,7 +336,7 @@
reserve_memory_for(&android_pmem_pdata);
reserve_memory_for(&android_pmem_audio_pdata);
#endif
- msm8960_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+ msm8960_reserve_table[MEMTYPE_EBI1].size += msm_contig_mem_size;
#endif
}
@@ -2594,7 +2594,6 @@
#endif
static struct platform_device *common_devices[] __initdata = {
- &msm8960_device_acpuclk,
&msm8960_device_dmov,
&msm_device_smd,
&msm_device_uart_dm6,
@@ -2643,7 +2642,6 @@
&msm8960_android_pmem_audio_device,
#endif
#endif
- &msm_device_vidc,
&msm_device_bam_dmux,
&msm_fm_platform_init,
#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
@@ -2696,6 +2694,7 @@
&android_usb_device,
&msm_pcm,
&msm_multi_ch_pcm,
+ &msm_lowlatency_pcm,
&msm_pcm_routing,
&msm_cpudai0,
&msm_cpudai1,
@@ -2710,11 +2709,6 @@
&msm_cpudai_auxpcm_tx,
&msm_cpu_fe,
&msm_stub_codec,
- &msm_kgsl_3d0,
-#ifdef CONFIG_MSM_KGSL_2D
- &msm_kgsl_2d0,
- &msm_kgsl_2d1,
-#endif
#ifdef CONFIG_MSM_GEMINI
&msm8960_gemini_device,
#endif
@@ -2762,21 +2756,26 @@
msm_kgsl_3d0.dev.platform_data;
uint32_t soc_platform_version = socinfo_get_version();
- if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
- kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
- kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
- }
if (cpu_is_msm8960ab()) {
kgsl_3d0_pdata->chipid = ADRENO_CHIPID(3, 2, 1, 0);
- } else {
-
+ } else if (SOCINFO_VERSION_MAJOR(soc_platform_version) == 1) {
+ kgsl_3d0_pdata->pwrlevel[0].gpu_freq = 320000000;
+ kgsl_3d0_pdata->pwrlevel[1].gpu_freq = 266667000;
+ } else if (SOCINFO_VERSION_MAJOR(soc_platform_version) >= 3) {
/* 8960v3 GPU registers returns 5 for patch release
* but it should be 6, so dummy up the chipid here
* based the platform type
*/
+ kgsl_3d0_pdata->chipid = ADRENO_CHIPID(2, 2, 0, 6);
+ }
- if (SOCINFO_VERSION_MAJOR(soc_platform_version) >= 3)
- kgsl_3d0_pdata->chipid = ADRENO_CHIPID(2, 2, 0, 6);
+ /* Register the 3D core */
+ platform_device_register(&msm_kgsl_3d0);
+
+ /* Register the 2D cores if we are not 8960PRO */
+ if (!cpu_is_msm8960ab()) {
+ platform_device_register(&msm_kgsl_2d0);
+ platform_device_register(&msm_kgsl_2d1);
}
}
@@ -3148,7 +3147,13 @@
msm_device_uart_dm8.dev.platform_data = &msm_uart_dm8_pdata;
platform_device_register(&msm_device_uart_dm8);
}
+ if (cpu_is_msm8960ab())
+ platform_device_register(&msm8960ab_device_acpuclk);
+ else
+ platform_device_register(&msm8960_device_acpuclk);
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+ msm8960_add_vidc_device();
+
msm8960_pm8921_gpio_mpp_init();
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
msm8960_init_smsc_hub();
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index d986670..8f1c619 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -92,3 +92,4 @@
extern struct msm_rtb_platform_data msm8960_rtb_pdata;
extern struct msm_cache_dump_platform_data msm8960_cache_dump_pdata;
+extern void msm8960_add_vidc_device(void);
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index bf80262..a2087e4 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -26,6 +26,12 @@
.dir = GPIOMUX_OUT_HIGH,
};
+static struct gpiomux_setting slimbus = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+};
+
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
static struct gpiomux_setting gpio_eth_config = {
.pull = GPIOMUX_PULL_NONE,
@@ -60,7 +66,59 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting lcd_en_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+static struct gpiomux_setting lcd_en_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_resout_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_resout_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_int_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_int_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm_touch_configs[] __initdata = {
+ {
+ .gpio = 60, /* TOUCH RESET */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &atmel_resout_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_resout_sus_cfg,
+ },
+ },
+ {
+ .gpio = 61, /* TOUCH IRQ */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &atmel_int_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_int_sus_cfg,
+ },
+ },
+
+};
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
{
@@ -89,6 +147,25 @@
},
#endif
{
+ .gpio = 58,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &lcd_en_act_cfg,
+ [GPIOMUX_SUSPENDED] = &lcd_en_sus_cfg,
+ },
+ },
+ {
+ .gpio = 6, /* BLSP1 QUP2 I2C_DAT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
+ .gpio = 7, /* BLSP1 QUP2 I2C_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
.gpio = 83, /* BLSP11 QUP I2C_DAT */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
@@ -114,6 +191,170 @@
},
};
+static struct msm_gpiomux_config msm8974_slimbus_config[] __initdata = {
+ {
+ .gpio = 70, /* slimbus clk */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &slimbus,
+ },
+ },
+ {
+ .gpio = 71, /* slimbus data */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &slimbus,
+ },
+ },
+};
+
+static struct gpiomux_setting cam_settings[] = {
+ {
+ .func = GPIOMUX_FUNC_1, /*active 1*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_1, /*suspend*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_1, /*i2c suspend*/
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+ },
+};
+
+static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
+ {
+ .gpio = 15, /* CAM_MCLK0 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 16, /* CAM_MCLK1 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 17, /* CAM_MCLK2 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 18, /* WEBCAM1_RESET_N / CAM_MCLK3 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 19, /* CCI_I2C_SDA0 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[2],
+ },
+ },
+ {
+ .gpio = 20, /* CCI_I2C_SCL0 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[2],
+ },
+ },
+ {
+ .gpio = 21, /* CCI_I2C_SDA1 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[2],
+ },
+ },
+ {
+ .gpio = 22, /* CCI_I2C_SCL1 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[2],
+ },
+ },
+ {
+ .gpio = 23, /* FLASH_LED_EN */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 24, /* FLASH_LED_NOW */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 25, /* WEBCAM2_RESET_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 26, /* CAM_IRQ */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 27, /* OIS_SYNC */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 28, /* WEBCAM1_STANDBY */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 89, /* CAM1_STANDBY_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 90, /* CAM1_RST_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 91, /* CAM2_STANDBY_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 92, /* CAM2_RST_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+};
+
void __init msm_8974_init_gpiomux(void)
{
int rc;
@@ -128,4 +369,11 @@
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(msm8974_slimbus_config,
+ ARRAY_SIZE(msm8974_slimbus_config));
+
+ msm_gpiomux_install(msm_touch_configs, ARRAY_SIZE(msm_touch_configs));
+
+ msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
}
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 388307b..c3eb10c 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -393,6 +393,51 @@
&msm_bus_ocmem_vnoc,
};
+static ssize_t mxt336s_vkeys_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, 200,
+ __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":62:1345:90:90" \
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":240:1345:90:90" \
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":470:1345:90:90" \
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":658:1345:90:90" \
+ "\n");
+}
+
+static struct kobj_attribute mxt336s_vkeys_attr = {
+ .attr = {
+ .mode = S_IRUGO,
+ },
+ .show = &mxt336s_vkeys_show,
+};
+
+static struct attribute *mxt336s_properties_attrs[] = {
+ &mxt336s_vkeys_attr.attr,
+ NULL
+};
+
+static struct attribute_group mxt336s_properties_attr_group = {
+ .attrs = mxt336s_properties_attrs,
+};
+
+static void mxt_init_vkeys_8974(void)
+{
+ int rc = 0;
+ static struct kobject *mxt336s_properties_kobj;
+
+ mxt336s_vkeys_attr.attr.name = "virtualkeys.atmel_mxt_ts";
+ mxt336s_properties_kobj = kobject_create_and_add("board_properties",
+ NULL);
+ if (mxt336s_properties_kobj)
+ rc = sysfs_create_group(mxt336s_properties_kobj,
+ &mxt336s_properties_attr_group);
+ if (!mxt336s_properties_kobj || rc)
+ pr_err("%s: failed to create board_properties\n",
+ __func__);
+
+ return;
+}
+
static void __init msm8974_init_buses(void)
{
#ifdef CONFIG_MSM_BUS_SCALING
@@ -436,6 +481,7 @@
msm_clock_init(&msm8974_clock_init_data);
msm8974_init_buses();
msm_thermal_device_init();
+ mxt_init_vkeys_8974();
}
static struct of_device_id irq_match[] __initdata = {
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index f885774..e599739 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -620,8 +620,8 @@
#define USB_BAM_PHY_BASE 0x12502000
#define HSIC_BAM_PHY_BASE 0x12542000
#define A2_BAM_PHY_BASE 0x124C2000
-static struct usb_bam_pipe_connect msm_usb_bam_connections[2][4][2] = {
- [0][0][USB_TO_PEER_PERIPHERAL] = {
+static struct usb_bam_pipe_connect msm_usb_bam_connections[MAX_BAMS][4][2] = {
+ [HSUSB_BAM][0][USB_TO_PEER_PERIPHERAL] = {
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 11,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -631,7 +631,7 @@
.desc_fifo_base_offset = 0x1700,
.desc_fifo_size = 0x300,
},
- [0][0][PEER_PERIPHERAL_TO_USB] = {
+ [HSUSB_BAM][0][PEER_PERIPHERAL_TO_USB] = {
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 1,
.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -641,7 +641,7 @@
.desc_fifo_base_offset = 0x1000,
.desc_fifo_size = 0x100,
},
- [0][1][USB_TO_PEER_PERIPHERAL] = {
+ [HSUSB_BAM][1][USB_TO_PEER_PERIPHERAL] = {
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 13,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -651,7 +651,7 @@
.desc_fifo_base_offset = 0x2700,
.desc_fifo_size = 0x300,
},
- [0][1][PEER_PERIPHERAL_TO_USB] = {
+ [HSUSB_BAM][1][PEER_PERIPHERAL_TO_USB] = {
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 3,
.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -661,7 +661,7 @@
.desc_fifo_base_offset = 0x2000,
.desc_fifo_size = 0x100,
},
- [0][2][USB_TO_PEER_PERIPHERAL] = {
+ [HSUSB_BAM][2][USB_TO_PEER_PERIPHERAL] = {
.src_phy_addr = USB_BAM_PHY_BASE,
.src_pipe_index = 15,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -671,7 +671,7 @@
.desc_fifo_base_offset = 0x3700,
.desc_fifo_size = 0x300,
},
- [0][2][PEER_PERIPHERAL_TO_USB] = {
+ [HSUSB_BAM][2][PEER_PERIPHERAL_TO_USB] = {
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 5,
.dst_phy_addr = USB_BAM_PHY_BASE,
@@ -681,7 +681,7 @@
.desc_fifo_base_offset = 0x3000,
.desc_fifo_size = 0x100,
},
- [1][0][USB_TO_PEER_PERIPHERAL] = {
+ [HSIC_BAM][0][USB_TO_PEER_PERIPHERAL] = {
.src_phy_addr = HSIC_BAM_PHY_BASE,
.src_pipe_index = 1,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -691,7 +691,7 @@
.desc_fifo_base_offset = 0x1700,
.desc_fifo_size = 0x300,
},
- [1][0][PEER_PERIPHERAL_TO_USB] = {
+ [HSIC_BAM][0][PEER_PERIPHERAL_TO_USB] = {
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 1,
.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -701,7 +701,7 @@
.desc_fifo_base_offset = 0x1000,
.desc_fifo_size = 0x100,
},
- [1][1][USB_TO_PEER_PERIPHERAL] = {
+ [HSIC_BAM][1][USB_TO_PEER_PERIPHERAL] = {
.src_phy_addr = HSIC_BAM_PHY_BASE,
.src_pipe_index = 3,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -711,7 +711,7 @@
.desc_fifo_base_offset = 0x2700,
.desc_fifo_size = 0x300,
},
- [1][1][PEER_PERIPHERAL_TO_USB] = {
+ [HSIC_BAM][1][PEER_PERIPHERAL_TO_USB] = {
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 3,
.dst_phy_addr = HSIC_BAM_PHY_BASE,
@@ -721,7 +721,7 @@
.desc_fifo_base_offset = 0x2000,
.desc_fifo_size = 0x100,
},
- [1][2][USB_TO_PEER_PERIPHERAL] = {
+ [HSIC_BAM][2][USB_TO_PEER_PERIPHERAL] = {
.src_phy_addr = HSIC_BAM_PHY_BASE,
.src_pipe_index = 5,
.dst_phy_addr = A2_BAM_PHY_BASE,
@@ -731,7 +731,7 @@
.desc_fifo_base_offset = 0x3700,
.desc_fifo_size = 0x300,
},
- [1][2][PEER_PERIPHERAL_TO_USB] = {
+ [HSIC_BAM][2][PEER_PERIPHERAL_TO_USB] = {
.src_phy_addr = A2_BAM_PHY_BASE,
.src_pipe_index = 5,
.dst_phy_addr = HSIC_BAM_PHY_BASE,
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index e28c734..2919f06 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -24,6 +24,18 @@
.dir = GPIOMUX_OUT_HIGH,
};
+static struct gpiomux_setting gpio_spi_cs_config = {
+ .func = GPIOMUX_FUNC_9,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gpio_spi_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
.gpio = 45, /* BLSP1 UART TX */
@@ -37,6 +49,31 @@
[GPIOMUX_SUSPENDED] = &gpio_uart_config,
},
},
+ {
+ .gpio = 69, /* BLSP6 QUP SPI_CS_N */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ },
+ },
+ {
+ .gpio = 20, /* BLSP6 QUP SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 21, /* BLSP6 QUP SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 23, /* BLSP6 QUP SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+
};
void __init msm9625_init_gpiomux(void)
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 4a9bbcd..e7ef1a9 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -46,8 +46,8 @@
CLK_DUMMY("dfab_clk", DFAB_CLK, NULL, 0),
CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, NULL, 0),
CLK_DUMMY("mem_clk", NULL, NULL, 0),
- CLK_DUMMY("core_clk", NULL, "spi_qsd.1", OFF),
- CLK_DUMMY("iface_clk", NULL, "spi_qsd.1", OFF),
+ CLK_DUMMY("core_clk", SPI_CLK, "spi_qsd.1", OFF),
+ CLK_DUMMY("iface_clk", SPI_P_CLK, "spi_qsd.1", OFF),
CLK_DUMMY("core_clk", NULL, "f9966000.i2c", 0),
CLK_DUMMY("iface_clk", NULL, "f9966000.i2c", 0),
CLK_DUMMY("core_clk", NULL, "fe12f000.slim", OFF),
@@ -72,6 +72,8 @@
static struct of_dev_auxdata msm9625_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
"msm_serial_hsl.0", NULL),
+ OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9928000, \
+ "spi_qsd.1", NULL),
{}
};
@@ -94,6 +96,8 @@
{
if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed\n", __func__);
+
+ msm9625_init_gpiomux();
msm_clock_init(&msm_dummy_clock_init_data);
of_platform_populate(NULL, of_default_bus_match_table,
msm9625_auxdata_lookup, NULL);
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index b2a4ce2..8f9a0ef 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -23,6 +23,7 @@
#include <asm/mach/time.h>
#include <mach/socinfo.h>
#include <mach/board.h>
+#include <mach/restart.h>
static void __init msm_dt_timer_init(void)
{
@@ -87,4 +88,5 @@
.dt_compat = msm_dt_match,
.reserve = msm_dt_reserve,
.init_very_early = msm_dt_init_very_early,
+ .restart = msm_restart,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 1e198a7..d1d85fc 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -19,7 +19,7 @@
#include <linux/module.h>
#include <asm/mach-types.h>
#include <mach/msm_iomap.h>
-#include <mach/board.h>
+#include <mach/camera.h>
#include <mach/irqs-7xxx.h>
#include "devices-msm7x2xa.h"
#include "board-msm7627a.h"
@@ -396,7 +396,7 @@
sensor_board_info_ov8825.num_vreg = 0;
}
- if (machine_is_msm8625_evb()
+ if (machine_is_msm8625_evb() || machine_is_msm7627a_evb()
|| machine_is_msm8625_evt()) {
sensor_board_info_ov7692.cam_vreg =
ov7692_gpio_vreg;
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 7b50db5..e00f150 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -63,6 +63,13 @@
#define PMEM_KERNEL_EBI1_SIZE 0x3A000
#define MSM_PMEM_AUDIO_SIZE 0x1F4000
+#define SNDDEV_CAP_NONE 0x0
+#define SNDDEV_CAP_RX 0x1 /* RX direction */
+#define SNDDEV_CAP_TX 0x2 /* TX direction */
+#define SNDDEV_CAP_VOICE 0x4 /* Support voice call */
+#define SNDDEV_CAP_FM 0x10 /* Support FM radio */
+#define SNDDEV_CAP_TTY 0x20 /* Support TTY */
+
#if defined(CONFIG_GPIO_SX150X)
enum {
SX150X_CORE,
@@ -494,7 +501,6 @@
SND(FM_ANALOG_STEREO_HEADSET_CODEC, 36),
};
#undef SND
-
static struct msm_snd_endpoints msm_device_snd_endpoints = {
.endpoints = snd_endpoints_list,
.num = sizeof(snd_endpoints_list) / sizeof(struct snd_endpoint)
@@ -508,12 +514,62 @@
},
};
+#define CAD(desc, num, cap) { .name = #desc, .id = num, .capability = cap, }
+static struct cad_endpoint cad_endpoints_list[] = {
+ CAD(NONE, 0, SNDDEV_CAP_NONE),
+ CAD(HANDSET_SPKR, 1, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(HANDSET_MIC, 2, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(HEADSET_MIC, 3, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(HEADSET_SPKR_MONO, 4, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(HEADSET_SPKR_STEREO, 5, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(SPEAKER_PHONE_MIC, 6, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(SPEAKER_PHONE_MONO, 7, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(SPEAKER_PHONE_STEREO, 8, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(BT_SCO_MIC, 9, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(BT_SCO_SPKR, 10, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(BT_A2DP_SPKR, 11, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(TTY_HEADSET_MIC, 12, (SNDDEV_CAP_TX | \
+ SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY)),
+ CAD(TTY_HEADSET_SPKR, 13, (SNDDEV_CAP_RX | \
+ SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY)),
+ CAD(HEADSET_STEREO_PLUS_SPKR_MONO_RX, 19, (SNDDEV_CAP_TX | \
+ SNDDEV_CAP_VOICE)),
+ CAD(LP_FM_HEADSET_SPKR_STEREO_RX, 25, (SNDDEV_CAP_TX | SNDDEV_CAP_FM)),
+ CAD(I2S_RX, 26, (SNDDEV_CAP_RX)),
+ CAD(SPEAKER_PHONE_MIC_ENDFIRE, 45, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(HANDSET_MIC_ENDFIRE, 46, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(I2S_TX, 48, (SNDDEV_CAP_TX)),
+ CAD(LP_FM_HEADSET_SPKR_STEREO_PLUS_HEADSET_SPKR_STEREO_RX, 57, \
+ (SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+ CAD(FM_DIGITAL_HEADSET_SPKR_STEREO, 65, \
+ (SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+ CAD(FM_DIGITAL_SPEAKER_PHONE_MONO, 67, \
+ (SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+ CAD(FM_DIGITAL_BT_A2DP_SPKR, 69, \
+ (SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+ CAD(MAX, 80, SNDDEV_CAP_NONE),
+};
+#undef CAD
+static struct msm_cad_endpoints msm_device_cad_endpoints = {
+ .endpoints = cad_endpoints_list,
+ .num = sizeof(cad_endpoints_list) / sizeof(struct cad_endpoint)
+};
+
+static struct platform_device msm_device_cad = {
+ .name = "msm_cad",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_device_cad_endpoints
+ },
+};
+
#define DEC0_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
- (1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+ (1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))| \
+ (1<<MSM_ADSP_CODEC_AC3)
#define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
@@ -813,6 +869,7 @@
&android_pmem_audio_device,
&msm_device_nand,
&msm_device_snd,
+ &msm_device_cad,
&msm_device_adspdec,
&asoc_msm_pcm,
&asoc_msm_dai0,
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 8adfdab..4524f43 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -4539,19 +4539,10 @@
.mddi_client_power = msm_fb_mddi_client_power,
};
-int mdp_core_clk_rate_table[] = {
- 122880000,
- 122880000,
- 192000000,
- 192000000,
-};
-
static struct msm_panel_common_pdata mdp_pdata = {
.hw_revision_addr = 0xac001270,
.gpio = 30,
- .mdp_core_clk_rate = 122880000,
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+ .mdp_max_clk = 192000000,
.mdp_rev = MDP_REV_40,
.mem_hid = MEMTYPE_EBI0,
};
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index cd95630..acd7f74 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -15,7 +15,7 @@
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/mfd/pmic8901.h>
-#include <mach/board.h>
+#include <mach/camera.h>
#include <mach/board-msm8660.h>
#include <mach/gpiomux.h>
#include <mach/msm_bus_board.h>
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 38f1170..47d847e 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2629,7 +2629,12 @@
#define USER_SMI_SIZE (MSM_SMI_SIZE - KERNEL_SMI_SIZE)
#define MSM_PMEM_SMIPOOL_SIZE USER_SMI_SIZE
+#ifdef CONFIG_MSM_CP
#define MSM_ION_HOLE_SIZE SZ_128K /* (128KB) */
+#else
+#define MSM_ION_HOLE_SIZE 0
+#endif
+
#define MSM_MM_FW_SIZE (0x200000 - MSM_ION_HOLE_SIZE) /*(2MB-128KB)*/
#define MSM_ION_MM_SIZE 0x3800000 /* (56MB) */
#define MSM_ION_MFC_SIZE SZ_8K
@@ -2639,6 +2644,14 @@
#define MSM_ION_MM_BASE (MSM_ION_HOLE_BASE + MSM_ION_HOLE_SIZE)
#define MSM_ION_MFC_BASE (MSM_ION_MM_BASE + MSM_ION_MM_SIZE)
+#ifdef CONFIG_MSM_CP
+#define SECURE_BASE (MSM_ION_HOLE_BASE)
+#define SECURE_SIZE (MSM_ION_MM_SIZE + MSM_ION_HOLE_SIZE)
+#else
+#define SECURE_BASE (MSM_MM_FW_BASE)
+#define SECURE_SIZE (MSM_ION_MM_SIZE + MSM_MM_FW_SIZE)
+#endif
+
#define MSM_ION_SF_SIZE 0x4000000 /* 64MB */
#define MSM_ION_CAMERA_SIZE MSM_PMEM_ADSP_SIZE
@@ -5293,8 +5306,8 @@
.request_region = request_smi_region,
.release_region = release_smi_region,
.setup_region = setup_smi_region,
- .secure_base = MSM_ION_HOLE_BASE,
- .secure_size = MSM_ION_HOLE_SIZE + MSM_ION_MM_SIZE,
+ .secure_base = SECURE_BASE,
+ .secure_size = SECURE_SIZE,
.iommu_map_all = 1,
.iommu_2x_map_domain = VIDEO_DOMAIN,
};
@@ -9638,27 +9651,9 @@
}
#endif
-#ifdef CONFIG_FB_MSM_MIPI_DSI
-int mdp_core_clk_rate_table[] = {
- 85330000,
- 128000000,
- 160000000,
- 200000000,
-};
-#else
-int mdp_core_clk_rate_table[] = {
- 59080000,
- 128000000,
- 128000000,
- 200000000,
-};
-#endif
-
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
- .mdp_core_clk_rate = 59080000,
- .mdp_core_clk_table = mdp_core_clk_rate_table,
- .num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+ .mdp_max_clk = 200000000,
#ifdef CONFIG_MSM_BUS_SCALING
.mdp_bus_scale_table = &mdp_bus_scale_pdata,
#endif
@@ -9751,9 +9746,7 @@
static void __init msm_fb_add_devices(void)
{
#ifdef CONFIG_FB_MSM_LCDC_DSUB
- mdp_pdata.mdp_core_clk_table = NULL;
- mdp_pdata.num_mdp_clk = 0;
- mdp_pdata.mdp_core_clk_rate = 200000000;
+ mdp_pdata.mdp_max_clk = 200000000;
#endif
msm_fb_register_device("mdp", &mdp_pdata);
@@ -9777,8 +9770,6 @@
*/
static void set_mdp_clocks_for_wuxga(void)
{
- int i;
-
mdp_sd_smi_vectors[0].ab = 2000000000;
mdp_sd_smi_vectors[0].ib = 2000000000;
mdp_sd_smi_vectors[1].ab = 2000000000;
@@ -9804,10 +9795,7 @@
mdp_1080p_vectors[1].ab = 2000000000;
mdp_1080p_vectors[1].ib = 2000000000;
- mdp_pdata.mdp_core_clk_rate = 200000000;
-
- for (i = 0; i < ARRAY_SIZE(mdp_core_clk_rate_table); i++)
- mdp_core_clk_rate_table[i] = 200000000;
+ mdp_pdata.mdp_max_clk = 200000000;
}
#if (defined(CONFIG_MARIMBA_CORE)) && \
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 95ec7ca..1da9ede 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -75,6 +75,13 @@
#define I2C_PIN_CTL 0x15
#define I2C_NORMAL 0x40
+#define SNDDEV_CAP_NONE 0x0
+#define SNDDEV_CAP_RX 0x1 /* RX direction */
+#define SNDDEV_CAP_TX 0x2 /* TX direction */
+#define SNDDEV_CAP_VOICE 0x4 /* Support voice call */
+#define SNDDEV_CAP_FM 0x10 /* Support FM radio */
+#define SNDDEV_CAP_TTY 0x20 /* Support TTY */
+
static struct platform_device msm_wlan_ar6000_pm_device = {
.name = "wlan_ar6000_pm_dev",
.id = -1,
@@ -132,12 +139,12 @@
#define MSM_PMEM_MDP_SIZE 0x1B00000
#define MSM_PMEM_ADSP_SIZE 0x1200000
-#define MSM_ION_AUDIO_SIZE (MSM_PMEM_AUDIO_SIZE + PMEM_KERNEL_EBI1_SIZE)
-#define MSM_ION_CAMERA_SIZE MSM_PMEM_ADSP_SIZE
-#define MSM_ION_SF_SIZE MSM_PMEM_MDP_SIZE
-#define MSM_ION_HEAP_NUM 4
#ifdef CONFIG_ION_MSM
+#define MSM_ION_HEAP_NUM 4
static struct platform_device ion_dev;
+static int msm_ion_camera_size;
+static int msm_ion_audio_size;
+static int msm_ion_sf_size;
#endif
#endif
@@ -454,12 +461,63 @@
},
};
+#define CAD(desc, num, cap) { .name = #desc, .id = num, .capability = cap, }
+static struct cad_endpoint cad_endpoints_list[] = {
+ CAD(NONE, 0, SNDDEV_CAP_NONE),
+ CAD(HANDSET_SPKR, 1, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(HANDSET_MIC, 2, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(HEADSET_MIC, 3, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(HEADSET_SPKR_MONO, 4, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(HEADSET_SPKR_STEREO, 5, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(SPEAKER_PHONE_MIC, 6, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(SPEAKER_PHONE_MONO, 7, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(SPEAKER_PHONE_STEREO, 8, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(BT_SCO_MIC, 9, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(BT_SCO_SPKR, 10, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(BT_A2DP_SPKR, 11, (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE)),
+ CAD(TTY_HEADSET_MIC, 12, (SNDDEV_CAP_TX | \
+ SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY)),
+ CAD(TTY_HEADSET_SPKR, 13, (SNDDEV_CAP_RX | \
+ SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY)),
+ CAD(HEADSET_STEREO_PLUS_SPKR_MONO_RX, 19, (SNDDEV_CAP_TX | \
+ SNDDEV_CAP_VOICE)),
+ CAD(LP_FM_HEADSET_SPKR_STEREO_RX, 25, (SNDDEV_CAP_TX | SNDDEV_CAP_FM)),
+ CAD(I2S_RX, 26, (SNDDEV_CAP_RX)),
+ CAD(SPEAKER_PHONE_MIC_ENDFIRE, 45, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(HANDSET_MIC_ENDFIRE, 46, (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE)),
+ CAD(I2S_TX, 48, (SNDDEV_CAP_TX)),
+ CAD(LP_FM_HEADSET_SPKR_STEREO_PLUS_HEADSET_SPKR_STEREO_RX, 57, \
+ (SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+ CAD(FM_DIGITAL_HEADSET_SPKR_STEREO, 65, \
+ (SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+ CAD(FM_DIGITAL_SPEAKER_PHONE_MONO, 67, \
+ (SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+ CAD(FM_DIGITAL_BT_A2DP_SPKR, 69, \
+ (SNDDEV_CAP_FM | SNDDEV_CAP_RX)),
+ CAD(MAX, 80, SNDDEV_CAP_NONE),
+};
+#undef CAD
+
+static struct msm_cad_endpoints msm_device_cad_endpoints = {
+ .endpoints = cad_endpoints_list,
+ .num = sizeof(cad_endpoints_list) / sizeof(struct cad_endpoint)
+};
+
+static struct platform_device msm_device_cad = {
+ .name = "msm_cad",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm_device_cad_endpoints
+ },
+};
+
#define DEC0_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
(1<<MSM_ADSP_CODEC_AMRNB)|(1<<MSM_ADSP_CODEC_WAV)| \
(1<<MSM_ADSP_CODEC_ADPCM)|(1<<MSM_ADSP_CODEC_YADPCM)| \
- (1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))
+ (1<<MSM_ADSP_CODEC_EVRC)|(1<<MSM_ADSP_CODEC_QCELP))| \
+ (1<<MSM_ADSP_CODEC_AC3)
#define DEC1_FORMAT ((1<<MSM_ADSP_CODEC_MP3)| \
(1<<MSM_ADSP_CODEC_AAC)|(1<<MSM_ADSP_CODEC_WMA)| \
(1<<MSM_ADSP_CODEC_WMAPRO)|(1<<MSM_ADSP_CODEC_AMRWB)| \
@@ -701,6 +759,7 @@
&msm_batt_device,
&msm_device_adspdec,
&msm_device_snd,
+ &msm_device_cad,
&asoc_msm_pcm,
&asoc_msm_dai0,
&asoc_msm_dai1,
@@ -758,6 +817,15 @@
}
early_param("pmem_audio_size", pmem_audio_size_setup);
+static void fix_sizes(void)
+{
+#ifdef CONFIG_ION_MSM
+ msm_ion_camera_size = pmem_adsp_size;
+ msm_ion_audio_size = (MSM_PMEM_AUDIO_SIZE + PMEM_KERNEL_EBI1_SIZE);
+ msm_ion_sf_size = pmem_mdp_size;
+#endif
+}
+
#ifdef CONFIG_ION_MSM
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct ion_co_heap_pdata co_ion_pdata = {
@@ -785,7 +853,6 @@
.id = ION_CAMERA_HEAP_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_CAMERA_HEAP_NAME,
- .size = MSM_ION_CAMERA_SIZE,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *)&co_ion_pdata,
},
@@ -794,7 +861,6 @@
.id = ION_AUDIO_HEAP_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_AUDIO_HEAP_NAME,
- .size = MSM_ION_AUDIO_SIZE,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *)&co_ion_pdata,
},
@@ -803,7 +869,6 @@
.id = ION_SF_HEAP_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_SF_HEAP_NAME,
- .size = MSM_ION_SF_SIZE,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *)&co_ion_pdata,
},
@@ -872,19 +937,30 @@
#endif
}
+static void __init size_ion_devices(void)
+{
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_pdata.heaps[1].size = msm_ion_camera_size;
+ ion_pdata.heaps[2].size = msm_ion_audio_size;
+ ion_pdata.heaps[3].size = msm_ion_sf_size;
+#endif
+}
+
static void __init reserve_ion_memory(void)
{
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
- msm7627a_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
- msm7627a_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
- msm7627a_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
+ msm7627a_reserve_table[MEMTYPE_EBI1].size += msm_ion_camera_size;
+ msm7627a_reserve_table[MEMTYPE_EBI1].size += msm_ion_audio_size;
+ msm7627a_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;
#endif
}
static void __init msm7627a_calculate_reserve_sizes(void)
{
+ fix_sizes();
size_pmem_devices();
reserve_pmem_memory();
+ size_ion_devices();
reserve_ion_memory();
}
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 21b6c0a..34901e8 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -3527,6 +3527,12 @@
static unsigned long fmax_gfx3d_8930[MAX_VDD_LEVELS] __initdata = {
[VDD_DIG_LOW] = 192000000,
[VDD_DIG_NOMINAL] = 320000000,
+ [VDD_DIG_HIGH] = 400000000
+};
+
+static unsigned long fmax_gfx3d_8930aa[MAX_VDD_LEVELS] __initdata = {
+ [VDD_DIG_LOW] = 192000000,
+ [VDD_DIG_NOMINAL] = 320000000,
[VDD_DIG_HIGH] = 450000000
};
@@ -5812,6 +5818,7 @@
static struct clk_lookup msm_clocks_8960ab_only[] __initdata = {
CLK_LOOKUP("bus_clk", gfx3d_axi_clk.c, "footswitch-8x60.2"),
+ CLK_LOOKUP("core_clk", gfx3d_axi_clk.c, "msm_iommu.10"),
CLK_LOOKUP("div_clk", tv_src_div_clk.c, ""),
};
@@ -6230,7 +6237,7 @@
rmwreg(0x00000003, AHB_EN_REG, 0x6C000103);
writel_relaxed(0x000007F9, AHB_EN2_REG);
} else {
- rmwreg(0x44000000, AHB_EN_REG, 0x6C000103);
+ rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
writel_relaxed(0x3C7097F9, AHB_EN2_REG);
}
@@ -6450,6 +6457,8 @@
msm_clocks_8960ab_only, sizeof(msm_clocks_8960ab_only));
msm8960_clock_init_data.size -=
ARRAY_SIZE(msm_clocks_8960_only);
+
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
} else if (cpu_is_msm8960()) {
memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
msm_clocks_8960_only, sizeof(msm_clocks_8960_only));
@@ -6481,12 +6490,15 @@
* Change the freq tables and voltage requirements for
* clocks which differ between 8960 and 8930.
*/
- if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
- gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
-
+ if (cpu_is_msm8930() || cpu_is_msm8627()) {
memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930,
sizeof(gfx3d_clk.c.fmax));
-
+ } else if (cpu_is_msm8930aa()) {
+ memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8930aa,
+ sizeof(gfx3d_clk.c.fmax));
+ }
+ if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
+ gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930;
pll15_clk.c.rate = 900000000;
gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
}
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 8ac1c88..e21a645 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -23,11 +23,13 @@
#include <mach/clk.h>
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
+#include <mach/rpm-smd.h>
#include "clock-local2.h"
#include "clock-pll.h"
#include "clock-rpm.h"
#include "clock-voter.h"
+#include "clock-mdss-8974.h"
enum {
GCC_BASE,
@@ -120,6 +122,10 @@
#define USB_HSIC_CMD_RCGR 0x0440
#define USB_HSIC_IO_CAL_CMD_RCGR 0x0458
#define USB_HS_SYSTEM_CMD_RCGR 0x0490
+#define SYS_NOC_USB3_AXI_CBCR 0x0108
+#define USB30_SLEEP_CBCR 0x03CC
+#define USB2A_PHY_SLEEP_CBCR 0x04AC
+#define USB2B_PHY_SLEEP_CBCR 0x04B4
#define SDCC1_APPS_CMD_RCGR 0x04D0
#define SDCC2_APPS_CMD_RCGR 0x0510
#define SDCC3_APPS_CMD_RCGR 0x0550
@@ -517,7 +523,8 @@
#define edppll_270_mm_source_val 4
#define edppll_350_mm_source_val 4
#define dsipll_750_mm_source_val 1
-#define dsipll_250_mm_source_val 2
+#define dsipll0_byte_mm_source_val 1
+#define dsipll0_pixel_mm_source_val 1
#define hdmipll_297_mm_source_val 3
#define F(f, s, div, m, n) \
@@ -615,13 +622,16 @@
#define RPM_BUS_CLK_TYPE 0x316b6c63
#define RPM_MEM_CLK_TYPE 0x326b6c63
-#define CXO_ID 0x0
-#define QDSS_ID 0x1
+#define RPM_SMD_KEY_ENABLE 0x62616E45
+
+#define CXO_ID 0x0
+#define QDSS_ID 0x1
+#define RPM_SCALING_ENABLE_ID 0x2
#define PNOC_ID 0x0
#define SNOC_ID 0x1
#define CNOC_ID 0x2
-#define MMSSNOC_AHB_ID 0x4
+#define MMSSNOC_AHB_ID 0x3
#define BIMC_ID 0x0
#define OCMEM_ID 0x1
@@ -766,6 +776,7 @@
static DEFINE_CLK_VOTER(ocmemgx_gfx3d_clk, &ocmemgx_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ocmemgx_msmbus_clk, &ocmemgx_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ocmemgx_core_clk, &ocmemgx_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_sdcc1_clk, &pnoc_clk.c, 0);
static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, 0);
@@ -2191,6 +2202,51 @@
},
};
+struct branch_clk gcc_sys_noc_usb3_axi_clk = {
+ .cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
+ .parent = &usb30_master_clk_src.c,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sys_noc_usb3_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
+ },
+};
+
+struct branch_clk gcc_usb30_sleep_clk = {
+ .cbcr_reg = USB30_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb30_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb30_sleep_clk.c),
+ },
+};
+
+struct branch_clk gcc_usb2a_phy_sleep_clk = {
+ .cbcr_reg = USB2A_PHY_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb2a_phy_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb2a_phy_sleep_clk.c),
+ },
+};
+
+struct branch_clk gcc_usb2b_phy_sleep_clk = {
+ .cbcr_reg = USB2B_PHY_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb2b_phy_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb2b_phy_sleep_clk.c),
+ },
+};
+
static struct branch_clk gcc_usb_hs_ahb_clk = {
.cbcr_reg = USB_HS_AHB_CBCR,
.has_sibling = 1,
@@ -2599,6 +2655,7 @@
};
static struct clk_freq_tbl ftbl_camss_mclk0_3_clk[] = {
+ F_MM(19200000, cxo, 1, 0, 0),
F_MM(66670000, gpll0, 9, 0, 0),
F_END
};
@@ -2729,21 +2786,101 @@
},
};
-static struct clk_freq_tbl ftbl_mdss_byte0_1_clk[] = {
- F_MDSS( 93750000, dsipll_750, 8, 0, 0),
- F_MDSS(187500000, dsipll_750, 4, 0, 0),
- F_END
+static struct clk *dsi_pll_clk_get_parent(struct clk *c)
+{
+ return &cxo_clk_src.c;
+}
+
+static struct clk dsipll0_byte_clk_src = {
+ .dbg_name = "dsipll0_byte_clk_src",
+ .ops = &clk_ops_dsi_byte_pll,
+ CLK_INIT(dsipll0_byte_clk_src),
};
+static struct clk dsipll0_pixel_clk_src = {
+ .dbg_name = "dsipll0_pixel_clk_src",
+ .ops = &clk_ops_dsi_pixel_pll,
+ CLK_INIT(dsipll0_pixel_clk_src),
+};
+
+static struct clk_freq_tbl byte_freq = {
+ .src_clk = &dsipll0_byte_clk_src,
+ .div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
+};
+static struct clk_freq_tbl pixel_freq = {
+ .src_clk = &dsipll0_byte_clk_src,
+ .div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
+};
+static struct clk_ops clk_ops_byte;
+static struct clk_ops clk_ops_pixel;
+
+#define CFG_RCGR_DIV_MASK BM(4, 0)
+
+static int set_rate_byte(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk *pll = &dsipll0_byte_clk_src;
+ unsigned long source_rate, div;
+ int rc;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ rc = clk_set_rate(pll, rate);
+ if (rc)
+ return rc;
+
+ source_rate = clk_round_rate(pll, rate);
+ if ((2 * source_rate) % rate)
+ return -EINVAL;
+
+ div = ((2 * source_rate)/rate) - 1;
+ if (div > CFG_RCGR_DIV_MASK)
+ return -EINVAL;
+
+ byte_freq.div_src_val &= ~CFG_RCGR_DIV_MASK;
+ byte_freq.div_src_val |= BVAL(4, 0, div);
+ set_rate_mnd(rcg, &byte_freq);
+
+ return 0;
+}
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk *pll = &dsipll0_pixel_clk_src;
+ unsigned long source_rate, div;
+ int rc;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ rc = clk_set_rate(pll, rate);
+ if (rc)
+ return rc;
+
+ source_rate = clk_round_rate(pll, rate);
+ if ((2 * source_rate) % rate)
+ return -EINVAL;
+
+ div = ((2 * source_rate)/rate) - 1;
+ if (div > CFG_RCGR_DIV_MASK)
+ return -EINVAL;
+
+ pixel_freq.div_src_val &= ~CFG_RCGR_DIV_MASK;
+ pixel_freq.div_src_val |= BVAL(4, 0, div);
+ set_rate_hid(rcg, &pixel_freq);
+
+ return 0;
+}
+
static struct rcg_clk byte0_clk_src = {
.cmd_rcgr_reg = BYTE0_CMD_RCGR,
- .set_rate = set_rate_hid,
- .freq_tbl = ftbl_mdss_byte0_1_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = &byte_freq,
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "byte0_clk_src",
- .ops = &clk_ops_rcg,
+ .ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
HIGH, 188000000),
CLK_INIT(byte0_clk_src.c),
@@ -2752,13 +2889,11 @@
static struct rcg_clk byte1_clk_src = {
.cmd_rcgr_reg = BYTE1_CMD_RCGR,
- .set_rate = set_rate_hid,
- .freq_tbl = ftbl_mdss_byte0_1_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = &byte_freq,
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "byte1_clk_src",
- .ops = &clk_ops_rcg,
+ .ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
HIGH, 188000000),
CLK_INIT(byte1_clk_src.c),
@@ -2895,21 +3030,14 @@
},
};
-static struct clk_freq_tbl ftbl_mdss_pclk0_1_clk[] = {
- F_MDSS(125000000, dsipll_250, 2, 0, 0),
- F_MDSS(250000000, dsipll_250, 1, 0, 0),
- F_END
-};
static struct rcg_clk pclk0_clk_src = {
.cmd_rcgr_reg = PCLK0_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_mdss_pclk0_1_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = &pixel_freq,
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "pclk0_clk_src",
- .ops = &clk_ops_rcg_mnd,
+ .ops = &clk_ops_pixel,
VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
CLK_INIT(pclk0_clk_src.c),
},
@@ -2917,13 +3045,11 @@
static struct rcg_clk pclk1_clk_src = {
.cmd_rcgr_reg = PCLK1_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_mdss_pclk0_1_clk,
- .current_freq = &rcg_dummy_freq,
+ .current_freq = &pixel_freq,
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "pclk1_clk_src",
- .ops = &clk_ops_rcg_mnd,
+ .ops = &clk_ops_pixel,
VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
CLK_INIT(pclk1_clk_src.c),
},
@@ -4476,6 +4602,10 @@
{&gcc_blsp1_qup1_i2c_apps_clk.c, GCC_BASE, 0x008b},
{&gcc_blsp2_uart6_apps_clk.c, GCC_BASE, 0x00c3},
{&gcc_sdcc2_ahb_clk.c, GCC_BASE, 0x0071},
+ {&gcc_usb30_sleep_clk.c, GCC_BASE, 0x0051},
+ {&gcc_usb2a_phy_sleep_clk.c, GCC_BASE, 0x0063},
+ {&gcc_usb2b_phy_sleep_clk.c, GCC_BASE, 0x0064},
+ {&gcc_sys_noc_usb3_axi_clk.c, GCC_BASE, 0x0001},
{&gcc_ocmem_noc_cfg_ahb_clk.c, GCC_BASE, 0x0029},
{&gcc_ce1_clk.c, GCC_BASE, 0x0138},
{&gcc_lpass_q6_axi_clk.c, GCC_BASE, 0x0160},
@@ -4532,6 +4662,16 @@
{&camss_vfe_vfe_ahb_clk.c, MMSS_BASE, 0x003c},
{&camss_vfe_vfe_axi_clk.c, MMSS_BASE, 0x003d},
{&camss_vfe_vfe_ocmemnoc_clk.c, MMSS_BASE, 0x003e},
+ {&oxilicx_axi_clk.c, MMSS_BASE, 0x000b},
+ {&oxilicx_ahb_clk.c, MMSS_BASE, 0x000c},
+ {&ocmemcx_ocmemnoc_clk.c, MMSS_BASE, 0x0009},
+ {&oxili_gfx3d_clk.c, MMSS_BASE, 0x000d},
+ {&venus0_axi_clk.c, MMSS_BASE, 0x000f},
+ {&venus0_ocmemnoc_clk.c, MMSS_BASE, 0x0010},
+ {&venus0_ahb_clk.c, MMSS_BASE, 0x0011},
+ {&venus0_vcodec0_clk.c, MMSS_BASE, 0x000e},
+ {&mmss_s0_axi_clk.c, MMSS_BASE, 0x0005},
+ {&mmssnoc_ahb_clk.c, MMSS_BASE, 0x0001},
{&mdss_ahb_clk.c, MMSS_BASE, 0x0022},
{&mdss_hdmi_clk.c, MMSS_BASE, 0x001d},
{&mdss_mdp_clk.c, MMSS_BASE, 0x0014},
@@ -4562,7 +4702,7 @@
{&q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
{&q6ss_ahbm_clk.c, LPASS_BASE, 0x001d},
{&audio_core_ixfabric_clk.c, LPASS_BASE, 0x0059},
- {&mss_bus_q6_clk.c, MSS_BASE, 0x003c},
+ {&mss_bus_q6_clk.c, MSS_BASE, 0x003b},
{&mss_xo_q6_clk.c, MSS_BASE, 0x0007},
{&l2_m_clk, APCS_BASE, 0x0081},
@@ -4598,18 +4738,15 @@
clk->sample_ticks = 0x10000;
clk->multiplier = 1;
- writel_relaxed(0, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
- writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
- writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
- writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
-
switch (measure_mux[i].base) {
case GCC_BASE:
+ writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
clk_sel = measure_mux[i].debug_mux;
break;
case MMSS_BASE:
+ writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
clk_sel = 0x02C;
regval = BVAL(11, 0, measure_mux[i].debug_mux);
writel_relaxed(regval, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
@@ -4620,6 +4757,7 @@
break;
case LPASS_BASE:
+ writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
clk_sel = 0x161;
regval = BVAL(11, 0, measure_mux[i].debug_mux);
writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
@@ -4630,6 +4768,7 @@
break;
case MSS_BASE:
+ writel_relaxed(0, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
clk_sel = 0x32;
regval = BVAL(5, 0, measure_mux[i].debug_mux);
writel_relaxed(regval, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
@@ -4816,12 +4955,12 @@
CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9924000.i2c"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991e000.serial"),
- CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "spi_qsd.1"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, "spi_qsd.1"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, "f9924000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
@@ -4899,8 +5038,14 @@
CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
+ CLK_LOOKUP("mem_clk", gcc_usb30_master_clk.c, "usb_bam"),
+ CLK_LOOKUP("mem_iface_clk", gcc_sys_noc_usb3_axi_clk.c, "usb_bam"),
CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c, "msm_dwc3"),
CLK_LOOKUP("utmi_clk", gcc_usb30_mock_utmi_clk.c, "msm_dwc3"),
+ CLK_LOOKUP("iface_clk", gcc_sys_noc_usb3_axi_clk.c, "msm_dwc3"),
+ 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("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"),
@@ -4917,43 +5062,100 @@
CLK_LOOKUP("byte_clk", mdss_byte1_clk.c, ""),
CLK_LOOKUP("core_clk", mdss_esc0_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("core_clk", mdss_esc1_clk.c, ""),
+ CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
+ CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, ""),
CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, ""),
CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "mdp.0"),
CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "mdp.0"),
- CLK_LOOKUP("iface_clk", camss_cci_cci_ahb_clk.c, ""),
- CLK_LOOKUP("core_clk", camss_cci_cci_clk.c, ""),
- CLK_LOOKUP("iface_clk", camss_csi0_ahb_clk.c, ""),
- CLK_LOOKUP("camss_csi0_clk", camss_csi0_clk.c, ""),
- CLK_LOOKUP("camss_csi0phy_clk", camss_csi0phy_clk.c, ""),
- CLK_LOOKUP("camss_csi0pix_clk", camss_csi0pix_clk.c, ""),
- CLK_LOOKUP("camss_csi0rdi_clk", camss_csi0rdi_clk.c, ""),
- CLK_LOOKUP("iface_clk", camss_csi1_ahb_clk.c, ""),
- CLK_LOOKUP("camss_csi1_clk", camss_csi1_clk.c, ""),
- CLK_LOOKUP("camss_csi1phy_clk", camss_csi1phy_clk.c, ""),
- CLK_LOOKUP("camss_csi1pix_clk", camss_csi1pix_clk.c, ""),
- CLK_LOOKUP("camss_csi1rdi_clk", camss_csi1rdi_clk.c, ""),
- CLK_LOOKUP("iface_clk", camss_csi2_ahb_clk.c, ""),
- CLK_LOOKUP("camss_csi2_clk", camss_csi2_clk.c, ""),
- CLK_LOOKUP("camss_csi2phy_clk", camss_csi2phy_clk.c, ""),
- CLK_LOOKUP("camss_csi2pix_clk", camss_csi2pix_clk.c, ""),
- CLK_LOOKUP("camss_csi2rdi_clk", camss_csi2rdi_clk.c, ""),
- CLK_LOOKUP("iface_clk", camss_csi3_ahb_clk.c, ""),
- CLK_LOOKUP("camss_csi3_clk", camss_csi3_clk.c, ""),
- CLK_LOOKUP("camss_csi3phy_clk", camss_csi3phy_clk.c, ""),
- CLK_LOOKUP("camss_csi3pix_clk", camss_csi3pix_clk.c, ""),
- CLK_LOOKUP("camss_csi3rdi_clk", camss_csi3rdi_clk.c, ""),
- CLK_LOOKUP("camss_csi0_clk_src", csi0_clk_src.c, ""),
- CLK_LOOKUP("camss_csi1_clk_src", csi1_clk_src.c, ""),
- CLK_LOOKUP("camss_csi2_clk_src", csi2_clk_src.c, ""),
- CLK_LOOKUP("camss_csi3_clk_src", csi3_clk_src.c, ""),
- CLK_LOOKUP("camss_csi_vfe0_clk", camss_csi_vfe0_clk.c, ""),
- CLK_LOOKUP("camss_csi_vfe1_clk", camss_csi_vfe1_clk.c, ""),
- CLK_LOOKUP("core_clk", camss_gp0_clk.c, ""),
- CLK_LOOKUP("core_clk", camss_gp1_clk.c, ""),
- CLK_LOOKUP("iface_clk", camss_ispif_ahb_clk.c, ""),
+
+ /* MM sensor clocks */
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,s5k3l1yx"),
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,ov2720"),
+ CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,s5k3l1yx"),
+ CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,ov2720"),
+ CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
+ CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, ""),
+ CLK_LOOKUP("cam_clk", camss_mclk3_clk.c, ""),
+ CLK_LOOKUP("cam_gp0_src_clk", mmss_gp0_clk_src.c, ""),
+ CLK_LOOKUP("cam_gp1_src_clk", mmss_gp1_clk_src.c, ""),
+ CLK_LOOKUP("cam_gp0_clk", camss_gp0_clk.c, ""),
+ CLK_LOOKUP("cam_gp1_clk", camss_gp1_clk.c, ""),
+ /* CCI clocks */
+ CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+ "fda0c000.qcom,cci"),
+ CLK_LOOKUP("cci_ahb_clk", camss_cci_cci_ahb_clk.c, "fda0c000.qcom,cci"),
+ CLK_LOOKUP("cci_src_clk", cci_clk_src.c, "fda0c000.qcom,cci"),
+ CLK_LOOKUP("cci_clk", camss_cci_cci_clk.c, "fda0c000.qcom,cci"),
+ /* CSIPHY clocks */
+ CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+ "fda0ac00.qcom,csiphy"),
+ CLK_LOOKUP("csiphy_timer_src_clk", csi0phytimer_clk_src.c,
+ "fda0ac00.qcom,csiphy"),
+ CLK_LOOKUP("csiphy_timer_clk", camss_phy0_csi0phytimer_clk.c,
+ "fda0ac00.qcom,csiphy"),
+ CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+ "fda0b000.qcom,csiphy"),
+ CLK_LOOKUP("csiphy_timer_src_clk", csi1phytimer_clk_src.c,
+ "fda0b000.qcom,csiphy"),
+ CLK_LOOKUP("csiphy_timer_clk", camss_phy1_csi1phytimer_clk.c,
+ "fda0b000.qcom,csiphy"),
+ CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
+ "fda0b400.qcom,csiphy"),
+ CLK_LOOKUP("csiphy_timer_src_clk", csi2phytimer_clk_src.c,
+ "fda0b400.qcom,csiphy"),
+ 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"),
+ /*VFE clocks*/
+ CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+ "fda10000.qcom,vfe"),
+ CLK_LOOKUP("vfe_clk_src", vfe0_clk_src.c, "fda10000.qcom,vfe"),
+ CLK_LOOKUP("camss_vfe_vfe_clk", camss_vfe_vfe0_clk.c,
+ "fda10000.qcom,vfe"),
+ CLK_LOOKUP("camss_csi_vfe_clk", camss_csi_vfe0_clk.c,
+ "fda10000.qcom,vfe"),
+ CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, "fda10000.qcom,vfe"),
+ CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c, "fda10000.qcom,vfe"),
+ CLK_LOOKUP("alt_bus_clk", camss_vfe_vfe_ocmemnoc_clk.c,
+ "fda10000.qcom,vfe"),
+ CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+ "fda14000.qcom,vfe"),
+ CLK_LOOKUP("vfe_clk_src", vfe1_clk_src.c, "fda14000.qcom,vfe"),
+ CLK_LOOKUP("camss_vfe_vfe_clk", camss_vfe_vfe1_clk.c,
+ "fda14000.qcom,vfe"),
+ CLK_LOOKUP("camss_csi_vfe_clk", camss_csi_vfe1_clk.c,
+ "fda14000.qcom,vfe"),
+ CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, "fda14000.qcom,vfe"),
+ CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c, "fda14000.qcom,vfe"),
+ CLK_LOOKUP("alt_bus_clk", camss_vfe_vfe_ocmemnoc_clk.c,
+ "fda14000.qcom,vfe"),
CLK_LOOKUP("core_clk", camss_jpeg_jpeg0_clk.c, ""),
CLK_LOOKUP("core_clk", camss_jpeg_jpeg1_clk.c, ""),
CLK_LOOKUP("core_clk", camss_jpeg_jpeg2_clk.c, ""),
@@ -4963,25 +5165,12 @@
"fda64000.qcom,iommu"),
CLK_LOOKUP("bus_clk", camss_jpeg_jpeg_axi_clk.c, ""),
CLK_LOOKUP("bus_clk", camss_jpeg_jpeg_ocmemnoc_clk.c, ""),
- CLK_LOOKUP("core_clk", camss_mclk0_clk.c, ""),
- CLK_LOOKUP("core_clk", camss_mclk1_clk.c, ""),
- CLK_LOOKUP("core_clk", camss_mclk2_clk.c, ""),
- CLK_LOOKUP("core_clk", camss_mclk3_clk.c, ""),
CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
- CLK_LOOKUP("core_clk", camss_phy0_csi0phytimer_clk.c, ""),
- CLK_LOOKUP("core_clk", camss_phy1_csi1phytimer_clk.c, ""),
- CLK_LOOKUP("core_clk", camss_phy2_csi2phytimer_clk.c, ""),
CLK_LOOKUP("iface_clk", camss_top_ahb_clk.c, ""),
CLK_LOOKUP("iface_clk", camss_vfe_cpp_ahb_clk.c, "fda44000.qcom,iommu"),
CLK_LOOKUP("core_clk", camss_vfe_cpp_clk.c, "fda44000.qcom,iommu"),
- CLK_LOOKUP("camss_vfe_vfe0_clk", camss_vfe_vfe0_clk.c, ""),
- CLK_LOOKUP("camss_vfe_vfe1_clk", camss_vfe_vfe1_clk.c, ""),
- CLK_LOOKUP("vfe0_clk_src", vfe0_clk_src.c, ""),
- CLK_LOOKUP("vfe1_clk_src", vfe1_clk_src.c, ""),
- CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, ""),
- CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c, ""),
- CLK_LOOKUP("bus_clk", camss_vfe_vfe_ocmemnoc_clk.c, ""),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdp.0"),
+ CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdss_dsi_clk_ctrl"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "mdp.0"),
@@ -4992,6 +5181,8 @@
CLK_LOOKUP("core_clk", oxilicx_axi_clk.c, "fdb10000.qcom,iommu"),
CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, "fdb10000.qcom,iommu"),
CLK_LOOKUP("alt_core_clk", oxili_gfx3d_clk.c, "fdb10000.qcom,iommu"),
+ CLK_LOOKUP("core_clk", ocmemgx_core_clk.c, "fdd00000.qcom,ocmem"),
+ CLK_LOOKUP("iface_clk", ocmemcx_ocmemnoc_clk.c, "fdd00000.qcom,ocmem"),
CLK_LOOKUP("iface_clk", venus0_ahb_clk.c, "fdc84000.qcom,iommu"),
CLK_LOOKUP("alt_core_clk", venus0_vcodec0_clk.c, "fdc84000.qcom,iommu"),
CLK_LOOKUP("core_clk", venus0_axi_clk.c, "fdc84000.qcom,iommu"),
@@ -5358,6 +5549,19 @@
WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
}
+static void __init mdss_clock_setup(void)
+{
+ clk_ops_byte = clk_ops_rcg_mnd;
+ clk_ops_byte.set_rate = set_rate_byte;
+ clk_ops_dsi_byte_pll.get_parent = dsi_pll_clk_get_parent;
+
+ clk_ops_pixel = clk_ops_rcg;
+ clk_ops_pixel.set_rate = set_rate_pixel;
+ clk_ops_dsi_pixel_pll.get_parent = dsi_pll_clk_get_parent;
+
+ mdss_clk_ctrl_init();
+}
+
static void __init msm8974_clock_post_init(void)
{
clk_set_rate(&axi_clk_src.c, 282000000);
@@ -5388,6 +5592,8 @@
clk_prepare_enable(&gcc_mmss_noc_cfg_ahb_clk.c);
clk_prepare_enable(&gcc_ocmem_noc_cfg_ahb_clk.c);
+ mdss_clock_setup();
+
/* Set rates for single-rate clocks. */
clk_set_rate(&usb30_master_clk_src.c,
usb30_master_clk_src.freq_tbl[0].freq_hz);
@@ -5432,6 +5638,24 @@
#define APCS_GCC_CC_PHYS 0xF9011000
#define APCS_GCC_CC_SIZE SZ_4K
+static void __init enable_rpm_scaling(void)
+{
+ int rc, value = 0x1;
+ struct msm_rpm_kvp kvp = {
+ .key = RPM_SMD_KEY_ENABLE,
+ .data = (void *)&value,
+ .length = sizeof(value),
+ };
+
+ rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_SLEEP_SET,
+ RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
+ WARN(rc < 0, "RPM clock scaling (sleep set) did not enable!\n");
+
+ rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_ACTIVE_SET,
+ RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
+ WARN(rc < 0, "RPM clock scaling (active set) did not enable!\n");
+}
+
static void __init msm8974_clock_pre_init(void)
{
virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
@@ -5469,6 +5693,8 @@
vote_vdd_level(&vdd_dig, VDD_DIG_HIGH);
rpm_regulator_enable(vdd_dig_reg);
+ enable_rpm_scaling();
+
reg_init();
}
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 099b012..807d587 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -250,6 +250,40 @@
.release = seq_release,
};
+static int fmax_rates_show(struct seq_file *m, void *unused)
+{
+ struct clk *clock = m->private;
+ int level = 0;
+
+ int vdd_level = find_vdd_level(clock, clock->rate);
+ if (vdd_level < 0) {
+ seq_printf(m, "could not find_vdd_level for %s, %ld\n",
+ clock->dbg_name, clock->rate);
+ return 0;
+ }
+ for (level = 0; level < ARRAY_SIZE(clock->fmax); level++) {
+ if (vdd_level == level)
+ seq_printf(m, "[%lu] ", clock->fmax[level]);
+ else
+ seq_printf(m, "%lu ", clock->fmax[level]);
+ }
+ seq_printf(m, "\n");
+
+ return 0;
+}
+
+static int fmax_rates_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, fmax_rates_show, inode->i_private);
+}
+
+static const struct file_operations fmax_rates_fops = {
+ .open = fmax_rates_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
int __init clock_debug_add(struct clk *clock)
{
char temp[50], *ptr;
@@ -293,6 +327,11 @@
S_IRUGO, clk_dir, clock, &list_rates_fops))
goto error;
+ if (clock->vdd_class && !debugfs_create_file("fmax_rates",
+ S_IRUGO, clk_dir, clock, &fmax_rates_fops))
+ goto error;
+
+
return 0;
error:
debugfs_remove_recursive(clk_dir);
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index d5ee35b..42b36f6 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -110,20 +110,26 @@
void set_rate_hid(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
{
u32 cfg_regval;
+ unsigned long flags;
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
cfg_regval &= ~(CFG_RCGR_DIV_MASK | CFG_RCGR_SRC_SEL_MASK);
cfg_regval |= nf->div_src_val;
writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg));
rcg_update_config(rcg);
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}
/* RCG set rate function for clocks with MND & Half Integer Dividers. */
void set_rate_mnd(struct rcg_clk *rcg, struct clk_freq_tbl *nf)
{
u32 cfg_regval;
+ unsigned long flags;
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
writel_relaxed(nf->m_val, M_REG(rcg));
writel_relaxed(nf->n_val, N_REG(rcg));
writel_relaxed(nf->d_val, D_REG(rcg));
@@ -139,6 +145,7 @@
writel_relaxed(cfg_regval, CFG_RCGR_REG(rcg));
rcg_update_config(rcg);
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}
static int rcg_clk_enable(struct clk *c)
@@ -157,7 +164,6 @@
struct clk_freq_tbl *cf, *nf;
struct rcg_clk *rcg = to_rcg_clk(c);
int rc = 0;
- unsigned long flags;
for (nf = rcg->freq_tbl; nf->freq_hz != FREQ_END
&& nf->freq_hz != rate; nf++)
@@ -178,13 +184,9 @@
BUG_ON(!rcg->set_rate);
- spin_lock_irqsave(&local_clock_reg_lock, flags);
-
/* Perform clock-specific frequency switch operations. */
rcg->set_rate(rcg, nf);
- spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
/* Release source requirements of the old freq. */
if (rcg->c.count)
clk_disable(cf->src_clk);
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 572cec6f..46e9e0c 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -36,7 +36,7 @@
const u32 m_val;
const u32 n_val;
const u32 d_val;
- const u32 div_src_val;
+ u32 div_src_val;
const unsigned sys_vdd;
};
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
new file mode 100644
index 0000000..e8aa790
--- /dev/null
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -0,0 +1,225 @@
+/* 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 <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/iopoll.h>
+#include <linux/clk.h>
+
+#include <asm/processor.h>
+#include <mach/msm_iomap.h>
+
+#include "clock.h"
+#include "clock-mdss-8974.h"
+
+#define MDSS_DSI_PHY_BASE_ADR 0xFD922800
+#define DSI_REG_SIZE 2048
+
+#define VCO_CLK 424000000
+static unsigned char *mdss_dsi_base;
+static int pll_byte_clk_rate;
+static int pll_pclk_rate;
+static int pll_initialized;
+static struct clk *mdss_dsi_ahb_clk;
+
+void __init mdss_clk_ctrl_init(void)
+{
+ mdss_dsi_base = ioremap(MDSS_DSI_PHY_BASE_ADR,
+ DSI_REG_SIZE);
+ if (!mdss_dsi_base)
+ pr_err("%s:%d unable to remap dsi base",
+ __func__, __LINE__);
+
+ mdss_dsi_ahb_clk = clk_get_sys("mdss_dsi_clk_ctrl", "iface_clk");
+ if (!IS_ERR(mdss_dsi_ahb_clk)) {
+ clk_prepare(mdss_dsi_ahb_clk);
+ } else {
+ mdss_dsi_ahb_clk = NULL;
+ pr_err("%s:%d unable to get iface clock\n",
+ __func__, __LINE__);
+ }
+}
+
+static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
+{
+ if (pll_initialized)
+ return pll_byte_clk_rate;
+ else {
+ pr_err("%s: DSI PLL not configured\n",
+ __func__);
+ return -EINVAL;
+ }
+}
+
+static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
+{
+ if (pll_initialized)
+ return pll_pclk_rate;
+ else {
+ pr_err("%s: Configure Byte clk first\n",
+ __func__);
+ return -EINVAL;
+ }
+}
+
+static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
+{
+ if (pll_initialized)
+ return 0;
+ else {
+ pr_err("%s: Configure Byte clk first\n",
+ __func__);
+ return -EINVAL;
+ }
+}
+
+static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
+{
+ int pll_divcfg1, pll_divcfg2;
+ int half_bitclk_rate;
+
+ if (pll_initialized)
+ return 0;
+
+ if (!mdss_dsi_ahb_clk) {
+ pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ clk_enable(mdss_dsi_ahb_clk);
+
+ half_bitclk_rate = rate * 4;
+
+ pll_divcfg1 = (VCO_CLK / half_bitclk_rate) - 2;
+
+ /* Configuring the VCO to 424 Mhz */
+ /* Configuring the half rate Bit clk to 212 Mhz */
+
+ pll_divcfg2 = 3; /* ByteClk is 1/4 the half-bitClk rate */
+
+ /* Configure the Loop filter */
+ /* Loop filter resistance value */
+ writel_relaxed(0x08, mdss_dsi_base + 0x022c);
+ /* Loop filter capacitance values : c1 and c2 */
+ writel_relaxed(0x70, mdss_dsi_base + 0x0230);
+ writel_relaxed(0x15, mdss_dsi_base + 0x0234);
+
+ writel_relaxed(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
+ writel_relaxed(pll_divcfg1, mdss_dsi_base + 0x0204); /* postDiv1 */
+ writel_relaxed(pll_divcfg2, mdss_dsi_base + 0x0224); /* postDiv2 */
+ writel_relaxed(0x03, mdss_dsi_base + 0x0228); /* postDiv3 */
+
+ writel_relaxed(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
+ writel_relaxed(0x06, mdss_dsi_base + 0x027c); /* Cal CFG4 */
+ writel_relaxed(0x05, mdss_dsi_base + 0x0264); /* Cal CFG4 */
+
+ writel_relaxed(0x0a, mdss_dsi_base + 0x023c); /* SDM CFG1 */
+ writel_relaxed(0xab, mdss_dsi_base + 0x0240); /* SDM CFG2 */
+ writel_relaxed(0x0a, mdss_dsi_base + 0x0244); /* SDM CFG3 */
+ writel_relaxed(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
+
+ udelay(10);
+
+ writel_relaxed(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
+ writel_relaxed(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
+ writel_relaxed(0x01, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
+ writel_relaxed(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
+ writel_relaxed(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
+
+ writel_relaxed(0x5f, mdss_dsi_base + 0x028c); /* CAL CFG8 */
+ writel_relaxed(0xa8, mdss_dsi_base + 0x0294); /* CAL CFG10 */
+ writel_relaxed(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
+ writel_relaxed(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
+ writel_relaxed(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
+ writel_relaxed(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
+ writel_relaxed(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
+ writel_relaxed(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
+
+ pll_byte_clk_rate = 53000000;
+ pll_pclk_rate = 105000000;
+
+ clk_disable(mdss_dsi_ahb_clk);
+ pll_initialized = 1;
+
+ return 0;
+}
+
+static int mdss_dsi_pll_enable(struct clk *c)
+{
+ u32 status;
+ u32 max_reads, timeout_us;
+ static int pll_enabled;
+
+ if (pll_enabled)
+ return 0;
+
+ if (!mdss_dsi_ahb_clk) {
+ pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ clk_enable(mdss_dsi_ahb_clk);
+ /* PLL power up */
+ writel_relaxed(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
+ writel_relaxed(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(20);
+ writel_relaxed(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
+ udelay(20);
+ writel_relaxed(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
+
+ /* poll for PLL ready status */
+ max_reads = 20;
+ timeout_us = 100;
+ if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
+ status,
+ ((status & 0x01) == 1),
+ max_reads, timeout_us)) {
+ pr_err("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ clk_disable(mdss_dsi_ahb_clk);
+ return -EINVAL;
+ }
+ clk_disable(mdss_dsi_ahb_clk);
+ pll_enabled = 1;
+
+ return 0;
+}
+
+static void mdss_dsi_pll_disable(struct clk *c)
+{
+ if (!mdss_dsi_ahb_clk)
+ pr_err("%s: mdss_dsi_ahb_clk not initialized\n",
+ __func__);
+
+ clk_enable(mdss_dsi_ahb_clk);
+ writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
+ clk_disable(mdss_dsi_ahb_clk);
+}
+
+struct clk_ops clk_ops_dsi_pixel_pll = {
+ .enable = mdss_dsi_pll_enable,
+ .disable = mdss_dsi_pll_disable,
+ .set_rate = mdss_dsi_pll_pixel_set_rate,
+ .round_rate = mdss_dsi_pll_pixel_round_rate,
+};
+
+struct clk_ops clk_ops_dsi_byte_pll = {
+ .enable = mdss_dsi_pll_enable,
+ .disable = mdss_dsi_pll_disable,
+ .set_rate = mdss_dsi_pll_byte_set_rate,
+ .round_rate = mdss_dsi_pll_byte_round_rate,
+};
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
new file mode 100644
index 0000000..aaf72d2
--- /dev/null
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -0,0 +1,20 @@
+/* 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 __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
+#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
+
+void mdss_clk_ctrl_init(void);
+extern struct clk_ops clk_ops_dsi_byte_pll;
+extern struct clk_ops clk_ops_dsi_pixel_pll;
+
+#endif
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index be69827..149a0511 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -64,7 +64,8 @@
if (!r->branch) {
r->last_set_khz = iv.value;
- r->last_set_sleep_khz = iv.value;
+ if (!r->active_only)
+ r->last_set_sleep_khz = iv.value;
r->c.rate = iv.value * r->factor;
}
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index da8c3a9..f605c1f 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -33,7 +33,7 @@
static LIST_HEAD(handoff_list);
/* Find the voltage level required for a given rate. */
-static int find_vdd_level(struct clk *clk, unsigned long rate)
+int find_vdd_level(struct clk *clk, unsigned long rate)
{
int level;
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index ff0e973..d88466d 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -175,6 +175,7 @@
void msm_clock_init(struct clock_init_data *data);
int vote_vdd_level(struct clk_vdd_class *vdd_class, int level);
int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level);
+int find_vdd_level(struct clk *clk, unsigned long rate);
#ifdef CONFIG_DEBUG_FS
int clock_debug_init(struct clock_init_data *data);
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index e4ec4d4..a3a1574 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -68,29 +68,6 @@
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
};
-
-#ifdef CONFIG_MSM_SLEEP_STATS
-static DEFINE_PER_CPU(struct atomic_notifier_head, msm_cpuidle_notifiers);
-
-int msm_cpuidle_register_notifier(unsigned int cpu, struct notifier_block *nb)
-{
- struct atomic_notifier_head *head =
- &per_cpu(msm_cpuidle_notifiers, cpu);
-
- return atomic_notifier_chain_register(head, nb);
-}
-EXPORT_SYMBOL(msm_cpuidle_register_notifier);
-
-int msm_cpuidle_unregister_notifier(unsigned int cpu, struct notifier_block *nb)
-{
- struct atomic_notifier_head *head =
- &per_cpu(msm_cpuidle_notifiers, cpu);
-
- return atomic_notifier_chain_unregister(head, nb);
-}
-EXPORT_SYMBOL(msm_cpuidle_unregister_notifier);
-#endif
-
static int msm_cpuidle_enter(
struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
{
@@ -98,16 +75,6 @@
int i = 0;
enum msm_pm_sleep_mode pm_mode;
struct cpuidle_state_usage *st_usage = NULL;
-#ifdef CONFIG_MSM_SLEEP_STATS
- struct atomic_notifier_head *head =
- &__get_cpu_var(msm_cpuidle_notifiers);
-#endif
-
- local_irq_disable();
-
-#ifdef CONFIG_MSM_SLEEP_STATS
- atomic_notifier_call_chain(head, MSM_CPUIDLE_STATE_ENTER, NULL);
-#endif
#ifdef CONFIG_CPU_PM
cpu_pm_enter();
@@ -128,10 +95,6 @@
cpu_pm_exit();
#endif
-#ifdef CONFIG_MSM_SLEEP_STATS
- atomic_notifier_call_chain(head, MSM_CPUIDLE_STATE_EXIT, NULL);
-#endif
-
local_irq_enable();
return ret;
@@ -219,16 +182,3 @@
return 0;
}
-
-static int __init msm_cpuidle_early_init(void)
-{
-#ifdef CONFIG_MSM_SLEEP_STATS
- unsigned int cpu;
-
- for_each_possible_cpu(cpu)
- ATOMIC_INIT_NOTIFIER_HEAD(&per_cpu(msm_cpuidle_notifiers, cpu));
-#endif
- return 0;
-}
-
-early_initcall(msm_cpuidle_early_init);
diff --git a/arch/arm/mach-msm/dal_axi.c b/arch/arm/mach-msm/dal_axi.c
index 739b7dc..1d873ca 100644
--- a/arch/arm/mach-msm/dal_axi.c
+++ b/arch/arm/mach-msm/dal_axi.c
@@ -17,6 +17,8 @@
#define DALRPC_PORT_NAME "DAL00"
enum {
+ DALRPC_AXI_ALLOCATE = DALDEVICE_FIRST_DEVICE_API_IDX + 1,
+ DALRPC_AXI_FREE = DALDEVICE_FIRST_DEVICE_API_IDX + 2,
DALRPC_AXI_CONFIGURE_BRIDGE = DALDEVICE_FIRST_DEVICE_API_IDX + 11
};
@@ -38,6 +40,67 @@
};
+static void *cam_dev_handle;
+static int __axi_free(int mode)
+{
+ int rc = 0;
+
+ if (!cam_dev_handle)
+ return rc;
+
+ rc = dalrpc_fcn_0(DALRPC_AXI_FREE, cam_dev_handle, mode);
+ if (rc) {
+ printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+ __func__, rc);
+ goto fail_dal_fcn_0;
+ }
+
+ /* close device handle */
+ rc = daldevice_detach(cam_dev_handle);
+ if (rc) {
+ printk(KERN_ERR "%s: failed to detach AXI bus device (%d)\n",
+ __func__, rc);
+ goto fail_dal_attach_detach;
+ }
+ cam_dev_handle = NULL;
+ return 0;
+
+fail_dal_fcn_0:
+ (void)daldevice_detach(cam_dev_handle);
+ cam_dev_handle = NULL;
+fail_dal_attach_detach:
+ return rc;
+}
+
+static int __axi_allocate(int mode)
+{
+ int rc;
+
+ /* get device handle */
+ rc = daldevice_attach(DALDEVICEID_AXI, DALRPC_PORT_NAME,
+ DALRPC_DEST_MODEM, &cam_dev_handle);
+ if (rc) {
+ printk(KERN_ERR "%s: failed to attach AXI bus device (%d)\n",
+ __func__, rc);
+ goto fail_dal_attach_detach;
+ }
+
+ rc = dalrpc_fcn_0(DALRPC_AXI_ALLOCATE, cam_dev_handle, mode);
+ if (rc) {
+ printk(KERN_ERR "%s: AXI bus device (%d) failed to be configured\n",
+ __func__, rc);
+ goto fail_dal_fcn_0;
+ }
+
+ return 0;
+
+fail_dal_fcn_0:
+ (void)daldevice_detach(cam_dev_handle);
+ cam_dev_handle = NULL;
+fail_dal_attach_detach:
+ return rc;
+}
+
static int axi_configure_bridge_grfx_sync_mode(int bridge_mode)
{
int rc;
@@ -82,7 +145,15 @@
return rc;
}
+int axi_free(mode)
+{
+ return __axi_free(mode);
+}
+int axi_allocate(mode)
+{
+ return __axi_allocate(mode);
+}
int set_grp2d_async(void)
{
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 0d05df9..3b262bc 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -29,6 +29,7 @@
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
#include <mach/msm_tsif.h>
+#include <mach/msm_tspp.h>
#include <mach/msm_bus_board.h>
#include <mach/rpm.h>
#include <mach/mdm2.h>
@@ -583,6 +584,67 @@
}
};
+#define MSM_TSPP_PHYS (0x18202000)
+#define MSM_TSPP_SIZE (0x1000)
+#define MSM_TSPP_BAM_PHYS (0x18204000)
+#define MSM_TSPP_BAM_SIZE (0x2000)
+
+static const struct msm_gpio tspp_gpios[] = {
+ { .gpio_cfg = TSIF_0_CLK, .label = "tsif_clk", },
+ { .gpio_cfg = TSIF_0_EN, .label = "tsif_en", },
+ { .gpio_cfg = TSIF_0_DATA, .label = "tsif_data", },
+ { .gpio_cfg = TSIF_0_SYNC, .label = "tsif_sync", },
+ { .gpio_cfg = TSIF_1_CLK, .label = "tsif_clk", },
+ { .gpio_cfg = TSIF_1_EN, .label = "tsif_en", },
+ { .gpio_cfg = TSIF_1_DATA, .label = "tsif_data", },
+ { .gpio_cfg = TSIF_1_SYNC, .label = "tsif_sync", },
+};
+
+static struct resource tspp_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ .start = TSIF_TSPP_IRQ,
+ .end = TSIF1_IRQ,
+ },
+ [1] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSIF0_PHYS,
+ .end = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
+ },
+ [2] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSIF1_PHYS,
+ .end = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
+ },
+ [3] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSPP_PHYS,
+ .end = MSM_TSPP_PHYS + MSM_TSPP_SIZE - 1,
+ },
+ [4] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSPP_BAM_PHYS,
+ .end = MSM_TSPP_BAM_PHYS + MSM_TSPP_BAM_SIZE - 1,
+ },
+};
+
+static struct msm_tspp_platform_data tspp_platform_data = {
+ .num_gpios = ARRAY_SIZE(tspp_gpios),
+ .gpios = tspp_gpios,
+ .tsif_pclk = "iface_clk",
+ .tsif_ref_clk = "ref_clk",
+};
+
+struct platform_device msm_8064_device_tspp = {
+ .name = "msm_tspp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(tspp_resources),
+ .resource = tspp_resources,
+ .dev = {
+ .platform_data = &tspp_platform_data
+ },
+};
+
/*
* Machine specific data for AUX PCM Interface
* which the driver will be unware of.
@@ -674,6 +736,11 @@
.id = -1,
};
+struct platform_device apq_lowlatency_pcm = {
+ .name = "msm-lowlatency-pcm-dsp",
+ .id = -1,
+};
+
struct platform_device apq_pcm_hostless = {
.name = "msm-pcm-hostless",
.id = -1,
@@ -2781,26 +2848,6 @@
struct msm_iommu_domain_name apq8064_iommu_ctx_names[] = {
/* Camera */
{
- .name = "vpe_src",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vpe_dst",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vfe_imgwr",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vfe_misc",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
.name = "ijpeg_src",
.domain = CAMERA_DOMAIN,
},
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index eac2140..a257a9c 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -853,26 +853,6 @@
struct msm_iommu_domain_name msm8930_iommu_ctx_names[] = {
/* Camera */
{
- .name = "vpe_src",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vpe_dst",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vfe_imgwr",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vfe_misc",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
.name = "ijpeg_src",
.domain = CAMERA_DOMAIN,
},
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 8347580..377ecae 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -50,6 +50,7 @@
#include "scm-pas.h"
#include <mach/msm_dcvs.h>
#include <mach/iommu_domains.h>
+#include <mach/socinfo.h>
#ifdef CONFIG_MSM_MPM
#include <mach/mpm.h>
@@ -207,6 +208,11 @@
.id = -1,
};
+struct platform_device msm8960ab_device_acpuclk = {
+ .name = "acpuclk-8960ab",
+ .id = -1,
+};
+
#define SHARED_IMEM_TZ_BASE 0x2a03f720
static struct resource tzlog_resources[] = {
{
@@ -712,7 +718,7 @@
},
{
ARRAY_SIZE(vidc_venc_1080p_turbo_vectors),
- vidc_vdec_1080p_turbo_vectors,
+ vidc_venc_1080p_turbo_vectors,
},
{
ARRAY_SIZE(vidc_vdec_1080p_turbo_vectors),
@@ -725,6 +731,286 @@
ARRAY_SIZE(vidc_bus_client_config),
.name = "vidc",
};
+
+static struct msm_bus_vectors vidc_pro_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+static struct msm_bus_vectors vidc_pro_venc_vga_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 54525952,
+ .ib = 436207616,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 72351744,
+ .ib = 289406976,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 500000,
+ .ib = 1000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 500000,
+ .ib = 1000000,
+ },
+};
+static struct msm_bus_vectors vidc_pro_vdec_vga_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 40894464,
+ .ib = 327155712,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 48234496,
+ .ib = 192937984,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 500000,
+ .ib = 2000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 500000,
+ .ib = 2000000,
+ },
+};
+static struct msm_bus_vectors vidc_pro_venc_720p_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 163577856,
+ .ib = 1308622848,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 219152384,
+ .ib = 876609536,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 1750000,
+ .ib = 3500000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 1750000,
+ .ib = 3500000,
+ },
+};
+static struct msm_bus_vectors vidc_pro_vdec_720p_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 121634816,
+ .ib = 973078528,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 155189248,
+ .ib = 620756992,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 1750000,
+ .ib = 7000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 1750000,
+ .ib = 7000000,
+ },
+};
+static struct msm_bus_vectors vidc_pro_venc_1080p_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 372244480,
+ .ib = 2560000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 501219328,
+ .ib = 2560000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 5000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 5000000,
+ },
+};
+static struct msm_bus_vectors vidc_pro_vdec_1080p_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 222298112,
+ .ib = 2560000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 330301440,
+ .ib = 2560000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 700000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 10000000,
+ },
+};
+static struct msm_bus_vectors vidc_pro_venc_1080p_turbo_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 222298112,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 330301440,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 700000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 10000000,
+ },
+};
+static struct msm_bus_vectors vidc_pro_vdec_1080p_turbo_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 222298112,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 330301440,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 700000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 10000000,
+ },
+};
+
+static struct msm_bus_paths vidc_pro_bus_client_config[] = {
+ {
+ ARRAY_SIZE(vidc_pro_init_vectors),
+ vidc_pro_init_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_pro_venc_vga_vectors),
+ vidc_pro_venc_vga_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_pro_vdec_vga_vectors),
+ vidc_pro_vdec_vga_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_pro_venc_720p_vectors),
+ vidc_pro_venc_720p_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_pro_vdec_720p_vectors),
+ vidc_pro_vdec_720p_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_pro_venc_1080p_vectors),
+ vidc_pro_venc_1080p_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_pro_vdec_1080p_vectors),
+ vidc_pro_vdec_1080p_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_pro_venc_1080p_turbo_vectors),
+ vidc_pro_venc_1080p_turbo_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_vdec_1080p_turbo_vectors),
+ vidc_pro_vdec_1080p_turbo_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata vidc_pro_bus_client_data = {
+ vidc_pro_bus_client_config,
+ ARRAY_SIZE(vidc_bus_client_config),
+ .name = "vidc",
+};
#endif
#ifdef CONFIG_HW_RANDOM_MSM
@@ -1949,6 +2235,11 @@
.id = -1,
};
+struct platform_device msm_lowlatency_pcm = {
+ .name = "msm-lowlatency-pcm-dsp",
+ .id = -1,
+};
+
struct platform_device msm_pcm_routing = {
.name = "msm-pcm-routing",
.id = -1,
@@ -2023,20 +2314,20 @@
.mode_8k = {
.mode = AFE_PCM_CFG_MODE_PCM,
.sync = AFE_PCM_CFG_SYNC_INT,
- .frame = AFE_PCM_CFG_FRM_256BPF,
+ .frame = AFE_PCM_CFG_FRM_32BPF,
.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
.slot = 0,
.data = AFE_PCM_CFG_CDATAOE_MASTER,
- .pcm_clk_rate = 2048000,
+ .pcm_clk_rate = 256000,
},
.mode_16k = {
.mode = AFE_PCM_CFG_MODE_PCM,
.sync = AFE_PCM_CFG_SYNC_INT,
- .frame = AFE_PCM_CFG_FRM_256BPF,
+ .frame = AFE_PCM_CFG_FRM_32BPF,
.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
.slot = 0,
.data = AFE_PCM_CFG_CDATAOE_MASTER,
- .pcm_clk_rate = 4096000,
+ .pcm_clk_rate = 512000,
}
};
@@ -3770,26 +4061,6 @@
struct msm_iommu_domain_name msm8960_iommu_ctx_names[] = {
/* Camera */
{
- .name = "vpe_src",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vpe_dst",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vfe_imgwr",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vfe_misc",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
.name = "ijpeg_src",
.domain = CAMERA_DOMAIN,
},
@@ -4039,3 +4310,19 @@
.num_resources = ARRAY_SIZE(sglte_resources),
.resource = sglte_resources,
};
+
+struct platform_device *msm8960_vidc_device[] __initdata = {
+ &msm_device_vidc
+};
+
+void __init msm8960_add_vidc_device(void)
+{
+ if (cpu_is_msm8960ab()) {
+ struct msm_vidc_platform_data *pdata;
+ pdata = (struct msm_vidc_platform_data *)
+ msm_device_vidc.dev.platform_data;
+ pdata->vidc_bus_client_pdata = &vidc_pro_bus_client_data;
+ }
+ platform_add_devices(msm8960_vidc_device,
+ ARRAY_SIZE(msm8960_vidc_device));
+}
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index c307714..0a9bbf6 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -174,25 +174,25 @@
static struct resource resources_usb_bam[] = {
{
- .name = "usb_bam_addr",
+ .name = "hsusb",
.start = MSM_USB_BAM_BASE,
.end = MSM_USB_BAM_BASE + MSM_USB_BAM_SIZE - 1,
.flags = IORESOURCE_MEM,
},
{
- .name = "usb_bam_irq",
+ .name = "hsusb",
.start = USB1_HS_BAM_IRQ,
.end = USB1_HS_BAM_IRQ,
.flags = IORESOURCE_IRQ,
},
{
- .name = "hsic_bam_addr",
+ .name = "hsic",
.start = MSM_HSIC_BAM_BASE,
.end = MSM_HSIC_BAM_BASE + MSM_HSIC_BAM_SIZE - 1,
.flags = IORESOURCE_MEM,
},
{
- .name = "hsic_bam_irq",
+ .name = "hsic",
.start = USB_HSIC_BAM_IRQ,
.end = USB_HSIC_BAM_IRQ,
.flags = IORESOURCE_IRQ,
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index ae8a8fe..b65bd1f 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -939,8 +939,11 @@
&msm_device_iommu_gfx2d1,
};
-static struct platform_device *msm_iommu_8064_devs[] = {
+static struct platform_device *msm_iommu_adreno3xx_gfx_devs[] = {
&msm_device_iommu_gfx3d1,
+};
+
+static struct platform_device *msm_iommu_vcap_devs[] = {
&msm_device_iommu_vcap,
};
@@ -973,9 +976,12 @@
&msm_device_gfx2d1_2d1_ctx,
};
-static struct platform_device *msm_iommu_8064_ctx_devs[] = {
+static struct platform_device *msm_iommu_adreno3xx_ctx_devs[] = {
&msm_device_gfx3d1_user_ctx,
&msm_device_gfx3d1_priv_ctx,
+};
+
+static struct platform_device *msm_iommu_vcap_ctx_devs[] = {
&msm_device_vcap_vc_ctx,
&msm_device_vcap_vp_ctx,
};
@@ -1014,9 +1020,12 @@
if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
platform_add_devices(msm_iommu_jpegd_devs,
ARRAY_SIZE(msm_iommu_jpegd_devs));
- platform_add_devices(msm_iommu_8064_devs,
- ARRAY_SIZE(msm_iommu_8064_devs));
+ platform_add_devices(msm_iommu_adreno3xx_gfx_devs,
+ ARRAY_SIZE(msm_iommu_adreno3xx_gfx_devs));
}
+ if (cpu_is_apq8064())
+ platform_add_devices(msm_iommu_vcap_devs,
+ ARRAY_SIZE(msm_iommu_vcap_devs));
/* Initialize common ctx_devs */
ret = platform_add_devices(msm_iommu_common_ctx_devs,
@@ -1033,9 +1042,13 @@
if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
platform_add_devices(msm_iommu_jpegd_ctx_devs,
ARRAY_SIZE(msm_iommu_jpegd_ctx_devs));
- platform_add_devices(msm_iommu_8064_ctx_devs,
- ARRAY_SIZE(msm_iommu_8064_ctx_devs));
+
+ platform_add_devices(msm_iommu_adreno3xx_ctx_devs,
+ ARRAY_SIZE(msm_iommu_adreno3xx_ctx_devs));
}
+ if (cpu_is_apq8064())
+ platform_add_devices(msm_iommu_vcap_ctx_devs,
+ ARRAY_SIZE(msm_iommu_vcap_ctx_devs));
return 0;
@@ -1068,16 +1081,33 @@
for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
platform_device_unregister(msm_iommu_jpegd_devs[i]);
}
+ if (cpu_is_apq8064()) {
+ for (i = 0; i < ARRAY_SIZE(msm_iommu_vcap_ctx_devs); i++)
+ platform_device_unregister(msm_iommu_vcap_ctx_devs[i]);
+ }
if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
- for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_ctx_devs); i++)
- platform_device_unregister(msm_iommu_8064_ctx_devs[i]);
+ for (i = 0; i < ARRAY_SIZE(msm_iommu_adreno3xx_ctx_devs);
+ i++)
+ platform_device_unregister(
+ msm_iommu_adreno3xx_ctx_devs[i]);
- for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_ctx_devs); i++)
- platform_device_unregister(msm_iommu_jpegd_ctx_devs[i]);
+ for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_ctx_devs);
+ i++)
+ platform_device_unregister(
+ msm_iommu_jpegd_ctx_devs[i]);
- for (i = 0; i < ARRAY_SIZE(msm_iommu_8064_devs); i++)
- platform_device_unregister(msm_iommu_8064_devs[i]);
+ if (cpu_is_apq8064()) {
+ for (i = 0; i < ARRAY_SIZE(msm_iommu_vcap_devs);
+ i++)
+ platform_device_unregister(
+ msm_iommu_vcap_devs[i]);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(msm_iommu_adreno3xx_gfx_devs);
+ i++)
+ platform_device_unregister(
+ msm_iommu_adreno3xx_gfx_devs[i]);
for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
platform_device_unregister(msm_iommu_jpegd_devs[i]);
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 1fcf7dc..0331919 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -39,6 +39,8 @@
#include "mpm-8625.h"
#include "irq.h"
#include "pm.h"
+#include "msm_cpr.h"
+#include "msm_smem_iface.h"
/* Address of GSBI blocks */
#define MSM_GSBI0_PHYS 0xA1200000
@@ -48,6 +50,12 @@
#define MSM_GSBI0_QUP_PHYS (MSM_GSBI0_PHYS + 0x80000)
#define MSM_GSBI1_QUP_PHYS (MSM_GSBI1_PHYS + 0x80000)
+#define A11S_TEST_BUS_SEL_ADDR (MSM_CSR_BASE + 0x518)
+#define RBCPR_CLK_MUX_SEL (1 << 13)
+
+/* Reset Address of RBCPR (Active Low)*/
+#define RBCPR_SW_RESET_N (MSM_CSR_BASE + 0x64)
+
static struct resource gsbi0_qup_i2c_resources[] = {
{
.name = "qup_phys_addr",
@@ -897,8 +905,13 @@
if (cpu_is_msm8625()) {
kgsl_3d0_pdata.idle_timeout = HZ/5;
kgsl_3d0_pdata.strtstp_sleepwake = false;
- /* 8x25 supports a higher GPU frequency */
- kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 320000000;
+
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+ /* 8x25 v2.0 & above supports a higher GPU frequency */
+ kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 320000000;
+ else
+ kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 300000000;
+
kgsl_3d0_pdata.pwrlevel[0].bus_freq = 200000000;
}
}
@@ -1250,8 +1263,8 @@
},
{
.name = "dma_chnl",
- .start = DMOV_SDC3_CHAN,
- .end = DMOV_SDC3_CHAN,
+ .start = DMOV_NAND_CHAN,
+ .end = DMOV_NAND_CHAN,
.flags = IORESOURCE_DMA,
},
{
@@ -1579,6 +1592,176 @@
},
};
+static struct resource cpr_resources[] = {
+ {
+ .start = MSM8625_INT_CPR_IRQ0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MSM8625_CPR_PHYS,
+ .end = MSM8625_CPR_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+/**
+ * These are various Vdd levels supported by PMIC
+ */
+static uint32_t msm_c2_pmic_mv[] __initdata = {
+ 1300, 12875 / 10, 1275, 12625 / 10, 1250,
+ 12375 / 10, 1225, 12125 / 10, 1200, 11875 / 10,
+ 1175, 11625 / 10, 1150, 11375 / 10, 1125,
+ 11125 / 10, 1100, 10875 / 10, 1075, 10625 / 10,
+ 1050, 10375 / 10, 1025, 10125 / 10, 0, 0, 0, 0,
+ 0, 0, 0, 1000,
+};
+
+/**
+ * This data will be based on CPR mode of operation
+ */
+static struct msm_cpr_mode msm_cpr_mode_data[] = {
+ [NORMAL_MODE] = {
+ .ring_osc_data = {
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ },
+ .ring_osc = 0,
+ .step_quot = ~0,
+ .tgt_volt_offset = 1,
+ .Vmax = 1200,
+ .Vmin = 1000,
+ .calibrated_mV = 1100,
+ },
+ [TURBO_MODE] = {
+ .ring_osc_data = {
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ {0, },
+ },
+ .ring_osc = 0,
+ .step_quot = ~0,
+ .tgt_volt_offset = 1,
+ .Vmax = 1350,
+ .Vmin = 1250,
+ .calibrated_mV = 1300,
+ },
+};
+
+struct msm_cpr_vp_data vp_data = {
+ .min_volt = 1000,
+ .max_volt = 1350,
+ .default_volt = 1300,
+ .step_size = (12500 / 1000),
+};
+
+static struct msm_cpr_config msm_cpr_pdata = {
+ .ref_clk_khz = 19200,
+ .delay_us = 10000,
+ .irq_line = 0,
+ .cpr_mode_data = msm_cpr_mode_data,
+ .tgt_count_div_N = 1,
+ .floor = 0,
+ .ceiling = 40,
+ .sw_vlevel = 20,
+ .up_threshold = 1,
+ .dn_threshold = 2,
+ .up_margin = 0,
+ .dn_margin = 0,
+ .nom_freq_limit = 1008000,
+ .vp_data = &vp_data,
+};
+
+static struct platform_device msm8625_device_cpr = {
+ .name = "msm-cpr",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cpr_resources),
+ .resource = cpr_resources,
+ .dev = {
+ .platform_data = &msm_cpr_pdata,
+ },
+};
+
+static struct platform_device msm8625_vp_device = {
+ .name = "vp-regulator",
+ .id = -1,
+};
+
+static void __init msm_cpr_init(void)
+{
+ struct cpr_info_type *cpr_info = NULL;
+ uint8_t ring_osc = 0;
+ uint32_t reg_val;
+
+ cpr_info = kzalloc(sizeof(struct cpr_info_type), GFP_KERNEL);
+ if (!cpr_info) {
+ pr_err("%s: Out of memory %d\n", __func__, -ENOMEM);
+ return;
+ }
+
+ msm_smem_get_cpr_info(cpr_info);
+
+ /**
+ * Set the ring_osc based on efuse BIT(0)
+ * CPR_fuse[0] = 0 selects 2nd RO (010)
+ * CPR_fuse[0] = 1 select 3rd RO (011)
+ */
+ if (cpr_info->ring_osc == 0x0)
+ ring_osc = 0x2;
+ else if (cpr_info->ring_osc == 0x1)
+ ring_osc = 0x3;
+
+ msm_cpr_mode_data[TURBO_MODE].ring_osc = ring_osc;
+ msm_cpr_mode_data[NORMAL_MODE].ring_osc = ring_osc;
+
+ /* GCNT = 1000 nsec/52nsec (@TCX0=19.2Mhz) = 19.2 */
+ msm_cpr_mode_data[TURBO_MODE].ring_osc_data[ring_osc].gcnt = 19;
+ msm_cpr_mode_data[NORMAL_MODE].ring_osc_data[ring_osc].gcnt = 19;
+
+ /* The multiplier and offset are as per PTE data */
+ msm_cpr_mode_data[TURBO_MODE].ring_osc_data[ring_osc].target_count =
+ cpr_info->turbo_quot * 10 + 440;
+ msm_cpr_mode_data[NORMAL_MODE].ring_osc_data[ring_osc].target_count =
+ cpr_info->turbo_quot / msm_cpr_pdata.tgt_count_div_N;
+
+ /**
+ * Bits 4:0 of pvs_fuse provide mapping to the safe boot up voltage.
+ * Boot up mode is by default Turbo.
+ */
+ msm_cpr_mode_data[TURBO_MODE].calibrated_mV =
+ msm_c2_pmic_mv[cpr_info->pvs_fuse & 0x1F];
+
+ /* TODO: Store the tgt_volt_offset values for the modes from PTE */
+
+
+ pr_debug("%s: cpr: ring_osc: 0x%x\n", __func__,
+ msm_cpr_mode_data[TURBO_MODE].ring_osc);
+ pr_debug("%s: cpr: turbo_quot: 0x%x\n", __func__, cpr_info->turbo_quot);
+ pr_debug("%s: cpr: pvs_fuse: 0x%x\n", __func__, cpr_info->pvs_fuse);
+ kfree(cpr_info);
+
+ /* Select TCXO (19.2MHz) as clock source */
+ reg_val = readl_relaxed(A11S_TEST_BUS_SEL_ADDR);
+ reg_val |= RBCPR_CLK_MUX_SEL;
+ writel_relaxed(reg_val, A11S_TEST_BUS_SEL_ADDR);
+
+ /* Get CPR out of reset */
+ writel_relaxed(0x1, RBCPR_SW_RESET_N);
+
+ platform_device_register(&msm8625_vp_device);
+ platform_device_register(&msm8625_device_cpr);
+}
+
static struct clk_lookup msm_clock_8625_dummy[] = {
CLK_DUMMY("core_clk", adm_clk.c, "msm_dmov", 0),
CLK_DUMMY("adsp_clk", adsp_clk.c, NULL, 0),
@@ -1645,7 +1828,6 @@
.table = msm_clock_8625_dummy,
.size = ARRAY_SIZE(msm_clock_8625_dummy),
};
-
enum {
MSM8625,
MSM8625A,
@@ -1669,6 +1851,7 @@
/* Part number for 1.2GHz part */
case 0x773:
case 0x774:
+ case 0x779:
case 0x781:
case 0x8D1:
cpu = MSM8625A;
@@ -1691,6 +1874,7 @@
{
if (machine_is_msm8625_rumi3()) {
msm_clock_init(&msm8625_dummy_clock_init_data);
+ msm_cpr_init();
return 0;
}
@@ -1707,6 +1891,11 @@
} else {
platform_device_register(&msm7x27a_device_acpuclk);
}
+
+ if (cpu_is_msm8625() &&
+ (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2))
+ msm_cpr_init();
+
return 0;
}
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index a6473c6..45486f4 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -1329,7 +1329,7 @@
static struct kgsl_device_platform_data kgsl_2d0_pdata = {
.pwrlevel = {
{
- .gpu_freq = 192000000,
+ .gpu_freq = 0,
.bus_freq = 192000000,
},
},
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 05f9d75..57d7f08 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -2315,10 +2315,14 @@
#ifdef CONFIG_MSM_BUS_SCALING
.vidc_bus_client_pdata = &vidc_bus_client_data,
#endif
+#ifdef CONFIG_MSM_VIDC_CONTENT_PROTECTION
+ .cp_enabled = 1,
+#else
+ .cp_enabled = 0,
+#endif
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
.memtype = ION_CP_MM_HEAP_ID,
.enable_ion = 1,
- .cp_enabled = 1,
.secure_wb_heap = 1,
#else
.memtype = MEMTYPE_SMI_KERNEL,
@@ -2999,26 +3003,6 @@
struct msm_iommu_domain_name msm8660_iommu_ctx_names[] = {
/* Camera */
{
- .name = "vpe_src",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vpe_dst",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vfe_imgwr",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
- .name = "vfe_misc",
- .domain = CAMERA_DOMAIN,
- },
- /* Camera */
- {
.name = "ijpeg_src",
.domain = CAMERA_DOMAIN,
},
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 8e2ab7d..3587672 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -190,6 +190,7 @@
extern struct platform_device msm_device_tsif[2];
extern struct platform_device msm_8064_device_tsif[2];
+extern struct platform_device msm_8064_device_tspp;
extern struct platform_device msm_device_ssbi_pmic1;
extern struct platform_device msm_device_ssbi_pmic2;
@@ -205,6 +206,7 @@
extern struct platform_device msm_pcm;
extern struct platform_device msm_multi_ch_pcm;
+extern struct platform_device msm_lowlatency_pcm;
extern struct platform_device msm_pcm_routing;
extern struct platform_device msm_cpudai0;
extern struct platform_device msm_cpudai1;
@@ -268,6 +270,7 @@
extern struct platform_device apq_lpa_pcm;
extern struct platform_device apq_compr_dsp;
extern struct platform_device apq_multi_ch_pcm;
+extern struct platform_device apq_lowlatency_pcm;
extern struct platform_device apq_pcm_hostless;
extern struct platform_device apq_cpudai_afe_01_rx;
extern struct platform_device apq_cpudai_afe_01_tx;
@@ -435,6 +438,7 @@
extern struct platform_device msm8930_device_acpuclk;
extern struct platform_device msm8930aa_device_acpuclk;
extern struct platform_device msm8960_device_acpuclk;
+extern struct platform_device msm8960ab_device_acpuclk;
extern struct platform_device msm9615_device_acpuclk;
extern struct platform_device msm_gpio_device;
diff --git a/arch/arm/mach-msm/idle_stats.c b/arch/arm/mach-msm/idle_stats.c
deleted file mode 100644
index f4d3a27..0000000
--- a/arch/arm/mach-msm/idle_stats.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/* Copyright (c) 2010, 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/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/cdev.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/hrtimer.h>
-#include <linux/interrupt.h>
-#include <linux/ktime.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-#include <linux/sched.h>
-#include <asm/uaccess.h>
-
-#include "idle_stats.h"
-#include <mach/cpuidle.h>
-
-/******************************************************************************
- * Debug Definitions
- *****************************************************************************/
-
-enum {
- MSM_IDLE_STATS_DEBUG_API = BIT(0),
- MSM_IDLE_STATS_DEBUG_SIGNAL = BIT(1),
- MSM_IDLE_STATS_DEBUG_MIGRATION = BIT(2),
-};
-
-static int msm_idle_stats_debug_mask;
-module_param_named(
- debug_mask, msm_idle_stats_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-
-/******************************************************************************
- * Driver Definitions
- *****************************************************************************/
-
-#define MSM_IDLE_STATS_DRIVER_NAME "msm_idle_stats"
-
-static dev_t msm_idle_stats_dev_nr;
-static struct cdev msm_idle_stats_cdev;
-static struct class *msm_idle_stats_class;
-
-/******************************************************************************
- * Device Definitions
- *****************************************************************************/
-
-struct msm_idle_stats_device {
- unsigned int cpu;
- struct mutex mutex;
- struct notifier_block notifier;
-
- int64_t collection_expiration;
- struct msm_idle_stats stats;
- struct hrtimer timer;
-
- wait_queue_head_t wait_q;
- atomic_t collecting;
-};
-
-static DEFINE_SPINLOCK(msm_idle_stats_devs_lock);
-static DEFINE_PER_CPU(struct msm_idle_stats_device *, msm_idle_stats_devs);
-
-/******************************************************************************
- *
- *****************************************************************************/
-
-static inline int64_t msm_idle_stats_bound_interval(int64_t interval)
-{
- if (interval <= 0)
- return 1;
-
- if (interval > UINT_MAX)
- return UINT_MAX;
-
- return interval;
-}
-
-static enum hrtimer_restart msm_idle_stats_timer(struct hrtimer *timer)
-{
- struct msm_idle_stats_device *stats_dev;
- unsigned int cpu;
- int64_t now;
- int64_t interval;
-
- stats_dev = container_of(timer, struct msm_idle_stats_device, timer);
- cpu = get_cpu();
-
- if (cpu != stats_dev->cpu) {
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_MIGRATION)
- pr_info("%s: timer migrated from cpu%u to cpu%u\n",
- __func__, stats_dev->cpu, cpu);
-
- stats_dev->stats.event = MSM_IDLE_STATS_EVENT_TIMER_MIGRATED;
- goto timer_exit;
- }
-
- now = ktime_to_us(ktime_get());
- interval = now - stats_dev->stats.last_busy_start;
-
- if (stats_dev->stats.busy_timer > 0 &&
- interval >= stats_dev->stats.busy_timer - 1)
- stats_dev->stats.event =
- MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED;
- else
- stats_dev->stats.event =
- MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED;
-
-timer_exit:
- atomic_set(&stats_dev->collecting, 0);
- wake_up_interruptible(&stats_dev->wait_q);
-
- put_cpu();
- return HRTIMER_NORESTART;
-}
-
-static void msm_idle_stats_pre_idle(struct msm_idle_stats_device *stats_dev)
-{
- int64_t now;
- int64_t interval;
-
- if (smp_processor_id() != stats_dev->cpu) {
- WARN_ON(1);
- return;
- }
-
- if (!atomic_read(&stats_dev->collecting))
- return;
-
- hrtimer_cancel(&stats_dev->timer);
-
- now = ktime_to_us(ktime_get());
- interval = now - stats_dev->stats.last_busy_start;
- interval = msm_idle_stats_bound_interval(interval);
-
- stats_dev->stats.busy_intervals[stats_dev->stats.nr_collected]
- = (__u32) interval;
- stats_dev->stats.last_idle_start = now;
-}
-
-static void msm_idle_stats_post_idle(struct msm_idle_stats_device *stats_dev)
-{
- int64_t now;
- int64_t interval;
- int64_t timer_interval;
- int rc;
-
- if (smp_processor_id() != stats_dev->cpu) {
- WARN_ON(1);
- return;
- }
-
- if (!atomic_read(&stats_dev->collecting))
- return;
-
- now = ktime_to_us(ktime_get());
- interval = now - stats_dev->stats.last_idle_start;
- interval = msm_idle_stats_bound_interval(interval);
-
- stats_dev->stats.idle_intervals[stats_dev->stats.nr_collected]
- = (__u32) interval;
- stats_dev->stats.nr_collected++;
- stats_dev->stats.last_busy_start = now;
-
- if (stats_dev->stats.nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS) {
- stats_dev->stats.event = MSM_IDLE_STATS_EVENT_COLLECTION_FULL;
- goto post_idle_collection_done;
- }
-
- timer_interval = stats_dev->collection_expiration - now;
- if (timer_interval <= 0) {
- stats_dev->stats.event =
- MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED;
- goto post_idle_collection_done;
- }
-
- if (stats_dev->stats.busy_timer > 0 &&
- timer_interval > stats_dev->stats.busy_timer)
- timer_interval = stats_dev->stats.busy_timer;
-
- rc = hrtimer_start(&stats_dev->timer,
- ktime_set(0, timer_interval * 1000), HRTIMER_MODE_REL_PINNED);
- WARN_ON(rc);
-
- return;
-
-post_idle_collection_done:
- atomic_set(&stats_dev->collecting, 0);
- wake_up_interruptible(&stats_dev->wait_q);
-}
-
-static int msm_idle_stats_notified(struct notifier_block *nb,
- unsigned long val, void *v)
-{
- struct msm_idle_stats_device *stats_dev = container_of(
- nb, struct msm_idle_stats_device, notifier);
-
- if (val == MSM_CPUIDLE_STATE_EXIT)
- msm_idle_stats_post_idle(stats_dev);
- else
- msm_idle_stats_pre_idle(stats_dev);
-
- return 0;
-}
-
-static int msm_idle_stats_collect(struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct msm_idle_stats_device *stats_dev;
- struct msm_idle_stats *stats;
- int rc;
-
- stats_dev = (struct msm_idle_stats_device *) filp->private_data;
- stats = &stats_dev->stats;
-
- rc = mutex_lock_interruptible(&stats_dev->mutex);
- if (rc) {
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_SIGNAL)
- pr_info("%s: interrupted while waiting on device "
- "mutex\n", __func__);
-
- rc = -EINTR;
- goto collect_exit;
- }
-
- if (atomic_read(&stats_dev->collecting)) {
- pr_err("%s: inconsistent state\n", __func__);
- rc = -EBUSY;
- goto collect_unlock_exit;
- }
-
- rc = copy_from_user(stats, (void *)arg, sizeof(*stats));
- if (rc) {
- rc = -EFAULT;
- goto collect_unlock_exit;
- }
-
- if (stats->nr_collected >= MSM_IDLE_STATS_NR_MAX_INTERVALS ||
- stats->busy_timer > MSM_IDLE_STATS_MAX_TIMER ||
- stats->collection_timer > MSM_IDLE_STATS_MAX_TIMER) {
- rc = -EINVAL;
- goto collect_unlock_exit;
- }
-
- if (get_cpu() != stats_dev->cpu) {
- put_cpu();
- rc = -EACCES;
- goto collect_unlock_exit;
- }
-
- /*
- * When collection_timer == 0, stop collecting at the next
- * post idle.
- */
- stats_dev->collection_expiration =
- ktime_to_us(ktime_get()) + stats->collection_timer;
-
- /*
- * Enable collection before starting any timer.
- */
- atomic_set(&stats_dev->collecting, 1);
-
- /*
- * When busy_timer == 0, do not set any busy timer.
- */
- if (stats->busy_timer > 0) {
- rc = hrtimer_start(&stats_dev->timer,
- ktime_set(0, stats->busy_timer * 1000),
- HRTIMER_MODE_REL_PINNED);
- WARN_ON(rc);
- }
-
- put_cpu();
- if (wait_event_interruptible(stats_dev->wait_q,
- !atomic_read(&stats_dev->collecting))) {
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_SIGNAL)
- pr_info("%s: interrupted while waiting on "
- "collection\n", __func__);
-
- hrtimer_cancel(&stats_dev->timer);
- atomic_set(&stats_dev->collecting, 0);
-
- rc = -EINTR;
- goto collect_unlock_exit;
- }
-
- stats->return_timestamp = ktime_to_us(ktime_get());
-
- rc = copy_to_user((void *)arg, stats, sizeof(*stats));
- if (rc) {
- rc = -EFAULT;
- goto collect_unlock_exit;
- }
-
-collect_unlock_exit:
- mutex_unlock(&stats_dev->mutex);
-
-collect_exit:
- return rc;
-}
-
-static int msm_idle_stats_open(struct inode *inode, struct file *filp)
-{
- struct msm_idle_stats_device *stats_dev;
- int rc;
-
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: enter\n", __func__);
-
- rc = nonseekable_open(inode, filp);
- if (rc) {
- pr_err("%s: failed to set nonseekable\n", __func__);
- goto open_bail;
- }
-
- stats_dev = (struct msm_idle_stats_device *)
- kzalloc(sizeof(*stats_dev), GFP_KERNEL);
- if (!stats_dev) {
- pr_err("%s: failed to allocate device struct\n", __func__);
- rc = -ENOMEM;
- goto open_bail;
- }
-
- stats_dev->cpu = MINOR(inode->i_rdev);
- mutex_init(&stats_dev->mutex);
- stats_dev->notifier.notifier_call = msm_idle_stats_notified;
- hrtimer_init(&stats_dev->timer,
- CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
- stats_dev->timer.function = msm_idle_stats_timer;
- init_waitqueue_head(&stats_dev->wait_q);
- atomic_set(&stats_dev->collecting, 0);
-
- filp->private_data = stats_dev;
-
- /*
- * Make sure only one device exists per cpu.
- */
- spin_lock(&msm_idle_stats_devs_lock);
- if (per_cpu(msm_idle_stats_devs, stats_dev->cpu)) {
- spin_unlock(&msm_idle_stats_devs_lock);
- rc = -EBUSY;
- goto open_free_bail;
- }
-
- per_cpu(msm_idle_stats_devs, stats_dev->cpu) = stats_dev;
- spin_unlock(&msm_idle_stats_devs_lock);
-
- rc = msm_cpuidle_register_notifier(stats_dev->cpu,
- &stats_dev->notifier);
- if (rc) {
- pr_err("%s: failed to register idle notification\n", __func__);
- goto open_null_bail;
- }
-
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: done\n", __func__);
- return 0;
-
-open_null_bail:
- spin_lock(&msm_idle_stats_devs_lock);
- per_cpu(msm_idle_stats_devs, stats_dev->cpu) = NULL;
- spin_unlock(&msm_idle_stats_devs_lock);
-
-open_free_bail:
- kfree(stats_dev);
-
-open_bail:
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: exit, %d\n", __func__, rc);
- return rc;
-}
-
-static int msm_idle_stats_release(struct inode *inode, struct file *filp)
-{
- struct msm_idle_stats_device *stats_dev;
- int rc;
-
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: enter\n", __func__);
-
- stats_dev = (struct msm_idle_stats_device *) filp->private_data;
- rc = msm_cpuidle_unregister_notifier(stats_dev->cpu,
- &stats_dev->notifier);
- WARN_ON(rc);
-
- spin_lock(&msm_idle_stats_devs_lock);
- per_cpu(msm_idle_stats_devs, stats_dev->cpu) = NULL;
- spin_unlock(&msm_idle_stats_devs_lock);
- filp->private_data = NULL;
-
- hrtimer_cancel(&stats_dev->timer);
- kfree(stats_dev);
-
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: done\n", __func__);
- return 0;
-}
-
-static long msm_idle_stats_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg)
-{
- int rc;
-
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: enter\n", __func__);
-
- switch (cmd) {
- case MSM_IDLE_STATS_IOC_COLLECT:
- rc = msm_idle_stats_collect(filp, cmd, arg);
- break;
-
- default:
- rc = -ENOTTY;
- break;
- }
-
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: exit, %d\n", __func__, rc);
- return rc;
-}
-
-/******************************************************************************
- *
- *****************************************************************************/
-
-static const struct file_operations msm_idle_stats_fops = {
- .owner = THIS_MODULE,
- .open = msm_idle_stats_open,
- .release = msm_idle_stats_release,
- .unlocked_ioctl = msm_idle_stats_ioctl,
-};
-
-static int __init msm_idle_stats_init(void)
-{
- unsigned int nr_cpus = num_possible_cpus();
- struct device *dev;
- int rc;
- int i;
-
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: enter\n", __func__);
-
- rc = alloc_chrdev_region(&msm_idle_stats_dev_nr,
- 0, nr_cpus, MSM_IDLE_STATS_DRIVER_NAME);
- if (rc) {
- pr_err("%s: failed to allocate device number, rc %d\n",
- __func__, rc);
- goto init_bail;
- }
-
- msm_idle_stats_class = class_create(THIS_MODULE,
- MSM_IDLE_STATS_DRIVER_NAME);
- if (IS_ERR(msm_idle_stats_class)) {
- pr_err("%s: failed to create device class\n", __func__);
- rc = -ENOMEM;
- goto init_unreg_bail;
- }
-
- for (i = 0; i < nr_cpus; i++) {
- dev = device_create(msm_idle_stats_class, NULL,
- msm_idle_stats_dev_nr + i, NULL,
- MSM_IDLE_STATS_DRIVER_NAME "%d", i);
-
- if (!dev) {
- pr_err("%s: failed to create device %d\n",
- __func__, i);
- rc = -ENOMEM;
- goto init_remove_bail;
- }
- }
-
- cdev_init(&msm_idle_stats_cdev, &msm_idle_stats_fops);
- msm_idle_stats_cdev.owner = THIS_MODULE;
-
- /*
- * Call cdev_add() last, after everything else is initialized and
- * the driver is ready to accept system calls.
- */
- rc = cdev_add(&msm_idle_stats_cdev, msm_idle_stats_dev_nr, nr_cpus);
- if (rc) {
- pr_err("%s: failed to register char device, rc %d\n",
- __func__, rc);
- goto init_remove_bail;
- }
-
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: done\n", __func__);
- return 0;
-
-init_remove_bail:
- for (i = i - 1; i >= 0; i--)
- device_destroy(
- msm_idle_stats_class, msm_idle_stats_dev_nr + i);
-
- class_destroy(msm_idle_stats_class);
-
-init_unreg_bail:
- unregister_chrdev_region(msm_idle_stats_dev_nr, nr_cpus);
-
-init_bail:
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: exit, %d\n", __func__, rc);
- return rc;
-}
-
-static void __exit msm_idle_stats_exit(void)
-{
- unsigned int nr_cpus = num_possible_cpus();
- int i;
-
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: enter\n", __func__);
-
- cdev_del(&msm_idle_stats_cdev);
-
- for (i = nr_cpus - 1; i >= 0; i--)
- device_destroy(
- msm_idle_stats_class, msm_idle_stats_dev_nr + i);
-
- class_destroy(msm_idle_stats_class);
- unregister_chrdev_region(msm_idle_stats_dev_nr, nr_cpus);
-
- if (msm_idle_stats_debug_mask & MSM_IDLE_STATS_DEBUG_API)
- pr_info("%s: done\n", __func__);
-}
-
-module_init(msm_idle_stats_init);
-module_exit(msm_idle_stats_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("idle stats driver");
-MODULE_VERSION("1.0");
diff --git a/arch/arm/mach-msm/idle_stats.h b/arch/arm/mach-msm/idle_stats.h
deleted file mode 100644
index 6c8db1e..0000000
--- a/arch/arm/mach-msm/idle_stats.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (c) 2010, 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 __ARCH_ARM_MACH_MSM_IDLE_STATS_H
-#define __ARCH_ARM_MACH_MSM_IDLE_STATS_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-enum msm_idle_stats_event {
- MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED = 1,
- MSM_IDLE_STATS_EVENT_COLLECTION_TIMER_EXPIRED = 2,
- MSM_IDLE_STATS_EVENT_COLLECTION_FULL = 3,
- MSM_IDLE_STATS_EVENT_TIMER_MIGRATED = 4,
-};
-
-/*
- * All time, timer, and time interval values are in units of
- * microseconds unless stated otherwise.
- */
-#define MSM_IDLE_STATS_NR_MAX_INTERVALS 100
-#define MSM_IDLE_STATS_MAX_TIMER 1000000
-
-struct msm_idle_stats {
- __u32 busy_timer;
- __u32 collection_timer;
-
- __u32 busy_intervals[MSM_IDLE_STATS_NR_MAX_INTERVALS];
- __u32 idle_intervals[MSM_IDLE_STATS_NR_MAX_INTERVALS];
- __u32 nr_collected;
- __s64 last_busy_start;
- __s64 last_idle_start;
-
- enum msm_idle_stats_event event;
- __s64 return_timestamp;
-};
-
-#define MSM_IDLE_STATS_IOC_MAGIC 0xD8
-#define MSM_IDLE_STATS_IOC_COLLECT \
- _IOWR(MSM_IDLE_STATS_IOC_MAGIC, 1, struct msm_idle_stats)
-
-#endif /* __ARCH_ARM_MACH_MSM_IDLE_STATS_H */
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 1770b97..d8f8480 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -64,18 +64,6 @@
uint8_t is_vpe;
struct msm_bus_scale_pdata *cam_bus_scale_table;
};
-enum msm_camera_csi_data_format {
- CSI_8BIT,
- CSI_10BIT,
- CSI_12BIT,
-};
-struct msm_camera_csi_params {
- enum msm_camera_csi_data_format data_format;
- uint8_t lane_cnt;
- uint8_t lane_assign;
- uint8_t settle_cnt;
- uint8_t dpcm_scheme;
-};
#ifdef CONFIG_SENSORS_MT9T013
struct msm_camera_legacy_device_platform_data {
@@ -180,21 +168,6 @@
YUV_SENSOR,
};
-enum camera_vreg_type {
- REG_LDO,
- REG_VS,
- REG_GPIO,
- REG_MAX
-};
-
-struct camera_vreg_t {
- const char *reg_name;
- enum camera_vreg_type type;
- int min_voltage;
- int max_voltage;
- int op_mode;
-};
-
struct msm_gpio_set_tbl {
unsigned gpio;
unsigned long flags;
@@ -234,6 +207,13 @@
enum msm_camera_i2c_mux_mode i2c_mux_mode;
};
+enum msm_camera_vreg_name_t {
+ CAM_VDIG,
+ CAM_VIO,
+ CAM_VANA,
+ CAM_VAF,
+};
+
struct msm_camera_sensor_platform_info {
int mount_angle;
int sensor_reset;
@@ -268,6 +248,9 @@
struct msm_eeprom_info {
struct i2c_board_info const *board_info;
int bus_id;
+ int eeprom_reg_addr;
+ int eeprom_read_length;
+ int eeprom_i2c_slave_addr;
};
struct msm_camera_sensor_info {
@@ -285,7 +268,6 @@
uint8_t num_resources;
struct msm_camera_sensor_flash_data *flash_data;
int csi_if;
- struct msm_camera_csi_params csi_params;
struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
char *eeprom_data;
enum msm_camera_type camera_type;
@@ -314,6 +296,17 @@
unsigned num;
};
+struct cad_endpoint {
+ int id;
+ const char *name;
+ uint32_t capability;
+};
+
+struct msm_cad_endpoints {
+ struct cad_endpoint *endpoints;
+ unsigned num;
+};
+
#define MSM_MAX_DEC_CNT 14
/* 7k target ADSP information */
/* Bit 23:0, for codec identification like mp3, wav etc *
@@ -334,6 +327,7 @@
MSM_ADSP_CODEC_AMRWB = 11,
MSM_ADSP_CODEC_EVRC = 12,
MSM_ADSP_CODEC_WMAPRO = 13,
+ MSM_ADSP_CODEC_AC3 = 23,
MSM_ADSP_MODE_TUNNEL = 24,
MSM_ADSP_MODE_NONTUNNEL = 25,
MSM_ADSP_MODE_LP = 26,
@@ -391,9 +385,7 @@
void (*panel_config_gpio)(int);
int (*vga_switch)(int select_vga);
int *gpio_num;
- int mdp_core_clk_rate;
- unsigned num_mdp_clk;
- int *mdp_core_clk_table;
+ u32 mdp_max_clk;
#ifdef CONFIG_MSM_BUS_SCALING
struct msm_bus_scale_pdata *mdp_bus_scale_table;
#endif
@@ -583,6 +575,7 @@
void msm_8974_reserve(void);
void msm_8974_very_early(void);
void msm_8974_init_gpiomux(void);
+void msm9625_init_gpiomux(void);
struct mmc_platform_data;
int msm_add_sdcc(unsigned int controller,
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index a51a6b5..0867c1d 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -127,30 +127,6 @@
uint32_t frame_id;
};
-struct msm_camera_csid_lut_params {
- uint8_t num_cid;
- struct msm_camera_csid_vc_cfg *vc_cfg;
-};
-
-struct msm_camera_csid_params {
- uint8_t lane_cnt;
- uint16_t lane_assign;
- uint8_t phy_sel;
- struct msm_camera_csid_lut_params lut_params;
-};
-
-struct msm_camera_csiphy_params {
- uint8_t lane_cnt;
- uint8_t settle_cnt;
- uint16_t lane_mask;
- uint8_t combo_mode;
-};
-
-struct msm_camera_csi2_params {
- struct msm_camera_csid_params csid_params;
- struct msm_camera_csiphy_params csiphy_params;
-};
-
#ifndef CONFIG_MSM_CAMERA_V4L2
#define VFE31_OUTPUT_MODE_PT (0x1 << 0)
#define VFE31_OUTPUT_MODE_S (0x1 << 1)
@@ -332,21 +308,6 @@
uint16_t i2c_queue;
};
-enum msm_camera_i2c_reg_addr_type {
- MSM_CAMERA_I2C_BYTE_ADDR = 1,
- MSM_CAMERA_I2C_WORD_ADDR,
-};
-
-enum msm_camera_i2c_data_type {
- MSM_CAMERA_I2C_BYTE_DATA = 1,
- MSM_CAMERA_I2C_WORD_DATA,
- MSM_CAMERA_I2C_SET_BYTE_MASK,
- MSM_CAMERA_I2C_UNSET_BYTE_MASK,
- MSM_CAMERA_I2C_SET_WORD_MASK,
- MSM_CAMERA_I2C_UNSET_WORD_MASK,
- MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
-};
-
enum msm_camera_i2c_cmd_type {
MSM_CAMERA_I2C_CMD_WRITE,
MSM_CAMERA_I2C_CMD_POLL,
@@ -406,6 +367,7 @@
atomic_t on_heap;
struct timespec ts;
uint32_t error_code;
+ uint32_t trans_code;
};
struct msm_device_queue {
@@ -673,11 +635,6 @@
S_EXIT
};
-struct msm_cam_clk_info {
- const char *clk_name;
- long clk_rate;
-};
-
int msm_camio_enable(struct platform_device *dev);
int msm_camio_vpe_clk_enable(uint32_t);
int msm_camio_vpe_clk_disable(void);
@@ -733,9 +690,11 @@
int msm_cam_core_reset(void);
int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
- int num_vreg, struct regulator **reg_ptr, int config);
+ int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+ int num_vreg_seq, struct regulator **reg_ptr, int config);
int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
- int num_vreg, struct regulator **reg_ptr, int enable);
+ int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+ int num_vreg_seq, struct regulator **reg_ptr, int enable);
int msm_camera_config_gpio_table
(struct msm_camera_sensor_info *sinfo, int gpio_en);
diff --git a/arch/arm/mach-msm/include/mach/cpuidle.h b/arch/arm/mach-msm/include/mach/cpuidle.h
index 8566e7f..af773a0 100644
--- a/arch/arm/mach-msm/include/mach/cpuidle.h
+++ b/arch/arm/mach-msm/include/mach/cpuidle.h
@@ -37,23 +37,4 @@
static inline int msm_cpuidle_init(void) { return -ENOSYS; }
#endif
-#ifdef CONFIG_MSM_SLEEP_STATS
-enum {
- MSM_CPUIDLE_STATE_ENTER,
- MSM_CPUIDLE_STATE_EXIT
-};
-
-int msm_cpuidle_register_notifier(unsigned int cpu,
- struct notifier_block *nb);
-int msm_cpuidle_unregister_notifier(unsigned int cpu,
- struct notifier_block *nb);
-#else
-static inline int msm_cpuidle_register_notifier(unsigned int cpu,
- struct notifier_block *nb)
-{ return -ENODEV; }
-static inline int msm_cpuidle_unregister_notifier(unsigned int cpu,
- struct notifier_block *nb)
-{ return -ENODEV; }
-#endif
-
#endif /* __ARCH_ARM_MACH_MSM_CPUIDLE_H */
diff --git a/arch/arm/mach-msm/include/mach/dal_axi.h b/arch/arm/mach-msm/include/mach/dal_axi.h
index 4e32aa3..84cd37f 100644
--- a/arch/arm/mach-msm/include/mach/dal_axi.h
+++ b/arch/arm/mach-msm/include/mach/dal_axi.h
@@ -17,5 +17,7 @@
int set_grp2d_async(void);
int set_grp3d_async(void);
int set_grp_xbar_async(void);
-
+int axi_allocate(int mode);
+int axi_free(int mode);
+#define AXI_FLOW_VIEWFINDER_HI 243
#endif /* _DAL_AXI_H */
diff --git a/arch/arm/mach-msm/include/mach/irqs-8625.h b/arch/arm/mach-msm/include/mach/irqs-8625.h
index 3ff73eb..413a778 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8625.h
@@ -84,6 +84,9 @@
#define MSM8625_INT_L2CC_EM (GIC_SPI_START + 32 + 22)
#define MSM8625_INT_L2CC_INTR (GIC_SPI_START + 32 + 23)
#define MSM8625_INT_CE_IRQ (GIC_SPI_START + 32 + 24)
+#define MSM8625_INT_CPR_IRQ0 (GIC_SPI_START + 32 + 25)
+#define MSM8625_INT_CPR_IRQ1 (GIC_SPI_START + 32 + 26)
+#define MSM8625_INT_CPR_IRQ2 (GIC_SPI_START + 32 + 27)
#define MSM8625_INT_ADSP_A11_SMSM MSM8625_INT_ADSP_A11
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8625.h b/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
index 3435c2a..43250f5 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8625.h
@@ -57,4 +57,7 @@
#define MSM8625_CFG_CTL_PHYS 0xA9800000
#define MSM8625_CFG_CTL_SIZE SZ_4K
+#define MSM8625_CPR_PHYS 0xC0900000
+#define MSM8625_CPR_SIZE SZ_4K
+
#endif
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 fb61d54..7f04be8 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8974.h
@@ -37,6 +37,18 @@
#define MSM8974_TLMM_PHYS 0xFD510000
#define MSM8974_TLMM_SIZE SZ_16K
+#define MSM8974_MPM2_PSHOLD_PHYS 0xFC4AB000
+#define MSM8974_MPM2_PSHOLD_SIZE SZ_4K
+
+/*
+ * TODO: Revert IMEM_PHYS back to actual
+ * address 0xfe805000
+ * after IMEM issues resolved.
+ *
+ */
+#define MSM8974_IMEM_PHYS 0xFC42B000
+#define MSM8974_IMEM_SIZE SZ_4K
+
#ifdef CONFIG_DEBUG_MSM8974_UART
#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
#define MSM_DEBUG_UART_PHYS 0xF991E000
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
index 4f90ea5..17156b1 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -126,6 +126,9 @@
#define MSM_HDMI_PHYS 0x04A00000
#define MSM_HDMI_SIZE SZ_4K
+/* Needed to keep the unified iomap happy */
+#define MSM_MPM2_PSHOLD_BASE MSM_TLMM_BASE
+
#ifdef CONFIG_DEBUG_MSM8660_UART
#define MSM_DEBUG_UART_BASE 0xFBC40000
#define MSM_DEBUG_UART_PHYS 0x19C40000
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 7085db7..4c849d4 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -93,6 +93,7 @@
#define MSM_SCU_BASE IOMEM(0xFA104000) /* 4K */
#define MSM_CFG_CTL_BASE IOMEM(0xFA105000) /* 4K */
#define MSM_CLK_CTL_SH2_BASE IOMEM(0xFA106000) /* 4K */
+#define MSM_MPM2_PSHOLD_BASE IOMEM(0xFA107000) /* 4k */
#define MSM_MDC_BASE IOMEM(0xFA400000) /* 1M */
#define MSM_AD5_BASE IOMEM(0xFA900000) /* 13M (D00000)
0xFB600000 */
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 49e283d..737db0b 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -17,6 +17,7 @@
* Client drivers should use wrappers available in ocmem.h
**/
#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <asm/io.h>
#include <mach/msm_iomap.h>
#include "ocmem.h"
@@ -36,6 +37,7 @@
};
struct ocmem_zone {
+ bool active;
int owner;
int active_regions;
int max_regions;
@@ -73,6 +75,8 @@
void __iomem *vbase;
unsigned long size;
unsigned long base;
+ struct clk *core_clk;
+ struct clk *iface_clk;
struct ocmem_partition *parts;
int nr_parts;
void __iomem *reg_base;
@@ -133,51 +137,15 @@
struct ocmem_req *req;
};
-static inline struct ocmem_buf *handle_to_buffer(struct ocmem_handle *handle)
-{
- if (handle)
- return &handle->buffer;
- else
- return NULL;
-}
-
-static inline struct ocmem_handle *buffer_to_handle(struct ocmem_buf *buffer)
-{
- if (buffer)
- return container_of(buffer, struct ocmem_handle, buffer);
- else
- return NULL;
-}
-
-static inline struct ocmem_req *handle_to_req(struct ocmem_handle *handle)
-{
- if (handle)
- return handle->req;
- else
- return NULL;
-}
-
-static inline struct ocmem_handle *req_to_handle(struct ocmem_req *req)
-{
- if (req && req->buffer)
- return container_of(req->buffer, struct ocmem_handle, buffer);
- else
- return NULL;
-}
-
-/* Simple wrappers which will have debug features added later */
-static inline int ocmem_read(void *at)
-{
- return readl_relaxed(at);
-}
-
-static inline int ocmem_write(unsigned long val, void *at)
-{
- writel_relaxed(val, at);
- return 0;
-}
+struct ocmem_buf *handle_to_buffer(struct ocmem_handle *);
+struct ocmem_handle *buffer_to_handle(struct ocmem_buf *);
+struct ocmem_req *handle_to_req(struct ocmem_handle *);
+struct ocmem_handle *req_to_handle(struct ocmem_req *);
+int ocmem_read(void *);
+int ocmem_write(unsigned long, void *);
struct ocmem_zone *get_zone(unsigned);
+int zone_active(int);
unsigned long offset_to_phys(unsigned long);
unsigned long phys_to_offset(unsigned long);
unsigned long allocate_head(struct ocmem_zone *, unsigned long);
@@ -206,4 +174,8 @@
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);
+void ocmem_disable_core_clock(void);
+void ocmem_disable_iface_clock(void);
#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/acdb_commands.h b/arch/arm/mach-msm/include/mach/qdsp5/acdb_commands.h
new file mode 100644
index 0000000..188af9f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/acdb_commands.h
@@ -0,0 +1,303 @@
+/* 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 _MACH_QDSP5_V2_ACDB_COMMANDS_H
+#define _MACH_QDSP5_V2_ACDB_COMMANDS_H
+
+#define ACDB_VOICE_NETWORK_ID_DEFAULT 0x00010037
+#define ACDB_INITIALISING 0
+#define ACDB_READY 1
+
+
+/* 4KB */
+#define ACDB_PAGE_SIZE 0x1000
+
+#define ACDB_CDMA_NB 0x0108b153
+#define ACDB_CDMA_WB 0x0108b154
+#define ACDB_GSM_NB 0x0108b155
+#define ACDB_GSM_WB 0x0108b156
+#define ACDB_WCDMA_NB 0x0108b157
+#define ACDB_WCDMA_WB 0x0108b158
+
+
+/* ACDB commands */
+
+
+/* struct acdb_cmd_install_device */
+#define ACDB_INSTALL_DEVICE 0x0108d245
+
+/* struct acdb_cmd_install_device */
+#define ACDB_UNINSTALL_DEVICE 0x0108d246
+
+/* struct acdb_cmd_device */
+#define ACDB_GET_DEVICE 0x0108bb92
+
+/* struct acdb_cmd_device */
+#define ACDB_SET_DEVICE 0x0108bb93
+
+/* struct acdb_cmd_get_device_table */
+#define ACDB_GET_DEVICE_TABLE 0x0108bb97
+
+/* struct acdb_cmd_get_device_capabilities */
+#define ACDB_GET_DEVICE_CAPABILITIES 0x0108f5ca
+
+/* struct acdb_cmd_get_device_info */
+#define ACDB_GET_DEVICE_INFO 0x0108f5cb
+
+/*command to intitialize ACDB based on codec type*/
+#define ACDB_CMD_INITIALIZE_FOR_ADIE 0x00011283
+
+
+/* ACDB Error codes */
+
+#define ACDB_RES_SUCCESS 0
+#define ACDB_RES_FAILURE -1
+#define ACDB_RES_BADPARM -2
+#define ACDB_RES_BADSTATE -3
+
+#define TGTVERS_MSM7x30_BRING_UP 0x00010064
+
+
+
+/* Algorithm Aspect IDs */
+
+#define IID_ENABLE_FLAG 0x0108b6b9
+
+
+#define IID_ENABLE_FLAG_SIZE 1
+#define IID_ECHO_CANCELLER_VERSION_SIZE 2
+#define IID_ECHO_CANCELLER_MODE_SIZE 2
+#define IID_ECHO_CANCELLER_NOISE_SUPPRESSOR_ENABLE_SIZE 1
+#define IID_ECHO_CANCELLER_PARAMETERS_SIZE 32
+#define IID_ECHO_CANCELLER_NEXTGEN_NB_PARAMETERS_SIZE (38 * 2)
+#define IID_ECHO_CANCELLER_NEXTGEN_WB_PARAMETERS_SIZE (38 * 2)
+#define IID_FLUENCE_PARAMETERS_SIZE 486
+#define IID_AFE_VOLUME_CONTROL_SIZE 6
+#define IID_GAIN_SIZE 2
+#define IID_VOICE_FIR_FILTER_SIZE 14
+#define IID_VOICE_IIR_FILTER_SIZE 114
+#define IID_RX_DBM_OFFSET_SIZE 2
+#define IID_AGC_SIZE 36
+#define IID_AVC_SIZE 80
+
+#define IID_AUDIO_IIR_COEFF_SIZE 100
+#define IID_MBADRC_PARAMETERS_SIZE 8
+#define IID_MBADRC_EXT_BUFF_SIZE 392
+#define IID_MBADRC_BAND_CONFIG_SIZE 100
+#define IID_QAFX_PARAMETERS_SIZE 2
+#define IID_QCONCERT_PARAMETERS_SIZE 2
+#define IID_AUDIO_AGC_PARAMETERS_SIZE 42
+#define IID_NS_PARAMETERS_SIZE 14
+
+#define IID_ECHO_CANCELLER_VERSION 0x00010042
+#define IID_ECHO_CANCELLER_MODE 0x00010043
+#define IID_ECHO_CANCELLER_NOISE_SUPPRESSOR_ENABLE 0x00010044
+#define IID_ECHO_CANCELLER_PARAMETERS 0x00010045
+#define IID_ECHO_CANCELLER_NEXTGEN_NB_PARAMETERS 0x00010046
+#define IID_ECHO_CANCELLER_NEXTGEN_WB_PARAMETERS 0x00010047
+#define IID_FLUENCE_PARAMETERS 0x00010048
+#define IID_AFE_VOLUME_CONTROL 0x00010049
+#define IID_GAIN 0x0001004A
+#define IID_VOICE_FIR_FILTER 0x0001004B
+#define IID_VOICE_IIR_FILTER 0x0001004C
+#define IID_AGC 0x0001004E
+#define IID_AVC 0x0001004F
+#define ABID_SIDETONE_GAIN 0x00010050
+#define ABID_TX_VOICE_GAIN 0x00010051
+#define ABID_TX_DTMF_GAIN 0x00010052
+#define ABID_CODEC_TX_GAIN 0x00010053
+#define ABID_HSSD 0x00010054
+#define ABID_TX_AGC 0x00010055
+#define ABID_TX_VOICE_FIR 0x00010056
+#define ABID_TX_VOICE_IIR 0x00010057
+#define ABID_ECHO_CANCELLER 0x00010058
+#define ABID_ECHO_CANCELLER_NB_LVHF 0x00010059
+#define ABID_ECHO_CANCELLER_WB_LVHF 0x0001005A
+#define ABID_FLUENCE 0x0001005B
+#define ABID_CODEC_RX_GAIN 0x0001005C
+#define ABID_RX_DBM_OFFSET 0x0001005D
+#define ABID_RX_AGC 0x0001005E
+#define ABID_AVC 0x0001005F
+#define ABID_RX_VOICE_FIR 0x00010060
+#define ABID_RX_VOICE_IIR 0x00010061
+#define ABID_AFE_VOL_CTRL 0x00010067
+
+
+/* AUDIO IDs */
+#define ABID_AUDIO_AGC_TX 0x00010068
+#define ABID_AUDIO_NS_TX 0x00010069
+#define ABID_VOICE_NS 0x0001006A
+#define ABID_AUDIO_IIR_TX 0x0001006B
+#define ABID_AUDIO_IIR_RX 0x0001006C
+#define ABID_AUDIO_MBADRC_RX 0x0001006E
+#define ABID_AUDIO_QAFX_RX 0x0001006F
+#define ABID_AUDIO_QCONCERT_RX 0x00010070
+#define ABID_AUDIO_STF_RX 0x00010071
+#define ABID_AUDIO_CALIBRATION_GAIN_RX 0x00011162
+#define ABID_AUDIO_CALIBRATION_GAIN_TX 0x00011149
+#define ABID_AUDIO_PBE_RX 0x00011197
+#define ABID_AUDIO_RMC_TX 0x00011226
+#define ABID_AUDIO_FLUENCE_TX 0x00011244
+
+
+#define IID_AUDIO_AGC_PARAMETERS 0x0001007E
+#define IID_NS_PARAMETERS 0x00010072
+#define IID_AUDIO_IIR_COEFF 0x00010073
+#define IID_MBADRC_EXT_BUFF 0x00010075
+#define IID_MBADRC_BAND_CONFIG 0x00010076
+#define IID_MBADRC_PARAMETERS 0x00010077
+#define IID_QAFX_PARAMETERS 0x00010079
+#define IID_QCONCERT_PARAMETERS 0x0001007A
+#define IID_STF_COEFF 0x0001007B
+#define IID_AUDIO_CALIBRATION_GAIN_RX 0x00011163
+#define IID_AUDIO_CALIBRATION_GAIN_TX 0x00011171
+#define IID_PBE_CONFIG_PARAMETERS 0x00011198
+#define IID_AUDIO_PBE_RX_ENABLE_FLAG 0x00011199
+#define IID_AUDIO_RMC_PARAM 0x00011227
+#define IID_AUDIO_FLUENCE_TX 0x00011245
+
+
+#define TOPID_RX_TOPOLOGY_1 0x00010062
+#define TOPID_TX_TOPOLOGY_1 0x00010063
+#define AFERID_INT_SINK 0x00010065
+#define AFERID_INT_SOURCE 0x00010066
+#define AFERID_NO_SINK 0x00000000
+#define AFERID_NULL_SINK 0x0108ea92
+
+
+struct acdb_cmd_install_device {
+ u32 command_id;
+ u32 device_id;
+ u32 topology_id;
+ u32 afe_routing_id;
+ u32 cad_routing_id; /* see "Sample Rate Bit Mask" below */
+ u32 sample_rate_mask;
+
+ /* represents device direction: Tx, Rx (aux pga - loopback) */
+ u8 device_type;
+ u8 channel_config; /* Mono or Stereo */
+ u32 adie_codec_path_id;
+};
+
+
+struct acdb_cmd_get_device_capabilities {
+ u32 command_id;
+ u32 total_bytes; /* Length in bytes allocated for buffer */
+ u32 *phys_buf; /* Physical Address of data */
+};
+
+
+struct acdb_cmd_get_device_info {
+ u32 command_id;
+ u32 device_id;
+ u32 total_bytes; /* Length in bytes allocated for buffer */
+ u32 *phys_buf; /* Physical Address of data */
+};
+
+struct acdb_cmd_device {
+ u32 command_id;
+ u32 device_id;
+ u32 network_id;
+ u32 sample_rate_id; /* Actual sample rate value */
+ u32 interface_id; /* See interface id's above */
+ u32 algorithm_block_id; /* See enumerations above */
+ u32 total_bytes; /* Length in bytes used by buffer */
+ u32 *phys_buf; /* Physical Address of data */
+};
+
+struct acdb_cmd_get_device_table {
+ u32 command_id;
+ u32 device_id;
+ u32 network_id;
+ u32 sample_rate_id; /* Actual sample rate value */
+ u32 total_bytes; /* Length in bytes used by buffer */
+ u32 *phys_buf; /* Physical Address of data */
+};
+
+struct acdb_result {
+ /* This field is populated in response to the */
+ /* ACDB_GET_DEVICE_CAPABILITIES command and indicates the total */
+ /* devices whose capabilities are copied to the physical memory. */
+ u32 total_devices;
+ u32 *buf; /* Physical Address of data */
+ u32 used_bytes; /* The size in bytes of the data */
+ u32 result; /* See ACDB Error codes above */
+};
+
+struct acdb_device_capability {
+ u32 device_id;
+ u32 sample_rate_mask; /* See "Sample Rate Bit Mask" below */
+};
+
+struct acdb_dev_info {
+ u32 cad_routing_id;
+ u32 sample_rate_mask; /* See "Sample Rate Bit Mask" below */
+ u32 adsp_device_id; /* QDSP6 device ID */
+ u32 device_type; /* Tx, Rx (aux pga - loopback) */
+ u32 channel_config; /* Mono or Stereo */
+ s32 min_volume; /* Min volume (mB) */
+ s32 max_volume; /* Max volume (mB) */
+};
+
+/*structure is used to intialize ACDB software on modem
+based on adie type detected*/
+struct acdb_cmd_init_adie {
+ u32 command_id;
+ u32 adie_type;
+};
+
+#define ACDB_CURRENT_ADIE_MODE_UNKNOWN 0
+#define ACDB_CURRENT_ADIE_MODE_TIMPANI 1
+#define ACDB_CURRENT_ADIE_MODE_MARIMBA 2
+
+/* Sample Rate Bit Mask */
+
+/* AUX PGA devices will have a sample rate mask of 0xFFFFFFFF */
+/* 8kHz 0x00000001 */
+/* 11.025kHz 0x00000002 */
+/* 12kHz 0x00000004 */
+/* 16kHz 0x00000008 */
+/* 22.5kHz 0x00000010 */
+/* 24kHz 0x00000020 */
+/* 32kHz 0x00000040 */
+/* 44.1kHz 0x00000080 */
+/* 48kHz 0x00000100 */
+
+
+/* Device type enumeration */
+enum {
+ RX_DEVICE = 1,
+ TX_DEVICE,
+ AUXPGA_DEVICE,
+ DEVICE_TYPE_MAX
+};
+
+#ifdef CONFIG_DEBUG_FS
+/*These are ABID used for RTC*/
+#define ABID_AUDIO_RTC_MBADRC_RX 0x0001118A
+#define ABID_AUDIO_RTC_VOLUME_PAN_RX 0x0001118C
+#define ABID_AUDIO_RTC_SPA 0x0001118E
+#define ABID_AUDIO_RTC_EQUALIZER_PARAMETERS 0x0001119F
+
+/*These are IID used for RTC*/
+#define IID_AUDIO_RTC_MBADRC_PARAMETERS 0x0001118B
+#define IID_AUDIO_RTC_VOLUME_PAN_PARAMETERS 0x0001118D
+#define IID_AUDIO_RTC_SPA_PARAMETERS 0x0001118F
+#define IID_AUDIO_RTC_EQUALIZER_PARAMETERS 0x0001119E
+#define IID_AUDIO_RTC_AGC_PARAMETERS 0x000111A7
+#define IID_AUDIO_RTC_TX_IIR_COEFF 0x000111A8
+
+#endif
+
+
+#endif
+
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/audio_acdb_def.h b/arch/arm/mach-msm/include/mach/qdsp5/audio_acdb_def.h
new file mode 100644
index 0000000..e1fc0cd
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/audio_acdb_def.h
@@ -0,0 +1,51 @@
+/* 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 _MACH_QDSP5_V2_AUDIO_ACDB_DEF_H
+#define _MACH_QDSP5_V2_AUDIO_ACDB_DEF_H
+
+/* Define ACDB device ID */
+#define ACDB_ID_HANDSET_SPKR 1
+#define ACDB_ID_HANDSET_MIC 2
+#define ACDB_ID_HEADSET_MIC 3
+#define ACDB_ID_HEADSET_SPKR_MONO 4
+#define ACDB_ID_HEADSET_SPKR_STEREO 5
+#define ACDB_ID_SPKR_PHONE_MIC 6
+#define ACDB_ID_SPKR_PHONE_MONO 7
+#define ACDB_ID_SPKR_PHONE_STEREO 8
+#define ACDB_ID_BT_SCO_MIC 9
+#define ACDB_ID_BT_SCO_SPKR 0x0A
+#define ACDB_ID_BT_A2DP_SPKR 0x0B
+#define ACDB_ID_BT_A2DP_TX 0x10
+#define ACDB_ID_TTY_HEADSET_MIC 0x0C
+#define ACDB_ID_TTY_HEADSET_SPKR 0x0D
+#define ACDB_ID_HEADSET_MONO_PLUS_SPKR_MONO_RX 0x11
+#define ACDB_ID_HEADSET_STEREO_PLUS_SPKR_STEREO_RX 0x14
+#define ACDB_ID_FM_TX_LOOPBACK 0x17
+#define ACDB_ID_FM_TX 0x18
+#define ACDB_ID_LP_FM_SPKR_PHONE_STEREO_RX 0x19
+#define ACDB_ID_LP_FM_HEADSET_SPKR_STEREO_RX 0x1A
+#define ACDB_ID_I2S_RX 0x20
+#define ACDB_ID_SPKR_PHONE_MIC_BROADSIDE 0x2B
+#define ACDB_ID_HANDSET_MIC_BROADSIDE 0x2C
+#define ACDB_ID_SPKR_PHONE_MIC_ENDFIRE 0x2D
+#define ACDB_ID_HANDSET_MIC_ENDFIRE 0x2E
+#define ACDB_ID_I2S_TX 0x30
+#define ACDB_ID_HDMI 0x40
+#define ACDB_ID_FM_RX 0x4F
+/*Replace the max device ID,if any new device is added Specific to RTC only*/
+#define ACDB_ID_MAX ACDB_ID_FM_RX
+
+/* ID used for virtual devices */
+#define PSEUDO_ACDB_ID 0xFFFF
+
+#endif /* _MACH_QDSP5_V2_AUDIO_ACDB_DEF_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/audio_acdbi.h b/arch/arm/mach-msm/include/mach/qdsp5/audio_acdbi.h
new file mode 100644
index 0000000..5bad4fa
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/audio_acdbi.h
@@ -0,0 +1,132 @@
+/* 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 _MACH_QDSP5_V2_AUDIO_ACDBI_H
+#define _MACH_QDSP5_V2_AUDIO_ACDBI_H
+
+#define DBOR_SIGNATURE 0x524F4244
+
+void acdb_rtc_set_err(u32 err_code);
+
+
+struct header {
+ u32 dbor_signature;
+ u32 abid;
+ u32 iid;
+ u32 data_len;
+};
+
+enum {
+ ACDB_AGC_BLOCK = 197,
+ ACDB_IIR_BLOCK = 245,
+ ACDB_MBADRC_BLOCK = 343
+};
+
+/* Structure to query for acdb parameter */
+struct acdb_get_block {
+ u32 acdb_id;
+ u32 sample_rate_id; /* Actual sample rate value */
+ u32 interface_id; /* Interface id's */
+ u32 algorithm_block_id; /* Algorithm block id */
+ u32 total_bytes; /* Length in bytes used by buffer for
+ configuration */
+ u32 *buf_ptr; /* Address for storing configuration
+ data */
+};
+
+struct acdb_agc_block {
+ u16 enable_status;
+ u16 comp_rlink_static_gain;
+ u16 comp_rlink_aig_flag;
+ u16 exp_rlink_threshold;
+ u16 exp_rlink_slope;
+ u16 comp_rlink_threshold;
+ u16 comp_rlink_slope;
+ u16 comp_rlink_aig_attack_k;
+ u16 comp_rlink_aig_leak_down;
+ u16 comp_rlink_aig_leak_up;
+ u16 comp_rlink_aig_max;
+ u16 comp_rlink_aig_min;
+ u16 comp_rlink_aig_release_k;
+ u16 comp_rlink_aig_sm_leak_rate_fast;
+ u16 comp_rlink_aig_sm_leak_rate_slow;
+ u16 comp_rlink_attack_k_msw;
+ u16 comp_rlink_attack_k_lsw;
+ u16 comp_rlink_delay;
+ u16 comp_rlink_release_k_msw;
+ u16 comp_rlink_release_k_lsw;
+ u16 comp_rlink_rms_trav;
+};
+
+
+struct iir_coeff_type {
+ u16 b0_lo;
+ u16 b0_hi;
+ u16 b1_lo;
+ u16 b1_hi;
+ u16 b2_lo;
+ u16 b2_hi;
+};
+
+struct iir_coeff_stage_a {
+ u16 a1_lo;
+ u16 a1_hi;
+ u16 a2_lo;
+ u16 a2_hi;
+};
+
+struct acdb_iir_block {
+ u16 enable_flag;
+ u16 stage_count;
+ struct iir_coeff_type stages[4];
+ struct iir_coeff_stage_a stages_a[4];
+ u16 shift_factor[4];
+ u16 pan[4];
+};
+
+struct mbadrc_band_config_type {
+ u16 mbadrc_sub_band_enable;
+ u16 mbadrc_sub_mute;
+ u16 mbadrc_comp_rms_tav;
+ u16 mbadrc_comp_threshold;
+ u16 mbadrc_comp_slop;
+ u16 mbadrc_comp_attack_msw;
+ u16 mbadrc_comp_attack_lsw;
+ u16 mbadrc_comp_release_msw;
+ u16 mbadrc_comp_release_lsw;
+ u16 mbadrc_make_up_gain;
+};
+
+struct mbadrc_parameter {
+ u16 mbadrc_enable;
+ u16 mbadrc_num_bands;
+ u16 mbadrc_down_sample_level;
+ u16 mbadrc_delay;
+};
+
+struct acdb_mbadrc_block {
+ u16 ext_buf[196];
+ struct mbadrc_band_config_type band_config[5];
+ struct mbadrc_parameter parameters;
+};
+
+struct acdb_ns_tx_block {
+ unsigned short ec_mode_new;
+ unsigned short dens_gamma_n;
+ unsigned short dens_nfe_block_size;
+ unsigned short dens_limit_ns;
+ unsigned short dens_limit_ns_d;
+ unsigned short wb_gamma_e;
+ unsigned short wb_gamma_n;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpp.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpp.h
new file mode 100644
index 0000000..bbd82a0
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpp.h
@@ -0,0 +1,93 @@
+/*arch/arm/mach-msm/qdsp5audpp.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#ifndef _MACH_QDSP5_AUDPP_H
+#define _MACH_QDSP5_AUDPP_H
+
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+
+typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
+
+/* worst case delay of 1sec for response */
+#define MSM_AUD_DECODER_WAIT_MS 1000
+#define MSM_AUD_MODE_TUNNEL 0x00000100
+#define MSM_AUD_MODE_NONTUNNEL 0x00000200
+#define MSM_AUD_DECODER_MASK 0x0000FFFF
+#define MSM_AUD_OP_MASK 0xFFFF0000
+
+/*Playback mode*/
+#define NON_TUNNEL_MODE_PLAYBACK 1
+#define TUNNEL_MODE_PLAYBACK 0
+
+enum msm_aud_decoder_state {
+ MSM_AUD_DECODER_STATE_NONE = 0,
+ MSM_AUD_DECODER_STATE_FAILURE = 1,
+ MSM_AUD_DECODER_STATE_SUCCESS = 2,
+ MSM_AUD_DECODER_STATE_CLOSE = 3,
+};
+
+int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
+ unsigned *queueid);
+void audpp_adec_free(int decid);
+
+struct audpp_event_callback {
+ audpp_event_func fn;
+ void *private;
+};
+
+int audpp_register_event_callback(struct audpp_event_callback *eh);
+int audpp_unregister_event_callback(struct audpp_event_callback *eh);
+int is_audpp_enable(void);
+
+int audpp_enable(int id, audpp_event_func func, void *private);
+void audpp_disable(int id, void *private);
+
+int audpp_send_queue1(void *cmd, unsigned len);
+int audpp_send_queue2(void *cmd, unsigned len);
+int audpp_send_queue3(void *cmd, unsigned len);
+
+int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan);
+int audpp_pause(unsigned id, int pause);
+int audpp_flush(unsigned id);
+void audpp_avsync(int id, unsigned rate);
+unsigned audpp_avsync_sample_count(int id);
+unsigned audpp_avsync_byte_count(int id);
+int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
+ audpp_cmd_cfg_object_params_mbadrc *mbadrc);
+int audpp_dsp_set_eq(unsigned id, unsigned enable,
+ audpp_cmd_cfg_object_params_eqalizer *eq);
+int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
+ audpp_cmd_cfg_object_params_pcm *iir);
+
+int audpp_dsp_set_rx_srs_trumedia_g
+ (struct audpp_cmd_cfg_object_params_srstm_g *srstm);
+int audpp_dsp_set_rx_srs_trumedia_w
+ (struct audpp_cmd_cfg_object_params_srstm_w *srstm);
+int audpp_dsp_set_rx_srs_trumedia_c
+ (struct audpp_cmd_cfg_object_params_srstm_c *srstm);
+int audpp_dsp_set_rx_srs_trumedia_h
+ (struct audpp_cmd_cfg_object_params_srstm_h *srstm);
+int audpp_dsp_set_rx_srs_trumedia_p
+ (struct audpp_cmd_cfg_object_params_srstm_p *srstm);
+int audpp_dsp_set_rx_srs_trumedia_l
+ (struct audpp_cmd_cfg_object_params_srstm_l *srstm);
+
+int audpp_dsp_set_vol_pan(unsigned id,
+ audpp_cmd_cfg_object_params_volume *vol_pan);
+int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
+ audpp_cmd_cfg_object_params_qconcert *qconcert_plus);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
index 98f20a2..de30c65 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppcmdi.h
@@ -414,6 +414,7 @@
/*
* Command Structure to configure Per decoder Parameters (AMRWB)
*/
+#define ADEC_PARAMS_AC3_INDEX 14
struct audpp_cmd_cfg_adec_params_amrwb {
audpp_cmd_cfg_adec_params_common common;
@@ -424,6 +425,18 @@
sizeof(struct audpp_cmd_cfg_adec_params_amrwb)
/*
+ * Command Structure to configure Per decoder Parameters (AC3)
+ */
+
+struct audpp_cmd_cfg_adec_params_ac3 {
+ audpp_cmd_cfg_adec_params_common common;
+ unsigned short index[ADEC_PARAMS_AC3_INDEX];
+} __packed;
+
+#define AUDPP_CMD_CFG_ADEC_PARAMS_AC3_LEN \
+ sizeof(struct audpp_cmd_cfg_adec_params_ac3)
+
+/*
* Command Structure to configure the HOST PCM interface
*/
@@ -517,6 +530,18 @@
unsigned short arm_to_dsp_buf_len;
} __attribute__((packed)) audpp_cmd_pcm_intf_send_buffer;
+#define AUDPP_CMD_PP_FEAT_QUERY_PARAMS 0x0003
+
+struct rtc_audpp_read_data {
+ unsigned short cmd_id;
+ unsigned short obj_id;
+ unsigned short feature_id;
+ unsigned short extbufsizemsw;
+ unsigned short extbufsizelsw;
+ unsigned short extpart;
+ unsigned short extbufstartmsw;
+ unsigned short extbufstartlsw;
+} __packed ;
/*
* Commands Related to uPAudPPCmd3Queue
@@ -551,6 +576,8 @@
#define AUDPP_CMD_COMMON_CFG_UPDATE 0x8000
#define AUDPP_CMD_COMMON_CFG_DONT_UPDATE 0x0000
+#define AUDPP_CMD_COPP_STREAM 0x0006
+
typedef struct {
unsigned short cmd_id;
unsigned short obj0_cfg;
@@ -567,6 +594,7 @@
* Command Structure to configure post processing params (Volume)
*/
+#define AUDPP_CMD_VOLUME_PAN 0
#define AUDPP_CMD_CFG_OBJECT_PARAMS_VOLUME_LEN \
sizeof(audpp_cmd_cfg_object_params_volume)
@@ -632,6 +660,7 @@
pan pan_filter[4];
} __attribute__((packed)) filter_4;
+#define AUDPP_CMD_IIR_TUNING_FILTER 1
#define AUDPP_CMD_CFG_OBJECT_PARAMS_PCM_LEN \
sizeof(audpp_cmd_cfg_object_params_pcm)
@@ -653,6 +682,7 @@
* Command Structure to configure post processing parameters (equalizer)
*/
+#define AUDPP_CMD_EQUALIZER 2
#define AUDPP_CMD_CFG_OBJECT_PARAMS_EQALIZER_LEN \
sizeof(audpp_cmd_cfg_object_params_eqalizer)
@@ -774,6 +804,7 @@
* Command Structure to configure post processing parameters (ADRC)
*/
+#define AUDPP_CMD_ADRC 3
#define AUDPP_CMD_CFG_OBJECT_PARAMS_ADRC_LEN \
sizeof(audpp_cmd_cfg_object_params_adrc)
@@ -781,6 +812,7 @@
#define AUDPP_CMD_ADRC_FLAG_DIS 0x0000
#define AUDPP_CMD_ADRC_FLAG_ENA -1
+#define AUDPP_CMD_MBADRC 10
#define AUDPP_MAX_MBADRC_BANDS 5
#define AUDPP_MBADRC_EXTERNAL_BUF_SIZE 196
@@ -826,6 +858,7 @@
* Command Structure to configure post processing parameters(Spectrum Analizer)
*/
+#define AUDPP_CMD_SPECTROGRAM 4
#define AUDPP_CMD_CFG_OBJECT_PARAMS_SPECTRAM_LEN \
sizeof(audpp_cmd_cfg_object_params_spectram)
@@ -840,6 +873,7 @@
* Command Structure to configure post processing parameters (QConcert)
*/
+#define AUDPP_CMD_QCONCERT 5
#define AUDPP_CMD_CFG_OBJECT_PARAMS_QCONCERT_LEN \
sizeof(audpp_cmd_cfg_object_params_qconcert)
@@ -886,6 +920,7 @@
* Command Structure to configure post processing parameters (Side Chain)
*/
+#define AUDPP_CMD_SIDECHAIN_TUNING_FILTER 6
#define AUDPP_CMD_CFG_OBJECT_PARAMS_SIDECHAIN_LEN \
sizeof(audpp_cmd_cfg_object_params_sidechain)
@@ -910,6 +945,7 @@
* Command Structure to configure post processing parameters (QAFX)
*/
+#define AUDPP_CMD_QAFX 8
#define AUDPP_CMD_CFG_OBJECT_PARAMS_QAFX_LEN \
sizeof(audpp_cmd_cfg_object_params_qafx)
@@ -1033,6 +1069,8 @@
audpp_cmd_cfg_object_params_common common;
unsigned short v[SRS_PARAMS_MAX_L];
} __packed;
+#define AUDPP_CMD_SAMPLING_FREQUENCY 7
+#define AUDPP_CMD_QRUMBLE 9
#endif /* QDSP5AUDPPCMDI_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h
index 0ba8261..fef4c35 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audppmsg.h
@@ -2,29 +2,29 @@
#define QDSP5AUDPPMSG_H
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
-
- Q D S P 5 A U D I O P O S T P R O C E S S I N G M S G
-
-GENERAL DESCRIPTION
- Messages sent by AUDPPTASK to ARM
-
-REFERENCES
- None
-
-EXTERNALIZED FUNCTIONS
- None
-
-Copyright (c) 1992-2009, Code Aurora Forum. All rights reserved.
-
-This software is licensed under the terms of the GNU General Public
-License version 2, as published by the Free Software Foundation, and
-may be copied, distributed, and modified under those terms.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
+*
+* Q D S P 5 A U D I O P O S T P R O C E S S I N G M S G
+*
+* GENERAL DESCRIPTION
+* Messages sent by AUDPPTASK to ARM
+*
+* REFERENCES
+* None
+*
+* EXTERNALIZED FUNCTIONS
+* None
+*
+* Copyright (c) 1992-2009, 2012 Code Aurora Forum. All rights reserved.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
/*===========================================================================
@@ -318,4 +318,5 @@
#define ADSP_MESSAGE_ID 0xFFFF
+#define AUDPP_MSG_FEAT_QUERY_DM_DONE 0x000b
#endif /* QDSP5AUDPPMSG_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h
index 234c4ac..5c7c5dc 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -25,9 +25,49 @@
#define MSM_ADSP_ENC_MODE_TUNNEL 24
#define MSM_ADSP_ENC_MODE_NON_TUNNEL 25
+/* event callback routine prototype*/
+typedef void (*audpreproc_event_func)(void *private, unsigned id, void *msg);
+
+struct audpreproc_event_callback {
+ audpreproc_event_func fn;
+ void *private;
+};
+
+/*holds audrec information*/
+struct audrec_session_info {
+ int session_id;
+ int sampling_freq;
+};
+
/* Exported common api's from audpreproc layer */
int audpreproc_aenc_alloc(unsigned enc_type, const char **module_name,
unsigned *queue_id);
void audpreproc_aenc_free(int enc_id);
+int audpreproc_enable(int enc_id, audpreproc_event_func func, void *private);
+void audpreproc_disable(int enc_id, void *private);
+
+int audpreproc_unregister_event_callback(struct audpreproc_event_callback *ecb);
+
+int audpreproc_register_event_callback(struct audpreproc_event_callback *ecb);
+
+int audpreproc_update_audrec_info(struct audrec_session_info
+ *audrec_session_info);
+int get_audrec_session_info(struct audrec_session_info *info);
+
+int audpreproc_dsp_set_agc(audpreproc_cmd_cfg_agc_params *agc,
+ unsigned len);
+int audpreproc_dsp_set_ns(audpreproc_cmd_cfg_ns_params *ns,
+ unsigned len);
+int audpreproc_dsp_set_iir(audpreproc_cmd_cfg_iir_tuning_filter_params *iir,
+ unsigned len);
+
+int audpreproc_send_preproccmdqueue(void *cmd, unsigned len);
+typedef void (*audrec_event_func)(void *private, unsigned id, uint16_t *msg);
+int audrectask_enable(unsigned enc_type, audrec_event_func func, void *private);
+void audrectask_disable(unsigned enc_type, void *private);
+
+int audrectask_send_cmdqueue(void *cmd, unsigned len);
+int audrectask_send_bitstreamqueue(void *cmd, unsigned len);
+
#endif /* QDSP5AUDPREPROC_H */
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h
index 8efc916..a38d224 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreproccmdi.h
@@ -2,30 +2,30 @@
#define QDSP5AUDPREPROCCMDI_H
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
-
- A U D I O P R E P R O C E S S I N G I N T E R N A L C O M M A N D S
-
-GENERAL DESCRIPTION
- This file contains defintions of format blocks of commands
- that are accepted by AUDPREPROC Task
-
-REFERENCES
- None
-
-EXTERNALIZED FUNCTIONS
- None
-
-Copyright (c) 1992-2009, Code Aurora Forum. All rights reserved.
-
-This software is licensed under the terms of the GNU General Public
-License version 2, as published by the Free Software Foundation, and
-may be copied, distributed, and modified under those terms.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
+*
+* A U D I O P R E P R O C E S S I N G I N T E R N A L C O M M A N D S
+*
+* GENERAL DESCRIPTION
+* This file contains defintions of format blocks of commands
+* that are accepted by AUDPREPROC Task
+*
+* REFERENCES
+* None
+*
+* EXTERNALIZED FUNCTIONS
+* None
+*
+* Copyright (c) 1992-2009, 2012 Code Aurora Forum. All rights reserved.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
/*===========================================================================
@@ -84,29 +84,29 @@
typedef struct {
unsigned short cmd_id;
unsigned short tx_agc_param_mask;
- unsigned short tx_agc_enable_flag;
- unsigned short static_gain;
- signed short adaptive_gain_flag;
- unsigned short expander_th;
- unsigned short expander_slope;
- unsigned short compressor_th;
- unsigned short compressor_slope;
- unsigned short param_mask;
- unsigned short aig_attackk;
- unsigned short aig_leak_down;
- unsigned short aig_leak_up;
- unsigned short aig_max;
- unsigned short aig_min;
- unsigned short aig_releasek;
- unsigned short aig_leakrate_fast;
- unsigned short aig_leakrate_slow;
- unsigned short attackk_msw;
- unsigned short attackk_lsw;
- unsigned short delay;
- unsigned short releasek_msw;
- unsigned short releasek_lsw;
- unsigned short rms_tav;
-} __attribute__((packed)) audpreproc_cmd_cfg_agc_params;
+ signed short tx_agc_enable_flag;
+ unsigned short comp_rlink_static_gain;
+ signed short comp_rlink_aig_flag;
+ unsigned short expander_rlink_th;
+ unsigned short expander_rlink_slope;
+ unsigned short compressor_rlink_th;
+ unsigned short compressor_rlink_slope;
+ unsigned short tx_adc_agc_param_mask;
+ unsigned short comp_rlink_aig_attackk;
+ unsigned short comp_rlink_aig_leak_down;
+ unsigned short comp_rlink_aig_leak_up;
+ unsigned short comp_rlink_aig_max;
+ unsigned short comp_rlink_aig_min;
+ unsigned short comp_rlink_aig_releasek;
+ unsigned short comp_rlink_aig_leakrate_fast;
+ unsigned short comp_rlink_aig_leakrate_slow;
+ unsigned short comp_rlink_attackk_msw;
+ unsigned short comp_rlink_attackk_lsw;
+ unsigned short comp_rlink_delay;
+ unsigned short comp_rlink_releasek_msw;
+ unsigned short comp_rlink_releasek_lsw;
+ unsigned short comp_rlink_rms_tav;
+} __packed audpreproc_cmd_cfg_agc_params;
/*
@@ -253,4 +253,16 @@
unsigned short channel_selected3;
} __attribute__((packed))audpreproc_cmd_cfg_iir_tuning_filter_params;
+#define AUDPREPROC_CMD_FEAT_QUERY_PARAMS 0x0004
+
+struct rtc_audpreproc_read_data {
+ unsigned short cmd_id;
+ unsigned short stream_id;
+ unsigned short feature_id;
+ unsigned short extbufsizemsw;
+ unsigned short extbufsizelsw;
+ unsigned short extpart;
+ unsigned short extbufstartmsw;
+ unsigned short extbufstartlsw;
+} __packed ;
#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h
index 0696066..d299995 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5/qdsp5audpreprocmsg.h
@@ -2,30 +2,30 @@
#define QDSP5AUDPREPROCMSG_H
/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
-
- A U D I O P R E P R O C E S S I N G M E S S A G E S
-
-GENERAL DESCRIPTION
- This file contains defintions of format blocks of messages
- that are rcvd by AUDPREPROC Task
-
-REFERENCES
- None
-
-EXTERNALIZED FUNCTIONS
- None
-
-Copyright (c) 1992-2009, Code Aurora Forum. All rights reserved.
-
-This software is licensed under the terms of the GNU General Public
-License version 2, as published by the Free Software Foundation, and
-may be copied, distributed, and modified under those terms.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
+*
+* A U D I O P R E P R O C E S S I N G M E S S A G E S
+*
+* GENERAL DESCRIPTION
+* This file contains defintions of format blocks of messages
+* that are rcvd by AUDPREPROC Task
+*
+* REFERENCES
+* None
+*
+* EXTERNALIZED FUNCTIONS
+* None
+*
+* Copyright (c) 1992-2009, 2012 Code Aurora Forum. All rights reserved.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/
/*===========================================================================
@@ -82,4 +82,5 @@
unsigned short err_index;
} __attribute__((packed)) audpreproc_msg_error_msg_id;
+#define AUDPREPROC_MSG_FEAT_QUERY_DM_DONE 0x0003
#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
index 62d7a33..296f222 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr.h
@@ -13,13 +13,18 @@
#ifndef __APR_H_
#define __APR_H_
-#define APR_Q6_NOIMG 0
-#define APR_Q6_LOADING 1
-#define APR_Q6_LOADED 2
+#include <linux/mutex.h>
+
+enum apr_subsys_state {
+ APR_SUBSYS_DOWN,
+ APR_SUBSYS_UP,
+ APR_SUBSYS_LOADED,
+};
struct apr_q6 {
void *pil;
- uint32_t state;
+ atomic_t q6_state;
+ atomic_t modem_state;
struct mutex lock;
};
@@ -138,6 +143,12 @@
struct apr_svc svc[APR_SVC_MAX];
};
+int apr_load_adsp_image(void);
+struct apr_client *apr_get_client(int dest_id, int client_id);
+int apr_wait_for_device_up(int dest_id);
+int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
+ int *svc_idx, int *svc_id);
+void apr_cb_func(void *buf, int len, void *priv);
struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
uint32_t src_port, void *priv);
inline int apr_fill_hdr(void *handle, uint32_t *buf, uint16_t src_port,
@@ -149,4 +160,9 @@
void change_q6_state(int state);
void q6audio_dsp_not_responding(void);
void apr_reset(void *handle);
+enum apr_subsys_state apr_get_modem_state(void);
+void apr_set_modem_state(enum apr_subsys_state state);
+enum apr_subsys_state apr_get_q6_state(void);
+int apr_set_q6_state(enum apr_subsys_state state);
+void apr_set_subsys_state(void);
#endif
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index f7ba507..a9598b1 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -83,6 +83,23 @@
MSM_CPU_9625
};
+enum pmic_model {
+ PMIC_MODEL_PM8058 = 13,
+ PMIC_MODEL_PM8028 = 14,
+ PMIC_MODEL_PM8901 = 15,
+ PMIC_MODEL_PM8027 = 16,
+ PMIC_MODEL_ISL_9519 = 17,
+ PMIC_MODEL_PM8921 = 18,
+ PMIC_MODEL_PM8018 = 19,
+ PMIC_MODEL_PM8015 = 20,
+ PMIC_MODEL_PM8014 = 21,
+ PMIC_MODEL_PM8821 = 22,
+ PMIC_MODEL_PM8038 = 23,
+ PMIC_MODEL_PM8922 = 24,
+ PMIC_MODEL_PM8917 = 25,
+ PMIC_MODEL_UNKNOWN = 0xFFFFFFFF
+};
+
enum msm_cpu socinfo_get_msm_cpu(void);
uint32_t socinfo_get_id(void);
uint32_t socinfo_get_version(void);
@@ -91,12 +108,15 @@
uint32_t socinfo_get_platform_type(void);
uint32_t socinfo_get_platform_subtype(void);
uint32_t socinfo_get_platform_version(void);
+enum pmic_model socinfo_get_pmic_model(void);
+uint32_t socinfo_get_pmic_die_revision(void);
int __init socinfo_init(void) __must_check;
const int read_msm_cpu_type(void);
const int get_core_count(void);
const int cpu_is_krait(void);
const int cpu_is_krait_v1(void);
const int cpu_is_krait_v2(void);
+const int cpu_is_krait_v3(void);
static inline int cpu_is_msm7x01(void)
{
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index edc4b39..000ffe4 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -75,6 +75,8 @@
#define SPS_BAM_OPT_BAMDMA (1UL << 2)
/* BAM IRQ is registered for apps wakeup */
#define SPS_BAM_OPT_IRQ_WAKEUP (1UL << 3)
+/* Ignore external block pipe reset */
+#define SPS_BAM_NO_EXT_P_RST (1UL << 4)
/* BAM device management flags */
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index a2f2c31..2035d3f 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -300,6 +300,8 @@
MSM_CHIP_DEVICE(QGIC_CPU, MSM8974),
MSM_CHIP_DEVICE(APCS_GCC, MSM8974),
MSM_CHIP_DEVICE(TLMM, MSM8974),
+ MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8974),
+ MSM_CHIP_DEVICE(IMEM, MSM8974),
{
.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
.length = MSM_SHARED_RAM_SIZE,
diff --git a/arch/arm/mach-msm/ipc_logging_debug.c b/arch/arm/mach-msm/ipc_logging_debug.c
index 5f7a95e..ee3672e 100644
--- a/arch/arm/mach-msm/ipc_logging_debug.c
+++ b/arch/arm/mach-msm/ipc_logging_debug.c
@@ -186,6 +186,15 @@
{
tsv_timestamp_read(ectxt, dctxt, " ");
tsv_byte_array_read(ectxt, dctxt, "");
+
+ /* add trailing \n if necessary */
+ if (*(dctxt->buff - 1) != '\n') {
+ if (dctxt->size) {
+ ++dctxt->buff;
+ --dctxt->size;
+ }
+ *(dctxt->buff - 1) = '\n';
+ }
}
void check_and_create_debugfs(void)
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 63b00c2..96c4809 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -61,17 +61,16 @@
#define PMIC_VOLTAGE_MIN 350000
#define PMIC_VOLTAGE_MAX 1355000
#define LV_RANGE_STEP 5000
-#define LV_RANGE_MIN 80000
/* use LDO for core voltage below LDO_THRESH */
#define CORE_VOLTAGE_LDO_THRESH 750000
#define LOAD_PER_PHASE 3200000
-#define CORE_VOLTAGE_MIN 500000
+#define CORE_VOLTAGE_MIN 900000
#define KRAIT_LDO_VOLTAGE_MIN 465000
-#define KRAIT_LDO_VOLTAGE_OFFSET 460000
+#define KRAIT_LDO_VOLTAGE_OFFSET 465000
#define KRAIT_LDO_STEP 5000
#define BHS_SETTLING_DELAY_US 1
@@ -291,7 +290,7 @@
uV = PMIC_VOLTAGE_MAX;
}
- setpoint = DIV_ROUND_UP(uV - LV_RANGE_MIN, LV_RANGE_STEP);
+ setpoint = DIV_ROUND_UP(uV, LV_RANGE_STEP);
return msm_spm_apcs_set_vdd(setpoint);
}
@@ -735,6 +734,22 @@
module_exit(krait_power_exit);
+void secondary_cpu_hs_init(void *base_ptr)
+{
+ /* 605mV retention and 705mV operational voltage */
+ writel_relaxed(0x1C30, base_ptr + APC_LDO_VREF_SET);
+ writel_relaxed(0x430000, base_ptr + 0x20);
+ writel_relaxed(0x21, base_ptr + 0x1C);
+
+ /* Turn on the BHS, turn off LDO Bypass and power down LDO */
+ writel_relaxed(0x403F007F, base_ptr + APC_PWR_GATE_CTL);
+ mb();
+ udelay(1);
+
+ /* Finally turn on the bypass so that BHS supplies power */
+ writel_relaxed(0x403F3F7F, base_ptr + APC_PWR_GATE_CTL);
+}
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("KRAIT POWER regulator driver");
MODULE_VERSION("1.0");
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 0758651..7d432f4 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -353,18 +353,21 @@
/* lpm resource handling functions */
/* Common */
-static void msm_lpm_notify_common(struct msm_rpm_notifier_data *rpm_notifier_cb,
+static void msm_lpm_notify_common(struct msm_rpm_notifier_data *cb,
struct msm_lpm_resource *rs)
{
- if ((rpm_notifier_cb->rsc_type == rs->rs_data.type) &&
- (rpm_notifier_cb->rsc_id == rs->rs_data.id) &&
- (rpm_notifier_cb->key == rs->rs_data.key)) {
- BUG_ON(rpm_notifier_cb->size > MAX_RS_SIZE);
+ if ((cb->rsc_type == rs->rs_data.type) &&
+ (cb->rsc_id == rs->rs_data.id) &&
+ (cb->key == rs->rs_data.key)) {
+
+ BUG_ON(cb->size > MAX_RS_SIZE);
if (rs->valid) {
- if (rpm_notifier_cb->value)
- memcpy(&rs->rs_data.value,
- rpm_notifier_cb->value, rpm_notifier_cb->size);
+ if (cb->value) {
+ memcpy(&rs->rs_data.value, cb->value, cb->size);
+ msm_rpm_add_kvp_data_noirq(rs->rs_data.handle,
+ cb->key, cb->value, cb->size);
+ }
else
rs->rs_data.value = rs->rs_data.default_value;
@@ -848,6 +851,7 @@
msm_lpm_l2.rs_data.default_value = MSM_LPM_L2_CACHE_HSFS_OPEN;
msm_lpm_l2.rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
}
+ msm_pm_set_l2_flush_flag(0);
return 0;
fail:
return ret;
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 2073856..43c85bb 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -108,6 +108,8 @@
int soft_reset_direction =
mdm_drv->pdata->soft_reset_inverted ? 1 : 0;
+ mdm_peripheral_disconnect(mdm_drv);
+
/* Wait for the modem to complete its power down actions. */
for (i = 20; i > 0; i--) {
if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
@@ -127,7 +129,6 @@
*/
msleep(4000);
}
- mdm_peripheral_disconnect(mdm_drv);
}
static void mdm_do_first_power_on(struct mdm_modem_drv *mdm_drv)
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 9ba9f7b1..70bb406 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -21,7 +21,7 @@
#include <mach/rpm.h>
#include "msm_bus_core.h"
-#define NMASTERS 45
+#define NMASTERS 55
#define NSLAVES 75
#define NFAB_8960 5
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index e035e35..012bf5a 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -26,6 +26,7 @@
enum {
SLAVE_NODE,
MASTER_NODE,
+ CLK_NODE,
};
enum {
@@ -57,7 +58,7 @@
static int msm_bus_fabric_add_node(struct msm_bus_fabric *fabric,
struct msm_bus_inode_info *info)
{
- int status = -ENOMEM;
+ int status = -ENOMEM, ctx;
MSM_BUS_DBG("msm_bus_fabric_add_node: ID %d Gw: %d\n",
info->node_info->priv_id, info->node_info->gateway);
status = radix_tree_preload(GFP_ATOMIC);
@@ -71,17 +72,15 @@
radix_tree_tag_set(&fabric->fab_tree, info->node_info->priv_id,
SLAVE_NODE);
- if (info->node_info->slaveclk[DUAL_CTX]) {
- info->nodeclk[DUAL_CTX].clk = clk_get_sys("msm_bus",
- info->node_info->slaveclk[DUAL_CTX]);
- if (IS_ERR(info->nodeclk[DUAL_CTX].clk)) {
- MSM_BUS_ERR("Could not get clock for %s\n",
- info->node_info->slaveclk[DUAL_CTX]);
- status = -EINVAL;
- goto out;
+ for (ctx = 0; ctx < NUM_CTX; ctx++) {
+ if (info->node_info->slaveclk[ctx]) {
+ radix_tree_tag_set(&fabric->fab_tree,
+ info->node_info->priv_id, CLK_NODE);
+ break;
}
- info->nodeclk[DUAL_CTX].enable = false;
- info->nodeclk[DUAL_CTX].dirty = false;
+
+ info->nodeclk[ctx].enable = false;
+ info->nodeclk[ctx].dirty = false;
}
out:
@@ -139,7 +138,7 @@
for (i = 0; i < fabric->pdata->len; i++) {
struct msm_bus_inode_info *info;
- int ctx;
+ int ctx, j;
info = kzalloc(sizeof(struct msm_bus_inode_info), GFP_KERNEL);
if (info == NULL) {
@@ -189,11 +188,17 @@
if (fabric->fabdev.hw_algo.node_init == NULL)
continue;
+ for (j = 0; j < NUM_CTX; j++)
+ clk_prepare_enable(fabric->info.nodeclk[j].clk);
+
fabric->fabdev.hw_algo.node_init(fabric->hw_data, info);
if (ret) {
MSM_BUS_ERR("Unable to init node info, ret: %d\n", ret);
kfree(info);
}
+
+ for (j = 0; j < NUM_CTX; j++)
+ clk_disable_unprepare(fabric->info.nodeclk[j].clk);
}
MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
@@ -337,6 +342,7 @@
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
void *sel_cdata;
+ int i;
/* Temporarily stub out arbitration settings for msm8974 */
if (machine_is_msm8974())
@@ -354,8 +360,14 @@
return;
}
+ for (i = 0; i < NUM_CTX; i++)
+ clk_prepare_enable(fabric->info.nodeclk[i].clk);
+
fabdev->hw_algo.update_bw(hop, info, fabric->pdata, sel_cdata,
master_tiers, add_bw);
+ for (i = 0; i < NUM_CTX; i++)
+ clk_disable_unprepare(fabric->info.nodeclk[i].clk);
+
fabric->arb_dirty = true;
}
@@ -422,11 +434,7 @@
unsigned int i, nfound = 0, status = 0;
struct msm_bus_inode_info *info[fabric->pdata->nslaves];
- if (fabric->clk_dirty == false) {
- MSM_BUS_DBG("No clocks have been touched for fabric: %d\n",
- fabric->fabdev.id);
- goto out;
- } else
+ if (fabric->clk_dirty == true)
status = msm_bus_fabric_clk_set(enable, &fabric->info);
if (status)
@@ -434,9 +442,9 @@
fabric->fabdev.id);
nfound = radix_tree_gang_lookup_tag(&fabric->fab_tree, (void **)&info,
- fabric->fabdev.id, fabric->pdata->nslaves, SLAVE_NODE);
+ fabric->fabdev.id, fabric->pdata->nslaves, CLK_NODE);
if (nfound == 0) {
- MSM_BUS_DBG("No slaves found for fabric: %d\n",
+ MSM_BUS_DBG("No clock nodes found for fabric: %d\n",
fabric->fabdev.id);
goto out;
}
@@ -490,7 +498,7 @@
*/
status = msm_bus_fabric_clk_commit(DISABLE, fabric);
if (status)
- MSM_BUS_DBG("Error disabling clocks on fabric: %d\n",
+ MSM_BUS_WARN("Error disabling clocks on fabric: %d\n",
fabric->fabdev.id);
fabric->clk_dirty = false;
return status;
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 2597e27..e6ec722 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -388,7 +388,8 @@
(struct msm_bus_noc_info *)hw_data;
if (!IS_SLAVE(info->node_info->priv_id))
- msm_bus_noc_mas_init(ninfo, info);
+ if (info->node_info->hw_sel != MSM_BUS_RPM)
+ msm_bus_noc_mas_init(ninfo, info);
}
static int msm_bus_noc_allocate_commit_data(struct msm_bus_fabric_registration
diff --git a/arch/arm/mach-msm/msm_cpr-debug.c b/arch/arm/mach-msm/msm_cpr-debug.c
new file mode 100644
index 0000000..723423c
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr-debug.c
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+struct msm_cpr_debug_device {
+ struct mutex debug_mutex;
+ struct dentry *dir;
+ int addr_offset;
+ void __iomem *base;
+};
+
+static inline
+void write_reg(struct msm_cpr_debug_device *cpr, u32 value)
+{
+ writel_relaxed(value, cpr->base + cpr->addr_offset);
+}
+
+static inline u32 read_reg(struct msm_cpr_debug_device *cpr)
+{
+ return readl_relaxed(cpr->base + cpr->addr_offset);
+}
+
+static bool msm_cpr_debug_addr_is_valid(int addr)
+{
+ if (addr < 0 || addr > 0x15C) {
+ pr_err("CPR register address is invalid: %d\n", addr);
+ return false;
+ }
+ return true;
+}
+
+static int msm_cpr_debug_data_set(void *data, u64 val)
+{
+ struct msm_cpr_debug_device *debugdev = data;
+ uint32_t reg = val;
+
+ mutex_lock(&debugdev->debug_mutex);
+
+ if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset))
+ write_reg(debugdev, reg);
+
+ mutex_unlock(&debugdev->debug_mutex);
+ return 0;
+}
+
+static int msm_cpr_debug_data_get(void *data, u64 *val)
+{
+ struct msm_cpr_debug_device *debugdev = data;
+ uint32_t reg;
+
+ mutex_lock(&debugdev->debug_mutex);
+
+ if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset)) {
+ reg = read_reg(debugdev);
+ *val = reg;
+ }
+ mutex_unlock(&debugdev->debug_mutex);
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, msm_cpr_debug_data_get,
+ msm_cpr_debug_data_set, "0x%02llX\n");
+
+static int msm_cpr_debug_addr_set(void *data, u64 val)
+{
+ struct msm_cpr_debug_device *debugdev = data;
+
+ if (msm_cpr_debug_addr_is_valid(val)) {
+ mutex_lock(&debugdev->debug_mutex);
+ debugdev->addr_offset = val;
+ mutex_unlock(&debugdev->debug_mutex);
+ }
+
+ return 0;
+}
+
+static int msm_cpr_debug_addr_get(void *data, u64 *val)
+{
+ struct msm_cpr_debug_device *debugdev = data;
+
+ mutex_lock(&debugdev->debug_mutex);
+
+ if (msm_cpr_debug_addr_is_valid(debugdev->addr_offset))
+ *val = debugdev->addr_offset;
+
+ mutex_unlock(&debugdev->debug_mutex);
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, msm_cpr_debug_addr_get,
+ msm_cpr_debug_addr_set, "0x%03llX\n");
+
+int msm_cpr_debug_init(void *data)
+{
+ char *name = "cpr-debug";
+ struct msm_cpr_debug_device *debugdev;
+ struct dentry *dir;
+ struct dentry *temp;
+ int rc;
+
+ debugdev = kzalloc(sizeof(struct msm_cpr_debug_device), GFP_KERNEL);
+ if (debugdev == NULL) {
+ pr_err("kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ dir = debugfs_create_dir(name, NULL);
+ if (dir == NULL || IS_ERR(dir)) {
+ pr_err("debugfs_create_dir failed: rc=%ld\n", PTR_ERR(dir));
+ rc = PTR_ERR(dir);
+ goto dir_error;
+ }
+
+ temp = debugfs_create_file("address", S_IRUGO | S_IWUSR, dir, debugdev,
+ &debug_addr_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+ rc = PTR_ERR(temp);
+ goto file_error;
+ }
+
+ temp = debugfs_create_file("data", S_IRUGO | S_IWUSR, dir, debugdev,
+ &debug_data_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+ rc = PTR_ERR(temp);
+ goto file_error;
+ }
+ debugdev->base = data;
+ debugdev->addr_offset = -1;
+ debugdev->dir = dir;
+ mutex_init(&debugdev->debug_mutex);
+
+ return 0;
+
+file_error:
+ debugfs_remove_recursive(dir);
+dir_error:
+ kfree(debugdev);
+
+ return rc;
+}
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
new file mode 100644
index 0000000..f4272f3
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -0,0 +1,861 @@
+/*
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/irqs.h>
+
+#include "msm_cpr.h"
+
+#define MODULE_NAME "msm-cpr"
+
+/* Need platform device handle for suspend and resume APIs */
+static struct platform_device *cpr_pdev;
+
+struct msm_cpr {
+ int curr_osc;
+ int cpr_mode;
+ int prev_mode;
+ uint32_t floor;
+ uint32_t ceiling;
+ void __iomem *base;
+ unsigned int irq;
+ struct mutex cpr_mutex;
+ struct regulator *vreg_cx;
+ const struct msm_cpr_config *config;
+ struct notifier_block freq_transition;
+ struct msm_cpr_vp_data *vp;
+};
+
+/* Need to maintain state data for suspend and resume APIs */
+static struct msm_cpr_reg cpr_save_state;
+
+static inline
+void cpr_write_reg(struct msm_cpr *cpr, u32 offset, u32 value)
+{
+ writel_relaxed(value, cpr->base + offset);
+}
+
+static inline u32 cpr_read_reg(struct msm_cpr *cpr, u32 offset)
+{
+ return readl_relaxed(cpr->base + offset);
+}
+
+static
+void cpr_modify_reg(struct msm_cpr *cpr, u32 offset, u32 mask, u32 value)
+{
+ u32 reg_val;
+
+ reg_val = readl_relaxed(cpr->base + offset);
+ reg_val &= ~mask;
+ reg_val |= value;
+ writel_relaxed(reg_val, cpr->base + offset);
+}
+
+#ifdef DEBUG
+static void cpr_regs_dump_all(struct msm_cpr *cpr)
+{
+ pr_debug("RBCPR_GCNT_TARGET(%d): 0x%x\n",
+ cpr->curr_osc, readl_relaxed(cpr->base +
+ RBCPR_GCNT_TARGET(cpr->curr_osc)));
+ pr_debug("RBCPR_TIMER_INTERVAL: 0x%x\n",
+ readl_relaxed(cpr->base + RBCPR_TIMER_INTERVAL));
+ pr_debug("RBIF_TIMER_ADJUST: 0x%x\n",
+ readl_relaxed(cpr->base + RBIF_TIMER_ADJUST));
+ pr_debug("RBIF_LIMIT: 0x%x\n",
+ readl_relaxed(cpr->base + RBIF_LIMIT));
+ pr_debug("RBCPR_STEP_QUOT: 0x%x\n",
+ readl_relaxed(cpr->base + RBCPR_STEP_QUOT));
+ pr_debug("RBIF_SW_VLEVEL: 0x%x\n",
+ readl_relaxed(cpr->base + RBIF_SW_VLEVEL));
+ pr_debug("RBCPR_DEBUG1: 0x%x\n",
+ readl_relaxed(cpr->base + RBCPR_DEBUG1));
+ pr_debug("RBCPR_RESULT_0: 0x%x\n",
+ readl_relaxed(cpr->base + RBCPR_RESULT_0));
+ pr_debug("RBCPR_RESULT_1: 0x%x\n",
+ readl_relaxed(cpr->base + RBCPR_RESULT_1));
+ pr_debug("RBCPR_QUOT_AVG: 0x%x\n",
+ readl_relaxed(cpr->base + RBCPR_QUOT_AVG));
+ pr_debug("RBCPR_CTL: 0x%x\n",
+ readl_relaxed(cpr->base + RBCPR_CTL));
+ pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+ cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
+ pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+ cpr_read_reg(cpr, RBIF_IRQ_STATUS));
+}
+#endif
+
+/* Enable the CPR H/W Block */
+static void cpr_enable(struct msm_cpr *cpr)
+{
+ mutex_lock(&cpr->cpr_mutex);
+ cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+ mutex_unlock(&cpr->cpr_mutex);
+}
+
+/* Disable the CPR H/W Block */
+static void cpr_disable(struct msm_cpr *cpr)
+{
+ mutex_lock(&cpr->cpr_mutex);
+ cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
+ mutex_unlock(&cpr->cpr_mutex);
+}
+
+static int32_t cpr_poll_result(struct msm_cpr *cpr)
+{
+ uint32_t val = 0;
+ int8_t rc = 0;
+
+ rc = readl_poll_timeout(cpr->base + RBCPR_RESULT_0, val, ~val & BUSY_M,
+ 10, 1000);
+ if (rc)
+ pr_info("%s: RBCPR_RESULT_0 read error: %d\n",
+ __func__, rc);
+ return rc;
+}
+
+static int32_t cpr_poll_result_done(struct msm_cpr *cpr)
+{
+ uint32_t val = 0;
+ int8_t rc = 0;
+
+ rc = readl_poll_timeout(cpr->base + RBIF_IRQ_STATUS, val, val & 0x1,
+ 10, 1000);
+ if (rc)
+ pr_info("%s: RBCPR_IRQ_STATUS read error: %d\n",
+ __func__, rc);
+ return rc;
+}
+
+static void
+cpr_2pt_kv_analysis(struct msm_cpr *cpr, struct msm_cpr_mode *chip_data)
+{
+ int32_t tgt_volt_mV = 0, level_uV, rc;
+ uint32_t quot1, quot2;
+
+ /**
+ * 2 Point KV Analysis to calculate Step Quot
+ * STEP_QUOT is number of QUOT units per PMIC step
+ * STEP_QUOT = (quot1 - quot2) / 4
+ *
+ * The step quot is calculated once for every mode and stored for
+ * later use.
+ */
+ if (chip_data->step_quot != ~0)
+ goto out_2pt_kv;
+
+ /**
+ * Using the value from chip_data->tgt_volt_offset
+ * calculate the new PMIC adjusted voltages and set
+ * the PMIC to provide this value.
+ *
+ * Assuming default voltage is the highest value of safe boot up
+ * voltage, offset is always subtracted from it.
+ *
+ */
+ if (chip_data->tgt_volt_offset > 0) {
+ tgt_volt_mV = chip_data->calibrated_mV -
+ (chip_data->tgt_volt_offset * cpr->vp->step_size);
+ }
+ pr_debug("tgt_volt_mV = %d, calibrated_mV = %d", tgt_volt_mV,
+ chip_data->calibrated_mV);
+
+ /* level_uV = tgt_volt_mV * 1000; */
+ level_uV = 1350000;
+ /* Call the PMIC specific routine to set the voltage */
+ rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
+ if (rc) {
+ pr_err("%s: Initial voltage set at %duV failed. %d\n",
+ __func__, level_uV, rc);
+ return;
+ }
+ rc = regulator_enable(cpr->vreg_cx);
+ if (rc) {
+ pr_err("failed to enable %s, rc=%d\n", "vdd_cx", rc);
+ return;
+ }
+
+ /* Store the adjusted value of voltage */
+ chip_data->calibrated_mV = 1300;
+
+ /* Take first CPR measurement at a higher voltage to get QUOT1 */
+
+ /* Enable the Software mode of operation */
+ cpr_modify_reg(cpr, RBCPR_CTL, HW_TO_PMIC_EN_M, SW_MODE);
+
+ /* Enable the cpr measurement */
+ cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+
+ /* IRQ is already disabled */
+ rc = cpr_poll_result_done(cpr);
+ if (rc) {
+ pr_err("%s: Quot1: Exiting due to INT_DONE poll timeout\n",
+ __func__);
+ return;
+ }
+
+ rc = cpr_poll_result(cpr);
+ if (rc) {
+ pr_err("%s: Quot1: Exiting due to BUSY poll timeout\n",
+ __func__);
+ return;
+ }
+
+ quot1 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
+
+ /* Take second CPR measurement at a lower voltage to get QUOT2 */
+ level_uV = 1300000;
+
+ cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
+ /* Call the PMIC specific routine to set the voltage */
+ rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
+ if (rc) {
+ pr_err("%s: Voltage set at %duV failed. %d\n",
+ __func__, level_uV, rc);
+ return;
+ }
+
+ cpr_modify_reg(cpr, RBCPR_CTL, HW_TO_PMIC_EN_M, SW_MODE);
+ cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+
+ /* cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1); */
+ rc = cpr_poll_result_done(cpr);
+ if (rc) {
+ pr_err("%s: Quot2: Exiting due to INT_DONE poll timeout\n",
+ __func__);
+ goto err_poll_result_done;
+ }
+ /* IRQ is already disabled */
+ rc = cpr_poll_result(cpr);
+ if (rc) {
+ pr_err("%s: Quot2: Exiting due to BUSY poll timeout\n",
+ __func__);
+ goto err_poll_result;
+ }
+ quot2 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
+ chip_data->step_quot = (quot1 - quot2) / 4;
+ pr_debug("%s: Calculated Step Quot is %d\n",
+ __func__, chip_data->step_quot);
+ /* Disable the cpr */
+ cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
+
+out_2pt_kv:
+ /* Program the step quot */
+ cpr_write_reg(cpr, RBCPR_STEP_QUOT, (chip_data->step_quot & 0xFF));
+ return;
+err_poll_result:
+err_poll_result_done:
+ regulator_disable(cpr->vreg_cx);
+}
+
+static inline
+void cpr_irq_clr_and_ack(struct msm_cpr *cpr, uint32_t mask)
+{
+ /* Clear the interrupt */
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+ /* Acknowledge the Recommendation */
+ cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
+}
+
+static inline
+void cpr_irq_clr_and_nack(struct msm_cpr *cpr, uint32_t mask)
+{
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+ cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1);
+}
+
+static void cpr_irq_set(struct msm_cpr *cpr, uint32_t irq, bool enable)
+{
+ uint32_t irq_enabled;
+
+ irq_enabled = cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line));
+ if (enable == 1)
+ irq_enabled |= irq;
+ else
+ irq_enabled &= ~irq;
+ cpr_modify_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
+ INT_MASK, irq_enabled);
+}
+
+static void
+cpr_up_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
+{
+ int rc, set_volt_mV;
+ struct msm_cpr_mode *chip_data;
+
+ chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+
+ /**
+ * FIXME: Need to handle a potential race condition between
+ * freq switch handler and CPR interrupt handler here
+ */
+ /* Set New PMIC voltage */
+ set_volt_mV = (new_volt < chip_data->Vmax ? new_volt
+ : chip_data->Vmax);
+ rc = regulator_set_voltage(cpr->vreg_cx, set_volt_mV * 1000,
+ set_volt_mV * 1000);
+ if (rc) {
+ pr_err("%s: Voltage set at %dmV failed. %d\n",
+ __func__, set_volt_mV, rc);
+ cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
+ return;
+ }
+ pr_debug("%s: Voltage set at %dmV\n", __func__, set_volt_mV);
+
+ /**
+ * Save the new calibrated voltage to be re-used
+ * whenever we return to same mode after a mode switch.
+ */
+ chip_data->calibrated_mV = set_volt_mV;
+
+ /* Clear all the interrupts */
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+
+ /* Disable Auto ACK for Down interrupts */
+ cpr_modify_reg(cpr, RBCPR_CTL, SW_AUTO_CONT_NACK_DN_EN_M, 0);
+
+ /* Enable down interrupts to App as it might have got disabled if CPR
+ * hit Vmin earlier. Voltage set is above Vmin now.
+ */
+ cpr_irq_set(cpr, DOWN_INT, 1);
+
+ /* Acknowledge the Recommendation */
+ cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
+}
+
+static void
+cpr_dn_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
+{
+ int rc, set_volt_mV;
+ struct msm_cpr_mode *chip_data;
+
+ chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+
+ /**
+ * FIXME: Need to handle a potential race condition between
+ * freq switch handler and CPR interrupt handler here
+ */
+ /* Set New PMIC volt */
+ set_volt_mV = (new_volt > chip_data->Vmin ? new_volt
+ : chip_data->Vmin);
+ rc = regulator_set_voltage(cpr->vreg_cx, set_volt_mV * 1000,
+ set_volt_mV * 1000);
+ if (rc) {
+ pr_err("%s: Voltage at %dmV failed %d\n",
+ __func__, set_volt_mV, rc);
+ cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
+ return;
+ }
+ pr_debug("%s: Voltage set at %dmV\n", __func__, set_volt_mV);
+
+ /**
+ * Save the new calibrated voltage to be re-used
+ * whenever we return to same mode after a mode switch.
+ */
+ chip_data->calibrated_mV = set_volt_mV;
+
+ /* Clear all the interrupts */
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, 0x3F);
+
+ if (new_volt <= chip_data->Vmin) {
+ /*
+ * Disable down interrupt to App after we hit Vmin
+ * It shall be enabled after we service an up interrupt
+ *
+ * A race condition between freq switch handler and CPR
+ * interrupt handler is possible. So, do not disable
+ * interrupt if a freq switch already caused a mode
+ * change since we need this interrupt in the new mode.
+ */
+ if (cpr->cpr_mode == cpr->prev_mode) {
+ /* Enable Auto ACK for CPR Down Flags
+ * while DOWN_INT to App is disabled */
+ cpr_modify_reg(cpr, RBCPR_CTL,
+ SW_AUTO_CONT_NACK_DN_EN_M,
+ SW_AUTO_CONT_NACK_DN_EN);
+ cpr_irq_set(cpr, DOWN_INT, 0);
+ pr_debug("%s: DOWN_INT disabled\n", __func__);
+ }
+ }
+ /* Acknowledge the Recommendation */
+ cpr_write_reg(cpr, RBIF_CONT_ACK_CMD, 0x1);
+}
+
+static void cpr_set_vdd(struct msm_cpr *cpr, enum cpr_action action)
+{
+ uint32_t curr_volt, new_volt, error_step;
+ struct msm_cpr_mode *chip_data;
+
+ chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+ error_step = cpr_read_reg(cpr, RBCPR_RESULT_0) >> 2;
+ error_step &= 0xF;
+ curr_volt = chip_data->calibrated_mV;
+
+ if (action == UP) {
+ /**
+ * Using up margin in the comparison helps avoid having to
+ * change up threshold values in chip register.
+ */
+ if (error_step < (cpr->config->up_threshold +
+ cpr->config->up_margin)) {
+ /* FIXME: Avoid repeated dn interrupts if we are here */
+ pr_debug("UP_INT error step too small to set\n");
+ cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
+ return;
+ }
+
+ /* Calculte new PMIC voltage */
+ new_volt = curr_volt + (error_step * cpr->vp->step_size);
+ pr_debug("UP_INT: new_volt: %d\n", new_volt);
+ cpr_up_event_handler(cpr, new_volt);
+
+ } else if (action == DOWN) {
+ /**
+ * Using down margin in the comparison helps avoid having to
+ * change down threshold values in chip register.
+ */
+ if (error_step < (cpr->config->dn_threshold +
+ cpr->config->dn_margin)) {
+ /* FIXME: Avoid repeated dn interrupts if we are here */
+ pr_debug("DOWN_INT error_step too small to set\n");
+ cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
+ return;
+ }
+
+ /* Calculte new PMIC voltage */
+ new_volt = curr_volt - (error_step * cpr->vp->step_size);
+ pr_debug("DOWN_INT: new_volt: %d\n", new_volt);
+ cpr_dn_event_handler(cpr, new_volt);
+ }
+}
+
+static irqreturn_t cpr_irq0_handler(int irq, void *dev_id)
+{
+ struct msm_cpr *cpr = dev_id;
+ uint32_t reg_val, ctl_reg;
+
+ reg_val = cpr_read_reg(cpr, RBIF_IRQ_STATUS);
+ ctl_reg = cpr_read_reg(cpr, RBCPR_CTL);
+
+ /* Following sequence of handling is as per each IRQ's priority */
+ if (reg_val & BIT(4)) {
+ pr_debug(" CPR:IRQ %d occured for UP Flag\n", irq);
+ cpr_set_vdd(cpr, UP);
+
+ } else if ((reg_val & BIT(2)) && !(ctl_reg & SW_AUTO_CONT_NACK_DN_EN)) {
+ pr_debug(" CPR:IRQ %d occured for Down Flag\n", irq);
+ cpr_set_vdd(cpr, DOWN);
+
+ } else if (reg_val & BIT(1)) {
+ pr_debug(" CPR:IRQ %d occured for Min Flag\n", irq);
+ cpr_irq_clr_and_nack(cpr, BIT(1) | BIT(0));
+
+ } else if (reg_val & BIT(5)) {
+ pr_debug(" CPR:IRQ %d occured for MAX Flag\n", irq);
+ cpr_irq_clr_and_nack(cpr, BIT(5) | BIT(0));
+
+ } else if (reg_val & BIT(3)) {
+ /* SW_AUTO_CONT_ACK_EN is enabled */
+ pr_debug(" CPR:IRQ %d occured for Mid Flag\n", irq);
+ }
+ return IRQ_HANDLED;
+}
+
+static void cpr_config(struct msm_cpr *cpr)
+{
+ uint32_t delay_count, cnt = 0, rc, tmp_uV;
+ struct msm_cpr_mode *chip_data;
+
+ chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
+
+ /* Program the SW vlevel */
+ cpr_modify_reg(cpr, RBIF_SW_VLEVEL, SW_VLEVEL_M,
+ cpr->config->sw_vlevel);
+
+ /* Set the floor and ceiling values */
+ cpr->floor = cpr->config->floor;
+ cpr->ceiling = cpr->config->ceiling;
+
+ /* Program the Ceiling & Floor values */
+ cpr_modify_reg(cpr, RBIF_LIMIT, (CEILING_M | FLOOR_M),
+ ((cpr->ceiling << 6) | cpr->floor));
+
+ /* Program the Up and Down Threshold values */
+ cpr_modify_reg(cpr, RBCPR_CTL, UP_THRESHOLD_M | DN_THRESHOLD_M,
+ cpr->config->up_threshold << 24 |
+ cpr->config->dn_threshold << 28);
+
+ cpr->curr_osc = chip_data->ring_osc;
+
+ /**
+ * Program the gate count and target values
+ * for all the ring oscilators
+ */
+ while (cnt < NUM_OSC) {
+ cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cnt),
+ (GCNT_M | TARGET_M),
+ (chip_data->ring_osc_data[cnt].gcnt << 12 |
+ chip_data->ring_osc_data[cnt].target_count));
+ pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cnt,
+ readl_relaxed(cpr->base + RBCPR_GCNT_TARGET(cnt)));
+ cnt++;
+ }
+
+ /* Configure the step quot */
+ cpr_2pt_kv_analysis(cpr, chip_data);
+
+ /**
+ * Call the PMIC specific routine to set the voltage
+ * Set with an extra step since it helps as per
+ * characterization data.
+ */
+ chip_data->calibrated_mV += cpr->vp->step_size;
+ tmp_uV = chip_data->calibrated_mV * 1000;
+ rc = regulator_set_voltage(cpr->vreg_cx, tmp_uV, tmp_uV);
+ if (rc)
+ pr_err("%s: Voltage set failed %d\n", __func__, rc);
+
+ /* Program the Timer for default delay between CPR measurements */
+ delay_count = 0xFFFF;
+ cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL, delay_count);
+
+ /* Enable the Timer */
+ cpr_modify_reg(cpr, RBCPR_CTL, TIMER_M, ENABLE_TIMER);
+
+ /* Enable Auto ACK for Mid interrupts */
+ cpr_modify_reg(cpr, RBCPR_CTL, SW_AUTO_CONT_ACK_EN_M,
+ SW_AUTO_CONT_ACK_EN);
+}
+
+static void cpr_mode_config(struct msm_cpr *cpr, enum cpr_mode mode)
+{
+ if (cpr->cpr_mode == mode)
+ return;
+
+ cpr->cpr_mode = mode;
+ pr_debug("%s: Switching to %s mode\n", __func__,
+ (mode == TURBO_MODE ? "TURBO" : "NORMAL"));
+
+ /* Configure the new mode */
+ cpr_config(cpr);
+}
+
+static int
+cpr_freq_transition(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
+ struct msm_cpr *cpr = container_of(nb, struct msm_cpr, freq_transition);
+ struct cpufreq_freqs *freqs = data;
+
+ switch (val) {
+ case CPUFREQ_PRECHANGE:
+ return 0;
+ pr_debug("pre freq change notification to cpr\n");
+
+ disable_irq(cpr->irq);
+ cpr_disable(cpr);
+ cpr->prev_mode = cpr->cpr_mode;
+ break;
+ case CPUFREQ_POSTCHANGE:
+ return 0;
+ pr_debug("post freq change notification to cpr\n");
+
+ if (freqs->new >= cpr->config->nom_freq_limit)
+ cpr_mode_config(cpr, TURBO_MODE);
+ else
+ cpr_mode_config(cpr, NORMAL_MODE);
+ /**
+ * Enable all interrupts. One of them could be in a disabled
+ * state if vdd had hit Vmax / Vmin earlier
+ */
+ cpr_irq_set(cpr, (UP_INT | DOWN_INT), 1);
+
+ enable_irq(cpr->irq);
+
+ cpr_enable(cpr);
+
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int msm_cpr_resume(struct device *dev)
+{
+ struct msm_cpr *cpr = dev_get_drvdata(dev);
+ int osc_num = cpr->config->cpr_mode_data->ring_osc;
+
+ cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL,
+ cpr_save_state.rbif_timer_interval);
+ cpr_write_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
+ cpr_save_state.rbif_int_en);
+ cpr_write_reg(cpr, RBIF_LIMIT,
+ cpr_save_state.rbif_limit);
+ cpr_write_reg(cpr, RBIF_TIMER_ADJUST,
+ cpr_save_state.rbif_timer_adjust);
+ cpr_write_reg(cpr, RBCPR_GCNT_TARGET(osc_num),
+ cpr_save_state.rbcpr_gcnt_target);
+ cpr_write_reg(cpr, RBCPR_STEP_QUOT,
+ cpr_save_state.rbcpr_step_quot);
+ cpr_write_reg(cpr, RBIF_SW_VLEVEL,
+ cpr_save_state.rbif_sw_level);
+
+ cpr_enable(cpr);
+ cpr_write_reg(cpr, RBCPR_CTL,
+ cpr_save_state.rbcpr_ctl);
+ enable_irq(cpr->irq);
+
+ return 0;
+}
+
+static int msm_cpr_suspend(struct device *dev)
+
+{
+ struct msm_cpr *cpr = dev_get_drvdata(dev);
+ int osc_num = cpr->config->cpr_mode_data->ring_osc;
+
+ cpr_save_state.rbif_timer_interval =
+ cpr_read_reg(cpr, RBCPR_TIMER_INTERVAL);
+ cpr_save_state.rbif_int_en =
+ cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line));
+ cpr_save_state.rbif_limit =
+ cpr_read_reg(cpr, RBIF_LIMIT);
+ cpr_save_state.rbif_timer_adjust =
+ cpr_read_reg(cpr, RBIF_TIMER_ADJUST);
+ cpr_save_state.rbcpr_gcnt_target =
+ cpr_read_reg(cpr, RBCPR_GCNT_TARGET(osc_num));
+ cpr_save_state.rbcpr_step_quot =
+ cpr_read_reg(cpr, RBCPR_STEP_QUOT);
+ cpr_save_state.rbif_sw_level =
+ cpr_read_reg(cpr, RBIF_SW_VLEVEL);
+ cpr_save_state.rbcpr_ctl =
+ cpr_read_reg(cpr, RBCPR_CTL);
+
+ disable_irq(cpr->irq);
+ cpr_disable(cpr);
+
+ return 0;
+}
+
+void msm_cpr_pm_resume(void)
+{
+ msm_cpr_resume(&cpr_pdev->dev);
+}
+EXPORT_SYMBOL(msm_cpr_pm_resume);
+
+void msm_cpr_pm_suspend(void)
+{
+ msm_cpr_suspend(&cpr_pdev->dev);
+}
+EXPORT_SYMBOL(msm_cpr_pm_suspend);
+#endif
+
+void msm_cpr_disable(void)
+{
+ struct msm_cpr *cpr = platform_get_drvdata(cpr_pdev);
+ cpr_disable(cpr);
+}
+EXPORT_SYMBOL(msm_cpr_disable);
+
+void msm_cpr_enable(void)
+{
+ struct msm_cpr *cpr = platform_get_drvdata(cpr_pdev);
+ cpr_enable(cpr);
+}
+EXPORT_SYMBOL(msm_cpr_enable);
+
+static int __devinit msm_cpr_probe(struct platform_device *pdev)
+{
+ int res, irqn, irq_enabled;
+ struct msm_cpr *cpr;
+ const struct msm_cpr_config *pdata = pdev->dev.platform_data;
+ void __iomem *base;
+ struct resource *mem;
+
+ if (!pdata) {
+ pr_err("CPR: Platform data is not available\n");
+ return -EIO;
+ }
+
+ cpr = devm_kzalloc(&pdev->dev, sizeof(struct msm_cpr), GFP_KERNEL);
+ if (!cpr)
+ return -ENOMEM;
+
+ /* Initialize platform_data */
+ cpr->config = pdata;
+
+ cpr_pdev = pdev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem || !mem->start) {
+ pr_err("CPR: get resource failed\n");
+ res = -ENXIO;
+ goto out;
+ }
+
+ base = ioremap_nocache(mem->start, resource_size(mem));
+ if (!base) {
+ pr_err("CPR: ioremap failed\n");
+ res = -ENOMEM;
+ goto out;
+ }
+
+ if (cpr->config->irq_line < 0) {
+ pr_err("CPR: Invalid IRQ line specified\n");
+ res = -ENXIO;
+ goto err_ioremap;
+ }
+ irqn = platform_get_irq(pdev, cpr->config->irq_line);
+ if (irqn < 0) {
+ pr_err("CPR: Unable to get irq\n");
+ res = -ENXIO;
+ goto err_ioremap;
+ }
+
+ cpr->irq = irqn;
+
+ cpr->base = base;
+
+ cpr->vp = pdata->vp_data;
+
+ mutex_init(&cpr->cpr_mutex);
+
+ /* Initialize the Voltage domain for CPR */
+ cpr->vreg_cx = regulator_get(&pdev->dev, "vddx_cx");
+ if (IS_ERR(cpr->vreg_cx)) {
+ res = PTR_ERR(cpr->vreg_cx);
+ pr_err("could not get regulator: %d\n", res);
+ goto err_reg_get;
+ }
+
+ /* Assume current mode is TURBO Mode */
+ cpr->cpr_mode = TURBO_MODE;
+ cpr->prev_mode = TURBO_MODE;
+
+ /* Initial configuration of CPR */
+ cpr_config(cpr);
+
+ platform_set_drvdata(pdev, cpr);
+
+ /* Initialze the Debugfs Entry for cpr */
+ res = msm_cpr_debug_init(cpr->base);
+ if (res) {
+ pr_err("CPR: Debugfs Creation Failed\n");
+ goto err_ioremap;
+ }
+
+ /* Register the interrupt handler for IRQ 0 */
+ res = request_threaded_irq(irqn, NULL, cpr_irq0_handler,
+ IRQF_TRIGGER_RISING, "msm-cpr-irq0", cpr);
+ if (res) {
+ pr_err("CPR: request irq failed for IRQ %d\n", irqn);
+ goto err_ioremap;
+ }
+
+ /**
+ * Enable the requested interrupt lines.
+ * Do not enable MID_INT since we shall use
+ * SW_AUTO_CONT_ACK_EN bit.
+ */
+ irq_enabled = INT_MASK & ~MID_INT;
+ cpr_modify_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line),
+ INT_MASK, irq_enabled);
+
+ /* Enable the cpr */
+ cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
+
+
+ cpr->freq_transition.notifier_call = cpr_freq_transition;
+ cpufreq_register_notifier(&cpr->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ return res;
+
+err_reg_get:
+ free_irq(irqn, cpr);
+err_ioremap:
+ iounmap(base);
+out:
+ return res;
+}
+
+static int __devexit msm_cpr_remove(struct platform_device *pdev)
+{
+ struct msm_cpr *cpr = platform_get_drvdata(pdev);
+
+ cpufreq_unregister_notifier(&cpr->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ regulator_disable(cpr->vreg_cx);
+ regulator_put(cpr->vreg_cx);
+ free_irq(cpr->irq, cpr);
+ iounmap(cpr->base);
+ mutex_destroy(&cpr->cpr_mutex);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static const struct dev_pm_ops msm_cpr_dev_pm_ops = {
+ .suspend = msm_cpr_suspend,
+ .resume = msm_cpr_resume,
+};
+
+static struct platform_driver msm_cpr_driver = {
+ .probe = msm_cpr_probe,
+ .remove = __devexit_p(msm_cpr_remove),
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &msm_cpr_dev_pm_ops,
+#endif
+ },
+};
+
+static int __init msm_init_cpr(void)
+{
+ return platform_driver_register(&msm_cpr_driver);
+}
+
+module_init(msm_init_cpr);
+
+static void __exit msm_exit_cpr(void)
+{
+ platform_driver_unregister(&msm_cpr_driver);
+}
+
+module_exit(msm_exit_cpr);
+
+MODULE_DESCRIPTION("MSM CPR Driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/msm_cpr.h b/arch/arm/mach-msm/msm_cpr.h
new file mode 100644
index 0000000..2642b9c
--- /dev/null
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -0,0 +1,226 @@
+/*
+ * 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 __ARCH_ARM_MACH_MSM_CPR_H
+#define __ARCH_ARM_MACH_MSM_CPR_H
+
+/* Register Offsets for RBCPR */
+
+/* RBCPR Gate Count and Target Registers */
+#define RBCPR_GCNT_TARGET(n) (0x60 + 4 * n)
+
+/* RBCPR Timer Control */
+#define RBCPR_TIMER_INTERVAL 0x44
+#define RBIF_TIMER_ADJUST 0x4C
+
+/* RBCPR Config Register */
+#define RBIF_LIMIT 0x48
+#define RBCPR_STEP_QUOT 0X80
+#define RBCPR_CTL 0x90
+#define RBIF_SW_VLEVEL 0x94
+#define RBIF_CONT_ACK_CMD 0x98
+#define RBIF_CONT_NACK_CMD 0x9C
+
+/* RBCPR Result status Register */
+#define RBCPR_RESULT_0 0xA0
+#define RBCPR_RESULT_1 0xA4
+#define RBCPR_QUOT_AVG 0x118
+
+/* RBCPR DEBUG Register */
+#define RBCPR_DEBUG1 0x120
+
+/* RBCPR Interrupt Control Register */
+#define RBIF_IRQ_EN(n) (0x100 + 4 * n)
+#define RBIF_IRQ_CLEAR 0x110
+#define RBIF_IRQ_STATUS 0x114
+
+/* Bit Mask Values */
+#define GCNT_M 0x003FF000
+#define TARGET_M 0x00000FFF
+#define SW_VLEVEL_M 0x0000003F
+#define UP_FLAG_M 0x00000010
+#define DOWN_FLAG_M 0x00000004
+#define CEILING_M 0x00000FC0
+#define FLOOR_M 0x0000003F
+#define LOOP_EN_M 0x00000001
+#define TIMER_M 0x00000008
+#define SW_AUTO_CONT_ACK_EN_M 0x00000020
+#define SW_AUTO_CONT_NACK_DN_EN_M 0x00000040
+#define HW_TO_PMIC_EN_M BIT(4)
+#define BUSY_M BIT(19)
+#define QUOT_SLOW_M 0x00FFF000
+#define UP_THRESHOLD_M 0x0F000000
+#define DN_THRESHOLD_M 0xF0000000
+
+/* Bit Values */
+#define ENABLE_CPR BIT(0)
+#define DISABLE_CPR 0x0
+#define ENABLE_TIMER BIT(3)
+#define DISABLE_TIMER 0x0
+#define SW_MODE 0x0
+#define SW_AUTO_CONT_ACK_EN BIT(5)
+#define SW_AUTO_CONT_NACK_DN_EN BIT(6)
+
+/* Test values for RBCPR RUMI Testing */
+#define GNT_CNT 0xC0
+#define TARGET 0xEFF
+
+#define CEILING_V 0x30
+#define FLOOR_V 0x15
+
+#define SW_LEVEL 0x20
+
+/* Interrupt Mask for All interrupt flags */
+#define INT_MASK (MIN_INT | DOWN_INT | MID_INT | UP_INT | MAX_INT)
+
+/* Number of oscilator in each sensor */
+#define NUM_OSC 8
+
+#define CPR_MODE 2
+
+/**
+ * enum cpr_mode - Modes in which cpr is used
+ */
+enum cpr_mode {
+ NORMAL_MODE = 0,
+ TURBO_MODE,
+ SVS_MODE,
+};
+
+/**
+ * enum cpr_action - Cpr actions to be taken
+ */
+enum cpr_action {
+ DOWN = 0,
+ UP,
+};
+
+/**
+ * enum cpr_interrupt
+ */
+enum cpr_interrupt {
+ DONE_INT = BIT(0),
+ MIN_INT = BIT(1),
+ DOWN_INT = BIT(2),
+ MID_INT = BIT(3),
+ UP_INT = BIT(4),
+ MAX_INT = BIT(5),
+};
+
+/**
+ * struct msm_vp_data - structure for VP configuration
+ * @min_volt_mV: minimum milivolt level for VP
+ * @max_volt_mV: maximum milivolt level for VP
+ * @default_volt_mV: default milivolt for VP
+ * @step_size_mV: step size of voltage
+ */
+struct msm_cpr_vp_data {
+ int min_volt;
+ int max_volt;
+ int default_volt;
+ int step_size;
+};
+
+/**
+ * struct msm_cpr_osc - Data for CPR ring oscillator
+ * @gcnt: gate count value for the oscillator
+ * @target_count: target value for ring oscillator
+ */
+struct msm_cpr_osc {
+ int gcnt;
+ uint32_t target_count;
+};
+
+/**
+ * struct msm_cpr_mode - Data for CPR modes of operation
+ * @msm_cpr_osc: structure for oscillator data
+ * @ring_osc: ring oscillator of the sensor
+ * @tgt_volt_offset: inital voltage offset from default value
+ * @step_quot: step Quot for CPR calcuation
+ */
+struct msm_cpr_mode {
+ struct msm_cpr_osc ring_osc_data[NUM_OSC];
+ int ring_osc;
+ int32_t tgt_volt_offset;
+ uint32_t step_quot;
+ uint32_t Vmax;
+ uint32_t Vmin;
+ uint32_t calibrated_mV;
+};
+
+/**
+ * struct msm_cpr_config - Platform data for CPR configuration
+ * @ref_clk_khz: clock value of CPR in KHz
+ * @delay_us: timer delay in micro second
+ * @irq_line: irq line to be use (0 or 1 or 2)
+ * @msm_cpr_mode: structure for CPR mode data
+ */
+struct msm_cpr_config {
+ unsigned long ref_clk_khz;
+ unsigned long delay_us;
+ int irq_line;
+ struct msm_cpr_mode *cpr_mode_data;
+ int min_down_step;
+ uint32_t tgt_count_div_N; /* Target Cnt(Nom) = Target Cnt(Turbo) / N */
+ uint32_t floor;
+ uint32_t ceiling;
+ uint32_t sw_vlevel;
+ uint32_t up_threshold;
+ uint32_t dn_threshold;
+ uint32_t up_margin;
+ uint32_t dn_margin;
+ uint32_t nom_freq_limit;
+ struct msm_cpr_vp_data *vp_data;
+};
+
+/**
+* struct msm_cpr_config - CPR Registers
+*/
+struct msm_cpr_reg {
+ uint32_t rbif_timer_interval;
+ uint32_t rbif_int_en;
+ uint32_t rbif_limit;
+ uint32_t rbif_timer_adjust;
+ uint32_t rbcpr_gcnt_target;
+ uint32_t rbcpr_step_quot;
+ uint32_t rbif_sw_level;
+ uint32_t rbcpr_ctl;
+};
+
+#if defined(CONFIG_MSM_CPR) || defined(CONFIG_MSM_CPR_MODULE)
+/* msm_cpr_pm_resume: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_resume(void);
+/* msm_cpr_pm_suspend: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_suspend(void);
+/* msm_cpr_enable: Used by Power Manager for GDFS */
+void msm_cpr_enable(void);
+/* msm_cpr_disable: Used by Power Manager for GDFS */
+void msm_cpr_disable(void);
+#else
+/* msm_cpr_pm_resume: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_resume(void) { }
+/* msm_cpr_pm_suspend: Used by Power Manager for Idle Power Collapse */
+void msm_cpr_pm_suspend(void) { }
+/* msm_cpr_enable: Used by Power Manager for GDFS */
+void msm_cpr_enable(void) { }
+/* msm_cpr_disable: Used by Power Manager for GDFS */
+void msm_cpr_disable(void) { }
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+int msm_cpr_debug_init(void *);
+#else
+static inline int msm_cpr_debug_init(void *) { return 0; }
+#endif
+#endif /* __ARCH_ARM_MACH_MSM_CPR_H */
diff --git a/arch/arm/mach-msm/msm_memory_dump.c b/arch/arm/mach-msm/msm_memory_dump.c
index 4f48a0d..17cb2da 100644
--- a/arch/arm/mach-msm/msm_memory_dump.c
+++ b/arch/arm/mach-msm/msm_memory_dump.c
@@ -20,7 +20,7 @@
/*TODO: Needs to be set to correct value */
-#define DUMP_TABLE_OFFSET 0x20
+#define DUMP_TABLE_OFFSET 0x14
#define MSM_DUMP_TABLE_VERSION MK_TABLE(1, 0)
static struct msm_memory_dump mem_dump_data;
@@ -67,7 +67,8 @@
table = mem_dump_data.dump_table_ptr;
table->version = MSM_DUMP_TABLE_VERSION;
mem_dump_data.dump_table_phys = virt_to_phys(table);
- /* TODO: Need to write physical address of table to IMEM */
+ writel_relaxed(mem_dump_data.dump_table_phys,
+ MSM_IMEM_BASE + DUMP_TABLE_OFFSET);
atomic_notifier_chain_register(&panic_notifier_list,
&msm_memory_dump_blk);
printk(KERN_INFO "MSM Memory Dump table set up\n");
diff --git a/arch/arm/mach-msm/msm_vp.c b/arch/arm/mach-msm/msm_vp.c
new file mode 100644
index 0000000..2569474
--- /dev/null
+++ b/arch/arm/mach-msm/msm_vp.c
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#include <mach/msm_iomap.h>
+
+/* Address for Perf Level Registor */
+#define VDD_APC_PLEVEL_BASE (MSM_CLK_CTL_BASE + 0x0298)
+#define VDD_APC_PLEVEL(n) (VDD_APC_PLEVEL_BASE + 4 * n)
+
+/* Address for SYS_P_Level register */
+#define VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
+
+#define MV_TO_UV(mv) ((mv)*1000)
+#define UV_TO_MV(uv) (((uv)+999)/1000)
+
+#define MSM_VP_REGULATOR_DEV_NAME "vp-regulator"
+
+/**
+ * Convert Voltage to PLEVEL register value
+ * Here x is required voltage in minivolt
+ * e.g. if Required voltage is 1200mV then
+ * required value to be programmed into the
+ * Plevel register is 0x32. This equation is
+ * based on H/W logic being used in SVS controller.
+ *
+ * Here we are taking the minimum voltage step
+ * to be 12.5mV as per H/W logic and adding 0x20
+ * is for selecting the reference voltage.
+ * 750mV is minimum voltage of MSMC2 smps.
+ */
+#define VOLT_TO_BIT(x) (((x-750)/(12500/1000)) + 0x20)
+#define VREG_VREF_SEL (1 << 5)
+#define VREG_PD_EN (1 << 6)
+
+/**
+ * struct msm_vp - Structure for VP
+ * @regulator_dev: structure for regulator device
+ * @current_voltage: current voltage value
+ */
+struct msm_vp {
+ struct device *dev;
+ struct regulator_dev *rdev;
+ int current_voltage;
+};
+
+/* Function to change the Vdd Level */
+static int vp_reg_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *sel)
+{
+ struct msm_vp *vp = rdev_get_drvdata(rdev);
+ uint32_t reg_val, perf_level, plevel, cur_plevel, fine_step_volt;
+
+ reg_val = readl_relaxed(VDD_SVS_PLEVEL_ADDR);
+ perf_level = reg_val & 0x07;
+
+ plevel = (min_uV - 750000) / 25000;
+ fine_step_volt = (min_uV - 750000) % 25000;
+
+ /**
+ * Program the new voltage level for the current perf_level
+ * in corresponding PLEVEL register.
+ */
+ cur_plevel = readl_relaxed(VDD_APC_PLEVEL(perf_level));
+ /* clear lower 6 bits */
+ cur_plevel &= ~0x3F;
+ cur_plevel |= (plevel | VREG_VREF_SEL);
+ if (fine_step_volt >= 12500)
+ cur_plevel |= VREG_PD_EN;
+ writel_relaxed(cur_plevel, VDD_APC_PLEVEL(perf_level));
+
+ /* Clear the current perf level */
+ reg_val &= 0xF8;
+ writel_relaxed(reg_val, VDD_SVS_PLEVEL_ADDR);
+
+ /* Initiate the PMIC SSBI request to change the voltage */
+ reg_val |= (BIT(7) | perf_level << 3);
+ writel_relaxed(reg_val, VDD_SVS_PLEVEL_ADDR);
+ mb();
+ udelay(62);
+
+ if ((readl_relaxed(VDD_SVS_PLEVEL_ADDR) & 0x07) != perf_level) {
+ pr_err("Vdd Set Failed\n");
+ return -EIO;
+ }
+
+ vp->current_voltage = (min_uV / 1000);
+ return 0;
+}
+
+static int vp_reg_get_voltage(struct regulator_dev *rdev)
+{
+ struct msm_vp *vp = rdev_get_drvdata(rdev);
+
+ return MV_TO_UV(vp->current_voltage);
+}
+
+static int vp_reg_enable(struct regulator_dev *rdev)
+{
+ return 0;
+}
+
+static int vp_reg_disable(struct regulator_dev *rdev)
+{
+ return 0;
+}
+
+/* Regulator registration specific data */
+/* FIXME: should move to board-xx-regulator.c file */
+static struct regulator_consumer_supply vp_consumer =
+ REGULATOR_SUPPLY("vddx_cx", "msm-cpr");
+
+static struct regulator_init_data vp_reg_data = {
+ .constraints = {
+ .name = "vddx_c2",
+ .min_uV = 750000,
+ .max_uV = 1500000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .boot_on = 1,
+ .input_uV = 0,
+ .always_on = 1,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &vp_consumer,
+};
+
+/* Regulator specific ops */
+static struct regulator_ops vp_reg_ops = {
+ .enable = vp_reg_enable,
+ .disable = vp_reg_disable,
+ .get_voltage = vp_reg_get_voltage,
+ .set_voltage = vp_reg_set_voltage,
+};
+
+/* Regulator Description */
+static struct regulator_desc vp_reg = {
+ .name = "vddcx",
+ .id = -1,
+ .ops = &vp_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+};
+
+static int __devinit msm_vp_reg_probe(struct platform_device *pdev)
+{
+ struct msm_vp *vp;
+ int rc;
+
+ vp = kzalloc(sizeof(struct msm_vp), GFP_KERNEL);
+ if (!vp) {
+ pr_err("Could not allocate memory for VP\n");
+ return -ENOMEM;
+ }
+
+ vp->rdev = regulator_register(&vp_reg, NULL, &vp_reg_data, vp, NULL);
+ if (IS_ERR(vp->rdev)) {
+ rc = PTR_ERR(vp->rdev);
+ pr_err("Failed to register regulator: %d\n", rc);
+ goto error;
+ }
+
+ platform_set_drvdata(pdev, vp);
+
+ return 0;
+error:
+ kfree(vp);
+ return rc;
+}
+
+static int __devexit msm_vp_reg_remove(struct platform_device *pdev)
+{
+ struct msm_vp *vp = platform_get_drvdata(pdev);
+
+ regulator_unregister(vp->rdev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(vp);
+
+ return 0;
+}
+
+static struct platform_driver msm_vp_reg_driver = {
+ .probe = msm_vp_reg_probe,
+ .remove = __devexit_p(msm_vp_reg_remove),
+ .driver = {
+ .name = MSM_VP_REGULATOR_DEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_vp_reg_init(void)
+{
+ return platform_driver_register(&msm_vp_reg_driver);
+}
+postcore_initcall(msm_vp_reg_init);
+
+static void __exit msm_vp_reg_exit(void)
+{
+ platform_driver_unregister(&msm_vp_reg_driver);
+}
+module_exit(msm_vp_reg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM VP regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" MSM_VP_REGULATOR_DEV_NAME);
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index a65cd21..af903f8 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -19,6 +19,8 @@
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/percpu.h>
#include <linux/of.h>
#include <linux/cpu.h>
#include <linux/platform_device.h>
@@ -54,6 +56,8 @@
cpumask_t alive_mask;
struct work_struct init_dogwork_struct;
struct delayed_work dogwork_struct;
+ bool irq_ppi;
+ struct msm_watchdog_data __percpu **wdog_cpu_dd;
struct notifier_block panic_blk;
};
@@ -92,11 +96,9 @@
static void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd)
{
static char alive_mask_buf[MASK_SIZE];
- size_t count = cpulist_scnprintf(alive_mask_buf, MASK_SIZE,
+ cpulist_scnprintf(alive_mask_buf, MASK_SIZE,
&wdog_dd->alive_mask);
- alive_mask_buf[count] = '\n';
- alive_mask_buf[count++] = '\0';
- printk(KERN_INFO "cpu alive mask from last pet\n%s", alive_mask_buf);
+ printk(KERN_INFO "cpu alive mask from last pet %s\n", alive_mask_buf);
}
static int msm_watchdog_suspend(struct device *dev)
@@ -200,10 +202,8 @@
if (wdog_dd->do_ipi_ping)
ping_other_cpus(wdog_dd);
pet_watchdog(wdog_dd);
- if (wdog_dd->do_ipi_ping)
- dump_cpu_alive_mask(wdog_dd);
if (enable)
- schedule_delayed_work(&wdog_dd->dogwork_struct,
+ schedule_delayed_work_on(0, &wdog_dd->dogwork_struct,
delay_time);
}
@@ -222,6 +222,8 @@
/* In case we got suspended mid-exit */
__raw_writel(0, wdog_dd->base + WDT0_EN);
}
+ if (wdog_dd->irq_ppi)
+ free_percpu(wdog_dd->wdog_cpu_dd);
printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n");
kzfree(wdog_dd);
return 0;
@@ -246,6 +248,13 @@
return IRQ_HANDLED;
}
+static irqreturn_t wdog_ppi_bark(int irq, void *dev_id)
+{
+ struct msm_watchdog_data *wdog_dd =
+ *(struct msm_watchdog_data **)(dev_id);
+ return wdog_bark_handler(irq, wdog_dd);
+}
+
static void configure_bark_dump(struct msm_watchdog_data *wdog_dd)
{
int ret;
@@ -291,6 +300,32 @@
init_dogwork_struct);
unsigned long delay_time;
u64 timeout;
+ int ret;
+
+ if (wdog_dd->irq_ppi) {
+ wdog_dd->wdog_cpu_dd = alloc_percpu(struct msm_watchdog_data *);
+ if (!wdog_dd->wdog_cpu_dd) {
+ dev_err(wdog_dd->dev, "fail to allocate cpu data\n");
+ return;
+ }
+ *__this_cpu_ptr(wdog_dd->wdog_cpu_dd) = wdog_dd;
+ ret = request_percpu_irq(wdog_dd->bark_irq, wdog_ppi_bark,
+ "apps_wdog_bark",
+ wdog_dd->wdog_cpu_dd);
+ if (ret) {
+ dev_err(wdog_dd->dev, "failed to request bark irq\n");
+ free_percpu(wdog_dd->wdog_cpu_dd);
+ return;
+ }
+ } else {
+ ret = devm_request_irq(wdog_dd->dev, wdog_dd->bark_irq,
+ wdog_bark_handler, IRQF_TRIGGER_RISING,
+ "apps_wdog_bark", wdog_dd);
+ if (ret) {
+ dev_err(wdog_dd->dev, "failed to request bark irq\n");
+ return;
+ }
+ }
delay_time = msecs_to_jiffies(wdog_dd->pet_time);
wdog_dd->min_slack_ticks = UINT_MAX;
wdog_dd->min_slack_ns = ULLONG_MAX;
@@ -302,12 +337,14 @@
wdog_dd->panic_blk.notifier_call = panic_wdog_handler;
atomic_notifier_chain_register(&panic_notifier_list,
&wdog_dd->panic_blk);
- schedule_delayed_work(&wdog_dd->dogwork_struct, delay_time);
+ schedule_delayed_work_on(0, &wdog_dd->dogwork_struct, delay_time);
__raw_writel(1, wdog_dd->base + WDT0_EN);
__raw_writel(1, wdog_dd->base + WDT0_RST);
wdog_dd->last_pet = sched_clock();
printk(KERN_INFO "MSM Watchdog Initialized\n");
+ if (wdog_dd->irq_ppi)
+ enable_percpu_irq(wdog_dd->bark_irq, 0);
return;
}
@@ -381,6 +418,7 @@
__func__);
return -ENXIO;
}
+ pdata->irq_ppi = irq_is_per_cpu(pdata->bark_irq);
dump_pdata(pdata);
return 0;
}
@@ -400,13 +438,6 @@
goto err;
wdog_dd->dev = &pdev->dev;
platform_set_drvdata(pdev, wdog_dd);
- ret = devm_request_irq(&pdev->dev, wdog_dd->bark_irq, wdog_bark_handler,
- IRQF_TRIGGER_RISING, "apps_wdog_bark", wdog_dd);
- if (ret) {
- dev_err(&pdev->dev, "failed to request bark irq\n");
- ret = -ENXIO;
- goto err;
- }
cpumask_clear(&wdog_dd->alive_mask);
INIT_WORK(&wdog_dd->init_dogwork_struct, init_watchdog_work);
INIT_DELAYED_WORK(&wdog_dd->dogwork_struct, pet_watchdog_work);
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index a9c3f4c..82fe2f8 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -103,7 +103,7 @@
const char *get_name(int id)
{
if (!check_id(id))
- return NULL;
+ return "Unknown";
return client_names[id];
}
@@ -126,6 +126,15 @@
return offset + ocmem_pdata->base;
}
+inline int zone_active(int id)
+{
+ struct ocmem_zone *z = get_zone(id);
+ if (z)
+ return z->active == true ? 1 : 0;
+ else
+ return 0;
+}
+
static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
{
struct ocmem_plat_data *pdata = NULL;
@@ -287,6 +296,44 @@
}
#endif /* CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL */
+/* Core Clock Operations */
+int ocmem_enable_core_clock(void)
+{
+ int ret;
+ ret = clk_prepare_enable(ocmem_pdata->core_clk);
+ if (ret) {
+ pr_err("ocmem: Failed to enable core clock\n");
+ return ret;
+ }
+ pr_debug("ocmem: Enabled core clock\n");
+ return 0;
+}
+
+void ocmem_disable_core_clock(void)
+{
+ clk_disable_unprepare(ocmem_pdata->core_clk);
+ pr_debug("ocmem: Disabled core clock\n");
+}
+
+/* Branch Clock Operations */
+int ocmem_enable_iface_clock(void)
+{
+ int ret;
+ ret = clk_prepare_enable(ocmem_pdata->iface_clk);
+ if (ret) {
+ pr_err("ocmem: Failed to disable branch clock\n");
+ return ret;
+ }
+ pr_debug("ocmem: Enabled iface clock\n");
+ return 0;
+}
+
+void ocmem_disable_iface_clock(void)
+{
+ clk_disable_unprepare(ocmem_pdata->iface_clk);
+ pr_debug("ocmem: Disabled iface clock\n");
+}
+
static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -444,6 +491,7 @@
for (i = 0; i < pdata->nr_parts; i++) {
struct ocmem_partition *part = &pdata->parts[i];
zone = get_zone(part->id);
+ zone->active = false;
dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
i, part->p_start, part->p_size,
@@ -501,6 +549,7 @@
z_ops->allocate = allocate_head;
z_ops->free = free_head;
}
+ zone->active = true;
active_zones++;
if (active_zones == 1)
@@ -515,10 +564,34 @@
return 0;
}
+/* Enable the ocmem graphics mpU as a workaround */
+/* This will be programmed by TZ after TZ support is integrated */
+static int ocmem_init_gfx_mpu(struct platform_device *pdev)
+{
+ int rc;
+ struct device *dev = &pdev->dev;
+ void __iomem *ocmem_region_vbase = NULL;
+
+ ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
+ OCMEM_REGION_CTL_SIZE);
+ if (!ocmem_region_vbase)
+ return -EBUSY;
+
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0)
+ return rc;
+
+ writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
+ ocmem_disable_core_clock();
+ return 0;
+}
+
static int __devinit msm_ocmem_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- void *ocmem_region_vbase = NULL;
+ struct clk *ocmem_core_clk = NULL;
+ struct clk *ocmem_iface_clk = NULL;
if (!pdev->dev.of_node) {
dev_info(dev, "Missing Configuration in Device Tree\n");
@@ -537,6 +610,29 @@
dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
+ ocmem_core_clk = devm_clk_get(dev, "core_clk");
+
+ if (IS_ERR(ocmem_core_clk)) {
+ dev_err(dev, "Unable to get the core clock\n");
+ return PTR_ERR(ocmem_core_clk);
+ }
+
+ /* The core clock is synchronous with graphics */
+ if (clk_set_rate(ocmem_core_clk, 1000) < 0) {
+ dev_err(dev, "Set rate failed on the core clock\n");
+ return -EBUSY;
+ }
+
+ ocmem_iface_clk = devm_clk_get(dev, "iface_clk");
+
+ if (IS_ERR(ocmem_iface_clk)) {
+ dev_err(dev, "Unable to get the memory interface clock\n");
+ return PTR_ERR(ocmem_core_clk);
+ };
+
+ ocmem_pdata->core_clk = ocmem_core_clk;
+ ocmem_pdata->iface_clk = ocmem_iface_clk;
+
platform_set_drvdata(pdev, ocmem_pdata);
if (ocmem_core_init(pdev))
@@ -551,18 +647,14 @@
if (ocmem_sched_init())
return -EBUSY;
- ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
- OCMEM_REGION_CTL_SIZE);
- if (!ocmem_region_vbase)
- return -EBUSY;
-
- /* Enable the ocmem graphics mpU as a workaround in Virtio */
- /* This will be programmed by TZ after TZ support is integrated */
- writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
-
if (ocmem_rdm_init(pdev))
return -EBUSY;
+ if (ocmem_init_gfx_mpu(pdev)) {
+ dev_err(dev, "Unable to initialize Graphics mPU\n");
+ return -EBUSY;
+ }
+
dev_dbg(dev, "initialized successfully\n");
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
index a5aed5e..2604d47 100644
--- a/arch/arm/mach-msm/ocmem_api.c
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -110,6 +110,12 @@
return NULL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return NULL;
+ }
+
if (size < OCMEM_MIN_ALLOC) {
pr_err("ocmem: requested size %lx must be at least %x\n",
size, OCMEM_MIN_ALLOC);
@@ -136,6 +142,12 @@
return NULL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return NULL;
+ }
+
if (size < OCMEM_MIN_ALLOC) {
pr_err("ocmem: requested size %lx must be at least %x\n",
size, OCMEM_MIN_ALLOC);
@@ -162,6 +174,12 @@
return NULL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return NULL;
+ }
+
/* Asynchronous API requires notifier registration */
if (!check_notifier(client_id)) {
pr_err("ocmem: No notifier registered for client %d\n",
@@ -202,6 +220,12 @@
return NULL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return NULL;
+ }
+
if (size < OCMEM_MIN_ALLOC) {
pr_err("ocmem: requested size %lx must be at least %x\n",
size, OCMEM_MIN_ALLOC);
@@ -226,6 +250,12 @@
return -EINVAL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return -EINVAL;
+ }
+
if (!buffer) {
pr_err("ocmem: Invalid buffer\n");
return -EINVAL;
@@ -240,6 +270,13 @@
return -EINVAL;
if (len >= buffer->len)
return -EINVAL;
+
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return -EINVAL;
+ }
+
return __ocmem_shrink(client_id, buffer, len);
}
@@ -282,6 +319,12 @@
return -EINVAL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return -EINVAL;
+ }
+
/* Asynchronous API requires notifier registration */
if (!check_notifier(client_id)) {
pr_err("ocmem: No notifier registered for client %d\n",
@@ -320,6 +363,12 @@
return -EINVAL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client id: %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return -EINVAL;
+ }
+
/* Asynchronous API requires notifier registration */
if (!check_notifier(client_id)) {
pr_err("ocmem: No notifier registered for client %d\n",
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index d8cfefc..d9d67a3 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -50,6 +50,7 @@
#define OCMEM_V1_REGIONS 3
#define OCMEM_V1_MACROS 8
+#define OCMEM_V1_MACRO_SZ (SZ_64K)
#define OC_HW_VERS (0x0)
#define OC_HW_PROFILE (0x4)
@@ -92,7 +93,7 @@
#define REGION_SLEEP_PERI_ON 0x00007777
#define REGION_DEFAULT_OFF REGION_SLEEP_NO_RETENTION
-#define REGION_DEFAULT_ON REGION_FORCE_ALL_ON
+#define REGION_DEFAULT_ON REGION_NORMAL_PASSTHROUGH
#define REGION_DEFAULT_RETENTION REGION_SLEEP_PERI_OFF
enum rpm_macro_state {
@@ -384,6 +385,22 @@
}
#if defined(CONFIG_MSM_OCMEM_POWER_DISABLE)
+static int ocmem_core_set_default_state(void)
+{
+ int rc = 0;
+
+ /* The OCMEM core clock and branch clocks are always turned ON */
+ rc = ocmem_enable_core_clock();
+ if (rc < 0)
+ return rc;
+
+ rc = ocmem_enable_iface_clock();
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
/* Initializes a region to be turned ON in wide mode */
static int ocmem_region_set_default_state(unsigned int r_num)
{
@@ -408,6 +425,11 @@
{
return 0;
}
+
+static int ocmem_core_set_default_state(void)
+{
+ return 0;
+}
#endif
#if defined(CONFIG_MSM_OCMEM_POWER_DEBUG)
@@ -535,6 +557,7 @@
unsigned start_m = num_banks;
unsigned end_m = num_banks;
unsigned long region_offset = 0;
+ int rc = 0;
if (offset < 0)
return -EINVAL;
@@ -555,6 +578,14 @@
(region_end >= num_regions))
return -EINVAL;
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0) {
+ pr_err("ocmem: Power transistion request for client %s (id: %d) failed\n",
+ get_name(id), id);
+ return rc;
+ }
+
mutex_lock(®ion_ctrl_lock);
for (i = region_start; i <= region_end; i++) {
@@ -605,9 +636,11 @@
}
mutex_unlock(®ion_ctrl_lock);
+ ocmem_disable_core_clock();
return 0;
invalid_transition:
mutex_unlock(®ion_ctrl_lock);
+ ocmem_disable_core_clock();
pr_err("ocmem_core: Invalid state transition detected for %d\n", id);
pr_err("ocmem_core: Offset %lx Len %lx curr_state %x new_state %x\n",
offset, len, curr_state, new_state);
@@ -640,10 +673,16 @@
bool interleaved;
unsigned i, j, k;
unsigned rsc_type = 0;
+ int rc = 0;
pdata = platform_get_drvdata(pdev);
ocmem_base = pdata->reg_base;
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0)
+ return rc;
+
hw_ver = ocmem_read(ocmem_base + OC_HW_PROFILE);
if (pdata->nr_regions != OCMEM_V1_REGIONS) {
@@ -671,9 +710,9 @@
pdata->interleaved = true;
pdata->nr_macros = num_macros;
pdata->nr_ports = num_ports;
- macro_size = SZ_64K;
- region_size = macro_size * num_ports;
+ macro_size = OCMEM_V1_MACRO_SZ * 2;
num_banks = num_ports / 2;
+ region_size = macro_size * num_banks;
rsc_type = pdata->rpm_rsc_type;
pr_debug("ocmem_core: ports %d regions %d macros %d interleaved %d\n",
@@ -684,8 +723,7 @@
* num_regions, GFP_KERNEL);
if (!region_ctrl) {
- pr_err("ocmem: Unable to allocate memory\n");
- return -EINVAL;
+ goto err_no_mem;
}
mutex_init(®ion_ctrl_lock);
@@ -702,8 +740,7 @@
sizeof(struct ocmem_hw_macro) *
num_banks, GFP_KERNEL);
if (!region->macro) {
- pr_err("ocmem: Unable to allocate memory\n");
- return -EINVAL;
+ goto err_no_mem;
}
for (j = 0; j < num_banks; j++) {
@@ -722,7 +759,7 @@
if (!req) {
pr_err("Unable to create RPM request\n");
- return -EINVAL;
+ goto region_init_error;
}
pr_debug("rpm request type %x (rsc: %d) with %d elements\n",
@@ -733,16 +770,28 @@
if (ocmem_region_toggle(i)) {
pr_err("Failed to verify region %d\n", i);
- goto hw_not_supported;
+ goto region_init_error;
}
if (ocmem_region_set_default_state(i)) {
pr_err("Failed to initialize region %d\n", i);
- goto hw_not_supported;
+ goto region_init_error;
}
}
+
+ rc = ocmem_core_set_default_state();
+
+ if (rc < 0)
+ return rc;
+
+ ocmem_disable_core_clock();
return 0;
+
+err_no_mem:
+ pr_err("ocmem: Unable to allocate memory\n");
+region_init_error:
hw_not_supported:
pr_err("Unsupported OCMEM h/w configuration %x\n", hw_ver);
+ ocmem_disable_core_clock();
return -EINVAL;
}
diff --git a/arch/arm/mach-msm/ocmem_notifier.c b/arch/arm/mach-msm/ocmem_notifier.c
index 9fbcd73..644c809 100644
--- a/arch/arm/mach-msm/ocmem_notifier.c
+++ b/arch/arm/mach-msm/ocmem_notifier.c
@@ -82,6 +82,12 @@
return NULL;
}
+ if (!zone_active(client_id)) {
+ pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
+ get_name(client_id), client_id);
+ return NULL;
+ }
+
if (!nb) {
pr_err("ocmem: Invalid Notifier Block\n");
return NULL;
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 5649021..ccbef9b 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -142,6 +142,15 @@
int i = 0;
int j = 0;
int status = 0;
+ int rc = 0;
+
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0) {
+ pr_err("RDM transfer failed for client %s (id: %d)\n",
+ get_name(id), id);
+ return rc;
+ }
for (i = 0, j = slot; i < num_chunks; i++, j++) {
@@ -196,6 +205,7 @@
wait_event_interruptible(dm_wq,
atomic_read(&dm_pending) == 0);
+ ocmem_disable_core_clock();
return 0;
}
@@ -218,8 +228,16 @@
return -EINVAL;
}
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0) {
+ pr_err("RDM initialization failed\n");
+ return rc;
+ }
+
init_waitqueue_head(&dm_wq);
/* enable dm interrupts */
ocmem_write(DM_INTR_ENABLE, dm_base + DM_INTR_MASK);
+ 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 70e6860..54510c9 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -116,7 +116,7 @@
int hw_interconnect;
} ocmem_client_table[OCMEM_CLIENT_MAX] = {
{OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
- {OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+ {OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_PORT},
{OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
{OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
{OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
@@ -158,6 +158,50 @@
return ocmem_client_table[id].hw_interconnect == OCMEM_BLOCKED ? 1 : 0;
}
+inline struct ocmem_buf *handle_to_buffer(struct ocmem_handle *handle)
+{
+ if (handle)
+ return &handle->buffer;
+ else
+ return NULL;
+}
+
+inline struct ocmem_handle *buffer_to_handle(struct ocmem_buf *buffer)
+{
+ if (buffer)
+ return container_of(buffer, struct ocmem_handle, buffer);
+ else
+ return NULL;
+}
+
+inline struct ocmem_req *handle_to_req(struct ocmem_handle *handle)
+{
+ if (handle)
+ return handle->req;
+ else
+ return NULL;
+}
+
+inline struct ocmem_handle *req_to_handle(struct ocmem_req *req)
+{
+ if (req && req->buffer)
+ return container_of(req->buffer, struct ocmem_handle, buffer);
+ else
+ return NULL;
+}
+
+/* Simple wrappers which will have debug features added later */
+inline int ocmem_read(void *at)
+{
+ return readl_relaxed(at);
+}
+
+inline int ocmem_write(unsigned long val, void *at)
+{
+ writel_relaxed(val, at);
+ return 0;
+}
+
/* Returns the address that can be used by a device core to access OCMEM */
static unsigned long device_address(int id, unsigned long addr)
{
@@ -511,18 +555,48 @@
return 0;
}
-/* process map is a wrapper where power control will be added later */
static int process_map(struct ocmem_req *req, unsigned long start,
unsigned long end)
{
+ int rc = 0;
+
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0)
+ goto core_clock_fail;
+
+ rc = ocmem_enable_iface_clock();
+
+ if (rc < 0)
+ goto process_map_fail;
+
return do_map(req);
+
+process_map_fail:
+ ocmem_disable_core_clock();
+core_clock_fail:
+ pr_err("ocmem: Failed to map ocmem request\n");
+ return rc;
}
-/* process unmap is a wrapper where power control will be added later */
static int process_unmap(struct ocmem_req *req, unsigned long start,
unsigned long end)
{
- return do_unmap(req);
+ int rc = 0;
+
+ rc = do_unmap(req);
+
+ if (rc < 0)
+ goto process_unmap_fail;
+
+ ocmem_disable_iface_clock();
+ ocmem_disable_core_clock();
+
+ return 0;
+
+process_unmap_fail:
+ pr_err("ocmem: Failed to unmap ocmem request\n");
+ return rc;
}
static int __sched_grow(struct ocmem_req *req, bool can_block)
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 540ffbb..4ff34bf 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -34,6 +34,15 @@
#include "peripheral-loader.h"
+/**
+ * proxy_timeout - Override for proxy vote timeouts
+ * -1: Use driver-specified timeout
+ * 0: Hold proxy votes until shutdown
+ * >0: Specify a custom timeout in ms
+ */
+static int proxy_timeout_ms = -1;
+module_param(proxy_timeout_ms, int, S_IRUGO | S_IWUSR);
+
enum pil_state {
PIL_OFFLINE,
PIL_ONLINE,
@@ -127,7 +136,10 @@
static void pil_proxy_unvote(struct pil_device *pil, unsigned long timeout)
{
- if (pil->desc->ops->proxy_unvote)
+ if (proxy_timeout_ms >= 0)
+ timeout = proxy_timeout_ms;
+
+ if (timeout && pil->desc->ops->proxy_unvote)
schedule_delayed_work(&pil->proxy, msecs_to_jiffies(timeout));
}
@@ -393,7 +405,11 @@
static void pil_shutdown(struct pil_device *pil)
{
pil->desc->ops->shutdown(pil->desc);
- flush_delayed_work(&pil->proxy);
+ if (proxy_timeout_ms == 0 && pil->desc->ops->proxy_unvote)
+ pil->desc->ops->proxy_unvote(pil->desc);
+ else
+ flush_delayed_work(&pil->proxy);
+
pil_set_state(pil, PIL_OFFLINE);
}
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
index 2176b26..5e67d4f 100644
--- a/arch/arm/mach-msm/pil-mba.c
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -38,10 +38,12 @@
#define STATUS_META_DATA_AUTH_SUCCESS 0x3
#define STATUS_AUTH_COMPLETE 0x4
-#define AUTH_TIMEOUT_US 10000000
#define PROXY_TIMEOUT_MS 10000
#define POLL_INTERVAL_US 50
+static int modem_auth_timeout_ms = 10000;
+module_param(modem_auth_timeout_ms, int, S_IRUGO | S_IWUSR);
+
struct mba_data {
void __iomem *reg_base;
void __iomem *metadata_base;
@@ -89,7 +91,7 @@
writel_relaxed(CMD_META_DATA_READY, drv->reg_base + RMB_MBA_COMMAND);
ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
status == STATUS_META_DATA_AUTH_SUCCESS || status < 0,
- POLL_INTERVAL_US, AUTH_TIMEOUT_US);
+ POLL_INTERVAL_US, modem_auth_timeout_ms * 1000);
if (ret) {
dev_err(pil->dev, "MBA authentication timed out\n");
} else if (status < 0) {
@@ -133,7 +135,7 @@
/* Wait for all segments to be authenticated or an error to occur */
ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
status == STATUS_AUTH_COMPLETE || status < 0,
- 50, AUTH_TIMEOUT_US);
+ 50, modem_auth_timeout_ms * 1000);
if (ret) {
dev_err(pil->dev, "MBA authentication timed out\n");
} else if (status < 0) {
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 6a30940..1720729 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -51,10 +51,12 @@
#define RMB_PBL_STATUS 0x04
#define RMB_MBA_STATUS 0x0C
-#define PBL_MBA_WAIT_TIMEOUT_US 100000
#define PROXY_TIMEOUT_MS 10000
#define POLL_INTERVAL_US 50
+static int pbl_mba_boot_timeout_ms = 100;
+module_param(pbl_mba_boot_timeout_ms, int, S_IRUGO | S_IWUSR);
+
static int pil_mss_power_up(struct device *dev)
{
int ret;
@@ -77,6 +79,7 @@
static int pil_mss_enable_clks(struct q6v5_data *drv)
{
int ret;
+ void __iomem *mpll1_config_ctl;
ret = clk_prepare_enable(drv->ahb_clk);
if (ret)
@@ -97,6 +100,12 @@
if (ret)
goto err_rom_clk;
+ /* TODO: Remove when support for 8974v1.0 HW is dropped. */
+ mpll1_config_ctl = ioremap(0xFC981034, 0x4);
+ writel_relaxed(0x0300403D, mpll1_config_ctl);
+ mb();
+ iounmap(mpll1_config_ctl);
+
return 0;
err_rom_clk:
@@ -131,7 +140,7 @@
/* Wait for PBL completion. */
ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
- status != 0, POLL_INTERVAL_US, PBL_MBA_WAIT_TIMEOUT_US);
+ status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
if (ret) {
dev_err(dev, "PBL boot timed out\n");
return ret;
@@ -143,7 +152,7 @@
/* Wait for MBA completion. */
ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
- status != 0, POLL_INTERVAL_US, PBL_MBA_WAIT_TIMEOUT_US);
+ status != 0, POLL_INTERVAL_US, pbl_mba_boot_timeout_ms * 1000);
if (ret) {
dev_err(dev, "MBA boot timed out\n");
return ret;
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 2d1fa80..3040a31 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -228,18 +228,6 @@
static int pil_riva_shutdown(struct pil_desc *pil)
{
- struct riva_data *drv = dev_get_drvdata(pil->dev);
- u32 reg;
-
- /* Put cCPU and cCPU clock into reset */
- reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
- reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
- writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_VAL);
- reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_EN);
- reg |= RIVA_PMU_OVRD_EN_CCPU_RESET | RIVA_PMU_OVRD_EN_CCPU_CLK;
- writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_EN);
- mb();
-
/* Assert reset to Riva */
writel_relaxed(1, RIVA_RESET);
mb();
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 28b7748..f6b44c6 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -14,6 +14,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/regulator/krait-regulator.h>
#include <asm/hardware/gic.h>
#include <asm/cacheflush.h>
@@ -101,17 +102,23 @@
msm_spm_turn_on_cpu_rail(cpu);
- writel_relaxed(0x109, base_ptr+0x04);
- writel_relaxed(0x101, base_ptr+0x04);
- ndelay(300);
-
- writel_relaxed(0x121, base_ptr+0x04);
+ if (cpu_is_krait_v1() || cpu_is_krait_v2()) {
+ writel_relaxed(0x109, base_ptr+0x04);
+ writel_relaxed(0x101, base_ptr+0x04);
+ mb();
+ ndelay(300);
+ writel_relaxed(0x121, base_ptr+0x04);
+ } else
+ writel_relaxed(0x021, base_ptr+0x04);
+ mb();
udelay(2);
writel_relaxed(0x020, base_ptr+0x04);
+ mb();
udelay(2);
writel_relaxed(0x000, base_ptr+0x04);
+ mb();
udelay(100);
writel_relaxed(0x080, base_ptr+0x04);
@@ -126,6 +133,8 @@
if (!base_ptr)
return -ENODEV;
+ secondary_cpu_hs_init(base_ptr);
+
writel_relaxed(0x021, base_ptr+0x04);
mb();
udelay(2);
@@ -175,7 +184,7 @@
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
int ret;
- int flag = 0;
+ unsigned int flag = 0;
unsigned long timeout;
pr_debug("Starting secondary CPU %d\n", cpu);
@@ -189,8 +198,7 @@
__WARN();
if (per_cpu(cold_boot_done, cpu) == false) {
- ret = scm_set_boot_addr((void *)
- virt_to_phys(msm_secondary_startup),
+ ret = scm_set_boot_addr(virt_to_phys(msm_secondary_startup),
flag);
if (ret == 0)
release_secondary(cpu);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index e203667..40929cc 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -27,6 +27,8 @@
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <mach/system.h>
+#include <mach/scm.h>
+#include <mach/socinfo.h>
#include <asm/cacheflush.h>
#include <asm/hardware/gic.h>
#include <asm/pgtable.h>
@@ -67,6 +69,7 @@
module_param_named(
debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
);
+static int msm_pm_retention_tz_call;
/******************************************************************************
@@ -78,6 +81,9 @@
MSM_PM_MODE_ATTR_NR,
};
+#define SCM_L2_RETENTION (0x2)
+#define SCM_CMD_TERMINATE_PC (0x2)
+
static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
@@ -332,7 +338,6 @@
*/
static void msm_pm_config_hw_after_power_up(void)
{
- return;
}
/*
@@ -343,6 +348,22 @@
return;
}
+/*
+ * Configure/Restore hardware registers in preparation for Retention.
+ */
+
+static void msm_pm_config_hw_after_retention(void)
+{
+ int ret;
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+ WARN_ON(ret);
+}
+
+static void msm_pm_config_hw_before_retention(void)
+{
+ return;
+}
+
/******************************************************************************
* Suspend Max Sleep Time
@@ -409,12 +430,17 @@
{
int ret = 0;
- msm_pm_config_hw_before_swfi();
+ msm_pm_config_hw_before_retention();
ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
WARN_ON(ret);
- msm_arch_idle();
- ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
- WARN_ON(ret);
+
+ if (msm_pm_retention_tz_call)
+ scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
+ SCM_L2_RETENTION);
+ else
+ msm_arch_idle();
+
+ msm_pm_config_hw_after_retention();
}
#ifdef CONFIG_CACHE_L2X0
@@ -676,6 +702,10 @@
case MSM_PM_SLEEP_MODE_RETENTION:
if (!allow)
break;
+ if (num_online_cpus() > 1) {
+ allow = false;
+ break;
+ }
/* fall through */
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
@@ -819,7 +849,7 @@
msm_pm_power_collapse_standalone(false);
else if (allow[MSM_PM_SLEEP_MODE_RETENTION])
msm_pm_retention();
- else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT])
+ else
msm_pm_swfi();
}
@@ -923,6 +953,11 @@
pm_sleep_ops = *ops;
}
+void __init msm_pm_set_tz_retention_flag(unsigned int flag)
+{
+ msm_pm_retention_tz_call = flag;
+}
+
static int __init msm_pm_init(void)
{
pgd_t *pc_pgd;
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index 079ed9c..ed15a0c 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -43,7 +43,7 @@
#ifdef CONFIG_MSM_SCM
static int __devinit msm_pm_tz_boot_init(void)
{
- int flag = 0;
+ unsigned int flag = 0;
if (num_possible_cpus() == 1)
flag = SCM_FLAG_WARMBOOT_CPU0;
else if (num_possible_cpus() == 2)
@@ -54,7 +54,7 @@
else
__WARN();
- return scm_set_boot_addr((void *)virt_to_phys(msm_pm_boot_entry), flag);
+ return scm_set_boot_addr(virt_to_phys(msm_pm_boot_entry), flag);
}
static void msm_pm_config_tz_before_pc(unsigned int cpu,
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index c722ff6..4dd6df3 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -86,6 +86,7 @@
void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
+void __init msm_pm_set_tz_retention_flag(unsigned int flag);
#ifdef CONFIG_MSM_PM8X60
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
diff --git a/arch/arm/mach-msm/qdsp5/Makefile b/arch/arm/mach-msm/qdsp5/Makefile
index 2ce0031..f4fe052 100644
--- a/arch/arm/mach-msm/qdsp5/Makefile
+++ b/arch/arm/mach-msm/qdsp5/Makefile
@@ -14,7 +14,7 @@
obj-y += audio_out.o audio_mp3.o audmgr.o audpp.o audrec.o audpreproc.o
obj-y += audio_evrc.o audio_qcelp.o audio_amrnb.o audio_aac.o audio_amrnb_in.o
obj-y += audio_wma.o audio_voicememo.o audio_pcm.o audio_amrwb.o audio_wmapro.o
-obj-y += snd.o snd_adie.o
+obj-y += snd.o snd_cad.o snd_adie.o audio_acdb.o
obj-$(CONFIG_ARCH_MSM7X27A) += audio_fm.o
obj-$(CONFIG_ARCH_MSM7X27A) += audio_mvs.o
-obj-$(CONFIG_ARCH_MSM7X27A) += audio_lpa.o
+obj-$(CONFIG_ARCH_MSM7X27A) += audio_lpa.o audio_ac3.o
diff --git a/arch/arm/mach-msm/qdsp5/adsp_rm.c b/arch/arm/mach-msm/qdsp5/adsp_rm.c
index 81147f7..f67946c 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_rm.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_rm.c
@@ -33,7 +33,8 @@
"PCM Blocks not Sufficient",
"TASK is already occupied",
"Concurrency not supported",
- "MIPS not sufficient"
+ "MIPS not sufficient",
+ "DDP invalid/no licence"
};
static struct client {
wait_queue_head_t wait;
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index 15e0590..01e529f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -41,6 +41,7 @@
#include <mach/iommu_domains.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
#include <mach/qdsp5/qdsp5audplaymsg.h>
#include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index 99e10a4..4a35939 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -109,7 +109,6 @@
int out_frame_cnt;
struct msm_adsp_module *audrec;
- struct msm_adsp_module *audpre;
/* configuration to use on next enable */
@@ -150,6 +149,8 @@
struct ion_client *client;
struct ion_handle *input_buff_handle;
struct ion_handle *output_buff_handle;
+
+ struct audrec_session_info session_info; /*audrec session info*/
};
struct audio_frame {
@@ -273,6 +274,31 @@
return temp;
}
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, void *event_data)
+{
+
+ uint16_t *msg = event_data;
+
+ if (!msg)
+ return;
+
+ switch (id) {
+ case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+ MM_DBG("type %d, status_flag %d\n",\
+ msg[0], msg[1]);
+ break;
+ case AUDPREPROC_MSG_ERROR_MSG_ID:
+ MM_INFO("err_index %d\n", msg[0]);
+ break;
+ case ADSP_MESSAGE_ID:
+ MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+ break;
+ default:
+ MM_ERR("unknown event %d\n", id);
+ }
+}
+
/* must be called with audio->lock held */
static int audaac_in_enable(struct audio_aac_in *audio)
{
@@ -293,16 +319,24 @@
if (rc < 0)
return rc;
- if (msm_adsp_enable(audio->audpre)) {
+ if (audpreproc_enable(audio->enc_id,
+ &audpre_dsp_event, audio)) {
+ MM_ERR("msm_adsp_enable(audpreproc) failed\n");
audmgr_disable(&audio->audmgr);
- MM_ERR("msm_adsp_enable(audpre) failed\n");
return -ENODEV;
}
+
+ /*update aurec session info in audpreproc layer*/
+ audio->session_info.session_id = audio->enc_id;
+ audio->session_info.sampling_freq =
+ convert_samp_index(audio->samp_rate);
+ audpreproc_update_audrec_info(&audio->session_info);
}
+
if (msm_adsp_enable(audio->audrec)) {
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+ audpreproc_disable(audio->enc_id, audio);
audmgr_disable(&audio->audmgr);
- msm_adsp_disable(audio->audpre);
}
MM_ERR("msm_adsp_enable(audrec) failed\n");
return -ENODEV;
@@ -328,36 +362,17 @@
wake_up(&audio->wait);
msm_adsp_disable(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- msm_adsp_disable(audio->audpre);
+ audpreproc_disable(audio->enc_id, audio);
+ /*reset the sampling frequency information at
+ audpreproc layer*/
+ audio->session_info.sampling_freq = 0;
+ audpreproc_update_audrec_info(&audio->session_info);
audmgr_disable(&audio->audmgr);
}
}
return 0;
}
-/* ------------------- dsp --------------------- */
-static void audpre_dsp_event(void *data, unsigned id, size_t len,
- void (*getevent)(void *ptr, size_t len))
-{
- uint16_t msg[2];
- getevent(msg, sizeof(msg));
-
- switch (id) {
- case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
- MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
- break;
- case AUDPREPROC_MSG_ERROR_MSG_ID:
- MM_ERR("err_index %d\n", msg[0]);
- break;
- case ADSP_MESSAGE_ID:
- MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
- break;
- default:
- MM_ERR("unknown event %d\n", id);
- }
-}
-
-
static void audaac_in_get_dsp_frames(struct audio_aac_in *audio)
{
struct audio_frame *frame;
@@ -596,11 +611,7 @@
}
}
-struct msm_adsp_ops audpre_aac_adsp_ops = {
- .event = audpre_dsp_event,
-};
-
-struct msm_adsp_ops audrec_aac_adsp_ops = {
+static struct msm_adsp_ops audrec_aac_adsp_ops = {
.event = audrec_dsp_event,
};
@@ -1241,12 +1252,9 @@
audaac_in_flush(audio);
msm_adsp_put(audio->audrec);
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
- msm_adsp_put(audio->audpre);
audpreproc_aenc_free(audio->enc_id);
audio->audrec = NULL;
- audio->audpre = NULL;
audio->opened = 0;
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
@@ -1342,16 +1350,6 @@
goto done;
}
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
- &audpre_aac_adsp_ops, audio);
- if (rc) {
- msm_adsp_put(audio->audrec);
- audpreproc_aenc_free(audio->enc_id);
- goto done;
- }
- }
-
audio->dsp_cnt = 0;
audio->stopped = 0;
audio->wflush = 0;
@@ -1493,8 +1491,6 @@
ion_client_destroy(client);
client_create_error:
msm_adsp_put(audio->audrec);
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
- msm_adsp_put(audio->audpre);
audpreproc_aenc_free(audio->enc_id);
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5/audio_ac3.c b/arch/arm/mach-msm/qdsp5/audio_ac3.c
new file mode 100644
index 0000000..c0e2059
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_ac3.c
@@ -0,0 +1,1754 @@
+/* arch/arm/mach-msm/audio_ac3.c
+ *
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
+ *
+ * This code also borrows from audio_aac.c, which is
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/earlysuspend.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/memory_alloc.h>
+#include <linux/msm_audio_ac3.h>
+#include <linux/ion.h>
+
+#include <mach/msm_adsp.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
+#include <mach/qdsp5/qdsp5audplaycmdi.h>
+#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5rmtcmdi.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+#define BUFSZ 4096
+#define DMASZ (BUFSZ * 2)
+
+#define AUDDEC_DEC_AC3 23
+
+#define PCM_BUFSZ 6168 /* maximum frame size is 512 * 6 samples */
+#define PCM_BUF_MAX_COUNT 5 /* DSP only accepts 5 buffers at most
+ * but support 2 buffers currently
+ */
+#define ROUTING_MODE_FTRT 1
+#define ROUTING_MODE_RT 2
+
+/* Decoder status received from AUDPPTASK */
+#define AUDPP_DEC_STATUS_SLEEP 0
+#define AUDPP_DEC_STATUS_INIT 1
+#define AUDPP_DEC_STATUS_CFG 2
+#define AUDPP_DEC_STATUS_PLAY 3
+
+#define AUDAC3_METAFIELD_MASK 0xFFFF0000
+#define AUDAC3_EOS_FLG_OFFSET 0x0A /* Offset from beginning of buffer */
+#define AUDAC3_EOS_FLG_MASK 0x01
+#define AUDAC3_EOS_NONE 0x0 /* No EOS detected */
+#define AUDAC3_EOS_SET 0x1 /* EOS set in meta field */
+
+#define AUDAC3_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+struct buffer {
+ void *data;
+ unsigned size;
+ unsigned used; /* Input usage actual DSP produced PCM size */
+ unsigned addr;
+ unsigned short mfield_sz; /* only useful for data has meta field */
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audac3_suspend_ctl {
+ struct early_suspend node;
+ struct audio *audio;
+};
+#endif
+
+struct audac3_event {
+ struct list_head list;
+ int event_type;
+ union msm_audio_event_payload payload;
+};
+
+struct audio {
+ struct buffer out[2];
+
+ spinlock_t dsp_lock;
+
+ uint8_t out_head;
+ uint8_t out_tail;
+ uint8_t out_needed; /* number of buffers the dsp is waiting for */
+
+ atomic_t out_bytes;
+
+ struct mutex lock;
+ struct mutex write_lock;
+ wait_queue_head_t write_wait;
+
+ /* Host PCM section */
+ struct buffer in[PCM_BUF_MAX_COUNT];
+ struct mutex read_lock;
+ wait_queue_head_t read_wait; /* Wait queue for read */
+ char *read_data; /* pointer to reader buffer */
+ int32_t read_phys; /* physical address of reader buffer */
+ uint8_t read_next; /* index to input buffers to be read next */
+ uint8_t fill_next; /* index to buffer that DSP should be filling */
+ uint8_t pcm_buf_count; /* number of pcm buffer allocated */
+ /* ---- End of Host PCM section */
+
+ struct msm_adsp_module *audplay;
+ struct audmgr audmgr;
+ struct msm_audio_ac3_config ac3_config;
+
+ /* data allocated for various buffers */
+ char *data;
+ int32_t phys; /* physical address of write buffer */
+ void *map_v_read;
+ void *map_v_write;
+
+ int mfield; /* meta field embedded in data */
+ int rflush; /* Read flush */
+ int wflush; /* Write flush */
+ uint8_t opened;
+ uint8_t enabled;
+ uint8_t running;
+ uint8_t stopped; /* set when stopped, cleared on flush */
+ uint8_t pcm_feedback;
+ uint8_t buf_refresh;
+ int teos; /* valid only if tunnel mode & no data left for decoder */
+ enum msm_aud_decoder_state dec_state; /* Represents decoder state */
+ int rmt_resource_released;
+
+ const char *module_name;
+ unsigned queue_id;
+ uint16_t dec_id;
+ uint32_t read_ptr_offset;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct audac3_suspend_ctl suspend_ctl;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+#endif
+
+ wait_queue_head_t wait;
+ struct list_head free_event_queue;
+ struct list_head event_queue;
+ wait_queue_head_t event_wait;
+ spinlock_t event_queue_lock;
+ struct mutex get_event_lock;
+ int event_abort;
+
+ int eq_enable;
+ int eq_needs_commit;
+ audpp_cmd_cfg_object_params_eqalizer eq;
+ audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *input_buff_handle;
+ struct ion_handle *output_buff_handle;
+};
+
+static int auddec_dsp_config(struct audio *audio, int enable);
+static void audpp_cmd_cfg_adec_params(struct audio *audio);
+static void audpp_cmd_cfg_routing_mode(struct audio *audio);
+static void audac3_send_data(struct audio *audio, unsigned needed);
+static void audac3_dsp_event(void *private, unsigned id, uint16_t *msg);
+static void audac3_config_hostpcm(struct audio *audio);
+static void audac3_buffer_refresh(struct audio *audio);
+static void audac3_post_event(struct audio *audio, int type,
+ union msm_audio_event_payload payload);
+
+static int rmt_put_resource(struct audio *audio)
+{
+ struct aud_codec_config_cmd cmd;
+ unsigned short client_idx;
+
+ cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+ cmd.client_id = RM_AUD_CLIENT_ID;
+ cmd.task_id = audio->dec_id;
+ cmd.enable = RMT_DISABLE;
+ cmd.dec_type = AUDDEC_DEC_AC3;
+ client_idx = ((cmd.client_id << 8) | cmd.task_id);
+
+ return put_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+static int rmt_get_resource(struct audio *audio)
+{
+ struct aud_codec_config_cmd cmd;
+ unsigned short client_idx;
+
+ cmd.cmd_id = RM_CMD_AUD_CODEC_CFG;
+ cmd.client_id = RM_AUD_CLIENT_ID;
+ cmd.task_id = audio->dec_id;
+ cmd.enable = RMT_ENABLE;
+ cmd.dec_type = AUDDEC_DEC_AC3;
+ client_idx = ((cmd.client_id << 8) | cmd.task_id);
+ return get_adsp_resource(client_idx, &cmd, sizeof(cmd));
+}
+
+/* must be called with audio->lock held */
+static int audac3_enable(struct audio *audio)
+{
+ struct audmgr_config cfg;
+ int rc;
+
+ MM_DBG("\n"); /* Macro prints the file name and function */
+
+ if (audio->enabled)
+ return 0;
+
+ if (audio->rmt_resource_released == 1) {
+ audio->rmt_resource_released = 0;
+ rc = rmt_get_resource(audio);
+ if (rc) {
+ MM_ERR("ADSP resources are not available for AC3"\
+ " session 0x%08x on decoder: %d\n Ignoring"\
+ " error and going ahead with the playback\n",
+ (int)audio, audio->dec_id);
+ }
+ }
+
+ audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+ audio->out_tail = 0;
+ audio->out_needed = 0;
+
+ if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK) {
+ cfg.tx_rate = RPC_AUD_DEF_SAMPLE_RATE_NONE;
+ cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
+ cfg.def_method = RPC_AUD_DEF_METHOD_PLAYBACK;
+ cfg.codec = RPC_AUD_DEF_CODEC_AC3;
+ cfg.snd_method = RPC_SND_METHOD_MIDI;
+
+ rc = audmgr_enable(&audio->audmgr, &cfg);
+ if (rc < 0)
+ return rc;
+ }
+
+ if (msm_adsp_enable(audio->audplay)) {
+ MM_ERR("msm_adsp_enable(audplay) failed\n");
+ if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+ audmgr_disable(&audio->audmgr);
+ return -ENODEV;
+ }
+
+ if (audpp_enable(audio->dec_id, audac3_dsp_event, audio)) {
+ MM_ERR("audpp_enable() failed\n");
+ msm_adsp_disable(audio->audplay);
+ if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+ audmgr_disable(&audio->audmgr);
+ return -ENODEV;
+ }
+ audio->enabled = 1;
+ return 0;
+}
+
+/* must be called with audio->lock held */
+static int audac3_disable(struct audio *audio)
+{
+ int rc = 0;
+ if (audio->enabled) {
+ audio->enabled = 0;
+ audio->dec_state = MSM_AUD_DECODER_STATE_NONE;
+ auddec_dsp_config(audio, 0);
+ rc = wait_event_interruptible_timeout(audio->wait,
+ audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+ msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+ if (rc == 0)
+ rc = -ETIMEDOUT;
+ else if (audio->dec_state != MSM_AUD_DECODER_STATE_CLOSE)
+ rc = -EFAULT;
+ else
+ rc = 0;
+ audio->stopped = 1;
+ wake_up(&audio->write_wait);
+ wake_up(&audio->read_wait);
+ msm_adsp_disable(audio->audplay);
+ audpp_disable(audio->dec_id, audio);
+ if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+ audmgr_disable(&audio->audmgr);
+ audio->out_needed = 0;
+ rmt_put_resource(audio);
+ audio->rmt_resource_released = 1;
+ }
+ return rc;
+}
+
+/* ------------------- dsp --------------------- */
+
+static void audac3_update_pcm_buf_entry(struct audio *audio,
+ uint32_t *payload)
+{
+ uint8_t index;
+ unsigned long flags;
+
+ if (audio->rflush)
+ return;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ for (index = 0; index < payload[1]; index++) {
+ if (audio->in[audio->fill_next].addr
+ == payload[2 + index * 2]) {
+ MM_DBG("in[%d] ready\n", audio->fill_next);
+ audio->in[audio->fill_next].used =
+ payload[3 + index * 2];
+ if ((++audio->fill_next) == audio->pcm_buf_count)
+ audio->fill_next = 0;
+
+ } else {
+ MM_ERR("expected=%x ret=%x\n",
+ audio->in[audio->fill_next].addr,
+ payload[1 + index * 2]);
+ break;
+ }
+ }
+ if (audio->in[audio->fill_next].used == 0) {
+ audac3_buffer_refresh(audio);
+ } else {
+ MM_DBG("read cannot keep up\n");
+ audio->buf_refresh = 1;
+ }
+ wake_up(&audio->read_wait);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static void audplay_dsp_event(void *data, unsigned id, size_t len,
+ void (*getevent) (void *ptr, size_t len))
+{
+ struct audio *audio = data;
+ uint32_t msg[28];
+ getevent(msg, sizeof(msg));
+
+ MM_DBG("msg_id=%x\n", id);
+ switch (id) {
+ case AUDPLAY_MSG_DEC_NEEDS_DATA:
+ audac3_send_data(audio, 1);
+ break;
+ case AUDPLAY_MSG_BUFFER_UPDATE:
+ MM_DBG("\n"); /* Macro prints the file name and function */
+ audac3_update_pcm_buf_entry(audio, msg);
+ break;
+ case ADSP_MESSAGE_ID:
+ MM_DBG("Received ADSP event: module enable(audplaytask)\n");
+ break;
+ default:
+ MM_ERR("unexpected message from decoder\n");
+ }
+}
+
+static void audac3_dsp_event(void *private, unsigned id, uint16_t *msg)
+{
+ struct audio *audio = private;
+
+ switch (id) {
+ case AUDPP_MSG_STATUS_MSG:{
+ unsigned status = msg[1];
+
+ switch (status) {
+ case AUDPP_DEC_STATUS_SLEEP: {
+ uint16_t reason = msg[2];
+ MM_DBG("decoder status:sleep reason =0x%04x\n",
+ reason);
+ if ((reason == AUDPP_MSG_REASON_MEM)
+ || (reason ==
+ AUDPP_MSG_REASON_NODECODER)) {
+ audio->dec_state =
+ MSM_AUD_DECODER_STATE_FAILURE;
+ wake_up(&audio->wait);
+ } else if (reason == AUDPP_MSG_REASON_NONE) {
+ /* decoder is in disable state */
+ audio->dec_state =
+ MSM_AUD_DECODER_STATE_CLOSE;
+ wake_up(&audio->wait);
+ }
+ break;
+ }
+ case AUDPP_DEC_STATUS_INIT:
+ MM_DBG("decoder status: init\n");
+ if (audio->pcm_feedback)
+ audpp_cmd_cfg_routing_mode(audio);
+ else
+ audpp_cmd_cfg_adec_params(audio);
+ break;
+
+ case AUDPP_DEC_STATUS_CFG:
+ MM_DBG("decoder status: cfg\n");
+ break;
+ case AUDPP_DEC_STATUS_PLAY:
+ MM_DBG("decoder status: play\n");
+ if (audio->pcm_feedback) {
+ audac3_config_hostpcm(audio);
+ audac3_buffer_refresh(audio);
+ }
+ audio->dec_state =
+ MSM_AUD_DECODER_STATE_SUCCESS;
+ wake_up(&audio->wait);
+ break;
+ default:
+ MM_ERR("unknown decoder status\n");
+ }
+ break;
+ }
+ case AUDPP_MSG_CFG_MSG:
+ if (msg[0] == AUDPP_MSG_ENA_ENA) {
+ MM_DBG("CFG_MSG ENABLE\n");
+ auddec_dsp_config(audio, 1);
+ audio->out_needed = 0;
+ audio->running = 1;
+ audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+ audpp_dsp_set_eq(audio->dec_id, audio->eq_enable,
+ &audio->eq);
+ audpp_avsync(audio->dec_id, 22050);
+ } else if (msg[0] == AUDPP_MSG_ENA_DIS) {
+ MM_DBG("CFG_MSG DISABLE\n");
+ audpp_avsync(audio->dec_id, 0);
+ audio->running = 0;
+ } else {
+ MM_DBG("CFG_MSG %d?\n", msg[0]);
+ }
+ break;
+ case AUDPP_MSG_ROUTING_ACK:
+ MM_DBG("ROUTING_ACK\n");
+ audpp_cmd_cfg_adec_params(audio);
+ break;
+ case AUDPP_MSG_FLUSH_ACK:
+ MM_DBG("FLUSH_ACK\n");
+ audio->wflush = 0;
+ audio->rflush = 0;
+ wake_up(&audio->write_wait);
+ if (audio->pcm_feedback)
+ audac3_buffer_refresh(audio);
+ break;
+ case AUDPP_MSG_PCMDMAMISSED:
+ MM_DBG("PCMDMAMISSED\n");
+ audio->teos = 1;
+ wake_up(&audio->write_wait);
+ break;
+ default:
+ MM_ERR("UNKNOWN (%d)\n", id);
+ }
+
+}
+
+struct msm_adsp_ops audplay_adsp_ops_ac3 = {
+ .event = audplay_dsp_event,
+};
+
+#define audplay_send_queue0(audio, cmd, len) \
+ msm_adsp_write(audio->audplay, audio->queue_id, \
+ cmd, len)
+
+static int auddec_dsp_config(struct audio *audio, int enable)
+{
+ u16 cfg_dec_cmd[AUDPP_CMD_CFG_DEC_TYPE_LEN / sizeof(unsigned short)];
+
+ memset(cfg_dec_cmd, 0, sizeof(cfg_dec_cmd));
+
+ cfg_dec_cmd[0] = AUDPP_CMD_CFG_DEC_TYPE;
+ if (enable)
+ cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+ AUDPP_CMD_ENA_DEC_V | AUDDEC_DEC_AC3;
+ else
+ cfg_dec_cmd[1 + audio->dec_id] = AUDPP_CMD_UPDATDE_CFG_DEC |
+ AUDPP_CMD_DIS_DEC_V;
+
+ return audpp_send_queue1(&cfg_dec_cmd, sizeof(cfg_dec_cmd));
+}
+static int get_frequency_index(unsigned short frequency)
+{
+ switch (frequency) {
+ case 48000: return 0;
+ case 44100: return 1;
+ case 32000: return 2;
+ default: return -EINVAL;
+ }
+}
+static void audpp_cmd_cfg_adec_params(struct audio *audio)
+{
+ struct audpp_cmd_cfg_adec_params_ac3 cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.common.cmd_id = AUDPP_CMD_CFG_ADEC_PARAMS;
+ /* dsp needs word size */
+ cmd.common.length = AUDPP_CMD_CFG_ADEC_PARAMS_AC3_LEN >> 1;
+ cmd.common.dec_id = audio->dec_id;
+ cmd.common.input_sampling_frequency = (audio->ac3_config).fsCod;
+
+ cmd.index[0] = (((audio->ac3_config).numChans << 8) & 0xFF00) |
+ ((audio->ac3_config).wordSize & 0x00FF);
+
+ cmd.index[1] = (((audio->ac3_config).kCapableMode << 12) & 0xF000) |
+ (((audio->ac3_config).compMode << 8) & 0x0F00) |
+ (((audio->ac3_config).outLfeOn << 4) & 0x00F0) |
+ ((audio->ac3_config).outputMode & 0x000F);
+
+ cmd.index[2] = ((((audio->ac3_config).stereoMode << 12) & 0xF000) |
+ (((audio->ac3_config).dualMonoMode << 8) & 0x0F00) |
+ ((get_frequency_index((audio->ac3_config).fsCod) << 4)
+ & 0x00F0)) & 0xFFF0; /* last 4 bytes are reserved */
+
+ cmd.index[3] = (audio->ac3_config).pcmScaleFac;
+ cmd.index[4] = (audio->ac3_config).dynRngScaleHi;
+ cmd.index[5] = (audio->ac3_config).dynRngScaleLow;
+
+ cmd.index[6] = (((audio->ac3_config).user_downmix_flag << 8) & 0xFF00)|
+ ((audio->ac3_config).user_karaoke_flag & 0x00FF);
+
+ cmd.index[7] = (audio->ac3_config).dm_address_high;
+ cmd.index[8] = (audio->ac3_config).dm_address_low;
+ cmd.index[9] = (audio->ac3_config).ko_address_high;
+ cmd.index[10] = (audio->ac3_config).ko_address_high;
+
+ cmd.index[11] = (((audio->ac3_config).max_rep_count << 1) & 0xFFFE) |
+ ((audio->ac3_config).error_concealment & 0x0001);
+
+ cmd.index[12] = (((audio->ac3_config).channel_routing_mode[3] << 12)
+ & 0xF000) |
+ (((audio->ac3_config).channel_routing_mode[2] << 8)
+ & 0x0F00) |
+ (((audio->ac3_config).channel_routing_mode[1] << 4)
+ & 0x00F0) |
+ ((audio->ac3_config).channel_routing_mode[0] & 0x000F);
+
+ cmd.index[13] = ((((audio->ac3_config).channel_routing_mode[5] << 12)
+ & 0xF000) |
+ (((audio->ac3_config).channel_routing_mode[4] << 8)
+ & 0x0F00)) & 0xFF00; /* last 8 bytes are reserved */
+
+ audpp_send_queue2(&cmd, sizeof(cmd));
+}
+
+static void audpp_cmd_cfg_routing_mode(struct audio *audio)
+{
+ struct audpp_cmd_routing_mode cmd;
+ MM_DBG("\n"); /* Macro prints the file name and function */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cmd_id = AUDPP_CMD_ROUTING_MODE;
+ cmd.object_number = audio->dec_id;
+ if (audio->pcm_feedback)
+ cmd.routing_mode = ROUTING_MODE_FTRT;
+ else
+ cmd.routing_mode = ROUTING_MODE_RT;
+
+ audpp_send_queue1(&cmd, sizeof(cmd));
+}
+
+static int audplay_dsp_send_data_avail(struct audio *audio,
+ unsigned idx, unsigned len)
+{
+ struct audplay_cmd_bitstream_data_avail_nt2 cmd;
+
+ cmd.cmd_id = AUDPLAY_CMD_BITSTREAM_DATA_AVAIL_NT2;
+ if (audio->mfield)
+ cmd.decoder_id = AUDAC3_METAFIELD_MASK |
+ (audio->out[idx].mfield_sz >> 1);
+ else
+ cmd.decoder_id = audio->dec_id;
+ cmd.buf_ptr = audio->out[idx].addr;
+ cmd.buf_size = len / 2;
+ cmd.partition_number = 0;
+ /* complete writes to the input buffer */
+ wmb();
+ return audplay_send_queue0(audio, &cmd, sizeof(cmd));
+}
+
+static void audac3_buffer_refresh(struct audio *audio)
+{
+ struct audplay_cmd_buffer_refresh refresh_cmd;
+
+ refresh_cmd.cmd_id = AUDPLAY_CMD_BUFFER_REFRESH;
+ refresh_cmd.num_buffers = 1;
+ refresh_cmd.buf0_address = audio->in[audio->fill_next].addr;
+ refresh_cmd.buf0_length = audio->in[audio->fill_next].size;
+
+ refresh_cmd.buf_read_count = 0;
+ MM_DBG("buf0_addr=%x buf0_len=%d\n", refresh_cmd.buf0_address,
+ refresh_cmd.buf0_length);
+ (void)audplay_send_queue0(audio, &refresh_cmd, sizeof(refresh_cmd));
+}
+
+static void audac3_config_hostpcm(struct audio *audio)
+{
+ struct audplay_cmd_hpcm_buf_cfg cfg_cmd;
+
+ MM_DBG("\n"); /* Macro prints the file name and function */
+ cfg_cmd.cmd_id = AUDPLAY_CMD_HPCM_BUF_CFG;
+ cfg_cmd.max_buffers = 1;
+ cfg_cmd.byte_swap = 0;
+ cfg_cmd.hostpcm_config = (0x8000) | (0x4000);
+ cfg_cmd.feedback_frequency = 1;
+ cfg_cmd.partition_number = 0;
+ (void)audplay_send_queue0(audio, &cfg_cmd, sizeof(cfg_cmd));
+
+}
+
+static void audac3_send_data(struct audio *audio, unsigned needed)
+{
+ struct buffer *frame;
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ if (!audio->running)
+ goto done;
+
+ if (needed && !audio->wflush) {
+ /* We were called from the callback because the DSP
+ * requested more data. Note that the DSP does want
+ * more data, and if a buffer was in-flight, mark it
+ * as available (since the DSP must now be done with
+ * it).
+ */
+ audio->out_needed = 1;
+ frame = audio->out + audio->out_tail;
+ if (frame->used == 0xffffffff) {
+ MM_DBG("frame %d free\n", audio->out_tail);
+ frame->used = 0;
+ audio->out_tail ^= 1;
+ wake_up(&audio->write_wait);
+ }
+ }
+
+ if (audio->out_needed) {
+ /* If the DSP currently wants data and we have a
+ * buffer available, we will send it and reset
+ * the needed flag. We'll mark the buffer as in-flight
+ * so that it won't be recycled until the next buffer
+ * is requested
+ */
+
+ frame = audio->out + audio->out_tail;
+ if (frame->used) {
+ BUG_ON(frame->used == 0xffffffff);
+ MM_DBG("frame %d busy\n", audio->out_tail);
+ audplay_dsp_send_data_avail(audio, audio->out_tail,
+ frame->used);
+ frame->used = 0xffffffff;
+ audio->out_needed = 0;
+ }
+ }
+done:
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+
+static void audac3_flush(struct audio *audio)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ audio->out[0].used = 0;
+ audio->out[1].used = 0;
+ audio->out_head = 0;
+ audio->out_tail = 0;
+ audio->out_needed = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ atomic_set(&audio->out_bytes, 0);
+}
+
+static void audac3_flush_pcm_buf(struct audio *audio)
+{
+ uint8_t index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ for (index = 0; index < PCM_BUF_MAX_COUNT; index++)
+ audio->in[index].used = 0;
+ audio->buf_refresh = 0;
+ audio->read_next = 0;
+ audio->fill_next = 0;
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+/*check if func to be added to validate user data*/
+
+static void audac3_ioport_reset(struct audio *audio)
+{
+ /* Make sure read/write thread are free from
+ * sleep and knowing that system is not able
+ * to process io request at the moment
+ */
+ wake_up(&audio->write_wait);
+ mutex_lock(&audio->write_lock);
+ audac3_flush(audio);
+ mutex_unlock(&audio->write_lock);
+ wake_up(&audio->read_wait);
+ mutex_lock(&audio->read_lock);
+ audac3_flush_pcm_buf(audio);
+ mutex_unlock(&audio->read_lock);
+}
+
+static int audac3_events_pending(struct audio *audio)
+{
+ unsigned long flags;
+ int empty;
+
+ spin_lock_irqsave(&audio->event_queue_lock, flags);
+ empty = !list_empty(&audio->event_queue);
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+ return empty || audio->event_abort;
+}
+
+static void audac3_reset_event_queue(struct audio *audio)
+{
+ unsigned long flags;
+ struct audac3_event *drv_evt;
+ struct list_head *ptr, *next;
+
+ spin_lock_irqsave(&audio->event_queue_lock, flags);
+ list_for_each_safe(ptr, next, &audio->event_queue) {
+ drv_evt = list_first_entry(&audio->event_queue,
+ struct audac3_event, list);
+ list_del(&drv_evt->list);
+ kfree(drv_evt);
+ }
+ list_for_each_safe(ptr, next, &audio->free_event_queue) {
+ drv_evt = list_first_entry(&audio->free_event_queue,
+ struct audac3_event, list);
+ list_del(&drv_evt->list);
+ kfree(drv_evt);
+ }
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+ return;
+}
+
+
+static long audac3_process_event_req(struct audio *audio, void __user *arg)
+{
+ long rc;
+ struct msm_audio_event usr_evt;
+ struct audac3_event *drv_evt = NULL;
+ int timeout;
+ unsigned long flags;
+
+ if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+ return -EFAULT;
+
+ timeout = (int) usr_evt.timeout_ms;
+
+ if (timeout > 0) {
+ rc = wait_event_interruptible_timeout(
+ audio->event_wait, audac3_events_pending(audio),
+ msecs_to_jiffies(timeout));
+ if (rc == 0)
+ return -ETIMEDOUT;
+ } else {
+ rc = wait_event_interruptible(
+ audio->event_wait, audac3_events_pending(audio));
+ }
+
+ if (rc < 0)
+ return rc;
+
+ if (audio->event_abort) {
+ audio->event_abort = 0;
+ return -ENODEV;
+ }
+
+ rc = 0;
+
+ spin_lock_irqsave(&audio->event_queue_lock, flags);
+ if (!list_empty(&audio->event_queue)) {
+ drv_evt = list_first_entry(&audio->event_queue,
+ struct audac3_event, list);
+ list_del(&drv_evt->list);
+ }
+ if (drv_evt) {
+ usr_evt.event_type = drv_evt->event_type;
+ usr_evt.event_payload = drv_evt->payload;
+ list_add_tail(&drv_evt->list, &audio->free_event_queue);
+ } else
+ rc = -1;
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+ if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+ rc = -EFAULT;
+
+ return rc;
+}
+
+static int audio_enable_eq(struct audio *audio, int enable)
+{
+ if (audio->eq_enable == enable && !audio->eq_needs_commit)
+ return 0;
+
+ audio->eq_enable = enable;
+
+ if (audio->running) {
+ audpp_dsp_set_eq(audio->dec_id, enable, &audio->eq);
+ audio->eq_needs_commit = 0;
+ }
+ return 0;
+}
+
+static long audac3_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct audio *audio = file->private_data;
+ int rc = -EINVAL;
+ unsigned long flags = 0;
+ uint16_t enable_mask;
+ int enable;
+ int prev_state;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ int len = 0;
+
+ MM_DBG("cmd = %d\n", cmd);
+
+ switch (cmd) {
+ case AUDIO_ENABLE_AUDPP:
+ if (copy_from_user(&enable_mask, (void *) arg,
+ sizeof(enable_mask))) {
+ rc = -EFAULT;
+ break;
+ }
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ enable = (enable_mask & EQ_ENABLE) ? 1 : 0;
+ audio_enable_eq(audio, enable);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ rc = 0;
+ break;
+ case AUDIO_SET_VOLUME:
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ audio->vol_pan.volume = arg;
+ if (audio->running)
+ audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ rc = 0;
+ break;
+
+ case AUDIO_SET_PAN:
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ audio->vol_pan.pan = arg;
+ if (audio->running)
+ audpp_dsp_set_vol_pan(audio->dec_id, &audio->vol_pan);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+ rc = 0;
+ break;
+
+ case AUDIO_SET_EQ:
+ prev_state = audio->eq_enable;
+ audio->eq_enable = 0;
+ if (copy_from_user(&audio->eq.num_bands, (void *) arg,
+ sizeof(audio->eq) -
+ (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+ rc = -EFAULT;
+ break;
+ }
+ audio->eq_enable = prev_state;
+ audio->eq_needs_commit = 1;
+ rc = 0;
+ break;
+ }
+
+ if (-EINVAL != rc)
+ return rc;
+
+ if (cmd == AUDIO_GET_EVENT) {
+ MM_DBG("AUDIO_GET_EVENT\n");
+ if (mutex_trylock(&audio->get_event_lock)) {
+ rc = audac3_process_event_req(audio,
+ (void __user *) arg);
+ mutex_unlock(&audio->get_event_lock);
+ } else
+ rc = -EBUSY;
+ return rc;
+ }
+
+ if (cmd == AUDIO_ABORT_GET_EVENT) {
+ audio->event_abort = 1;
+ wake_up(&audio->event_wait);
+ return 0;
+ }
+
+ mutex_lock(&audio->lock);
+ switch (cmd) {
+ case AUDIO_START:
+ MM_DBG("AUDIO_START\n");
+ rc = audac3_enable(audio);
+ if (!rc) {
+ rc = wait_event_interruptible_timeout(audio->wait,
+ audio->dec_state != MSM_AUD_DECODER_STATE_NONE,
+ msecs_to_jiffies(MSM_AUD_DECODER_WAIT_MS));
+ MM_INFO("dec_state %d rc = %d\n", audio->dec_state, rc);
+
+ if (audio->dec_state != MSM_AUD_DECODER_STATE_SUCCESS) {
+ MM_ERR("In audio->dec_state !=\n");
+ rc = -ENODEV;
+ } else
+ rc = 0;
+ }
+ break;
+ case AUDIO_STOP:
+ MM_DBG("AUDIO_STOP\n");
+ rc = audac3_disable(audio);
+ audac3_ioport_reset(audio);
+ audio->stopped = 0;
+ break;
+ case AUDIO_FLUSH:
+ MM_DBG("AUDIO_FLUSH\n");
+ audio->rflush = 1;
+ audio->wflush = 1;
+ audac3_ioport_reset(audio);
+ if (audio->running) {
+ audpp_flush(audio->dec_id);
+ rc = wait_event_interruptible(audio->write_wait,
+ !audio->wflush);
+ if (rc < 0) {
+ MM_ERR("AUDIO_FLUSH interrupted\n");
+ rc = -EINTR;
+ }
+ } else {
+ audio->rflush = 0;
+ audio->wflush = 0;
+ }
+ break;
+ case AUDIO_SET_CONFIG:{
+ struct msm_audio_config config;
+ if (copy_from_user
+ (&config, (void *)arg, sizeof(config))) {
+ rc = -EFAULT;
+ break;
+ }
+ audio->mfield = config.meta_field;
+ rc = 0;
+ MM_DBG("AUDIO_SET_CONFIG applicable only"\
+ " for meta field configuration\n");
+ break;
+ }
+ case AUDIO_GET_CONFIG:{
+ struct msm_audio_config config;
+ config.buffer_size = BUFSZ;
+ config.buffer_count = 2;
+ config.sample_rate = (audio->ac3_config).fsCod;
+ config.channel_count = 2;
+ config.meta_field = 0;
+ config.unused[0] = 0;
+ config.unused[1] = 0;
+ config.unused[2] = 0;
+ if (copy_to_user((void *)arg, &config, sizeof(config)))
+ rc = -EFAULT;
+ else
+ rc = 0;
+ break;
+ }
+ case AUDIO_GET_AC3_CONFIG:{
+ if (copy_to_user((void *)arg, &audio->ac3_config,
+ sizeof(audio->ac3_config)))
+ rc = -EFAULT;
+ else
+ rc = 0;
+ break;
+ }
+ case AUDIO_SET_AC3_CONFIG:{
+ struct msm_audio_ac3_config usr_config;
+
+ if (copy_from_user
+ (&usr_config, (void *)arg,
+ sizeof(usr_config))) {
+ rc = -EFAULT;
+ break;
+ }
+
+ audio->ac3_config = usr_config;
+ rc = 0;
+ break;
+ }
+ case AUDIO_GET_PCM_CONFIG:{
+ struct msm_audio_pcm_config config;
+ config.pcm_feedback = audio->pcm_feedback;
+ config.buffer_count = PCM_BUF_MAX_COUNT;
+ config.buffer_size = PCM_BUFSZ;
+ if (copy_to_user((void *)arg, &config, sizeof(config)))
+ rc = -EFAULT;
+ else
+ rc = 0;
+ break;
+ }
+ case AUDIO_SET_PCM_CONFIG:{
+ struct msm_audio_pcm_config config;
+ if (copy_from_user
+ (&config, (void *)arg, sizeof(config))) {
+ rc = -EFAULT;
+ break;
+ }
+ if (config.pcm_feedback != audio->pcm_feedback) {
+
+ MM_ERR("Not sufficient permission to"\
+ " change the playback mode\n");
+ rc = -EACCES;
+ break;
+
+ }
+ if ((config.buffer_count > PCM_BUF_MAX_COUNT) ||
+ (config.buffer_count == 1))
+ config.buffer_count = PCM_BUF_MAX_COUNT;
+
+ if (config.buffer_size < PCM_BUFSZ)
+ config.buffer_size = PCM_BUFSZ;
+
+ /* Check if pcm feedback is required */
+ if ((config.pcm_feedback) && (!audio->read_data)) {
+ MM_DBG("allocate PCM buf %d\n",
+ config.buffer_count *
+ config.buffer_size);
+ handle = ion_alloc(audio->client,
+ (config.buffer_size *
+ config.buffer_count),
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to alloc I/P buffs\n");
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ }
+
+ audio->input_buff_handle = handle;
+
+ rc = ion_phys(audio->client ,
+ handle, &addr, &len);
+ if (rc) {
+ MM_ERR("Invalid phy: %x sz: %x\n",
+ (unsigned int) addr,
+ (unsigned int) len);
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ } else {
+ MM_INFO("Got valid phy: %x sz: %x\n",
+ (unsigned int) audio->read_phys,
+ (unsigned int) len);
+ }
+ audio->read_phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(audio->client,
+ handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ break;
+ }
+
+ audio->map_v_read = ion_map_kernel(
+ audio->client,
+ handle, ionflag);
+ if (IS_ERR(audio->map_v_read)) {
+ MM_ERR("map of read buf failed\n");
+ ion_free(audio->client, handle);
+ audio->input_buff_handle = NULL;
+ rc = -ENOMEM;
+ } else {
+ uint8_t index;
+ uint32_t offset = 0;
+ audio->read_data =
+ audio->map_v_read;
+ audio->buf_refresh = 0;
+ audio->pcm_buf_count =
+ config.buffer_count;
+ audio->read_next = 0;
+ audio->fill_next = 0;
+
+ for (index = 0;
+ index < config.buffer_count;
+ index++) {
+ audio->in[index].data =
+ audio->read_data + offset;
+ audio->in[index].addr =
+ audio->read_phys + offset;
+ audio->in[index].size =
+ config.buffer_size;
+ audio->in[index].used = 0;
+ offset += config.buffer_size;
+ }
+ MM_DBG("read buf: phy addr"\
+ " 0x%08x kernel addr 0x%08x\n",
+ audio->read_phys,
+ (int)audio->read_data);
+ rc = 0;
+ }
+ } else {
+ rc = 0;
+ }
+ break;
+ }
+ case AUDIO_PAUSE:
+ MM_DBG("AUDIO_PAUSE %ld\n", arg);
+ rc = audpp_pause(audio->dec_id, (int) arg);
+ break;
+ default:
+ rc = -EINVAL;
+ }
+ mutex_unlock(&audio->lock);
+ return rc;
+}
+
+/* Only useful in tunnel-mode */
+static int audac3_fsync(struct file *file, loff_t a, loff_t b, int datasync)
+{
+ struct audio *audio = file->private_data;
+ int rc = 0;
+
+ MM_DBG("\n"); /* Macro prints the file name and function */
+ if (!audio->running || audio->pcm_feedback) {
+ rc = -EINVAL;
+ goto done_nolock;
+ }
+
+ mutex_lock(&audio->write_lock);
+
+ rc = wait_event_interruptible(audio->write_wait,
+ (!audio->out[0].used &&
+ !audio->out[1].used &&
+ audio->out_needed) || audio->wflush);
+
+ if (rc < 0)
+ goto done;
+ else if (audio->wflush) {
+ rc = -EBUSY;
+ goto done;
+ }
+
+ /* pcm dmamiss message is sent continously
+ * when decoder is starved so no race
+ * condition concern
+ */
+ audio->teos = 0;
+
+ rc = wait_event_interruptible(audio->write_wait,
+ audio->teos || audio->wflush);
+
+ if (audio->wflush)
+ rc = -EBUSY;
+
+done:
+ mutex_unlock(&audio->write_lock);
+done_nolock:
+ return rc;
+}
+
+static ssize_t audac3_read(struct file *file, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct audio *audio = file->private_data;
+ const char __user *start = buf;
+ int rc = 0;
+ if (!audio->pcm_feedback) {
+ MM_ERR("returning from read as tunnel mode\n");
+ return 0;
+ /* PCM feedback is not enabled. Nothing to read */
+ }
+ mutex_lock(&audio->read_lock);
+ MM_DBG("\n"); /* Macro prints the file name and function */
+ while (count > 0) {
+ rc = wait_event_interruptible(audio->read_wait,
+ (audio->in[audio->read_next].used > 0) ||
+ (audio->stopped) || (audio->rflush));
+
+ MM_DBG("wait terminated count%d\n", count);
+ if (rc < 0)
+ break;
+ if (audio->stopped || audio->rflush) {
+ rc = -EBUSY;
+ break;
+ }
+ if (count < audio->in[audio->read_next].used) {
+ /* Read must happen in frame boundary. Since driver does
+ * not know frame size, read count must be greater or
+ * equal to size of PCM samples
+ */
+ MM_DBG("read stop - partial frame\n");
+ break;
+ } else {
+ MM_DBG("read from in[%d]\n", audio->read_next);
+ /* order reads from the output buffer */
+ rmb();
+ if (copy_to_user
+ (buf, audio->in[audio->read_next].data,
+ audio->in[audio->read_next].used)) {
+ MM_ERR("invalid addr %x\n",
+ (unsigned int)buf);
+ rc = -EFAULT;
+ break;
+ }
+ count -= audio->in[audio->read_next].used;
+ buf += audio->in[audio->read_next].used;
+ audio->in[audio->read_next].used = 0;
+ if ((++audio->read_next) == audio->pcm_buf_count)
+ audio->read_next = 0;
+ break;
+ /* Force to exit while loop
+ * to prevent output thread
+ * sleep too long if data is
+ * not ready at this moment
+ */
+
+ }
+ }
+ /* don't feed output buffer to HW decoder during flushing
+ * buffer refresh command will be sent once flush completes
+ * send buf refresh command here can confuse HW decoder
+ */
+ if (audio->buf_refresh && !audio->rflush) {
+ audio->buf_refresh = 0;
+ MM_DBG("kick start pcm feedback again\n");
+ audac3_buffer_refresh(audio);
+ }
+ mutex_unlock(&audio->read_lock);
+ if (buf > start)
+ rc = buf - start;
+ MM_DBG("read %d bytes\n", rc);
+ return rc;
+}
+
+static int audac3_process_eos(struct audio *audio,
+ const char __user *buf_start, unsigned short mfield_size)
+{
+ int rc = 0;
+ struct buffer *frame;
+
+ frame = audio->out + audio->out_head;
+
+ rc = wait_event_interruptible(audio->write_wait,
+ (audio->out_needed &&
+ audio->out[0].used == 0 &&
+ audio->out[1].used == 0)
+ || (audio->stopped)
+ || (audio->wflush));
+
+ if (rc < 0)
+ goto done;
+ if (audio->stopped || audio->wflush) {
+ rc = -EBUSY;
+ goto done;
+ }
+
+ if (copy_from_user(frame->data, buf_start, mfield_size)) {
+ rc = -EFAULT;
+ goto done;
+ }
+
+ frame->mfield_sz = mfield_size;
+ audio->out_head ^= 1;
+ frame->used = mfield_size;
+ audac3_send_data(audio, 0);
+
+done:
+ return rc;
+}
+
+static ssize_t audac3_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct audio *audio = file->private_data;
+ const char __user *start = buf;
+ struct buffer *frame;
+ size_t xfer;
+ char *cpy_ptr;
+ unsigned short mfield_size = 0;
+ int rc = 0, eos_condition = AUDAC3_EOS_NONE;
+
+ MM_DBG("cnt=%d\n", count);
+
+ if (count & 1)
+ return -EINVAL;
+
+ mutex_lock(&audio->write_lock);
+ while (count > 0) {
+ frame = audio->out + audio->out_head;
+ cpy_ptr = frame->data;
+ rc = wait_event_interruptible(audio->write_wait,
+ (frame->used == 0)
+ || (audio->stopped)
+ || (audio->wflush));
+ if (rc < 0)
+ break;
+ if (audio->stopped || audio->wflush) {
+ rc = -EBUSY;
+ break;
+ }
+
+ if (audio->mfield) {
+ if (buf == start) {
+ /* Processing beginning of user buffer */
+ if (__get_user(mfield_size,
+ (unsigned short __user *) buf)) {
+ rc = -EFAULT;
+ break;
+ } else if (mfield_size > count) {
+ rc = -EINVAL;
+ break;
+ }
+ MM_DBG("mf offset_val %x\n", mfield_size);
+ if (copy_from_user(cpy_ptr, buf,
+ mfield_size)) {
+ rc = -EFAULT;
+ break;
+ }
+ /* Check if EOS flag is set and buffer has
+ * contains just meta field
+ */
+ if (cpy_ptr[AUDAC3_EOS_FLG_OFFSET] &
+ AUDAC3_EOS_FLG_MASK) {
+ MM_DBG("eos set\n");
+ eos_condition = AUDAC3_EOS_SET;
+ if (mfield_size == count) {
+ buf += mfield_size;
+ break;
+ } else
+ cpy_ptr[AUDAC3_EOS_FLG_OFFSET] &=
+ ~AUDAC3_EOS_FLG_MASK;
+ }
+ /* Check EOS to see if */
+ cpy_ptr += mfield_size;
+ count -= mfield_size;
+ buf += mfield_size;
+ } else {
+ mfield_size = 0;
+ MM_DBG("continuous buffer\n");
+ }
+ frame->mfield_sz = mfield_size;
+ }
+
+ xfer = (count > (frame->size - mfield_size)) ?
+ (frame->size - mfield_size) : count;
+ if (copy_from_user(cpy_ptr, buf, xfer)) {
+ rc = -EFAULT;
+ break;
+ }
+ frame->used = xfer + mfield_size;
+ audio->out_head ^= 1;
+ count -= xfer;
+ buf += xfer;
+ audac3_send_data(audio, 0);
+ }
+ if (eos_condition == AUDAC3_EOS_SET)
+ rc = audac3_process_eos(audio, start, mfield_size);
+ mutex_unlock(&audio->write_lock);
+ if (!rc) {
+ if (buf > start)
+ return buf - start;
+ }
+ return rc;
+}
+
+static int audac3_release(struct inode *inode, struct file *file)
+{
+ struct audio *audio = file->private_data;
+
+ MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
+ mutex_lock(&audio->lock);
+ audac3_disable(audio);
+ if (audio->rmt_resource_released == 0)
+ rmt_put_resource(audio);
+ audac3_flush(audio);
+ audac3_flush_pcm_buf(audio);
+ msm_adsp_put(audio->audplay);
+ audpp_adec_free(audio->dec_id);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+ audio->event_abort = 1;
+ wake_up(&audio->event_wait);
+ audac3_reset_event_queue(audio);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
+ if (audio->input_buff_handle != NULL) {
+ ion_unmap_kernel(audio->client, audio->input_buff_handle);
+ ion_free(audio->client, audio->input_buff_handle);
+ }
+ ion_client_destroy(audio->client);
+ mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+ if (audio->dentry)
+ debugfs_remove(audio->dentry);
+#endif
+ kfree(audio);
+ return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audac3_post_event(struct audio *audio, int type,
+ union msm_audio_event_payload payload)
+{
+ struct audac3_event *e_node = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+ if (!list_empty(&audio->free_event_queue)) {
+ e_node = list_first_entry(&audio->free_event_queue,
+ struct audac3_event, list);
+ list_del(&e_node->list);
+ } else {
+ e_node = kmalloc(sizeof(struct audac3_event), GFP_ATOMIC);
+ if (!e_node) {
+ MM_ERR("No mem to post event %d\n", type);
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+ return;
+ }
+ }
+
+ e_node->event_type = type;
+ e_node->payload = payload;
+
+ list_add_tail(&e_node->list, &audio->event_queue);
+ spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+ wake_up(&audio->event_wait);
+}
+
+static void audac3_suspend(struct early_suspend *h)
+{
+ struct audac3_suspend_ctl *ctl =
+ container_of(h, struct audac3_suspend_ctl, node);
+ union msm_audio_event_payload payload;
+
+ MM_DBG("\n"); /* Macro prints the file name and function */
+ audac3_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audac3_resume(struct early_suspend *h)
+{
+ struct audac3_suspend_ctl *ctl =
+ container_of(h, struct audac3_suspend_ctl, node);
+ union msm_audio_event_payload payload;
+
+ MM_DBG("\n"); /* Macro prints the file name and function */
+ audac3_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audac3_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t audac3_debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ const int debug_bufmax = 1024;
+ static char buffer[1024];
+ int n = 0, i;
+ struct audio *audio = file->private_data;
+
+ mutex_lock(&audio->lock);
+ n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "enabled %d\n", audio->enabled);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "stopped %d\n", audio->stopped);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "pcm_feedback %d\n", audio->pcm_feedback);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "out_buf_sz %d\n", audio->out[0].size);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "pcm_buf_count %d\n", audio->pcm_buf_count);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "pcm_buf_sz %d\n", audio->in[0].size);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "volume %x\n", audio->vol_pan.volume);
+ mutex_unlock(&audio->lock);
+ /* Following variables are only useful for debugging when
+ * when playback halts unexpectedly. Thus, no mutual exclusion
+ * enforced
+ */
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "wflush %d\n", audio->wflush);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "rflush %d\n", audio->rflush);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "running %d\n", audio->running);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "dec state %d\n", audio->dec_state);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "out_needed %d\n", audio->out_needed);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "out_head %d\n", audio->out_head);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "out_tail %d\n", audio->out_tail);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "out[0].used %d\n", audio->out[0].used);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "out[1].used %d\n", audio->out[1].used);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "buffer_refresh %d\n", audio->buf_refresh);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "read_next %d\n", audio->read_next);
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "fill_next %d\n", audio->fill_next);
+ for (i = 0; i < audio->pcm_buf_count; i++)
+ n += scnprintf(buffer + n, debug_bufmax - n,
+ "in[%d].size %d\n", i, audio->in[i].used);
+ buffer[n] = 0;
+ return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audac3_debug_fops = {
+ .read = audac3_debug_read,
+ .open = audac3_debug_open,
+};
+#endif
+
+static int audac3_open(struct inode *inode, struct file *file)
+{
+ struct audio *audio = NULL;
+ int rc, dec_attrb, decid, i;
+ struct audac3_event *e_node = NULL;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+#ifdef CONFIG_DEBUG_FS
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_ac3_" + 5];
+#endif
+
+ /* Allocate audio instance, set to zero */
+ audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+ if (!audio) {
+ MM_ERR("no memory to allocate audio instance\n");
+ rc = -ENOMEM;
+ goto done;
+ }
+ MM_INFO("audio instance 0x%08x created\n", (int)audio);
+
+ /* Allocate the decoder */
+ dec_attrb = AUDDEC_DEC_AC3;
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ dec_attrb |= MSM_AUD_MODE_NONTUNNEL;
+ audio->pcm_feedback = NON_TUNNEL_MODE_PLAYBACK;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ dec_attrb |= MSM_AUD_MODE_TUNNEL;
+ audio->pcm_feedback = TUNNEL_MODE_PLAYBACK;
+ } else {
+ kfree(audio);
+ rc = -EACCES;
+ goto done;
+ }
+ decid = audpp_adec_alloc(dec_attrb, &audio->module_name,
+ &audio->queue_id);
+
+ if (decid < 0) {
+ MM_ERR("No free decoder available, freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENODEV;
+ kfree(audio);
+ goto done;
+ }
+
+ audio->dec_id = decid & MSM_AUD_DECODER_MASK;
+
+ client = msm_ion_client_create(UINT_MAX, "Audio_AC3_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
+ rc = -ENOMEM;
+ goto client_create_error;
+ }
+ audio->client = client;
+
+ handle = ion_alloc(client, DMASZ, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client, handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR(audio->map_v_write)) {
+ MM_ERR("could not map write buffers,freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ audio->data = audio->map_v_write;
+ MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ rc = msm_adsp_get(audio->module_name, &audio->audplay,
+ &audplay_adsp_ops_ac3, audio);
+ if (rc) {
+ MM_ERR("failed to get %s module, freeing instance 0x%08x\n",
+ audio->module_name, (int)audio);
+ if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+ audmgr_close(&audio->audmgr);
+ goto err;
+ }
+
+ rc = rmt_get_resource(audio);
+ if (rc) {
+ MM_ERR("ADSP resources are not available for AC3 session"\
+ " 0x%08x on decoder: %d\n", (int)audio, audio->dec_id);
+ if (audio->pcm_feedback == TUNNEL_MODE_PLAYBACK)
+ audmgr_close(&audio->audmgr);
+ msm_adsp_put(audio->audplay);
+ goto err;
+ }
+
+ /* Initialize all locks of audio instance */
+ audio->input_buff_handle = NULL;
+ mutex_init(&audio->lock);
+ mutex_init(&audio->write_lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->get_event_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->write_wait);
+ init_waitqueue_head(&audio->read_wait);
+ INIT_LIST_HEAD(&audio->free_event_queue);
+ INIT_LIST_HEAD(&audio->event_queue);
+ init_waitqueue_head(&audio->wait);
+ init_waitqueue_head(&audio->event_wait);
+ spin_lock_init(&audio->event_queue_lock);
+
+ audio->out[0].data = audio->data + 0;
+ audio->out[0].addr = audio->phys + 0;
+ audio->out[0].size = BUFSZ;
+
+ audio->out[1].data = audio->data + BUFSZ;
+ audio->out[1].addr = audio->phys + BUFSZ;
+ audio->out[1].size = BUFSZ;
+
+ audio->vol_pan.volume = 0x3FFF;
+
+ (audio->ac3_config).wordSize = AUDAC3_DEF_WORDSIZE;
+ (audio->ac3_config).user_downmix_flag = AUDAC3_DEF_USER_DOWNMIX_FLAG;
+ (audio->ac3_config).user_karaoke_flag = AUDAC3_DEF_USER_KARAOKE_FLAG;
+ (audio->ac3_config).error_concealment = AUDAC3_DEF_ERROR_CONCEALMENT;
+ (audio->ac3_config).max_rep_count = AUDAC3_DEF_MAX_REPEAT_COUNT;
+
+ audac3_flush(audio);
+
+ file->private_data = audio;
+ audio->opened = 1;
+#ifdef CONFIG_DEBUG_FS
+ snprintf(name, sizeof name, "msm_ac3_%04x", audio->dec_id);
+ audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *) audio, &audac3_debug_fops);
+
+ if (IS_ERR(audio->dentry))
+ MM_DBG("debugfs_create_file failed\n");
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+ audio->suspend_ctl.node.resume = audac3_resume;
+ audio->suspend_ctl.node.suspend = audac3_suspend;
+ audio->suspend_ctl.audio = audio;
+ register_early_suspend(&audio->suspend_ctl.node);
+#endif
+ for (i = 0; i < AUDAC3_EVENT_NUM; i++) {
+ e_node = kmalloc(sizeof(struct audac3_event), GFP_KERNEL);
+ if (e_node)
+ list_add_tail(&e_node->list, &audio->free_event_queue);
+ else {
+ MM_ERR("event pkt alloc failed\n");
+ break;
+ }
+ }
+done:
+ return rc;
+err:
+ ion_unmap_kernel(client, audio->output_buff_handle);
+output_buff_map_error:
+output_buff_get_flags_error:
+output_buff_get_phys_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
+ audpp_adec_free(audio->dec_id);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_ac3_fops = {
+ .owner = THIS_MODULE,
+ .open = audac3_open,
+ .release = audac3_release,
+ .read = audac3_read,
+ .write = audac3_write,
+ .unlocked_ioctl = audac3_ioctl,
+ .fsync = audac3_fsync,
+};
+
+struct miscdevice audio_ac3_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_ac3",
+ .fops = &audio_ac3_fops,
+};
+
+static int __init audac3_init(void)
+{
+ return misc_register(&audio_ac3_misc);
+
+}
+
+static void __exit audac3_exit(void)
+{
+ misc_deregister(&audio_ac3_misc);
+}
+
+module_init(audac3_init);
+module_exit(audac3_exit);
+
+MODULE_DESCRIPTION("MSM AC3 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_acdb.c b/arch/arm/mach-msm/qdsp5/audio_acdb.c
new file mode 100644
index 0000000..16f23f4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/audio_acdb.c
@@ -0,0 +1,2646 @@
+/* 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 <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/memory_alloc.h>
+#include <linux/mfd/marimba.h>
+#include <mach/dal.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/socinfo.h>
+#include <mach/qdsp5/qdsp5audpp.h>
+#include <mach/qdsp5/qdsp5audpreproc.h>
+#include <mach/qdsp5/qdsp5audppcmdi.h>
+#include <mach/qdsp5/qdsp5audpreproccmdi.h>
+#include <mach/qdsp5/qdsp5audpreprocmsg.h>
+#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/audio_acdbi.h>
+#include <mach/qdsp5/acdb_commands.h>
+#include <mach/qdsp5/audio_acdb_def.h>
+#include <mach/debug_mm.h>
+#include <mach/msm_memtypes.h>
+
+#include "audmgr.h"
+
+/* this is the ACDB device ID */
+#define DALDEVICEID_ACDB 0x02000069
+#define ACDB_PORT_NAME "DAL00"
+#define ACDB_CPU SMD_APPS_MODEM
+#define ACDB_BUF_SIZE 4096
+#define FLUENCE_BUF_SIZE 498
+
+#define ACDB_VALUES_NOT_FILLED 0
+#define ACDB_VALUES_FILLED 1
+#define MAX_RETRY 10
+
+#define COMMON_OBJ_ID 6
+
+/*below macro is used to align the session info received from
+Devctl driver with the state mentioned as not to alter the
+Existing code*/
+#define AUDREC_OFFSET 2
+/* rpc table index */
+enum {
+ ACDB_DAL_IOCTL = DALDEVICE_FIRST_DEVICE_API_IDX
+};
+
+enum {
+ CAL_DATA_READY = 0x1,
+ AUDPP_READY = 0x2,
+ AUDREC_READY = 0x4,
+};
+
+struct acdb_data {
+ void *handle;
+
+ u32 phys_addr;
+ u8 *virt_addr;
+
+ struct task_struct *cb_thread_task;
+ struct device_info_callback dev_cb;
+
+ u32 acdb_state;
+ struct audpp_event_callback audpp_cb;
+ struct audpreproc_event_callback audpreproc_cb;
+ struct dev_evt_msg *device_info;
+
+ audpp_cmd_cfg_object_params_pcm *pp_iir;
+ audpp_cmd_cfg_object_params_mbadrc *pp_mbadrc;
+ audpreproc_cmd_cfg_agc_params *preproc_agc;
+ audpreproc_cmd_cfg_iir_tuning_filter_params *preproc_iir;
+ audpreproc_cmd_cfg_ns_params *preproc_ns;
+ struct acdb_mbadrc_block mbadrc_block;
+
+ wait_queue_head_t wait;
+ struct mutex acdb_mutex;
+ u32 device_cb_compl;
+ u32 audpp_cb_compl;
+ u32 preproc_cb_compl;
+ u8 preproc_stream_id;
+ u8 audrec_applied;
+ u32 multiple_sessions;
+ u32 cur_tx_session;
+ struct acdb_result acdb_result;
+
+ spinlock_t dsp_lock;
+ int dec_id;
+ audpp_cmd_cfg_object_params_eqalizer eq;
+ struct audrec_session_info session_info;
+ /*pmem info*/
+ int pmem_fd;
+ unsigned long paddr;
+ unsigned long kvaddr;
+ unsigned long pmem_len;
+ struct file *file;
+ /* pmem for get acdb blk */
+ unsigned long get_blk_paddr;
+ u8 *get_blk_kvaddr;
+ void *map_v_get_blk;
+};
+
+static struct acdb_data acdb_data;
+
+struct acdb_cache_node {
+ u32 node_status;
+ s32 stream_id;
+ u32 phys_addr_acdb_values;
+ void *map_v_addr;
+ u8 *virt_addr_acdb_values;
+ struct dev_evt_msg device_info;
+};
+
+struct acdb_cache_node acdb_cache_rx;
+
+/*for TX devices acdb values are applied based on AUDREC session and
+the depth of the tx cache is define by number of AUDREC sessions supported*/
+struct acdb_cache_node acdb_cache_tx;
+
+/*Audrec session info includes Attributes Sampling frequency and enc_id */
+struct audrec_session_info session_info;
+#ifdef CONFIG_DEBUG_FS
+
+#define RTC_MAX_TIMEOUT 500 /* 500 ms */
+#define PMEM_RTC_ACDB_QUERY_MEM 4096
+#define EXTRACT_HIGH_WORD(x) ((x & 0xFFFF0000)>>16)
+#define EXTRACT_LOW_WORD(x) (0x0000FFFF & x)
+#define ACDB_RTC_TX 0xF1
+#define ACDB_RTC_RX 0x1F
+
+
+static u32 acdb_audpp_entry[][4] = {
+
+ {
+ ABID_AUDIO_RTC_VOLUME_PAN_RX,\
+ IID_AUDIO_RTC_VOLUME_PAN_PARAMETERS,\
+ AUDPP_CMD_VOLUME_PAN,\
+ ACDB_RTC_RX
+ },
+ {
+ ABID_AUDIO_IIR_RX,\
+ IID_AUDIO_IIR_COEFF,\
+ AUDPP_CMD_IIR_TUNING_FILTER,
+ ACDB_RTC_RX
+ },
+ {
+ ABID_AUDIO_RTC_EQUALIZER_PARAMETERS,\
+ IID_AUDIO_RTC_EQUALIZER_PARAMETERS,\
+ AUDPP_CMD_EQUALIZER,\
+ ACDB_RTC_RX
+ },
+ {
+ ABID_AUDIO_RTC_SPA,\
+ IID_AUDIO_RTC_SPA_PARAMETERS,\
+ AUDPP_CMD_SPECTROGRAM,
+ ACDB_RTC_RX
+ },
+ {
+ ABID_AUDIO_STF_RX,\
+ IID_AUDIO_IIR_COEFF,\
+ AUDPP_CMD_SIDECHAIN_TUNING_FILTER,\
+ ACDB_RTC_RX
+ },
+ {
+ ABID_AUDIO_MBADRC_RX,\
+ IID_AUDIO_RTC_MBADRC_PARAMETERS,\
+ AUDPP_CMD_MBADRC,\
+ ACDB_RTC_RX
+ },
+ {
+ ABID_AUDIO_AGC_TX,\
+ IID_AUDIO_AGC_PARAMETERS,\
+ AUDPREPROC_CMD_CFG_AGC_PARAMS,\
+ ACDB_RTC_TX
+ },
+ {
+ ABID_AUDIO_AGC_TX,\
+ IID_AUDIO_RTC_AGC_PARAMETERS,\
+ AUDPREPROC_CMD_CFG_AGC_PARAMS,\
+ ACDB_RTC_TX
+ },
+ {
+ ABID_AUDIO_NS_TX,\
+ IID_NS_PARAMETERS,\
+ AUDPREPROC_CMD_CFG_NS_PARAMS,\
+ ACDB_RTC_TX
+ },
+ {
+ ABID_AUDIO_IIR_TX,\
+ IID_AUDIO_RTC_TX_IIR_COEFF,\
+ AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS,\
+ ACDB_RTC_TX
+ },
+ {
+ ABID_AUDIO_IIR_TX,\
+ IID_AUDIO_IIR_COEFF,\
+ AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS,\
+ ACDB_RTC_TX
+ }
+ /*Any new entries should be added here*/
+};
+
+static struct dentry *get_set_abid_dentry;
+static struct dentry *get_set_abid_data_dentry;
+
+struct rtc_acdb_pmem {
+ u8 *viraddr;
+ int32_t phys;
+ void *map_v_rtc;
+};
+
+struct rtc_acdb_data {
+ u32 acdb_id;
+ u32 cmd_id;
+ u32 set_abid;
+ u32 set_iid;
+ u32 abid;
+ u32 err;
+ bool valid_abid;
+ u32 tx_rx_ctl;
+ struct rtc_acdb_pmem rtc_read;
+ struct rtc_acdb_pmem rtc_write;
+ wait_queue_head_t wait;
+};
+
+struct get_abid {
+ u32 cmd_id;
+ u32 acdb_id;
+ u32 set_abid;
+ u32 set_iid;
+};
+
+struct acdb_block_mbadrc_rtc {
+ u16 enable;
+ u16 num_bands;
+ u16 down_samp_level;
+ u16 adrc_delay;
+ u16 ext_buf_size;
+ u16 ext_partition;
+ u16 ext_buf_msw;
+ u16 ext_buf_lsw;
+ struct adrc_config adrc_band[AUDPP_MAX_MBADRC_BANDS];
+ signed int ext_buff[196];
+} __packed;
+
+enum {
+ ACDB_RTC_SUCCESS,
+ ACDB_RTC_ERR_INVALID_DEVICE,
+ ACDB_RTC_ERR_DEVICE_INACTIVE,
+ ACDB_RTC_ERR_INVALID_ABID,
+ ACDB_RTC_DSP_FAILURE,
+ ACDB_RTC_DSP_FEATURE_NOT_AVAILABLE,
+ ACDB_RTC_ERR_INVALID_LEN,
+ ACDB_RTC_ERR_UNKNOWN_FAILURE,
+ ACDB_RTC_PENDING_RESPONSE,
+ ACDB_RTC_INIT_FAILURE,
+};
+
+static struct rtc_acdb_data rtc_acdb;
+
+static int rtc_getsetabid_dbg_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ MM_DBG("GET-SET ABID Open debug intf %s\n",\
+ (char *) file->private_data);
+ return 0;
+}
+
+static bool get_feature_id(u32 set_abid, u32 iid, unsigned short *feature_id)
+{
+ bool ret_value = false;
+ int i = 0;
+
+ for (; i < (sizeof(acdb_audpp_entry) / sizeof(acdb_audpp_entry[0]));\
+ i++) {
+ if (acdb_audpp_entry[i][0] == set_abid &&
+ acdb_audpp_entry[i][1] == iid) {
+ *feature_id = acdb_audpp_entry[i][2];
+ rtc_acdb.tx_rx_ctl = acdb_audpp_entry[i][3];
+ ret_value = true;
+ break;
+ }
+ }
+ return ret_value;
+}
+static ssize_t rtc_getsetabid_dbg_write(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct get_abid write_abid;
+ unsigned short feat_id = 0;
+ rtc_acdb.valid_abid = false;
+
+ if (copy_from_user(&write_abid, \
+ (void *)ubuf, sizeof(struct get_abid))) {
+ MM_ERR("ACDB DATA WRITE - INVALID READ LEN\n");
+ rtc_acdb.err = ACDB_RTC_ERR_INVALID_LEN;
+ return cnt;
+ }
+ MM_DBG("SET ABID : Cmd ID: %d Device:%d ABID:%d IID : %d cnt: %d\n",\
+ write_abid.cmd_id, write_abid.acdb_id,\
+ write_abid.set_abid, write_abid.set_iid, cnt);
+ if (write_abid.acdb_id > ACDB_ID_MAX ||
+ write_abid.acdb_id < ACDB_ID_HANDSET_SPKR){
+ rtc_acdb.err = ACDB_RTC_ERR_INVALID_DEVICE;
+ return cnt;
+ }
+
+ rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
+ rtc_acdb.abid = write_abid.set_abid;
+ if (get_feature_id(write_abid.set_abid, \
+ write_abid.set_iid, &feat_id)) {
+ rtc_acdb.err = ACDB_RTC_SUCCESS;
+ rtc_acdb.cmd_id = write_abid.cmd_id;
+ rtc_acdb.acdb_id = write_abid.acdb_id;
+ rtc_acdb.set_abid = feat_id;
+ rtc_acdb.valid_abid = true;
+ rtc_acdb.set_iid = write_abid.set_iid;
+ }
+ return cnt;
+}
+static ssize_t rtc_getsetabid_dbg_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ static char buffer[1024];
+ int n = 0;
+ u32 msg = rtc_acdb.err;
+ memcpy(buffer, &rtc_acdb.cmd_id, sizeof(struct get_abid));
+ memcpy(buffer+16, &msg, 4);
+ n = 20;
+ MM_INFO("SET ABID : Cmd ID: %x Device:%x ABID:%x IID : %x Err: %d\n",\
+ rtc_acdb.cmd_id, rtc_acdb.acdb_id, rtc_acdb.set_abid,\
+ rtc_acdb.set_iid, rtc_acdb.err);
+ return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static int rtc_getsetabid_data_dbg_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ MM_INFO("GET-SET ABID DATA Open debug intf %s\n",
+ (char *) file->private_data);
+ return 0;
+}
+
+void acdb_rtc_set_err(u32 err_code)
+{
+ if (rtc_acdb.err == ACDB_RTC_PENDING_RESPONSE) {
+ if (err_code == 0xFFFF) {
+ rtc_acdb.err = ACDB_RTC_SUCCESS;
+ MM_INFO("RTC READ SUCCESS---\n");
+ } else if (err_code == 0) {
+ rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
+ MM_INFO("RTC READ FAIL---\n");
+ } else if (err_code == 1) {
+ rtc_acdb.err = ACDB_RTC_DSP_FEATURE_NOT_AVAILABLE;
+ MM_INFO("RTC READ FEAT UNAVAILABLE---\n");
+ } else {
+ rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
+ MM_INFO("RTC Err CODE---\n");
+ }
+ } else {
+ rtc_acdb.err = ACDB_RTC_DSP_FAILURE;
+ MM_ERR("RTC Err code Invalid State\n");
+ }
+ wake_up(&rtc_acdb.wait);
+}
+
+static ssize_t rtc_getsetabid_data_dbg_read(struct file *file,
+ char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ static char buffer[PMEM_RTC_ACDB_QUERY_MEM];
+ int rc, n = 0;
+ int counter = 0;
+ struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
+ memset(&buffer, 0, PMEM_RTC_ACDB_QUERY_MEM);
+
+ if (rtc_acdb.valid_abid != true) {
+ MM_ERR("ACDB DATA READ ---INVALID ABID\n");
+ n = 0;
+ rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
+ } else {
+ if (PMEM_RTC_ACDB_QUERY_MEM < count) {
+ MM_ERR("ACDB DATA READ ---"\
+ "INVALID READ LEN %x\n", count);
+ n = 0;
+ rtc_acdb.err = ACDB_RTC_ERR_INVALID_LEN;
+ } else {
+ rtc_acdb.err = ACDB_RTC_PENDING_RESPONSE;
+ if (rtc_read->viraddr != NULL) {
+ memset(rtc_read->viraddr,
+ 0, PMEM_RTC_ACDB_QUERY_MEM);
+ }
+ if (rtc_acdb.tx_rx_ctl == ACDB_RTC_RX) {
+ struct rtc_audpp_read_data rtc_read_cmd;
+ rtc_read_cmd.cmd_id =
+ AUDPP_CMD_PP_FEAT_QUERY_PARAMS;
+ rtc_read_cmd.obj_id =
+ AUDPP_CMD_COPP_STREAM;
+ rtc_read_cmd.feature_id = rtc_acdb.set_abid;
+ rtc_read_cmd.extbufsizemsw =
+ EXTRACT_HIGH_WORD(\
+ PMEM_RTC_ACDB_QUERY_MEM);
+ rtc_read_cmd.extbufsizelsw =
+ EXTRACT_LOW_WORD(\
+ PMEM_RTC_ACDB_QUERY_MEM);
+ rtc_read_cmd.extpart = 0x0000;
+ rtc_read_cmd.extbufstartmsw =
+ EXTRACT_HIGH_WORD(rtc_read->phys);
+ rtc_read_cmd.extbufstartlsw =
+ EXTRACT_LOW_WORD(rtc_read->phys);
+ rc = audpp_send_queue2(&rtc_read_cmd,
+ sizeof(rtc_read_cmd));
+ } else if (rtc_acdb.tx_rx_ctl == ACDB_RTC_TX) {
+ struct rtc_audpreproc_read_data rtc_audpreproc;
+ rtc_audpreproc.cmd_id =
+ AUDPREPROC_CMD_FEAT_QUERY_PARAMS;
+ rtc_audpreproc.feature_id = rtc_acdb.set_abid;
+ /*AUDREC1 is used for pcm recording */
+ rtc_audpreproc.stream_id = 1;
+ rtc_audpreproc.extbufsizemsw =
+ EXTRACT_HIGH_WORD(\
+ PMEM_RTC_ACDB_QUERY_MEM);
+ rtc_audpreproc.extbufsizelsw =
+ EXTRACT_LOW_WORD(\
+ PMEM_RTC_ACDB_QUERY_MEM);
+ rtc_audpreproc.extpart = 0x0000;
+ rtc_audpreproc.extbufstartmsw =
+ EXTRACT_HIGH_WORD(rtc_read->phys);
+ rtc_audpreproc.extbufstartlsw =
+ EXTRACT_LOW_WORD(rtc_read->phys);
+ rc = audpreproc_send_preproccmdqueue(
+ &rtc_audpreproc,\
+ sizeof(rtc_audpreproc));
+ MM_INFO("ACDB READ Command RC --->%x,"\
+ "stream_id %x\n", rc,
+ acdb_data.preproc_stream_id);
+ }
+ rc = wait_event_timeout(rtc_acdb.wait,
+ (rtc_acdb.err !=
+ ACDB_RTC_PENDING_RESPONSE),
+ msecs_to_jiffies(RTC_MAX_TIMEOUT));
+ MM_INFO("ACDB READ ACK Count = %x Err = %x\n",
+ count, rtc_acdb.err);
+ {
+ if (rtc_acdb.err == ACDB_RTC_SUCCESS
+ && rtc_read->viraddr != NULL) {
+ memcpy(buffer, rtc_read->viraddr, count);
+ n = count;
+ while (counter < count) {
+ MM_DBG("%x", \
+ rtc_read->viraddr[counter]);
+ counter++;
+ }
+ }
+ }
+ }
+ }
+ return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static bool acdb_set_tx_rtc(const char *ubuf, size_t writecount)
+{
+ audpreproc_cmd_cfg_iir_tuning_filter_params *preproc_iir;
+ audpreproc_cmd_cfg_agc_params *preproc_agc;
+ audpreproc_cmd_cfg_ns_params *preproc_ns;
+ s32 result = 0;
+ bool retval = false;
+ unsigned short iircmdsize =
+ sizeof(audpreproc_cmd_cfg_iir_tuning_filter_params);
+ unsigned short iircmdid = AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+
+ rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
+
+ switch (rtc_acdb.set_abid) {
+
+ case AUDPREPROC_CMD_CFG_AGC_PARAMS:
+ {
+ preproc_agc = kmalloc(sizeof(\
+ audpreproc_cmd_cfg_agc_params),\
+ GFP_KERNEL);
+ if ((sizeof(audpreproc_cmd_cfg_agc_params) -\
+ (sizeof(unsigned short)))
+ < writecount) {
+ MM_ERR("ACDB DATA WRITE --"\
+ "AGC TX writecount > DSP struct\n");
+ } else {
+ if (preproc_agc != NULL) {
+ char *base; unsigned short offset;
+ unsigned short *offset_addr;
+ base = (char *)preproc_agc;
+ offset = offsetof(\
+ audpreproc_cmd_cfg_agc_params,\
+ tx_agc_param_mask);
+ offset_addr = (unsigned short *)(base + offset);
+ if ((copy_from_user(offset_addr,\
+ (void *)ubuf, writecount)) == 0x00) {
+ preproc_agc->cmd_id =
+ AUDPREPROC_CMD_CFG_AGC_PARAMS;
+
+ result = audpreproc_dsp_set_agc(
+ preproc_agc,
+ sizeof(\
+ audpreproc_cmd_cfg_agc_params));
+ if (result) {
+ MM_ERR("ACDB=> Failed to "\
+ "send AGC data to "\
+ "preproc)\n");
+ } else {
+ retval = true;
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE ---"\
+ "GC Tx copy_from_user Fail\n");
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE --"\
+ "AGC TX kalloc Failed LEN\n");
+ }
+ }
+ if (preproc_agc != NULL)
+ kfree(preproc_agc);
+ break;
+ }
+ case AUDPREPROC_CMD_CFG_NS_PARAMS:
+ {
+
+ preproc_ns = kmalloc(sizeof(\
+ audpreproc_cmd_cfg_ns_params),\
+ GFP_KERNEL);
+ if ((sizeof(audpreproc_cmd_cfg_ns_params) -\
+ (sizeof(unsigned short)))
+ < writecount) {
+ MM_ERR("ACDB DATA WRITE --"\
+ "NS TX writecount > DSP struct\n");
+ } else {
+ if (preproc_ns != NULL) {
+ char *base; unsigned short offset;
+ unsigned short *offset_addr;
+ base = (char *)preproc_ns;
+ offset = offsetof(\
+ audpreproc_cmd_cfg_ns_params,\
+ ec_mode_new);
+ offset_addr = (unsigned short *)(base + offset);
+ if ((copy_from_user(offset_addr,\
+ (void *)ubuf, writecount)) == 0x00) {
+ preproc_ns->cmd_id =
+ AUDPREPROC_CMD_CFG_NS_PARAMS;
+ result = audpreproc_dsp_set_ns(
+ preproc_ns,
+ sizeof(\
+ audpreproc_cmd_cfg_ns_params));
+ if (result) {
+ MM_ERR("ACDB=> Failed to send "\
+ "NS data to preproc\n");
+ } else {
+ retval = true;
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE ---NS Tx "\
+ "copy_from_user Fail\n");
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE --NS TX "\
+ "kalloc Failed LEN\n");
+ }
+ }
+ if (preproc_ns != NULL)
+ kfree(preproc_ns);
+ break;
+ }
+ case AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS:
+ {
+
+ preproc_iir = kmalloc(sizeof(\
+ audpreproc_cmd_cfg_iir_tuning_filter_params),\
+ GFP_KERNEL);
+ if ((sizeof(\
+ audpreproc_cmd_cfg_iir_tuning_filter_params)-\
+ (sizeof(unsigned short)))
+ < writecount) {
+ MM_ERR("ACDB DATA WRITE --IIR TX writecount "\
+ "> DSP struct\n");
+ } else {
+ if (preproc_iir != NULL) {
+ char *base; unsigned short offset;
+ unsigned short *offset_addr;
+ base = (char *)preproc_iir;
+ offset = offsetof(\
+ audpreproc_cmd_cfg_iir_tuning_filter_params,\
+ active_flag);
+ offset_addr = (unsigned short *)(base + \
+ offset);
+ if ((copy_from_user(offset_addr,\
+ (void *)ubuf, writecount)) == 0x00) {
+ preproc_iir->cmd_id = iircmdid;
+ result = audpreproc_dsp_set_iir(\
+ preproc_iir,
+ iircmdsize);
+ if (result) {
+ MM_ERR("ACDB=> Failed to send "\
+ "IIR data to preproc\n");
+ } else {
+ retval = true;
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE ---IIR Tx "\
+ "copy_from_user Fail\n");
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE --IIR TX kalloc "\
+ "Failed LEN\n");
+ }
+ }
+ if (preproc_iir != NULL)
+ kfree(preproc_iir);
+ break;
+ }
+ }
+ return retval;
+}
+
+static bool acdb_set_rx_rtc(const char *ubuf, size_t writecount)
+{
+
+ audpp_cmd_cfg_object_params_volume *volpan_config;
+ audpp_cmd_cfg_object_params_mbadrc *mbadrc_config;
+ struct acdb_block_mbadrc_rtc *acdb_mbadrc_rtc;
+ audpp_cmd_cfg_object_params_eqalizer *eq_config;
+ audpp_cmd_cfg_object_params_pcm *iir_config;
+ struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
+ s32 result = 0;
+ bool retval = false;
+
+ switch (rtc_acdb.set_abid) {
+ case AUDPP_CMD_VOLUME_PAN:
+ {
+ volpan_config = kmalloc(sizeof(\
+ audpp_cmd_cfg_object_params_volume),\
+ GFP_KERNEL);
+ if ((sizeof(audpp_cmd_cfg_object_params_volume) -\
+ sizeof(audpp_cmd_cfg_object_params_common))
+ < writecount) {
+ MM_ERR("ACDB DATA WRITE -- "\
+ "VolPan writecount > DSP struct\n");
+ } else {
+ if (volpan_config != NULL) {
+ char *base; unsigned short offset;
+ unsigned short *offset_addr;
+ base = (char *)volpan_config;
+ offset = offsetof(\
+ audpp_cmd_cfg_object_params_volume,\
+ volume);
+ offset_addr = (unsigned short *)(base+offset);
+ if ((copy_from_user(offset_addr,\
+ (void *)ubuf, writecount)) == 0x00) {
+ MM_ERR("ACDB RX WRITE DATA: "\
+ "AUDPP_CMD_VOLUME_PAN\n");
+ result = audpp_set_volume_and_pan(
+ COMMON_OBJ_ID,
+ volpan_config->volume,
+ volpan_config->pan);
+ if (result) {
+ MM_ERR("ACDB=> Failed to "\
+ "send VOLPAN data to"
+ " postproc\n");
+ } else {
+ retval = true;
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE ---"\
+ "copy_from_user Fail\n");
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE --"\
+ "Vol Pan kalloc Failed LEN\n");
+ }
+ }
+ if (volpan_config != NULL)
+ kfree(volpan_config);
+ break;
+ }
+
+ case AUDPP_CMD_IIR_TUNING_FILTER:
+ {
+ iir_config = kmalloc(sizeof(\
+ audpp_cmd_cfg_object_params_pcm),\
+ GFP_KERNEL);
+ if ((sizeof(audpp_cmd_cfg_object_params_pcm) -\
+ sizeof(audpp_cmd_cfg_object_params_common))
+ < writecount) {
+ MM_ERR("ACDB DATA WRITE --"\
+ "IIR RX writecount > DSP struct\n");
+ } else {
+ if (iir_config != NULL) {
+ char *base; unsigned short offset;
+ unsigned short *offset_addr;
+ base = (char *)iir_config;
+ offset = offsetof(\
+ audpp_cmd_cfg_object_params_pcm,\
+ active_flag);
+ offset_addr = (unsigned short *)(base+offset);
+ if ((copy_from_user(offset_addr,\
+ (void *)ubuf, writecount)) == 0x00) {
+ MM_ERR("ACDB RX WRITE DATA:"\
+ "AUDPP_CMD_IIR_TUNING_FILTER\n");
+ result = audpp_dsp_set_rx_iir(
+ COMMON_OBJ_ID,
+ iir_config->active_flag,\
+ iir_config);
+ if (result) {
+ MM_ERR("ACDB=> Failed to send"\
+ "IIR data to"\
+ "postproc\n");
+ } else {
+ retval = true;
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE ---"\
+ "IIR Rx copy_from_user Fail\n");
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE --"\
+ "acdb_iir_block kalloc Failed LEN\n");
+ }
+ }
+ if (iir_config != NULL)
+ kfree(iir_config);
+ break;
+ }
+ case AUDPP_CMD_EQUALIZER:
+ {
+ eq_config = kmalloc(sizeof(\
+ audpp_cmd_cfg_object_params_eqalizer),\
+ GFP_KERNEL);
+ if ((sizeof(audpp_cmd_cfg_object_params_eqalizer) -\
+ sizeof(audpp_cmd_cfg_object_params_common))
+ < writecount) {
+ MM_ERR("ACDB DATA WRITE --"\
+ "EQ RX writecount > DSP struct\n");
+ } else {
+ if (eq_config != NULL) {
+ char *base; unsigned short offset;
+ unsigned short *offset_addr;
+ base = (char *)eq_config;
+ offset = offsetof(\
+ audpp_cmd_cfg_object_params_eqalizer,\
+ eq_flag);
+ offset_addr = (unsigned short *)(base+offset);
+ if ((copy_from_user(offset_addr,\
+ (void *)ubuf, writecount)) == 0x00) {
+ MM_ERR("ACDB RX WRITE"\
+ "DATA:AUDPP_CMD_EQUALIZER\n");
+ result = audpp_dsp_set_eq(
+ COMMON_OBJ_ID,
+ eq_config->eq_flag,\
+ eq_config);
+ if (result) {
+ MM_ERR("ACDB=> Failed to "\
+ "send EQ data to postproc\n");
+ } else {
+ retval = true;
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE ---"\
+ "EQ Rx copy_from_user Fail\n");
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE --"\
+ "EQ kalloc Failed LEN\n");
+ }
+ }
+ if (eq_config != NULL)
+ kfree(eq_config);
+ break;
+ }
+
+ case AUDPP_CMD_MBADRC:
+ {
+ acdb_mbadrc_rtc = kmalloc(sizeof(struct \
+ acdb_block_mbadrc_rtc),\
+ GFP_KERNEL);
+ mbadrc_config = kmalloc(sizeof(\
+ audpp_cmd_cfg_object_params_mbadrc),\
+ GFP_KERNEL);
+ if (mbadrc_config != NULL && acdb_mbadrc_rtc != NULL) {
+ if ((copy_from_user(acdb_mbadrc_rtc,\
+ (void *)ubuf,
+ sizeof(struct acdb_block_mbadrc_rtc)))
+ == 0x00) {
+
+ memset(mbadrc_config, 0,
+ sizeof(\
+ audpp_cmd_cfg_object_params_mbadrc));
+
+ mbadrc_config->enable =
+ acdb_mbadrc_rtc->enable;
+ mbadrc_config->num_bands =
+ acdb_mbadrc_rtc->num_bands;
+ mbadrc_config->down_samp_level =
+ acdb_mbadrc_rtc->down_samp_level;
+ mbadrc_config->adrc_delay =
+ acdb_mbadrc_rtc->adrc_delay;
+ memcpy(mbadrc_config->adrc_band,\
+ acdb_mbadrc_rtc->adrc_band,\
+ AUDPP_MAX_MBADRC_BANDS *\
+ sizeof(struct adrc_config));
+ if (mbadrc_config->num_bands > 1) {
+ mbadrc_config->ext_buf_size =
+ (97 * 2) + (33 * 2 * \
+ (mbadrc_config->num_bands - 2));
+ }
+ mbadrc_config->ext_partition = 0;
+ mbadrc_config->ext_buf_lsw =
+ (u16) EXTRACT_LOW_WORD(\
+ rtc_write->phys);
+ mbadrc_config->ext_buf_msw =
+ (u16) EXTRACT_HIGH_WORD(\
+ rtc_write->phys);
+ memcpy(rtc_write->viraddr,
+ acdb_mbadrc_rtc->ext_buff,
+ (196*sizeof(signed int)));
+ result = audpp_dsp_set_mbadrc(
+ COMMON_OBJ_ID,
+ mbadrc_config->enable,
+ mbadrc_config);
+ if (result) {
+ MM_ERR("ACDB=> Failed to "\
+ "Send MBADRC data "\
+ "to postproc\n");
+ } else {
+ retval = true;
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE ---"\
+ "MBADRC Rx copy_from_user Fail\n");
+ }
+ } else {
+ MM_ERR("ACDB DATA WRITE --MBADRC kalloc Failed LEN\n");
+ }
+ if (mbadrc_config != NULL)
+ kfree(mbadrc_config);
+ if (acdb_mbadrc_rtc != NULL)
+ kfree(acdb_mbadrc_rtc);
+ break;
+ }
+ }
+ return retval;
+}
+static ssize_t rtc_getsetabid_data_dbg_write(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ if (rtc_acdb.valid_abid != true) {
+ MM_INFO("ACDB DATA READ ---INVALID ABID\n");
+ rtc_acdb.err = ACDB_RTC_ERR_INVALID_ABID;
+ } else {
+ if (rtc_acdb.tx_rx_ctl == ACDB_RTC_RX) {
+ if (acdb_set_rx_rtc(ubuf, cnt)) {
+ rtc_acdb.err = ACDB_RTC_SUCCESS;
+ } else {
+ rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
+ cnt = 0;
+ }
+ } else if (rtc_acdb.tx_rx_ctl == ACDB_RTC_TX) {
+ if (acdb_set_tx_rtc(ubuf, cnt)) {
+ rtc_acdb.err = ACDB_RTC_SUCCESS;
+ } else {
+ rtc_acdb.err = ACDB_RTC_ERR_UNKNOWN_FAILURE;
+ cnt = 0;
+ }
+ }
+ }
+ return cnt;
+}
+
+
+static const struct file_operations rtc_acdb_data_debug_fops = {
+ .open = rtc_getsetabid_data_dbg_open,
+ .write = rtc_getsetabid_data_dbg_write,
+ .read = rtc_getsetabid_data_dbg_read
+};
+
+static const struct file_operations rtc_acdb_debug_fops = {
+ .open = rtc_getsetabid_dbg_open,
+ .write = rtc_getsetabid_dbg_write,
+ .read = rtc_getsetabid_dbg_read
+};
+
+static void rtc_acdb_deinit(void)
+{
+ struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
+ struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
+ if (get_set_abid_dentry) {
+ MM_DBG("GetSet ABID remove debugfs\n");
+ debugfs_remove(get_set_abid_dentry);
+ }
+
+ if (get_set_abid_data_dentry) {
+ MM_DBG("GetSet ABID remove debugfs\n");
+ debugfs_remove(get_set_abid_data_dentry);
+ }
+ rtc_acdb.abid = 0;
+ rtc_acdb.acdb_id = 0;
+ rtc_acdb.cmd_id = 0;
+ rtc_acdb.err = 1;
+ rtc_acdb.set_abid = 0;
+ rtc_acdb.set_iid = 0;
+ rtc_acdb.tx_rx_ctl = 0;
+ rtc_acdb.valid_abid = false;
+
+ if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
+ iounmap(rtc_read->map_v_rtc);
+ free_contiguous_memory_by_paddr(rtc_read->phys);
+ }
+ if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
+ iounmap(rtc_write->map_v_rtc);
+ free_contiguous_memory_by_paddr(rtc_write->phys);
+ }
+}
+
+static bool rtc_acdb_init(void)
+{
+ struct rtc_acdb_pmem *rtc_read = &rtc_acdb.rtc_read;
+ struct rtc_acdb_pmem *rtc_write = &rtc_acdb.rtc_write;
+ s32 result = 0;
+ char name[sizeof "get_set_abid"+1];
+ char name1[sizeof "get_set_abid_data"+1];
+ rtc_acdb.abid = 0;
+ rtc_acdb.acdb_id = 0;
+ rtc_acdb.cmd_id = 0;
+ rtc_acdb.err = 1;
+ rtc_acdb.set_abid = 0;
+ rtc_acdb.set_iid = 0;
+ rtc_acdb.valid_abid = false;
+ rtc_acdb.tx_rx_ctl = 0;
+
+ snprintf(name, sizeof name, "get_set_abid");
+ get_set_abid_dentry = debugfs_create_file(name,
+ S_IFREG | S_IRUGO | S_IWUGO,
+ NULL, NULL, &rtc_acdb_debug_fops);
+ if (IS_ERR(get_set_abid_dentry)) {
+ MM_ERR("SET GET ABID debugfs_create_file failed\n");
+ return false;
+ }
+
+ snprintf(name1, sizeof name1, "get_set_abid_data");
+ get_set_abid_data_dentry = debugfs_create_file(name1,
+ S_IFREG | S_IRUGO | S_IWUGO,
+ NULL, NULL,
+ &rtc_acdb_data_debug_fops);
+ if (IS_ERR(get_set_abid_data_dentry)) {
+ MM_ERR("SET GET ABID DATA"\
+ " debugfs_create_file failed\n");
+ return false;
+ }
+
+ rtc_read->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
+ SZ_4K);
+
+ if (!rtc_read->phys) {
+ MM_ERR("ACDB Cannot allocate physical memory\n");
+ result = -ENOMEM;
+ goto error;
+ }
+ rtc_read->map_v_rtc = ioremap(rtc_read->phys,
+ PMEM_RTC_ACDB_QUERY_MEM);
+
+ if (IS_ERR(rtc_read->map_v_rtc)) {
+ MM_ERR("ACDB Could not map physical address\n");
+ result = -ENOMEM;
+ goto error;
+ }
+ rtc_read->viraddr = rtc_read->map_v_rtc;
+ memset(rtc_read->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
+
+ rtc_write->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
+ SZ_4K);
+
+ if (!rtc_write->phys) {
+ MM_ERR("ACDB Cannot allocate physical memory\n");
+ result = -ENOMEM;
+ goto error;
+ }
+ rtc_write->map_v_rtc = ioremap(rtc_write->phys,
+ PMEM_RTC_ACDB_QUERY_MEM);
+
+ if (IS_ERR(rtc_write->map_v_rtc)) {
+ MM_ERR("ACDB Could not map physical address\n");
+ result = -ENOMEM;
+ goto error;
+ }
+ rtc_write->viraddr = rtc_write->map_v_rtc;
+ memset(rtc_write->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
+ init_waitqueue_head(&rtc_acdb.wait);
+ return true;
+error:
+ MM_DBG("INIT RTC FAILED REMOVING RTC DEBUG FS\n");
+ if (get_set_abid_dentry) {
+ MM_DBG("GetSet ABID remove debugfs\n");
+ debugfs_remove(get_set_abid_dentry);
+ }
+
+ if (get_set_abid_data_dentry) {
+ MM_DBG("GetSet ABID remove debugfs\n");
+ debugfs_remove(get_set_abid_data_dentry);
+ }
+ if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
+ iounmap(rtc_read->map_v_rtc);
+ free_contiguous_memory_by_paddr(rtc_read->phys);
+ }
+ if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
+ iounmap(rtc_write->map_v_rtc);
+ free_contiguous_memory_by_paddr(rtc_write->phys);
+ }
+ return false;
+}
+#else
+void acdb_rtc_set_err(u32 err_code)
+{
+ return 0
+}
+#endif /*CONFIG_DEBUG_FS*/
+static s32 acdb_set_calibration_blk(unsigned long arg)
+{
+ struct acdb_cmd_device acdb_cmd;
+ s32 result = 0;
+
+ MM_DBG("acdb_set_calibration_blk\n");
+ if (copy_from_user(&acdb_cmd, (struct acdb_cmd_device *)arg,
+ sizeof(acdb_cmd))) {
+ MM_ERR("Failed copy command struct from user in"\
+ "acdb_set_calibration_blk\n");
+ return -EFAULT;
+ }
+ acdb_cmd.phys_buf = (u32 *)acdb_data.paddr;
+
+ MM_DBG("acdb_cmd.phys_buf %x\n", (u32)acdb_cmd.phys_buf);
+
+ result = dalrpc_fcn_8(ACDB_DAL_IOCTL, acdb_data.handle,
+ (const void *)&acdb_cmd, sizeof(acdb_cmd),
+ &acdb_data.acdb_result,
+ sizeof(acdb_data.acdb_result));
+
+ if (result < 0) {
+ MM_ERR("ACDB=> Device Set RPC failure"\
+ " result = %d\n", result);
+ return -EINVAL;
+ } else {
+ MM_ERR("ACDB=> Device Set RPC success\n");
+ if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS)
+ MM_DBG("ACDB_SET_DEVICE Success\n");
+ else if (acdb_data.acdb_result.result == ACDB_RES_FAILURE)
+ MM_ERR("ACDB_SET_DEVICE Failure\n");
+ else if (acdb_data.acdb_result.result == ACDB_RES_BADPARM)
+ MM_ERR("ACDB_SET_DEVICE BadParams\n");
+ else
+ MM_ERR("Unknown error\n");
+ }
+ return result;
+}
+
+static s32 acdb_get_calibration_blk(unsigned long arg)
+{
+ s32 result = 0;
+ struct acdb_cmd_device acdb_cmd;
+
+ MM_DBG("acdb_get_calibration_blk\n");
+
+ if (copy_from_user(&acdb_cmd, (struct acdb_cmd_device *)arg,
+ sizeof(acdb_cmd))) {
+ MM_ERR("Failed copy command struct from user in"\
+ "acdb_get_calibration_blk\n");
+ return -EFAULT;
+ }
+ acdb_cmd.phys_buf = (u32 *)acdb_data.paddr;
+ MM_ERR("acdb_cmd.phys_buf %x\n", (u32)acdb_cmd.phys_buf);
+
+ result = dalrpc_fcn_8(ACDB_DAL_IOCTL, acdb_data.handle,
+ (const void *)&acdb_cmd, sizeof(acdb_cmd),
+ &acdb_data.acdb_result,
+ sizeof(acdb_data.acdb_result));
+
+ if (result < 0) {
+ MM_ERR("ACDB=> Device Get RPC failure"\
+ " result = %d\n", result);
+ return -EINVAL;
+ } else {
+ MM_ERR("ACDB=> Device Get RPC Success\n");
+ if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS)
+ MM_DBG("ACDB_GET_DEVICE Success\n");
+ else if (acdb_data.acdb_result.result == ACDB_RES_FAILURE)
+ MM_ERR("ACDB_GET_DEVICE Failure\n");
+ else if (acdb_data.acdb_result.result == ACDB_RES_BADPARM)
+ MM_ERR("ACDB_GET_DEVICE BadParams\n");
+ else
+ MM_ERR("Unknown error\n");
+ }
+ return result;
+}
+
+static int audio_acdb_open(struct inode *inode, struct file *file)
+{
+ MM_DBG("%s\n", __func__);
+ return 0;
+}
+static int audio_acdb_release(struct inode *inode, struct file *file)
+{
+ MM_DBG("%s\n", __func__);
+ return 0;
+}
+
+static long audio_acdb_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc = 0;
+ unsigned long flags = 0;
+ struct msm_audio_pmem_info info;
+
+ MM_DBG("%s\n", __func__);
+
+ switch (cmd) {
+ case AUDIO_SET_EQ:
+ MM_DBG("IOCTL SET_EQ_CONFIG\n");
+ if (copy_from_user(&acdb_data.eq.num_bands, (void *) arg,
+ sizeof(acdb_data.eq) -
+ (AUDPP_CMD_CFG_OBJECT_PARAMS_COMMON_LEN + 2))) {
+ rc = -EFAULT;
+ break;
+ }
+ spin_lock_irqsave(&acdb_data.dsp_lock, flags);
+ rc = audpp_dsp_set_eq(COMMON_OBJ_ID, 1,
+ &acdb_data.eq);
+ if (rc < 0)
+ MM_ERR("AUDPP returned err =%d\n", rc);
+ spin_unlock_irqrestore(&acdb_data.dsp_lock, flags);
+ break;
+ case AUDIO_REGISTER_PMEM:
+ MM_DBG("AUDIO_REGISTER_PMEM\n");
+ if (copy_from_user(&info, (void *) arg, sizeof(info))) {
+ MM_ERR("Cannot copy from user\n");
+ return -EFAULT;
+ }
+ rc = get_pmem_file(info.fd, &acdb_data.paddr,
+ &acdb_data.kvaddr,
+ &acdb_data.pmem_len,
+ &acdb_data.file);
+ if (rc == 0)
+ acdb_data.pmem_fd = info.fd;
+ break;
+ case AUDIO_DEREGISTER_PMEM:
+ if (acdb_data.pmem_fd)
+ put_pmem_file(acdb_data.file);
+ break;
+ case AUDIO_SET_ACDB_BLK:
+ MM_DBG("IOCTL AUDIO_SET_ACDB_BLK\n");
+ rc = acdb_set_calibration_blk(arg);
+ break;
+ case AUDIO_GET_ACDB_BLK:
+ MM_DBG("IOiCTL AUDIO_GET_ACDB_BLK\n");
+ rc = acdb_get_calibration_blk(arg);
+ break;
+ default:
+ MM_DBG("Unknown IOCTL%d\n", cmd);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static const struct file_operations acdb_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_acdb_open,
+ .release = audio_acdb_release,
+ .llseek = no_llseek,
+ .unlocked_ioctl = audio_acdb_ioctl
+};
+
+struct miscdevice acdb_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_acdb",
+ .fops = &acdb_fops,
+};
+
+static s32 acdb_get_calibration(void)
+{
+ struct acdb_cmd_get_device_table acdb_cmd;
+ s32 result = 0;
+ u32 iterations = 0;
+
+ MM_DBG("acdb state = %d\n", acdb_data.acdb_state);
+
+ acdb_cmd.command_id = ACDB_GET_DEVICE_TABLE;
+ acdb_cmd.device_id = acdb_data.device_info->acdb_id;
+ acdb_cmd.network_id = 0x0108B153;
+ acdb_cmd.sample_rate_id = acdb_data.device_info->sample_rate;
+ acdb_cmd.total_bytes = ACDB_BUF_SIZE;
+ acdb_cmd.phys_buf = (u32 *)acdb_data.phys_addr;
+ MM_DBG("device_id = %d, sampling_freq = %d\n",
+ acdb_cmd.device_id, acdb_cmd.sample_rate_id);
+
+ do {
+ result = dalrpc_fcn_8(ACDB_DAL_IOCTL, acdb_data.handle,
+ (const void *)&acdb_cmd, sizeof(acdb_cmd),
+ &acdb_data.acdb_result,
+ sizeof(acdb_data.acdb_result));
+
+ if (result < 0) {
+ MM_ERR("ACDB=> Device table RPC failure"\
+ " result = %d\n", result);
+ goto error;
+ }
+ /*following check is introduced to handle boot up race
+ condition between AUDCAL SW peers running on apps
+ and modem (ACDB_RES_BADSTATE indicates modem AUDCAL SW is
+ not in initialized sate) we need to retry to get ACDB
+ values*/
+ if (acdb_data.acdb_result.result == ACDB_RES_BADSTATE) {
+ msleep(500);
+ iterations++;
+ } else if (acdb_data.acdb_result.result == ACDB_RES_SUCCESS) {
+ MM_DBG("Modem query for acdb values is successful"\
+ " (iterations = %d)\n", iterations);
+ acdb_data.acdb_state |= CAL_DATA_READY;
+ return result;
+ } else {
+ MM_ERR("ACDB=> modem failed to fill acdb values,"\
+ " reuslt = %d, (iterations = %d)\n",
+ acdb_data.acdb_result.result,
+ iterations);
+ goto error;
+ }
+ } while (iterations < MAX_RETRY);
+ MM_ERR("ACDB=> AUDCAL SW on modem is not in intiailized state (%d)\n",
+ acdb_data.acdb_result.result);
+error:
+ result = -EINVAL;
+ return result;
+}
+
+s32 acdb_get_calibration_data(struct acdb_get_block *get_block)
+{
+ s32 result = -EINVAL;
+ struct acdb_cmd_device acdb_cmd;
+ struct acdb_result acdb_result;
+
+ MM_DBG("acdb_get_calibration_data\n");
+
+ acdb_cmd.command_id = ACDB_GET_DEVICE;
+ acdb_cmd.network_id = 0x0108B153;
+ acdb_cmd.device_id = get_block->acdb_id;
+ acdb_cmd.sample_rate_id = get_block->sample_rate_id;
+ acdb_cmd.interface_id = get_block->interface_id;
+ acdb_cmd.algorithm_block_id = get_block->algorithm_block_id;
+ acdb_cmd.total_bytes = get_block->total_bytes;
+ acdb_cmd.phys_buf = (u32 *)acdb_data.get_blk_paddr;
+
+ result = dalrpc_fcn_8(ACDB_DAL_IOCTL, acdb_data.handle,
+ (const void *)&acdb_cmd, sizeof(acdb_cmd),
+ &acdb_result,
+ sizeof(acdb_result));
+
+ if (result < 0) {
+ MM_ERR("ACDB=> Device Get RPC failure"\
+ " result = %d\n", result);
+ goto err_state;
+ } else {
+ MM_DBG("ACDB=> Device Get RPC Success\n");
+ if (acdb_result.result == ACDB_RES_SUCCESS) {
+ MM_DBG("ACDB_GET_DEVICE Success\n");
+ result = 0;
+ memcpy(get_block->buf_ptr, acdb_data.get_blk_kvaddr,
+ get_block->total_bytes);
+ } else if (acdb_result.result == ACDB_RES_FAILURE)
+ MM_ERR("ACDB_GET_DEVICE Failure\n");
+ else if (acdb_result.result == ACDB_RES_BADPARM)
+ MM_ERR("ACDB_GET_DEVICE BadParams\n");
+ else
+ MM_ERR("Unknown error\n");
+ }
+err_state:
+ return result;
+}
+EXPORT_SYMBOL(acdb_get_calibration_data);
+
+static u8 check_device_info_already_present(
+ struct dev_evt_msg device_info,
+ struct acdb_cache_node *acdb_cache_free_node)
+{
+ if ((device_info.sample_rate ==
+ acdb_cache_free_node->device_info.\
+ sample_rate) &&
+ (device_info.acdb_id ==
+ acdb_cache_free_node->device_info.acdb_id)) {
+ MM_DBG("acdb values are already present\n");
+ /*if acdb state is not set for CAL_DATA_READY and node status
+ is filled, acdb state should be updated with CAL_DATA_READY
+ state*/
+ acdb_data.acdb_state |= CAL_DATA_READY;
+ return 1; /*node is present but status as filled*/
+ }
+ MM_DBG("copying device info into node\n");
+ /*as device information is not present in cache copy
+ the current device information into the node*/
+ memcpy(&acdb_cache_free_node->device_info,
+ &device_info, sizeof(device_info));
+ return 0; /*cant find the node*/
+}
+
+static struct acdb_iir_block *get_audpp_irr_block(void)
+{
+ struct header *prs_hdr;
+ u32 index = 0;
+
+ while (index < acdb_data.acdb_result.used_bytes) {
+ prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+ if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+ if (prs_hdr->abid == ABID_AUDIO_IIR_RX) {
+ if (prs_hdr->iid == IID_AUDIO_IIR_COEFF)
+ return (struct acdb_iir_block *)
+ (acdb_data.virt_addr + index
+ + sizeof(struct header));
+ } else {
+ index += prs_hdr->data_len +
+ sizeof(struct header);
+ }
+ } else {
+ break;
+ }
+ }
+ return NULL;
+}
+
+
+static s32 acdb_fill_audpp_iir(void)
+{
+ struct acdb_iir_block *acdb_iir;
+ s32 i = 0;
+
+ acdb_iir = get_audpp_irr_block();
+ if (acdb_iir == NULL) {
+ MM_ERR("unable to find audpp iir block returning\n");
+ return -EINVAL;
+ }
+ memset(acdb_data.pp_iir, 0, sizeof(*acdb_data.pp_iir));
+
+ acdb_data.pp_iir->active_flag = acdb_iir->enable_flag;
+ acdb_data.pp_iir->num_bands = acdb_iir->stage_count;
+ for (; i < acdb_iir->stage_count; i++) {
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ numerator_filter[i].numerator_b0_filter_lsw =
+ acdb_iir->stages[i].b0_lo;
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ numerator_filter[i].numerator_b0_filter_msw =
+ acdb_iir->stages[i].b0_hi;
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ numerator_filter[i].numerator_b1_filter_lsw =
+ acdb_iir->stages[i].b1_lo;
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ numerator_filter[i].numerator_b1_filter_msw =
+ acdb_iir->stages[i].b1_hi;
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ numerator_filter[i].numerator_b2_filter_lsw =
+ acdb_iir->stages[i].b2_lo;
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ numerator_filter[i].numerator_b2_filter_msw =
+ acdb_iir->stages[i].b2_hi;
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ denominator_filter[i].denominator_a0_filter_lsw =
+ acdb_iir->stages_a[i].a1_lo;
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ denominator_filter[i].denominator_a0_filter_msw =
+ acdb_iir->stages_a[i].a1_hi;
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ denominator_filter[i].denominator_a1_filter_lsw =
+ acdb_iir->stages_a[i].a2_lo;
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ denominator_filter[i].denominator_a1_filter_msw =
+ acdb_iir->stages_a[i].a2_hi;
+ acdb_data.pp_iir->params_filter.filter_4_params.
+ shift_factor_filter[i].shift_factor_0 =
+ acdb_iir->shift_factor[i];
+ acdb_data.pp_iir->params_filter.filter_4_params.pan_filter[i].
+ pan_filter_0 = acdb_iir->pan[i];
+ }
+ return 0;
+}
+
+static void extract_mbadrc(u32 *phy_addr, struct header *prs_hdr, u32 *index)
+{
+ if (prs_hdr->iid == IID_MBADRC_EXT_BUFF) {
+ MM_DBG("Got IID = IID_MBADRC_EXT_BUFF\n");
+ *phy_addr = acdb_data.phys_addr + *index +
+ sizeof(struct header);
+ memcpy(acdb_data.mbadrc_block.ext_buf,
+ (acdb_data.virt_addr + *index +
+ sizeof(struct header)), 196*2);
+ MM_DBG("phy_addr = %x\n", *phy_addr);
+ *index += prs_hdr->data_len + sizeof(struct header);
+ } else if (prs_hdr->iid == IID_MBADRC_BAND_CONFIG) {
+ MM_DBG("Got IID == IID_MBADRC_BAND_CONFIG\n");
+ memcpy(acdb_data.mbadrc_block.band_config, (acdb_data.virt_addr
+ + *index + sizeof(struct header)),
+ sizeof(struct mbadrc_band_config_type) *
+ acdb_data.mbadrc_block.parameters.\
+ mbadrc_num_bands);
+ *index += prs_hdr->data_len + sizeof(struct header);
+ } else if (prs_hdr->iid == IID_MBADRC_PARAMETERS) {
+ struct mbadrc_parameter *tmp;
+ tmp = (struct mbadrc_parameter *)(acdb_data.virt_addr + *index
+ + sizeof(struct header));
+ MM_DBG("Got IID == IID_MBADRC_PARAMETERS");
+ acdb_data.mbadrc_block.parameters.mbadrc_enable =
+ tmp->mbadrc_enable;
+ acdb_data.mbadrc_block.parameters.mbadrc_num_bands =
+ tmp->mbadrc_num_bands;
+ acdb_data.mbadrc_block.parameters.mbadrc_down_sample_level =
+ tmp->mbadrc_down_sample_level;
+ acdb_data.mbadrc_block.parameters.mbadrc_delay =
+ tmp->mbadrc_delay;
+ *index += prs_hdr->data_len + sizeof(struct header);
+ }
+}
+
+static void get_audpp_mbadrc_block(u32 *phy_addr)
+{
+ struct header *prs_hdr;
+ u32 index = 0;
+
+ while (index < acdb_data.acdb_result.used_bytes) {
+ prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+
+ if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+ if (prs_hdr->abid == ABID_AUDIO_MBADRC_RX) {
+ if ((prs_hdr->iid == IID_MBADRC_EXT_BUFF)
+ || (prs_hdr->iid ==
+ IID_MBADRC_BAND_CONFIG)
+ || (prs_hdr->iid ==
+ IID_MBADRC_PARAMETERS)) {
+ extract_mbadrc(phy_addr, prs_hdr,
+ &index);
+ }
+ } else {
+ index += prs_hdr->data_len +
+ sizeof(struct header);
+ }
+ } else {
+ break;
+ }
+ }
+}
+
+static s32 acdb_fill_audpp_mbadrc(void)
+{
+ u32 mbadrc_phys_addr = -1;
+ get_audpp_mbadrc_block(&mbadrc_phys_addr);
+ if (IS_ERR_VALUE(mbadrc_phys_addr)) {
+ MM_ERR("failed to get mbadrc block\n");
+ return -EINVAL;
+ }
+
+ memset(acdb_data.pp_mbadrc, 0, sizeof(*acdb_data.pp_mbadrc));
+
+ acdb_data.pp_mbadrc->enable = acdb_data.mbadrc_block.\
+ parameters.mbadrc_enable;
+ acdb_data.pp_mbadrc->num_bands =
+ acdb_data.mbadrc_block.\
+ parameters.mbadrc_num_bands;
+ acdb_data.pp_mbadrc->down_samp_level =
+ acdb_data.mbadrc_block.parameters.\
+ mbadrc_down_sample_level;
+ acdb_data.pp_mbadrc->adrc_delay =
+ acdb_data.mbadrc_block.parameters.\
+ mbadrc_delay;
+
+ if (acdb_data.mbadrc_block.parameters.mbadrc_num_bands > 1)
+ acdb_data.pp_mbadrc->ext_buf_size = (97 * 2) +
+ (33 * 2 * (acdb_data.mbadrc_block.parameters.\
+ mbadrc_num_bands - 2));
+
+ acdb_data.pp_mbadrc->ext_partition = 0;
+ acdb_data.pp_mbadrc->ext_buf_lsw = (u16)(mbadrc_phys_addr\
+ & 0xFFFF);
+ acdb_data.pp_mbadrc->ext_buf_msw = (u16)((mbadrc_phys_addr\
+ & 0xFFFF0000) >> 16);
+ memcpy(acdb_data.pp_mbadrc->adrc_band, acdb_data.mbadrc_block.\
+ band_config,
+ sizeof(struct mbadrc_band_config_type) *
+ acdb_data.mbadrc_block.parameters.mbadrc_num_bands);
+ return 0;
+}
+
+static s32 acdb_calibrate_audpp(void)
+{
+ s32 result = 0;
+
+ result = acdb_fill_audpp_iir();
+ if (!IS_ERR_VALUE(result)) {
+ result = audpp_dsp_set_rx_iir(COMMON_OBJ_ID,
+ acdb_data.pp_iir->active_flag,
+ acdb_data.pp_iir);
+ if (result) {
+ MM_ERR("ACDB=> Failed to send IIR data to postproc\n");
+ result = -EINVAL;
+ goto done;
+ } else
+ MM_DBG("AUDPP is calibrated with IIR parameters");
+ }
+ result = acdb_fill_audpp_mbadrc();
+ if (!IS_ERR_VALUE(result)) {
+ result = audpp_dsp_set_mbadrc(COMMON_OBJ_ID,
+ acdb_data.pp_mbadrc->enable,
+ acdb_data.pp_mbadrc);
+ if (result) {
+ MM_ERR("ACDB=> Failed to send MBADRC data to"\
+ " postproc\n");
+ result = -EINVAL;
+ goto done;
+ } else
+ MM_DBG("AUDPP is calibrated with MBADRC parameters");
+ }
+done:
+ return result;
+}
+
+static struct acdb_agc_block *get_audpreproc_agc_block(void)
+{
+ struct header *prs_hdr;
+ u32 index = 0;
+
+ while (index < acdb_data.acdb_result.used_bytes) {
+ prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+ if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+ if (prs_hdr->abid == ABID_AUDIO_AGC_TX) {
+ if (prs_hdr->iid == IID_AUDIO_AGC_PARAMETERS) {
+ MM_DBG("GOT ABID_AUDIO_AGC_TX\n");
+ return (struct acdb_agc_block *)
+ (acdb_data.virt_addr + index
+ + sizeof(struct header));
+ }
+ } else {
+ index += prs_hdr->data_len +
+ sizeof(struct header);
+ }
+ } else {
+ break;
+ }
+ }
+ return NULL;
+}
+
+static s32 acdb_fill_audpreproc_agc(void)
+{
+ struct acdb_agc_block *acdb_agc;
+
+ acdb_agc = get_audpreproc_agc_block();
+ if (!acdb_agc) {
+ MM_DBG("unable to find preproc agc parameters winding up\n");
+ return -EINVAL;
+ }
+ memset(acdb_data.preproc_agc, 0, sizeof(*acdb_data.preproc_agc));
+ acdb_data.preproc_agc->cmd_id = AUDPREPROC_CMD_CFG_AGC_PARAMS;
+ /* 0xFE00 to configure all parameters */
+ acdb_data.preproc_agc->tx_agc_param_mask = 0xFFFF;
+ if (acdb_agc->enable_status)
+ acdb_data.preproc_agc->tx_agc_enable_flag =
+ AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA;
+ else
+ acdb_data.preproc_agc->tx_agc_enable_flag =
+ AUDPREPROC_CMD_TX_AGC_ENA_FLAG_DIS;
+
+ acdb_data.preproc_agc->comp_rlink_static_gain =
+ acdb_agc->comp_rlink_static_gain;
+ acdb_data.preproc_agc->comp_rlink_aig_flag =
+ acdb_agc->comp_rlink_aig_flag;
+ acdb_data.preproc_agc->expander_rlink_th =
+ acdb_agc->exp_rlink_threshold;
+ acdb_data.preproc_agc->expander_rlink_slope =
+ acdb_agc->exp_rlink_slope;
+ acdb_data.preproc_agc->compressor_rlink_th =
+ acdb_agc->comp_rlink_threshold;
+ acdb_data.preproc_agc->compressor_rlink_slope =
+ acdb_agc->comp_rlink_slope;
+
+ /* 0xFFF0 to configure all parameters */
+ acdb_data.preproc_agc->tx_adc_agc_param_mask = 0xFFFF;
+
+ acdb_data.preproc_agc->comp_rlink_aig_attackk =
+ acdb_agc->comp_rlink_aig_attack_k;
+ acdb_data.preproc_agc->comp_rlink_aig_leak_down =
+ acdb_agc->comp_rlink_aig_leak_down;
+ acdb_data.preproc_agc->comp_rlink_aig_leak_up =
+ acdb_agc->comp_rlink_aig_leak_up;
+ acdb_data.preproc_agc->comp_rlink_aig_max =
+ acdb_agc->comp_rlink_aig_max;
+ acdb_data.preproc_agc->comp_rlink_aig_min =
+ acdb_agc->comp_rlink_aig_min;
+ acdb_data.preproc_agc->comp_rlink_aig_releasek =
+ acdb_agc->comp_rlink_aig_release_k;
+ acdb_data.preproc_agc->comp_rlink_aig_leakrate_fast =
+ acdb_agc->comp_rlink_aig_sm_leak_rate_fast;
+ acdb_data.preproc_agc->comp_rlink_aig_leakrate_slow =
+ acdb_agc->comp_rlink_aig_sm_leak_rate_slow;
+ acdb_data.preproc_agc->comp_rlink_attackk_msw =
+ acdb_agc->comp_rlink_attack_k_msw;
+ acdb_data.preproc_agc->comp_rlink_attackk_lsw =
+ acdb_agc->comp_rlink_attack_k_lsw;
+ acdb_data.preproc_agc->comp_rlink_delay =
+ acdb_agc->comp_rlink_delay;
+ acdb_data.preproc_agc->comp_rlink_releasek_msw =
+ acdb_agc->comp_rlink_release_k_msw;
+ acdb_data.preproc_agc->comp_rlink_releasek_lsw =
+ acdb_agc->comp_rlink_release_k_lsw;
+ acdb_data.preproc_agc->comp_rlink_rms_tav =
+ acdb_agc->comp_rlink_rms_trav;
+ return 0;
+}
+
+static struct acdb_iir_block *get_audpreproc_irr_block(void)
+{
+
+ struct header *prs_hdr;
+ u32 index = 0;
+
+ while (index < acdb_data.acdb_result.used_bytes) {
+ prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+
+ if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+ if (prs_hdr->abid == ABID_AUDIO_IIR_TX) {
+ if (prs_hdr->iid == IID_AUDIO_IIR_COEFF)
+ return (struct acdb_iir_block *)
+ (acdb_data.virt_addr + index
+ + sizeof(struct header));
+ } else {
+ index += prs_hdr->data_len +
+ sizeof(struct header);
+ }
+ } else {
+ break;
+ }
+ }
+ return NULL;
+}
+
+
+static s32 acdb_fill_audpreproc_iir(void)
+{
+ struct acdb_iir_block *acdb_iir;
+
+
+ acdb_iir = get_audpreproc_irr_block();
+ if (!acdb_iir) {
+ MM_DBG("unable to find preproc iir parameters winding up\n");
+ return -EINVAL;
+ }
+ memset(acdb_data.preproc_iir, 0, sizeof(*acdb_data.preproc_iir));
+
+ acdb_data.preproc_iir->cmd_id =
+ AUDPREPROC_CMD_CFG_IIR_TUNING_FILTER_PARAMS;
+ acdb_data.preproc_iir->active_flag = acdb_iir->enable_flag;
+ acdb_data.preproc_iir->num_bands = acdb_iir->stage_count;
+
+ acdb_data.preproc_iir->numerator_coeff_b0_filter0_lsw =
+ acdb_iir->stages[0].b0_lo;
+ acdb_data.preproc_iir->numerator_coeff_b0_filter0_msw =
+ acdb_iir->stages[0].b0_hi;
+ acdb_data.preproc_iir->numerator_coeff_b1_filter0_lsw =
+ acdb_iir->stages[0].b1_lo;
+ acdb_data.preproc_iir->numerator_coeff_b1_filter0_msw =
+ acdb_iir->stages[0].b1_hi;
+ acdb_data.preproc_iir->numerator_coeff_b2_filter0_lsw =
+ acdb_iir->stages[0].b2_lo;
+ acdb_data.preproc_iir->numerator_coeff_b2_filter0_msw =
+ acdb_iir->stages[0].b2_hi;
+
+ acdb_data.preproc_iir->numerator_coeff_b0_filter1_lsw =
+ acdb_iir->stages[1].b0_lo;
+ acdb_data.preproc_iir->numerator_coeff_b0_filter1_msw =
+ acdb_iir->stages[1].b0_hi;
+ acdb_data.preproc_iir->numerator_coeff_b1_filter1_lsw =
+ acdb_iir->stages[1].b1_lo;
+ acdb_data.preproc_iir->numerator_coeff_b1_filter1_msw =
+ acdb_iir->stages[1].b1_hi;
+ acdb_data.preproc_iir->numerator_coeff_b2_filter1_lsw =
+ acdb_iir->stages[1].b2_lo;
+ acdb_data.preproc_iir->numerator_coeff_b2_filter1_msw =
+ acdb_iir->stages[1].b2_hi;
+
+ acdb_data.preproc_iir->numerator_coeff_b0_filter2_lsw =
+ acdb_iir->stages[2].b0_lo;
+ acdb_data.preproc_iir->numerator_coeff_b0_filter2_msw =
+ acdb_iir->stages[2].b0_hi;
+ acdb_data.preproc_iir->numerator_coeff_b1_filter2_lsw =
+ acdb_iir->stages[2].b1_lo;
+ acdb_data.preproc_iir->numerator_coeff_b1_filter2_msw =
+ acdb_iir->stages[2].b1_hi;
+ acdb_data.preproc_iir->numerator_coeff_b2_filter2_lsw =
+ acdb_iir->stages[2].b2_lo;
+ acdb_data.preproc_iir->numerator_coeff_b2_filter2_msw =
+ acdb_iir->stages[2].b2_hi;
+
+ acdb_data.preproc_iir->numerator_coeff_b0_filter3_lsw =
+ acdb_iir->stages[3].b0_lo;
+ acdb_data.preproc_iir->numerator_coeff_b0_filter3_msw =
+ acdb_iir->stages[3].b0_hi;
+ acdb_data.preproc_iir->numerator_coeff_b1_filter3_lsw =
+ acdb_iir->stages[3].b1_lo;
+ acdb_data.preproc_iir->numerator_coeff_b1_filter3_msw =
+ acdb_iir->stages[3].b1_hi;
+ acdb_data.preproc_iir->numerator_coeff_b2_filter3_lsw =
+ acdb_iir->stages[3].b2_lo;
+ acdb_data.preproc_iir->numerator_coeff_b2_filter3_msw =
+ acdb_iir->stages[3].b2_hi;
+
+ acdb_data.preproc_iir->denominator_coeff_a0_filter0_lsw =
+ acdb_iir->stages_a[0].a1_lo;
+ acdb_data.preproc_iir->denominator_coeff_a0_filter0_msw =
+ acdb_iir->stages_a[0].a1_hi;
+ acdb_data.preproc_iir->denominator_coeff_a1_filter0_lsw =
+ acdb_iir->stages_a[0].a2_lo;
+ acdb_data.preproc_iir->denominator_coeff_a1_filter0_msw =
+ acdb_iir->stages_a[0].a2_hi;
+
+ acdb_data.preproc_iir->denominator_coeff_a0_filter1_lsw =
+ acdb_iir->stages_a[1].a1_lo;
+ acdb_data.preproc_iir->denominator_coeff_a0_filter1_msw =
+ acdb_iir->stages_a[1].a1_hi;
+ acdb_data.preproc_iir->denominator_coeff_a1_filter1_lsw =
+ acdb_iir->stages_a[1].a2_lo;
+ acdb_data.preproc_iir->denominator_coeff_a1_filter1_msw =
+ acdb_iir->stages_a[1].a2_hi;
+
+ acdb_data.preproc_iir->denominator_coeff_a0_filter2_lsw =
+ acdb_iir->stages_a[2].a1_lo;
+ acdb_data.preproc_iir->denominator_coeff_a0_filter2_msw =
+ acdb_iir->stages_a[2].a1_hi;
+ acdb_data.preproc_iir->denominator_coeff_a1_filter2_lsw =
+ acdb_iir->stages_a[2].a2_lo;
+ acdb_data.preproc_iir->denominator_coeff_a1_filter2_msw =
+ acdb_iir->stages_a[2].a2_hi;
+
+ acdb_data.preproc_iir->denominator_coeff_a0_filter3_lsw =
+ acdb_iir->stages_a[3].a1_lo;
+ acdb_data.preproc_iir->denominator_coeff_a0_filter3_msw =
+ acdb_iir->stages_a[3].a1_hi;
+ acdb_data.preproc_iir->denominator_coeff_a1_filter3_lsw =
+ acdb_iir->stages_a[3].a2_lo;
+ acdb_data.preproc_iir->denominator_coeff_a1_filter3_msw =
+ acdb_iir->stages_a[3].a2_hi;
+
+ acdb_data.preproc_iir->shift_factor_filter0 =
+ acdb_iir->shift_factor[0];
+ acdb_data.preproc_iir->shift_factor_filter1 =
+ acdb_iir->shift_factor[1];
+ acdb_data.preproc_iir->shift_factor_filter2 =
+ acdb_iir->shift_factor[2];
+ acdb_data.preproc_iir->shift_factor_filter3 =
+ acdb_iir->shift_factor[3];
+
+ acdb_data.preproc_iir->channel_selected0 =
+ acdb_iir->pan[0];
+ acdb_data.preproc_iir->channel_selected1 =
+ acdb_iir->pan[1];
+ acdb_data.preproc_iir->channel_selected2 =
+ acdb_iir->pan[2];
+ acdb_data.preproc_iir->channel_selected3 =
+ acdb_iir->pan[3];
+ return 0;
+}
+
+static struct acdb_ns_tx_block *get_audpreproc_ns_block(void)
+{
+
+ struct header *prs_hdr;
+ u32 index = 0;
+
+ while (index < acdb_data.acdb_result.used_bytes) {
+ prs_hdr = (struct header *)(acdb_data.virt_addr + index);
+
+ if (prs_hdr->dbor_signature == DBOR_SIGNATURE) {
+ if (prs_hdr->abid == ABID_AUDIO_NS_TX) {
+ if (prs_hdr->iid == IID_NS_PARAMETERS)
+ return (struct acdb_ns_tx_block *)
+ (acdb_data.virt_addr + index
+ + sizeof(struct header));
+ } else {
+ index += prs_hdr->data_len +
+ sizeof(struct header);
+ }
+ } else {
+ break;
+ }
+ }
+ return NULL;
+}
+
+static s32 acdb_fill_audpreproc_ns(void)
+{
+ struct acdb_ns_tx_block *acdb_ns;
+ /* TO DO: do we enable_status_filled */
+ acdb_ns = get_audpreproc_ns_block();
+ if (!acdb_ns) {
+ MM_DBG("unable to find preproc ns parameters winding up\n");
+ return -EINVAL;
+ }
+ memset(acdb_data.preproc_ns, 0, sizeof(*acdb_data.preproc_ns));
+ acdb_data.preproc_ns->cmd_id = AUDPREPROC_CMD_CFG_NS_PARAMS;
+
+ acdb_data.preproc_ns->ec_mode_new = acdb_ns->ec_mode_new;
+ acdb_data.preproc_ns->dens_gamma_n = acdb_ns->dens_gamma_n;
+ acdb_data.preproc_ns->dens_nfe_block_size =
+ acdb_ns->dens_nfe_block_size;
+ acdb_data.preproc_ns->dens_limit_ns = acdb_ns->dens_limit_ns;
+ acdb_data.preproc_ns->dens_limit_ns_d = acdb_ns->dens_limit_ns_d;
+ acdb_data.preproc_ns->wb_gamma_e = acdb_ns->wb_gamma_e;
+ acdb_data.preproc_ns->wb_gamma_n = acdb_ns->wb_gamma_n;
+
+ return 0;
+}
+
+s32 acdb_calibrate_audpreproc(void)
+{
+ s32 result = 0;
+
+ result = acdb_fill_audpreproc_agc();
+ if (!IS_ERR_VALUE(result)) {
+ result = audpreproc_dsp_set_agc(acdb_data.preproc_agc, sizeof(
+ audpreproc_cmd_cfg_agc_params));
+ if (result) {
+ MM_ERR("ACDB=> Failed to send AGC data to preproc)\n");
+ result = -EINVAL;
+ goto done;
+ } else
+ MM_DBG("AUDPREC is calibrated with AGC parameters");
+ }
+ result = acdb_fill_audpreproc_iir();
+ if (!IS_ERR_VALUE(result)) {
+ result = audpreproc_dsp_set_iir(acdb_data.preproc_iir,
+ sizeof(\
+ audpreproc_cmd_cfg_iir_tuning_filter_params));
+ if (result) {
+ MM_ERR("ACDB=> Failed to send IIR data to preproc\n");
+ result = -EINVAL;
+ goto done;
+ } else
+ MM_DBG("audpreproc is calibrated with iir parameters");
+ }
+
+ result = acdb_fill_audpreproc_ns();
+ if (!IS_ERR_VALUE(result)) {
+ result = audpreproc_dsp_set_ns(acdb_data.preproc_ns,
+ sizeof(\
+ audpreproc_cmd_cfg_ns_params));
+ if (result) {
+ MM_ERR("ACDB=> Failed to send NS data to preproc\n");
+ result = -EINVAL;
+ goto done;
+ } else
+ MM_DBG("audpreproc is calibrated with NS parameters");
+ }
+done:
+ return result;
+}
+
+static s32 acdb_send_calibration(void)
+{
+ s32 result = 0;
+
+ if (acdb_data.device_info->dev_type.rx_device) {
+ result = acdb_calibrate_audpp();
+ if (result)
+ goto done;
+ } else if (acdb_data.device_info->dev_type.tx_device) {
+ result = acdb_calibrate_audpreproc();
+ if (result)
+ goto done;
+ acdb_data.audrec_applied |= AUDREC_READY;
+ MM_DBG("acdb_data.audrec_applied = %x\n",
+ acdb_data.audrec_applied);
+ }
+done:
+ return result;
+}
+
+static u8 check_tx_acdb_values_cached(void)
+{
+ if ((acdb_data.device_info->sample_rate ==
+ acdb_cache_tx.device_info.sample_rate) &&
+ (acdb_data.device_info->acdb_id ==
+ acdb_cache_tx.device_info.acdb_id) &&
+ (acdb_cache_tx.node_status ==
+ ACDB_VALUES_FILLED))
+ return 0;
+ else
+ return 1;
+}
+
+static void handle_tx_device_ready_callback(void)
+{
+ u8 acdb_value_apply = 0;
+ u8 result = 0;
+
+ /*check wheather AUDREC enabled before device call backs*/
+ if ((acdb_data.acdb_state & AUDREC_READY) &&
+ !(acdb_data.audrec_applied & AUDREC_READY)) {
+ MM_DBG("AUDREC already enabled apply acdb values\n");
+ acdb_value_apply |= AUDREC_READY;
+ }
+ if (acdb_value_apply) {
+ if (session_info.sampling_freq)
+ acdb_data.device_info->sample_rate =
+ session_info.sampling_freq;
+ result = check_tx_acdb_values_cached();
+ if (result) {
+ result = acdb_get_calibration();
+ if (result < 0) {
+ MM_ERR("Not able to get calibration"\
+ " data continue\n");
+ return;
+ }
+ }
+ acdb_cache_tx.node_status = ACDB_VALUES_FILLED;
+ acdb_send_calibration();
+ }
+}
+
+static struct acdb_cache_node *get_acdb_values_from_cache_tx(u32 stream_id)
+{
+ MM_DBG("searching node with stream_id");
+ if ((acdb_cache_tx.stream_id == stream_id) &&
+ (acdb_cache_tx.node_status ==
+ ACDB_VALUES_NOT_FILLED)) {
+ return &acdb_cache_tx;
+ }
+ MM_DBG("Error! in finding node\n");
+ return NULL;
+}
+
+static void update_acdb_data_struct(struct acdb_cache_node *cur_node)
+{
+ if (cur_node) {
+ acdb_data.device_info = &cur_node->device_info;
+ acdb_data.virt_addr = cur_node->virt_addr_acdb_values;
+ acdb_data.phys_addr = cur_node->phys_addr_acdb_values;
+ } else
+ MM_ERR("error in curent node\n");
+}
+
+static void send_acdb_values_for_active_devices(void)
+{
+ if (acdb_cache_rx.node_status ==
+ ACDB_VALUES_FILLED) {
+ update_acdb_data_struct(&acdb_cache_rx);
+ if (acdb_data.acdb_state & CAL_DATA_READY)
+ acdb_send_calibration();
+ }
+}
+
+static s32 initialize_rpc(void)
+{
+ s32 result = 0;
+
+ result = daldevice_attach(DALDEVICEID_ACDB, ACDB_PORT_NAME,
+ ACDB_CPU, &acdb_data.handle);
+
+ if (result) {
+ MM_ERR("ACDB=> Device Attach failed\n");
+ result = -ENODEV;
+ goto done;
+ }
+done:
+ return result;
+}
+
+static u32 allocate_memory_acdb_cache_tx(void)
+{
+ u32 result = 0;
+ /*initialize local cache */
+ acdb_cache_tx.phys_addr_acdb_values =
+ allocate_contiguous_ebi_nomap(ACDB_BUF_SIZE,
+ SZ_4K);
+
+ if (!acdb_cache_tx.phys_addr_acdb_values) {
+ MM_ERR("ACDB=> Cannot allocate physical memory\n");
+ result = -ENOMEM;
+ goto error;
+ }
+ acdb_cache_tx.map_v_addr = ioremap(
+ acdb_cache_tx.phys_addr_acdb_values,
+ ACDB_BUF_SIZE);
+ if (IS_ERR(acdb_cache_tx.map_v_addr)) {
+ MM_ERR("ACDB=> Could not map physical address\n");
+ result = -ENOMEM;
+ free_contiguous_memory_by_paddr(
+ acdb_cache_tx.phys_addr_acdb_values);
+ goto error;
+ }
+ acdb_cache_tx.virt_addr_acdb_values =
+ acdb_cache_tx.map_v_addr;
+ memset(acdb_cache_tx.virt_addr_acdb_values, 0,
+ ACDB_BUF_SIZE);
+ return result;
+error:
+ iounmap(acdb_cache_tx.map_v_addr);
+ free_contiguous_memory_by_paddr(
+ acdb_cache_tx.phys_addr_acdb_values);
+ return result;
+}
+
+static u32 allocate_memory_acdb_cache_rx(void)
+{
+ u32 result = 0;
+
+ /*initialize local cache */
+ acdb_cache_rx.phys_addr_acdb_values =
+ allocate_contiguous_ebi_nomap(
+ ACDB_BUF_SIZE, SZ_4K);
+
+ if (!acdb_cache_rx.phys_addr_acdb_values) {
+ MM_ERR("ACDB=> Can not allocate physical memory\n");
+ result = -ENOMEM;
+ goto error;
+ }
+ acdb_cache_rx.map_v_addr =
+ ioremap(acdb_cache_rx.phys_addr_acdb_values,
+ ACDB_BUF_SIZE);
+ if (IS_ERR(acdb_cache_rx.map_v_addr)) {
+ MM_ERR("ACDB=> Could not map physical address\n");
+ result = -ENOMEM;
+ free_contiguous_memory_by_paddr(
+ acdb_cache_rx.phys_addr_acdb_values);
+ goto error;
+ }
+ acdb_cache_rx.virt_addr_acdb_values =
+ acdb_cache_rx.map_v_addr;
+ memset(acdb_cache_rx.virt_addr_acdb_values, 0,
+ ACDB_BUF_SIZE);
+ return result;
+error:
+ iounmap(acdb_cache_rx.map_v_addr);
+ free_contiguous_memory_by_paddr(
+ acdb_cache_rx.phys_addr_acdb_values);
+ return result;
+}
+
+static u32 allocate_memory_acdb_get_blk(void)
+{
+ u32 result = 0;
+ acdb_data.get_blk_paddr = allocate_contiguous_ebi_nomap(
+ ACDB_BUF_SIZE, SZ_4K);
+ if (!acdb_data.get_blk_paddr) {
+ MM_ERR("ACDB=> Cannot allocate physical memory\n");
+ result = -ENOMEM;
+ goto error;
+ }
+ acdb_data.map_v_get_blk = ioremap(acdb_data.get_blk_paddr,
+ ACDB_BUF_SIZE);
+ if (IS_ERR(acdb_data.map_v_get_blk)) {
+ MM_ERR("ACDB=> Could not map physical address\n");
+ result = -ENOMEM;
+ free_contiguous_memory_by_paddr(
+ acdb_data.get_blk_paddr);
+ goto error;
+ }
+ acdb_data.get_blk_kvaddr = acdb_data.map_v_get_blk;
+ memset(acdb_data.get_blk_kvaddr, 0, ACDB_BUF_SIZE);
+error:
+ return result;
+}
+
+static void free_memory_acdb_cache_rx(void)
+{
+ iounmap(acdb_cache_rx.map_v_addr);
+ free_contiguous_memory_by_paddr(
+ acdb_cache_rx.phys_addr_acdb_values);
+}
+
+static void free_memory_acdb_cache_tx(void)
+{
+
+ iounmap(acdb_cache_tx.map_v_addr);
+ free_contiguous_memory_by_paddr(
+ acdb_cache_tx.phys_addr_acdb_values);
+}
+
+static void free_memory_acdb_get_blk(void)
+{
+ iounmap(acdb_data.map_v_get_blk);
+ free_contiguous_memory_by_paddr(acdb_data.get_blk_paddr);
+}
+
+static s32 initialize_memory(void)
+{
+ s32 result = 0;
+
+ result = allocate_memory_acdb_get_blk();
+ if (result < 0) {
+ MM_ERR("memory allocation for get blk failed\n");
+ goto done;
+ }
+
+ result = allocate_memory_acdb_cache_rx();
+ if (result < 0) {
+ MM_ERR("memory allocation for rx cache is failed\n");
+ free_memory_acdb_get_blk();
+ goto done;
+ }
+ result = allocate_memory_acdb_cache_tx();
+ if (result < 0) {
+ MM_ERR("memory allocation for tx cache is failed\n");
+ free_memory_acdb_get_blk();
+ free_memory_acdb_cache_rx();
+ goto done;
+ }
+ acdb_data.pp_iir = kmalloc(sizeof(*acdb_data.pp_iir),
+ GFP_KERNEL);
+ if (acdb_data.pp_iir == NULL) {
+ MM_ERR("ACDB=> Could not allocate postproc iir memory\n");
+ free_memory_acdb_get_blk();
+ free_memory_acdb_cache_rx();
+ free_memory_acdb_cache_tx();
+ result = -ENOMEM;
+ goto done;
+ }
+
+ acdb_data.pp_mbadrc = kmalloc(sizeof(*acdb_data.pp_mbadrc), GFP_KERNEL);
+ if (acdb_data.pp_mbadrc == NULL) {
+ MM_ERR("ACDB=> Could not allocate postproc mbadrc memory\n");
+ free_memory_acdb_get_blk();
+ free_memory_acdb_cache_rx();
+ free_memory_acdb_cache_tx();
+ kfree(acdb_data.pp_iir);
+ result = -ENOMEM;
+ goto done;
+ }
+
+ acdb_data.preproc_agc = kmalloc(sizeof(*acdb_data.preproc_agc),
+ GFP_KERNEL);
+ if (acdb_data.preproc_agc == NULL) {
+ MM_ERR("ACDB=> Could not allocate preproc agc memory\n");
+ free_memory_acdb_get_blk();
+ free_memory_acdb_cache_rx();
+ free_memory_acdb_cache_tx();
+ kfree(acdb_data.pp_iir);
+ kfree(acdb_data.pp_mbadrc);
+ result = -ENOMEM;
+ goto done;
+ }
+
+ acdb_data.preproc_iir = kmalloc(sizeof(*acdb_data.preproc_iir),
+ GFP_KERNEL);
+ if (acdb_data.preproc_iir == NULL) {
+ MM_ERR("ACDB=> Could not allocate preproc iir memory\n");
+ free_memory_acdb_get_blk();
+ free_memory_acdb_cache_rx();
+ free_memory_acdb_cache_tx();
+ kfree(acdb_data.pp_iir);
+ kfree(acdb_data.pp_mbadrc);
+ kfree(acdb_data.preproc_agc);
+ result = -ENOMEM;
+ goto done;
+ }
+
+ acdb_data.preproc_ns = kmalloc(sizeof(*acdb_data.preproc_ns),
+ GFP_KERNEL);
+ if (acdb_data.preproc_ns == NULL) {
+ MM_ERR("ACDB=> Could not allocate preproc ns memory\n");
+ free_memory_acdb_get_blk();
+ free_memory_acdb_cache_rx();
+ free_memory_acdb_cache_tx();
+ kfree(acdb_data.pp_iir);
+ kfree(acdb_data.pp_mbadrc);
+ kfree(acdb_data.preproc_agc);
+ kfree(acdb_data.preproc_iir);
+ result = -ENOMEM;
+ goto done;
+ }
+done:
+ return result;
+}
+
+static u8 check_device_change(struct dev_evt_msg device_info)
+{
+ if (!acdb_data.device_info) {
+ MM_ERR("not pointing to previous valid device detail\n");
+ return 1; /*device info will not be pointing to*/
+ /* valid device when acdb driver comes up*/
+ }
+ if ((device_info.sample_rate ==
+ acdb_data.device_info->sample_rate) &&
+ (device_info.acdb_id == acdb_data.device_info->acdb_id)) {
+ return 0;
+ }
+ return 1;
+}
+
+static void device_cb(struct dev_evt_msg *evt, void *private)
+{
+ struct cad_device_info_type dev_type;
+ struct acdb_cache_node *acdb_cache_free_node = NULL;
+ u32 session_id = 0;
+ u8 ret = 0;
+ u8 device_change = 0;
+
+ /*if session value is zero it indicates that device call back is for
+ voice call we will drop the request as acdb values for voice call is
+ not applied from acdb driver*/
+ if (!evt->session_info) {
+ MM_DBG("no active sessions and call back is for"\
+ " voice call\n");
+ goto done;
+ }
+
+ if ((evt->dev_type.rx_device) &&
+ (evt->acdb_id == PSEUDO_ACDB_ID)) {
+ MM_INFO("device cb is for rx device with pseudo acdb id\n");
+ goto done;
+ }
+ dev_type = evt->dev_type;
+ MM_DBG("sample_rate = %d\n", evt->sample_rate);
+ MM_DBG("acdb_id = %d\n", evt->acdb_id);
+ MM_DBG("sessions = %d\n", evt->session_info);
+ MM_DBG("acdb_state = %x\n", acdb_data.acdb_state);
+ mutex_lock(&acdb_data.acdb_mutex);
+ device_change = check_device_change(*evt);
+ if (!device_change) {
+ if (dev_type.tx_device) {
+ if (!(acdb_data.acdb_state & AUDREC_READY))
+ acdb_data.audrec_applied &= ~AUDREC_READY;
+
+ acdb_data.acdb_state &= ~CAL_DATA_READY;
+ goto update_cache;
+ }
+ } else
+ /* state is updated to query the modem for values */
+ acdb_data.acdb_state &= ~CAL_DATA_READY;
+
+update_cache:
+ if (dev_type.tx_device) {
+ /*Only one recording session possible*/
+ session_id = 0;
+ acdb_cache_free_node = &acdb_cache_tx;
+ ret = check_device_info_already_present(
+ *evt,
+ acdb_cache_free_node);
+ acdb_cache_free_node->stream_id = session_id;
+ acdb_data.cur_tx_session = session_id;
+ } else {
+ acdb_cache_free_node = &acdb_cache_rx;
+ ret = check_device_info_already_present(*evt,
+ acdb_cache_free_node);
+ if (ret == 1) {
+ MM_DBG("got device ready call back for another "\
+ "audplay task sessions on same COPP\n");
+ /*stream_id is used to keep track of number of active*/
+ /*sessions active on this device*/
+ acdb_cache_free_node->stream_id++;
+ mutex_unlock(&acdb_data.acdb_mutex);
+ goto done;
+ }
+ acdb_cache_free_node->stream_id++;
+ }
+ update_acdb_data_struct(acdb_cache_free_node);
+ acdb_data.device_cb_compl = 1;
+ mutex_unlock(&acdb_data.acdb_mutex);
+ wake_up(&acdb_data.wait);
+done:
+ return;
+}
+
+static s32 register_device_cb(void)
+{
+ s32 result = 0;
+ acdb_data.dev_cb.func = device_cb;
+ acdb_data.dev_cb.private = (void *)&acdb_data;
+
+ result = audmgr_register_device_info_callback(&acdb_data.dev_cb);
+
+ if (result) {
+ MM_ERR("ACDB=> Could not register device callback\n");
+ result = -ENODEV;
+ goto done;
+ }
+done:
+ return result;
+}
+
+static void audpp_cb(void *private, u32 id, u16 *msg)
+{
+ MM_DBG("\n");
+ if (id != AUDPP_MSG_CFG_MSG)
+ goto done;
+
+ if (msg[0] == AUDPP_MSG_ENA_DIS) {
+ if (--acdb_cache_rx.stream_id <= 0) {
+ acdb_data.acdb_state &= ~AUDPP_READY;
+ acdb_cache_rx.stream_id = 0;
+ MM_DBG("AUDPP_MSG_ENA_DIS\n");
+ }
+ goto done;
+ }
+
+ acdb_data.acdb_state |= AUDPP_READY;
+ acdb_data.audpp_cb_compl = 1;
+ wake_up(&acdb_data.wait);
+done:
+ return;
+}
+
+static s8 handle_audpreproc_cb(void)
+{
+ struct acdb_cache_node *acdb_cached_values;
+ s8 result = 0;
+ u8 stream_id = acdb_data.preproc_stream_id;
+ acdb_data.preproc_cb_compl = 0;
+ acdb_cached_values = get_acdb_values_from_cache_tx(stream_id);
+ if (acdb_cached_values == NULL) {
+ MM_DBG("ERROR: to get chached acdb values\n");
+ return -EPERM;
+ }
+ update_acdb_data_struct(acdb_cached_values);
+
+ if (session_info.sampling_freq)
+ acdb_data.device_info->sample_rate =
+ session_info.sampling_freq;
+
+ if (!(acdb_data.acdb_state & CAL_DATA_READY)) {
+ result = check_tx_acdb_values_cached();
+ if (result) {
+ result = acdb_get_calibration();
+ if (result < 0) {
+ MM_ERR("failed to get calibration data\n");
+ return result;
+ }
+ }
+ acdb_cached_values->node_status = ACDB_VALUES_FILLED;
+ }
+ return result;
+}
+
+static void audpreproc_cb(void *private, u32 id, void *event_data)
+{
+ u8 result = 0;
+ uint16_t *msg = event_data;
+ int stream_id = 0; /* Only single tunnel mode recording supported */
+ if (id != AUDPREPROC_MSG_CMD_CFG_DONE_MSG)
+ goto done;
+
+ acdb_data.preproc_stream_id = stream_id;
+ get_audrec_session_info(&session_info);
+ MM_DBG("status_flag = %x\n", msg[0]);
+ if (msg[0] == AUDPREPROC_MSG_STATUS_FLAG_DIS) {
+ acdb_data.acdb_state &= ~AUDREC_READY;
+ acdb_cache_tx.node_status =\
+ ACDB_VALUES_NOT_FILLED;
+ acdb_data.acdb_state &= ~CAL_DATA_READY;
+ goto done;
+ }
+ /*Following check is added to make sure that device info
+ is updated. audpre proc layer enabled without device
+ callback at this scenario we should not access
+ device information
+ */
+ if (acdb_data.device_info &&
+ session_info.sampling_freq) {
+ acdb_data.device_info->sample_rate =
+ session_info.sampling_freq;
+ result = check_tx_acdb_values_cached();
+ if (!result) {
+ MM_INFO("acdb values for the stream is" \
+ " querried from modem");
+ acdb_data.acdb_state |= CAL_DATA_READY;
+ } else {
+ acdb_data.acdb_state &= ~CAL_DATA_READY;
+ }
+ }
+ acdb_data.acdb_state |= AUDREC_READY;
+
+ acdb_data.preproc_cb_compl = 1;
+ MM_DBG("acdb_data.acdb_state = %x\n", acdb_data.acdb_state);
+ wake_up(&acdb_data.wait);
+done:
+ return;
+}
+
+static s32 register_audpp_cb(void)
+{
+ s32 result = 0;
+
+ acdb_data.audpp_cb.fn = audpp_cb;
+ acdb_data.audpp_cb.private = NULL;
+ result = audpp_register_event_callback(&acdb_data.audpp_cb);
+ if (result) {
+ MM_ERR("ACDB=> Could not register audpp callback\n");
+ result = -ENODEV;
+ goto done;
+ }
+done:
+ return result;
+}
+
+static s32 register_audpreproc_cb(void)
+{
+ s32 result = 0;
+
+ acdb_data.audpreproc_cb.fn = audpreproc_cb;
+ acdb_data.audpreproc_cb.private = NULL;
+ result = audpreproc_register_event_callback(&acdb_data.audpreproc_cb);
+ if (result) {
+ MM_ERR("ACDB=> Could not register audpreproc callback\n");
+ result = -ENODEV;
+ goto done;
+ }
+
+done:
+ return result;
+}
+
+static s32 acdb_initialize_data(void)
+{
+ s32 result = 0;
+
+ mutex_init(&acdb_data.acdb_mutex);
+
+ result = initialize_rpc();
+ if (result)
+ goto err;
+
+ result = initialize_memory();
+ if (result)
+ goto err1;
+
+ result = register_device_cb();
+ if (result)
+ goto err2;
+
+ result = register_audpp_cb();
+ if (result)
+ goto err3;
+
+ result = register_audpreproc_cb();
+ if (result)
+ goto err4;
+
+
+ return result;
+
+err4:
+ result = audpreproc_unregister_event_callback(&acdb_data.audpreproc_cb);
+ if (result)
+ MM_ERR("ACDB=> Could not unregister audpreproc callback\n");
+err3:
+ result = audpp_unregister_event_callback(&acdb_data.audpp_cb);
+ if (result)
+ MM_ERR("ACDB=> Could not unregister audpp callback\n");
+err2:
+ result = audmgr_deregister_device_info_callback(&acdb_data.dev_cb);
+ if (result)
+ MM_ERR("ACDB=> Could not unregister device callback\n");
+err1:
+ daldevice_detach(acdb_data.handle);
+ acdb_data.handle = NULL;
+err:
+ return result;
+}
+
+static s32 acdb_calibrate_device(void *data)
+{
+ s32 result = 0;
+
+ /* initialize driver */
+ result = acdb_initialize_data();
+ if (result)
+ goto done;
+
+ while (!kthread_should_stop()) {
+ MM_DBG("Waiting for call back events\n");
+ wait_event_interruptible(acdb_data.wait,
+ (acdb_data.device_cb_compl
+ | acdb_data.audpp_cb_compl
+ | acdb_data.preproc_cb_compl));
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.device_cb_compl) {
+ acdb_data.device_cb_compl = 0;
+ if (!(acdb_data.acdb_state & CAL_DATA_READY)) {
+ if (acdb_data.device_info->dev_type.rx_device) {
+ /*we need to get calibration values
+ only for RX device as resampler
+ moved to start of the pre - proc chain
+ tx calibration value will be based on
+ sampling frequency what audrec is
+ configured, calibration values for tx
+ device are fetch in audpreproc
+ callback*/
+ result = acdb_get_calibration();
+ if (result < 0) {
+ mutex_unlock(
+ &acdb_data.acdb_mutex);
+ MM_ERR("Not able to get "\
+ "calibration "\
+ "data continue\n");
+ continue;
+ }
+ }
+ }
+ MM_DBG("acdb state = %d\n",
+ acdb_data.acdb_state);
+ if (acdb_data.device_info->dev_type.tx_device)
+ handle_tx_device_ready_callback();
+ else {
+ acdb_cache_rx.node_status =\
+ ACDB_VALUES_FILLED;
+ if (acdb_data.acdb_state &
+ AUDPP_READY) {
+ MM_DBG("AUDPP already enabled "\
+ "apply acdb values\n");
+ goto apply;
+ }
+ }
+ }
+
+ if (!(acdb_data.audpp_cb_compl ||
+ acdb_data.preproc_cb_compl)) {
+ MM_DBG("need to wait for either AUDPP / AUDPREPROC "\
+ "Event\n");
+ mutex_unlock(&acdb_data.acdb_mutex);
+ continue;
+ } else {
+ MM_DBG("got audpp / preproc call back\n");
+ if (acdb_data.audpp_cb_compl) {
+ send_acdb_values_for_active_devices();
+ acdb_data.audpp_cb_compl = 0;
+ mutex_unlock(&acdb_data.acdb_mutex);
+ continue;
+ } else {
+ result = handle_audpreproc_cb();
+ if (result < 0) {
+ mutex_unlock(&acdb_data.acdb_mutex);
+ continue;
+ }
+ }
+ }
+apply:
+ if (acdb_data.acdb_state & CAL_DATA_READY)
+ result = acdb_send_calibration();
+
+ mutex_unlock(&acdb_data.acdb_mutex);
+ }
+done:
+ return 0;
+}
+
+static int __init acdb_init(void)
+{
+
+ s32 result = 0;
+
+ memset(&acdb_data, 0, sizeof(acdb_data));
+ spin_lock_init(&acdb_data.dsp_lock);
+ acdb_data.cb_thread_task = kthread_run(acdb_calibrate_device,
+ NULL, "acdb_cb_thread");
+
+ if (IS_ERR(acdb_data.cb_thread_task)) {
+ MM_ERR("ACDB=> Could not register cb thread\n");
+ result = -ENODEV;
+ goto err;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ /*This is RTC specific INIT used only with debugfs*/
+ if (!rtc_acdb_init())
+ MM_ERR("RTC ACDB=>INIT Failure\n");
+
+#endif
+ init_waitqueue_head(&acdb_data.wait);
+
+ return misc_register(&acdb_misc);
+err:
+ return result;
+}
+
+static void __exit acdb_exit(void)
+{
+ s32 result = 0;
+
+ result = audmgr_deregister_device_info_callback(&acdb_data.dev_cb);
+ if (result)
+ MM_ERR("ACDB=> Could not unregister device callback\n");
+
+ result = audpp_unregister_event_callback(&acdb_data.audpp_cb);
+ if (result)
+ MM_ERR("ACDB=> Could not unregister audpp callback\n");
+
+ result = audpreproc_unregister_event_callback(&acdb_data.\
+ audpreproc_cb);
+ if (result)
+ MM_ERR("ACDB=> Could not unregister audpreproc callback\n");
+
+ result = kthread_stop(acdb_data.cb_thread_task);
+ if (result)
+ MM_ERR("ACDB=> Could not stop kthread\n");
+
+ free_memory_acdb_get_blk();
+
+ iounmap(acdb_cache_tx.map_v_addr);
+ free_contiguous_memory_by_paddr(
+ acdb_cache_tx.phys_addr_acdb_values);
+ iounmap(acdb_cache_rx.map_v_addr);
+ free_contiguous_memory_by_paddr(
+ acdb_cache_rx.phys_addr_acdb_values);
+ kfree(acdb_data.device_info);
+ kfree(acdb_data.pp_iir);
+ kfree(acdb_data.pp_mbadrc);
+ kfree(acdb_data.preproc_agc);
+ kfree(acdb_data.preproc_iir);
+ kfree(acdb_data.preproc_ns);
+ mutex_destroy(&acdb_data.acdb_mutex);
+ memset(&acdb_data, 0, sizeof(acdb_data));
+ #ifdef CONFIG_DEBUG_FS
+ rtc_acdb_deinit();
+ #endif
+}
+
+late_initcall(acdb_init);
+module_exit(acdb_exit);
+
+MODULE_DESCRIPTION("MSM 8x25 Audio ACDB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 45fa045..7e6c9ce 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -51,6 +51,7 @@
#include <mach/qdsp5/qdsp5audppmsg.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
#include <mach/qdsp5/qdsp5audplaymsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/qdsp5/qdsp5rmtcmdi.h>
#include <mach/debug_mm.h>
#include <mach/msm_memtypes.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index 39578c1..05ad373 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -114,8 +114,6 @@
uint32_t out_frame_cnt;
struct msm_adsp_module *audrec;
- struct msm_adsp_module *audpre;
-
/* configuration to use on next enable */
uint32_t samp_rate;
@@ -154,6 +152,7 @@
struct ion_client *client;
struct ion_handle *input_buff_handle;
+ struct audrec_session_info session_info; /*audrec session info*/
};
struct audio_frame {
@@ -232,6 +231,30 @@
}
}
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, void *event_data)
+{
+
+ uint16_t *msg = event_data;
+
+ if (!msg)
+ return;
+
+ switch (id) {
+ case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+ MM_DBG("type %d, status_flag %d\n",\
+ msg[0], msg[1]);
+ break;
+ case AUDPREPROC_MSG_ERROR_MSG_ID:
+ MM_INFO("err_index %d\n", msg[0]);
+ break;
+ case ADSP_MESSAGE_ID:
+ MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+ break;
+ default:
+ MM_ERR("unknown event %d\n", id);
+ }
+}
/* must be called with audio->lock held */
static int audamrnb_in_enable(struct audio_amrnb_in *audio)
{
@@ -252,16 +275,23 @@
if (rc < 0)
return rc;
- if (msm_adsp_enable(audio->audpre)) {
+ if (audpreproc_enable(audio->enc_id,
+ &audpre_dsp_event, audio)) {
+ MM_ERR("msm_adsp_enable(audpreproc) failed\n");
audmgr_disable(&audio->audmgr);
- MM_ERR("msm_adsp_enable(audpre) failed\n");
return -ENODEV;
}
+ /*update aurec session info in audpreproc layer*/
+ audio->session_info.session_id = audio->enc_id;
+ audio->session_info.sampling_freq =
+ convert_samp_index(audio->samp_rate);
+ audpreproc_update_audrec_info(&audio->session_info);
}
+
if (msm_adsp_enable(audio->audrec)) {
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+ audpreproc_disable(audio->enc_id, audio);
audmgr_disable(&audio->audmgr);
- msm_adsp_disable(audio->audpre);
}
MM_ERR("msm_adsp_enable(audrec) failed\n");
return -ENODEV;
@@ -286,35 +316,17 @@
audio->running == 0, 1*HZ);
msm_adsp_disable(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- msm_adsp_disable(audio->audpre);
+ /*reset the sampling frequency information at
+ audpreproc layer*/
+ audio->session_info.sampling_freq = 0;
+ audpreproc_update_audrec_info(&audio->session_info);
+ audpreproc_disable(audio->enc_id, audio);
audmgr_disable(&audio->audmgr);
}
}
return 0;
}
-/* ------------------- dsp --------------------- */
-static void audpre_dsp_event(void *data, unsigned id, size_t len,
- void (*getevent)(void *ptr, size_t len))
-{
- uint16_t msg[2];
- getevent(msg, sizeof(msg));
-
- switch (id) {
- case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
- MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
- break;
- case AUDPREPROC_MSG_ERROR_MSG_ID:
- MM_ERR("err_index %d\n", msg[0]);
- break;
- case ADSP_MESSAGE_ID:
- MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
- break;
- default:
- MM_ERR("unknown event %d\n", id);
- }
-}
-
static void audamrnb_in_get_dsp_frames(struct audio_amrnb_in *audio)
{
struct audio_frame *frame;
@@ -555,10 +567,6 @@
}
}
-struct msm_adsp_ops audpre_amrnb_adsp_ops = {
- .event = audpre_dsp_event,
-};
-
struct msm_adsp_ops audrec_amrnb_adsp_ops = {
.event = audrec_dsp_event,
};
@@ -1201,12 +1209,8 @@
audamrnb_in_flush(audio);
msm_adsp_put(audio->audrec);
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
- msm_adsp_put(audio->audpre);
-
audpreproc_aenc_free(audio->enc_id);
audio->audrec = NULL;
- audio->audpre = NULL;
audio->opened = 0;
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
(audio->out_data)) {
@@ -1304,15 +1308,6 @@
goto done;
}
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
- &audpre_amrnb_adsp_ops, audio);
- if (rc) {
- msm_adsp_put(audio->audrec);
- audpreproc_aenc_free(audio->enc_id);
- goto done;
- }
- }
audio->dsp_cnt = 0;
audio->stopped = 0;
audio->wflush = 0;
@@ -1414,8 +1409,6 @@
dma_free_coherent(NULL, dma_size, audio->data, audio->phys);
evt_error:
msm_adsp_put(audio->audrec);
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
- msm_adsp_put(audio->audpre);
audpreproc_aenc_free(audio->enc_id);
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index 66b9354..f18aca7 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -48,6 +48,7 @@
#include <mach/iommu_domains.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
#include <mach/qdsp5/qdsp5audplaymsg.h>
#include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 1d4148a..7aeadac 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -43,6 +43,7 @@
#include <mach/iommu_domains.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
#include <mach/qdsp5/qdsp5audplaymsg.h>
#include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index e955c4b..3310743 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -111,7 +111,6 @@
int out_frame_cnt;
struct msm_adsp_module *audrec;
- struct msm_adsp_module *audpre;
/* configuration to use on next enable */
@@ -154,6 +153,8 @@
struct ion_client *client;
struct ion_handle *input_buff_handle;
struct ion_handle *output_buff_handle;
+
+ struct audrec_session_info session_info; /*audrec session info*/
};
struct audio_frame {
@@ -232,6 +233,32 @@
}
}
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, void *event_data)
+{
+
+ uint16_t *msg = event_data;
+
+ if (!msg)
+ return;
+
+ switch (id) {
+ case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+ MM_DBG("type %d, status_flag %d\n",\
+ msg[0], msg[1]);
+ break;
+ case AUDPREPROC_MSG_ERROR_MSG_ID:
+ MM_INFO("err_index %d\n", msg[0]);
+ break;
+ case ADSP_MESSAGE_ID:
+ MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+ break;
+ default:
+ MM_ERR("unknown event %d\n", id);
+ }
+}
+
+
/* must be called with audio->lock held */
static int audevrc_in_enable(struct audio_evrc_in *audio)
{
@@ -252,16 +279,24 @@
if (rc < 0)
return rc;
- if (msm_adsp_enable(audio->audpre)) {
+ if (audpreproc_enable(audio->enc_id,
+ &audpre_dsp_event, audio)) {
+ MM_ERR("msm_adsp_enable(audpreproc) failed\n");
audmgr_disable(&audio->audmgr);
- MM_ERR("msm_adsp_enable(audpre) failed\n");
return -ENODEV;
}
+
+ /*update aurec session info in audpreproc layer*/
+ audio->session_info.session_id = audio->enc_id;
+ audio->session_info.sampling_freq =
+ convert_samp_index(audio->samp_rate);
+ audpreproc_update_audrec_info(&audio->session_info);
}
+
if (msm_adsp_enable(audio->audrec)) {
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+ audpreproc_disable(audio->enc_id, audio);
audmgr_disable(&audio->audmgr);
- msm_adsp_disable(audio->audpre);
}
MM_ERR("msm_adsp_enable(audrec) failed\n");
return -ENODEV;
@@ -288,35 +323,17 @@
wake_up(&audio->wait);
msm_adsp_disable(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- msm_adsp_disable(audio->audpre);
+ audpreproc_disable(audio->enc_id, audio);
+ /*reset the sampling frequency information at
+ audpreproc layer*/
+ audio->session_info.sampling_freq = 0;
+ audpreproc_update_audrec_info(&audio->session_info);
audmgr_disable(&audio->audmgr);
}
}
return 0;
}
-/* ------------------- dsp --------------------- */
-static void audpre_dsp_event(void *data, unsigned id, size_t len,
- void (*getevent)(void *ptr, size_t len))
-{
- uint16_t msg[2];
- getevent(msg, sizeof(msg));
-
- switch (id) {
- case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
- MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
- break;
- case AUDPREPROC_MSG_ERROR_MSG_ID:
- MM_ERR("err_index %d\n", msg[0]);
- break;
- case ADSP_MESSAGE_ID:
- MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
- break;
- default:
- MM_ERR("unknown event %d\n", id);
- }
-}
-
static void audevrc_in_get_dsp_frames(struct audio_evrc_in *audio)
{
struct audio_frame *frame;
@@ -557,10 +574,6 @@
}
}
-static struct msm_adsp_ops audpre_evrc_adsp_ops = {
- .event = audpre_dsp_event,
-};
-
static struct msm_adsp_ops audrec_evrc_adsp_ops = {
.event = audrec_dsp_event,
};
@@ -1186,12 +1199,8 @@
audevrc_in_flush(audio);
msm_adsp_put(audio->audrec);
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
- msm_adsp_put(audio->audpre);
-
audpreproc_aenc_free(audio->enc_id);
audio->audrec = NULL;
- audio->audpre = NULL;
audio->opened = 0;
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
(audio->out_data)) {
@@ -1282,16 +1291,6 @@
goto done;
}
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
- &audpre_evrc_adsp_ops, audio);
- if (rc) {
- msm_adsp_put(audio->audrec);
- audpreproc_aenc_free(audio->enc_id);
- goto done;
- }
- }
-
audio->dsp_cnt = 0;
audio->stopped = 0;
audio->wflush = 0;
@@ -1429,8 +1428,6 @@
ion_client_destroy(client);
client_create_error:
msm_adsp_put(audio->audrec);
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
- msm_adsp_put(audio->audpre);
audpreproc_aenc_free(audio->enc_id);
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index fe7b270..6cbb981a3 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -48,6 +48,7 @@
#include <mach/iommu_domains.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
#include <mach/qdsp5/qdsp5audplaymsg.h>
#include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index 427dc8f..167de9c 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -42,6 +42,7 @@
#include <mach/msm_memtypes.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
#include <mach/qdsp5/qdsp5audplaymsg.h>
#include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
index 0c8034c..6f3bf91 100644
--- a/arch/arm/mach-msm/qdsp5/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -41,6 +41,7 @@
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/htc_pwrsink.h>
#include <mach/debug_mm.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 880de09..3a92e0c 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -48,6 +48,7 @@
#include <mach/iommu_domains.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
#include <mach/qdsp5/qdsp5audplaymsg.h>
#include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 716dbd2..4dcbc7b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -75,7 +75,6 @@
struct mutex read_lock;
wait_queue_head_t wait;
- struct msm_adsp_module *audpre;
struct msm_adsp_module *audrec;
const char *module_name;
unsigned queue_ids;
@@ -105,6 +104,7 @@
int enabled;
int running;
int stopped; /* set when stopped, cleared on flush */
+ struct audrec_session_info session_info; /*audrec session info*/
/* audpre settings */
int tx_agc_enable;
@@ -176,6 +176,32 @@
}
}
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, void *event_data)
+{
+
+ uint16_t *msg = event_data;
+
+ if (!msg)
+ return;
+
+ switch (id) {
+ case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+ MM_DBG("type %d, status_flag %d\n",\
+ msg[0], msg[1]);
+ break;
+ case AUDPREPROC_MSG_ERROR_MSG_ID:
+ MM_INFO("err_index %d\n", msg[0]);
+ break;
+ case ADSP_MESSAGE_ID:
+ MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+ break;
+ default:
+ MM_ERR("unknown event %d\n", id);
+ }
+}
+
+
/* must be called with audio->lock held */
static int audpcm_in_enable(struct audio_in *audio)
{
@@ -195,14 +221,15 @@
if (rc < 0)
return rc;
- if (msm_adsp_enable(audio->audpre)) {
- MM_ERR("msm_adsp_enable(audpre) failed\n");
+ if (audpreproc_enable(audio->enc_id, &audpre_dsp_event, audio)) {
+ MM_ERR("msm_adsp_enable(audpreproc) failed\n");
audmgr_disable(&audio->audmgr);
return -ENODEV;
}
+
if (msm_adsp_enable(audio->audrec)) {
+ audpreproc_disable(audio->enc_id, audio);
audmgr_disable(&audio->audmgr);
- msm_adsp_disable(audio->audpre);
MM_ERR("msm_adsp_enable(audrec) failed\n");
return -ENODEV;
}
@@ -210,6 +237,12 @@
audio->enabled = 1;
audpcm_in_dsp_enable(audio, 1);
+ /*update aurec session info in audpreproc layer*/
+ audio->session_info.session_id = audio->enc_id;
+ audio->session_info.sampling_freq =
+ convert_samp_index(audio->samp_rate);
+ audpreproc_update_audrec_info(&audio->session_info);
+
return 0;
}
@@ -225,34 +258,15 @@
wake_up(&audio->wait);
msm_adsp_disable(audio->audrec);
- msm_adsp_disable(audio->audpre);
+ audpreproc_disable(audio->enc_id, audio);
+ /*reset the sampling frequency information at audpreproc layer*/
+ audio->session_info.sampling_freq = 0;
+ audpreproc_update_audrec_info(&audio->session_info);
audmgr_disable(&audio->audmgr);
}
return 0;
}
-/* ------------------- dsp --------------------- */
-static void audpre_dsp_event(void *data, unsigned id, size_t len,
- void (*getevent)(void *ptr, size_t len))
-{
- uint16_t msg[2];
- getevent(msg, sizeof(msg));
-
- switch (id) {
- case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
- MM_INFO("type %d, status_flag %d\n", msg[0], msg[1]);
- break;
- case AUDPREPROC_MSG_ERROR_MSG_ID:
- MM_ERR("err_index %d\n", msg[0]);
- break;
- case ADSP_MESSAGE_ID:
- MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
- break;
- default:
- MM_ERR("unknown event %d\n", id);
- }
-}
-
struct audio_frame {
uint16_t count_low;
uint16_t count_high;
@@ -360,18 +374,10 @@
}
}
-static struct msm_adsp_ops audpre_adsp_ops = {
- .event = audpre_dsp_event,
-};
-
static struct msm_adsp_ops audrec_adsp_ops = {
.event = audrec_dsp_event,
};
-
-#define audio_send_queue_pre(audio, cmd, len) \
- msm_adsp_write(audio->audpre, QDSP_uPAudPreProcCmdQueue, cmd, len)
-
#define audio_send_queue_recbs(audio, cmd, len) \
msm_adsp_write(audio->audrec, ((audio->queue_ids & 0xFFFF0000) >> 16),\
cmd, len)
@@ -399,7 +405,7 @@
audio->tx_agc_cfg.tx_agc_enable_flag =
AUDPREPROC_CMD_TX_AGC_ENA_FLAG_ENA;
/* cmd.param_mask = 0xFFF0 from sample code */
- audio->tx_agc_cfg.param_mask =
+ audio->tx_agc_cfg.tx_agc_param_mask =
(1 << AUDPREPROC_CMD_PARAM_MASK_RMS_TAY) |
(1 << AUDPREPROC_CMD_PARAM_MASK_RELEASEK) |
(1 << AUDPREPROC_CMD_PARAM_MASK_DELAY) |
@@ -420,7 +426,7 @@
}
cmd = audio->tx_agc_cfg;
- return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+ return audpreproc_dsp_set_agc(&cmd, sizeof(cmd));
}
static int audio_enable_tx_agc(struct audio_in *audio, int enable)
@@ -466,7 +472,7 @@
}
cmd = audio->ns_cfg;
- return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+ return audpreproc_dsp_set_ns(&cmd, sizeof(cmd));
}
static int audio_enable_ns(struct audio_in *audio, int enable)
@@ -495,7 +501,7 @@
cmd = audio->iir_cfg;
- return audio_send_queue_pre(audio, &cmd, sizeof(cmd));
+ return audpreproc_dsp_set_iir(&cmd, sizeof(cmd));
}
static int audio_enable_iir(struct audio_in *audio, int enable)
@@ -762,9 +768,7 @@
audpcm_in_flush(audio);
audpreproc_aenc_free(audio->enc_id);
msm_adsp_put(audio->audrec);
- msm_adsp_put(audio->audpre);
audio->audrec = NULL;
- audio->audpre = NULL;
audio->opened = 0;
if (audio->data) {
ion_unmap_kernel(audio->client, audio->output_buff_handle);
@@ -824,14 +828,6 @@
goto done;
}
- rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
- &audpre_adsp_ops, audio);
- if (rc) {
- msm_adsp_put(audio->audrec);
- audpreproc_aenc_free(audio->enc_id);
- goto done;
- }
-
audio->dsp_cnt = 0;
audio->stopped = 0;
@@ -899,7 +895,6 @@
ion_client_destroy(client);
client_create_error:
msm_adsp_put(audio->audrec);
- msm_adsp_put(audio->audpre);
audpreproc_aenc_free(audio->enc_id);
mutex_unlock(&audio->lock);
return rc;
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index dc257cd..e1a6299 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -44,6 +44,7 @@
#include <mach/iommu_domains.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
#include <mach/qdsp5/qdsp5audplaymsg.h>
#include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index 99a169d..57ae772 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -112,7 +112,6 @@
int out_frame_cnt;
struct msm_adsp_module *audrec;
- struct msm_adsp_module *audpre;
/* configuration to use on next enable */
@@ -155,6 +154,8 @@
struct ion_client *client;
struct ion_handle *input_buff_handle;
struct ion_handle *output_buff_handle;
+
+ struct audrec_session_info session_info; /*audrec session info*/
};
struct audio_frame {
@@ -233,6 +234,32 @@
}
}
+/* ------------------- dsp --------------------- */
+static void audpre_dsp_event(void *data, unsigned id, void *event_data)
+{
+
+ uint16_t *msg = event_data;
+
+ if (!msg)
+ return;
+
+ switch (id) {
+ case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+ MM_DBG("type %d, status_flag %d\n",\
+ msg[0], msg[1]);
+ break;
+ case AUDPREPROC_MSG_ERROR_MSG_ID:
+ MM_INFO("err_index %d\n", msg[0]);
+ break;
+ case ADSP_MESSAGE_ID:
+ MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+ break;
+ default:
+ MM_ERR("unknown event %d\n", id);
+ }
+}
+
+
/* must be called with audio->lock held */
static int audqcelp_in_enable(struct audio_qcelp_in *audio)
{
@@ -253,16 +280,23 @@
if (rc < 0)
return rc;
- if (msm_adsp_enable(audio->audpre)) {
+ if (audpreproc_enable(audio->enc_id,
+ &audpre_dsp_event, audio)) {
+ MM_ERR("msm_adsp_enable(audpreproc) failed\n");
audmgr_disable(&audio->audmgr);
- MM_ERR("msm_adsp_enable(audpre) failed\n");
return -ENODEV;
}
+
+ /*update aurec session info in audpreproc layer*/
+ audio->session_info.session_id = audio->enc_id;
+ audio->session_info.sampling_freq =
+ convert_samp_index(audio->samp_rate);
+ audpreproc_update_audrec_info(&audio->session_info);
}
if (msm_adsp_enable(audio->audrec)) {
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
+ audpreproc_disable(audio->enc_id, audio);
audmgr_disable(&audio->audmgr);
- msm_adsp_disable(audio->audpre);
}
MM_ERR("msm_adsp_enable(audrec) failed\n");
return -ENODEV;
@@ -288,35 +322,17 @@
wake_up(&audio->wait);
msm_adsp_disable(audio->audrec);
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- msm_adsp_disable(audio->audpre);
+ audpreproc_disable(audio->enc_id, audio);
audmgr_disable(&audio->audmgr);
+ /*reset the sampling frequency information at
+ audpreproc layer*/
+ audio->session_info.sampling_freq = 0;
+ audpreproc_update_audrec_info(&audio->session_info);
}
}
return 0;
}
-/* ------------------- dsp --------------------- */
-static void audpre_dsp_event(void *data, unsigned id, size_t len,
- void (*getevent)(void *ptr, size_t len))
-{
- uint16_t msg[2];
- getevent(msg, sizeof(msg));
-
- switch (id) {
- case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
- MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
- break;
- case AUDPREPROC_MSG_ERROR_MSG_ID:
- MM_ERR("err_index %d\n", msg[0]);
- break;
- case ADSP_MESSAGE_ID:
- MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
- break;
- default:
- MM_ERR("unknown event %d\n", id);
- }
-}
-
static void audqcelp_in_get_dsp_frames(struct audio_qcelp_in *audio)
{
struct audio_frame *frame;
@@ -557,10 +573,6 @@
}
}
-static struct msm_adsp_ops audpre_qcelp_adsp_ops = {
- .event = audpre_dsp_event,
-};
-
static struct msm_adsp_ops audrec_qcelp_adsp_ops = {
.event = audrec_dsp_event,
};
@@ -1187,12 +1199,8 @@
audqcelp_in_flush(audio);
msm_adsp_put(audio->audrec);
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
- msm_adsp_put(audio->audpre);
-
audpreproc_aenc_free(audio->enc_id);
audio->audrec = NULL;
- audio->audpre = NULL;
audio->opened = 0;
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
@@ -1285,16 +1293,6 @@
goto done;
}
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- rc = msm_adsp_get("AUDPREPROCTASK", &audio->audpre,
- &audpre_qcelp_adsp_ops, audio);
- if (rc) {
- msm_adsp_put(audio->audrec);
- audpreproc_aenc_free(audio->enc_id);
- goto done;
- }
- }
-
audio->dsp_cnt = 0;
audio->stopped = 0;
audio->wflush = 0;
@@ -1434,8 +1432,6 @@
ion_client_destroy(client);
client_create_error:
msm_adsp_put(audio->audrec);
- if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL)
- msm_adsp_put(audio->audpre);
audpreproc_aenc_free(audio->enc_id);
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index e28e704..276c9d4 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -48,6 +48,7 @@
#include <mach/iommu_domains.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
#include <mach/qdsp5/qdsp5audplaymsg.h>
#include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index 87afcf0..b881c59 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -45,6 +45,7 @@
#include <mach/msm_adsp.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
#include <mach/qdsp5/qdsp5audplaymsg.h>
#include <mach/qdsp5/qdsp5rmtcmdi.h>
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.c b/arch/arm/mach-msm/qdsp5/audmgr.c
index 231a28c..666323b 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr.c
+++ b/arch/arm/mach-msm/qdsp5/audmgr.c
@@ -3,7 +3,7 @@
* interface to "audmgr" service on the baseband cpu
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2012 Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -35,6 +35,10 @@
#define STATE_ENABLED 3
#define STATE_DISABLING 4
#define STATE_ERROR 5
+#define MAX_DEVICE_INFO_CALLBACK 1
+#define SESSION_VOICE 0
+#define SESSION_PLAYBACK 1
+#define SESSION_RECORDING 2
/* store information used across complete audmgr sessions */
struct audmgr_global {
@@ -42,6 +46,9 @@
struct msm_rpc_endpoint *ept;
struct task_struct *task;
uint32_t rpc_version;
+ int cad;
+ struct device_info_callback *device_cb[MAX_DEVICE_INFO_CALLBACK];
+
};
static DEFINE_MUTEX(audmgr_lock);
@@ -49,6 +56,59 @@
.lock = &audmgr_lock,
};
+static void audmgr_rpc_connect(struct audmgr_global *amg)
+{
+ amg->cad = 0;
+ amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
+ AUDMGR_VERS_COMP_VER3,
+ MSM_RPC_UNINTERRUPTIBLE);
+ if (IS_ERR(amg->ept)) {
+ MM_DBG("connect failed with current VERS"\
+ "= %x, trying again with Cad API\n",
+ AUDMGR_VERS_COMP_VER3);
+ amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
+ AUDMGR_VERS_COMP_VER4,
+ MSM_RPC_UNINTERRUPTIBLE);
+ if (IS_ERR(amg->ept)) {
+ amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
+ AUDMGR_VERS_COMP_VER2,
+ MSM_RPC_UNINTERRUPTIBLE);
+ if (IS_ERR(amg->ept)) {
+ MM_ERR("connect failed with current VERS" \
+ "= %x, trying again with another API\n",
+ AUDMGR_VERS_COMP_VER2);
+ amg->ept = msm_rpc_connect_compatible(
+ AUDMGR_PROG,
+ AUDMGR_VERS_COMP,
+ MSM_RPC_UNINTERRUPTIBLE);
+ if (IS_ERR(amg->ept)) {
+ MM_ERR("connect failed with current" \
+ "VERS=%x, trying again with" \
+ "another API\n",
+ AUDMGR_VERS_COMP);
+ amg->ept = msm_rpc_connect(AUDMGR_PROG,
+ AUDMGR_VERS,
+ MSM_RPC_UNINTERRUPTIBLE);
+ amg->rpc_version = AUDMGR_VERS;
+ } else
+ amg->rpc_version = AUDMGR_VERS_COMP;
+ } else
+ amg->rpc_version = AUDMGR_VERS_COMP_VER2;
+ } else {
+ amg->rpc_version = AUDMGR_VERS_COMP_VER4;
+ amg->cad = 1;
+ }
+ } else
+ amg->rpc_version = AUDMGR_VERS_COMP_VER3;
+
+ if (IS_ERR(amg->ept)) {
+ amg->ept = NULL;
+ MM_ERR("failed to connect to audmgr svc\n");
+ }
+
+ return;
+}
+
static void rpc_ack(struct msm_rpc_endpoint *ept, uint32_t xid)
{
uint32_t rep[6];
@@ -64,34 +124,45 @@
}
static void process_audmgr_callback(struct audmgr_global *amg,
- struct rpc_audmgr_cb_func_ptr *args,
- int len)
+ void *args, int len)
{
struct audmgr *am;
+ int i = 0;
+ struct rpc_audmgr_cb_device_info *temp;
- /* Allow only if complete arguments recevied */
- if (len < (sizeof(struct rpc_audmgr_cb_func_ptr)))
+ /* Allow only if complete arguments recevied*/
+ if (len < MIN_RPC_DATA_LENGTH)
return;
/* Allow only if valid argument */
- if (be32_to_cpu(args->set_to_one) != 1)
+ if (be32_to_cpu(((struct rpc_audmgr_cb_common *)args)->set_to_one) != 1)
return;
- am = (struct audmgr *) be32_to_cpu(args->client_data);
-
- if (!am)
- return;
-
- switch (be32_to_cpu(args->status)) {
+ switch (be32_to_cpu(((struct rpc_audmgr_cb_common *)args)->status)) {
case RPC_AUDMGR_STATUS_READY:
- am->handle = be32_to_cpu(args->u.handle);
+ am = (struct audmgr *) be32_to_cpu(
+ ((struct rpc_audmgr_cb_ready *)args)->client_data);
+ if (!am)
+ return;
+ am->handle = be32_to_cpu(
+ ((struct rpc_audmgr_cb_ready *)args)->u.handle);
MM_INFO("rpc READY handle=0x%08x\n", am->handle);
break;
case RPC_AUDMGR_STATUS_CODEC_CONFIG: {
- uint32_t volume;
- volume = be32_to_cpu(args->u.volume);
- MM_INFO("rpc CODEC_CONFIG volume=0x%08x\n", volume);
- am->state = STATE_ENABLED;
+ MM_INFO("rpc CODEC_CONFIG\n");
+ am = (struct audmgr *) be32_to_cpu(
+ ((struct rpc_audmgr_cb_ready *)args)->client_data);
+ if (!am)
+ return;
+ if (am->state != STATE_ENABLED)
+ am->state = STATE_ENABLED;
+ while ((amg->device_cb[i] != NULL) &&
+ (i < MAX_DEVICE_INFO_CALLBACK) &&
+ (amg->cad)) {
+ amg->device_cb[i]->func(&(am->evt),
+ amg->device_cb[i]->private);
+ i++;
+ }
wake_up(&am->wait);
break;
}
@@ -109,14 +180,51 @@
break;
case RPC_AUDMGR_STATUS_DISABLED:
MM_ERR("DISABLED\n");
+ am = (struct audmgr *) be32_to_cpu(
+ ((struct rpc_audmgr_cb_ready *)args)->client_data);
+ if (!am)
+ return;
am->state = STATE_DISABLED;
wake_up(&am->wait);
break;
case RPC_AUDMGR_STATUS_ERROR:
MM_ERR("ERROR?\n");
+ am = (struct audmgr *) be32_to_cpu(
+ ((struct rpc_audmgr_cb_ready *)args)->client_data);
+ if (!am)
+ return;
am->state = STATE_ERROR;
wake_up(&am->wait);
break;
+ case RPC_AUDMGR_STATUS_DEVICE_INFO:
+ MM_INFO("rpc DEVICE_INFO\n");
+ if (!amg->cad)
+ break;
+ temp = (struct rpc_audmgr_cb_device_info *)args;
+ am = (struct audmgr *) be32_to_cpu(temp->client_data);
+ if (!am)
+ return;
+ if (am->evt.session_info == SESSION_PLAYBACK) {
+ am->evt.dev_type.rx_device =
+ be32_to_cpu(temp->d.rx_device);
+ am->evt.dev_type.tx_device = 0;
+ am->evt.acdb_id = am->evt.dev_type.rx_device;
+ } else if (am->evt.session_info == SESSION_RECORDING) {
+ am->evt.dev_type.rx_device = 0;
+ am->evt.dev_type.tx_device =
+ be32_to_cpu(temp->d.tx_device);
+ am->evt.acdb_id = am->evt.dev_type.tx_device;
+ }
+ am->evt.dev_type.ear_mute =
+ be32_to_cpu(temp->d.ear_mute);
+ am->evt.dev_type.mic_mute =
+ be32_to_cpu(temp->d.mic_mute);
+ am->evt.dev_type.volume =
+ be32_to_cpu(temp->d.volume);
+ break;
+ case RPC_AUDMGR_STATUS_DEVICE_CONFIG:
+ MM_ERR("rpc DEVICE_CONFIG\n");
+ break;
default:
break;
}
@@ -201,6 +309,36 @@
return 0;
}
+static unsigned convert_samp_index(unsigned index)
+{
+ switch (index) {
+ case RPC_AUD_DEF_SAMPLE_RATE_48000: return 48000;
+ case RPC_AUD_DEF_SAMPLE_RATE_44100: return 44100;
+ case RPC_AUD_DEF_SAMPLE_RATE_32000: return 32000;
+ case RPC_AUD_DEF_SAMPLE_RATE_24000: return 24000;
+ case RPC_AUD_DEF_SAMPLE_RATE_22050: return 22050;
+ case RPC_AUD_DEF_SAMPLE_RATE_16000: return 16000;
+ case RPC_AUD_DEF_SAMPLE_RATE_12000: return 12000;
+ case RPC_AUD_DEF_SAMPLE_RATE_11025: return 11025;
+ case RPC_AUD_DEF_SAMPLE_RATE_8000: return 8000;
+ default: return 11025;
+ }
+}
+
+static void get_current_session_info(struct audmgr *am,
+ struct audmgr_config *cfg)
+{
+ if (cfg->def_method == RPC_AUD_DEF_METHOD_PLAYBACK ||
+ (cfg->def_method == RPC_AUD_DEF_METHOD_HOST_PCM && cfg->rx_rate)) {
+ am->evt.session_info = SESSION_PLAYBACK; /* playback */
+ am->evt.sample_rate = convert_samp_index(cfg->rx_rate);
+ } else if (cfg->def_method == RPC_AUD_DEF_METHOD_RECORD) {
+ am->evt.session_info = SESSION_RECORDING; /* recording */
+ am->evt.sample_rate = convert_samp_index(cfg->tx_rate);
+ } else
+ am->evt.session_info = SESSION_VOICE;
+}
+
struct audmgr_enable_msg {
struct rpc_request_hdr hdr;
struct rpc_audmgr_enable_client_args args;
@@ -223,39 +361,7 @@
/* connect to audmgr end point and polling thread only once */
if (amg->ept == NULL) {
- amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
- AUDMGR_VERS_COMP_VER3,
- MSM_RPC_UNINTERRUPTIBLE);
- if (IS_ERR(amg->ept)) {
- MM_ERR("connect failed with current VERS \
- = %x, trying again with another API\n",
- AUDMGR_VERS_COMP_VER3);
- amg->ept = msm_rpc_connect_compatible(AUDMGR_PROG,
- AUDMGR_VERS_COMP_VER2,
- MSM_RPC_UNINTERRUPTIBLE);
- if (IS_ERR(amg->ept)) {
- MM_ERR("connect failed with current VERS \
- = %x, trying again with another API\n",
- AUDMGR_VERS_COMP_VER2);
- amg->ept = msm_rpc_connect_compatible(
- AUDMGR_PROG,
- AUDMGR_VERS_COMP,
- MSM_RPC_UNINTERRUPTIBLE);
- if (IS_ERR(amg->ept)) {
- MM_ERR("connect failed with current \
- VERS=%x, trying again with another \
- API\n", AUDMGR_VERS_COMP);
- amg->ept = msm_rpc_connect(AUDMGR_PROG,
- AUDMGR_VERS,
- MSM_RPC_UNINTERRUPTIBLE);
- amg->rpc_version = AUDMGR_VERS;
- } else
- amg->rpc_version = AUDMGR_VERS_COMP;
- } else
- amg->rpc_version = AUDMGR_VERS_COMP_VER2;
- } else
- amg->rpc_version = AUDMGR_VERS_COMP_VER3;
-
+ audmgr_rpc_connect(amg);
if (IS_ERR(amg->ept)) {
rc = PTR_ERR(amg->ept);
amg->ept = NULL;
@@ -312,6 +418,7 @@
msg.args.cb_func = cpu_to_be32(0x11111111);
msg.args.client_data = cpu_to_be32((int)am);
+ get_current_session_info(am, cfg);
msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, amg->rpc_version,
AUDMGR_ENABLE_CLIENT);
@@ -326,6 +433,7 @@
if (am->state == STATE_ENABLED)
return 0;
+ am->evt.session_info = -1;
MM_ERR("unexpected state %d while enabling?!\n", am->state);
return -ENODEV;
}
@@ -341,6 +449,7 @@
return 0;
MM_INFO("session 0x%08x\n", (int) am);
+ am->evt.session_info = -1;
msg.handle = cpu_to_be32(am->handle);
msm_rpc_setup_req(&msg.hdr, AUDMGR_PROG, amg->rpc_version,
AUDMGR_DISABLE_CLIENT);
@@ -363,3 +472,33 @@
return -ENODEV;
}
EXPORT_SYMBOL(audmgr_disable);
+
+int audmgr_register_device_info_callback(struct device_info_callback *dcb)
+{
+ struct audmgr_global *amg = &the_audmgr_state;
+ int i;
+
+ for (i = 0; i < MAX_DEVICE_INFO_CALLBACK; i++) {
+ if (NULL == amg->device_cb[i]) {
+ amg->device_cb[i] = dcb;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(audmgr_register_device_info_callback);
+
+int audmgr_deregister_device_info_callback(struct device_info_callback *dcb)
+{
+ struct audmgr_global *amg = &the_audmgr_state;
+ int i;
+
+ for (i = 0; i < MAX_DEVICE_INFO_CALLBACK; i++) {
+ if (dcb == amg->device_cb[i]) {
+ amg->device_cb[i] = NULL;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(audmgr_deregister_device_info_callback);
diff --git a/arch/arm/mach-msm/qdsp5/audmgr.h b/arch/arm/mach-msm/qdsp5/audmgr.h
index 34c8488..15dd954 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr.h
+++ b/arch/arm/mach-msm/qdsp5/audmgr.h
@@ -77,6 +77,7 @@
RPC_AUD_DEF_CODEC_AMR_NB,
RPC_AUD_DEF_CODEC_13K,
RPC_AUD_DEF_CODEC_EVRC,
+ RPC_AUD_DEF_CODEC_AC3,
RPC_AUD_DEF_CODEC_MAX_002,
};
@@ -124,6 +125,9 @@
RPC_AUDMGR_STATUS_VOLUME_CHANGE,
RPC_AUDMGR_STATUS_DISABLED,
RPC_AUDMGR_STATUS_ERROR,
+ RPC_AUDMGR_STATUS_DEVICE_CONFIG,
+ RPC_AUDMGR_STATUS_DEVICE_INFO
+
};
struct rpc_audmgr_enable_client_args {
@@ -147,6 +151,7 @@
#define AUDMGR_GET_RX_SAMPLE_RATE 8
#define AUDMGR_GET_TX_SAMPLE_RATE 9
#define AUDMGR_SET_DEVICE_MODE 10
+#define MIN_RPC_DATA_LENGTH 16
#define AUDMGR_PROG_VERS "rs30000013:0x7feccbff"
#define AUDMGR_PROG 0x30000013
@@ -154,8 +159,17 @@
#define AUDMGR_VERS_COMP 0x00010001
#define AUDMGR_VERS_COMP_VER2 0x00020001
#define AUDMGR_VERS_COMP_VER3 0x00030001
+#define AUDMGR_VERS_COMP_VER4 0x00040001
-struct rpc_audmgr_cb_func_ptr {
+struct cad_device_info_type {
+ uint32_t rx_device;
+ uint32_t tx_device;
+ uint32_t ear_mute;
+ uint32_t mic_mute;
+ uint32_t volume;
+};
+
+struct rpc_audmgr_cb_common {
uint32_t cb_id; /* cb_func */
uint32_t status; /* Audmgr status */
uint32_t set_to_one; /* Pointer status (1 = valid, 0 = invalid) */
@@ -164,6 +178,10 @@
disc = AUDMGR_STATUS_CODEC_CONFIG => data = volume
disc = AUDMGR_STATUS_DISABLED => data =status_disabled
disc = AUDMGR_STATUS_VOLUME_CHANGE => data = volume_change */
+};
+
+struct rpc_audmgr_cb_ready {
+ struct rpc_audmgr_cb_common c_data;
union {
uint32_t handle;
uint32_t volume;
@@ -173,18 +191,35 @@
uint32_t client_data;
};
+struct rpc_audmgr_cb_device_info {
+ struct rpc_audmgr_cb_common c_data;
+ struct cad_device_info_type d;
+ uint32_t client_data;
+};
+
#define AUDMGR_CB_FUNC_PTR 1
#define AUDMGR_OPR_LSTNR_CB_FUNC_PTR 2
#define AUDMGR_CODEC_LSTR_FUNC_PTR 3
-#define AUDMGR_CB_PROG_VERS "rs31000013:0xf8e3e2d9"
-#define AUDMGR_CB_PROG 0x31000013
-#define AUDMGR_CB_VERS 0xf8e3e2d9
+struct dev_evt_msg {
+ struct cad_device_info_type dev_type;
+ uint32_t acdb_id;
+ int session_info;
+ uint32_t sample_rate;
+};
+
+typedef void (*device_info_func)(struct dev_evt_msg *evt_msg, void *private);
+
+struct device_info_callback {
+ device_info_func func;
+ void *private;
+};
struct audmgr {
wait_queue_head_t wait;
uint32_t handle;
int state;
+ struct dev_evt_msg evt;
};
struct audmgr_config {
@@ -195,86 +230,11 @@
uint32_t snd_method;
};
+int audmgr_register_device_info_callback(struct device_info_callback *dcb);
+int audmgr_deregister_device_info_callback(struct device_info_callback *dcb);
+
int audmgr_open(struct audmgr *am);
int audmgr_close(struct audmgr *am);
int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg);
int audmgr_disable(struct audmgr *am);
-
-typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
-typedef void (*audrec_event_func)(void *private, unsigned id, uint16_t *msg);
-
-/* worst case delay of 1sec for response */
-#define MSM_AUD_DECODER_WAIT_MS 1000
-#define MSM_AUD_MODE_TUNNEL 0x00000100
-#define MSM_AUD_MODE_NONTUNNEL 0x00000200
-#define MSM_AUD_DECODER_MASK 0x0000FFFF
-#define MSM_AUD_OP_MASK 0xFFFF0000
-
-/*Playback mode*/
-#define NON_TUNNEL_MODE_PLAYBACK 1
-#define TUNNEL_MODE_PLAYBACK 0
-
-enum msm_aud_decoder_state {
- MSM_AUD_DECODER_STATE_NONE = 0,
- MSM_AUD_DECODER_STATE_FAILURE = 1,
- MSM_AUD_DECODER_STATE_SUCCESS = 2,
- MSM_AUD_DECODER_STATE_CLOSE = 3,
-};
-
-int audpp_adec_alloc(unsigned dec_attrb, const char **module_name,
- unsigned *queueid);
-void audpp_adec_free(int decid);
-
-struct audpp_event_callback {
- audpp_event_func fn;
- void *private;
-};
-
-int audpp_register_event_callback(struct audpp_event_callback *eh);
-int audpp_unregister_event_callback(struct audpp_event_callback *eh);
-int is_audpp_enable(void);
-
-int audpp_enable(int id, audpp_event_func func, void *private);
-void audpp_disable(int id, void *private);
-
-int audpp_send_queue1(void *cmd, unsigned len);
-int audpp_send_queue2(void *cmd, unsigned len);
-int audpp_send_queue3(void *cmd, unsigned len);
-
-int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan);
-int audpp_pause(unsigned id, int pause);
-int audpp_flush(unsigned id);
-void audpp_avsync(int id, unsigned rate);
-unsigned audpp_avsync_sample_count(int id);
-unsigned audpp_avsync_byte_count(int id);
-int audpp_dsp_set_mbadrc(unsigned id, unsigned enable,
- audpp_cmd_cfg_object_params_mbadrc *mbadrc);
-int audpp_dsp_set_eq(unsigned id, unsigned enable,
- audpp_cmd_cfg_object_params_eqalizer *eq);
-int audpp_dsp_set_rx_iir(unsigned id, unsigned enable,
- audpp_cmd_cfg_object_params_pcm *iir);
-
-int audpp_dsp_set_rx_srs_trumedia_g
- (struct audpp_cmd_cfg_object_params_srstm_g *srstm);
-int audpp_dsp_set_rx_srs_trumedia_w
- (struct audpp_cmd_cfg_object_params_srstm_w *srstm);
-int audpp_dsp_set_rx_srs_trumedia_c
- (struct audpp_cmd_cfg_object_params_srstm_c *srstm);
-int audpp_dsp_set_rx_srs_trumedia_h
- (struct audpp_cmd_cfg_object_params_srstm_h *srstm);
-int audpp_dsp_set_rx_srs_trumedia_p
- (struct audpp_cmd_cfg_object_params_srstm_p *srstm);
-int audpp_dsp_set_rx_srs_trumedia_l
- (struct audpp_cmd_cfg_object_params_srstm_l *srstm);
-
-int audpp_dsp_set_vol_pan(unsigned id,
- audpp_cmd_cfg_object_params_volume *vol_pan);
-int audpp_dsp_set_qconcert_plus(unsigned id, unsigned enable,
- audpp_cmd_cfg_object_params_qconcert *qconcert_plus);
-int audrectask_enable(unsigned enc_type, audrec_event_func func, void *private);
-void audrectask_disable(unsigned enc_type, void *private);
-
-int audrectask_send_cmdqueue(void *cmd, unsigned len);
-int audrectask_send_bitstreamqueue(void *cmd, unsigned len);
-
#endif
diff --git a/arch/arm/mach-msm/qdsp5/audmgr_new.h b/arch/arm/mach-msm/qdsp5/audmgr_new.h
index 3604405..20e27f1 100644
--- a/arch/arm/mach-msm/qdsp5/audmgr_new.h
+++ b/arch/arm/mach-msm/qdsp5/audmgr_new.h
@@ -1,6 +1,6 @@
/* arch/arm/mach-msm/qdsp5/audmgr.h
*
- * Copyright 2008 (c) Code Aurora Forum. All rights reserved.
+ * Copyright 2008,2012 (c) Code Aurora Forum. All rights reserved.
* Copyright (C) 2008 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
@@ -75,6 +75,7 @@
RPC_AUD_DEF_CODEC_AMR_NB,
RPC_AUD_DEF_CODEC_13K,
RPC_AUD_DEF_CODEC_EVRC,
+ RPC_AUD_DEF_CODEC_AC3,
RPC_AUD_DEF_CODEC_MAX_002,
};
@@ -193,21 +194,4 @@
int audmgr_close(struct audmgr *am);
int audmgr_enable(struct audmgr *am, struct audmgr_config *cfg);
int audmgr_disable(struct audmgr *am);
-
-typedef void (*audpp_event_func)(void *private, unsigned id, uint16_t *msg);
-
-int audpp_enable(int id, audpp_event_func func, void *private);
-void audpp_disable(int id, void *private);
-
-int audpp_send_queue1(void *cmd, unsigned len);
-int audpp_send_queue2(void *cmd, unsigned len);
-int audpp_send_queue3(void *cmd, unsigned len);
-
-int audpp_set_volume_and_pan(unsigned id, unsigned volume, int pan);
-int audpp_pause(unsigned id, int pause);
-int audpp_flush(unsigned id);
-void audpp_avsync(int id, unsigned rate);
-unsigned audpp_avsync_sample_count(int id);
-unsigned audpp_avsync_byte_count(int id);
-
#endif
diff --git a/arch/arm/mach-msm/qdsp5/audpp.c b/arch/arm/mach-msm/qdsp5/audpp.c
index 1616ad0..b4ead5c 100644
--- a/arch/arm/mach-msm/qdsp5/audpp.c
+++ b/arch/arm/mach-msm/qdsp5/audpp.c
@@ -34,6 +34,8 @@
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
+#include <mach/qdsp5/qdsp5audpp.h>
+#include <mach/qdsp5v2/audio_acdbi.h>
#include <mach/debug_mm.h>
#include "evlog.h"
@@ -85,19 +87,7 @@
#define AUDPP_CMD_IIR_FLAG_DIS 0x0000
#define AUDPP_CMD_IIR_FLAG_ENA -1
-#define AUDPP_CMD_VOLUME_PAN 0
-#define AUDPP_CMD_IIR_TUNING_FILTER 1
-#define AUDPP_CMD_EQUALIZER 2
-#define AUDPP_CMD_ADRC 3
-#define AUDPP_CMD_SPECTROGRAM 4
-#define AUDPP_CMD_QCONCERT 5
-#define AUDPP_CMD_SIDECHAIN_TUNING_FILTER 6
-#define AUDPP_CMD_SAMPLING_FREQUENCY 7
-#define AUDPP_CMD_QAFX 8
-#define AUDPP_CMD_QRUMBLE 9
-#define AUDPP_CMD_MBADRC 10
-
-#define MAX_EVENT_CALLBACK_CLIENTS 1
+#define MAX_EVENT_CALLBACK_CLIENTS 2
#define AUDPP_CONCURRENCY_DEFAULT 6 /* All non tunnel mode */
#define AUDPP_MAX_DECODER_CNT 5
@@ -335,6 +325,11 @@
case ADSP_MESSAGE_ID:
MM_DBG("Received ADSP event: module enable/disable(audpptask)");
break;
+ case AUDPP_MSG_FEAT_QUERY_DM_DONE:
+ MM_INFO(" RTC ACK --> %x %x %x\n", msg[0],\
+ msg[1], msg[2]);
+ acdb_rtc_set_err(msg[2]);
+ break;
default:
MM_ERR("unhandled msg id %x\n", id);
}
diff --git a/arch/arm/mach-msm/qdsp5/audpreproc.c b/arch/arm/mach-msm/qdsp5/audpreproc.c
index 230429f..92e54f8 100644
--- a/arch/arm/mach-msm/qdsp5/audpreproc.c
+++ b/arch/arm/mach-msm/qdsp5/audpreproc.c
@@ -1,7 +1,7 @@
/*
* Common code to deal with the AUDPREPROC dsp task (audio preprocessing)
*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
*
@@ -23,6 +23,8 @@
#include <mach/debug_mm.h>
#include <mach/qdsp5/qdsp5audpreproc.h>
#include <mach/qdsp5/qdsp5audreccmdi.h>
+#include <mach/qdsp5v2/audio_acdbi.h>
+
static DEFINE_MUTEX(audpreproc_lock);
@@ -56,6 +58,9 @@
(1<<AUDREC_CMD_TYPE_0_INDEX_QCELP))
#endif
+#define MAX_ENC_COUNT 2
+#define MAX_EVENT_CALLBACK_CLIENTS 2
+
struct msm_adspenc_database {
unsigned num_enc;
struct msm_adspenc_info *enc_info_list;
@@ -90,15 +95,237 @@
struct audpreproc_state {
struct msm_adsp_module *mod;
+ audpreproc_event_func func[MAX_ENC_COUNT];
+ void *private[MAX_ENC_COUNT];
struct mutex *lock;
unsigned open_count;
unsigned enc_inuse;
+ struct audpreproc_event_callback *cb_tbl[MAX_EVENT_CALLBACK_CLIENTS];
};
+static struct audrec_session_info session_info;
+
static struct audpreproc_state the_audpreproc_state = {
.lock = &audpreproc_lock,
};
+/* DSP preproc event handler */
+static void audpreproc_dsp_event(void *data, unsigned id, size_t len,
+ void (*getevent)(void *ptr, size_t len))
+{
+ struct audpreproc_state *audpreproc = data;
+ uint16_t msg[2];
+ MM_ERR("audpreproc_dsp_event %id", id);
+
+ getevent(msg, sizeof(msg));
+
+ switch (id) {
+ case AUDPREPROC_MSG_CMD_CFG_DONE_MSG:
+ MM_DBG("type %d, status_flag %d\n", msg[0], msg[1]);
+ if (audpreproc->func[0])
+ audpreproc->func[0](
+ audpreproc->private[0], id,
+ &msg);
+ break;
+ case AUDPREPROC_MSG_ERROR_MSG_ID:
+ MM_INFO("err_index %d\n", msg[0]);
+ if (audpreproc->func[0])
+ audpreproc->func[0](
+ audpreproc->private[0], id,
+ &msg);
+ break;
+ case ADSP_MESSAGE_ID:
+ MM_DBG("Received ADSP event: module enable(audpreproctask)\n");
+ if (audpreproc->func[0])
+ audpreproc->func[0](
+ audpreproc->private[0], id,
+ &msg);
+ break;
+ case AUDPREPROC_MSG_FEAT_QUERY_DM_DONE:
+ {
+ uint16_t msg[3];
+ getevent(msg, sizeof(msg));
+ MM_INFO("RTC ACK --> %x %x %x\n", msg[0], msg[1], msg[2]);
+ acdb_rtc_set_err(msg[2]);
+ }
+ break;
+ default:
+ MM_ERR("unknown event %d\n", id);
+ }
+ return;
+}
+
+static struct msm_adsp_ops adsp_ops = {
+ .event = audpreproc_dsp_event,
+};
+
+/* EXPORTED API's */
+int audpreproc_enable(int enc_id, audpreproc_event_func func, void *private)
+{
+ struct audpreproc_state *audpreproc = &the_audpreproc_state;
+ int res = 0;
+ uint16_t msg[2];
+ int n = 0;
+ MM_DBG("audpreproc_enable %d\n", enc_id);
+
+ if (enc_id < 0 || enc_id > (MAX_ENC_COUNT - 1))
+ return -EINVAL;
+
+ mutex_lock(audpreproc->lock);
+ if (audpreproc->func[enc_id]) {
+ res = -EBUSY;
+ goto out;
+ }
+
+ audpreproc->func[enc_id] = func;
+ audpreproc->private[enc_id] = private;
+
+ /* First client to enable preproc task */
+ if (audpreproc->open_count++ == 0) {
+ MM_DBG("Get AUDPREPROCTASK\n");
+ res = msm_adsp_get("AUDPREPROCTASK", &audpreproc->mod,
+ &adsp_ops, audpreproc);
+ if (res < 0) {
+ MM_ERR("Can not get AUDPREPROCTASK\n");
+ audpreproc->open_count = 0;
+ audpreproc->func[enc_id] = NULL;
+ audpreproc->private[enc_id] = NULL;
+ goto out;
+ }
+ if (msm_adsp_enable(audpreproc->mod)) {
+ audpreproc->open_count = 0;
+ audpreproc->func[enc_id] = NULL;
+ audpreproc->private[enc_id] = NULL;
+ msm_adsp_put(audpreproc->mod);
+ audpreproc->mod = NULL;
+ res = -ENODEV;
+ goto out;
+ }
+ }
+ msg[0] = AUDPREPROC_MSG_STATUS_FLAG_ENA;
+ /* Generate audpre enabled message for registered clients */
+ for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n) {
+ if (audpreproc->cb_tbl[n] &&
+ audpreproc->cb_tbl[n]->fn) {
+ audpreproc->cb_tbl[n]->fn( \
+ audpreproc->cb_tbl[n]->private,\
+ AUDPREPROC_MSG_CMD_CFG_DONE_MSG,
+ (void *) &msg);
+ }
+ }
+ res = 0;
+out:
+ mutex_unlock(audpreproc->lock);
+ return res;
+}
+EXPORT_SYMBOL(audpreproc_enable);
+
+
+void audpreproc_disable(int enc_id, void *private)
+{
+ struct audpreproc_state *audpreproc = &the_audpreproc_state;
+ uint16_t msg[2];
+ int n = 0;
+
+ if (enc_id < 0 || enc_id > (MAX_ENC_COUNT - 1))
+ return;
+
+ mutex_lock(audpreproc->lock);
+ if (!audpreproc->func[enc_id])
+ goto out;
+ if (audpreproc->private[enc_id] != private)
+ goto out;
+
+ audpreproc->func[enc_id] = NULL;
+ audpreproc->private[enc_id] = NULL;
+
+ /* Last client then disable preproc task */
+ if (--audpreproc->open_count == 0) {
+ msm_adsp_disable(audpreproc->mod);
+ MM_DBG("Put AUDPREPROCTASK\n");
+ msm_adsp_put(audpreproc->mod);
+ audpreproc->mod = NULL;
+ }
+ msg[0] = AUDPREPROC_MSG_STATUS_FLAG_DIS;
+ /* Generate audpre enabled message for registered clients */
+ for (n = 0; n < MAX_EVENT_CALLBACK_CLIENTS; ++n) {
+ if (audpreproc->cb_tbl[n] &&
+ audpreproc->cb_tbl[n]->fn) {
+ audpreproc->cb_tbl[n]->fn( \
+ audpreproc->cb_tbl[n]->private,\
+ AUDPREPROC_MSG_CMD_CFG_DONE_MSG,
+ (void *) &msg);
+ }
+ }
+out:
+ mutex_unlock(audpreproc->lock);
+ return;
+}
+EXPORT_SYMBOL(audpreproc_disable);
+
+int audpreproc_update_audrec_info(
+ struct audrec_session_info *audrec_session_info)
+{
+ if (!audrec_session_info) {
+ MM_ERR("error in audrec session info address\n");
+ return -EINVAL;
+ }
+ if (audrec_session_info->session_id < MAX_ENC_COUNT) {
+ memcpy(&session_info,
+ audrec_session_info,
+ sizeof(struct audrec_session_info));
+ return 0;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(audpreproc_update_audrec_info);
+
+int get_audrec_session_info(struct audrec_session_info *info)
+{
+ if (!info) {
+ MM_ERR("error in audrec session info address\n");
+ return -EINVAL;
+ }
+
+ if (the_audpreproc_state.open_count == 0) {
+ MM_ERR("No aud pre session active\n");
+ return -EINVAL;
+ }
+
+ memcpy(info, &session_info, sizeof(struct audrec_session_info));
+
+ return 0;
+}
+EXPORT_SYMBOL(get_audrec_session_info);
+
+int audpreproc_register_event_callback(struct audpreproc_event_callback *ecb)
+{
+ struct audpreproc_state *audpreproc = &the_audpreproc_state;
+ int i;
+
+ for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
+ if (NULL == audpreproc->cb_tbl[i]) {
+ audpreproc->cb_tbl[i] = ecb;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(audpreproc_register_event_callback);
+
+int audpreproc_unregister_event_callback(struct audpreproc_event_callback *ecb)
+{
+ struct audpreproc_state *audpreproc = &the_audpreproc_state;
+ int i;
+
+ for (i = 0; i < MAX_EVENT_CALLBACK_CLIENTS; ++i) {
+ if (ecb == audpreproc->cb_tbl[i]) {
+ audpreproc->cb_tbl[i] = NULL;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
/* enc_type = supported encode format *
* like pcm, aac, sbc, evrc, qcelp, amrnb etc ... *
*/
@@ -167,3 +394,37 @@
}
EXPORT_SYMBOL(audpreproc_aenc_free);
+
+int audpreproc_dsp_set_agc(
+ audpreproc_cmd_cfg_agc_params *agc_cfg,
+ unsigned len)
+{
+ return msm_adsp_write(the_audpreproc_state.mod,
+ QDSP_uPAudPreProcCmdQueue, agc_cfg, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_agc);
+
+int audpreproc_dsp_set_ns(
+ audpreproc_cmd_cfg_ns_params *ns_cfg,
+ unsigned len)
+{
+ return msm_adsp_write(the_audpreproc_state.mod,
+ QDSP_uPAudPreProcCmdQueue, ns_cfg, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_ns);
+
+int audpreproc_dsp_set_iir(
+ audpreproc_cmd_cfg_iir_tuning_filter_params *iir_cfg,
+ unsigned len)
+{
+ return msm_adsp_write(the_audpreproc_state.mod,
+ QDSP_uPAudPreProcCmdQueue, iir_cfg, len);
+}
+EXPORT_SYMBOL(audpreproc_dsp_set_iir);
+
+int audpreproc_send_preproccmdqueue(void *cmd, unsigned len)
+{
+ return msm_adsp_write(the_audpreproc_state.mod,
+ QDSP_uPAudPreProcCmdQueue, cmd, len);
+}
+EXPORT_SYMBOL(audpreproc_send_preproccmdqueue);
diff --git a/arch/arm/mach-msm/qdsp5/audrec.c b/arch/arm/mach-msm/qdsp5/audrec.c
index d5cb168..e238e32 100644
--- a/arch/arm/mach-msm/qdsp5/audrec.c
+++ b/arch/arm/mach-msm/qdsp5/audrec.c
@@ -2,7 +2,7 @@
*
* common code to deal with the AUDREC dsp task (audio recording)
*
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009,2012 Code Aurora Forum. All rights reserved.
*
* Based on the audpp layer in arch/arm/mach-msm/qdsp5/audpp.c
*
@@ -34,6 +34,7 @@
#include <mach/qdsp5/qdsp5audreccmdi.h>
#include <mach/qdsp5/qdsp5audrecmsg.h>
+#include <mach/qdsp5/qdsp5audpreproc.h>
#include "audmgr.h"
#include <mach/debug_mm.h>
diff --git a/arch/arm/mach-msm/qdsp5/snd_cad.c b/arch/arm/mach-msm/qdsp5/snd_cad.c
new file mode 100644
index 0000000..c0efa3b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/snd_cad.c
@@ -0,0 +1,607 @@
+/* arch/arm/mach-msm/qdsp5/snd_cad.c
+ *
+ * interface to "snd" service on the baseband cpu
+ * This code also borrows from snd.c, which is
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009, 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/msm_audio.h>
+#include <linux/seq_file.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/board.h>
+#include <mach/msm_rpcrouter.h>
+#include <mach/debug_mm.h>
+#include <linux/debugfs.h>
+
+struct snd_cad_ctxt {
+ struct mutex lock;
+ int opened;
+ struct msm_rpc_endpoint *ept;
+ struct msm_cad_endpoints *cad_epts;
+};
+
+struct snd_cad_sys_ctxt {
+ struct mutex lock;
+ struct msm_rpc_endpoint *ept;
+};
+
+struct snd_curr_dev_info {
+ int rx_dev;
+ int tx_dev;
+};
+
+static struct snd_cad_sys_ctxt the_snd_cad_sys;
+
+static struct snd_cad_ctxt the_snd;
+static struct snd_curr_dev_info curr_dev;
+
+#define RPC_SND_PROG 0x30000002
+#define RPC_SND_CB_PROG 0x31000002
+
+#define RPC_SND_VERS 0x00030003
+
+#define SND_CAD_SET_DEVICE_PROC 40
+#define SND_CAD_SET_VOLUME_PROC 39
+#define MAX_SND_ACTIVE_DEVICE 2
+
+struct rpc_cad_set_device_args {
+ struct cad_devices_type device;
+ uint32_t ear_mute;
+ uint32_t mic_mute;
+
+ uint32_t cb_func;
+ uint32_t client_data;
+};
+
+struct rpc_cad_set_volume_args {
+ struct cad_devices_type device;
+ uint32_t method;
+ uint32_t volume;
+
+ uint32_t cb_func;
+ uint32_t client_data;
+};
+
+struct snd_cad_set_device_msg {
+ struct rpc_request_hdr hdr;
+ struct rpc_cad_set_device_args args;
+};
+
+struct snd_cad_set_volume_msg {
+ struct rpc_request_hdr hdr;
+ struct rpc_cad_set_volume_args args;
+};
+
+struct cad_endpoint *get_cad_endpoints(int *size);
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *dentry;
+
+static int rtc_getdevice_dbg_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ MM_INFO("debug intf %s\n", (char *) file->private_data);
+ return 0;
+}
+
+static ssize_t rtc_getdevice_dbg_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int n = 0;
+ static char *buffer;
+ static char *swap_buf;
+ const int debug_bufmax = 1024;
+ int swap_count = 0;
+ int rc = 0;
+ int dev_count = 0;
+ int dev_id = 0;
+ struct msm_cad_endpoints *msm_cad_epts = the_snd.cad_epts;
+ struct cad_endpoint *cad_epts;
+
+ buffer = kmalloc(sizeof(char) * 1024, GFP_KERNEL);
+ if (buffer == NULL) {
+ MM_ERR("Memory allocation failed for buffer failed\n");
+ return -EFAULT;
+ }
+
+ swap_buf = kmalloc(sizeof(char) * 1024, GFP_KERNEL);
+ if (swap_buf == NULL) {
+ MM_ERR("Memory allocation failed for swap buffer failed\n");
+ kfree(buffer);
+ return -EFAULT;
+ }
+
+ if (msm_cad_epts->num <= 0) {
+ dev_count = 0;
+ n = scnprintf(buffer, debug_bufmax, "DEV_NO:0x%x\n",
+ msm_cad_epts->num);
+ } else {
+ for (dev_id = 0; dev_id < msm_cad_epts->num; dev_id++) {
+ cad_epts = &msm_cad_epts->endpoints[dev_id];
+ if (IS_ERR(cad_epts)) {
+ MM_ERR("invalid snd endpoint for dev_id %d\n",
+ dev_id);
+ rc = PTR_ERR(cad_epts);
+ continue;
+ }
+
+ if ((cad_epts->id != curr_dev.tx_dev) &&
+ (cad_epts->id != curr_dev.rx_dev))
+ continue;
+
+ n += scnprintf(swap_buf + n, debug_bufmax - n,
+ "ACDB_ID:0x%x;CAPB:0x%x\n",
+ cad_epts->id,
+ cad_epts->capability);
+ dev_count++;
+ MM_DBG("RTC Get Device %x Capb %x Dev Count %x\n",
+ dev_id, cad_epts->capability,
+ dev_count);
+
+ }
+ }
+ swap_count = scnprintf(buffer, debug_bufmax, \
+ "DEV_NO:0x%x\n", dev_count);
+
+ memcpy(buffer+swap_count, swap_buf, n*sizeof(char));
+ n = n+swap_count;
+
+ buffer[n] = 0;
+ rc = simple_read_from_buffer(buf, count, ppos, buffer, n);
+ kfree(buffer);
+ kfree(swap_buf);
+ return rc;
+}
+
+static const struct file_operations rtc_acdb_debug_fops = {
+ .open = rtc_getdevice_dbg_open,
+ .read = rtc_getdevice_dbg_read
+};
+
+static int rtc_debugfs_create_entry(void)
+{
+ int rc = 0;
+ char name[sizeof "rtc_get_device"+1];
+
+ snprintf(name, sizeof name, "rtc_get_device");
+ dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, NULL, &rtc_acdb_debug_fops);
+ if (IS_ERR(dentry)) {
+ MM_ERR("debugfs_create_file failed\n");
+ rc = PTR_ERR(dentry);
+ }
+ return rc;
+}
+#else
+static int rtc_debugfs_create_entry()
+{
+ return 0;
+}
+#endif
+
+static inline int check_mute(int mute)
+{
+ return (mute == SND_MUTE_MUTED ||
+ mute == SND_MUTE_UNMUTED) ? 0 : -EINVAL;
+}
+
+static int get_endpoint(struct snd_cad_ctxt *snd, unsigned long arg)
+{
+ int rc = 0, index;
+ struct msm_cad_endpoint ept;
+
+ if (copy_from_user(&ept, (void __user *)arg, sizeof(ept))) {
+ MM_ERR("cad_ioctl get endpoint: invalid read pointer\n");
+ return -EFAULT;
+ }
+
+ index = ept.id;
+ if (index < 0 || index >= snd->cad_epts->num) {
+ MM_ERR("snd_ioctl get endpoint: invalid index!\n");
+ return -EINVAL;
+ }
+
+ ept.id = snd->cad_epts->endpoints[index].id;
+ strlcpy(ept.name,
+ snd->cad_epts->endpoints[index].name,
+ sizeof(ept.name));
+
+ if (copy_to_user((void __user *)arg, &ept, sizeof(ept))) {
+ MM_ERR("snd_ioctl get endpoint: invalid write pointer\n");
+ rc = -EFAULT;
+ }
+
+ return rc;
+}
+
+static long snd_cad_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct snd_cad_set_device_msg dmsg;
+ struct snd_cad_set_volume_msg vmsg;
+
+ struct msm_cad_device_config dev;
+ struct msm_cad_volume_config vol;
+ struct snd_cad_ctxt *snd = file->private_data;
+ int rc = 0;
+
+ mutex_lock(&snd->lock);
+ switch (cmd) {
+ case SND_SET_DEVICE:
+ if (copy_from_user(&dev, (void __user *) arg, sizeof(dev))) {
+ MM_ERR("set device: invalid pointer\n");
+ rc = -EFAULT;
+ break;
+ }
+
+ dmsg.args.device.rx_device = cpu_to_be32(dev.device.rx_device);
+ dmsg.args.device.tx_device = cpu_to_be32(dev.device.tx_device);
+ dmsg.args.device.pathtype = cpu_to_be32(dev.device.pathtype);
+ dmsg.args.ear_mute = cpu_to_be32(dev.ear_mute);
+ dmsg.args.mic_mute = cpu_to_be32(dev.mic_mute);
+ if (check_mute(dev.ear_mute) < 0 ||
+ check_mute(dev.mic_mute) < 0) {
+ MM_ERR("set device: invalid mute status\n");
+ rc = -EINVAL;
+ break;
+ }
+ dmsg.args.cb_func = -1;
+ dmsg.args.client_data = 0;
+ curr_dev.tx_dev = dev.device.tx_device;
+ curr_dev.rx_dev = dev.device.rx_device;
+ MM_ERR("snd_cad_set_device %d %d %d %d\n", dev.device.rx_device,
+ dev.device.tx_device, dev.ear_mute, dev.mic_mute);
+
+ rc = msm_rpc_call(snd->ept,
+ SND_CAD_SET_DEVICE_PROC,
+ &dmsg, sizeof(dmsg), 5 * HZ);
+ break;
+
+ case SND_SET_VOLUME:
+ if (copy_from_user(&vol, (void __user *) arg, sizeof(vol))) {
+ MM_ERR("set volume: invalid pointer\n");
+ rc = -EFAULT;
+ break;
+ }
+
+ vmsg.args.device.rx_device = cpu_to_be32(dev.device.rx_device);
+ vmsg.args.device.tx_device = cpu_to_be32(dev.device.tx_device);
+ vmsg.args.method = cpu_to_be32(vol.method);
+ if (vol.method != SND_METHOD_VOICE) {
+ MM_ERR("set volume: invalid method\n");
+ rc = -EINVAL;
+ break;
+ }
+
+ vmsg.args.volume = cpu_to_be32(vol.volume);
+ vmsg.args.cb_func = -1;
+ vmsg.args.client_data = 0;
+
+ MM_ERR("snd_cad_set_volume %d %d %d %d\n", vol.device.rx_device,
+ vol.device.tx_device, vol.method, vol.volume);
+
+ rc = msm_rpc_call(snd->ept,
+ SND_CAD_SET_VOLUME_PROC,
+ &vmsg, sizeof(vmsg), 5 * HZ);
+
+ break;
+
+ case SND_GET_NUM_ENDPOINTS:
+ if (copy_to_user((void __user *)arg,
+ &snd->cad_epts->num, sizeof(unsigned))) {
+ MM_ERR("get endpoint: invalid pointer\n");
+ rc = -EFAULT;
+ }
+ break;
+
+ case SND_GET_ENDPOINT:
+ rc = get_endpoint(snd, arg);
+ break;
+
+ default:
+ MM_ERR("unknown command\n");
+ rc = -EINVAL;
+ break;
+ }
+ mutex_unlock(&snd->lock);
+
+ return rc;
+}
+
+static int snd_cad_release(struct inode *inode, struct file *file)
+{
+ struct snd_cad_ctxt *snd = file->private_data;
+ int rc;
+
+ mutex_lock(&snd->lock);
+ rc = msm_rpc_close(snd->ept);
+ if (rc < 0)
+ MM_ERR("msm_rpc_close failed\n");
+ snd->ept = NULL;
+ snd->opened = 0;
+ mutex_unlock(&snd->lock);
+ return 0;
+}
+static int snd_cad_sys_release(void)
+{
+ struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+ int rc = 0;
+
+ mutex_lock(&snd_cad_sys->lock);
+ rc = msm_rpc_close(snd_cad_sys->ept);
+ if (rc < 0)
+ MM_ERR("msm_rpc_close failed\n");
+ snd_cad_sys->ept = NULL;
+ mutex_unlock(&snd_cad_sys->lock);
+ return rc;
+}
+static int snd_cad_open(struct inode *inode, struct file *file)
+{
+ struct snd_cad_ctxt *snd = &the_snd;
+ int rc = 0;
+
+ mutex_lock(&snd->lock);
+ if (snd->opened == 0) {
+ if (snd->ept == NULL) {
+ snd->ept = msm_rpc_connect_compatible(RPC_SND_PROG,
+ RPC_SND_VERS, 0);
+ if (IS_ERR(snd->ept)) {
+ rc = PTR_ERR(snd->ept);
+ snd->ept = NULL;
+ MM_ERR("cad connect failed with VERS %x\n",
+ RPC_SND_VERS);
+ goto err;
+ }
+ }
+ file->private_data = snd;
+ snd->opened = 1;
+ } else {
+ MM_ERR("snd already opened\n");
+ rc = -EBUSY;
+ }
+
+err:
+ mutex_unlock(&snd->lock);
+ return rc;
+}
+static int snd_cad_sys_open(void)
+{
+ struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+ int rc = 0;
+
+ mutex_lock(&snd_cad_sys->lock);
+ if (snd_cad_sys->ept == NULL) {
+ snd_cad_sys->ept = msm_rpc_connect_compatible(RPC_SND_PROG,
+ RPC_SND_VERS, 0);
+ if (IS_ERR(snd_cad_sys->ept)) {
+ rc = PTR_ERR(snd_cad_sys->ept);
+ snd_cad_sys->ept = NULL;
+ MM_ERR("func %s : cad connect failed with VERS %x\n",
+ __func__, RPC_SND_VERS);
+ goto err;
+ }
+ } else
+ MM_DBG("snd already opened\n");
+err:
+ mutex_unlock(&snd_cad_sys->lock);
+ return rc;
+}
+
+static const struct file_operations snd_cad_fops = {
+ .owner = THIS_MODULE,
+ .open = snd_cad_open,
+ .release = snd_cad_release,
+ .unlocked_ioctl = snd_cad_ioctl,
+};
+
+struct miscdevice snd_cad_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_cad",
+ .fops = &snd_cad_fops,
+};
+
+static long snd_cad_vol_enable(const char *arg)
+{
+ struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+ struct snd_cad_set_volume_msg vmsg;
+ struct msm_cad_volume_config vol;
+ int rc = 0;
+
+ rc = sscanf(arg, "%d %d %d %d", &vol.device.rx_device,
+ &vol.device.tx_device, &vol.method, &vol.volume);
+ if (rc != 4) {
+ MM_ERR("Invalid arguments. Usage: <rx_device> <tx_device>" \
+ "method> <volume>\n");
+ rc = -EINVAL;
+ return rc;
+ }
+
+ vmsg.args.device.rx_device = cpu_to_be32(vol.device.rx_device);
+ vmsg.args.device.tx_device = cpu_to_be32(vol.device.tx_device);
+ vmsg.args.method = cpu_to_be32(vol.method);
+ if (vol.method != SND_METHOD_VOICE) {
+ MM_ERR("snd_cad_ioctl set volume: invalid method\n");
+ rc = -EINVAL;
+ return rc;
+ }
+
+ vmsg.args.volume = cpu_to_be32(vol.volume);
+ vmsg.args.cb_func = -1;
+ vmsg.args.client_data = 0;
+
+ MM_DBG("snd_cad_set_volume %d %d %d %d\n", vol.device.rx_device,
+ vol.device.rx_device, vol.method, vol.volume);
+
+ rc = msm_rpc_call(snd_cad_sys->ept,
+ SND_CAD_SET_VOLUME_PROC,
+ &vmsg, sizeof(vmsg), 5 * HZ);
+ return rc;
+}
+
+static long snd_cad_dev_enable(const char *arg)
+{
+ struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+ struct snd_cad_set_device_msg dmsg;
+ struct msm_cad_device_config dev;
+ int rc = 0;
+
+
+ rc = sscanf(arg, "%d %d %d %d", &dev.device.rx_device,
+ &dev.device.tx_device, &dev.ear_mute, &dev.mic_mute);
+ if (rc != 4) {
+ MM_ERR("Invalid arguments. Usage: <rx_device> <tx_device> "\
+ "<ear_mute> <mic_mute>\n");
+ rc = -EINVAL;
+ return rc;
+ }
+ dmsg.args.device.rx_device = cpu_to_be32(dev.device.rx_device);
+ dmsg.args.device.tx_device = cpu_to_be32(dev.device.tx_device);
+ dmsg.args.device.pathtype = cpu_to_be32(CAD_DEVICE_PATH_RX_TX);
+ dmsg.args.ear_mute = cpu_to_be32(dev.ear_mute);
+ dmsg.args.mic_mute = cpu_to_be32(dev.mic_mute);
+ if (check_mute(dev.ear_mute) < 0 ||
+ check_mute(dev.mic_mute) < 0) {
+ MM_ERR("snd_cad_ioctl set device: invalid mute status\n");
+ rc = -EINVAL;
+ return rc;
+ }
+ dmsg.args.cb_func = -1;
+ dmsg.args.client_data = 0;
+ curr_dev.tx_dev = dev.device.tx_device;
+ curr_dev.rx_dev = dev.device.rx_device;
+
+ MM_INFO("snd_cad_set_device %d %d %d %d\n", dev.device.rx_device,
+ dev.device.tx_device, dev.ear_mute, dev.mic_mute);
+
+ rc = msm_rpc_call(snd_cad_sys->ept,
+ SND_CAD_SET_DEVICE_PROC,
+ &dmsg, sizeof(dmsg), 5 * HZ);
+ return rc;
+}
+
+static ssize_t snd_cad_dev_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t status;
+ struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+ int rc = 0;
+
+ rc = snd_cad_sys_open();
+ if (rc)
+ return rc;
+
+ mutex_lock(&snd_cad_sys->lock);
+ status = snd_cad_dev_enable(buf);
+ mutex_unlock(&snd_cad_sys->lock);
+
+ rc = snd_cad_sys_release();
+ if (rc)
+ return rc;
+
+ return status ? : size;
+}
+
+static ssize_t snd_cad_vol_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ ssize_t status;
+ struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+ int rc = 0;
+
+ rc = snd_cad_sys_open();
+ if (rc)
+ return rc;
+
+ mutex_lock(&snd_cad_sys->lock);
+ status = snd_cad_vol_enable(buf);
+ mutex_unlock(&snd_cad_sys->lock);
+
+ rc = snd_cad_sys_release();
+ if (rc)
+ return rc;
+
+ return status ? : size;
+}
+
+static DEVICE_ATTR(device, S_IWUSR | S_IRUGO,
+ NULL, snd_cad_dev_store);
+
+static DEVICE_ATTR(volume, S_IWUSR | S_IRUGO,
+ NULL, snd_cad_vol_store);
+
+static int snd_cad_probe(struct platform_device *pdev)
+{
+ struct snd_cad_ctxt *snd = &the_snd;
+ struct snd_cad_sys_ctxt *snd_cad_sys = &the_snd_cad_sys;
+ int rc = 0;
+
+ mutex_init(&snd->lock);
+ mutex_init(&snd_cad_sys->lock);
+ snd_cad_sys->ept = NULL;
+ snd->cad_epts =
+ (struct msm_cad_endpoints *)pdev->dev.platform_data;
+ rc = misc_register(&snd_cad_misc);
+ if (rc)
+ return rc;
+
+ rc = device_create_file(snd_cad_misc.this_device, &dev_attr_device);
+ if (rc) {
+ misc_deregister(&snd_cad_misc);
+ return rc;
+ }
+
+ rc = device_create_file(snd_cad_misc.this_device, &dev_attr_volume);
+ if (rc) {
+ device_remove_file(snd_cad_misc.this_device,
+ &dev_attr_device);
+ misc_deregister(&snd_cad_misc);
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ rc = rtc_debugfs_create_entry();
+ if (rc) {
+ device_remove_file(snd_cad_misc.this_device,
+ &dev_attr_volume);
+ device_remove_file(snd_cad_misc.this_device,
+ &dev_attr_device);
+ misc_deregister(&snd_cad_misc);
+ }
+#endif
+ return rc;
+}
+
+static struct platform_driver snd_cad_plat_driver = {
+ .probe = snd_cad_probe,
+ .driver = {
+ .name = "msm_cad",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init snd_cad_init(void)
+{
+ return platform_driver_register(&snd_cad_plat_driver);
+}
+
+module_init(snd_cad_init);
+
+MODULE_DESCRIPTION("MSM CAD SND driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index 2ea1bc9..0c75f66 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -10,7 +10,8 @@
obj-y += audio_mvs.o
obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
endif
-obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_tal.o q6core.o dsp_debug.o
+obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_v1.o apr_tal.o q6core.o dsp_debug.o
+obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o q6core.o dsp_debug.o
obj-y += audio_acdb.o
ifdef CONFIG_ARCH_MSM9615
obj-y += rtac.o
@@ -23,4 +24,5 @@
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += rtac_v2.o q6audio_v2.o q6audio_v2_aio.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
diff --git a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
new file mode 100644
index 0000000..9924b52
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -0,0 +1,100 @@
+/*
+ * 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 <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <mach/peripheral-loader.h>
+#include <mach/qdsp6v2/apr.h>
+
+#define Q6_PIL_GET_DELAY_MS 100
+
+struct adsp_loader_private {
+ void *pil_h;
+};
+
+static int adsp_loader_probe(struct platform_device *pdev)
+{
+ struct adsp_loader_private *priv;
+ int rc = 0;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ priv->pil_h = pil_get("adsp");
+ if (IS_ERR(priv->pil_h)) {
+ pr_err("%s: pil get adsp failed, error:%d\n", __func__, rc);
+ devm_kfree(&pdev->dev, priv);
+ goto fail;
+ }
+
+ /* Query the DSP to check if resources are available */
+ msleep(Q6_PIL_GET_DELAY_MS);
+
+ /* Set the state of the ADSP in APR driver */
+ apr_set_q6_state(APR_SUBSYS_LOADED);
+
+ /* Query for MMPM API */
+
+ pr_info("%s: Q6/ADSP image is loaded\n", __func__);
+fail:
+ return rc;
+}
+
+static int adsp_loader_remove(struct platform_device *pdev)
+{
+ struct adsp_loader_private *priv;
+
+ priv = platform_get_drvdata(pdev);
+ pil_put(priv->pil_h);
+ pr_info("%s: Q6/ADSP image is unloaded\n", __func__);
+
+ return 0;
+}
+
+static const struct of_device_id adsp_loader_dt_match[] = {
+ { .compatible = "qcom,adsp-loader" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adsp_loader_dt_match);
+
+static struct platform_driver adsp_loader_driver = {
+ .driver = {
+ .name = "adsp-loader",
+ .owner = THIS_MODULE,
+ .of_match_table = adsp_loader_dt_match,
+ },
+ .probe = adsp_loader_probe,
+ .remove = __devexit_p(adsp_loader_remove),
+};
+
+static int __init adsp_loader_init(void)
+{
+ return platform_driver_register(&adsp_loader_driver);
+}
+module_init(adsp_loader_init);
+
+static void __exit adsp_loader_exit(void)
+{
+ platform_driver_unregister(&adsp_loader_driver);
+}
+module_exit(adsp_loader_exit);
+
+MODULE_DESCRIPTION("ADSP Loader module");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
index a0bfb27..8ac1fea 100644
--- a/arch/arm/mach-msm/qdsp6v2/apr.c
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -15,7 +15,6 @@
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/spinlock.h>
-#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/wait.h>
@@ -36,13 +35,11 @@
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>
-struct apr_q6 q6;
-struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
-static atomic_t dsp_state;
-static atomic_t modem_state;
+static struct apr_q6 q6;
+static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
-static wait_queue_head_t dsp_wait;
-static wait_queue_head_t modem_wait;
+static wait_queue_head_t dsp_wait;
+static wait_queue_head_t modem_wait;
/* Subsystem restart: QDSP6 data, functions */
static struct workqueue_struct *apr_reset_workqueue;
static void apr_reset_deregister(struct work_struct *work);
@@ -51,6 +48,199 @@
struct work_struct work;
};
+struct apr_svc_table {
+ char name[64];
+ int idx;
+ int id;
+ int client_id;
+};
+
+static const struct apr_svc_table svc_tbl_audio[] = {
+ {
+ .name = "AFE",
+ .idx = 0,
+ .id = APR_SVC_AFE,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "ASM",
+ .idx = 1,
+ .id = APR_SVC_ASM,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "ADM",
+ .idx = 2,
+ .id = APR_SVC_ADM,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "CORE",
+ .idx = 3,
+ .id = APR_SVC_ADSP_CORE,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "TEST",
+ .idx = 4,
+ .id = APR_SVC_TEST_CLIENT,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "MVM",
+ .idx = 5,
+ .id = APR_SVC_ADSP_MVM,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "CVS",
+ .idx = 6,
+ .id = APR_SVC_ADSP_CVS,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "CVP",
+ .idx = 7,
+ .id = APR_SVC_ADSP_CVP,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+ {
+ .name = "USM",
+ .idx = 8,
+ .id = APR_SVC_USM,
+ .client_id = APR_CLIENT_AUDIO,
+ },
+};
+
+static struct apr_svc_table svc_tbl_voice[] = {
+ {
+ .name = "VSM",
+ .idx = 0,
+ .id = APR_SVC_VSM,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "VPM",
+ .idx = 1,
+ .id = APR_SVC_VPM,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "MVS",
+ .idx = 2,
+ .id = APR_SVC_MVS,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "MVM",
+ .idx = 3,
+ .id = APR_SVC_MVM,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "CVS",
+ .idx = 4,
+ .id = APR_SVC_CVS,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "CVP",
+ .idx = 5,
+ .id = APR_SVC_CVP,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "SRD",
+ .idx = 6,
+ .id = APR_SVC_SRD,
+ .client_id = APR_CLIENT_VOICE,
+ },
+ {
+ .name = "TEST",
+ .idx = 7,
+ .id = APR_SVC_TEST_CLIENT,
+ .client_id = APR_CLIENT_VOICE,
+ },
+};
+
+enum apr_subsys_state apr_get_modem_state(void)
+{
+ return atomic_read(&q6.modem_state);
+}
+
+void apr_set_modem_state(enum apr_subsys_state state)
+{
+ atomic_set(&q6.modem_state, state);
+}
+
+enum apr_subsys_state apr_cmpxchg_modem_state(enum apr_subsys_state prev,
+ enum apr_subsys_state new)
+{
+ return atomic_cmpxchg(&q6.modem_state, prev, new);
+}
+
+enum apr_subsys_state apr_get_q6_state(void)
+{
+ return atomic_read(&q6.q6_state);
+}
+EXPORT_SYMBOL_GPL(apr_get_q6_state);
+
+int apr_set_q6_state(enum apr_subsys_state state)
+{
+ pr_debug("%s: setting adsp state %d\n", __func__, state);
+ if (state < APR_SUBSYS_DOWN || state > APR_SUBSYS_LOADED)
+ return -EINVAL;
+ atomic_set(&q6.q6_state, state);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(apr_set_q6_state);
+
+enum apr_subsys_state apr_cmpxchg_q6_state(enum apr_subsys_state prev,
+ enum apr_subsys_state new)
+{
+ return atomic_cmpxchg(&q6.q6_state, prev, new);
+}
+
+int apr_wait_for_device_up(int dest_id)
+{
+ int rc = -1;
+ if (dest_id == APR_DEST_MODEM)
+ rc = wait_event_interruptible_timeout(modem_wait,
+ (apr_get_modem_state() == APR_SUBSYS_UP),
+ (1 * HZ));
+ else if (dest_id == APR_DEST_QDSP6)
+ rc = wait_event_interruptible_timeout(dsp_wait,
+ (apr_get_q6_state() == APR_SUBSYS_UP),
+ (1 * HZ));
+ else
+ pr_err("%s: unknown dest_id %d\n", __func__, dest_id);
+ /* returns left time */
+ return rc;
+}
+
+int apr_load_adsp_image(void)
+{
+ int rc = 0;
+ mutex_lock(&q6.lock);
+ if (apr_get_q6_state() == APR_SUBSYS_UP) {
+ q6.pil = pil_get("q6");
+ if (IS_ERR(q6.pil)) {
+ rc = PTR_ERR(q6.pil);
+ pr_err("APR: Unable to load q6 image, error:%d\n", rc);
+ } else {
+ apr_set_q6_state(APR_SUBSYS_LOADED);
+ pr_debug("APR: Image is loaded, stated\n");
+ }
+ } else
+ pr_debug("APR: cannot load state %d\n", apr_get_q6_state());
+ mutex_unlock(&q6.lock);
+ return rc;
+}
+
+struct apr_client *apr_get_client(int dest_id, int client_id)
+{
+ return &client[dest_id][client_id];
+}
int apr_send_pkt(void *handle, uint32_t *buf)
{
@@ -72,11 +262,11 @@
}
if ((svc->dest_id == APR_DEST_QDSP6) &&
- (atomic_read(&dsp_state) == 0)) {
- pr_err("apr: Still dsp is not Up\n");
+ (apr_get_q6_state() != APR_SUBSYS_LOADED)) {
+ pr_err("%s: Still dsp is not Up\n", __func__);
return -ENETRESET;
} else if ((svc->dest_id == APR_DEST_MODEM) &&
- (atomic_read(&modem_state) == 0)) {
+ (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
pr_err("apr: Still Modem is not Up\n");
return -ENETRESET;
}
@@ -111,7 +301,7 @@
return w_len;
}
-static void apr_cb_func(void *buf, int len, void *priv)
+void apr_cb_func(void *buf, int len, void *priv)
{
struct apr_client_data data;
struct apr_client *apr_client;
@@ -136,8 +326,7 @@
pr_debug("\n*****************\n");
if (!buf || len <= APR_HDR_SIZE) {
- pr_err("APR: Improper apr pkt received:%p %d\n",
- buf, len);
+ pr_err("APR: Improper apr pkt received:%p %d\n", buf, len);
return;
}
hdr = buf;
@@ -162,8 +351,7 @@
}
msg_type = hdr->hdr_field;
msg_type = (msg_type >> 0x08) & 0x0003;
- if (msg_type >= APR_MSG_TYPE_MAX &&
- msg_type != APR_BASIC_RSP_RESULT) {
+ if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) {
pr_err("APR: Wrong message type: %d\n", msg_type);
return;
}
@@ -180,8 +368,8 @@
if (hdr->src_domain == APR_DOMAIN_MODEM) {
src = APR_DEST_MODEM;
if (svc == APR_SVC_MVS || svc == APR_SVC_MVM ||
- svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
- svc == APR_SVC_TEST_CLIENT)
+ svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
+ svc == APR_SVC_TEST_CLIENT)
clnt = APR_CLIENT_VOICE;
else {
pr_err("APR: Wrong svc :%d\n", svc);
@@ -190,11 +378,11 @@
} else if (hdr->src_domain == APR_DOMAIN_ADSP) {
src = APR_DEST_QDSP6;
if (svc == APR_SVC_AFE || svc == APR_SVC_ASM ||
- svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
- svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
- svc == APR_SVC_USM ||
- svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
- svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
+ svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
+ svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
+ svc == APR_SVC_USM ||
+ svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
+ svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
clnt = APR_CLIENT_AUDIO;
else {
pr_err("APR: Wrong svc :%d\n", svc);
@@ -220,7 +408,7 @@
}
pr_debug("svc_idx = %d\n", i);
pr_debug("%x %x %x %p %p\n", c_svc->id, c_svc->dest_id,
- c_svc->client_id, c_svc->fn, c_svc->priv);
+ c_svc->client_id, c_svc->fn, c_svc->priv);
data.payload_size = hdr->pkt_size - hdr_size;
data.opcode = hdr->opcode;
data.src = src;
@@ -241,199 +429,39 @@
pr_err("APR: Rxed a packet for NULL callback\n");
}
-struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
- uint32_t src_port, void *priv)
+int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
+ int *svc_idx, int *svc_id)
{
- int client_id = 0;
- int svc_idx = 0;
- int svc_id = 0;
- int dest_id = 0;
- int temp_port = 0;
- struct apr_svc *svc = NULL;
- int rc = 0;
+ int i;
+ int size;
+ struct apr_svc_table *tbl;
+ int ret = 0;
- if (!dest || !svc_name || !svc_fn)
- return NULL;
-
- if (!strncmp(dest, "ADSP", 4))
- dest_id = APR_DEST_QDSP6;
- else if (!strncmp(dest, "MODEM", 5)) {
- dest_id = APR_DEST_MODEM;
+ if (dest_id == APR_DEST_QDSP6) {
+ tbl = (struct apr_svc_table *)&svc_tbl_audio;
+ size = ARRAY_SIZE(svc_tbl_audio);
} else {
- pr_err("APR: wrong destination\n");
- goto done;
+ tbl = (struct apr_svc_table *)&svc_tbl_voice;
+ size = ARRAY_SIZE(svc_tbl_voice);
}
- if ((dest_id == APR_DEST_QDSP6) &&
- (atomic_read(&dsp_state) == 0)) {
- pr_info("%s: Wait for Lpass to bootup\n", __func__);
- rc = wait_event_interruptible_timeout(dsp_wait,
- (atomic_read(&dsp_state) == 1), (1 * HZ));
- if (rc == 0) {
- pr_err("%s: DSP is not Up\n", __func__);
- return NULL;
- }
- pr_info("%s: Lpass Up\n", __func__);
- } else if ((dest_id == APR_DEST_MODEM) &&
- (atomic_read(&modem_state) == 0)) {
- pr_info("%s: Wait for modem to bootup\n", __func__);
- rc = wait_event_interruptible_timeout(modem_wait,
- (atomic_read(&modem_state) == 1), (1 * HZ));
- if (rc == 0) {
- pr_err("%s: Modem is not Up\n", __func__);
- return NULL;
- }
- pr_info("%s: modem Up\n", __func__);
- }
-
- if (!strncmp(svc_name, "AFE", 3)) {
- client_id = APR_CLIENT_AUDIO;
- svc_idx = 0;
- svc_id = APR_SVC_AFE;
- } else if (!strncmp(svc_name, "ASM", 3)) {
- client_id = APR_CLIENT_AUDIO;
- svc_idx = 1;
- svc_id = APR_SVC_ASM;
- } else if (!strncmp(svc_name, "ADM", 3)) {
- client_id = APR_CLIENT_AUDIO;
- svc_idx = 2;
- svc_id = APR_SVC_ADM;
- } else if (!strncmp(svc_name, "CORE", 4)) {
- client_id = APR_CLIENT_AUDIO;
- svc_idx = 3;
- svc_id = APR_SVC_ADSP_CORE;
- } else if (!strncmp(svc_name, "TEST", 4)) {
- if (dest_id == APR_DEST_QDSP6) {
- client_id = APR_CLIENT_AUDIO;
- svc_idx = 4;
- } else {
- client_id = APR_CLIENT_VOICE;
- svc_idx = 7;
- }
- svc_id = APR_SVC_TEST_CLIENT;
- } else if (!strncmp(svc_name, "VSM", 3)) {
- client_id = APR_CLIENT_VOICE;
- svc_idx = 0;
- svc_id = APR_SVC_VSM;
- } else if (!strncmp(svc_name, "VPM", 3)) {
- client_id = APR_CLIENT_VOICE;
- svc_idx = 1;
- svc_id = APR_SVC_VPM;
- } else if (!strncmp(svc_name, "MVS", 3)) {
- client_id = APR_CLIENT_VOICE;
- svc_idx = 2;
- svc_id = APR_SVC_MVS;
- } else if (!strncmp(svc_name, "MVM", 3)) {
- if (dest_id == APR_DEST_MODEM) {
- client_id = APR_CLIENT_VOICE;
- svc_idx = 3;
- svc_id = APR_SVC_MVM;
- } else {
- client_id = APR_CLIENT_AUDIO;
- svc_idx = 5;
- svc_id = APR_SVC_ADSP_MVM;
- }
- } else if (!strncmp(svc_name, "CVS", 3)) {
- if (dest_id == APR_DEST_MODEM) {
- client_id = APR_CLIENT_VOICE;
- svc_idx = 4;
- svc_id = APR_SVC_CVS;
- } else {
- client_id = APR_CLIENT_AUDIO;
- svc_idx = 6;
- svc_id = APR_SVC_ADSP_CVS;
- }
- } else if (!strncmp(svc_name, "CVP", 3)) {
- if (dest_id == APR_DEST_MODEM) {
- client_id = APR_CLIENT_VOICE;
- svc_idx = 5;
- svc_id = APR_SVC_CVP;
- } else {
- client_id = APR_CLIENT_AUDIO;
- svc_idx = 7;
- svc_id = APR_SVC_ADSP_CVP;
- }
- } else if (!strncmp(svc_name, "SRD", 3)) {
- client_id = APR_CLIENT_VOICE;
- svc_idx = 6;
- svc_id = APR_SVC_SRD;
- } else if (!strncmp(svc_name, "USM", 3)) {
- client_id = APR_CLIENT_AUDIO;
- svc_idx = 8;
- svc_id = APR_SVC_USM;
- } else {
- pr_err("APR: Wrong svc name\n");
- goto done;
- }
-
- pr_debug("svc name = %s c_id = %d dest_id = %d\n",
- svc_name, client_id, dest_id);
- mutex_lock(&q6.lock);
- if (q6.state == APR_Q6_NOIMG) {
- q6.pil = pil_get("q6");
- if (IS_ERR(q6.pil)) {
- q6.pil = pil_get("adsp");
- if (IS_ERR(q6.pil)) {
- rc = PTR_ERR(q6.pil);
- pr_err("APR: Unable to load q6 image, error:%d\n",
- rc);
- mutex_unlock(&q6.lock);
- return svc;
- }
- }
- q6.state = APR_Q6_LOADED;
- }
- mutex_unlock(&q6.lock);
- mutex_lock(&client[dest_id][client_id].m_lock);
- if (!client[dest_id][client_id].handle) {
- client[dest_id][client_id].handle = apr_tal_open(client_id,
- dest_id, APR_DL_SMD, apr_cb_func, NULL);
- if (!client[dest_id][client_id].handle) {
- svc = NULL;
- pr_err("APR: Unable to open handle\n");
- mutex_unlock(&client[dest_id][client_id].m_lock);
- goto done;
- }
- }
- mutex_unlock(&client[dest_id][client_id].m_lock);
- svc = &client[dest_id][client_id].svc[svc_idx];
- mutex_lock(&svc->m_lock);
- client[dest_id][client_id].id = client_id;
- if (svc->need_reset) {
- mutex_unlock(&svc->m_lock);
- pr_err("APR: Service needs reset\n");
- goto done;
- }
- svc->priv = priv;
- svc->id = svc_id;
- svc->dest_id = dest_id;
- svc->client_id = client_id;
- if (src_port != 0xFFFFFFFF) {
- temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
- pr_debug("port = %d t_port = %d\n", src_port, temp_port);
- if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
- pr_err("APR: temp_port out of bounds\n");
- mutex_unlock(&svc->m_lock);
- return NULL;
- }
- if (!svc->port_cnt && !svc->svc_cnt)
- client[dest_id][client_id].svc_cnt++;
- svc->port_cnt++;
- svc->port_fn[temp_port] = svc_fn;
- svc->port_priv[temp_port] = priv;
- } else {
- if (!svc->fn) {
- if (!svc->port_cnt && !svc->svc_cnt)
- client[dest_id][client_id].svc_cnt++;
- svc->fn = svc_fn;
- if (svc->port_cnt)
- svc->svc_cnt++;
+ for (i = 0; i < size; i++) {
+ if (!strncmp(svc_name, tbl[i].name, strlen(tbl[i].name))) {
+ *client_id = tbl[i].client_id;
+ *svc_idx = tbl[i].idx;
+ *svc_id = tbl[i].id;
+ break;
}
}
- mutex_unlock(&svc->m_lock);
-done:
- return svc;
+ pr_debug("%s: svc_name = %s c_id = %d dest_id = %d\n",
+ __func__, svc_name, *client_id, dest_id);
+ if (i == size) {
+ pr_err("%s: APR: Wrong svc name %s\n", __func__, svc_name);
+ ret = -EINVAL;
+ }
+
+ return ret;
}
static void apr_reset_deregister(struct work_struct *work)
@@ -489,7 +517,7 @@
svc->need_reset = 0x0;
}
if (client[dest_id][client_id].handle &&
- !client[dest_id][client_id].svc_cnt) {
+ !client[dest_id][client_id].svc_cnt) {
apr_tal_close(client[dest_id][client_id].handle);
client[dest_id][client_id].handle = NULL;
}
@@ -524,14 +552,7 @@
queue_work(apr_reset_workqueue, &apr_reset_worker->work);
}
-void change_q6_state(int state)
-{
- mutex_lock(&q6.lock);
- q6.state = state;
- mutex_unlock(&q6.lock);
-}
-
-int adsp_state(int state)
+static int adsp_state(int state)
{
pr_info("dsp state = %d\n", state);
return 0;
@@ -590,12 +611,12 @@
}
static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
- void *_cmd)
+ void *_cmd)
{
switch (code) {
case SUBSYS_BEFORE_SHUTDOWN:
pr_debug("M-Notify: Shutdown started\n");
- atomic_set(&modem_state, 0);
+ apr_set_modem_state(APR_SUBSYS_DOWN);
dispatch_event(code, APR_DEST_MODEM);
break;
case SUBSYS_AFTER_SHUTDOWN:
@@ -605,10 +626,9 @@
pr_debug("M-notify: Bootup started\n");
break;
case SUBSYS_AFTER_POWERUP:
- if (atomic_read(&modem_state) == 0) {
- atomic_set(&modem_state, 1);
+ if (apr_cmpxchg_modem_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
+ APR_SUBSYS_DOWN)
wake_up(&modem_wait);
- }
pr_debug("M-Notify: Bootup Completed\n");
break;
default:
@@ -623,12 +643,12 @@
};
static int lpass_notifier_cb(struct notifier_block *this, unsigned long code,
- void *_cmd)
+ void *_cmd)
{
switch (code) {
case SUBSYS_BEFORE_SHUTDOWN:
pr_debug("L-Notify: Shutdown started\n");
- atomic_set(&dsp_state, 0);
+ apr_set_q6_state(APR_SUBSYS_DOWN);
dispatch_event(code, APR_DEST_QDSP6);
break;
case SUBSYS_AFTER_SHUTDOWN:
@@ -638,10 +658,9 @@
pr_debug("L-notify: Bootup started\n");
break;
case SUBSYS_AFTER_POWERUP:
- if (atomic_read(&dsp_state) == 0) {
- atomic_set(&dsp_state, 1);
+ if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_UP) ==
+ APR_SUBSYS_DOWN)
wake_up(&dsp_wait);
- }
pr_debug("L-Notify: Bootup Completed\n");
break;
default:
@@ -668,10 +687,10 @@
spin_lock_init(&client[i][j].svc[k].w_lock);
}
}
+ apr_set_subsys_state();
mutex_init(&q6.lock);
dsp_debug_register(adsp_state);
- apr_reset_workqueue =
- create_singlethread_workqueue("apr_driver");
+ apr_reset_workqueue = create_singlethread_workqueue("apr_driver");
if (!apr_reset_workqueue)
return -ENOMEM;
return 0;
@@ -683,8 +702,6 @@
int ret = 0;
init_waitqueue_head(&dsp_wait);
init_waitqueue_head(&modem_wait);
- atomic_set(&dsp_state, 1);
- atomic_set(&modem_state, 1);
subsys_notif_register_notifier("modem", &mnb);
subsys_notif_register_notifier("lpass", &lnb);
return ret;
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v1.c b/arch/arm/mach-msm/qdsp6v2/apr_v1.c
new file mode 100644
index 0000000..9535968
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v1.c
@@ -0,0 +1,133 @@
+/*
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/err.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/qdsp6v2/apr_tal.h>
+#include <mach/qdsp6v2/dsp_debug.h>
+#include <mach/peripheral-loader.h>
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+ uint32_t src_port, void *priv)
+{
+ struct apr_client *client;
+ int client_id = 0;
+ int svc_idx = 0;
+ int svc_id = 0;
+ int dest_id = 0;
+ int temp_port = 0;
+ struct apr_svc *svc = NULL;
+ int rc = 0;
+
+ if (!dest || !svc_name || !svc_fn)
+ return NULL;
+
+ if (!strncmp(dest, "ADSP", 4))
+ dest_id = APR_DEST_QDSP6;
+ else if (!strncmp(dest, "MODEM", 5)) {
+ dest_id = APR_DEST_MODEM;
+ } else {
+ pr_err("APR: wrong destination\n");
+ goto done;
+ }
+
+ if (dest_id == APR_DEST_QDSP6 &&
+ apr_get_q6_state() == APR_SUBSYS_DOWN) {
+ pr_info("%s: Wait for Lpass to bootup\n", __func__);
+ rc = apr_wait_for_device_up(dest_id);
+ if (rc == 0) {
+ pr_err("%s: DSP is not Up\n", __func__);
+ return NULL;
+ }
+ pr_info("%s: Lpass Up\n", __func__);
+ } else if (dest_id == APR_DEST_MODEM &&
+ (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
+ pr_info("%s: Wait for modem to bootup\n", __func__);
+ rc = apr_wait_for_device_up(dest_id);
+ if (rc == 0) {
+ pr_err("%s: Modem is not Up\n", __func__);
+ return NULL;
+ }
+ pr_info("%s: modem Up\n", __func__);
+ }
+
+ if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
+ pr_err("%s: apr_get_svc failed\n", __func__);
+ goto done;
+ }
+
+ /* APRv1 loads ADSP image automatically */
+ apr_load_adsp_image();
+
+ client = apr_get_client(dest_id, client_id);
+ mutex_lock(&client->m_lock);
+ if (!client->handle) {
+ client->handle = apr_tal_open(client_id, dest_id, APR_DL_SMD,
+ apr_cb_func, NULL);
+ if (!client->handle) {
+ svc = NULL;
+ pr_err("APR: Unable to open handle\n");
+ mutex_unlock(&client->m_lock);
+ goto done;
+ }
+ }
+ mutex_unlock(&client->m_lock);
+ svc = &client->svc[svc_idx];
+ mutex_lock(&svc->m_lock);
+ client->id = client_id;
+ if (svc->need_reset) {
+ mutex_unlock(&svc->m_lock);
+ pr_err("APR: Service needs reset\n");
+ goto done;
+ }
+ svc->priv = priv;
+ svc->id = svc_id;
+ svc->dest_id = dest_id;
+ svc->client_id = client_id;
+ if (src_port != 0xFFFFFFFF) {
+ temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
+ pr_debug("port = %d t_port = %d\n", src_port, temp_port);
+ if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
+ pr_err("APR: temp_port out of bounds\n");
+ mutex_unlock(&svc->m_lock);
+ return NULL;
+ }
+ if (!svc->port_cnt && !svc->svc_cnt)
+ client->svc_cnt++;
+ svc->port_cnt++;
+ svc->port_fn[temp_port] = svc_fn;
+ svc->port_priv[temp_port] = priv;
+ } else {
+ if (!svc->fn) {
+ if (!svc->port_cnt && !svc->svc_cnt)
+ client->svc_cnt++;
+ svc->fn = svc_fn;
+ if (svc->port_cnt)
+ svc->svc_cnt++;
+ }
+ }
+
+ mutex_unlock(&svc->m_lock);
+done:
+ return svc;
+}
+
+void apr_set_subsys_state(void)
+{
+ apr_set_q6_state(APR_SUBSYS_UP);
+ apr_set_modem_state(APR_SUBSYS_UP);
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_v2.c b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
new file mode 100644
index 0000000..1ef189f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/apr_v2.c
@@ -0,0 +1,127 @@
+/*
+ * 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 <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/qdsp6v2/apr_tal.h>
+#include <mach/qdsp6v2/dsp_debug.h>
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+ uint32_t src_port, void *priv)
+{
+ struct apr_client *client;
+ int client_id = 0;
+ int svc_idx = 0;
+ int svc_id = 0;
+ int dest_id = 0;
+ int temp_port = 0;
+ struct apr_svc *svc = NULL;
+ int rc = 0;
+
+ if (!dest || !svc_name || !svc_fn)
+ return NULL;
+
+ if (!strncmp(dest, "ADSP", 4))
+ dest_id = APR_DEST_QDSP6;
+ else if (!strncmp(dest, "MODEM", 5)) {
+ dest_id = APR_DEST_MODEM;
+ } else {
+ pr_err("APR: wrong destination\n");
+ goto done;
+ }
+
+ if ((dest_id == APR_DEST_QDSP6)) {
+ if (apr_get_q6_state() != APR_SUBSYS_LOADED) {
+ pr_err("%s: adsp not up\n", __func__);
+ return NULL;
+ }
+ pr_info("%s: Lpass Up\n", __func__);
+ } else if ((dest_id == APR_DEST_MODEM) &&
+ (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
+ pr_info("%s: Wait for modem to bootup\n", __func__);
+ rc = apr_wait_for_device_up(dest_id);
+ if (rc == 0) {
+ pr_err("%s: Modem is not Up\n", __func__);
+ return NULL;
+ }
+ pr_info("%s: modem Up\n", __func__);
+ }
+
+ if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
+ pr_err("%s: apr_get_svc failed\n", __func__);
+ goto done;
+ }
+
+ /* APRv2 doen't load ADSP image automatically */
+
+ client = apr_get_client(dest_id, client_id);
+ mutex_lock(&client->m_lock);
+ if (!client->handle) {
+ client->handle = apr_tal_open(client_id, dest_id, APR_DL_SMD,
+ apr_cb_func, NULL);
+ if (!client->handle) {
+ svc = NULL;
+ pr_err("APR: Unable to open handle\n");
+ mutex_unlock(&client->m_lock);
+ goto done;
+ }
+ }
+ mutex_unlock(&client->m_lock);
+ svc = &client->svc[svc_idx];
+ mutex_lock(&svc->m_lock);
+ client->id = client_id;
+ if (svc->need_reset) {
+ mutex_unlock(&svc->m_lock);
+ pr_err("APR: Service needs reset\n");
+ goto done;
+ }
+ svc->priv = priv;
+ svc->id = svc_id;
+ svc->dest_id = dest_id;
+ svc->client_id = client_id;
+ if (src_port != 0xFFFFFFFF) {
+ temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
+ pr_debug("port = %d t_port = %d\n", src_port, temp_port);
+ if (temp_port >= APR_MAX_PORTS || temp_port < 0) {
+ pr_err("APR: temp_port out of bounds\n");
+ mutex_unlock(&svc->m_lock);
+ return NULL;
+ }
+ if (!svc->port_cnt && !svc->svc_cnt)
+ client->svc_cnt++;
+ svc->port_cnt++;
+ svc->port_fn[temp_port] = svc_fn;
+ svc->port_priv[temp_port] = priv;
+ } else {
+ if (!svc->fn) {
+ if (!svc->port_cnt && !svc->svc_cnt)
+ client->svc_cnt++;
+ svc->fn = svc_fn;
+ if (svc->port_cnt)
+ svc->svc_cnt++;
+ }
+ }
+
+ mutex_unlock(&svc->m_lock);
+done:
+ return svc;
+}
+
+void apr_set_subsys_state(void)
+{
+ apr_set_q6_state(APR_SUBSYS_DOWN);
+ apr_set_modem_state(APR_SUBSYS_UP);
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
index edb1e7d..d7de50e 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.c
@@ -337,7 +337,7 @@
if (apr_handle_q)
apr_deregister(apr_handle_q);
} else if (!strncmp(l_buf + 20, "loaded", 64)) {
- change_q6_state(APR_Q6_LOADED);
+ apr_set_q6_state(APR_SUBSYS_LOADED);
} else if (!strncmp(l_buf + 20, "boom", 64)) {
q6audio_dsp_not_responding();
} else if (!strncmp(l_buf + 20, "dsp_ver", 64)) {
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 7288c1d..aac83e5 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -47,6 +47,12 @@
#define SCM_IO_DISABLE_PMIC_ARBITER 1
+#ifdef CONFIG_MSM_RESTART_V2
+#define use_restart_v2() 1
+#else
+#define use_restart_v2() 0
+#endif
+
static int restart_mode;
void *restart_reason;
@@ -177,9 +183,8 @@
return IRQ_HANDLED;
}
-void msm_restart(char mode, const char *cmd)
+static void msm_restart_prepare(const char *cmd)
{
-
#ifdef CONFIG_MSM_DLOAD_MODE
/* This looks like a normal reboot at this point. */
@@ -197,8 +202,6 @@
set_dload_mode(0);
#endif
- printk(KERN_NOTICE "Going down for restart now\n");
-
pm8xxx_reset_pwr_off(1);
if (cmd != NULL) {
@@ -214,19 +217,31 @@
__raw_writel(0x77665501, restart_reason);
}
}
+}
- __raw_writel(0, msm_tmr0_base + WDT0_EN);
- if (!(machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())) {
- mb();
- __raw_writel(0, PSHOLD_CTL_SU); /* Actually reset the chip */
- mdelay(5000);
- pr_notice("PS_HOLD didn't work, falling back to watchdog\n");
- }
+void msm_restart(char mode, const char *cmd)
+{
+ printk(KERN_NOTICE "Going down for restart now\n");
- __raw_writel(1, msm_tmr0_base + WDT0_RST);
- __raw_writel(5*0x31F3, msm_tmr0_base + WDT0_BARK_TIME);
- __raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME);
- __raw_writel(1, msm_tmr0_base + WDT0_EN);
+ msm_restart_prepare(cmd);
+
+ if (!use_restart_v2()) {
+ __raw_writel(0, msm_tmr0_base + WDT0_EN);
+ if (!(machine_is_msm8x60_fusion() ||
+ machine_is_msm8x60_fusn_ffa())) {
+ mb();
+ /* Actually reset the chip */
+ __raw_writel(0, PSHOLD_CTL_SU);
+ mdelay(5000);
+ pr_notice("PS_HOLD didn't work, falling back to watchdog\n");
+ }
+
+ __raw_writel(1, msm_tmr0_base + WDT0_RST);
+ __raw_writel(5*0x31F3, msm_tmr0_base + WDT0_BARK_TIME);
+ __raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME);
+ __raw_writel(1, msm_tmr0_base + WDT0_EN);
+ } else
+ __raw_writel(0, MSM_MPM2_PSHOLD_BASE);
mdelay(10000);
printk(KERN_ERR "Restarting has failed\n");
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 0faafc8..cd5556a 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -62,9 +62,10 @@
#define DEFAULT_BUFFER_SIZE 256
#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
-#define INV_HDR "resource does not exist"
+#define INV_RSC "resource does not exist"
#define ERR "err\0"
-#define MAX_ERR_BUFFER_SIZE 60
+#define MAX_ERR_BUFFER_SIZE 128
+#define INIT_ERROR 1
static ATOMIC_NOTIFIER_HEAD(msm_rpm_sleep_notifier);
static bool standalone;
@@ -171,8 +172,10 @@
int i;
int data_size, msg_size;
- if (!handle)
+ if (!handle) {
+ pr_err("%s(): Invalid handle\n", __func__);
return -EINVAL;
+ }
data_size = ALIGN(size, SZ_4);
msg_size = data_size + sizeof(struct rpm_request_header);
@@ -190,8 +193,11 @@
break;
}
- if (i >= handle->num_elements)
+ if (i >= handle->num_elements) {
+ pr_err("%s(): Number of resources exceeds max allocated\n",
+ __func__);
return -ENOMEM;
+ }
if (i == handle->write_idx)
handle->write_idx++;
@@ -199,8 +205,10 @@
if (!handle->kvp[i].value) {
handle->kvp[i].value = kzalloc(data_size, GFP_FLAG(noirq));
- if (!handle->kvp[i].value)
+ if (!handle->kvp[i].value) {
+ pr_err("%s(): Failed malloc\n", __func__);
return -ENOMEM;
+ }
} else {
/* We enter the else case, if a key already exists but the
* data doesn't match. In which case, we should zero the data
@@ -365,13 +373,20 @@
return elem;
}
-static int msm_rpm_get_next_msg_id(void)
+static uint32_t msm_rpm_get_next_msg_id(void)
{
- int id;
+ uint32_t id;
+
+ /*
+ * A message id of 0 is used by the driver to indicate a error
+ * condition. The RPM driver uses a id of 1 to indicate unsent data
+ * when the data sent over hasn't been modified. This isn't a error
+ * scenario and wait for ack returns a success when the message id is 1.
+ */
do {
id = atomic_inc_return(&msm_rpm_msg_id);
- } while ((id == 0) || msm_rpm_get_entry_from_msg_id(id));
+ } while ((id == 0) || (id == 1) || msm_rpm_get_entry_from_msg_id(id));
return id;
}
@@ -388,6 +403,7 @@
init_completion(&data->ack);
data->ack_recd = false;
data->msg_id = msg_id;
+ data->errno = INIT_ERROR;
spin_lock_irqsave(&msm_rpm_list_lock, flags);
list_add(&data->list, &msm_rpm_wait_list);
spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
@@ -457,13 +473,17 @@
tmp += 2 * sizeof(uint32_t);
- if (!(memcmp(tmp, INV_HDR, min(req_len, sizeof(INV_HDR))-1)))
+ if (!(memcmp(tmp, INV_RSC, min(req_len, sizeof(INV_RSC))-1))) {
+ pr_err("%s(): RPM NACK Unsupported resource\n", __func__);
rc = -EINVAL;
+ } else {
+ pr_err("%s(): RPM NACK Invalid header\n", __func__);
+ }
return rc;
}
-static void msm_rpm_read_smd_data(char *buf)
+static int msm_rpm_read_smd_data(char *buf)
{
int pkt_sz;
int bytes_read = 0;
@@ -473,7 +493,7 @@
BUG_ON(pkt_sz > MAX_ERR_BUFFER_SIZE);
if (pkt_sz != smd_read_avail(msm_rpm_data.ch_info))
- return;
+ return -EAGAIN;
BUG_ON(pkt_sz == 0);
@@ -487,6 +507,8 @@
} while (pkt_sz > 0);
BUG_ON(pkt_sz < 0);
+
+ return 0;
}
static void msm_rpm_smd_work(struct work_struct *work)
@@ -498,11 +520,15 @@
while (smd_is_pkt_avail(msm_rpm_data.ch_info) && !irq_process) {
spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
- msm_rpm_read_smd_data(buf);
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
+ if (msm_rpm_read_smd_data(buf)) {
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read,
+ flags);
+ break;
+ }
msg_id = msm_rpm_get_msg_id_from_ack(buf);
errno = msm_rpm_get_error_from_ack(buf);
msm_rpm_process_ack(msg_id, errno);
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
}
}
@@ -650,7 +676,8 @@
int req_hdr_sz, msg_hdr_sz;
if (!cdata->msg_hdr.data_len)
- return 0;
+ return 1;
+
req_hdr_sz = sizeof(cdata->req_hdr);
msg_hdr_sz = sizeof(cdata->msg_hdr);
@@ -668,8 +695,10 @@
cdata->buf = kzalloc(msg_size, GFP_FLAG(noirq));
}
- if (!cdata->buf)
+ if (!cdata->buf) {
+ pr_err("%s(): Failed malloc\n", __func__);
return 0;
+ }
tmpbuff = cdata->buf;
@@ -714,7 +743,7 @@
ret = smd_write_avail(msm_rpm_data.ch_info);
if (ret < 0) {
- pr_warn("%s(): SMD not initialized\n", __func__);
+ pr_err("%s(): SMD not initialized\n", __func__);
spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
return 0;
}
@@ -741,7 +770,7 @@
} else if (ret < msg_size) {
struct msm_rpm_wait_data *rc;
ret = 0;
- pr_info("Failed to write data msg_size:%d ret:%d\n",
+ pr_err("Failed to write data msg_size:%d ret:%d\n",
msg_size, ret);
rc = msm_rpm_get_entry_from_msg_id(cdata->msg_hdr.msg_id);
if (rc)
@@ -765,10 +794,14 @@
int msm_rpm_wait_for_ack(uint32_t msg_id)
{
struct msm_rpm_wait_data *elem;
- int rc = 0;
- if (!msg_id)
- return -EINVAL;
+ if (!msg_id) {
+ pr_err("%s(): Invalid msg id\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (msg_id == 1)
+ return 0;
if (standalone)
return 0;
@@ -777,15 +810,9 @@
if (!elem)
return 0;
- rc = wait_for_completion_timeout(&elem->ack, msecs_to_jiffies(1));
- if (!rc) {
- pr_warn("%s(): Timed out after 1 ms\n", __func__);
- rc = -ETIMEDOUT;
- } else {
- rc = elem->errno;
- msm_rpm_free_list_entry(elem);
- }
- return rc;
+ wait_for_completion(&elem->ack);
+ msm_rpm_free_list_entry(elem);
+ return elem->errno;
}
EXPORT_SYMBOL(msm_rpm_wait_for_ack);
@@ -797,8 +824,13 @@
uint32_t id = 0;
int count = 0;
- if (!msg_id)
- return -EINVAL;
+ if (!msg_id) {
+ pr_err("%s(): Invalid msg id\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (msg_id == 1)
+ return 0;
if (standalone)
return 0;
@@ -814,6 +846,12 @@
*/
goto wait_ack_cleanup;
+ if (elem->errno != INIT_ERROR) {
+ rc = elem->errno;
+ msm_rpm_free_list_entry(elem);
+ goto wait_ack_cleanup;
+ }
+
while ((id != msg_id) && (count++ < 10)) {
if (smd_is_pkt_avail(msm_rpm_data.ch_info)) {
int errno;
@@ -950,10 +988,7 @@
complete(&msm_rpm_data.smd_open);
}
- ret = wait_for_completion_timeout(&msm_rpm_data.smd_open,
- msecs_to_jiffies(5));
-
- BUG_ON(!ret);
+ wait_for_completion(&msm_rpm_data.smd_open);
smd_disable_read_intr(msm_rpm_data.ch_info);
diff --git a/arch/arm/mach-msm/scm-boot.c b/arch/arm/mach-msm/scm-boot.c
index e377633..01d0853 100644
--- a/arch/arm/mach-msm/scm-boot.c
+++ b/arch/arm/mach-msm/scm-boot.c
@@ -19,11 +19,11 @@
/*
* Set the cold/warm boot address for one of the CPU cores.
*/
-int scm_set_boot_addr(void *addr, int flags)
+int scm_set_boot_addr(phys_addr_t addr, unsigned int flags)
{
struct {
unsigned int flags;
- void *addr;
+ unsigned long addr;
} cmd;
cmd.addr = addr;
diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-msm/scm-boot.h
index 221ffca..0d0e6aa 100644
--- a/arch/arm/mach-msm/scm-boot.h
+++ b/arch/arm/mach-msm/scm-boot.h
@@ -22,9 +22,12 @@
#define SCM_FLAG_WARMBOOT_CPU3 0x40
#ifdef CONFIG_MSM_SCM
-int scm_set_boot_addr(void *addr, int flags);
+int scm_set_boot_addr(phys_addr_t addr, unsigned int flags);
#else
-static inline int scm_set_boot_addr(void *addr, int flags) { return 0; }
+static inline int scm_set_boot_addr(phys_addr_t addr, unsigned int flags)
+{
+ return 0;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index decee95..e82e44b 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -2264,13 +2264,17 @@
int smd_is_pkt_avail(smd_channel_t *ch)
{
+ unsigned long flags;
+
if (!ch || !ch->is_pkt_ch)
return -EINVAL;
if (ch->current_packet)
return 1;
+ spin_lock_irqsave(&smd_lock, flags);
update_packet_state(ch);
+ spin_unlock_irqrestore(&smd_lock, flags);
return ch->current_packet ? 1 : 0;
}
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 39fbba8..ea0b7a3 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -114,6 +114,14 @@
uint32_t hw_platform_subtype;
};
+struct socinfo_v7 {
+ struct socinfo_v6 v6;
+
+ /* only valid when format==7 */
+ uint32_t pmic_model;
+ uint32_t pmic_die_revision;
+};
+
static union {
struct socinfo_v1 v1;
struct socinfo_v2 v2;
@@ -121,6 +129,7 @@
struct socinfo_v4 v4;
struct socinfo_v5 v5;
struct socinfo_v6 v6;
+ struct socinfo_v7 v7;
} *socinfo;
static enum msm_cpu cpu_of_id[] = {
@@ -246,6 +255,7 @@
[127] = MSM_CPU_8625,
[128] = MSM_CPU_8625,
[129] = MSM_CPU_8625,
+ [137] = MSM_CPU_8625,
/* 8064 MPQ ID */
[130] = MSM_CPU_8064,
@@ -343,6 +353,21 @@
: 0;
}
+enum pmic_model socinfo_get_pmic_model(void)
+{
+ return socinfo ?
+ (socinfo->v1.format >= 7 ? socinfo->v7.pmic_model
+ : PMIC_MODEL_UNKNOWN)
+ : PMIC_MODEL_UNKNOWN;
+}
+
+uint32_t socinfo_get_pmic_die_revision(void)
+{
+ return socinfo ?
+ (socinfo->v1.format >= 7 ? socinfo->v7.pmic_die_revision : 0)
+ : 0;
+}
+
enum msm_cpu socinfo_get_msm_cpu(void)
{
return cur_cpu;
@@ -515,6 +540,42 @@
hw_platform_subtype[hw_subtype]);
}
+static ssize_t
+socinfo_show_pmic_model(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ if (!socinfo) {
+ pr_err("%s: No socinfo found!\n", __func__);
+ return 0;
+ }
+ if (socinfo->v1.format < 7) {
+ pr_err("%s: pmic_model not available!\n", __func__);
+ return 0;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ socinfo_get_pmic_model());
+}
+
+static ssize_t
+socinfo_show_pmic_die_revision(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ if (!socinfo) {
+ pr_err("%s: No socinfo found!\n", __func__);
+ return 0;
+ }
+ if (socinfo->v1.format < 7) {
+ pr_err("%s: pmic_die_revision not available!\n", __func__);
+ return 0;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ socinfo_get_pmic_die_revision());
+}
+
static struct sysdev_attribute socinfo_v1_files[] = {
_SYSDEV_ATTR(id, 0444, socinfo_show_id, NULL),
_SYSDEV_ATTR(version, 0444, socinfo_show_version, NULL),
@@ -545,6 +606,13 @@
socinfo_show_platform_subtype, NULL),
};
+static struct sysdev_attribute socinfo_v7_files[] = {
+ _SYSDEV_ATTR(pmic_model, 0444,
+ socinfo_show_pmic_model, NULL),
+ _SYSDEV_ATTR(pmic_die_revision, 0444,
+ socinfo_show_pmic_die_revision, NULL),
+};
+
static struct sysdev_class soc_sysdev_class = {
.name = "soc",
};
@@ -619,9 +687,14 @@
if (socinfo->v1.format < 6)
return err;
- return socinfo_create_files(&soc_sys_device, socinfo_v6_files,
+ socinfo_create_files(&soc_sys_device, socinfo_v6_files,
ARRAY_SIZE(socinfo_v6_files));
+ if (socinfo->v1.format < 7)
+ return err;
+
+ return socinfo_create_files(&soc_sys_device, socinfo_v7_files,
+ ARRAY_SIZE(socinfo_v7_files));
}
arch_initcall(socinfo_init_sysdev);
@@ -649,7 +722,11 @@
int __init socinfo_init(void)
{
- socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v6));
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v7));
+
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v6));
if (!socinfo)
socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
@@ -741,6 +818,20 @@
socinfo->v5.accessory_chip,
socinfo->v6.hw_platform_subtype);
break;
+ case 7:
+ pr_info("%s: v%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u\n",
+ __func__,
+ socinfo->v1.format,
+ socinfo->v1.id,
+ SOCINFO_VERSION_MAJOR(socinfo->v1.version),
+ SOCINFO_VERSION_MINOR(socinfo->v1.version),
+ socinfo->v2.raw_id, socinfo->v2.raw_version,
+ socinfo->v3.hw_platform, socinfo->v4.platform_version,
+ socinfo->v5.accessory_chip,
+ socinfo->v6.hw_platform_subtype,
+ socinfo->v7.pmic_model,
+ socinfo->v7.pmic_die_revision);
+ break;
default:
pr_err("%s: Unknown format found\n", __func__);
break;
@@ -830,3 +921,17 @@
return 0;
};
}
+
+const int cpu_is_krait_v3(void)
+{
+ switch (read_cpuid_id()) {
+ case 0x512F04D0:
+ case 0x511F06F0:
+ case 0x511F06F1:
+ case 0x510F05D0:
+ return 1;
+
+ default:
+ return 0;
+ };
+}
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index b6d5324..9f5aa99 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -139,6 +139,10 @@
dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F;
dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |= (vlevel & 0x3F);
+
+ dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] &= ~0x3F0000;
+ dev->reg_shadow[MSM_SPM_REG_SAW2_PMIC_DATA_1] |=
+ ((vlevel & 0x3F) << 16);
}
static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 65da903..fdde328 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -59,7 +59,7 @@
char wlname[64];
struct work_struct work;
spinlock_t restart_lock;
- bool restarting;
+ int restart_count;
void *notify;
@@ -406,8 +406,9 @@
out:
spin_lock_irqsave(&dev->restart_lock, flags);
- wake_unlock(&dev->wake_lock);
- dev->restarting = false;
+ dev->restart_count--;
+ if (!dev->restart_count)
+ wake_unlock(&dev->wake_lock);
spin_unlock_irqrestore(&dev->restart_lock, flags);
}
@@ -416,16 +417,21 @@
struct subsys_desc *desc = dev->desc;
unsigned long flags;
- spin_lock_irqsave(&dev->restart_lock, flags);
- if (!dev->restarting) {
- pr_debug("Restarting %s [level=%d]!\n", desc->name,
- restart_level);
+ pr_debug("Restarting %s [level=%d]!\n", desc->name, restart_level);
- dev->restarting = true;
+ spin_lock_irqsave(&dev->restart_lock, flags);
+ if (!dev->restart_count)
wake_lock(&dev->wake_lock);
- queue_work(ssr_wq, &dev->work);
- }
+ dev->restart_count++;
spin_unlock_irqrestore(&dev->restart_lock, flags);
+
+ if (!queue_work(ssr_wq, &dev->work)) {
+ spin_lock_irqsave(&dev->restart_lock, flags);
+ dev->restart_count--;
+ if (!dev->restart_count)
+ wake_unlock(&dev->wake_lock);
+ spin_unlock_irqrestore(&dev->restart_lock, flags);
+ }
}
int subsystem_restart_dev(struct subsys_device *dev)
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
index 5d18bb4..ebe1819 100644
--- a/arch/arm/mach-msm/timer.h
+++ b/arch/arm/mach-msm/timer.h
@@ -16,10 +16,10 @@
extern struct sys_timer msm_timer;
-void __iomem *msm_timer_get_timer0_base(void);
uint32_t msm_timer_get_sclk_ticks(void);
int msm_timer_init_time_sync(void (*timeout)(void));
#ifndef CONFIG_ARM_ARCH_TIMER
+void __iomem *msm_timer_get_timer0_base(void);
int64_t msm_timer_enter_idle(void);
void msm_timer_exit_idle(int low_power);
int64_t msm_timer_get_sclk_time(int64_t *period);
@@ -27,5 +27,6 @@
static inline int64_t msm_timer_enter_idle(void) { return 0; }
static inline void msm_timer_exit_idle(int low_power) { return; }
static inline int64_t msm_timer_get_sclk_time(int64_t *period) { return 0; }
+static inline void __iomem *msm_timer_get_timer0_base(void) { return NULL; }
#endif
#endif
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 318523b..cbf1d72 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -180,8 +180,13 @@
static void riva_crash_shutdown(const struct subsys_desc *subsys)
{
pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
- if (riva_crash != true)
+ if (riva_crash != true) {
smsm_riva_reset();
+ /* give sufficient time for wcnss to finish it's error
+ * fatal routine */
+ msleep(3000);
+ }
+
}
static struct subsys_desc riva_8960 = {
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index b1911c4..8404601 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -21,6 +21,8 @@
#include <linux/highmem.h>
#include <linux/memblock.h>
#include <linux/slab.h>
+#include <linux/iommu.h>
+#include <linux/vmalloc.h>
#include <asm/memory.h>
#include <asm/highmem.h>
@@ -31,9 +33,109 @@
#include <asm/mach/map.h>
#include <asm/system_info.h>
#include <asm/dma-contiguous.h>
+#include <asm/dma-iommu.h>
#include "mm.h"
+/*
+ * The DMA API is built upon the notion of "buffer ownership". A buffer
+ * is either exclusively owned by the CPU (and therefore may be accessed
+ * by it) or exclusively owned by the DMA device. These helper functions
+ * represent the transitions between these two ownership states.
+ *
+ * Note, however, that on later ARMs, this notion does not work due to
+ * speculative prefetches. We model our approach on the assumption that
+ * the CPU does do speculative prefetches, which means we clean caches
+ * before transfers and delay cache invalidation until transfer completion.
+ *
+ */
+static void __dma_page_cpu_to_dev(struct page *, unsigned long,
+ size_t, enum dma_data_direction);
+static void __dma_page_dev_to_cpu(struct page *, unsigned long,
+ size_t, enum dma_data_direction);
+
+/**
+ * arm_dma_map_page - map a portion of a page for streaming DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * Ensure that any data held in the cache is appropriately discarded
+ * or written back.
+ *
+ * The device owns this memory once this call has completed. The CPU
+ * can regain ownership by calling dma_unmap_page().
+ */
+static dma_addr_t arm_dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+ return pfn_to_dma(dev, page_to_pfn(page)) + offset;
+}
+
+/**
+ * arm_dma_unmap_page - unmap a buffer previously mapped through dma_map_page()
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @handle: DMA address of buffer
+ * @size: size of buffer (same as passed to dma_map_page)
+ * @dir: DMA transfer direction (same as passed to dma_map_page)
+ *
+ * Unmap a page streaming mode DMA translation. The handle and size
+ * must match what was provided in the previous dma_map_page() call.
+ * All other usages are undefined.
+ *
+ * After this call, reads by the CPU to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+static void arm_dma_unmap_page(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)),
+ handle & ~PAGE_MASK, size, dir);
+}
+
+static void arm_dma_sync_single_for_cpu(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ unsigned int offset = handle & (PAGE_SIZE - 1);
+ struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(page, offset, size, dir);
+}
+
+static void arm_dma_sync_single_for_device(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ unsigned int offset = handle & (PAGE_SIZE - 1);
+ struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset));
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+}
+
+static int arm_dma_set_mask(struct device *dev, u64 dma_mask);
+
+struct dma_map_ops arm_dma_ops = {
+ .alloc = arm_dma_alloc,
+ .free = arm_dma_free,
+ .mmap = arm_dma_mmap,
+ .map_page = arm_dma_map_page,
+ .unmap_page = arm_dma_unmap_page,
+ .map_sg = arm_dma_map_sg,
+ .unmap_sg = arm_dma_unmap_sg,
+ .sync_single_for_cpu = arm_dma_sync_single_for_cpu,
+ .sync_single_for_device = arm_dma_sync_single_for_device,
+ .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
+ .sync_sg_for_device = arm_dma_sync_sg_for_device,
+ .set_dma_mask = arm_dma_set_mask,
+};
+EXPORT_SYMBOL(arm_dma_ops);
+
static u64 get_coherent_dma_mask(struct device *dev)
{
u64 mask = (u64)arm_dma_limit;
@@ -69,9 +171,11 @@
* lurking in the kernel direct-mapped region is invalidated.
*/
ptr = page_address(page);
- memset(ptr, 0, size);
- dmac_flush_range(ptr, ptr + size);
- outer_flush_range(__pa(ptr), __pa(ptr) + size);
+ if (ptr) {
+ memset(ptr, 0, size);
+ dmac_flush_range(ptr, ptr + size);
+ outer_flush_range(__pa(ptr), __pa(ptr) + size);
+ }
}
/*
@@ -124,7 +228,7 @@
#define DEFAULT_CONSISTENT_DMA_SIZE (7*SZ_2M)
-unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE;
+static unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE;
void __init init_consistent_dma_size(unsigned long size)
{
@@ -181,14 +285,14 @@
pud = pud_alloc(&init_mm, pgd, base);
if (!pud) {
- printk(KERN_ERR "%s: no pud tables\n", __func__);
+ pr_err("%s: no pud tables\n", __func__);
ret = -ENOMEM;
break;
}
pmd = pmd_alloc(&init_mm, pud, base);
if (!pmd) {
- printk(KERN_ERR "%s: no pmd tables\n", __func__);
+ pr_err("%s: no pmd tables\n", __func__);
ret = -ENOMEM;
break;
}
@@ -196,7 +300,7 @@
pte = pte_alloc_kernel(pmd, base);
if (!pte) {
- printk(KERN_ERR "%s: no pte tables\n", __func__);
+ pr_err("%s: no pte tables\n", __func__);
ret = -ENOMEM;
break;
}
@@ -217,7 +321,7 @@
.vm_list = LIST_HEAD_INIT(coherent_head.vm_list),
};
-size_t coherent_pool_size = DEFAULT_CONSISTENT_DMA_SIZE / 8;
+static size_t coherent_pool_size = DEFAULT_CONSISTENT_DMA_SIZE / 8;
static int __init early_coherent_pool(char *p)
{
@@ -295,7 +399,7 @@
* Clear previous low-memory mapping
*/
for (addr = __phys_to_virt(start); addr < __phys_to_virt(end);
- addr += PGDIR_SIZE)
+ addr += PMD_SIZE)
pmd_clear(pmd_off_k(addr));
iotable_init(&map, 1);
@@ -311,7 +415,7 @@
int bit;
if (!consistent_pte) {
- printk(KERN_ERR "%s: not initialised\n", __func__);
+ pr_err("%s: not initialised\n", __func__);
dump_stack();
return NULL;
}
@@ -338,7 +442,7 @@
u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
pte = consistent_pte[idx] + off;
- c->vm_pages = page;
+ c->priv = page;
do {
BUG_ON(!pte_none(*pte));
@@ -370,14 +474,14 @@
c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr);
if (!c) {
- printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
+ pr_err("%s: trying to free invalid coherent area: %p\n",
__func__, cpu_addr);
dump_stack();
return;
}
if ((c->vm_end - c->vm_start) != size) {
- printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
+ pr_err("%s: freeing wrong coherent size (%ld != %d)\n",
__func__, c->vm_end - c->vm_start, size);
dump_stack();
size = c->vm_end - c->vm_start;
@@ -399,8 +503,8 @@
}
if (pte_none(pte) || !pte_present(pte))
- printk(KERN_CRIT "%s: bad page in kernel page table\n",
- __func__);
+ pr_crit("%s: bad page in kernel page table\n",
+ __func__);
} while (size -= PAGE_SIZE);
flush_tlb_kernel_range(c->vm_start, c->vm_end);
@@ -524,6 +628,14 @@
dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
}
+static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
+{
+ prot = dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs) ?
+ pgprot_writecombine(prot) :
+ pgprot_dmacoherent(prot);
+ return prot;
+}
+
#define nommu() 0
#else /* !CONFIG_MMU */
@@ -536,6 +648,7 @@
#define __free_from_pool(cpu_addr, size) 0
#define __free_from_contiguous(dev, page, size) do { } while (0)
#define __dma_free_remap(cpu_addr, size) do { } while (0)
+#define __get_dma_pgprot(attrs, prot) __pgprot(0)
#endif /* CONFIG_MMU */
@@ -584,7 +697,7 @@
*/
gfp &= ~(__GFP_COMP);
- *handle = ~0;
+ *handle = DMA_ERROR_CODE;
size = PAGE_ALIGN(size);
if (arch_is_coherent() || nommu())
@@ -606,39 +719,34 @@
* Allocate DMA-coherent memory space and return both the kernel remapped
* virtual and bus address for that space.
*/
-void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle,
- gfp_t gfp)
+void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
+ gfp_t gfp, struct dma_attrs *attrs)
{
+ pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
void *memory;
if (dma_alloc_from_coherent(dev, size, handle, &memory))
return memory;
- return __dma_alloc(dev, size, handle, gfp,
- pgprot_dmacoherent(pgprot_kernel),
+ return __dma_alloc(dev, size, handle, gfp, prot,
__builtin_return_address(0));
}
-EXPORT_SYMBOL(dma_alloc_coherent);
/*
- * Allocate a writecombining region, in much the same way as
- * dma_alloc_coherent above.
+ * Create userspace mapping for the DMA-coherent memory.
*/
-void *
-dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
-{
- return __dma_alloc(dev, size, handle, gfp,
- pgprot_writecombine(pgprot_kernel),
- __builtin_return_address(0));
-}
-EXPORT_SYMBOL(dma_alloc_writecombine);
-
-static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
- void *cpu_addr, dma_addr_t dma_addr, size_t size)
+int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
{
int ret = -ENXIO;
#ifdef CONFIG_MMU
unsigned long pfn = dma_to_pfn(dev, dma_addr);
+ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
+
+ if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
+ return ret;
+
ret = remap_pfn_range(vma, vma->vm_start,
pfn + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
@@ -648,27 +756,11 @@
return ret;
}
-int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
- void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
- vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot);
- return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
-}
-EXPORT_SYMBOL(dma_mmap_coherent);
-
-int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
- void *cpu_addr, dma_addr_t dma_addr, size_t size)
-{
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
-}
-EXPORT_SYMBOL(dma_mmap_writecombine);
-
-
/*
* Free a buffer as defined by the above mapping.
*/
-void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
+void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, struct dma_attrs *attrs)
{
struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
@@ -692,53 +784,6 @@
__free_from_contiguous(dev, page, size);
}
}
-EXPORT_SYMBOL(dma_free_coherent);
-
-/*
- * Make an area consistent for devices.
- * Note: Drivers should NOT use this function directly, as it will break
- * platforms with CONFIG_DMABOUNCE.
- * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
- */
-void ___dma_single_cpu_to_dev(const void *kaddr, size_t size,
- enum dma_data_direction dir)
-{
-#ifdef CONFIG_OUTER_CACHE
- unsigned long paddr;
-
- BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
-#endif
-
- dmac_map_area(kaddr, size, dir);
-
-#ifdef CONFIG_OUTER_CACHE
- paddr = __pa(kaddr);
- if (dir == DMA_FROM_DEVICE) {
- outer_inv_range(paddr, paddr + size);
- } else {
- outer_clean_range(paddr, paddr + size);
- }
-#endif
- /* FIXME: non-speculating: flush on bidirectional mappings? */
-}
-EXPORT_SYMBOL(___dma_single_cpu_to_dev);
-
-void ___dma_single_dev_to_cpu(const void *kaddr, size_t size,
- enum dma_data_direction dir)
-{
-#ifdef CONFIG_OUTER_CACHE
- BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1));
-
- /* FIXME: non-speculating: not required */
- /* don't bother invalidating if DMA to device */
- if (dir != DMA_TO_DEVICE) {
- unsigned long paddr = __pa(kaddr);
- outer_inv_range(paddr, paddr + size);
- }
-#endif
- dmac_unmap_area(kaddr, size, dir);
-}
-EXPORT_SYMBOL(___dma_single_dev_to_cpu);
static void dma_cache_maint_page(struct page *page, unsigned long offset,
size_t size, enum dma_data_direction dir,
@@ -784,7 +829,13 @@
} while (left);
}
-void ___dma_page_cpu_to_dev(struct page *page, unsigned long off,
+/*
+ * Make an area consistent for devices.
+ * Note: Drivers should NOT use this function directly, as it will break
+ * platforms with CONFIG_DMABOUNCE.
+ * Use the driver DMA support - see dma-mapping.h (dma_sync_*)
+ */
+static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
size_t size, enum dma_data_direction dir)
{
unsigned long paddr;
@@ -799,9 +850,8 @@
}
/* FIXME: non-speculating: flush on bidirectional mappings? */
}
-EXPORT_SYMBOL(___dma_page_cpu_to_dev);
-void ___dma_page_dev_to_cpu(struct page *page, unsigned long off,
+static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
size_t size, enum dma_data_direction dir)
{
unsigned long paddr = page_to_phys(page) + off;
@@ -819,10 +869,9 @@
if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
set_bit(PG_dcache_clean, &page->flags);
}
-EXPORT_SYMBOL(___dma_page_dev_to_cpu);
/**
- * dma_map_sg - map a set of SG buffers for streaming mode DMA
+ * arm_dma_map_sg - map a set of SG buffers for streaming mode DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @sg: list of buffers
* @nents: number of buffers to map
@@ -837,32 +886,32 @@
* Device ownership issues as mentioned for dma_map_single are the same
* here.
*/
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction dir)
+int arm_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
int i, j;
- BUG_ON(!valid_dma_direction(dir));
-
for_each_sg(sg, s, nents, i) {
- s->dma_address = __dma_map_page(dev, sg_page(s), s->offset,
- s->length, dir);
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+ s->dma_length = s->length;
+#endif
+ s->dma_address = ops->map_page(dev, sg_page(s), s->offset,
+ s->length, dir, attrs);
if (dma_mapping_error(dev, s->dma_address))
goto bad_mapping;
}
- debug_dma_map_sg(dev, sg, nents, nents, dir);
return nents;
bad_mapping:
for_each_sg(sg, s, i, j)
- __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
+ ops->unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, attrs);
return 0;
}
-EXPORT_SYMBOL(dma_map_sg);
/**
- * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * arm_dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @sg: list of buffers
* @nents: number of buffers to unmap (same as was passed to dma_map_sg)
@@ -871,70 +920,55 @@
* Unmap a set of streaming mode DMA translations. Again, CPU access
* rules concerning calls here are the same as for dma_unmap_single().
*/
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction dir)
+void arm_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
- int i;
- debug_dma_unmap_sg(dev, sg, nents, dir);
+ int i;
for_each_sg(sg, s, nents, i)
- __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir);
+ ops->unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, attrs);
}
-EXPORT_SYMBOL(dma_unmap_sg);
/**
- * dma_sync_sg_for_cpu
+ * arm_dma_sync_sg_for_cpu
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @sg: list of buffers
* @nents: number of buffers to map (returned from dma_map_sg)
* @dir: DMA transfer direction (same as was passed to dma_map_sg)
*/
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+void arm_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
int i;
- for_each_sg(sg, s, nents, i) {
- if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0,
- sg_dma_len(s), dir))
- continue;
-
- __dma_page_dev_to_cpu(sg_page(s), s->offset,
- s->length, dir);
- }
-
- debug_dma_sync_sg_for_cpu(dev, sg, nents, dir);
+ for_each_sg(sg, s, nents, i)
+ ops->sync_single_for_cpu(dev, sg_dma_address(s), s->length,
+ dir);
}
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
/**
- * dma_sync_sg_for_device
+ * arm_dma_sync_sg_for_device
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
* @sg: list of buffers
* @nents: number of buffers to map (returned from dma_map_sg)
* @dir: DMA transfer direction (same as was passed to dma_map_sg)
*/
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+void arm_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir)
{
+ struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
int i;
- for_each_sg(sg, s, nents, i) {
- if (!dmabounce_sync_for_device(dev, sg_dma_address(s), 0,
- sg_dma_len(s), dir))
- continue;
-
- __dma_page_cpu_to_dev(sg_page(s), s->offset,
- s->length, dir);
- }
-
- debug_dma_sync_sg_for_device(dev, sg, nents, dir);
+ for_each_sg(sg, s, nents, i)
+ ops->sync_single_for_device(dev, sg_dma_address(s), s->length,
+ dir);
}
-EXPORT_SYMBOL(dma_sync_sg_for_device);
/*
* Return whether the given device DMA address mask can be supported
@@ -950,18 +984,15 @@
}
EXPORT_SYMBOL(dma_supported);
-int dma_set_mask(struct device *dev, u64 dma_mask)
+static int arm_dma_set_mask(struct device *dev, u64 dma_mask)
{
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
return -EIO;
-#ifndef CONFIG_DMABOUNCE
*dev->dma_mask = dma_mask;
-#endif
return 0;
}
-EXPORT_SYMBOL(dma_set_mask);
#define PREALLOC_DMA_DEBUG_ENTRIES 4096
@@ -974,3 +1005,679 @@
return 0;
}
fs_initcall(dma_debug_do_init);
+
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+
+/* IOMMU */
+
+static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
+ size_t size)
+{
+ unsigned int order = get_order(size);
+ unsigned int align = 0;
+ unsigned int count, start;
+ unsigned long flags;
+
+ count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+
+ if (order > mapping->order)
+ align = (1 << (order - mapping->order)) - 1;
+
+ spin_lock_irqsave(&mapping->lock, flags);
+ start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
+ count, align);
+ if (start > mapping->bits) {
+ spin_unlock_irqrestore(&mapping->lock, flags);
+ return DMA_ERROR_CODE;
+ }
+
+ bitmap_set(mapping->bitmap, start, count);
+ spin_unlock_irqrestore(&mapping->lock, flags);
+
+ return mapping->base + (start << (mapping->order + PAGE_SHIFT));
+}
+
+static inline void __free_iova(struct dma_iommu_mapping *mapping,
+ dma_addr_t addr, size_t size)
+{
+ unsigned int start = (addr - mapping->base) >>
+ (mapping->order + PAGE_SHIFT);
+ unsigned int count = ((size >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mapping->lock, flags);
+ bitmap_clear(mapping->bitmap, start, count);
+ spin_unlock_irqrestore(&mapping->lock, flags);
+}
+
+static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
+{
+ struct page **pages;
+ int count = size >> PAGE_SHIFT;
+ int array_size = count * sizeof(struct page *);
+ int i = 0;
+
+ if (array_size <= PAGE_SIZE)
+ pages = kzalloc(array_size, gfp);
+ else
+ pages = vzalloc(array_size);
+ if (!pages)
+ return NULL;
+
+ while (count) {
+ int j, order = __fls(count);
+
+ pages[i] = alloc_pages(gfp | __GFP_NOWARN, order);
+ while (!pages[i] && order)
+ pages[i] = alloc_pages(gfp | __GFP_NOWARN, --order);
+ if (!pages[i])
+ goto error;
+
+ if (order)
+ split_page(pages[i], order);
+ j = 1 << order;
+ while (--j)
+ pages[i + j] = pages[i] + j;
+
+ __dma_clear_buffer(pages[i], PAGE_SIZE << order);
+ i += 1 << order;
+ count -= 1 << order;
+ }
+
+ return pages;
+error:
+ while (--i)
+ if (pages[i])
+ __free_pages(pages[i], 0);
+ if (array_size < PAGE_SIZE)
+ kfree(pages);
+ else
+ vfree(pages);
+ return NULL;
+}
+
+static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t size)
+{
+ int count = size >> PAGE_SHIFT;
+ int array_size = count * sizeof(struct page *);
+ int i;
+ for (i = 0; i < count; i++)
+ if (pages[i])
+ __free_pages(pages[i], 0);
+ if (array_size < PAGE_SIZE)
+ kfree(pages);
+ else
+ vfree(pages);
+ return 0;
+}
+
+/*
+ * Create a CPU mapping for a specified pages
+ */
+static void *
+__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot)
+{
+ struct arm_vmregion *c;
+ size_t align;
+ size_t count = size >> PAGE_SHIFT;
+ int bit;
+
+ if (!consistent_pte[0]) {
+ pr_err("%s: not initialised\n", __func__);
+ dump_stack();
+ return NULL;
+ }
+
+ /*
+ * Align the virtual region allocation - maximum alignment is
+ * a section size, minimum is a page size. This helps reduce
+ * fragmentation of the DMA space, and also prevents allocations
+ * smaller than a section from crossing a section boundary.
+ */
+ bit = fls(size - 1);
+ if (bit > SECTION_SHIFT)
+ bit = SECTION_SHIFT;
+ align = 1 << bit;
+
+ /*
+ * Allocate a virtual address in the consistent mapping region.
+ */
+ c = arm_vmregion_alloc(&consistent_head, align, size,
+ gfp & ~(__GFP_DMA | __GFP_HIGHMEM), NULL);
+ if (c) {
+ pte_t *pte;
+ int idx = CONSISTENT_PTE_INDEX(c->vm_start);
+ int i = 0;
+ u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
+
+ pte = consistent_pte[idx] + off;
+ c->priv = pages;
+
+ do {
+ BUG_ON(!pte_none(*pte));
+
+ set_pte_ext(pte, mk_pte(pages[i], prot), 0);
+ pte++;
+ off++;
+ i++;
+ if (off >= PTRS_PER_PTE) {
+ off = 0;
+ pte = consistent_pte[++idx];
+ }
+ } while (i < count);
+
+ dsb();
+
+ return (void *)c->vm_start;
+ }
+ return NULL;
+}
+
+/*
+ * Create a mapping in device IO address space for specified pages
+ */
+static dma_addr_t
+__iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ dma_addr_t dma_addr, iova;
+ int i, ret = DMA_ERROR_CODE;
+
+ dma_addr = __alloc_iova(mapping, size);
+ if (dma_addr == DMA_ERROR_CODE)
+ return dma_addr;
+
+ iova = dma_addr;
+ for (i = 0; i < count; ) {
+ unsigned int next_pfn = page_to_pfn(pages[i]) + 1;
+ phys_addr_t phys = page_to_phys(pages[i]);
+ unsigned int len, j;
+
+ for (j = i + 1; j < count; j++, next_pfn++)
+ if (page_to_pfn(pages[j]) != next_pfn)
+ break;
+
+ len = (j - i) << PAGE_SHIFT;
+ ret = iommu_map(mapping->domain, iova, phys, len, 0);
+ if (ret < 0)
+ goto fail;
+ iova += len;
+ i = j;
+ }
+ return dma_addr;
+fail:
+ iommu_unmap(mapping->domain, dma_addr, iova-dma_addr);
+ __free_iova(mapping, dma_addr, size);
+ return DMA_ERROR_CODE;
+}
+
+static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t size)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+
+ /*
+ * add optional in-page offset from iova to size and align
+ * result to page size
+ */
+ size = PAGE_ALIGN((iova & ~PAGE_MASK) + size);
+ iova &= PAGE_MASK;
+
+ iommu_unmap(mapping->domain, iova, size);
+ __free_iova(mapping, iova, size);
+ return 0;
+}
+
+static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
+ dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
+{
+ pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel);
+ struct page **pages;
+ void *addr = NULL;
+
+ *handle = DMA_ERROR_CODE;
+ size = PAGE_ALIGN(size);
+
+ pages = __iommu_alloc_buffer(dev, size, gfp);
+ if (!pages)
+ return NULL;
+
+ *handle = __iommu_create_mapping(dev, pages, size);
+ if (*handle == DMA_ERROR_CODE)
+ goto err_buffer;
+
+ addr = __iommu_alloc_remap(pages, size, gfp, prot);
+ if (!addr)
+ goto err_mapping;
+
+ return addr;
+
+err_mapping:
+ __iommu_remove_mapping(dev, *handle, size);
+err_buffer:
+ __iommu_free_buffer(dev, pages, size);
+ return NULL;
+}
+
+static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size,
+ struct dma_attrs *attrs)
+{
+ struct arm_vmregion *c;
+
+ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
+ c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
+
+ if (c) {
+ struct page **pages = c->priv;
+
+ unsigned long uaddr = vma->vm_start;
+ unsigned long usize = vma->vm_end - vma->vm_start;
+ int i = 0;
+
+ do {
+ int ret;
+
+ ret = vm_insert_page(vma, uaddr, pages[i++]);
+ if (ret) {
+ pr_err("Remapping memory, error: %d\n", ret);
+ return ret;
+ }
+
+ uaddr += PAGE_SIZE;
+ usize -= PAGE_SIZE;
+ } while (usize > 0);
+ }
+ return 0;
+}
+
+/*
+ * free a page as defined by the above mapping.
+ * Must not be called with IRQs disabled.
+ */
+void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle, struct dma_attrs *attrs)
+{
+ struct arm_vmregion *c;
+ size = PAGE_ALIGN(size);
+
+ c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr);
+ if (c) {
+ struct page **pages = c->priv;
+ __dma_free_remap(cpu_addr, size);
+ __iommu_remove_mapping(dev, handle, size);
+ __iommu_free_buffer(dev, pages, size);
+ }
+}
+
+/*
+ * Map a part of the scatter-gather list into contiguous io address space
+ */
+static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
+ size_t size, dma_addr_t *handle,
+ enum dma_data_direction dir)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova, iova_base;
+ int ret = 0;
+ unsigned int count;
+ struct scatterlist *s;
+
+ size = PAGE_ALIGN(size);
+ *handle = DMA_ERROR_CODE;
+
+ iova_base = iova = __alloc_iova(mapping, size);
+ if (iova == DMA_ERROR_CODE)
+ return -ENOMEM;
+
+ for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s)) {
+ phys_addr_t phys = page_to_phys(sg_page(s));
+ unsigned int len = PAGE_ALIGN(s->offset + s->length);
+
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
+
+ ret = iommu_map(mapping->domain, iova, phys, len, 0);
+ if (ret < 0)
+ goto fail;
+ count += len >> PAGE_SHIFT;
+ iova += len;
+ }
+ *handle = iova_base;
+
+ return 0;
+fail:
+ iommu_unmap(mapping->domain, iova_base, count * PAGE_SIZE);
+ __free_iova(mapping, iova_base, size);
+ return ret;
+}
+
+/**
+ * arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map
+ * @dir: DMA transfer direction
+ *
+ * Map a set of buffers described by scatterlist in streaming mode for DMA.
+ * The scatter gather list elements are merged together (if possible) and
+ * tagged with the appropriate dma address and length. They are obtained via
+ * sg_dma_{address,length}.
+ */
+int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ struct scatterlist *s = sg, *dma = sg, *start = sg;
+ int i, count = 0;
+ unsigned int offset = s->offset;
+ unsigned int size = s->offset + s->length;
+ unsigned int max = dma_get_max_seg_size(dev);
+
+ for (i = 1; i < nents; i++) {
+ s = sg_next(s);
+
+ s->dma_address = DMA_ERROR_CODE;
+ s->dma_length = 0;
+
+ if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) {
+ if (__map_sg_chunk(dev, start, size, &dma->dma_address,
+ dir) < 0)
+ goto bad_mapping;
+
+ dma->dma_address += offset;
+ dma->dma_length = size - offset;
+
+ size = offset = s->offset;
+ start = s;
+ dma = sg_next(dma);
+ count += 1;
+ }
+ size += s->length;
+ }
+ if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir) < 0)
+ goto bad_mapping;
+
+ dma->dma_address += offset;
+ dma->dma_length = size - offset;
+
+ return count+1;
+
+bad_mapping:
+ for_each_sg(sg, s, count, i)
+ __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s));
+ return 0;
+}
+
+/**
+ * arm_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to unmap (same as was passed to dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ *
+ * Unmap a set of streaming mode DMA translations. Again, CPU access
+ * rules concerning calls here are the same as for dma_unmap_single().
+ */
+void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, struct dma_attrs *attrs)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i) {
+ if (sg_dma_len(s))
+ __iommu_remove_mapping(dev, sg_dma_address(s),
+ sg_dma_len(s));
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(sg_page(s), s->offset,
+ s->length, dir);
+ }
+}
+
+/**
+ * arm_iommu_sync_sg_for_cpu
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i)
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir);
+
+}
+
+/**
+ * arm_iommu_sync_sg_for_device
+ * @dev: valid struct device pointer
+ * @sg: list of buffers
+ * @nents: number of buffers to map (returned from dma_map_sg)
+ * @dir: DMA transfer direction (same as was passed to dma_map_sg)
+ */
+void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i)
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
+}
+
+
+/**
+ * arm_iommu_map_page
+ * @dev: valid struct device pointer
+ * @page: page that buffer resides in
+ * @offset: offset into page for start of buffer
+ * @size: size of buffer to map
+ * @dir: DMA transfer direction
+ *
+ * IOMMU aware version of arm_dma_map_page()
+ */
+static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t dma_addr;
+ int ret, len = PAGE_ALIGN(size + offset);
+
+ if (!arch_is_coherent())
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+
+ dma_addr = __alloc_iova(mapping, len);
+ if (dma_addr == DMA_ERROR_CODE)
+ return dma_addr;
+
+ ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, 0);
+ if (ret < 0)
+ goto fail;
+
+ return dma_addr + offset;
+fail:
+ __free_iova(mapping, dma_addr, len);
+ return DMA_ERROR_CODE;
+}
+
+/**
+ * arm_iommu_unmap_page
+ * @dev: valid struct device pointer
+ * @handle: DMA address of buffer
+ * @size: size of buffer (same as passed to dma_map_page)
+ * @dir: DMA transfer direction (same as passed to dma_map_page)
+ *
+ * IOMMU aware version of arm_dma_unmap_page()
+ */
+static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = handle & PAGE_MASK;
+ struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
+ int offset = handle & ~PAGE_MASK;
+ int len = PAGE_ALIGN(size + offset);
+
+ if (!iova)
+ return;
+
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(page, offset, size, dir);
+
+ iommu_unmap(mapping->domain, iova, len);
+ __free_iova(mapping, iova, len);
+}
+
+static void arm_iommu_sync_single_for_cpu(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = handle & PAGE_MASK;
+ struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
+ unsigned int offset = handle & ~PAGE_MASK;
+
+ if (!iova)
+ return;
+
+ if (!arch_is_coherent())
+ __dma_page_dev_to_cpu(page, offset, size, dir);
+}
+
+static void arm_iommu_sync_single_for_device(struct device *dev,
+ dma_addr_t handle, size_t size, enum dma_data_direction dir)
+{
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = handle & PAGE_MASK;
+ struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
+ unsigned int offset = handle & ~PAGE_MASK;
+
+ if (!iova)
+ return;
+
+ __dma_page_cpu_to_dev(page, offset, size, dir);
+}
+
+struct dma_map_ops iommu_ops = {
+ .alloc = arm_iommu_alloc_attrs,
+ .free = arm_iommu_free_attrs,
+ .mmap = arm_iommu_mmap_attrs,
+
+ .map_page = arm_iommu_map_page,
+ .unmap_page = arm_iommu_unmap_page,
+ .sync_single_for_cpu = arm_iommu_sync_single_for_cpu,
+ .sync_single_for_device = arm_iommu_sync_single_for_device,
+
+ .map_sg = arm_iommu_map_sg,
+ .unmap_sg = arm_iommu_unmap_sg,
+ .sync_sg_for_cpu = arm_iommu_sync_sg_for_cpu,
+ .sync_sg_for_device = arm_iommu_sync_sg_for_device,
+};
+
+/**
+ * arm_iommu_create_mapping
+ * @bus: pointer to the bus holding the client device (for IOMMU calls)
+ * @base: start address of the valid IO address space
+ * @size: size of the valid IO address space
+ * @order: accuracy of the IO addresses allocations
+ *
+ * Creates a mapping structure which holds information about used/unused
+ * IO address ranges, which is required to perform memory allocation and
+ * mapping with IOMMU aware functions.
+ *
+ * The client device need to be attached to the mapping with
+ * arm_iommu_attach_device function.
+ */
+struct dma_iommu_mapping *
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
+ int order)
+{
+ unsigned int count = size >> (PAGE_SHIFT + order);
+ unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
+ struct dma_iommu_mapping *mapping;
+ int err = -ENOMEM;
+
+ if (!count)
+ return ERR_PTR(-EINVAL);
+
+ mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
+ if (!mapping)
+ goto err;
+
+ mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!mapping->bitmap)
+ goto err2;
+
+ mapping->base = base;
+ mapping->bits = BITS_PER_BYTE * bitmap_size;
+ mapping->order = order;
+ spin_lock_init(&mapping->lock);
+
+ mapping->domain = iommu_domain_alloc(bus);
+ if (!mapping->domain)
+ goto err3;
+
+ kref_init(&mapping->kref);
+ return mapping;
+err3:
+ kfree(mapping->bitmap);
+err2:
+ kfree(mapping);
+err:
+ return ERR_PTR(err);
+}
+
+static void release_iommu_mapping(struct kref *kref)
+{
+ struct dma_iommu_mapping *mapping =
+ container_of(kref, struct dma_iommu_mapping, kref);
+
+ iommu_domain_free(mapping->domain);
+ kfree(mapping->bitmap);
+ kfree(mapping);
+}
+
+void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
+{
+ if (mapping)
+ kref_put(&mapping->kref, release_iommu_mapping);
+}
+
+/**
+ * arm_iommu_attach_device
+ * @dev: valid struct device pointer
+ * @mapping: io address space mapping structure (returned from
+ * arm_iommu_create_mapping)
+ *
+ * Attaches specified io address space mapping to the provided device,
+ * this replaces the dma operations (dma_map_ops pointer) with the
+ * IOMMU aware version. More than one client might be attached to
+ * the same io address space mapping.
+ */
+int arm_iommu_attach_device(struct device *dev,
+ struct dma_iommu_mapping *mapping)
+{
+ int err;
+
+ err = iommu_attach_device(mapping->domain, dev);
+ if (err)
+ return err;
+
+ kref_get(&mapping->kref);
+ dev->archdata.mapping = mapping;
+ set_dma_ops(dev, &iommu_ops);
+
+ pr_info("Attached IOMMU controller to %s device.\n", dev_name(dev));
+ return 0;
+}
+
+#endif
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index bd41abc..8877ddd 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -55,6 +55,9 @@
/* permanent static mappings from iotable_init() */
#define VM_ARM_STATIC_MAPPING 0x40000000
+/* empty mapping */
+#define VM_ARM_EMPTY_MAPPING 0x20000000
+
/* mapping type (attributes) for permanent static mappings */
#define VM_ARM_MTYPE(mt) ((mt) << 20)
#define VM_ARM_MTYPE_MASK (0x1f << 20)
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index ce8cb19..06262c5 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -11,49 +11,10 @@
#include <linux/random.h>
#include <asm/cachetype.h>
-static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
- unsigned long pgoff)
-{
- unsigned long base = addr & ~(SHMLBA-1);
- unsigned long off = (pgoff << PAGE_SHIFT) & (SHMLBA-1);
-
- if (base + off <= addr)
- return base + off;
-
- return base - off;
-}
-
#define COLOUR_ALIGN(addr,pgoff) \
((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \
(((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
-/* gap between mmap and stack */
-#define MIN_GAP (128*1024*1024UL)
-#define MAX_GAP ((TASK_SIZE)/6*5)
-
-static int mmap_is_legacy(void)
-{
- if (current->personality & ADDR_COMPAT_LAYOUT)
- return 1;
-
- if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
- return 1;
-
- return sysctl_legacy_va_layout;
-}
-
-static unsigned long mmap_base(unsigned long rnd)
-{
- unsigned long gap = rlimit(RLIMIT_STACK);
-
- if (gap < MIN_GAP)
- gap = MIN_GAP;
- else if (gap > MAX_GAP)
- gap = MAX_GAP;
-
- return PAGE_ALIGN(TASK_SIZE - gap - rnd);
-}
-
/*
* We need to ensure that shared mappings are correctly aligned to
* avoid aliasing issues with VIPT caches. We need to ensure that
@@ -107,9 +68,13 @@
if (len > mm->cached_hole_size) {
start_addr = addr = mm->free_area_cache;
} else {
- start_addr = addr = mm->mmap_base;
+ start_addr = addr = TASK_UNMAPPED_BASE;
mm->cached_hole_size = 0;
}
+ /* 8 bits of randomness in 20 address space bits */
+ if ((current->flags & PF_RANDOMIZE) &&
+ !(current->personality & ADDR_NO_RANDOMIZE))
+ addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT;
full_search:
if (do_align)
@@ -146,134 +111,6 @@
}
}
-unsigned long
-arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
- const unsigned long len, const unsigned long pgoff,
- const unsigned long flags)
-{
- struct vm_area_struct *vma;
- struct mm_struct *mm = current->mm;
- unsigned long addr = addr0;
- int do_align = 0;
- int aliasing = cache_is_vipt_aliasing();
-
- /*
- * We only need to do colour alignment if either the I or D
- * caches alias.
- */
- if (aliasing)
- do_align = filp || (flags & MAP_SHARED);
-
- /* requested length too big for entire address space */
- if (len > TASK_SIZE)
- return -ENOMEM;
-
- if (flags & MAP_FIXED) {
- if (aliasing && flags & MAP_SHARED &&
- (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
- return -EINVAL;
- return addr;
- }
-
- /* requesting a specific address */
- if (addr) {
- if (do_align)
- addr = COLOUR_ALIGN(addr, pgoff);
- else
- addr = PAGE_ALIGN(addr);
- vma = find_vma(mm, addr);
- if (TASK_SIZE - len >= addr &&
- (!vma || addr + len <= vma->vm_start))
- return addr;
- }
-
- /* check if free_area_cache is useful for us */
- if (len <= mm->cached_hole_size) {
- mm->cached_hole_size = 0;
- mm->free_area_cache = mm->mmap_base;
- }
-
- /* either no address requested or can't fit in requested address hole */
- addr = mm->free_area_cache;
- if (do_align) {
- unsigned long base = COLOUR_ALIGN_DOWN(addr - len, pgoff);
- addr = base + len;
- }
-
- /* make sure it can fit in the remaining address space */
- if (addr > len) {
- vma = find_vma(mm, addr-len);
- if (!vma || addr <= vma->vm_start)
- /* remember the address as a hint for next time */
- return (mm->free_area_cache = addr-len);
- }
-
- if (mm->mmap_base < len)
- goto bottomup;
-
- addr = mm->mmap_base - len;
- if (do_align)
- addr = COLOUR_ALIGN_DOWN(addr, pgoff);
-
- do {
- /*
- * Lookup failure means no vma is above this address,
- * else if new region fits below vma->vm_start,
- * return with success:
- */
- vma = find_vma(mm, addr);
- if (!vma || addr+len <= vma->vm_start)
- /* remember the address as a hint for next time */
- return (mm->free_area_cache = addr);
-
- /* remember the largest hole we saw so far */
- if (addr + mm->cached_hole_size < vma->vm_start)
- mm->cached_hole_size = vma->vm_start - addr;
-
- /* try just below the current vma->vm_start */
- addr = vma->vm_start - len;
- if (do_align)
- addr = COLOUR_ALIGN_DOWN(addr, pgoff);
- } while (len < vma->vm_start);
-
-bottomup:
- /*
- * A failed mmap() very likely causes application failure,
- * so fall back to the bottom-up function here. This scenario
- * can happen with large stack limits and large mmap()
- * allocations.
- */
- mm->cached_hole_size = ~0UL;
- mm->free_area_cache = TASK_UNMAPPED_BASE;
- addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
- /*
- * Restore the topdown base:
- */
- mm->free_area_cache = mm->mmap_base;
- mm->cached_hole_size = ~0UL;
-
- return addr;
-}
-
-void arch_pick_mmap_layout(struct mm_struct *mm)
-{
- unsigned long random_factor = 0UL;
-
- /* 8 bits of randomness in 20 address space bits */
- if ((current->flags & PF_RANDOMIZE) &&
- !(current->personality & ADDR_NO_RANDOMIZE))
- random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT;
-
- if (mmap_is_legacy()) {
- mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
- mm->get_unmapped_area = arch_get_unmapped_area;
- mm->unmap_area = arch_unmap_area;
- } else {
- mm->mmap_base = mmap_base(random_factor);
- mm->get_unmapped_area = arch_get_unmapped_area_topdown;
- mm->unmap_area = arch_unmap_area_topdown;
- }
-}
/*
* You really shouldn't be using read() or write() on /dev/mem. This
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index da33be0..bae23b0 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -861,7 +861,7 @@
vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
vm->addr = (void *)addr;
vm->size = SECTION_SIZE;
- vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
+ vm->flags = VM_IOREMAP | VM_ARM_EMPTY_MAPPING;
vm->caller = pmd_empty_section_gap;
vm_area_add_early(vm);
}
@@ -874,7 +874,7 @@
/* we're still single threaded hence no lock needed here */
for (vm = vmlist; vm; vm = vm->next) {
- if (!(vm->flags & VM_ARM_STATIC_MAPPING))
+ if (!(vm->flags & (VM_ARM_STATIC_MAPPING | VM_ARM_EMPTY_MAPPING)))
continue;
addr = (unsigned long)vm->addr;
if (addr < next)
diff --git a/arch/arm/mm/vmregion.h b/arch/arm/mm/vmregion.h
index 162be66..bf312c3 100644
--- a/arch/arm/mm/vmregion.h
+++ b/arch/arm/mm/vmregion.h
@@ -17,7 +17,7 @@
struct list_head vm_list;
unsigned long vm_start;
unsigned long vm_end;
- struct page *vm_pages;
+ void *priv;
int vm_active;
const void *caller;
};
diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c
index bb0025c..1b85949 100644
--- a/drivers/base/dma-coherent.c
+++ b/drivers/base/dma-coherent.c
@@ -10,6 +10,7 @@
struct dma_coherent_mem {
void *virt_base;
dma_addr_t device_base;
+ phys_addr_t pfn_base;
int size;
int flags;
unsigned long *bitmap;
@@ -44,6 +45,7 @@
dev->dma_mem->virt_base = mem_base;
dev->dma_mem->device_base = device_addr;
+ dev->dma_mem->pfn_base = PFN_DOWN(bus_addr);
dev->dma_mem->size = pages;
dev->dma_mem->flags = flags;
@@ -176,3 +178,43 @@
return 0;
}
EXPORT_SYMBOL(dma_release_from_coherent);
+
+/**
+ * dma_mmap_from_coherent() - try to mmap the memory allocated from
+ * per-device coherent memory pool to userspace
+ * @dev: device from which the memory was allocated
+ * @vma: vm_area for the userspace memory
+ * @vaddr: cpu address returned by dma_alloc_from_coherent
+ * @size: size of the memory buffer allocated by dma_alloc_from_coherent
+ *
+ * This checks whether the memory was allocated from the per-device
+ * coherent memory pool and if so, maps that memory to the provided vma.
+ *
+ * Returns 1 if we correctly mapped the memory, or 0 if
+ * dma_release_coherent() should proceed with mapping memory from
+ * generic pools.
+ */
+int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
+ void *vaddr, size_t size, int *ret)
+{
+ struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
+
+ if (mem && vaddr >= mem->virt_base && vaddr + size <=
+ (mem->virt_base + (mem->size << PAGE_SHIFT))) {
+ unsigned long off = vma->vm_pgoff;
+ int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+ int user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ int count = size >> PAGE_SHIFT;
+
+ *ret = -ENXIO;
+ if (off < count && user_count <= count - off) {
+ unsigned pfn = mem->pfn_base + start + off;
+ *ret = remap_pfn_range(vma, vma->vm_start, pfn,
+ user_count << PAGE_SHIFT,
+ vma->vm_page_prot);
+ }
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(dma_mmap_from_coherent);
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 95d2f17..b5d38d5 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1010,8 +1010,16 @@
int dpm_suspend_end(pm_message_t state)
{
int error = dpm_suspend_late(state);
+ if (error)
+ return error;
- return error ? : dpm_suspend_noirq(state);
+ error = dpm_suspend_noirq(state);
+ if (error) {
+ dpm_resume_early(state);
+ return error;
+ }
+
+ return 0;
}
EXPORT_SYMBOL_GPL(dpm_suspend_end);
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index b117309..50b3362 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -44,7 +44,7 @@
#include "hci_uart.h"
-unsigned int enableuartsleep;
+unsigned int enableuartsleep = 1;
module_param(enableuartsleep, uint, 0644);
/*
* Global variables
@@ -93,7 +93,7 @@
static void hostwake_interrupt(unsigned long data)
{
- printk(KERN_INFO " wakeup host\n");
+ BT_INFO(" wakeup host\n");
}
static void modify_timer_task(void)
@@ -109,10 +109,10 @@
{
int status = 0;
if (test_bit(BT_TXEXPIRED, &flags)) {
- printk(KERN_INFO "wakeup device\n");
- gpio_set_value(bsi->ext_wake, 1);
- msleep(20);
+ BT_INFO("wakeup device\n");
gpio_set_value(bsi->ext_wake, 0);
+ msleep(20);
+ gpio_set_value(bsi->ext_wake, 1);
}
modify_timer_task();
return status;
@@ -138,12 +138,114 @@
hci_uart_tx_wakeup(hu);
}
+static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
+{
+ /* schedule a tasklet to handle the change in the host wake line */
+ tasklet_schedule(&hostwake_task);
+ return IRQ_HANDLED;
+}
+
+static int ath_bluesleep_gpio_config(int on)
+{
+ int ret = 0;
+
+ BT_INFO("%s config: %d", __func__, on);
+ if (!on) {
+ if (disable_irq_wake(bsi->host_wake_irq))
+ BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
+ goto free_host_wake_irq;
+ }
+
+ ret = gpio_request(bsi->host_wake, "bt_host_wake");
+ if (ret < 0) {
+ BT_ERR("failed to request gpio pin %d, error %d\n",
+ bsi->host_wake, ret);
+ goto gpio_config_failed;
+ }
+
+ /* configure host_wake as input */
+ ret = gpio_direction_input(bsi->host_wake);
+ if (ret < 0) {
+ BT_ERR("failed to config GPIO %d as input pin, err %d\n",
+ bsi->host_wake, ret);
+ goto gpio_host_wake;
+ }
+
+ ret = gpio_request(bsi->ext_wake, "bt_ext_wake");
+ if (ret < 0) {
+ BT_ERR("failed to request gpio pin %d, error %d\n",
+ bsi->ext_wake, ret);
+ goto gpio_host_wake;
+ }
+
+ ret = gpio_direction_output(bsi->ext_wake, 1);
+ if (ret < 0) {
+ BT_ERR("failed to config GPIO %d as output pin, err %d\n",
+ bsi->ext_wake, ret);
+ goto gpio_ext_wake;
+ }
+
+ gpio_set_value(bsi->ext_wake, 1);
+
+ /* Initialize spinlock. */
+ spin_lock_init(&rw_lock);
+
+ /* Initialize timer */
+ init_timer(&tx_timer);
+ tx_timer.function = bluesleep_tx_timer_expire;
+ tx_timer.data = 0;
+
+ /* initialize host wake tasklet */
+ tasklet_init(&hostwake_task, hostwake_interrupt, 0);
+
+ if (bsi->irq_polarity == POLARITY_LOW) {
+ ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
+ IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+ "bluetooth hostwake", NULL);
+ } else {
+ ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ "bluetooth hostwake", NULL);
+ }
+ if (ret < 0) {
+ BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
+ goto delete_timer;
+ }
+
+ ret = enable_irq_wake(bsi->host_wake_irq);
+ if (ret < 0) {
+ BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt");
+ goto free_host_wake_irq;
+ }
+
+ return 0;
+
+free_host_wake_irq:
+ free_irq(bsi->host_wake_irq, NULL);
+delete_timer:
+ del_timer(&tx_timer);
+gpio_ext_wake:
+ gpio_free(bsi->ext_wake);
+gpio_host_wake:
+ gpio_free(bsi->host_wake);
+gpio_config_failed:
+ return ret;
+}
+
/* Initialize protocol */
static int ath_open(struct hci_uart *hu)
{
struct ath_struct *ath;
- BT_DBG("hu %p", hu);
+ BT_DBG("hu %p, bsi %p", hu, bsi);
+
+ if (!bsi)
+ return -EIO;
+
+ if (ath_bluesleep_gpio_config(1) < 0) {
+ BT_ERR("HCIATH3K GPIO Config failed");
+ return -EIO;
+ }
ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
if (!ath)
@@ -190,6 +292,9 @@
hu->priv = NULL;
kfree(ath);
+ if (bsi)
+ ath_bluesleep_gpio_config(0);
+
return 0;
}
@@ -200,6 +305,8 @@
{
struct ath_struct *ath = hu->priv;
+ BT_DBG("");
+
if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
kfree_skb(skb);
return 0;
@@ -243,6 +350,8 @@
struct ath_struct *ath = hu->priv;
unsigned int type;
+ BT_DBG("");
+
if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
BT_ERR("Frame Reassembly Failed");
@@ -260,7 +369,7 @@
if (type == HCI_EVENT_PKT) {
clear_bit(BT_SLEEPCMD, &flags);
- printk(KERN_INFO "cur_sleep:%d\n", ath->cur_sleep);
+ BT_INFO("cur_sleep:%d\n", ath->cur_sleep);
if (ath->cur_sleep == 1)
set_bit(BT_SLEEPENABLE, &flags);
else
@@ -276,19 +385,11 @@
{
if (!test_bit(BT_SLEEPENABLE, &flags))
return;
- BT_DBG("Tx timer expired");
- printk(KERN_INFO "Tx timer expired\n");
+ BT_INFO("Tx timer expired\n");
set_bit(BT_TXEXPIRED, &flags);
}
-static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id)
-{
- /* schedule a tasklet to handle the change in the host wake line */
- tasklet_schedule(&hostwake_task);
- return IRQ_HANDLED;
-}
-
static struct hci_uart_proto athp = {
.id = HCI_UART_ATH3K,
.open = ath_open,
@@ -304,6 +405,8 @@
int ret;
struct resource *res;
+ BT_DBG("");
+
bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL);
if (!bsi) {
ret = -ENOMEM;
@@ -319,107 +422,35 @@
}
bsi->host_wake = res->start;
- ret = gpio_request(bsi->host_wake, "bt_host_wake");
- if (ret)
- goto free_bsi;
-
- /* configure host_wake as input */
- ret = gpio_direction_input(bsi->host_wake);
- if (ret < 0) {
- pr_err("%s: gpio_direction_input failed for GPIO %d, error %d\n",
- __func__, bsi->host_wake, ret);
- gpio_free(bsi->host_wake);
- goto free_bsi;
- }
-
res = platform_get_resource_byname(pdev, IORESOURCE_IO,
"gpio_ext_wake");
if (!res) {
BT_ERR("couldn't find ext_wake gpio\n");
ret = -ENODEV;
- goto free_bt_host_wake;
+ goto free_bsi;
}
bsi->ext_wake = res->start;
- ret = gpio_request(bsi->ext_wake, "bt_ext_wake");
- if (ret)
- goto free_bt_host_wake;
-
- /* configure ext_wake as output mode*/
- ret = gpio_direction_output(bsi->ext_wake, 1);
- if (ret < 0) {
- pr_err("%s: gpio_direction_output failed for GPIO %d, error %d\n",
- __func__, bsi->ext_wake, ret);
- gpio_free(bsi->ext_wake);
- goto free_bt_host_wake;
- }
- gpio_set_value(bsi->ext_wake, 0);
-
bsi->host_wake_irq = platform_get_irq_byname(pdev, "host_wake");
if (bsi->host_wake_irq < 0) {
BT_ERR("couldn't find host_wake irq\n");
ret = -ENODEV;
- goto free_bt_ext_wake;
+ goto free_bsi;
}
bsi->irq_polarity = POLARITY_LOW; /* low edge (falling edge) */
- /* Initialize spinlock. */
- spin_lock_init(&rw_lock);
-
- /* Initialize timer */
- init_timer(&tx_timer);
- tx_timer.function = bluesleep_tx_timer_expire;
- tx_timer.data = 0;
-
- /* initialize host wake tasklet */
- tasklet_init(&hostwake_task, hostwake_interrupt, 0);
-
- if (bsi->irq_polarity == POLARITY_LOW) {
- ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
- IRQF_DISABLED | IRQF_TRIGGER_FALLING,
- "bluetooth hostwake", NULL);
- } else {
- ret = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr,
- IRQF_DISABLED | IRQF_TRIGGER_RISING,
- "bluetooth hostwake", NULL);
- }
- if (ret < 0) {
- BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ");
- goto free_bt_timer;
- }
-
- ret = enable_irq_wake(bsi->host_wake_irq);
- if (ret < 0) {
- BT_ERR("Couldn't enable BT_HOST_WAKE as wakeup interrupt");
- free_irq(bsi->host_wake_irq, NULL);
- goto free_bt_timer;
- }
-
return 0;
-free_bt_timer:
- del_timer(&tx_timer);
-free_bt_ext_wake:
- gpio_free(bsi->ext_wake);
-free_bt_host_wake:
- gpio_free(bsi->host_wake);
free_bsi:
kfree(bsi);
+ bsi = NULL;
failed:
return ret;
}
static int bluesleep_remove(struct platform_device *pdev)
{
- /* assert bt wake */
- gpio_set_value(bsi->ext_wake, 0);
- if (disable_irq_wake(bsi->host_wake_irq))
- BT_ERR("Couldn't disable hostwake IRQ wakeup mode\n");
- free_irq(bsi->host_wake_irq, NULL);
- del_timer_sync(&tx_timer);
- gpio_free(bsi->host_wake);
- gpio_free(bsi->ext_wake);
kfree(bsi);
return 0;
}
diff --git a/drivers/bluetooth/hci_ibs.c b/drivers/bluetooth/hci_ibs.c
index fb084f5..6253605 100644
--- a/drivers/bluetooth/hci_ibs.c
+++ b/drivers/bluetooth/hci_ibs.c
@@ -112,6 +112,13 @@
unsigned long rx_vote; /* clock must be on for RX */
struct timer_list tx_idle_timer;
struct timer_list wake_retrans_timer;
+ struct workqueue_struct *workqueue;
+ struct work_struct ws_awake_rx;
+ struct work_struct ws_awake_device;
+ struct work_struct ws_rx_vote_off;
+ struct work_struct ws_tx_vote_off;
+ void *ibs_hu; /* keeps the hci_uart pointer for reference */
+
/* debug */
unsigned long ibs_sent_wacks;
unsigned long ibs_sent_slps;
@@ -242,12 +249,90 @@
return err;
}
+static void ibs_wq_awake_device(struct work_struct *work)
+{
+ struct ibs_struct *ibs = container_of(work, struct ibs_struct,
+ ws_awake_device);
+ struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+
+ BT_DBG(" %p ", hu);
+
+ /* Vote for serial clock */
+ ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
+
+ spin_lock(&ibs->hci_ibs_lock);
+
+ /* send wake indication to device */
+ if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
+ BT_ERR("cannot send WAKE to device");
+
+ ibs->ibs_sent_wakes++; /* debug */
+
+ /* start retransmit timer */
+ mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
+
+ spin_unlock(&ibs->hci_ibs_lock);
+}
+
+static void ibs_wq_awake_rx(struct work_struct *work)
+{
+ struct ibs_struct *ibs = container_of(work, struct ibs_struct,
+ ws_awake_rx);
+ struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+
+ BT_DBG(" %p ", hu);
+
+ ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
+
+ spin_lock(&ibs->hci_ibs_lock);
+ ibs->rx_ibs_state = HCI_IBS_RX_AWAKE;
+ /* Always acknowledge device wake up,
+ * sending IBS message doesn't count as TX ON
+ */
+ if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0)
+ BT_ERR("cannot acknowledge device wake up");
+
+ ibs->ibs_sent_wacks++; /* debug */
+
+ spin_unlock(&ibs->hci_ibs_lock);
+ /* actually send the packets */
+ hci_uart_tx_wakeup(hu);
+
+}
+
+static void ibs_wq_serial_rx_clock_vote_off(struct work_struct *work)
+{
+ struct ibs_struct *ibs = container_of(work, struct ibs_struct,
+ ws_rx_vote_off);
+ struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+
+ BT_DBG(" %p ", hu);
+
+ ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu);
+
+}
+
+static void ibs_wq_serial_tx_clock_vote_off(struct work_struct *work)
+{
+ struct ibs_struct *ibs = container_of(work, struct ibs_struct,
+ ws_tx_vote_off);
+ struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+
+ BT_DBG(" %p ", hu);
+
+ hci_uart_tx_wakeup(hu); /* run HCI tx handling unlocked */
+
+ /* now that message queued to tty driver, vote for tty clocks off */
+ /* It is up to the tty driver to pend the clocks off until tx done. */
+ ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
+
+}
+
static void hci_ibs_tx_idle_timeout(unsigned long arg)
{
struct hci_uart *hu = (struct hci_uart *) arg;
struct ibs_struct *ibs = hu->priv;
unsigned long flags;
- unsigned long vote_tx_sleep = 0;
BT_DBG("hu %p idle timeout in %lu state", hu, ibs->tx_ibs_state);
@@ -267,22 +352,11 @@
}
ibs->tx_ibs_state = HCI_IBS_TX_ASLEEP;
ibs->ibs_sent_slps++; /* debug */
- vote_tx_sleep = 1;
break;
}
- spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+ queue_work(ibs->workqueue, &ibs->ws_tx_vote_off);
- hci_uart_tx_wakeup(hu); /* run HCI tx handling unlocked */
-
- if (!vote_tx_sleep)
- return;
- /* now that message queued to tty driver, vote for tty clocks off */
- /* It is up to the tty driver to pend the clocks off until tx done. */
-
- spin_lock_irqsave_nested(&ibs->hci_ibs_lock,
- flags, SINGLE_DEPTH_NESTING);
- ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
out:
spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
}
@@ -336,6 +410,19 @@
skb_queue_head_init(&ibs->txq);
skb_queue_head_init(&ibs->tx_wait_q);
spin_lock_init(&ibs->hci_ibs_lock);
+ ibs->workqueue = create_singlethread_workqueue("ibs_wq");
+ if (!ibs->workqueue) {
+ BT_ERR("IBS Workqueue not initialized properly");
+ kfree(ibs);
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&ibs->ws_awake_rx, ibs_wq_awake_rx);
+ INIT_WORK(&ibs->ws_awake_device, ibs_wq_awake_device);
+ INIT_WORK(&ibs->ws_rx_vote_off, ibs_wq_serial_rx_clock_vote_off);
+ INIT_WORK(&ibs->ws_tx_vote_off, ibs_wq_serial_tx_clock_vote_off);
+
+ ibs->ibs_hu = (void *)hu;
/* Assume we start with both sides asleep -- extra wakes OK */
ibs->tx_ibs_state = HCI_IBS_TX_ASLEEP;
@@ -432,6 +519,8 @@
skb_queue_purge(&ibs->txq);
del_timer(&ibs->tx_idle_timer);
del_timer(&ibs->wake_retrans_timer);
+ destroy_workqueue(ibs->workqueue);
+ ibs->ibs_hu = NULL;
kfree_skb(ibs->rx_skb);
@@ -463,9 +552,10 @@
/* Make sure clock is on - we may have turned clock off since
* receiving the wake up indicator
*/
- ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
- ibs->rx_ibs_state = HCI_IBS_RX_AWAKE;
- /* deliberate fall-through */
+ /* awake rx clock */
+ queue_work(ibs->workqueue, &ibs->ws_awake_rx);
+ spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+ return;
case HCI_IBS_RX_AWAKE:
/* Always acknowledge device wake up,
* sending IBS message doesn't count as TX ON.
@@ -510,7 +600,8 @@
case HCI_IBS_RX_AWAKE:
/* update state */
ibs->rx_ibs_state = HCI_IBS_RX_ASLEEP;
- ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu);
+ /* vote off rx clock under workqueue */
+ queue_work(ibs->workqueue, &ibs->ws_rx_vote_off);
break;
case HCI_IBS_RX_ASLEEP:
/* deliberate fall-through */
@@ -595,20 +686,12 @@
case HCI_IBS_TX_ASLEEP:
BT_DBG("device asleep, waking up and queueing packet");
- ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
/* save packet for later */
skb_queue_tail(&ibs->tx_wait_q, skb);
- /* awake device */
- if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) {
- BT_ERR("cannot send WAKE to device");
- break;
- }
- ibs->ibs_sent_wakes++; /* debug */
-
- /* start retransmit timer */
- mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
ibs->tx_ibs_state = HCI_IBS_TX_WAKING;
+ /* schedule a work queue to wake up device */
+ queue_work(ibs->workqueue, &ibs->ws_awake_device);
break;
case HCI_IBS_TX_WAKING:
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 0febaf3..69783f4 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -272,6 +272,7 @@
unsigned char *buf_in_smux;
int in_busy_smux;
int diag_smux_enabled;
+ int smux_connected;
/* HSIC variables */
unsigned char *buf_in_hsic;
int hsic_ch;
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index fedcf03..81c6afa 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -296,7 +296,7 @@
usb_diag_free_req(driver->mdm_ch);
}
- if (driver->logging_mode != MEMORY_DEVICE_MODE) {
+ if (driver->logging_mode == USB_MODE) {
if (driver->hsic_device_enabled) {
driver->in_busy_hsic_write_on_device = 1;
driver->in_busy_hsic_read_on_device = 1;
@@ -307,6 +307,7 @@
} else if (driver->diag_smux_enabled) {
driver->in_busy_smux = 1;
driver->lcid = LCID_INVALID;
+ driver->smux_connected = 0;
/* Turn off communication over usb mdm and smux */
msm_smux_close(LCID_VALID);
}
@@ -440,7 +441,8 @@
int ret;
if (driver->diag_smux_enabled) {
if (driver->lcid && driver->usb_buf_mdm_out &&
- (driver->read_len_mdm > 0)) {
+ (driver->read_len_mdm > 0) &&
+ driver->smux_connected) {
ret = msm_smux_write(driver->lcid, NULL,
driver->usb_buf_mdm_out, driver->read_len_mdm);
if (ret)
diff --git a/drivers/char/diag/diagfwd_smux.c b/drivers/char/diag/diagfwd_smux.c
index 8bbc67e..ae90686 100644
--- a/drivers/char/diag/diagfwd_smux.c
+++ b/drivers/char/diag/diagfwd_smux.c
@@ -26,13 +26,17 @@
switch (event_type) {
case SMUX_CONNECTED:
- pr_debug("diag: SMUX_CONNECTED received\n");
+ pr_info("diag: SMUX_CONNECTED received\n");
+ driver->smux_connected = 1;
driver->in_busy_smux = 0;
/* read data from USB MDM channel & Initiate first write */
queue_work(driver->diag_bridge_wq,
&(driver->diag_read_mdm_work));
break;
case SMUX_DISCONNECTED:
+ driver->smux_connected = 0;
+ driver->lcid = LCID_INVALID;
+ msm_smux_close(LCID_VALID);
pr_info("diag: SMUX_DISCONNECTED received\n");
break;
case SMUX_WRITE_DONE:
@@ -112,6 +116,7 @@
pr_info("diag: open SMUX ch, r = %d\n", ret);
} else {
pr_err("diag: failed to open SMUX ch, r = %d\n", ret);
+ return ret;
}
}
/* Poll USB channel to check for data*/
@@ -146,8 +151,20 @@
return ret;
}
+static int diagfwd_smux_remove(struct platform_device *pdev)
+{
+ driver->lcid = LCID_INVALID;
+ driver->smux_connected = 0;
+ driver->diag_smux_enabled = 0;
+ driver->in_busy_smux = 1;
+ kfree(driver->buf_in_smux);
+ driver->buf_in_smux = NULL;
+ return 0;
+}
+
struct platform_driver msm_diagfwd_smux_driver = {
.probe = diagfwd_smux_probe,
+ .remove = diagfwd_smux_remove,
.driver = {
.name = "SMUX_DIAG",
.owner = THIS_MODULE,
diff --git a/drivers/coresight/coresight-etb.c b/drivers/coresight/coresight-etb.c
index 9deec2e..56cee06 100644
--- a/drivers/coresight/coresight-etb.c
+++ b/drivers/coresight/coresight-etb.c
@@ -30,7 +30,6 @@
#include "coresight-priv.h"
-
#define etb_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
#define etb_readl(drvdata, off) __raw_readl(drvdata->base + off)
@@ -45,7 +44,6 @@
mb(); \
} while (0)
-
#define ETB_RAM_DEPTH_REG (0x004)
#define ETB_STATUS_REG (0x00C)
#define ETB_RAM_READ_DATA_REG (0x010)
@@ -64,12 +62,10 @@
#define ETB_ITATBCTR1 (0xEF4)
#define ETB_ITATBCTR0 (0xEF8)
-
#define BYTES_PER_WORD 4
#define ETB_SIZE_WORDS 4096
#define FRAME_SIZE_WORDS 4
-
struct etb_drvdata {
void __iomem *base;
struct device *dev;
@@ -84,7 +80,6 @@
uint32_t trigger_cntr;
};
-
static void __etb_enable(struct etb_drvdata *drvdata)
{
int i;
@@ -381,6 +376,7 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
+
drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!drvdata->base)
return -ENOMEM;
@@ -390,6 +386,7 @@
drvdata->clk = devm_clk_get(dev, "core_clk");
if (IS_ERR(drvdata->clk))
return PTR_ERR(drvdata->clk);
+
ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
if (ret)
return ret;
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index 73a16e6..46d3e5d 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -35,7 +35,6 @@
#include "coresight-priv.h"
-
#define etm_writel(drvdata, val, off) \
__raw_writel((val), drvdata->base + off)
#define etm_readl(drvdata, off) \
@@ -52,7 +51,6 @@
mb(); \
} while (0)
-
/*
* Device registers:
* 0x000 - 0x2FC: Trace registers
@@ -117,7 +115,6 @@
#define ETMPDCR (0x310)
#define ETMPDSR (0x314)
-
#define ETM_MAX_ADDR_CMP (16)
#define ETM_MAX_CNTR (4)
#define ETM_MAX_CTXID_CMP (3)
@@ -143,7 +140,6 @@
ETM_ADDR_TYPE_STOP,
};
-
#ifdef CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE
static int boot_enable = 1;
#else
@@ -199,7 +195,6 @@
uint32_t timestamp_event;
};
-
/* ETM clock is derived from the processor clock and gets enabled on a
* logical OR of below items on Krait (pass2 onwards):
* 1.CPMR[ETMCLKEN] is 1
@@ -482,7 +477,11 @@
for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
drvdata->ctxid_val[i] = 0x0;
drvdata->ctxid_mask = 0x0;
- drvdata->sync_freq = 0x80;
+ /* Bits[7:0] of ETMSYNCFR are reserved on Krait pass3 onwards */
+ if (cpu_is_krait() && !cpu_is_krait_v1() && !cpu_is_krait_v2())
+ drvdata->sync_freq = 0x100;
+ else
+ drvdata->sync_freq = 0x80;
drvdata->timestamp_event = 0x406F;
}
mutex_unlock(&drvdata->mutex);
@@ -1484,7 +1483,11 @@
drvdata->seq_31_event = 0x406F;
drvdata->seq_32_event = 0x406F;
drvdata->seq_13_event = 0x406F;
- drvdata->sync_freq = 0x80;
+ /* Bits[7:0] of ETMSYNCFR are reserved on Krait pass3 onwards */
+ if (cpu_is_krait() && !cpu_is_krait_v1() && !cpu_is_krait_v2())
+ drvdata->sync_freq = 0x100;
+ else
+ drvdata->sync_freq = 0x80;
drvdata->timestamp_event = 0x406F;
/* Overrides for Krait pass1 */
@@ -1513,6 +1516,12 @@
static int etm_count;
struct coresight_desc *desc;
+ /* Fail probe for Krait pass3 until supported */
+ if (cpu_is_krait_v3()) {
+ dev_info(dev, "ETM: failing probe for Krait pass3\n");
+ return -EINVAL;
+ }
+
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
@@ -1529,6 +1538,7 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
+
drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!drvdata->base)
return -ENOMEM;
@@ -1543,6 +1553,7 @@
ret = PTR_ERR(drvdata->clk);
goto err0;
}
+
ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
if (ret)
goto err0;
@@ -1552,10 +1563,12 @@
ret = clk_prepare_enable(drvdata->clk);
if (ret)
goto err0;
+
ret = etm_init_arch_data(drvdata);
if (ret)
goto err1;
etm_init_default_data(drvdata);
+
clk_disable_unprepare(drvdata->clk);
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c
index bf1df0b..3d5c0c2 100644
--- a/drivers/coresight/coresight-funnel.c
+++ b/drivers/coresight/coresight-funnel.c
@@ -25,7 +25,6 @@
#include "coresight-priv.h"
-
#define funnel_writel(drvdata, val, off) \
__raw_writel((val), drvdata->base + off)
#define funnel_readl(drvdata, off) \
@@ -42,7 +41,6 @@
mb(); \
} while (0)
-
#define FUNNEL_FUNCTL (0x000)
#define FUNNEL_PRICTL (0x004)
#define FUNNEL_ITATBDATA0 (0xEEC)
@@ -50,12 +48,10 @@
#define FUNNEL_ITATBCTR1 (0xEF4)
#define FUNNEL_ITATBCTR0 (0xEF8)
-
#define FUNNEL_HOLDTIME_MASK (0xF00)
#define FUNNEL_HOLDTIME_SHFT (0x8)
#define FUNNEL_HOLDTIME (0x7 << FUNNEL_HOLDTIME_SHFT)
-
struct funnel_drvdata {
void __iomem *base;
struct device *dev;
@@ -64,7 +60,6 @@
uint32_t priority;
};
-
static void __funnel_enable(struct funnel_drvdata *drvdata, int port)
{
uint32_t functl;
@@ -195,6 +190,7 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
+
drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!drvdata->base)
return -ENOMEM;
@@ -202,6 +198,7 @@
drvdata->clk = devm_clk_get(dev, "core_clk");
if (IS_ERR(drvdata->clk))
return PTR_ERR(drvdata->clk);
+
ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
if (ret)
return ret;
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index a6486da..a28a3a5 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -15,7 +15,6 @@
#include <linux/bitops.h>
-
/* Coresight management registers (0xF00-0xFCC)
* 0xFA0 - 0xFA4: Management registers in PFTv1.0
* Trace registers in PFTv1.1
@@ -29,7 +28,6 @@
#define CORESIGHT_DEVID (0xFC8)
#define CORESIGHT_DEVTYPE (0xFCC)
-
#define CORESIGHT_UNLOCK (0xC5ACCE55)
#define TIMEOUT_US (100)
diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c
index ccf49e9..fec76c5 100644
--- a/drivers/coresight/coresight-replicator.c
+++ b/drivers/coresight/coresight-replicator.c
@@ -24,7 +24,6 @@
#include "coresight-priv.h"
-
#define replicator_writel(drvdata, val, off) \
__raw_writel((val), drvdata->base + off)
#define replicator_readl(drvdata, off) \
@@ -41,13 +40,11 @@
mb(); \
} while (0)
-
#define REPLICATOR_IDFILTER0 (0x000)
#define REPLICATOR_IDFILTER1 (0x004)
#define REPLICATOR_ITATBCTR0 (0xEFC)
#define REPLICATOR_ITATBCTR1 (0xEF8)
-
struct replicator_drvdata {
void __iomem *base;
struct device *dev;
@@ -55,7 +52,6 @@
struct clk *clk;
};
-
static void __replicator_enable(struct replicator_drvdata *drvdata, int outport)
{
REPLICATOR_UNLOCK(drvdata);
@@ -146,6 +142,7 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
+
drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!drvdata->base)
return -ENOMEM;
@@ -153,6 +150,7 @@
drvdata->clk = devm_clk_get(dev, "core_clk");
if (IS_ERR(drvdata->clk))
return PTR_ERR(drvdata->clk);
+
ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
if (ret)
return ret;
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
index 050a01d..e366918 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -31,7 +31,6 @@
#include "coresight-priv.h"
-
#define stm_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
#define stm_readl(drvdata, off) __raw_readl(drvdata->base + off)
@@ -78,7 +77,6 @@
#define STMITATBID (0xEF4)
#define STMITATBCTR0 (0xEF8)
-
#define NR_STM_CHANNEL (32)
#define BYTES_PER_CHANNEL (256)
#define STM_TRACE_BUF_SIZE (1024)
@@ -100,7 +98,6 @@
(ch * BYTES_PER_CHANNEL))
#define stm_channel_off(type, opts) (type & ~opts)
-
#ifdef CONFIG_MSM_QDSS_STM_DEFAULT_ENABLE
static int boot_enable = 1;
#else
@@ -136,7 +133,6 @@
static struct stm_drvdata *stmdrvdata;
-
static int stm_hwevent_isenable(struct stm_drvdata *drvdata)
{
int ret = 0;
@@ -664,6 +660,7 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
+
drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!drvdata->base)
return -ENOMEM;
@@ -671,6 +668,7 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res)
return -ENODEV;
+
if (boot_nr_channel) {
res_size = min((resource_size_t)(boot_nr_channel *
BYTES_PER_CHANNEL), resource_size(res));
@@ -692,6 +690,7 @@
drvdata->clk = devm_clk_get(dev, "core_clk");
if (IS_ERR(drvdata->clk))
return PTR_ERR(drvdata->clk);
+
ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
if (ret)
return ret;
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 02b8378..1c85aff 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -32,7 +32,6 @@
#include "coresight-priv.h"
-
#define tmc_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
#define tmc_readl(drvdata, off) __raw_readl(drvdata->base + off)
@@ -47,7 +46,6 @@
mb(); \
} while (0)
-
#define TMC_RSZ (0x004)
#define TMC_STS (0x00C)
#define TMC_RRD (0x010)
@@ -75,7 +73,6 @@
#define TMC_ITATBCTR1 (0xEF4)
#define TMC_ITATBCTR0 (0xEF8)
-
#define BYTES_PER_WORD 4
enum tmc_config_type {
@@ -97,7 +94,6 @@
TMC_MEM_INTF_WIDTH_256BITS = 0x5,
};
-
struct tmc_drvdata {
void __iomem *base;
struct device *dev;
@@ -116,7 +112,6 @@
uint32_t trigger_cntr;
};
-
static void tmc_wait_for_ready(struct tmc_drvdata *drvdata)
{
int count;
@@ -643,6 +638,7 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
+
drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!drvdata->base)
return -ENOMEM;
@@ -652,6 +648,7 @@
drvdata->clk = devm_clk_get(dev, "core_clk");
if (IS_ERR(drvdata->clk))
return PTR_ERR(drvdata->clk);
+
ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
if (ret)
return ret;
@@ -659,12 +656,15 @@
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
+
devid = tmc_readl(drvdata, CORESIGHT_DEVID);
drvdata->config_type = BMVAL(devid, 6, 7);
+
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
drvdata->size = SZ_1M;
else
drvdata->size = tmc_readl(drvdata, TMC_RSZ) * BYTES_PER_WORD;
+
clk_disable_unprepare(drvdata->clk);
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index 6984e32..290ae7f 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -24,7 +24,6 @@
#include "coresight-priv.h"
-
#define tpiu_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
#define tpiu_readl(drvdata, off) __raw_readl(drvdata->base + off)
@@ -39,7 +38,6 @@
mb(); \
} while (0)
-
#define TPIU_SUPP_PORTSZ (0x000)
#define TPIU_CURR_PORTSZ (0x004)
#define TPIU_SUPP_TRIGMODES (0x100)
@@ -60,7 +58,6 @@
#define TPIU_ITATBCTR1 (0xEF4)
#define TPIU_ITATBCTR0 (0xEF8)
-
struct tpiu_drvdata {
void __iomem *base;
struct device *dev;
@@ -68,7 +65,6 @@
struct clk *clk;
};
-
static void __tpiu_enable(struct tpiu_drvdata *drvdata)
{
TPIU_UNLOCK(drvdata);
@@ -158,6 +154,7 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
+
drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!drvdata->base)
return -ENOMEM;
@@ -165,15 +162,18 @@
drvdata->clk = devm_clk_get(dev, "core_clk");
if (IS_ERR(drvdata->clk))
return PTR_ERR(drvdata->clk);
+
ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
if (ret)
return ret;
- /* Disable tpiu to support older targets that need this */
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
+
+ /* Disable tpiu to support older targets that need this */
__tpiu_disable(drvdata);
+
clk_disable_unprepare(drvdata->clk);
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
index 455ed1d..f76d303 100644
--- a/drivers/coresight/coresight.c
+++ b/drivers/coresight/coresight.c
@@ -26,16 +26,13 @@
#include "coresight-priv.h"
-
#define NO_SINK (-1)
-
static int curr_sink = NO_SINK;
static LIST_HEAD(coresight_orph_conns);
static LIST_HEAD(coresight_devs);
static DEFINE_SEMAPHORE(coresight_mutex);
-
static int coresight_find_link_inport(struct coresight_device *csdev)
{
int i;
diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c
index cdc76f1..5c2c525 100644
--- a/drivers/coresight/of_coresight.c
+++ b/drivers/coresight/of_coresight.c
@@ -17,7 +17,6 @@
#include <linux/of.h>
#include <linux/coresight.h>
-
struct coresight_platform_data *of_get_coresight_platform_data(
struct device *dev, struct device_node *node)
{
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 63f7fd9..f1c31c1 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -2038,18 +2038,6 @@
podev->pdev = pdev;
platform_set_drvdata(pdev, podev);
- if (podev->platform_support.bus_scale_table != NULL) {
- podev->bus_scale_handle =
- msm_bus_scale_register_client(
- (struct msm_bus_scale_pdata *)
- podev->platform_support.bus_scale_table);
- if (!podev->bus_scale_handle) {
- printk(KERN_ERR "%s not able to get bus scale\n",
- __func__);
- rc = -ENOMEM;
- goto err;
- }
- }
rc = misc_register(&podev->miscdevice);
qce_hw_support(podev->qce, &podev->ce_support);
if (podev->ce_support.bam) {
@@ -2070,6 +2058,18 @@
platform_support->bus_scale_table;
podev->platform_support.sha_hmac = platform_support->sha_hmac;
}
+ if (podev->platform_support.bus_scale_table != NULL) {
+ podev->bus_scale_handle =
+ msm_bus_scale_register_client(
+ (struct msm_bus_scale_pdata *)
+ podev->platform_support.bus_scale_table);
+ if (!podev->bus_scale_handle) {
+ pr_err("%s not able to get bus scale\n",
+ __func__);
+ rc = -ENOMEM;
+ goto err;
+ }
+ }
if (rc >= 0)
return 0;
else
diff --git a/drivers/gpio/gpio-msm-v3.c b/drivers/gpio/gpio-msm-v3.c
index e0b01cd..26716a0 100644
--- a/drivers/gpio/gpio-msm-v3.c
+++ b/drivers/gpio/gpio-msm-v3.c
@@ -141,7 +141,7 @@
void __msm_gpio_set_intr_status(unsigned gpio)
{
- __raw_writel(BIT(INTR_STATUS_BIT), GPIO_INTR_STATUS(gpio));
+ __raw_writel(0, GPIO_INTR_STATUS(gpio));
}
unsigned __msm_gpio_get_intr_config(unsigned gpio)
@@ -167,15 +167,12 @@
{
unsigned cfg;
- cfg = __raw_readl(GPIO_INTR_CFG(gpio));
-
/* RAW_STATUS_EN is left on for all gpio irqs. Due to the
* internal circuitry of TLMM, toggling the RAW_STATUS
* could cause the INTR_STATUS to be set for EDGE interrupts.
*/
- cfg |= (INTR_RAW_STATUS_EN | INTR_TARGET_PROC_APPS);
+ cfg = INTR_RAW_STATUS_EN | INTR_TARGET_PROC_APPS;
__raw_writel(cfg, GPIO_INTR_CFG(gpio));
- cfg = __raw_readl(GPIO_INTR_CFG(gpio));
cfg &= ~INTR_DECT_CTL_MASK;
if (type == IRQ_TYPE_EDGE_RISING)
cfg |= INTR_DECT_CTL_POS_EDGE;
@@ -186,10 +183,10 @@
else
cfg |= INTR_DECT_CTL_LEVEL;
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
- cfg |= INTR_POL_CTL_HI;
- else
+ if (type & IRQ_TYPE_LEVEL_LOW)
cfg &= ~INTR_POL_CTL_HI;
+ else
+ cfg |= INTR_POL_CTL_HI;
__raw_writel(cfg, GPIO_INTR_CFG(gpio));
/* Sometimes it might take a little while to update
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index ccbbd67..67a2e6b 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -31,25 +31,35 @@
((q_spec)->offset + reg_index)
#define Q_REG_STATUS1 0x8
+#define Q_REG_STATUS1_VAL_MASK 0x1
+#define Q_REG_STATUS1_GPIO_EN_REV0_MASK 0x2
+#define Q_REG_STATUS1_GPIO_EN_MASK 0x80
+#define Q_REG_STATUS1_MPP_EN_MASK 0x80
+
#define Q_NUM_CTL_REGS 0xD
+/* revision registers base address offsets */
+#define Q_REG_DIG_MINOR_REV 0x0
+#define Q_REG_DIG_MAJOR_REV 0x1
+#define Q_REG_ANA_MINOR_REV 0x2
+
/* type registers base address offsets */
#define Q_REG_TYPE 0x4
#define Q_REG_SUBTYPE 0x5
/* gpio peripheral type and subtype values */
#define Q_GPIO_TYPE 0x10
-#define Q_GPIO_SUBTYPE_GPIO_4CH 0x0
-#define Q_GPIO_SUBTYPE_GPIOC_4CH 0x2
-#define Q_GPIO_SUBTYPE_GPIO_8CH 0x4
-#define Q_GPIO_SUBTYPE_GPIOC_8CH 0x6
+#define Q_GPIO_SUBTYPE_GPIO_4CH 0x1
+#define Q_GPIO_SUBTYPE_GPIOC_4CH 0x5
+#define Q_GPIO_SUBTYPE_GPIO_8CH 0x9
+#define Q_GPIO_SUBTYPE_GPIOC_8CH 0xD
/* mpp peripheral type and subtype values */
#define Q_MPP_TYPE 0x11
#define Q_MPP_SUBTYPE_4CH_NO_ANA_OUT 0x3
#define Q_MPP_SUBTYPE_4CH_NO_SINK 0x5
-#define Q_MPP_SUBTYPE_4CH_FULL_FUNC 0x2
-#define Q_MPP_SUBTYPE_8CH_FULL_FUNC 0x4
+#define Q_MPP_SUBTYPE_4CH_FULL_FUNC 0x7
+#define Q_MPP_SUBTYPE_8CH_FULL_FUNC 0xF
/* control register base address offsets */
#define Q_REG_MODE_CTL 0x40
@@ -129,7 +139,8 @@
#define Q_NUM_PARAMS Q_PIN_CFG_INVALID
/* param error checking */
-#define QPNP_PIN_MODE_INVALID 3
+#define QPNP_PIN_GPIO_MODE_INVALID 3
+#define QPNP_PIN_MPP_MODE_INVALID 7
#define QPNP_PIN_INVERT_INVALID 2
#define QPNP_PIN_OUT_BUF_INVALID 3
#define QPNP_PIN_VIN_4CH_INVALID 5
@@ -153,6 +164,7 @@
u8 num_ctl_regs; /* usable number on this pin */
u8 type; /* peripheral type */
u8 subtype; /* peripheral subtype */
+ u8 dig_major_rev;
struct device_node *node;
enum qpnp_pin_param_type params[Q_NUM_PARAMS];
struct qpnp_pin_chip *q_chip;
@@ -225,8 +237,12 @@
{
switch (idx) {
case Q_PIN_CFG_MODE:
- if (val >= QPNP_PIN_MODE_INVALID)
- return -EINVAL;
+ if (q_spec->type == Q_GPIO_TYPE &&
+ val >= QPNP_PIN_GPIO_MODE_INVALID)
+ return -EINVAL;
+ else if (q_spec->type == Q_MPP_TYPE &&
+ val >= QPNP_PIN_MPP_MODE_INVALID)
+ return -EINVAL;
break;
case Q_PIN_CFG_OUTPUT_TYPE:
if (q_spec->type != Q_GPIO_TYPE)
@@ -327,29 +343,40 @@
name = (q_spec->type == Q_GPIO_TYPE) ? "gpio" : "mpp";
if (Q_CHK_INVALID(Q_PIN_CFG_MODE, q_spec, param->mode))
- pr_err("invalid direction for %s %d\n", name, pin);
+ pr_err("invalid direction value %d for %s %d\n",
+ param->mode, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_INVERT, q_spec, param->invert))
- pr_err("invalid invert polarity for %s %d\n", name, pin);
+ pr_err("invalid invert polarity value %d for %s %d\n",
+ param->invert, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_SELECT, q_spec, param->select))
- pr_err("invalid source select for %s %d\n", name, pin);
+ pr_err("invalid source select value %d for %s %d\n",
+ param->select, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_OUT_STRENGTH,
q_spec, param->out_strength))
- pr_err("invalid out strength for %s %d\n", name, pin);
+ pr_err("invalid out strength value %d for %s %d\n",
+ param->out_strength, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_OUTPUT_TYPE,
q_spec, param->output_type))
- pr_err("invalid out type for %s %d\n", name, pin);
+ pr_err("invalid out type value %d for %s %d\n",
+ param->output_type, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_VIN_SEL, q_spec, param->vin_sel))
- pr_err("invalid vin select value for %s %d\n", name, pin);
+ pr_err("invalid vin select %d value for %s %d\n",
+ param->vin_sel, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_PULL, q_spec, param->pull))
- pr_err("invalid pull value for pin %s %d\n", name, pin);
+ pr_err("invalid pull value %d for pin %s %d\n",
+ param->pull, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_MASTER_EN, q_spec, param->master_en))
- pr_err("invalid master_en value for %s %d\n", name, pin);
+ pr_err("invalid master_en value %d for %s %d\n",
+ param->master_en, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_AOUT_REF, q_spec, param->aout_ref))
- pr_err("invalid aout_reg value for %s %d\n", name, pin);
+ pr_err("invalid aout_reg value %d for %s %d\n",
+ param->aout_ref, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_AIN_ROUTE, q_spec, param->ain_route))
- pr_err("invalid ain_route value for %s %d\n", name, pin);
+ pr_err("invalid ain_route value %d for %s %d\n",
+ param->ain_route, name, pin);
else if (Q_CHK_INVALID(Q_PIN_CFG_CS_OUT, q_spec, param->cs_out))
- pr_err("invalid cs_out value for %s %d\n", name, pin);
+ pr_err("invalid cs_out value %d for %s %d\n",
+ param->cs_out, name, pin);
else
return 0;
@@ -402,39 +429,41 @@
}
static int qpnp_pin_read_regs(struct qpnp_pin_chip *q_chip,
- struct qpnp_pin_spec *q_spec, u16 addr, u8 *buf)
+ struct qpnp_pin_spec *q_spec)
{
int bytes_left = q_spec->num_ctl_regs;
int rc;
- char *reg_p = &q_spec->regs[0];
+ char *buf_p = &q_spec->regs[0];
+ u16 reg_addr = Q_REG_ADDR(q_spec, Q_REG_MODE_CTL);
while (bytes_left > 0) {
rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
- Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
- reg_p, bytes_left < 8 ? bytes_left : 8);
+ reg_addr, buf_p, bytes_left < 8 ? bytes_left : 8);
if (rc)
return rc;
bytes_left -= 8;
- reg_p += 8;
+ buf_p += 8;
+ reg_addr += 8;
}
return 0;
}
static int qpnp_pin_write_regs(struct qpnp_pin_chip *q_chip,
- struct qpnp_pin_spec *q_spec, u16 addr, u8 *buf)
+ struct qpnp_pin_spec *q_spec)
{
int bytes_left = q_spec->num_ctl_regs;
int rc;
- char *reg_p = &q_spec->regs[0];
+ char *buf_p = &q_spec->regs[0];
+ u16 reg_addr = Q_REG_ADDR(q_spec, Q_REG_MODE_CTL);
while (bytes_left > 0) {
rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
- Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
- reg_p, bytes_left < 8 ? bytes_left : 8);
+ reg_addr, buf_p, bytes_left < 8 ? bytes_left : 8);
if (rc)
return rc;
bytes_left -= 8;
- reg_p += 8;
+ buf_p += 8;
+ reg_addr += 8;
}
return 0;
}
@@ -445,9 +474,7 @@
int rc;
struct device *dev = &q_chip->spmi->dev;
- rc = qpnp_pin_read_regs(q_chip, q_spec,
- Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
- &q_spec->regs[Q_REG_I_MODE_CTL]);
+ rc = qpnp_pin_read_regs(q_chip, q_spec);
if (rc)
dev_err(dev, "%s: unable to read control regs\n", __func__);
@@ -520,9 +547,7 @@
Q_REG_CS_OUT_SHIFT, Q_REG_CS_OUT_MASK,
param->cs_out);
- rc = qpnp_pin_write_regs(q_chip, q_spec,
- Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
- &q_spec->regs[Q_REG_I_MODE_CTL]);
+ rc = qpnp_pin_write_regs(q_chip, q_spec);
if (rc) {
dev_err(&q_chip->spmi->dev, "%s: unable to write master enable\n",
__func__);
@@ -532,7 +557,7 @@
return 0;
gpio_cfg:
- dev_err(dev, "%s: unable to set default config for pmic gpio %d\n",
+ dev_err(dev, "%s: unable to set default config for pmic pin %d\n",
__func__, q_spec->pmic_pin);
return rc;
@@ -612,7 +637,7 @@
int rc, ret_val;
struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
struct qpnp_pin_spec *q_spec = NULL;
- u8 buf[1];
+ u8 buf[1], en_mask;
if (WARN_ON(!q_chip))
return -ENODEV;
@@ -624,11 +649,22 @@
/* gpio val is from RT status iff input is enabled */
if ((q_spec->regs[Q_REG_I_MODE_CTL] & Q_REG_MODE_SEL_MASK)
== QPNP_PIN_MODE_DIG_IN) {
- /* INT_RT_STS */
rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
Q_REG_ADDR(q_spec, Q_REG_STATUS1),
&buf[0], 1);
- return buf[0];
+
+ if (q_spec->type == Q_GPIO_TYPE && q_spec->dig_major_rev == 0)
+ en_mask = Q_REG_STATUS1_GPIO_EN_REV0_MASK;
+ else if (q_spec->type == Q_GPIO_TYPE &&
+ q_spec->dig_major_rev > 0)
+ en_mask = Q_REG_STATUS1_GPIO_EN_MASK;
+ else /* MPP */
+ en_mask = Q_REG_STATUS1_MPP_EN_MASK;
+
+ if (!(buf[0] & en_mask))
+ return -EPERM;
+
+ return buf[0] & Q_REG_STATUS1_VAL_MASK;
} else {
ret_val = (q_spec->regs[Q_REG_I_MODE_CTL] &
@@ -655,7 +691,7 @@
Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 0);
rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
- Q_REG_ADDR(q_spec, Q_REG_I_MODE_CTL),
+ Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
&q_spec->regs[Q_REG_I_MODE_CTL], 1);
if (rc)
dev_err(&q_chip->spmi->dev, "%s: spmi write failed\n",
@@ -688,7 +724,7 @@
if (!q_chip || !q_spec)
return -EINVAL;
- if (mode >= QPNP_PIN_MODE_INVALID) {
+ if (qpnp_pin_check_config(Q_PIN_CFG_MODE, q_spec, mode)) {
pr_err("invalid mode specification %d\n", mode);
return -EINVAL;
}
@@ -699,7 +735,7 @@
mode);
rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
- Q_REG_ADDR(q_spec, Q_REG_I_MODE_CTL),
+ Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
&q_spec->regs[Q_REG_I_MODE_CTL], 1);
return rc;
}
@@ -783,7 +819,7 @@
Q_REG_OUT_TYPE_SHIFT,
Q_REG_OUT_TYPE_MASK);
param.invert = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
- Q_REG_OUT_INVERT_MASK,
+ Q_REG_OUT_INVERT_SHIFT,
Q_REG_OUT_INVERT_MASK);
param.pull = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
Q_REG_PULL_SHIFT, Q_REG_PULL_MASK);
@@ -1075,6 +1111,28 @@
}
#endif
+static int qpnp_pin_is_valid_pin(struct qpnp_pin_spec *q_spec)
+{
+ if (q_spec->type == Q_GPIO_TYPE)
+ switch (q_spec->subtype) {
+ case Q_GPIO_SUBTYPE_GPIO_4CH:
+ case Q_GPIO_SUBTYPE_GPIOC_4CH:
+ case Q_GPIO_SUBTYPE_GPIO_8CH:
+ case Q_GPIO_SUBTYPE_GPIOC_8CH:
+ return 1;
+ }
+ else if (q_spec->type == Q_MPP_TYPE)
+ switch (q_spec->subtype) {
+ case Q_MPP_SUBTYPE_4CH_NO_ANA_OUT:
+ case Q_MPP_SUBTYPE_4CH_NO_SINK:
+ case Q_MPP_SUBTYPE_4CH_FULL_FUNC:
+ case Q_MPP_SUBTYPE_8CH_FULL_FUNC:
+ return 1;
+ }
+
+ return 0;
+}
+
static int qpnp_pin_probe(struct spmi_device *spmi)
{
struct qpnp_pin_chip *q_chip;
@@ -1084,7 +1142,7 @@
int i, rc;
int lowest_gpio = UINT_MAX, highest_gpio = 0;
u32 intspec[3], gpio;
- char buf[2];
+ char version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV + 1];
const char *dev_name;
dev_name = spmi_get_primary_dev_name(spmi);
@@ -1194,14 +1252,23 @@
q_spec->q_chip = q_chip;
rc = spmi_ext_register_readl(spmi->ctrl, q_spec->slave,
- Q_REG_ADDR(q_spec, Q_REG_TYPE), &buf[0], 2);
+ Q_REG_ADDR(q_spec, Q_REG_DIG_MAJOR_REV),
+ &version[0], ARRAY_SIZE(version));
if (rc) {
dev_err(&spmi->dev, "%s: unable to read type regs\n",
__func__);
goto err_probe;
}
- q_spec->type = buf[0];
- q_spec->subtype = buf[1];
+ q_spec->dig_major_rev = version[Q_REG_DIG_MAJOR_REV -
+ Q_REG_DIG_MAJOR_REV];
+ q_spec->type = version[Q_REG_TYPE - Q_REG_DIG_MAJOR_REV];
+ q_spec->subtype = version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV];
+
+ if (!qpnp_pin_is_valid_pin(q_spec)) {
+ dev_err(&spmi->dev, "%s: invalid pin type (type=0x%x subtype=0x%x)\n",
+ __func__, q_spec->type, q_spec->subtype);
+ goto err_probe;
+ }
rc = qpnp_pin_ctl_regs_init(q_spec);
if (rc)
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 6a894c8..6e95fff 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -111,7 +111,7 @@
.gmem_size = SZ_256K,
.pfp_fw = NULL,
.pm4_fw = NULL,
- .wait_timeout = 10000, /* in milliseconds */
+ .wait_timeout = 0, /* in milliseconds, 0 means disabled */
.ib_check_level = 0,
};
@@ -179,7 +179,7 @@
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_256K },
/* A3XX doesn't use the pix_shader_start */
- { ADRENO_REV_A320, 3, 2, 0, ANY_ID,
+ { ADRENO_REV_A320, 3, 2, ANY_ID, ANY_ID,
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_512K },
{ ADRENO_REV_A330, 3, 3, 0, 0,
@@ -275,25 +275,20 @@
unsigned int *cmds = &link[0];
int sizedwords = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct kgsl_memdesc **reg_map_desc;
- void *reg_map_array = NULL;
int num_iommu_units, i;
struct kgsl_context *context;
struct adreno_context *adreno_ctx = NULL;
if (!adreno_dev->drawctxt_active)
return kgsl_mmu_device_setstate(&device->mmu, flags);
- num_iommu_units = kgsl_mmu_get_reg_map_desc(&device->mmu,
- ®_map_array);
+ num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
context = idr_find(&device->context_idr, context_id);
adreno_ctx = context->devctxt;
- reg_map_desc = reg_map_array;
-
if (kgsl_mmu_enable_clk(&device->mmu,
KGSL_IOMMU_CONTEXT_USER))
- goto done;
+ return;
cmds += __adreno_add_idle_indirect_cmds(cmds,
device->mmu.setstate_memory.gpuaddr +
@@ -309,26 +304,23 @@
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
- pt_val = kgsl_mmu_pt_get_base_addr(device->mmu.hwpagetable);
+ pt_val = kgsl_mmu_get_pt_base_addr(&device->mmu,
+ device->mmu.hwpagetable);
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
/*
* We need to perfrom the following operations for all
* IOMMU units
*/
for (i = 0; i < num_iommu_units; i++) {
- reg_pt_val = (pt_val &
- (KGSL_IOMMU_TTBR0_PA_MASK <<
- KGSL_IOMMU_TTBR0_PA_SHIFT)) +
- kgsl_mmu_get_pt_lsb(&device->mmu, i,
- KGSL_IOMMU_CONTEXT_USER);
+ reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
+ i, KGSL_IOMMU_CONTEXT_USER));
/*
* Set address of the new pagetable by writng to IOMMU
* TTBR0 register
*/
*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
- *cmds++ = reg_map_desc[i]->gpuaddr +
- (KGSL_IOMMU_CONTEXT_USER <<
- KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0;
+ *cmds++ = kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+ KGSL_IOMMU_CONTEXT_USER, KGSL_IOMMU_CTX_TTBR0);
*cmds++ = reg_pt_val;
*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
*cmds++ = 0x00000000;
@@ -338,9 +330,8 @@
* above writes have completed
*/
cmds += adreno_add_read_cmds(device, cmds,
- reg_map_desc[i]->gpuaddr +
- (KGSL_IOMMU_CONTEXT_USER <<
- KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0,
+ kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+ KGSL_IOMMU_CONTEXT_USER, KGSL_IOMMU_CTX_TTBR0),
reg_pt_val,
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
@@ -358,16 +349,12 @@
* tlb flush
*/
for (i = 0; i < num_iommu_units; i++) {
- reg_pt_val = (pt_val &
- (KGSL_IOMMU_TTBR0_PA_MASK <<
- KGSL_IOMMU_TTBR0_PA_SHIFT)) +
- kgsl_mmu_get_pt_lsb(&device->mmu, i,
- KGSL_IOMMU_CONTEXT_USER);
+ reg_pt_val = (pt_val + kgsl_mmu_get_pt_lsb(&device->mmu,
+ i, KGSL_IOMMU_CONTEXT_USER));
*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
- *cmds++ = (reg_map_desc[i]->gpuaddr +
- (KGSL_IOMMU_CONTEXT_USER <<
- KGSL_IOMMU_CTX_SHIFT) +
+ *cmds++ = kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+ KGSL_IOMMU_CONTEXT_USER,
KGSL_IOMMU_CTX_TLBIALL);
*cmds++ = 1;
@@ -376,9 +363,9 @@
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
cmds += adreno_add_read_cmds(device, cmds,
- reg_map_desc[i]->gpuaddr +
- (KGSL_IOMMU_CONTEXT_USER <<
- KGSL_IOMMU_CTX_SHIFT) + KGSL_IOMMU_TTBR0,
+ kgsl_mmu_get_reg_gpuaddr(&device->mmu, i,
+ KGSL_IOMMU_CONTEXT_USER,
+ KGSL_IOMMU_CTX_TTBR0),
reg_pt_val,
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
@@ -387,7 +374,8 @@
if (cpu_is_msm8960())
cmds += adreno_add_change_mh_phys_limit_cmds(cmds,
- reg_map_desc[num_iommu_units - 1]->gpuaddr - PAGE_SIZE,
+ kgsl_mmu_get_reg_gpuaddr(&device->mmu, 0,
+ 0, KGSL_IOMMU_GLOBAL_BASE),
device->mmu.setstate_memory.gpuaddr +
KGSL_IOMMU_SETSTATE_NOP_OFFSET);
else
@@ -413,9 +401,6 @@
kgsl_mmu_disable_clk_on_ts(&device->mmu,
adreno_dev->ringbuffer.timestamp[KGSL_MEMSTORE_GLOBAL], true);
}
-done:
- if (num_iommu_units)
- kfree(reg_map_array);
}
static void adreno_gpummu_setstate(struct kgsl_device *device,
@@ -453,7 +438,7 @@
/* set page table base */
*cmds++ = cp_type0_packet(MH_MMU_PT_BASE, 1);
- *cmds++ = kgsl_mmu_pt_get_base_addr(
+ *cmds++ = kgsl_mmu_get_pt_base_addr(&device->mmu,
device->mmu.hwpagetable);
sizedwords += 4;
}
@@ -1481,7 +1466,7 @@
* them to pass */
adreno_ringbuffer_restore(rb, rec_data->bad_rb_buffer,
rec_data->bad_rb_size);
- idle_ret = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ idle_ret = adreno_idle(device);
if (idle_ret) {
ret = adreno_stop(device);
if (ret) {
@@ -1524,7 +1509,7 @@
if (ret || !rec_data->bad_rb_size) {
adreno_ringbuffer_restore(rb, rec_data->rb_buffer,
rec_data->rb_size);
- ret = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ ret = adreno_idle(device);
if (ret) {
/* If we fail here we can try to invalidate another
* context and try recovering again */
@@ -1806,61 +1791,74 @@
adreno_regwrite(device, REG_CP_RB_WPTR, adreno_dev->ringbuffer.wptr);
}
-/* Caller must hold the device mutex. */
-int adreno_idle(struct kgsl_device *device, unsigned int timeout)
+static int adreno_ringbuffer_drain(struct kgsl_device *device,
+ unsigned int *regs)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ unsigned long wait;
+ unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
+
+ if (!(rb->flags & KGSL_FLAGS_STARTED))
+ return 0;
+
+ /*
+ * The first time into the loop, wait for 100 msecs and kick wptr again
+ * to ensure that the hardware has updated correctly. After that, kick
+ * it periodically every KGSL_TIMEOUT_PART msecs until the timeout
+ * expires
+ */
+
+ wait = jiffies + msecs_to_jiffies(100);
+
+ adreno_poke(device);
+
+ do {
+ if (time_after(jiffies, wait)) {
+ adreno_poke(device);
+
+ /* Check to see if the core is hung */
+ if (adreno_hang_detect(device, regs))
+ return -ETIMEDOUT;
+
+ wait = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
+ }
+ GSL_RB_GET_READPTR(rb, &rb->rptr);
+
+ if (time_after(jiffies, timeout)) {
+ KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
+ rb->rptr, rb->wptr);
+ return -ETIMEDOUT;
+ }
+ } while (rb->rptr != rb->wptr);
+
+ return 0;
+}
+
+/* Caller must hold the device mutex. */
+int adreno_idle(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int rbbm_status;
- unsigned long wait_timeout =
- msecs_to_jiffies(adreno_dev->wait_timeout);
unsigned long wait_time;
unsigned long wait_time_part;
- unsigned int msecs;
- unsigned int msecs_first;
- unsigned int msecs_part = KGSL_TIMEOUT_PART;
unsigned int prev_reg_val[hang_detect_regs_count];
memset(prev_reg_val, 0, sizeof(prev_reg_val));
- /* Restrict timeout value between adreno_dev->wait_timeout and 0 */
- if ((timeout == 0) || (timeout > adreno_dev->wait_timeout))
- msecs = adreno_dev->wait_timeout;
- else
- msecs = timeout;
-
kgsl_cffdump_regpoll(device->id,
adreno_dev->gpudev->reg_rbbm_status << 2,
0x00000000, 0x80000000);
- /* first, wait until the CP has consumed all the commands in
- * the ring buffer
- */
+
retry:
- if (rb->flags & KGSL_FLAGS_STARTED) {
- msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
- wait_time = jiffies + wait_timeout;
- wait_time_part = jiffies + msecs_to_jiffies(msecs_first);
- adreno_poke(device);
- do {
- if (time_after(jiffies, wait_time_part)) {
- adreno_poke(device);
- wait_time_part = jiffies +
- msecs_to_jiffies(msecs_part);
- if ((adreno_hang_detect(device, prev_reg_val)))
- goto err;
- }
- GSL_RB_GET_READPTR(rb, &rb->rptr);
- if (time_after(jiffies, wait_time)) {
- KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
- rb->rptr, rb->wptr);
- goto err;
- }
- } while (rb->rptr != rb->wptr);
- }
+ /* First, wait for the ringbuffer to drain */
+ if (adreno_ringbuffer_drain(device, prev_reg_val))
+ goto err;
/* now, wait for the GPU to finish its operations */
- wait_time = jiffies + wait_timeout;
- wait_time_part = jiffies + msecs_to_jiffies(msecs_part);
+ wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
+ wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
+
while (time_before(jiffies, wait_time)) {
adreno_regread(device, adreno_dev->gpudev->reg_rbbm_status,
&rbbm_status);
@@ -1876,7 +1874,7 @@
*/
if (time_after(jiffies, wait_time_part)) {
wait_time_part = jiffies +
- msecs_to_jiffies(msecs_part);
+ msecs_to_jiffies(KGSL_TIMEOUT_PART);
if ((adreno_hang_detect(device, prev_reg_val)))
goto err;
}
@@ -1887,7 +1885,7 @@
KGSL_DRV_ERR(device, "spun too long waiting for RB to idle\n");
if (KGSL_STATE_DUMP_AND_RECOVER != device->state &&
!adreno_dump_and_recover(device)) {
- wait_time = jiffies + wait_timeout;
+ wait_time = jiffies + ADRENO_IDLE_TIMEOUT;
goto retry;
}
return -ETIMEDOUT;
@@ -1934,7 +1932,7 @@
/* switch to NULL ctxt */
if (adreno_dev->drawctxt_active != NULL) {
adreno_drawctxt_switch(adreno_dev, NULL, 0);
- status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ status = adreno_idle(device);
}
return status;
@@ -1956,7 +1954,8 @@
adreno_context = (struct adreno_context *)context->devctxt;
- if (kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base)) {
+ if (kgsl_mmu_pt_equal(&device->mmu, adreno_context->pagetable,
+ pt_base)) {
struct kgsl_memdesc *desc;
desc = &adreno_context->gpustate;
@@ -1995,7 +1994,7 @@
size))
return &device->mmu.setstate_memory;
- entry = kgsl_get_mem_entry(pt_base, gpuaddr, size);
+ entry = kgsl_get_mem_entry(device, pt_base, gpuaddr, size);
if (entry)
return &entry->memdesc;
@@ -2184,12 +2183,11 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
int retries = 0;
- unsigned int msecs_first;
- unsigned int msecs_part = KGSL_TIMEOUT_PART;
unsigned int ts_issued;
unsigned int context_id = _get_context_id(context);
unsigned int time_elapsed = 0;
unsigned int prev_reg_val[hang_detect_regs_count];
+ unsigned int wait;
memset(prev_reg_val, 0, sizeof(prev_reg_val));
@@ -2207,11 +2205,18 @@
goto done;
}
- /* Keep the first timeout as 100msecs before rewriting
- * the WPTR. Less visible impact if the WPTR has not
- * been updated properly.
+ /*
+ * Make the first timeout interval 100 msecs and then try to kick the
+ * wptr again. This helps to ensure the wptr is updated properly. If
+ * the requested timeout is less than 100 msecs, then wait 20msecs which
+ * is the minimum amount of time we can safely wait at 100HZ
*/
- msecs_first = (msecs <= 100) ? ((msecs + 4) / 5) : 100;
+
+ if (msecs == 0 || msecs >= 100)
+ wait = 100;
+ else
+ wait = 20;
+
do {
/*
* If the context ID is invalid, we are in a race with
@@ -2250,8 +2255,8 @@
device->wait_queue,
kgsl_check_interrupt_timestamp(device,
context, timestamp),
- msecs_to_jiffies(retries ?
- msecs_part : msecs_first), io);
+ msecs_to_jiffies(wait), io);
+
mutex_lock(&device->mutex);
if (status > 0) {
@@ -2264,11 +2269,12 @@
}
/*this wait timed out*/
- time_elapsed = time_elapsed +
- (retries ? msecs_part : msecs_first);
+ time_elapsed += wait;
+ wait = KGSL_TIMEOUT_PART;
+
retries++;
- } while (time_elapsed < msecs);
+ } while (!msecs || time_elapsed < msecs);
hang_dump:
/*
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index b923049e..26d5eaa 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -55,6 +55,12 @@
#define ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW 50
+/* One cannot wait forever for the core to idle, so set an upper limit to the
+ * amount of time to wait for the core to go idle
+ */
+
+#define ADRENO_IDLE_TIMEOUT (20 * 1000)
+
enum adreno_gpurev {
ADRENO_REV_UNKNOWN = 0,
ADRENO_REV_A200 = 200,
@@ -162,7 +168,7 @@
extern const unsigned int hang_detect_regs_count;
-int adreno_idle(struct kgsl_device *device, unsigned int timeout);
+int adreno_idle(struct kgsl_device *device);
void adreno_regread(struct kgsl_device *device, unsigned int offsetwords,
unsigned int *value);
void adreno_regwrite(struct kgsl_device *device, unsigned int offsetwords,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 2dbfd8f..5ce34db 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2290,9 +2290,6 @@
build_quad_vtxbuff(drawctxt, &drawctxt->context_gmem_shadow,
&tmp_ctx.cmd);
- /* Dow we need to idle? */
- /* adreno_idle(&adreno_dev->dev, KGSL_TIMEOUT_DEFAULT); */
-
tmp_ctx.cmd = build_gmem2sys_cmds(adreno_dev, drawctxt,
&drawctxt->context_gmem_shadow);
tmp_ctx.cmd = build_sys2gmem_cmds(adreno_dev, drawctxt,
@@ -2702,15 +2699,15 @@
/* Set up 16 deep read/write request queues */
if (adreno_dev->gpurev == ADRENO_REV_A330) {
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x00001818);
- adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x00001818);
- adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x00001818);
+ adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x01010101);
+ adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x01010101);
+ adreno_regwrite(device, A3XX_VBIF_OUT_RD_LIM_CONF0, 0x01010101);
+ adreno_regwrite(device, A3XX_VBIF_OUT_WR_LIM_CONF0, 0x01010101);
adreno_regwrite(device, A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x18181818);
- adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x00001818);
+ adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF0, 0x01010101);
+ adreno_regwrite(device, A3XX_VBIF_IN_WR_LIM_CONF1, 0x01010101);
/* Enable WR-REQ */
- adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x0000FF);
+ adreno_regwrite(device, A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003F);
/* Set up round robin arbitration between both AXI ports */
adreno_regwrite(device, A3XX_VBIF_ARB_CTL, 0x00000030);
@@ -2718,12 +2715,12 @@
adreno_regwrite(device, A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
/* Set up AOOO */
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x00000FFF);
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0x0FFF0FFF);
+ adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000FFFF);
+ adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AOOO, 0xFFFFFFFF);
- /* VBIF AXI AMEMTYPE CONFIG */
- adreno_regwrite(device, A3XX_VBIF_OUT_AXI_AMEMTYPE_CONF0,
- 0x22222222);
+ /* Enable 1K sort */
+ adreno_regwrite(device, A3XX_VBIF_ABIT_SORT, 0x1FFFF);
+ adreno_regwrite(device, A3XX_VBIF_ABIT_SORT_CONF, 0x000000A4);
} else {
adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010);
adreno_regwrite(device, A3XX_VBIF_IN_RD_LIM_CONF1, 0x10101010);
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 6c74dfa..74493f4 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -224,7 +224,11 @@
adreno_drawctxt_switch(adreno_dev, NULL, 0);
}
- adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ adreno_idle(device);
+
+ if (adreno_is_a20x(adreno_dev) && adreno_dev->drawctxt_active)
+ kgsl_setstate(&device->mmu, adreno_dev->drawctxt_active->id,
+ KGSL_MMUFLAGS_PTUPDATE);
kgsl_sharedmem_free(&drawctxt->gpustate);
kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 2038c10..261e518 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -697,8 +697,6 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct kgsl_memdesc **reg_map;
- void *reg_map_array;
int num_iommu_units = 0;
mb();
@@ -783,9 +781,7 @@
ib_list.count = 0;
i = 0;
/* get the register mapped array in case we are using IOMMU */
- num_iommu_units = kgsl_mmu_get_reg_map_desc(&device->mmu,
- ®_map_array);
- reg_map = reg_map_array;
+ num_iommu_units = kgsl_mmu_get_num_iommu_units(&device->mmu);
for (read_idx = 0; read_idx < num_item; ) {
uint32_t this_cmd = rb_copy[read_idx++];
if (adreno_cmd_is_ib(this_cmd)) {
@@ -799,13 +795,14 @@
ib_list.bases[i],
ib_list.sizes[i], 0);
} else if (this_cmd == cp_type0_packet(MH_MMU_PT_BASE, 1) ||
- (num_iommu_units && this_cmd == (reg_map[0]->gpuaddr +
- (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
- KGSL_IOMMU_TTBR0))) {
-
+ (num_iommu_units && this_cmd ==
+ kgsl_mmu_get_reg_gpuaddr(&device->mmu, 0,
+ KGSL_IOMMU_CONTEXT_USER,
+ KGSL_IOMMU_CTX_TTBR0))) {
KGSL_LOG_DUMP(device, "Current pagetable: %x\t"
"pagetable base: %x\n",
- kgsl_mmu_get_ptname_from_ptbase(cur_pt_base),
+ kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
+ cur_pt_base),
cur_pt_base);
/* Set cur_pt_base to the new pagetable base */
@@ -813,12 +810,11 @@
KGSL_LOG_DUMP(device, "New pagetable: %x\t"
"pagetable base: %x\n",
- kgsl_mmu_get_ptname_from_ptbase(cur_pt_base),
+ kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
+ cur_pt_base),
cur_pt_base);
}
}
- if (num_iommu_units)
- kfree(reg_map_array);
/* Restore cur_pt_base back to the pt_base of
the process in whose context the GPU hung */
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index ca9e335..ad9007f 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -52,11 +52,9 @@
unsigned int freecmds;
unsigned int *cmds;
uint cmds_gpu;
- struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
- unsigned long wait_timeout = msecs_to_jiffies(adreno_dev->wait_timeout);
unsigned long wait_time;
+ unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
unsigned long wait_time_part;
- unsigned int msecs_part = KGSL_TIMEOUT_PART;
unsigned int prev_reg_val[hang_detect_regs_count];
memset(prev_reg_val, 0, sizeof(prev_reg_val));
@@ -87,7 +85,7 @@
}
wait_time = jiffies + wait_timeout;
- wait_time_part = jiffies + msecs_to_jiffies(msecs_part);
+ wait_time_part = jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART);
/* wait for space in ringbuffer */
while (1) {
GSL_RB_GET_READPTR(rb, &rb->rptr);
@@ -101,7 +99,7 @@
*/
if (time_after(jiffies, wait_time_part)) {
wait_time_part = jiffies +
- msecs_to_jiffies(msecs_part);
+ msecs_to_jiffies(KGSL_TIMEOUT_PART);
if ((adreno_hang_detect(rb->device,
prev_reg_val))){
KGSL_DRV_ERR(rb->device,
@@ -393,7 +391,7 @@
adreno_dev->gpudev->rb_init(adreno_dev, rb);
/* idle device to validate ME INIT */
- status = adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ status = adreno_idle(device);
if (status == 0)
rb->flags |= KGSL_FLAGS_STARTED;
@@ -961,7 +959,7 @@
* this is conservative but works reliably and is ok
* even for performance simulations
*/
- adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
+ adreno_idle(device);
#endif
/* If context hung and recovered then return error so that the
* application may handle it */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 3d83508..1066b49 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -193,13 +193,14 @@
EXPORT_SYMBOL(kgsl_cancel_events);
/* kgsl_get_mem_entry - get the mem_entry structure for the specified object
+ * @device - Pointer to the device structure
* @ptbase - the pagetable base of the object
* @gpuaddr - the GPU address of the object
* @size - Size of the region to search
*/
-struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
- unsigned int gpuaddr, unsigned int size)
+struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
+ unsigned int ptbase, unsigned int gpuaddr, unsigned int size)
{
struct kgsl_process_private *priv;
struct kgsl_mem_entry *entry;
@@ -207,7 +208,7 @@
mutex_lock(&kgsl_driver.process_mutex);
list_for_each_entry(priv, &kgsl_driver.process_list, list) {
- if (!kgsl_mmu_pt_equal(priv->pagetable, ptbase))
+ if (!kgsl_mmu_pt_equal(&device->mmu, priv->pagetable, ptbase))
continue;
spin_lock(&priv->mem_lock);
entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
@@ -559,7 +560,7 @@
break;
case KGSL_STATE_ACTIVE:
/* Wait for the device to become idle */
- device->ftbl->idle(device, KGSL_TIMEOUT_DEFAULT);
+ device->ftbl->idle(device);
case KGSL_STATE_NAP:
case KGSL_STATE_SLEEP:
/* Get the completion ready to be waited upon. */
@@ -1769,8 +1770,10 @@
return -ENODEV;
handle = ion_import_dma_buf(kgsl_ion_client, fd);
- if (IS_ERR_OR_NULL(handle))
+ if (IS_ERR(handle))
return PTR_ERR(handle);
+ else if (!handle)
+ return -EINVAL;
entry->memtype = KGSL_MEM_ENTRY_ION;
entry->priv_data = handle;
@@ -2605,7 +2608,7 @@
}
if (device->state == KGSL_STATE_ACTIVE)
- kgsl_idle(device, KGSL_TIMEOUT_DEFAULT);
+ kgsl_idle(device);
}
KGSL_LOG_DUMP(device, "|%s| Dump Started\n", device->name);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index ac04c56..416eda9 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -175,8 +175,8 @@
void kgsl_mem_entry_destroy(struct kref *kref);
int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
-struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
- unsigned int gpuaddr, unsigned int size);
+struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
+ unsigned int ptbase, unsigned int gpuaddr, unsigned int size);
struct kgsl_mem_entry *kgsl_sharedmem_find_region(
struct kgsl_process_private *private, unsigned int gpuaddr,
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index d0932ef..2a2e916 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -67,7 +67,7 @@
unsigned int offsetwords, unsigned int *value);
void (*regwrite) (struct kgsl_device *device,
unsigned int offsetwords, unsigned int value);
- int (*idle) (struct kgsl_device *device, unsigned int timeout);
+ int (*idle) (struct kgsl_device *device);
unsigned int (*isidle) (struct kgsl_device *device);
int (*suspend_context) (struct kgsl_device *device);
int (*start) (struct kgsl_device *device, unsigned int init_ram);
@@ -287,9 +287,9 @@
device->ftbl->regwrite(device, offsetwords, value);
}
-static inline int kgsl_idle(struct kgsl_device *device, unsigned int timeout)
+static inline int kgsl_idle(struct kgsl_device *device)
{
- return device->ftbl->idle(device, timeout);
+ return device->ftbl->idle(device);
}
static inline unsigned int kgsl_gpuid(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index d8472f2..326e79d 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -355,8 +355,9 @@
return NULL;
}
-int kgsl_gpummu_pt_equal(struct kgsl_pagetable *pt,
- unsigned int pt_base)
+int kgsl_gpummu_pt_equal(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt,
+ unsigned int pt_base)
{
struct kgsl_gpummu_pt *gpummu_pt = pt ? pt->priv : NULL;
return gpummu_pt && pt_base && (gpummu_pt->base.gpuaddr == pt_base);
@@ -409,10 +410,10 @@
KGSL_MEM_CRIT(mmu->device,
"mmu page fault: page=0x%lx pt=%d op=%s axi=%d\n",
reg & ~(PAGE_SIZE - 1),
- kgsl_mmu_get_ptname_from_ptbase(ptbase),
+ kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
reg & 0x02 ? "WRITE" : "READ", (reg >> 4) & 0xF);
trace_kgsl_mmu_pagefault(mmu->device, reg & ~(PAGE_SIZE - 1),
- kgsl_mmu_get_ptname_from_ptbase(ptbase),
+ kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase),
reg & 0x02 ? "WRITE" : "READ");
}
@@ -472,7 +473,7 @@
return;
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
- kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
+ kgsl_idle(mmu->device);
gpummu_pt = mmu->hwpagetable->priv;
kgsl_regwrite(mmu->device, MH_MMU_PT_BASE,
gpummu_pt->base.gpuaddr);
@@ -552,7 +553,7 @@
kgsl_regwrite(device, MH_MMU_CONFIG, mmu->config);
/* idle device */
- kgsl_idle(device, KGSL_TIMEOUT_DEFAULT);
+ kgsl_idle(device);
/* enable axi interrupts */
kgsl_regwrite(device, MH_INTERRUPT_MASK,
@@ -714,12 +715,18 @@
}
static unsigned int
-kgsl_gpummu_pt_get_base_addr(struct kgsl_pagetable *pt)
+kgsl_gpummu_get_pt_base_addr(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt)
{
struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
return gpummu_pt->base.gpuaddr;
}
+static int kgsl_gpummu_get_num_iommu_units(struct kgsl_mmu *mmu)
+{
+ return 1;
+}
+
struct kgsl_mmu_ops gpummu_ops = {
.mmu_init = kgsl_gpummu_init,
.mmu_close = kgsl_gpummu_close,
@@ -729,10 +736,13 @@
.mmu_device_setstate = kgsl_gpummu_default_setstate,
.mmu_pagefault = kgsl_gpummu_pagefault,
.mmu_get_current_ptbase = kgsl_gpummu_get_current_ptbase,
+ .mmu_pt_equal = kgsl_gpummu_pt_equal,
+ .mmu_get_pt_base_addr = kgsl_gpummu_get_pt_base_addr,
.mmu_enable_clk = NULL,
.mmu_disable_clk_on_ts = NULL,
.mmu_get_pt_lsb = NULL,
- .mmu_get_reg_map_desc = NULL,
+ .mmu_get_reg_gpuaddr = NULL,
+ .mmu_get_num_iommu_units = kgsl_gpummu_get_num_iommu_units,
};
struct kgsl_mmu_pt_ops gpummu_pt_ops = {
@@ -740,6 +750,4 @@
.mmu_unmap = kgsl_gpummu_unmap,
.mmu_create_pagetable = kgsl_gpummu_create_pagetable,
.mmu_destroy_pagetable = kgsl_gpummu_destroy_pagetable,
- .mmu_pt_equal = kgsl_gpummu_pt_equal,
- .mmu_pt_get_base_addr = kgsl_gpummu_pt_get_base_addr,
};
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e858651..7254647 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -28,7 +28,16 @@
#include "adreno.h"
#include "kgsl_trace.h"
-static struct kgsl_iommu_unit *get_iommu_unit(struct device *dev)
+static struct kgsl_iommu_register_list kgsl_iommuv1_reg[KGSL_IOMMU_REG_MAX] = {
+ { 0, 0, 0 }, /* GLOBAL_BASE */
+ { 0x10, 0x0003FFFF, 14 }, /* TTBR0 */
+ { 0x14, 0x0003FFFF, 14 }, /* TTBR1 */
+ { 0x20, 0, 0 }, /* FSR */
+ { 0x800, 0, 0 }, /* TLBIALL */
+};
+
+static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
+ struct kgsl_iommu_unit **iommu_unit_out)
{
int i, j, k;
@@ -49,13 +58,16 @@
struct kgsl_iommu_unit *iommu_unit =
&iommu->iommu_units[j];
for (k = 0; k < iommu_unit->dev_count; k++) {
- if (iommu_unit->dev[k].dev == dev)
- return iommu_unit;
+ if (iommu_unit->dev[k].dev == dev) {
+ *mmu_out = mmu;
+ *iommu_unit_out = iommu_unit;
+ return 0;
+ }
}
}
}
- return NULL;
+ return -EINVAL;
}
static struct kgsl_iommu_device *get_iommu_device(struct kgsl_iommu_unit *unit,
@@ -74,31 +86,41 @@
static int kgsl_iommu_fault_handler(struct iommu_domain *domain,
struct device *dev, unsigned long addr, int flags)
{
- struct kgsl_iommu_unit *iommu_unit = get_iommu_unit(dev);
- struct kgsl_iommu_device *iommu_dev = get_iommu_device(iommu_unit, dev);
+ int ret = 0;
+ struct kgsl_mmu *mmu;
+ struct kgsl_iommu *iommu;
+ struct kgsl_iommu_unit *iommu_unit;
+ struct kgsl_iommu_device *iommu_dev;
unsigned int ptbase, fsr;
+ ret = get_iommu_unit(dev, &mmu, &iommu_unit);
+ if (ret)
+ goto done;
+ iommu_dev = get_iommu_device(iommu_unit, dev);
if (!iommu_dev) {
KGSL_CORE_ERR("Invalid IOMMU device %p\n", dev);
- return -ENOSYS;
+ ret = -ENOSYS;
+ goto done;
}
+ iommu = mmu->priv;
- ptbase = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
+ ptbase = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
iommu_dev->ctx_id, TTBR0);
- fsr = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
+ fsr = KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit,
iommu_dev->ctx_id, FSR);
KGSL_MEM_CRIT(iommu_dev->kgsldev,
"GPU PAGE FAULT: addr = %lX pid = %d\n",
- addr, kgsl_mmu_get_ptname_from_ptbase(ptbase));
+ addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
iommu_dev->ctx_id, fsr);
trace_kgsl_mmu_pagefault(iommu_dev->kgsldev, addr,
- kgsl_mmu_get_ptname_from_ptbase(ptbase), 0);
+ kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase), 0);
- return 0;
+done:
+ return ret;
}
/*
@@ -121,6 +143,8 @@
continue;
iommu_drvdata = dev_get_drvdata(
iommu_unit->dev[j].dev->parent);
+ if (iommu_drvdata->aclk)
+ clk_disable_unprepare(iommu_drvdata->aclk);
if (iommu_drvdata->clk)
clk_disable_unprepare(iommu_drvdata->clk);
clk_disable_unprepare(iommu_drvdata->pclk);
@@ -247,6 +271,17 @@
goto done;
}
}
+ if (iommu_drvdata->aclk) {
+ ret = clk_prepare_enable(iommu_drvdata->aclk);
+ if (ret) {
+ if (iommu_drvdata->clk)
+ clk_disable_unprepare(
+ iommu_drvdata->clk);
+ clk_disable_unprepare(
+ iommu_drvdata->pclk);
+ goto done;
+ }
+ }
iommu_unit->dev[j].clk_enabled = true;
}
}
@@ -258,6 +293,7 @@
/*
* kgsl_iommu_pt_equal - Check if pagetables are equal
+ * @mmu - Pointer to mmu structure
* @pt - Pointer to pagetable
* @pt_base - Address of a pagetable that the IOMMU register is
* programmed with
@@ -266,17 +302,23 @@
* the pagetable which is contained in the pt structure
* Return - Non-zero if the pagetable addresses are equal else 0
*/
-static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
- unsigned int pt_base)
+static int kgsl_iommu_pt_equal(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt,
+ unsigned int pt_base)
{
+ struct kgsl_iommu *iommu = mmu->priv;
struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
unsigned int domain_ptbase = iommu_pt ?
iommu_get_pt_base_addr(iommu_pt->domain) : 0;
/* Only compare the valid address bits of the pt_base */
- domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
- KGSL_IOMMU_TTBR0_PA_SHIFT);
- pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
- KGSL_IOMMU_TTBR0_PA_SHIFT);
+ domain_ptbase &=
+ (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+
+ pt_base &=
+ (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+
return domain_ptbase && pt_base &&
(domain_ptbase == pt_base);
}
@@ -313,7 +355,7 @@
return NULL;
}
iommu_pt->domain = iommu_domain_alloc(&platform_bus_type,
- MSM_IOMMU_DOMAIN_PT_CACHEABLE);
+ MSM_IOMMU_DOMAIN_PT_CACHEABLE);
if (!iommu_pt->domain) {
KGSL_CORE_ERR("Failed to create iommu domain\n");
kfree(iommu_pt);
@@ -568,17 +610,22 @@
}
/*
- * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
+ * kgsl_iommu_get_pt_base_addr - Get the address of the pagetable that the
* IOMMU ttbr0 register is programmed with
+ * @mmu - Pointer to mmu
* @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
*
* Return - actual pagetable address that the ttbr0 register is programmed
* with
*/
-static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
+static unsigned int kgsl_iommu_get_pt_base_addr(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt)
{
+ struct kgsl_iommu *iommu = mmu->priv;
struct kgsl_iommu_pt *iommu_pt = pt->priv;
- return iommu_get_pt_base_addr(iommu_pt->domain);
+ return iommu_get_pt_base_addr(iommu_pt->domain) &
+ (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
}
/*
@@ -653,6 +700,9 @@
if (status)
goto done;
+ iommu->iommu_reg_list = kgsl_iommuv1_reg;
+ iommu->ctx_offset = KGSL_IOMMU_CTX_OFFSET_V1;
+
/* A nop is required in an indirect buffer when switching
* pagetables in-stream */
kgsl_sharedmem_writel(&mmu->setstate_memory,
@@ -707,13 +757,14 @@
mmu->defaultpagetable;
/* Map the IOMMU regsiters to only defaultpagetable */
for (i = 0; i < iommu->unit_count; i++) {
- iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
+ iommu->iommu_units[i].reg_map.priv |=
+ KGSL_MEMFLAGS_GLOBAL;
status = kgsl_mmu_map(pagetable,
&(iommu->iommu_units[i].reg_map),
GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
if (status) {
iommu->iommu_units[i].reg_map.priv &=
- ~KGSL_MEMFLAGS_GLOBAL;
+ ~KGSL_MEMFLAGS_GLOBAL;
goto err;
}
}
@@ -756,9 +807,7 @@
kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
mh->mpu_base +
- iommu->iommu_units
- [iommu->unit_count - 1].reg_map.gpuaddr -
- PAGE_SIZE);
+ iommu->iommu_units[0].reg_map.gpuaddr);
} else {
kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
}
@@ -788,9 +837,9 @@
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
for (j = 0; j < iommu_unit->dev_count; j++)
- iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
- KGSL_IOMMU_GET_IOMMU_REG(
- iommu_unit->reg_map.hostptr,
+ iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(iommu,
+ KGSL_IOMMU_GET_CTX_REG(iommu,
+ iommu_unit,
iommu_unit->dev[j].ctx_id,
TTBR0));
}
@@ -929,12 +978,13 @@
return 0;
/* Return the current pt base by reading IOMMU pt_base register */
kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
- pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
- (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
- KGSL_IOMMU_TTBR0);
+ pt_base = KGSL_IOMMU_GET_CTX_REG(iommu, (&iommu->iommu_units[0]),
+ KGSL_IOMMU_CONTEXT_USER,
+ TTBR0);
kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
- return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
- KGSL_IOMMU_TTBR0_PA_SHIFT);
+ return pt_base &
+ (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
}
/*
@@ -955,8 +1005,8 @@
struct kgsl_iommu *iommu = mmu->priv;
int temp;
int i;
- unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
- mmu->hwpagetable);
+ unsigned int pt_base = kgsl_iommu_get_pt_base_addr(mmu,
+ mmu->hwpagetable);
unsigned int pt_val;
if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
@@ -964,9 +1014,11 @@
return;
}
/* Mask off the lsb of the pt base address since lsb will not change */
- pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
+ pt_base &= (iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask <<
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift);
+
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
- kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
+ kgsl_idle(mmu->device);
for (i = 0; i < iommu->unit_count; i++) {
/* get the lsb value which should not change when
* changing ttbr0 */
@@ -974,23 +1026,20 @@
KGSL_IOMMU_CONTEXT_USER);
pt_val += pt_base;
- KGSL_IOMMU_SET_IOMMU_REG(
- iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
mb();
- temp = KGSL_IOMMU_GET_IOMMU_REG(
- iommu->iommu_units[i].reg_map.hostptr,
+ temp = KGSL_IOMMU_GET_CTX_REG(iommu,
+ (&iommu->iommu_units[i]),
KGSL_IOMMU_CONTEXT_USER, TTBR0);
}
}
/* Flush tlb */
if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
for (i = 0; i < iommu->unit_count; i++) {
- KGSL_IOMMU_SET_IOMMU_REG(
- iommu->iommu_units[i].reg_map.hostptr,
- KGSL_IOMMU_CONTEXT_USER, CTX_TLBIALL,
- 1);
+ KGSL_IOMMU_SET_CTX_REG(iommu, (&iommu->iommu_units[i]),
+ KGSL_IOMMU_CONTEXT_USER, TLBIALL, 1);
mb();
}
}
@@ -999,40 +1048,32 @@
}
/*
- * kgsl_iommu_get_reg_map_desc - Returns an array of pointers that contain
- * the address of memory descriptors which map the IOMMU registers
+ * kgsl_iommu_get_reg_gpuaddr - Returns the gpu address of IOMMU regsiter
* @mmu - Pointer to mmu structure
- * @reg_map_desc - Out parameter in which the address of the array containing
- * pointers to register map descriptors is returned. The caller is supposed
- * to free this array
+ * @iommu_unit - The iommu unit for which base address is requested
+ * @ctx_id - The context ID of the IOMMU ctx
+ * @reg - The register for which address is required
*
* Return - The number of iommu units which is also the number of register
* mapped descriptor arrays which the out parameter will have
*/
-static int kgsl_iommu_get_reg_map_desc(struct kgsl_mmu *mmu,
- void **reg_map_desc)
+static unsigned int kgsl_iommu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
+ int iommu_unit, int ctx_id, int reg)
{
struct kgsl_iommu *iommu = mmu->priv;
- void **reg_desc_ptr;
- int i;
- /*
- * Alocate array of pointers that will hold address of the register map
- * descriptors
- */
- reg_desc_ptr = kmalloc(iommu->unit_count *
- sizeof(struct kgsl_memdesc *), GFP_KERNEL);
- if (!reg_desc_ptr) {
- KGSL_CORE_ERR("Failed to kmalloc(%d)\n",
- iommu->unit_count * sizeof(struct kgsl_memdesc *));
- return -ENOMEM;
- }
+ if (KGSL_IOMMU_GLOBAL_BASE == reg)
+ return iommu->iommu_units[iommu_unit].reg_map.gpuaddr;
+ else
+ return iommu->iommu_units[iommu_unit].reg_map.gpuaddr +
+ iommu->iommu_reg_list[reg].reg_offset +
+ (ctx_id << KGSL_IOMMU_CTX_SHIFT) + iommu->ctx_offset;
+}
- for (i = 0; i < iommu->unit_count; i++)
- reg_desc_ptr[i] = &(iommu->iommu_units[i].reg_map);
-
- *reg_map_desc = reg_desc_ptr;
- return i;
+static int kgsl_iommu_get_num_iommu_units(struct kgsl_mmu *mmu)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ return iommu->unit_count;
}
struct kgsl_mmu_ops iommu_ops = {
@@ -1047,7 +1088,10 @@
.mmu_enable_clk = kgsl_iommu_enable_clk,
.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
.mmu_get_pt_lsb = kgsl_iommu_get_pt_lsb,
- .mmu_get_reg_map_desc = kgsl_iommu_get_reg_map_desc,
+ .mmu_get_reg_gpuaddr = kgsl_iommu_get_reg_gpuaddr,
+ .mmu_get_num_iommu_units = kgsl_iommu_get_num_iommu_units,
+ .mmu_pt_equal = kgsl_iommu_pt_equal,
+ .mmu_get_pt_base_addr = kgsl_iommu_get_pt_base_addr,
};
struct kgsl_mmu_pt_ops iommu_pt_ops = {
@@ -1055,6 +1099,4 @@
.mmu_unmap = kgsl_iommu_unmap,
.mmu_create_pagetable = kgsl_iommu_create_pagetable,
.mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
- .mmu_pt_equal = kgsl_iommu_pt_equal,
- .mmu_pt_get_base_addr = kgsl_iommu_pt_get_base_addr,
};
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index f14db93..7dc222e 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -15,15 +15,23 @@
#include <mach/iommu.h>
-/* IOMMU registers and masks */
-#define KGSL_IOMMU_TTBR0 0x10
-#define KGSL_IOMMU_TTBR1 0x14
-#define KGSL_IOMMU_FSR 0x20
+#define KGSL_IOMMU_CTX_OFFSET_V1 0
+#define KGSL_IOMMU_CTX_SHIFT 12
-#define KGSL_IOMMU_TTBR0_PA_MASK 0x0003FFFF
-#define KGSL_IOMMU_TTBR0_PA_SHIFT 14
-#define KGSL_IOMMU_CTX_TLBIALL 0x800
-#define KGSL_IOMMU_CTX_SHIFT 12
+enum kgsl_iommu_reg_map {
+ KGSL_IOMMU_GLOBAL_BASE = 0,
+ KGSL_IOMMU_CTX_TTBR0,
+ KGSL_IOMMU_CTX_TTBR1,
+ KGSL_IOMMU_CTX_FSR,
+ KGSL_IOMMU_CTX_TLBIALL,
+ KGSL_IOMMU_REG_MAX
+};
+
+struct kgsl_iommu_register_list {
+ unsigned int reg_offset;
+ unsigned int reg_mask;
+ unsigned int reg_shift;
+};
/*
* Max number of iommu units that the gpu core can have
@@ -35,20 +43,25 @@
#define KGSL_IOMMU_MAX_DEVS_PER_UNIT 2
/* Macros to read/write IOMMU registers */
-#define KGSL_IOMMU_SET_IOMMU_REG(base_addr, ctx, REG, val) \
- writel_relaxed(val, base_addr + \
- (ctx << KGSL_IOMMU_CTX_SHIFT) + \
- KGSL_IOMMU_##REG)
+#define KGSL_IOMMU_SET_CTX_REG(iommu, iommu_unit, ctx, REG, val) \
+ writel_relaxed(val, \
+ iommu_unit->reg_map.hostptr + \
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_##REG].reg_offset +\
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ iommu->ctx_offset)
-#define KGSL_IOMMU_GET_IOMMU_REG(base_addr, ctx, REG) \
- readl_relaxed(base_addr + \
- (ctx << KGSL_IOMMU_CTX_SHIFT) + \
- KGSL_IOMMU_##REG)
+#define KGSL_IOMMU_GET_CTX_REG(iommu, iommu_unit, ctx, REG) \
+ readl_relaxed( \
+ iommu_unit->reg_map.hostptr + \
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_##REG].reg_offset +\
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ iommu->ctx_offset)
/* Gets the lsb value of pagetable */
-#define KGSL_IOMMMU_PT_LSB(pt_val) \
- (pt_val & ~(KGSL_IOMMU_TTBR0_PA_MASK << \
- KGSL_IOMMU_TTBR0_PA_SHIFT))
+#define KGSL_IOMMMU_PT_LSB(iommu, pt_val) \
+ (pt_val & \
+ ~(iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_mask << \
+ iommu->iommu_reg_list[KGSL_IOMMU_CTX_TTBR0].reg_shift))
/* offset at which a nop command is placed in setstate_memory */
#define KGSL_IOMMU_SETSTATE_NOP_OFFSET 1024
@@ -99,6 +112,9 @@
* @clk_event_queued: Indicates whether an event to disable clocks
* is already queued or not
* @device: Pointer to kgsl device
+ * @ctx_offset: The context offset to be added to base address when
+ * accessing IOMMU registers
+ * @iommu_reg_list: List of IOMMU registers { offset, map, shift } array
*/
struct kgsl_iommu {
struct kgsl_iommu_unit iommu_units[KGSL_IOMMU_MAX_UNITS];
@@ -106,6 +122,8 @@
unsigned int iommu_last_cmd_ts;
bool clk_event_queued;
struct kgsl_device *device;
+ unsigned int ctx_offset;
+ struct kgsl_iommu_register_list *iommu_reg_list;
};
/*
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 8e6c5c0..3aea81f 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/iommu.h>
+#include <mach/iommu.h>
#include <mach/socinfo.h>
#include "kgsl.h"
@@ -325,14 +326,16 @@
}
int
-kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base)
+kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu, unsigned int pt_base)
{
struct kgsl_pagetable *pt;
int ptid = -1;
+ if (!mmu->mmu_ops || !mmu->mmu_ops->mmu_pt_equal)
+ return KGSL_MMU_GLOBAL_PT;
spin_lock(&kgsl_driver.ptlock);
list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) {
- if (pt->pt_ops->mmu_pt_equal(pt, pt_base)) {
+ if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
ptid = (int) pt->name;
break;
}
@@ -560,7 +563,7 @@
struct kgsl_mh *mh = &device->mh;
/* force mmu off to for now*/
kgsl_regwrite(device, MH_MMU_CONFIG, 0);
- kgsl_idle(device, KGSL_TIMEOUT_DEFAULT);
+ kgsl_idle(device);
/* define physical memory range accessible by the core */
kgsl_regwrite(device, MH_MMU_MPU_BASE, mh->mpu_base);
@@ -824,3 +827,13 @@
kgsl_mmu_type = KGSL_MMU_TYPE_NONE;
}
EXPORT_SYMBOL(kgsl_mmu_set_mmutype);
+
+int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
+{
+ if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
+ return 1;
+ return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
+ (gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
+}
+EXPORT_SYMBOL(kgsl_mmu_gpuaddr_in_range);
+
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 5293d66..234629b 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -139,8 +139,15 @@
int (*mmu_get_pt_lsb)(struct kgsl_mmu *mmu,
unsigned int unit_id,
enum kgsl_iommu_context_id ctx_id);
- int (*mmu_get_reg_map_desc)(struct kgsl_mmu *mmu,
- void **reg_map_desc);
+ unsigned int (*mmu_get_reg_gpuaddr)(struct kgsl_mmu *mmu,
+ int iommu_unit_num, int ctx_id, int reg);
+ int (*mmu_get_num_iommu_units)(struct kgsl_mmu *mmu);
+ int (*mmu_pt_equal) (struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt,
+ unsigned int pt_base);
+ unsigned int (*mmu_get_pt_base_addr)
+ (struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt);
};
struct kgsl_mmu_pt_ops {
@@ -153,10 +160,6 @@
unsigned int *tlb_flags);
void *(*mmu_create_pagetable) (void);
void (*mmu_destroy_pagetable) (void *pt);
- int (*mmu_pt_equal) (struct kgsl_pagetable *pt,
- unsigned int pt_base);
- unsigned int (*mmu_pt_get_base_addr)
- (struct kgsl_pagetable *pt);
};
struct kgsl_mmu {
@@ -196,7 +199,8 @@
unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr);
void kgsl_setstate(struct kgsl_mmu *mmu, unsigned int context_id,
uint32_t flags);
-int kgsl_mmu_get_ptname_from_ptbase(unsigned int pt_base);
+int kgsl_mmu_get_ptname_from_ptbase(struct kgsl_mmu *mmu,
+ unsigned int pt_base);
int kgsl_mmu_pt_get_flags(struct kgsl_pagetable *pt,
enum kgsl_deviceid id);
void kgsl_mmu_ptpool_destroy(void *ptpool);
@@ -205,6 +209,7 @@
void kgsl_mmu_set_mmutype(char *mmutype);
enum kgsl_mmutype kgsl_mmu_get_mmutype(void);
unsigned int kgsl_mmu_get_ptsize(void);
+int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr);
/*
* Static inline functions of MMU that simply call the SMMU specific
@@ -241,28 +246,21 @@
mmu->mmu_ops->mmu_stop(mmu);
}
-static inline int kgsl_mmu_pt_equal(struct kgsl_pagetable *pt,
+static inline int kgsl_mmu_pt_equal(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt,
unsigned int pt_base)
{
- if (KGSL_MMU_TYPE_NONE == kgsl_mmu_get_mmutype())
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_pt_equal)
+ return mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base);
+ else
return 1;
- else
- return pt->pt_ops->mmu_pt_equal(pt, pt_base);
}
-static inline unsigned int kgsl_mmu_pt_get_base_addr(struct kgsl_pagetable *pt)
+static inline unsigned int kgsl_mmu_get_pt_base_addr(struct kgsl_mmu *mmu,
+ struct kgsl_pagetable *pt)
{
- if (KGSL_MMU_TYPE_NONE == kgsl_mmu_get_mmutype())
- return 0;
- else
- return pt->pt_ops->mmu_pt_get_base_addr(pt);
-}
-
-static inline int kgsl_mmu_get_reg_map_desc(struct kgsl_mmu *mmu,
- void **reg_map_desc)
-{
- if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_reg_map_desc)
- return mmu->mmu_ops->mmu_get_reg_map_desc(mmu, reg_map_desc);
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_pt_base_addr)
+ return mmu->mmu_ops->mmu_get_pt_base_addr(mmu, pt);
else
return 0;
}
@@ -293,12 +291,6 @@
mmu->mmu_ops->mmu_disable_clk_on_ts(mmu, ts, ts_valid);
}
-static inline int kgsl_mmu_gpuaddr_in_range(unsigned int gpuaddr)
-{
- return ((gpuaddr >= KGSL_PAGETABLE_BASE) &&
- (gpuaddr < (KGSL_PAGETABLE_BASE + kgsl_mmu_get_ptsize())));
-}
-
static inline unsigned int kgsl_mmu_get_int_mask(void)
{
/* Dont enable gpummu interrupts, if iommu is enabled */
@@ -309,4 +301,23 @@
MH_INTERRUPT_MASK__AXI_WRITE_ERROR);
}
+static inline unsigned int kgsl_mmu_get_reg_gpuaddr(struct kgsl_mmu *mmu,
+ int iommu_unit_num,
+ int ctx_id, int reg)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_reg_gpuaddr)
+ return mmu->mmu_ops->mmu_get_reg_gpuaddr(mmu, iommu_unit_num,
+ ctx_id, reg);
+ else
+ return 0;
+}
+
+static inline int kgsl_mmu_get_num_iommu_units(struct kgsl_mmu *mmu)
+{
+ if (mmu->mmu_ops && mmu->mmu_ops->mmu_get_num_iommu_units)
+ return mmu->mmu_ops->mmu_get_num_iommu_units(mmu);
+ else
+ return 0;
+}
+
#endif /* __KGSL_MMU_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 4b5021d..8c45475 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -17,6 +17,7 @@
#include <linux/pm_runtime.h>
#include <mach/msm_iomap.h>
#include <mach/msm_bus.h>
+#include <linux/ktime.h>
#include "kgsl.h"
#include "kgsl_pwrscale.h"
@@ -60,6 +61,30 @@
},
};
+/* Update the elapsed time at a particular clock level
+ * if the device is active(on_time = true).Otherwise
+ * store it as sleep time.
+ */
+static void update_clk_statistics(struct kgsl_device *device,
+ bool on_time)
+{
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ struct kgsl_clk_stats *clkstats = &pwr->clk_stats;
+ ktime_t elapsed;
+ int elapsed_us;
+ if (clkstats->start.tv64 == 0)
+ clkstats->start = ktime_get();
+ clkstats->stop = ktime_get();
+ elapsed = ktime_sub(clkstats->stop, clkstats->start);
+ elapsed_us = ktime_to_us(elapsed);
+ clkstats->elapsed += elapsed_us;
+ if (on_time)
+ clkstats->clock_time[pwr->active_pwrlevel] += elapsed_us;
+ else
+ clkstats->clock_time[pwr->num_pwrlevels - 1] += elapsed_us;
+ clkstats->start = ktime_get();
+}
+
void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
unsigned int new_level)
{
@@ -71,6 +96,9 @@
int diff = new_level - pwr->active_pwrlevel;
int d = (diff > 0) ? 1 : -1;
int level = pwr->active_pwrlevel;
+ /* Update the clock stats */
+ update_clk_statistics(device, true);
+ /* Finally set active level */
pwr->active_pwrlevel = new_level;
if ((test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) ||
(device->state == KGSL_STATE_NAP)) {
@@ -80,8 +108,8 @@
* Idle the gpu core before changing the clock freq.
*/
if (pwr->idle_needed == true)
- device->ftbl->idle(device,
- KGSL_TIMEOUT_DEFAULT);
+ device->ftbl->idle(device);
+
/* Don't shift by more than one level at a time to
* avoid glitches.
*/
@@ -285,23 +313,73 @@
{
int ret;
struct kgsl_device *device = kgsl_device_from_dev(dev);
- struct kgsl_busy *b = &device->pwrctrl.busy;
- ret = snprintf(buf, 17, "%7d %7d\n",
- b->on_time_old, b->time_old);
+ struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+ ret = snprintf(buf, PAGE_SIZE, "%7d %7d\n",
+ clkstats->on_time_old, clkstats->elapsed_old);
if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
- b->on_time_old = 0;
- b->time_old = 0;
+ clkstats->on_time_old = 0;
+ clkstats->elapsed_old = 0;
}
return ret;
}
+static int kgsl_pwrctrl_gputop_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+ int i = 0;
+ char *ptr = buf;
+
+ ret = snprintf(buf, PAGE_SIZE, "%7d %7d ", clkstats->on_time_old,
+ clkstats->elapsed_old);
+ for (i = 0, ptr += ret; i < device->pwrctrl.num_pwrlevels;
+ i++, ptr += ret)
+ ret = snprintf(ptr, PAGE_SIZE, "%7d ",
+ clkstats->old_clock_time[i]);
+
+ if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
+ clkstats->on_time_old = 0;
+ clkstats->elapsed_old = 0;
+ for (i = 0; i < KGSL_MAX_PWRLEVELS ; i++)
+ clkstats->old_clock_time[i] = 0;
+ }
+ return (unsigned int) (ptr - buf);
+}
+
+static int kgsl_pwrctrl_gpu_available_frequencies_show(
+ struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct kgsl_device *device = kgsl_device_from_dev(dev);
+ struct kgsl_pwrctrl *pwr;
+ int index, num_chars = 0;
+
+ if (device == NULL)
+ return 0;
+ pwr = &device->pwrctrl;
+ for (index = 0; index < pwr->num_pwrlevels - 1; index++)
+ num_chars += snprintf(buf + num_chars, PAGE_SIZE, "%d ",
+ pwr->pwrlevels[index].gpu_freq);
+ buf[num_chars++] = '\n';
+ return num_chars;
+}
+
DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
kgsl_pwrctrl_max_gpuclk_store);
DEVICE_ATTR(pwrnap, 0664, kgsl_pwrctrl_pwrnap_show, kgsl_pwrctrl_pwrnap_store);
DEVICE_ATTR(idle_timer, 0644, kgsl_pwrctrl_idle_timer_show,
kgsl_pwrctrl_idle_timer_store);
-DEVICE_ATTR(gpubusy, 0644, kgsl_pwrctrl_gpubusy_show,
+DEVICE_ATTR(gpubusy, 0444, kgsl_pwrctrl_gpubusy_show,
+ NULL);
+DEVICE_ATTR(gputop, 0444, kgsl_pwrctrl_gputop_show,
+ NULL);
+DEVICE_ATTR(gpu_available_frequencies, 0444,
+ kgsl_pwrctrl_gpu_available_frequencies_show,
NULL);
static const struct device_attribute *pwrctrl_attr_list[] = {
@@ -310,6 +388,8 @@
&dev_attr_pwrnap,
&dev_attr_idle_timer,
&dev_attr_gpubusy,
+ &dev_attr_gputop,
+ &dev_attr_gpu_available_frequencies,
NULL
};
@@ -323,29 +403,37 @@
kgsl_remove_device_sysfs_files(device->dev, pwrctrl_attr_list);
}
+static void update_statistics(struct kgsl_device *device)
+{
+ struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+ unsigned int on_time = 0;
+ int i;
+ int num_pwrlevels = device->pwrctrl.num_pwrlevels - 1;
+ /*PER CLK TIME*/
+ for (i = 0; i < num_pwrlevels; i++) {
+ clkstats->old_clock_time[i] = clkstats->clock_time[i];
+ on_time += clkstats->clock_time[i];
+ clkstats->clock_time[i] = 0;
+ }
+ clkstats->old_clock_time[num_pwrlevels] =
+ clkstats->clock_time[num_pwrlevels];
+ clkstats->clock_time[num_pwrlevels] = 0;
+ clkstats->on_time_old = on_time;
+ clkstats->elapsed_old = clkstats->elapsed;
+ clkstats->elapsed = 0;
+}
+
/* Track the amount of time the gpu is on vs the total system time. *
* Regularly update the percentage of busy time displayed by sysfs. */
static void kgsl_pwrctrl_busy_time(struct kgsl_device *device, bool on_time)
{
- struct kgsl_busy *b = &device->pwrctrl.busy;
- int elapsed;
- if (b->start.tv_sec == 0)
- do_gettimeofday(&(b->start));
- do_gettimeofday(&(b->stop));
- elapsed = (b->stop.tv_sec - b->start.tv_sec) * 1000000;
- elapsed += b->stop.tv_usec - b->start.tv_usec;
- b->time += elapsed;
- if (on_time)
- b->on_time += elapsed;
+ struct kgsl_clk_stats *clkstats = &device->pwrctrl.clk_stats;
+ update_clk_statistics(device, on_time);
/* Update the output regularly and reset the counters. */
- if ((b->time > UPDATE_BUSY_VAL) ||
+ if ((clkstats->elapsed > UPDATE_BUSY_VAL) ||
!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
- b->on_time_old = b->on_time;
- b->time_old = b->time;
- b->on_time = 0;
- b->time = 0;
+ update_statistics(device);
}
- do_gettimeofday(&(b->start));
}
void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
@@ -377,16 +465,17 @@
&pwr->power_flags)) {
trace_kgsl_clk(device, state);
/* High latency clock maintenance. */
- if ((pwr->pwrlevels[0].gpu_freq > 0) &&
- (device->state != KGSL_STATE_NAP)) {
+ if (device->state != KGSL_STATE_NAP) {
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
if (pwr->grp_clks[i])
clk_prepare(pwr->grp_clks[i]);
- clk_set_rate(pwr->grp_clks[0],
- pwr->pwrlevels[pwr->active_pwrlevel].
+
+ if (pwr->pwrlevels[0].gpu_freq > 0)
+ clk_set_rate(pwr->grp_clks[0],
+ pwr->pwrlevels
+ [pwr->active_pwrlevel].
gpu_freq);
}
-
/* as last step, enable grp_clk
this is to let GPU interrupt to come */
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
@@ -648,10 +737,11 @@
device->pwrctrl.interval_timeout);
/* If the GPU has been too busy to sleep, make sure *
* that is acurately reflected in the % busy numbers. */
- device->pwrctrl.busy.no_nap_cnt++;
- if (device->pwrctrl.busy.no_nap_cnt > UPDATE_BUSY) {
+ device->pwrctrl.clk_stats.no_nap_cnt++;
+ if (device->pwrctrl.clk_stats.no_nap_cnt >
+ UPDATE_BUSY) {
kgsl_pwrctrl_busy_time(device, true);
- device->pwrctrl.busy.no_nap_cnt = 0;
+ device->pwrctrl.clk_stats.no_nap_cnt = 0;
}
}
} else if (device->state & (KGSL_STATE_HUNG |
@@ -753,7 +843,7 @@
_sleep_accounting(struct kgsl_device *device)
{
kgsl_pwrctrl_busy_time(device, false);
- device->pwrctrl.busy.start.tv_sec = 0;
+ device->pwrctrl.clk_stats.start = ktime_set(0, 0);
device->pwrctrl.time = 0;
kgsl_pwrscale_sleep(device);
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index cd44152..c02a9fc 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -27,14 +27,15 @@
struct platform_device;
-struct kgsl_busy {
- struct timeval start;
- struct timeval stop;
- int on_time;
- int time;
- int on_time_old;
- int time_old;
+struct kgsl_clk_stats {
+ unsigned int old_clock_time[KGSL_MAX_PWRLEVELS];
+ unsigned int clock_time[KGSL_MAX_PWRLEVELS];
+ unsigned int on_time_old;
+ ktime_t start;
+ ktime_t stop;
unsigned int no_nap_cnt;
+ unsigned int elapsed;
+ unsigned int elapsed_old;
};
struct kgsl_pwrctrl {
@@ -56,8 +57,8 @@
unsigned int idle_needed;
const char *irq_name;
s64 time;
- struct kgsl_busy busy;
unsigned int restore_slumber;
+ struct kgsl_clk_stats clk_stats;
};
void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index b341485..c2ce5c7 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -438,6 +438,20 @@
free_contiguous_memory_by_paddr(memdesc->physaddr);
}
+static int kgsl_ebimem_map_kernel(struct kgsl_memdesc *memdesc)
+{
+ if (!memdesc->hostptr) {
+ memdesc->hostptr = ioremap(memdesc->physaddr, memdesc->size);
+ if (!memdesc->hostptr) {
+ KGSL_CORE_ERR("ioremap failed, addr:0x%p, size:0x%x\n",
+ memdesc->hostptr, memdesc->size);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
static void kgsl_coherent_free(struct kgsl_memdesc *memdesc)
{
kgsl_driver.stats.coherent -= memdesc->size;
@@ -458,6 +472,7 @@
.free = kgsl_ebimem_free,
.vmflags = kgsl_contiguous_vmflags,
.vmfault = kgsl_contiguous_vmfault,
+ .map_kernel_mem = kgsl_ebimem_map_kernel,
};
static struct kgsl_memdesc_ops kgsl_coherent_ops = {
@@ -495,6 +510,25 @@
struct page **pages = NULL;
pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
void *ptr;
+ struct sysinfo si;
+
+ /*
+ * Get the current memory information to be used in deciding if we
+ * should go ahead with this allocation
+ */
+
+ si_meminfo(&si);
+
+ /*
+ * Limit the size of the allocation to the amount of free memory minus
+ * 32MB. Why 32MB? Because thats the buffer that page_alloc uses and
+ * it just seems like a reasonable limit that won't make the OOM killer
+ * go all serial on us. Of course, if we are down this low all bets
+ * are off but above all do no harm.
+ */
+
+ if (size >= ((si.freeram << PAGE_SHIFT) - SZ_32M))
+ return -ENOMEM;
/*
* Add guard page to the end of the allocation when the
@@ -666,7 +700,8 @@
{
unsigned int protflags;
- BUG_ON(size == 0);
+ if (size == 0)
+ return -EINVAL;
protflags = GSL_PT_PAGE_RV;
if (!(flags & KGSL_MEMFLAGS_GPUREADONLY))
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 824d806..abaa8ce 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -175,7 +175,8 @@
/* Get the current PT base */
header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
/* And the PID for the task leader */
- pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
+ pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
+ header->ptbase);
task = find_task_by_vpid(pid);
@@ -307,7 +308,7 @@
struct kgsl_snapshot_object *obj;
int offset;
- entry = kgsl_get_mem_entry(ptbase, gpuaddr, size);
+ entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size);
if (entry == NULL) {
KGSL_DRV_ERR(device, "Unable to find GPU buffer %8.8X\n",
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 9037f3c..8ddc991 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -358,7 +358,7 @@
return ts_diff < Z180_PACKET_COUNT;
}
-static int z180_idle(struct kgsl_device *device, unsigned int timeout)
+static int z180_idle(struct kgsl_device *device)
{
int status = 0;
struct z180_device *z180_dev = Z180_DEVICE(device);
@@ -366,7 +366,8 @@
if (timestamp_cmp(z180_dev->current_timestamp,
z180_dev->timestamp) > 0)
status = z180_wait(device, NULL,
- z180_dev->current_timestamp, timeout);
+ z180_dev->current_timestamp,
+ Z180_IDLE_TIMEOUT);
if (status)
KGSL_DRV_ERR(device, "z180_waittimestamp() timed out\n");
@@ -583,7 +584,7 @@
static int z180_stop(struct kgsl_device *device)
{
device->ftbl->irqctrl(device, 0);
- z180_idle(device, KGSL_TIMEOUT_DEFAULT);
+ z180_idle(device);
del_timer_sync(&device->idle_timer);
@@ -852,7 +853,7 @@
{
struct z180_device *z180_dev = Z180_DEVICE(device);
- z180_idle(device, KGSL_TIMEOUT_DEFAULT);
+ z180_idle(device);
if (z180_dev->ringbuffer.prevctx == context->id) {
z180_dev->ringbuffer.prevctx = Z180_INVALID_CONTEXT;
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index 6e81a9d..a8973d2 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -28,6 +28,9 @@
#define Z180_DEFAULT_PWRSCALE_POLICY NULL
+/* Wait a maximum of 10 seconds when trying to idle the core */
+#define Z180_IDLE_TIMEOUT (10 * 1000)
+
struct z180_ringbuffer {
unsigned int prevctx;
struct kgsl_memdesc cmdbufdesc;
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index a9b0c50..7cf3799 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -152,7 +152,8 @@
ib_gpuptr = rb_hostptr[i+1];
- entry = kgsl_get_mem_entry(pt_base, ib_gpuptr, 1);
+ entry = kgsl_get_mem_entry(device, pt_base, ib_gpuptr,
+ 1);
if (entry == NULL) {
KGSL_LOG_DUMP(device,
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 297afa7..c1617bff 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1339,8 +1339,10 @@
}
free_irq(dev->err_irq, dev);
} else {
- if (dev->dev->of_node)
+ if (dev->dev->of_node) {
+ dev->adapter.dev.of_node = pdev->dev.of_node;
of_i2c_register_devices(&dev->adapter);
+ }
return 0;
}
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 8b6e172..d3da652 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -40,6 +40,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+#include <linux/gpio.h>
#include <linux/input/mpu3050.h>
#include <linux/regulator/consumer.h>
@@ -50,6 +51,8 @@
#define MPU3050_MIN_VALUE -32768
#define MPU3050_MAX_VALUE 32767
+#define MPU3050_MIN_POLL_INTERVAL 1
+#define MPU3050_MAX_POLL_INTERVAL 250
#define MPU3050_DEFAULT_POLL_INTERVAL 200
#define MPU3050_DEFAULT_FS_RANGE 3
@@ -90,8 +93,10 @@
#define MPU3050_DLPF_CFG_MASK 0x07
/* INT_CFG */
#define MPU3050_RAW_RDY_EN 0x01
-#define MPU3050_MPU_RDY_EN 0x02
-#define MPU3050_LATCH_INT_EN 0x04
+#define MPU3050_MPU_RDY_EN 0x04
+#define MPU3050_LATCH_INT_EN 0x20
+#define MPU3050_OPEN_DRAIN 0x40
+#define MPU3050_ACTIVE_LOW 0x80
/* PWR_MGM */
#define MPU3050_PWR_MGM_PLL_X 0x01
#define MPU3050_PWR_MGM_PLL_Y 0x02
@@ -117,6 +122,7 @@
struct mpu3050_gyro_platform_data *platform_data;
struct delayed_work input_work;
u32 use_poll;
+ u32 poll_interval;
};
struct sensor_regulator {
@@ -190,6 +196,78 @@
}
/**
+ * mpu3050_attr_get_polling_rate - get the sampling rate
+ */
+static ssize_t mpu3050_attr_get_polling_rate(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int val;
+ struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
+ val = sensor ? sensor->poll_interval : 0;
+ return snprintf(buf, 8, "%d\n", val);
+}
+
+/**
+ * mpu3050_attr_set_polling_rate - set the sampling rate
+ */
+static ssize_t mpu3050_attr_set_polling_rate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct mpu3050_sensor *sensor = dev_get_drvdata(dev);
+ unsigned long interval_ms;
+
+ if (kstrtoul(buf, 10, &interval_ms))
+ return -EINVAL;
+ if ((interval_ms < MPU3050_MIN_POLL_INTERVAL) ||
+ (interval_ms > MPU3050_MAX_POLL_INTERVAL))
+ return -EINVAL;
+
+ if (sensor)
+ sensor->poll_interval = interval_ms;
+
+ /* Output frequency divider. The poll interval */
+ i2c_smbus_write_byte_data(sensor->client, MPU3050_SMPLRT_DIV,
+ interval_ms - 1);
+
+ return size;
+}
+
+static struct device_attribute attributes[] = {
+
+ __ATTR(pollrate_ms, 0666,
+ mpu3050_attr_get_polling_rate,
+ mpu3050_attr_set_polling_rate),
+};
+
+static int create_sysfs_interfaces(struct device *dev)
+{
+ int i;
+ int err;
+ for (i = 0; i < ARRAY_SIZE(attributes); i++) {
+ err = device_create_file(dev, attributes + i);
+ if (err)
+ goto error;
+ }
+ return 0;
+
+error:
+ for ( ; i >= 0; i--)
+ device_remove_file(dev, attributes + i);
+ dev_err(dev, "%s:Unable to create interface\n", __func__);
+ return err;
+}
+
+static int remove_sysfs_interfaces(struct device *dev)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(attributes); i++)
+ device_remove_file(dev, attributes + i);
+ return 0;
+}
+
+/**
* mpu3050_xyz_read_reg - read the axes values
* @buffer: provide register addr and get register
* @length: length of register
@@ -284,20 +362,20 @@
struct mpu3050_sensor *sensor = input_get_drvdata(input);
int error;
- pm_runtime_get(sensor->dev);
+ pm_runtime_get_sync(sensor->dev);
/* Enable interrupts */
error = i2c_smbus_write_byte_data(sensor->client, MPU3050_INT_CFG,
- MPU3050_LATCH_INT_EN |
- MPU3050_RAW_RDY_EN |
- MPU3050_MPU_RDY_EN);
+ MPU3050_ACTIVE_LOW |
+ MPU3050_OPEN_DRAIN |
+ MPU3050_RAW_RDY_EN);
if (error < 0) {
pm_runtime_put(sensor->dev);
return error;
}
if (sensor->use_poll)
schedule_delayed_work(&sensor->input_work,
- msecs_to_jiffies(MPU3050_DEFAULT_POLL_INTERVAL));
+ msecs_to_jiffies(sensor->poll_interval));
return 0;
}
@@ -366,7 +444,7 @@
if (sensor->use_poll)
schedule_delayed_work(&sensor->input_work,
- msecs_to_jiffies(MPU3050_DEFAULT_POLL_INTERVAL));
+ msecs_to_jiffies(sensor->poll_interval));
}
/**
@@ -399,7 +477,7 @@
/* Output frequency divider. The poll interval */
ret = i2c_smbus_write_byte_data(client, MPU3050_SMPLRT_DIV,
- MPU3050_DEFAULT_POLL_INTERVAL - 1);
+ sensor->poll_interval - 1);
if (ret < 0)
return ret;
@@ -444,6 +522,18 @@
sensor->dev = &client->dev;
sensor->idev = idev;
sensor->platform_data = client->dev.platform_data;
+ i2c_set_clientdata(client, sensor);
+ if (sensor->platform_data) {
+ u32 interval = sensor->platform_data->poll_interval;
+
+ if ((interval < MPU3050_MIN_POLL_INTERVAL) ||
+ (interval > MPU3050_MAX_POLL_INTERVAL))
+ sensor->poll_interval = MPU3050_DEFAULT_POLL_INTERVAL;
+ else
+ sensor->poll_interval = interval;
+ } else {
+ sensor->poll_interval = MPU3050_DEFAULT_POLL_INTERVAL;
+ }
mpu3050_set_power_mode(client, 1);
msleep(10);
@@ -485,14 +575,34 @@
goto err_pm_set_suspended;
if (client->irq == 0) {
- INIT_DELAYED_WORK(&sensor->input_work, mpu3050_input_work_fn);
sensor->use_poll = 1;
+ INIT_DELAYED_WORK(&sensor->input_work, mpu3050_input_work_fn);
} else {
sensor->use_poll = 0;
+ if (gpio_is_valid(sensor->platform_data->gpio_int)) {
+ /* configure interrupt gpio */
+ ret = gpio_request(sensor->platform_data->gpio_int,
+ "gyro_gpio_int");
+ if (ret) {
+ pr_err("%s: unable to request interrupt gpio %d\n",
+ __func__,
+ sensor->platform_data->gpio_int);
+ goto err_pm_set_suspended;
+ }
+
+ ret = gpio_direction_input(
+ sensor->platform_data->gpio_int);
+ if (ret) {
+ pr_err("%s: unable to set direction for gpio %d\n",
+ __func__, sensor->platform_data->gpio_int);
+ goto err_free_gpio;
+ }
+ }
+
error = request_threaded_irq(client->irq,
NULL, mpu3050_interrupt_thread,
- IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_FALLING,
"mpu3050", sensor);
if (error) {
dev_err(&client->dev,
@@ -508,14 +618,26 @@
goto err_free_irq;
}
+ error = create_sysfs_interfaces(&client->dev);
+ if (error < 0) {
+ dev_err(&client->dev, "failed to create sysfs\n");
+ goto err_input_cleanup;
+ }
+
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev, MPU3050_AUTO_DELAY);
return 0;
+err_input_cleanup:
+ input_unregister_device(idev);
err_free_irq:
if (client->irq > 0)
free_irq(client->irq, sensor);
+err_free_gpio:
+ if ((client->irq > 0) &&
+ (gpio_is_valid(sensor->platform_data->gpio_int)))
+ gpio_free(sensor->platform_data->gpio_int);
err_pm_set_suspended:
pm_runtime_set_suspended(&client->dev);
err_free_mem:
@@ -537,8 +659,12 @@
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- free_irq(client->irq, sensor);
+ if (client->irq)
+ free_irq(client->irq, sensor);
+
+ remove_sysfs_interfaces(&client->dev);
input_unregister_device(sensor->idev);
+
kfree(sensor);
return 0;
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1c70527..f10f433 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -26,7 +26,7 @@
#include <linux/seq_file.h>
#include <linux/regulator/consumer.h>
#include <linux/string.h>
-
+#include <linux/of_gpio.h>
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
/* Early-suspend level */
@@ -36,7 +36,9 @@
/* Family ID */
#define MXT224_ID 0x80
#define MXT224E_ID 0x81
+#define MXT336S_ID 0x82
#define MXT1386_ID 0xA0
+#define MXT1664S_ID 0xA2
/* Version */
#define MXT_VER_20 20
@@ -94,6 +96,7 @@
#define MXT_TOUCH_PROXKEY_T52 52
#define MXT_PROCI_GRIPFACE_T20 20
#define MXT_PROCG_NOISE_T22 22
+#define MXT_PROCG_NOISE_T62 62
#define MXT_PROCI_ONETOUCH_T24 24
#define MXT_PROCI_TWOTOUCH_T27 27
#define MXT_PROCI_GRIP_T40 40
@@ -102,6 +105,7 @@
#define MXT_PROCI_STYLUS_T47 47
#define MXT_PROCI_ADAPTIVETHRESHOLD_T55 55
#define MXT_PROCI_SHIELDLESS_T56 56
+#define MXT_PROCI_EXTRATSDATA_T57 57
#define MXT_PROCG_NOISESUPPRESSION_T48 48
#define MXT_SPT_COMMSCONFIG_T18 18
#define MXT_SPT_GPIOPWM_T19 19
@@ -111,6 +115,7 @@
#define MXT_SPT_DIGITIZER_T43 43
#define MXT_SPT_MESSAGECOUNT_T44 44
#define MXT_SPT_CTECONFIG_T46 46
+#define MXT_SPT_TIMER_T61 61
/* MXT_GEN_COMMAND_T6 field */
#define MXT_COMMAND_RESET 0
@@ -231,6 +236,8 @@
#define MXT224_RESET_TIME 65 /* msec */
#define MXT224E_RESET_TIME 150 /* msec */
#define MXT1386_RESET_TIME 250 /* msec */
+#define MXT336S_RESET_TIME 25 /* msec */
+#define MXT1664S_RESET_TIME 65 /* msec */
#define MXT_RESET_TIME 250 /* msec */
#define MXT_RESET_NOCHGREAD 400 /* msec */
@@ -283,6 +290,8 @@
#define MXT_CFG_VERSION_LESS 1
#define MXT_CFG_VERSION_GREATER 2
+#define MXT_COORDS_ARR_SIZE 4
+
#define MXT_DEBUGFS_DIR "atmel_mxt_ts"
#define MXT_DEBUGFS_FILE "object"
@@ -372,6 +381,7 @@
case MXT_TOUCH_PROXKEY_T52:
case MXT_PROCI_GRIPFACE_T20:
case MXT_PROCG_NOISE_T22:
+ case MXT_PROCG_NOISE_T62:
case MXT_PROCI_ONETOUCH_T24:
case MXT_PROCI_TWOTOUCH_T27:
case MXT_PROCI_GRIP_T40:
@@ -379,6 +389,7 @@
case MXT_PROCI_TOUCHSUPPRESSION_T42:
case MXT_PROCI_STYLUS_T47:
case MXT_PROCI_SHIELDLESS_T56:
+ case MXT_PROCI_EXTRATSDATA_T57:
case MXT_PROCG_NOISESUPPRESSION_T48:
case MXT_SPT_COMMSCONFIG_T18:
case MXT_SPT_GPIOPWM_T19:
@@ -387,6 +398,7 @@
case MXT_SPT_USERDATA_T38:
case MXT_SPT_DIGITIZER_T43:
case MXT_SPT_CTECONFIG_T46:
+ case MXT_SPT_TIMER_T61:
case MXT_PROCI_ADAPTIVETHRESHOLD_T55:
return true;
default:
@@ -406,6 +418,7 @@
case MXT_TOUCH_PROXKEY_T52:
case MXT_PROCI_GRIPFACE_T20:
case MXT_PROCG_NOISE_T22:
+ case MXT_PROCG_NOISE_T62:
case MXT_PROCI_ONETOUCH_T24:
case MXT_PROCI_TWOTOUCH_T27:
case MXT_PROCI_GRIP_T40:
@@ -413,6 +426,7 @@
case MXT_PROCI_TOUCHSUPPRESSION_T42:
case MXT_PROCI_STYLUS_T47:
case MXT_PROCI_SHIELDLESS_T56:
+ case MXT_PROCI_EXTRATSDATA_T57:
case MXT_PROCG_NOISESUPPRESSION_T48:
case MXT_SPT_COMMSCONFIG_T18:
case MXT_SPT_GPIOPWM_T19:
@@ -421,6 +435,7 @@
case MXT_SPT_USERDATA_T38:
case MXT_SPT_DIGITIZER_T43:
case MXT_SPT_CTECONFIG_T46:
+ case MXT_SPT_TIMER_T61:
case MXT_PROCI_ADAPTIVETHRESHOLD_T55:
return true;
default:
@@ -1293,8 +1308,12 @@
case MXT224E_ID:
msleep(MXT224E_RESET_TIME);
break;
+ case MXT336S_ID:
+ msleep(MXT336S_RESET_TIME);
case MXT1386_ID:
msleep(MXT1386_RESET_TIME);
+ case MXT1664S_ID:
+ msleep(MXT1664S_RESET_TIME);
break;
default:
msleep(MXT_RESET_TIME);
@@ -2307,14 +2326,228 @@
}
}
+#ifdef CONFIG_OF
+static int mxt_get_dt_coords(struct device *dev, char *name,
+ struct mxt_platform_data *pdata)
+{
+ u32 coords[MXT_COORDS_ARR_SIZE];
+ struct property *prop;
+ struct device_node *np = dev->of_node;
+ int coords_size, rc;
+
+ prop = of_find_property(np, name, NULL);
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ coords_size = prop->length / sizeof(u32);
+ if (coords_size != MXT_COORDS_ARR_SIZE) {
+ dev_err(dev, "invalid %s\n", name);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(np, name, coords, coords_size);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read %s\n", name);
+ return rc;
+ }
+
+ if (strncmp(name, "atmel,panel-coords",
+ sizeof("atmel,panel-coords")) == 0) {
+ pdata->panel_minx = coords[0];
+ pdata->panel_miny = coords[1];
+ pdata->panel_maxx = coords[2];
+ pdata->panel_maxy = coords[3];
+ } else if (strncmp(name, "atmel,display-coords",
+ sizeof("atmel,display-coords")) == 0) {
+ pdata->disp_minx = coords[0];
+ pdata->disp_miny = coords[1];
+ pdata->disp_maxx = coords[2];
+ pdata->disp_maxy = coords[3];
+ } else {
+ dev_err(dev, "unsupported property %s\n", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mxt_parse_config(struct device *dev, struct device_node *np,
+ struct mxt_config_info *info)
+{
+ struct property *prop;
+ u8 *temp_cfg;
+
+ prop = of_find_property(np, "atmel,config", &info->config_length);
+ if (!prop) {
+ dev_err(dev, "Looking up %s property in node %s failed",
+ "atmel,config", np->full_name);
+ return -ENODEV;
+ } else if (!info->config_length) {
+ dev_err(dev, "Invalid length of configuration data\n");
+ return -EINVAL;
+ }
+
+ temp_cfg = devm_kzalloc(dev,
+ info->config_length * sizeof(u8), GFP_KERNEL);
+ if (!temp_cfg) {
+ dev_err(dev, "Unable to allocate memory to store cfg\n");
+ return -ENOMEM;
+ }
+
+ memcpy(temp_cfg, prop->value, info->config_length);
+ info->config = temp_cfg;
+
+ return 0;
+}
+
+static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
+{
+ int rc;
+ struct mxt_config_info *info;
+ struct device_node *temp, *np = dev->of_node;
+ struct property *prop;
+ u32 temp_val;
+
+ rc = mxt_get_dt_coords(dev, "atmel,panel-coords", pdata);
+ if (rc)
+ return rc;
+
+ rc = mxt_get_dt_coords(dev, "atmel,display-coords", pdata);
+ if (rc)
+ return rc;
+
+ /* regulator info */
+ pdata->i2c_pull_up = of_property_read_bool(np, "atmel,i2c-pull-up");
+ pdata->digital_pwr_regulator = of_property_read_bool(np,
+ "atmel,dig-reg-support");
+ /* reset, irq gpio info */
+ pdata->reset_gpio = of_get_named_gpio_flags(np, "atmel,reset-gpio",
+ 0, &pdata->reset_gpio_flags);
+ pdata->irq_gpio = of_get_named_gpio_flags(np, "atmel,irq-gpio",
+ 0, &pdata->irq_gpio_flags);
+
+ /* keycodes for keyarray object*/
+ prop = of_find_property(np, "atmel,key-codes", NULL);
+ if (prop) {
+ pdata->key_codes = devm_kzalloc(dev,
+ sizeof(int) * MXT_KEYARRAY_MAX_KEYS,
+ GFP_KERNEL);
+ if (!pdata->key_codes)
+ return -ENOMEM;
+ if ((prop->length/sizeof(u32)) == MXT_KEYARRAY_MAX_KEYS) {
+ rc = of_property_read_u32_array(np, "atmel,key-codes",
+ pdata->key_codes, MXT_KEYARRAY_MAX_KEYS);
+ if (rc) {
+ dev_err(dev, "Unable to read key codes\n");
+ return rc;
+ }
+ } else
+ return -EINVAL;
+ }
+
+ /* config array size */
+ pdata->config_array_size = 0;
+ temp = NULL;
+ while ((temp = of_get_next_child(np, temp)))
+ pdata->config_array_size++;
+
+ if (!pdata->config_array_size)
+ return 0;
+
+ info = devm_kzalloc(dev, pdata->config_array_size *
+ sizeof(struct mxt_config_info), GFP_KERNEL);
+ if (!info) {
+ dev_err(dev, "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ pdata->config_array = info;
+
+ for_each_child_of_node(np, temp) {
+ rc = of_property_read_string(temp, "atmel,fw-name",
+ &info->fw_name);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read fw name\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(temp, "atmel,family-id", &temp_val);
+ if (rc) {
+ dev_err(dev, "Unable to read family id\n");
+ return rc;
+ } else
+ info->family_id = (u8) temp_val;
+
+ rc = of_property_read_u32(temp, "atmel,variant-id", &temp_val);
+ if (rc) {
+ dev_err(dev, "Unable to read variant id\n");
+ return rc;
+ } else
+ info->variant_id = (u8) temp_val;
+
+ rc = of_property_read_u32(temp, "atmel,version", &temp_val);
+ if (rc) {
+ dev_err(dev, "Unable to read controller version\n");
+ return rc;
+ } else
+ info->version = (u8) temp_val;
+
+ rc = of_property_read_u32(temp, "atmel,build", &temp_val);
+ if (rc) {
+ dev_err(dev, "Unable to read build id\n");
+ return rc;
+ } else
+ info->build = (u8) temp_val;
+
+ info->bootldr_id = of_property_read_u32(temp,
+ "atmel,bootldr-id", &temp_val);
+ if (rc) {
+ dev_err(dev, "Unable to read bootldr-id\n");
+ return rc;
+ } else
+ info->bootldr_id = (u8) temp_val;
+
+ rc = mxt_parse_config(dev, temp, info);
+ if (rc) {
+ dev_err(dev, "Unable to parse config data\n");
+ return rc;
+ }
+ info++;
+ }
+
+ return 0;
+}
+#else
+static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
+{
+ return -ENODEV;
+}
+#endif
+
static int __devinit mxt_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- const struct mxt_platform_data *pdata = client->dev.platform_data;
+ struct mxt_platform_data *pdata;
struct mxt_data *data;
struct input_dev *input_dev;
int error, i;
+ if (client->dev.of_node) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct mxt_platform_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ error = mxt_parse_dt(&client->dev, pdata);
+ if (error)
+ return error;
+ } else
+ pdata = client->dev.platform_data;
+
if (!pdata)
return -EINVAL;
@@ -2336,7 +2569,6 @@
data->client = client;
data->input_dev = input_dev;
data->pdata = pdata;
- data->irq = client->irq;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
@@ -2394,46 +2626,47 @@
if (gpio_is_valid(pdata->irq_gpio)) {
/* configure touchscreen irq gpio */
- error = gpio_request(pdata->irq_gpio,
- "mxt_irq_gpio");
+ error = gpio_request(pdata->irq_gpio, "mxt_irq_gpio");
if (error) {
- pr_err("%s: unable to request gpio [%d]\n", __func__,
+ dev_err(&client->dev, "unable to request gpio [%d]\n",
pdata->irq_gpio);
goto err_power_on;
}
error = gpio_direction_input(pdata->irq_gpio);
if (error) {
- pr_err("%s: unable to set_direction for gpio [%d]\n",
- __func__, pdata->irq_gpio);
+ dev_err(&client->dev,
+ "unable to set direction for gpio [%d]\n",
+ pdata->irq_gpio);
goto err_irq_gpio_req;
}
+ data->irq = client->irq = gpio_to_irq(pdata->irq_gpio);
+ } else {
+ dev_err(&client->dev, "irq gpio not provided\n");
+ goto err_power_on;
}
if (gpio_is_valid(pdata->reset_gpio)) {
/* configure touchscreen reset out gpio */
- error = gpio_request(pdata->reset_gpio,
- "mxt_reset_gpio");
+ error = gpio_request(pdata->reset_gpio, "mxt_reset_gpio");
if (error) {
- pr_err("%s: unable to request reset gpio %d\n",
- __func__, pdata->reset_gpio);
+ dev_err(&client->dev, "unable to request gpio [%d]\n",
+ pdata->reset_gpio);
goto err_irq_gpio_req;
}
- error = gpio_direction_output(
- pdata->reset_gpio, 1);
+ error = gpio_direction_output(pdata->reset_gpio, 1);
if (error) {
- pr_err("%s: unable to set direction for gpio %d\n",
- __func__, pdata->reset_gpio);
+ dev_err(&client->dev,
+ "unable to set direction for gpio [%d]\n",
+ pdata->reset_gpio);
goto err_reset_gpio_req;
}
}
mxt_reset_delay(data);
-
error = mxt_initialize(data);
if (error)
goto err_reset_gpio_req;
-
error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
pdata->irqflags, client->dev.driver->name, data);
if (error) {
@@ -2540,11 +2773,20 @@
{ }
};
MODULE_DEVICE_TABLE(i2c, mxt_id);
+#ifdef CONFIG_OF
+static struct of_device_id mxt_match_table[] = {
+ { .compatible = "atmel,mxt-ts",},
+ { },
+};
+#else
+#define mxt_match_table NULL
+#endif
static struct i2c_driver mxt_driver = {
.driver = {
.name = "atmel_mxt_ts",
.owner = THIS_MODULE,
+ .of_match_table = mxt_match_table,
#ifdef CONFIG_PM
.pm = &mxt_pm_ops,
#endif
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index 28ad0ff..de31859 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -260,15 +260,15 @@
SET_S2CR_N(base, num, 0);
SET_S2CR_CBNDX(base, num, ctx);
/* Set security bit override to be Non-secure */
- SET_S2CR_NSCFG(base, sids[i], 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_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);
+
/* Find if this page table is used elsewhere, and re-use ASID */
found = 0;
for (i = 0; i < ncb; i++)
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 9240605..26e8496 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -307,6 +307,16 @@
This option enables support for LEDs connected to the PCA9633
LED driver chip accessed via the I2C bus.
+config LEDS_QPNP
+ tristate "Support for QPNP LEDs"
+ depends on SPMI && OF_SPMI
+ help
+ This driver supports the leds functionality of Qualcomm PNP PMIC. It
+ includes RGB Leds, WLED and Flash Led.
+
+ To compile this driver as a module, choose M here: the module will
+ be called leds-qpnp.
+
config LEDS_WM831X_STATUS
tristate "LED support for status LEDs on WM831x PMICs"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 8edd465..c688898 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -19,6 +19,7 @@
obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
obj-$(CONFIG_LEDS_PM8XXX) += leds-pm8xxx.o
+obj-$(CONFIG_LEDS_QPNP) += leds-qpnp.o
obj-$(CONFIG_LEDS_GPIO_REGISTER) += leds-gpio-register.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
new file mode 100644
index 0000000..f42fb5e
--- /dev/null
+++ b/drivers/leds/leds-qpnp.c
@@ -0,0 +1,725 @@
+
+/* 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/spmi.h>
+
+#define WLED_MOD_EN_REG(base, n) (base + 0x60 + n*0x10)
+#define WLED_IDAC_DLY_REG(base, n) (WLED_MOD_EN_REG(base, n) + 0x01)
+#define WLED_FULL_SCALE_REG(base, n) (WLED_IDAC_DLY_REG(base, n) + 0x01)
+
+/* wled control registers */
+#define WLED_BRIGHTNESS_CNTL_LSB(base, n) (base + 0x40 + 2*n)
+#define WLED_BRIGHTNESS_CNTL_MSB(base, n) (base + 0x41 + 2*n)
+#define WLED_MOD_CTRL_REG(base) (base + 0x46)
+#define WLED_SYNC_REG(base) (base + 0x47)
+#define WLED_FDBCK_CTRL_REG(base) (base + 0x48)
+#define WLED_SWITCHING_FREQ_REG(base) (base + 0x4C)
+#define WLED_OVP_CFG_REG(base) (base + 0x4D)
+#define WLED_BOOST_LIMIT_REG(base) (base + 0x4E)
+#define WLED_CURR_SINK_REG(base) (base + 0x4F)
+#define WLED_HIGH_POLE_CAP_REG(base) (base + 0x58)
+#define WLED_CURR_SINK_MASK 0xE0
+#define WLED_CURR_SINK_SHFT 0x05
+#define WLED_SWITCH_FREQ_MASK 0x02
+#define WLED_OVP_VAL_MASK 0x03
+#define WLED_OVP_VAL_BIT_SHFT 0x00
+#define WLED_BOOST_LIMIT_MASK 0x07
+#define WLED_BOOST_LIMIT_BIT_SHFT 0x00
+#define WLED_BOOST_ON 0x80
+#define WLED_BOOST_OFF 0x00
+#define WLED_EN_MASK 0x80
+#define WLED_NO_MASK 0x00
+#define WLED_CP_SELECT_MAX 0x03
+#define WLED_CP_SELECT_MASK 0x02
+#define WLED_USE_EXT_GEN_MOD_SRC 0x01
+#define WLED_CTL_DLY_STEP 200
+#define WLED_CTL_DLY_MAX 1400
+#define WLED_MAX_CURR 25
+#define WLED_MSB_MASK 0x0F
+#define WLED_MAX_CURR_MASK 0x19
+#define WLED_OP_FDBCK_MASK 0x07
+#define WLED_OP_FDBCK_BIT_SHFT 0x00
+
+#define WLED_MAX_LEVEL 255
+#define WLED_8_BIT_MASK 0xFF
+#define WLED_4_BIT_MASK 0x0F
+#define WLED_8_BIT_SHFT 0x08
+#define WLED_MAX_DUTY_CYCLE 0xFFF
+
+#define WLED_SYNC_VAL 0x07
+#define WLED_SYNC_RESET_VAL 0x00
+
+#define WLED_TRIGGER_DEFAULT "none"
+#define WLED_FLAGS_DEFAULT 0x00
+#define WLED_DEFAULT_STRINGS 0x01
+#define WLED_DEFAULT_OVP_VAL 0x02
+#define WLED_BOOST_LIM_DEFAULT 0x03
+#define WLED_CP_SEL_DEFAULT 0x00
+#define WLED_CTRL_DLY_DEFAULT 0x00
+#define WLED_SWITCH_FREQ_DEFAULT 0x02
+
+/**
+ * enum qpnp_leds - QPNP supported led ids
+ * @QPNP_ID_WLED - White led backlight
+ */
+enum qpnp_leds {
+ QPNP_ID_WLED,
+};
+
+/* current boost limit */
+enum wled_current_boost_limit {
+ WLED_CURR_LIMIT_105mA,
+ WLED_CURR_LIMIT_385mA,
+ WLED_CURR_LIMIT_525mA,
+ WLED_CURR_LIMIT_805mA,
+ WLED_CURR_LIMIT_980mA,
+ WLED_CURR_LIMIT_1260mA,
+ WLED_CURR_LIMIT_1400mA,
+ WLED_CURR_LIMIT_1680mA,
+};
+
+/* over voltage protection threshold */
+enum wled_ovp_threshold {
+ WLED_OVP_35V,
+ WLED_OVP_32V,
+ WLED_OVP_29V,
+ WLED_OVP_37V,
+};
+
+/* switch frquency */
+enum wled_switch_freq {
+ WLED_800kHz = 0,
+ WLED_960kHz,
+ WLED_1600kHz,
+ WLED_3200kHz,
+};
+
+static u8 wled_debug_regs[] = {
+ /* common registers */
+ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ /* LED1 */
+ 0x60, 0x61, 0x62, 0x63, 0x66,
+ /* LED1 */
+ 0x70, 0x71, 0x72, 0x73, 0x76,
+ /* LED1 */
+ 0x80, 0x81, 0x82, 0x83, 0x86,
+};
+
+/**
+ * wled_config_data - wled configuration data
+ * @num_strings - number of wled strings supported
+ * @ovp_val - over voltage protection threshold
+ * @boost_curr_lim - boot current limit
+ * @cp_select - high pole capacitance
+ * @ctrl_delay_us - delay in activation of led
+ * @dig_mod_gen_en - digital module generator
+ * @cs_out_en - current sink output enable
+ * @op_fdbck - selection of output as feedback for the boost
+ */
+struct wled_config_data {
+ u8 num_strings;
+ u8 ovp_val;
+ u8 boost_curr_lim;
+ u8 cp_select;
+ u8 ctrl_delay_us;
+ u8 switch_freq;
+ bool dig_mod_gen_en;
+ bool cs_out_en;
+ bool op_fdbck;
+};
+
+/**
+ * struct qpnp_led_data - internal led data structure
+ * @led_classdev - led class device
+ * @id - led index
+ * @base_reg - base register given in device tree
+ * @lock - to protect the transactions
+ * @reg - cached value of led register
+ * @max_current - maximum current supported by LED
+ * @default_on - true: default state max, false, default state 0
+ */
+struct qpnp_led_data {
+ struct led_classdev cdev;
+ struct spmi_device *spmi_dev;
+ int id;
+ u16 base;
+ u8 reg;
+ struct mutex lock;
+ struct wled_config_data *wled_cfg;
+ int max_current;
+ bool default_on;
+};
+
+static int
+qpnp_led_masked_write(struct qpnp_led_data *led, u16 addr, u8 mask, u8 val)
+{
+ int rc;
+ u8 reg;
+
+ rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ addr, ®, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to read from addr=%x, rc(%d)\n", addr, rc);
+ }
+
+ reg &= ~mask;
+ reg |= val;
+
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ addr, ®, 1);
+ if (rc)
+ dev_err(&led->spmi_dev->dev,
+ "Unable to write to addr=%x, rc(%d)\n", addr, rc);
+ return rc;
+}
+
+static int qpnp_wled_set(struct qpnp_led_data *led)
+{
+ int rc, duty;
+ u8 level, val, i, num_wled_strings;
+
+ level = led->cdev.brightness;
+
+ if (level > WLED_MAX_LEVEL)
+ level = WLED_MAX_LEVEL;
+ if (level == 0) {
+ val = WLED_BOOST_OFF;
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+ led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
+ &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED write ctrl reg failed(%d)\n", rc);
+ return rc;
+ }
+ } else {
+ val = WLED_BOOST_ON;
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+ led->spmi_dev->sid, WLED_MOD_CTRL_REG(led->base),
+ &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED write ctrl reg failed(%d)\n", rc);
+ return rc;
+ }
+ }
+
+ duty = (WLED_MAX_DUTY_CYCLE * level) / WLED_MAX_LEVEL;
+
+ num_wled_strings = led->wled_cfg->num_strings;
+
+ /* program brightness control registers */
+ for (i = 0; i < num_wled_strings; i++) {
+ rc = qpnp_led_masked_write(led,
+ WLED_BRIGHTNESS_CNTL_MSB(led->base, i), WLED_MSB_MASK,
+ (duty >> WLED_8_BIT_SHFT) & WLED_4_BIT_MASK);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED set brightness MSB failed(%d)\n", rc);
+ return rc;
+ }
+ val = duty & WLED_8_BIT_MASK;
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl,
+ led->spmi_dev->sid,
+ WLED_BRIGHTNESS_CNTL_LSB(led->base, i), &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED set brightness LSB failed(%d)\n", rc);
+ return rc;
+ }
+ }
+
+ /* sync */
+ val = WLED_SYNC_VAL;
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ WLED_SYNC_REG(led->base), &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED set sync reg failed(%d)\n", rc);
+ return rc;
+ }
+
+ val = WLED_SYNC_RESET_VAL;
+ rc = spmi_ext_register_writel(led->spmi_dev->ctrl, led->spmi_dev->sid,
+ WLED_SYNC_REG(led->base), &val, 1);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED reset sync reg failed(%d)\n", rc);
+ return rc;
+ }
+ return 0;
+}
+
+static void qpnp_wled_dump_regs(struct qpnp_led_data *led)
+{
+ int i;
+ u8 val;
+
+ pr_debug("===== WLED register dump start =====\n");
+ for (i = 0; i < ARRAY_SIZE(wled_debug_regs); i++) {
+ spmi_ext_register_readl(led->spmi_dev->ctrl,
+ led->spmi_dev->sid,
+ led->base + wled_debug_regs[i],
+ &val, sizeof(val));
+ pr_debug("0x%x = 0x%x\n", led->base + wled_debug_regs[i], val);
+ }
+ pr_debug("===== WLED register dump end =====\n");
+}
+
+static void qpnp_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ int rc;
+ struct qpnp_led_data *led;
+
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ if (value < LED_OFF || value > led->cdev.max_brightness) {
+ dev_err(led->cdev.dev, "Invalid brightness value\n");
+ return;
+ }
+
+ mutex_lock(&led->lock);
+ led->cdev.brightness = value;
+
+ switch (led->id) {
+ case QPNP_ID_WLED:
+ rc = qpnp_wled_set(led);
+ if (rc < 0)
+ dev_err(led->cdev.dev,
+ "WLED set brightness failed (%d)\n", rc);
+ break;
+ default:
+ dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+ break;
+ }
+ mutex_unlock(&led->lock);
+}
+
+static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
+{
+ switch (led->id) {
+ case QPNP_ID_WLED:
+ led->cdev.max_brightness = WLED_MAX_LEVEL;
+ break;
+ default:
+ dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static enum led_brightness qpnp_led_get(struct led_classdev *led_cdev)
+{
+ struct qpnp_led_data *led;
+
+ led = container_of(led_cdev, struct qpnp_led_data, cdev);
+
+ return led->cdev.brightness;
+}
+
+static int __devinit qpnp_wled_init(struct qpnp_led_data *led)
+{
+ int rc, i;
+ u8 num_wled_strings;
+
+ num_wled_strings = led->wled_cfg->num_strings;
+
+ /* verify ranges */
+ if (led->wled_cfg->ovp_val > WLED_OVP_37V) {
+ dev_err(&led->spmi_dev->dev, "Invalid ovp value\n");
+ return -EINVAL;
+ }
+
+ if (led->wled_cfg->boost_curr_lim > WLED_CURR_LIMIT_1680mA) {
+ dev_err(&led->spmi_dev->dev, "Invalid boost current limit\n");
+ return -EINVAL;
+ }
+
+ if (led->wled_cfg->cp_select > WLED_CP_SELECT_MAX) {
+ dev_err(&led->spmi_dev->dev, "Invalid pole capacitance\n");
+ return -EINVAL;
+ }
+
+ if ((led->max_current > WLED_MAX_CURR)) {
+ dev_err(&led->spmi_dev->dev, "Invalid max current\n");
+ return -EINVAL;
+ }
+
+ if ((led->wled_cfg->ctrl_delay_us % WLED_CTL_DLY_STEP) ||
+ (led->wled_cfg->ctrl_delay_us > WLED_CTL_DLY_MAX)) {
+ dev_err(&led->spmi_dev->dev, "Invalid control delay\n");
+ return -EINVAL;
+ }
+
+ /* program over voltage protection threshold */
+ rc = qpnp_led_masked_write(led, WLED_OVP_CFG_REG(led->base),
+ WLED_OVP_VAL_MASK,
+ (led->wled_cfg->ovp_val << WLED_OVP_VAL_BIT_SHFT));
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED OVP reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ /* program current boost limit */
+ rc = qpnp_led_masked_write(led, WLED_BOOST_LIMIT_REG(led->base),
+ WLED_BOOST_LIMIT_MASK, led->wled_cfg->boost_curr_lim);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED boost limit reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ /* program output feedback */
+ rc = qpnp_led_masked_write(led, WLED_FDBCK_CTRL_REG(led->base),
+ WLED_OP_FDBCK_MASK,
+ (led->wled_cfg->op_fdbck << WLED_OP_FDBCK_BIT_SHFT));
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED fdbck ctrl reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ /* program switch frequency */
+ rc = qpnp_led_masked_write(led, WLED_SWITCHING_FREQ_REG(led->base),
+ WLED_SWITCH_FREQ_MASK, led->wled_cfg->switch_freq);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED switch freq reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ /* program current sink */
+ if (led->wled_cfg->cs_out_en) {
+ rc = qpnp_led_masked_write(led, WLED_CURR_SINK_REG(led->base),
+ WLED_CURR_SINK_MASK,
+ (led->wled_cfg->num_strings << WLED_CURR_SINK_SHFT));
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED curr sink reg write failed(%d)\n", rc);
+ return rc;
+ }
+ }
+
+ /* program high pole capacitance */
+ rc = qpnp_led_masked_write(led, WLED_HIGH_POLE_CAP_REG(led->base),
+ WLED_CP_SELECT_MASK, led->wled_cfg->cp_select);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED pole cap reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ /* program modulator, current mod src and cabc */
+ for (i = 0; i < num_wled_strings; i++) {
+ rc = qpnp_led_masked_write(led, WLED_MOD_EN_REG(led->base, i),
+ WLED_NO_MASK, WLED_EN_MASK);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED mod enable reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ if (led->wled_cfg->dig_mod_gen_en) {
+ rc = qpnp_led_masked_write(led,
+ WLED_MOD_EN_REG(led->base, i),
+ WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED dig mod en reg write failed(%d)\n", rc);
+ }
+ }
+
+ rc = qpnp_led_masked_write(led,
+ WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
+ led->max_current);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "WLED max current reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ }
+
+ /* dump wled registers */
+ qpnp_wled_dump_regs(led);
+
+ return 0;
+}
+
+static int __devinit qpnp_led_initialize(struct qpnp_led_data *led)
+{
+ int rc;
+
+ switch (led->id) {
+ case QPNP_ID_WLED:
+ rc = qpnp_wled_init(led);
+ if (rc)
+ dev_err(led->cdev.dev,
+ "WLED initialize failed(%d)\n", rc);
+ break;
+ default:
+ dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+/*
+ * Handlers for alternative sources of platform_data
+ */
+static int __devinit qpnp_get_config_wled(struct qpnp_led_data *led,
+ struct device_node *node)
+{
+ u32 val;
+ int rc;
+ const char *temp_string;
+
+ led->id = QPNP_ID_WLED;
+
+ led->wled_cfg = devm_kzalloc(&led->spmi_dev->dev,
+ sizeof(struct wled_config_data), GFP_KERNEL);
+ if (!led->wled_cfg) {
+ dev_err(&led->spmi_dev->dev, "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ led->cdev.default_trigger = WLED_TRIGGER_DEFAULT;
+ rc = of_property_read_string(node, "linux,default-trigger",
+ &temp_string);
+ if (!rc)
+ led->cdev.default_trigger = temp_string;
+ else if (rc != -EINVAL)
+ return rc;
+
+
+ led->cdev.flags = WLED_FLAGS_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,flags", &val);
+ if (!rc)
+ led->cdev.flags = (int) val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ led->default_on = true;
+ rc = of_property_read_string(node, "qcom,default-state",
+ &temp_string);
+ if (!rc) {
+ if (!strncmp(temp_string, "off", sizeof("off")))
+ led->default_on = false;
+ } else if (rc != -EINVAL)
+ return rc;
+
+ led->wled_cfg->num_strings = WLED_DEFAULT_STRINGS;
+ rc = of_property_read_u32(node, "qcom,num-strings", &val);
+ if (!rc)
+ led->wled_cfg->num_strings = (u8) val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ led->wled_cfg->ovp_val = WLED_DEFAULT_OVP_VAL;
+ rc = of_property_read_u32(node, "qcom,ovp-val", &val);
+ if (!rc)
+ led->wled_cfg->ovp_val = (u8) val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ led->wled_cfg->boost_curr_lim = WLED_BOOST_LIM_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,boost-curr-lim", &val);
+ if (!rc)
+ led->wled_cfg->boost_curr_lim = (u8) val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ led->wled_cfg->cp_select = WLED_CP_SEL_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,cp-sel", &val);
+ if (!rc)
+ led->wled_cfg->cp_select = (u8) val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ led->wled_cfg->ctrl_delay_us = WLED_CTRL_DLY_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,ctrl-delay-us", &val);
+ if (!rc)
+ led->wled_cfg->ctrl_delay_us = (u8) val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ led->wled_cfg->switch_freq = WLED_SWITCH_FREQ_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,switch-freq", &val);
+ if (!rc)
+ led->wled_cfg->switch_freq = (u8) val;
+ else if (rc != -EINVAL)
+ return rc;
+
+ led->wled_cfg->dig_mod_gen_en =
+ of_property_read_bool(node, "qcom,dig-mod-gen-en");
+
+ led->wled_cfg->cs_out_en =
+ of_property_read_bool(node, "qcom,cs-out-en");
+
+ led->wled_cfg->op_fdbck =
+ of_property_read_bool(node, "qcom,op-fdbck");
+
+ return 0;
+}
+
+static int __devinit qpnp_leds_probe(struct spmi_device *spmi)
+{
+ struct qpnp_led_data *led;
+ struct resource *led_resource;
+ struct device_node *node;
+ int rc;
+ const char *led_label;
+
+ led = devm_kzalloc(&spmi->dev, (sizeof(struct qpnp_led_data)),
+ GFP_KERNEL);
+ if (!led) {
+ dev_err(&spmi->dev, "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ led->spmi_dev = spmi;
+
+ led_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+ if (!led_resource) {
+ dev_err(&spmi->dev, "Unable to get LED base address\n");
+ return -ENXIO;
+ }
+ led->base = led_resource->start;
+
+ dev_set_drvdata(&spmi->dev, led);
+
+ node = led->spmi_dev->dev.of_node;
+ if (node == NULL)
+ return -ENODEV;
+
+ rc = of_property_read_string(node, "qcom,label", &led_label);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading label, rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_string(node, "qcom,name", &led->cdev.name);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading led name, rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,max-current", &led->max_current);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Failure reading max_current, rc = %d\n", rc);
+ return rc;
+ }
+
+ led->cdev.brightness_set = qpnp_led_set;
+ led->cdev.brightness_get = qpnp_led_get;
+ led->cdev.brightness = LED_OFF;
+
+ if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
+ rc = qpnp_get_config_wled(led, node);
+ if (rc < 0) {
+ dev_err(&led->spmi_dev->dev,
+ "Unable to read wled config data\n");
+ return rc;
+ }
+ } else {
+ dev_err(&led->spmi_dev->dev, "No LED matching label\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&led->lock);
+
+ rc = qpnp_led_initialize(led);
+ if (rc < 0)
+ goto fail_id_check;
+
+ rc = qpnp_led_set_max_brightness(led);
+ if (rc < 0)
+ goto fail_id_check;
+
+
+ rc = led_classdev_register(&spmi->dev, &led->cdev);
+ if (rc) {
+ dev_err(&spmi->dev, "unable to register led %d,rc=%d\n",
+ led->id, rc);
+ goto fail_id_check;
+ }
+
+ /* configure default state */
+ if (led->default_on)
+ led->cdev.brightness = led->cdev.max_brightness;
+
+ qpnp_led_set(&led->cdev, led->cdev.brightness);
+
+ return 0;
+
+fail_id_check:
+ mutex_destroy(&led->lock);
+ led_classdev_unregister(&led->cdev);
+ return rc;
+}
+
+static int __devexit qpnp_leds_remove(struct spmi_device *spmi)
+{
+ struct qpnp_led_data *led = dev_get_drvdata(&spmi->dev);
+
+ mutex_destroy(&led->lock);
+ led_classdev_unregister(&led->cdev);
+
+ return 0;
+}
+static struct of_device_id spmi_match_table[] = {
+ { .compatible = "qcom,leds-qpnp",
+ }
+};
+
+static struct spmi_driver qpnp_leds_driver = {
+ .driver = {
+ .name = "qcom,leds-qpnp",
+ .of_match_table = spmi_match_table,
+ },
+ .probe = qpnp_leds_probe,
+ .remove = __devexit_p(qpnp_leds_remove),
+};
+
+static int __init qpnp_led_init(void)
+{
+ return spmi_driver_register(&qpnp_leds_driver);
+}
+module_init(qpnp_led_init);
+
+static void __exit qpnp_led_exit(void)
+{
+ spmi_driver_unregister(&qpnp_leds_driver);
+}
+module_exit(qpnp_led_exit);
+
+MODULE_DESCRIPTION("QPNP LEDs driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("leds:leds-qpnp");
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
index 372c612..c1d1462 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -65,6 +65,11 @@
/* Channel timeout in msec */
#define TSPP_CHANNEL_TIMEOUT 16
+/* module parameters for load time configuration */
+static int tsif0_mode = TSPP_TSIF_MODE_2;
+static int tsif1_mode = TSPP_TSIF_MODE_2;
+module_param(tsif0_mode, int, S_IRUGO);
+module_param(tsif1_mode, int, S_IRUGO);
/*
* Work scheduled each time TSPP notifies dmx
@@ -273,14 +278,17 @@
int ret;
int channel_id;
int *channel_ref_count;
+ enum tspp_tsif_mode mode;
/* determine the TSIF we are reading from */
if (mpq_demux->source == DMX_SOURCE_FRONT0) {
tsif = 0;
tspp_source = TSPP_SOURCE_TSIF0;
+ mode = (enum tspp_tsif_mode)tsif0_mode;
} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
tsif = 1;
tspp_source = TSPP_SOURCE_TSIF1;
+ mode = (enum tspp_tsif_mode)tsif1_mode;
} else {
/* invalid source */
MPQ_DVB_ERR_PRINT(
@@ -333,7 +341,7 @@
}
/* set TSPP source */
- ret = tspp_open_stream(0, channel_id, tspp_source);
+ ret = tspp_open_stream(0, channel_id, tspp_source, mode);
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
"%s: tspp_select_source(%d,%d) failed (%d)\n",
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index c0a35f9..1894465 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2347,37 +2347,6 @@
int retval;
radio->region = req_region;
- switch (radio->region) {
- case IRIS_REGION_US:
- radio->recv_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_EU:
- radio->recv_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN:
- radio->recv_conf.band_low_limit =
- REGION_JAPAN_STANDARD_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_JAPAN_STANDARD_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN_WIDE:
- radio->recv_conf.band_low_limit =
- REGION_JAPAN_WIDE_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_JAPAN_WIDE_BAND_HIGH;
- break;
- default:
- /* The user specifies the value.
- So nothing needs to be done */
- break;
- }
-
retval = hci_set_fm_recv_conf(
&radio->recv_conf,
radio->fm_hdev);
@@ -2391,34 +2360,6 @@
int retval;
radio->region = req_region;
- switch (radio->region) {
- case IRIS_REGION_US:
- radio->trans_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->trans_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_EU:
- radio->trans_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->trans_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN:
- radio->trans_conf.band_low_limit =
- REGION_JAPAN_STANDARD_BAND_LOW;
- radio->trans_conf.band_high_limit =
- REGION_JAPAN_STANDARD_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN_WIDE:
- radio->recv_conf.band_low_limit =
- REGION_JAPAN_WIDE_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_JAPAN_WIDE_BAND_HIGH;
- default:
- break;
- }
-
retval = hci_set_fm_trans_conf(
&radio->trans_conf,
radio->fm_hdev);
diff --git a/drivers/media/video/msm/actuators/msm_actuator.c b/drivers/media/video/msm/actuators/msm_actuator.c
index 554cddc..b5bdaae 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.c
+++ b/drivers/media/video/msm/actuators/msm_actuator.c
@@ -250,8 +250,6 @@
target_step_pos = dest_step_pos;
target_lens_pos =
a_ctrl->step_position_table[target_step_pos];
- if (curr_lens_pos == target_lens_pos)
- return rc;
rc = a_ctrl->func_tbl->
actuator_write_focus(
a_ctrl,
@@ -272,8 +270,6 @@
target_step_pos = step_boundary;
target_lens_pos =
a_ctrl->step_position_table[target_step_pos];
- if (curr_lens_pos == target_lens_pos)
- return rc;
rc = a_ctrl->func_tbl->
actuator_write_focus(
a_ctrl,
diff --git a/drivers/media/video/msm/cci/msm_cci.c b/drivers/media/video/msm/cci/msm_cci.c
index ad3cc6a..3caa580 100644
--- a/drivers/media/video/msm/cci/msm_cci.c
+++ b/drivers/media/video/msm/cci/msm_cci.c
@@ -24,11 +24,10 @@
#include "msm_cam_cci_hwreg.h"
#define V4L2_IDENT_CCI 50005
-#define CCI_I2C_QUEUE_0_SIZE 2
+#define CCI_I2C_QUEUE_0_SIZE 64
#define CCI_I2C_QUEUE_1_SIZE 16
-#undef CDBG
-#define CDBG pr_debug
+#define CCI_TIMEOUT msecs_to_jiffies(100)
static void msm_cci_set_clk_param(struct cci_device *cci_dev)
{
@@ -127,8 +126,9 @@
msm_camera_io_w(reg_val, cci_dev->base + CCI_QUEUE_START_ADDR);
CDBG("%s line %d wait_for_completion_interruptible\n",
__func__, __LINE__);
- wait_for_completion_interruptible(&cci_dev->
- cci_master_info[master].reset_complete);
+ wait_for_completion_interruptible_timeout(&cci_dev->
+ cci_master_info[master].reset_complete, CCI_TIMEOUT);
+
rc = cci_dev->cci_master_info[master].status;
if (rc < 0)
pr_err("%s failed rc %d\n", __func__, rc);
@@ -234,6 +234,9 @@
read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
mutex_lock(&cci_dev->cci_master_info[master].mutex);
CDBG("%s master %d, queue %d\n", __func__, master, queue);
+ CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
+ c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
+ c_ctrl->cci_info->id_map);
val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
c_ctrl->cci_info->retries << 16 |
c_ctrl->cci_info->id_map << 18;
@@ -285,9 +288,8 @@
val = 1 << ((master * 2) + queue);
msm_camera_io_w(val, cci_dev->base + CCI_QUEUE_START_ADDR);
-
- wait_for_completion_interruptible(&cci_dev->
- cci_master_info[master].reset_complete);
+ wait_for_completion_interruptible_timeout(&cci_dev->
+ cci_master_info[master].reset_complete, CCI_TIMEOUT);
read_bytes = (read_cfg->num_byte / 4) + 1;
index = 0;
@@ -328,6 +330,9 @@
cci_dev = v4l2_get_subdevdata(sd);
master = c_ctrl->cci_info->cci_i2c_master;
CDBG("%s master %d, queue %d\n", __func__, master, queue);
+ CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
+ c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
+ c_ctrl->cci_info->id_map);
mutex_lock(&cci_dev->cci_master_info[master].mutex);
val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
c_ctrl->cci_info->retries << 16 |
@@ -366,7 +371,7 @@
val = msm_camera_io_r(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR +
master * 0x200 + queue * 0x100);
- CDBG("%s line %d size of queue %d\n", __func__, __LINE__, val);
+ CDBG("%s:%d cur word count %d\n", __func__, __LINE__, val);
CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR\n", __func__, __LINE__);
msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR +
master * 0x200 + queue * 0x100);
@@ -378,8 +383,9 @@
CDBG("%s line %d wait_for_completion_interruptible\n",
__func__, __LINE__);
- wait_for_completion_interruptible(&cci_dev->
- cci_master_info[master].reset_complete);
+ wait_for_completion_interruptible_timeout(&cci_dev->
+ cci_master_info[master].reset_complete, CCI_TIMEOUT);
+
ERROR:
mutex_unlock(&cci_dev->cci_master_info[master].mutex);
return rc;
@@ -395,7 +401,10 @@
}
static struct msm_cam_clk_info cci_clk_info[] = {
- {"cci_clk_src", 19200000},
+ {"camss_top_ahb_clk", -1},
+ {"cci_src_clk", 19200000},
+ {"cci_ahb_clk", -1},
+ {"cci_clk", -1},
};
static int32_t msm_cci_init(struct v4l2_subdev *sd)
@@ -411,7 +420,7 @@
rc = msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
cci_dev->cci_clk, ARRAY_SIZE(cci_clk_info), 1);
if (rc < 0) {
- CDBG("%s: regulator enable failed\n", __func__);
+ CDBG("%s: clk enable failed\n", __func__);
goto clk_enable_failed;
}
@@ -421,8 +430,9 @@
cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
msm_camera_io_w(0xFFFFFFFF, cci_dev->base + CCI_RESET_CMD_ADDR);
msm_camera_io_w(0x1, cci_dev->base + CCI_RESET_CMD_ADDR);
- wait_for_completion_interruptible(&cci_dev->cci_master_info[MASTER_0].
- reset_complete);
+ wait_for_completion_interruptible_timeout(
+ &cci_dev->cci_master_info[MASTER_0].reset_complete,
+ CCI_TIMEOUT);
msm_cci_set_clk_param(cci_dev);
msm_camera_io_w(0xFFFFFFFF, cci_dev->base + CCI_IRQ_MASK_0_ADDR);
msm_camera_io_w(0xFFFFFFFF, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
@@ -535,6 +545,12 @@
cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE;
msm_camera_io_w(CCI_M1_RESET_RMSK,
cci_dev->base + CCI_RESET_CMD_ADDR);
+ } else {
+ pr_err("%s unhandled irq 0x%x\n", __func__, irq);
+ cci_dev->cci_master_info[MASTER_0].status = 0;
+ complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
+ cci_dev->cci_master_info[MASTER_1].status = 0;
+ complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
}
return IRQ_HANDLED;
}
@@ -686,11 +702,6 @@
goto cci_release_mem;
}
- CDBG("%s line %d cci irq start %d end %d\n", __func__,
- __LINE__,
- new_cci_dev->irq->start,
- new_cci_dev->irq->end);
-
new_cci_dev->pdev = pdev;
msm_cci_initialize_cci_params(new_cci_dev);
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
index 547eb13..5aaaff7 100644
--- a/drivers/media/video/msm/csi/Makefile
+++ b/drivers/media/video/msm/csi/Makefile
@@ -1,5 +1,5 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
-ccflags-y += -Idrivers/media/video/msm
+ccflags-y += -Idrivers/media/video/msm -Idrivers/media/video/msm/server
ifeq ($(CONFIG_MSM_CSI20_HEADER),y)
ccflags-y += -Idrivers/media/video/msm/csi/include/csi2.0
else ifeq ($(CONFIG_MSM_CSI30_HEADER),y)
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 c79748c..b66bee0 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
@@ -47,5 +47,6 @@
#define CSID_RST_STB_ALL 0x7FFF
#define CSID_DL_INPUT_SEL_SHIFT 0x2
#define CSID_PHY_SEL_SHIFT 0x17
+#define CSID_VERSION 0x02000011
#endif
diff --git a/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h b/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h
index 93d1fc4..2e83101 100644
--- a/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi2.0/msm_csiphy_hwreg.h
@@ -28,6 +28,7 @@
#define MIPI_CSIPHY_LNCK_MISC1_ADDR 0x128
#define MIPI_CSIPHY_GLBL_RESET_ADDR 0x140
#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR 0x144
+#define MIPI_CSIPHY_GLBL_IRQ_CMD_ADDR 0x164
#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR 0x180
#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR 0x1A0
#define MIPI_CSIPHY_INTERRUPT_MASK_VAL 0x6F
@@ -37,5 +38,6 @@
#define MIPI_CSIPHY_MODE_CONFIG_SHIFT 0x4
#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR 0x1E0
#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR 0x1E8
+#define CSIPHY_VERSION 0x0
#endif
diff --git a/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h b/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h
index c678ea2..d37d67e 100644
--- a/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi2.0/msm_ispif_hwreg.h
@@ -64,16 +64,25 @@
#define MISC_LOGIC_RST_STB 1
#define STROBED_RST_EN 0
+#define ISPIF_RST_CMD_MASK 0xFE0F1FFF
+#define ISPIF_RST_CMD_1_MASK 0xFC0F1FF9
+
#define PIX_INTF_0_OVERFLOW_IRQ 12
#define RAW_INTF_0_OVERFLOW_IRQ 25
#define RAW_INTF_1_OVERFLOW_IRQ 25
+#define RAW_INTF_2_OVERFLOW_IRQ 12
#define RESET_DONE_IRQ 27
-#define ISPIF_IRQ_STATUS_MASK 0xA493249
-#define ISPIF_IRQ_1_STATUS_MASK 0xA493249
-#define ISPIF_IRQ_STATUS_RDI_SOF_MASK 0x492000
-#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249
-#define ISPIF_IRQ_STATUS_SOF_MASK 0x492249
+#define ISPIF_IRQ_STATUS_MASK 0x0A493249
+#define ISPIF_IRQ_STATUS_1_MASK 0x02493249
+#define ISPIF_IRQ_STATUS_2_MASK 0x00001249
+
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249
+#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000
+#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000
+#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x249
+
+#define ISPIF_IRQ_STATUS_SOF_MASK 0x492249
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1
#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 27d5a06..ca21238 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
@@ -47,5 +47,6 @@
#define CSID_RST_STB_ALL 0x7FFF
#define CSID_DL_INPUT_SEL_SHIFT 0x4
#define CSID_PHY_SEL_SHIFT 0x17
+#define CSID_VERSION 0x30000000
#endif
diff --git a/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h b/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h
index 79791bd..4e640e3 100644
--- a/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi3.0/msm_csiphy_hwreg.h
@@ -27,15 +27,17 @@
#define MIPI_CSIPHY_LNCK_MISC1_ADDR 0x128
#define MIPI_CSIPHY_GLBL_RESET_ADDR 0x140
#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR 0x144
+#define MIPI_CSIPHY_GLBL_IRQ_CMD_ADDR 0x164
#define MIPI_CSIPHY_HW_VERSION_ADDR 0x188
#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR 0x18C
#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR 0x1AC
#define MIPI_CSIPHY_INTERRUPT_MASK_VAL 0x3F
-#define MIPI_CSIPHY_INTERRUPT_MASK_ADDR 0x1B0
+#define MIPI_CSIPHY_INTERRUPT_MASK_ADDR 0x1AC
#define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR 0x1CC
-#define MIPI_CSIPHY_INTERRUPT_CLEAR_ADDR 0x1D0
+#define MIPI_CSIPHY_INTERRUPT_CLEAR_ADDR 0x1CC
#define MIPI_CSIPHY_MODE_CONFIG_SHIFT 0x4
#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR 0x1EC
#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR 0x1F4
+#define CSIPHY_VERSION 0x10
#endif
diff --git a/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h b/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h
index 4b17538..7c09c4f 100644
--- a/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h
+++ b/drivers/media/video/msm/csi/include/csi3.0/msm_ispif_hwreg.h
@@ -78,17 +78,25 @@
#define MISC_LOGIC_RST_STB 1
#define STROBED_RST_EN 0
+#define ISPIF_RST_CMD_MASK 0xFE0F1FFF
+#define ISPIF_RST_CMD_1_MASK 0xFC0F1FF9
+
#define PIX_INTF_0_OVERFLOW_IRQ 12
#define RAW_INTF_0_OVERFLOW_IRQ 25
#define RAW_INTF_1_OVERFLOW_IRQ 25
+#define RAW_INTF_2_OVERFLOW_IRQ 12
#define RESET_DONE_IRQ 27
-#define ISPIF_IRQ_STATUS_MASK 0xA493249
-#define ISPIF_IRQ_1_STATUS_MASK 0xA493249
-#define ISPIF_IRQ_STATUS_RDI_SOF_MASK 0x492000
-#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249
-#define ISPIF_IRQ_STATUS_SOF_MASK 0x492249
-#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1
+#define ISPIF_IRQ_STATUS_MASK 0x0A493249
+#define ISPIF_IRQ_STATUS_1_MASK 0x02493249
+#define ISPIF_IRQ_STATUS_2_MASK 0x00001249
+#define ISPIF_IRQ_STATUS_PIX_SOF_MASK 0x249
+#define ISPIF_IRQ_STATUS_RDI0_SOF_MASK 0x492000
+#define ISPIF_IRQ_STATUS_RDI1_SOF_MASK 0x492000
+#define ISPIF_IRQ_STATUS_RDI2_SOF_MASK 0x249
+
+#define ISPIF_IRQ_STATUS_SOF_MASK 0x492249
+#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1
#endif
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index bcb7bb3..c34d9f7 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -137,18 +137,17 @@
#define MIPI_PWR_CNTL_EN 0x07
#define MIPI_PWR_CNTL_DIS 0x0
-static int msm_csic_config(struct csic_cfg_params *cfg_params)
+static int msm_csic_config(struct v4l2_subdev *sd,
+ struct msm_camera_csi_params *csic_params)
{
int rc = 0;
uint32_t val = 0;
struct csic_device *csic_dev;
- struct msm_camera_csi_params *csic_params;
void __iomem *csicbase;
int i;
- csic_dev = v4l2_get_subdevdata(cfg_params->subdev);
+ csic_dev = v4l2_get_subdevdata(sd);
csicbase = csic_dev->base;
- csic_params = cfg_params->parms;
/* Enable error correction for DATA lane. Applies to all data lanes */
msm_camera_io_w(0x4, csicbase + MIPI_PHY_CONTROL);
@@ -259,7 +258,7 @@
{"csi_pclk", -1},
};
-static int msm_csic_init(struct v4l2_subdev *sd, uint32_t *csic_version)
+static int msm_csic_init(struct v4l2_subdev *sd)
{
int rc = 0;
struct csic_device *csic_dev;
@@ -355,17 +354,40 @@
return 0;
}
+static long msm_csic_cmd(struct v4l2_subdev *sd, void *arg)
+{
+ long rc = 0;
+ struct csic_cfg_data cdata;
+ struct msm_camera_csi_params csic_params;
+ if (copy_from_user(&cdata,
+ (void *)arg,
+ sizeof(struct csic_cfg_data)))
+ return -EFAULT;
+ CDBG("%s cfgtype = %d\n", __func__, cdata.cfgtype);
+ switch (cdata.cfgtype) {
+ case CSIC_INIT:
+ rc = msm_csic_init(sd);
+ break;
+ case CSIC_CFG:
+ if (copy_from_user(&csic_params,
+ (void *)cdata.csic_params,
+ sizeof(struct msm_camera_csi_params)))
+ return -EFAULT;
+ rc = msm_csic_config(sd, &csic_params);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
static long msm_csic_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
- struct csic_cfg_params cfg_params;
switch (cmd) {
case VIDIOC_MSM_CSIC_CFG:
- cfg_params.subdev = sd;
- cfg_params.parms = arg;
- return msm_csic_config((struct csic_cfg_params *)&cfg_params);
- case VIDIOC_MSM_CSIC_INIT:
- return msm_csic_init(sd, (uint32_t *)arg);
+ return msm_csic_cmd(sd, arg);
case VIDIOC_MSM_CSIC_RELEASE:
return msm_csic_release(sd);
default:
diff --git a/drivers/media/video/msm/csi/msm_csic.h b/drivers/media/video/msm/csi/msm_csic.h
index 177e9d1..c8f1f99 100644
--- a/drivers/media/video/msm/csi/msm_csic.h
+++ b/drivers/media/video/msm/csi/msm_csic.h
@@ -33,19 +33,10 @@
struct clk *csic_clk[5];
};
-struct csic_cfg_params {
- struct v4l2_subdev *subdev;
- void *parms;
-};
-
#define VIDIOC_MSM_CSIC_CFG \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csic_cfg_params)
-
-#define VIDIOC_MSM_CSIC_INIT \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csic_cfg_data*)
#define VIDIOC_MSM_CSIC_RELEASE \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_subdev*)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
#endif
-
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index 6ee87b7..7996ed1 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -11,8 +11,6 @@
*/
#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <mach/board.h>
@@ -21,11 +19,17 @@
#include "msm_csid.h"
#include "msm_csid_hwreg.h"
#include "msm.h"
+#include "msm_cam_server.h"
#define V4L2_IDENT_CSID 50002
+#define CSID_VERSION_V2 0x02000011
+#define CSID_VERSION_V3 0x30000000
#define DBG_CSID 0
+#define TRUE 1
+#define FALSE 0
+
static int msm_csid_cid_lut(
struct msm_camera_csid_lut_params *csid_lut_params,
void __iomem *csidbase)
@@ -33,7 +37,17 @@
int rc = 0, i = 0;
uint32_t val = 0;
+ if (!csid_lut_params) {
+ pr_err("%s:%d csid_lut_params NULL\n", __func__, __LINE__);
+ return -EINVAL;
+ }
for (i = 0; i < csid_lut_params->num_cid && i < 16; i++) {
+ CDBG("%s lut params num_cid = %d, cid = %d, dt = %x, df = %d\n",
+ __func__,
+ csid_lut_params->num_cid,
+ csid_lut_params->vc_cfg[i].cid,
+ csid_lut_params->vc_cfg[i].dt,
+ csid_lut_params->vc_cfg[i].decode_format);
if (csid_lut_params->vc_cfg[i].dt < 0x12 ||
csid_lut_params->vc_cfg[i].dt > 0x37) {
CDBG("%s: unsupported data type 0x%x\n",
@@ -68,19 +82,23 @@
struct msm_camera_csid_params *csid_params) {}
#endif
-static int msm_csid_config(struct csid_cfg_params *cfg_params)
+static int msm_csid_config(struct csid_device *csid_dev,
+ struct msm_camera_csid_params *csid_params)
{
int rc = 0;
uint32_t val = 0;
- struct csid_device *csid_dev;
- struct msm_camera_csid_params *csid_params;
void __iomem *csidbase;
- csid_dev = v4l2_get_subdevdata(cfg_params->subdev);
csidbase = csid_dev->base;
- if (csidbase == NULL)
- return -ENOMEM;
- csid_params = cfg_params->parms;
+ if (!csidbase || !csid_params) {
+ pr_err("%s:%d csidbase %p, csid params %p\n", __func__,
+ __LINE__, csidbase, csid_params);
+ return -EINVAL;
+ }
+ CDBG("%s csid_params, lane_cnt = %d, lane_assign = %x\n",
+ __func__,
+ csid_params->lane_cnt,
+ csid_params->lane_assign);
val = csid_params->lane_cnt - 1;
val |= csid_params->lane_assign << CSID_DL_INPUT_SEL_SHIFT;
if (csid_dev->hw_version < 0x30000000) {
@@ -98,7 +116,6 @@
return rc;
msm_csid_set_debug_reg(csidbase, csid_params);
-
return rc;
}
@@ -106,6 +123,10 @@
{
uint32_t irq;
struct csid_device *csid_dev = data;
+ if (!csid_dev) {
+ pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__);
+ return IRQ_HANDLED;
+ }
irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
CDBG("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
__func__, csid_dev->pdev->id, irq);
@@ -115,6 +136,16 @@
return IRQ_HANDLED;
}
+int msm_csid_irq_routine(struct v4l2_subdev *sd, u32 status, bool *handled)
+{
+ struct csid_device *csid_dev = v4l2_get_subdevdata(sd);
+ irqreturn_t ret;
+ CDBG("%s E\n", __func__);
+ ret = msm_csid_irq(csid_dev->irq->start, csid_dev);
+ *handled = TRUE;
+ return 0;
+}
+
static void msm_csid_reset(struct csid_device *csid_dev)
{
msm_camera_io_w(CSID_RST_STB_ALL, csid_dev->base + CSID_RST_CMD_ADDR);
@@ -131,53 +162,95 @@
return 0;
}
-static struct msm_cam_clk_info csid_clk_info[] = {
+static struct msm_cam_clk_info csid_8960_clk_info[] = {
{"csi_src_clk", 177780000},
{"csi_clk", -1},
{"csi_phy_clk", -1},
{"csi_pclk", -1},
};
-static struct camera_vreg_t csid_vreg_info[] = {
+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 camera_vreg_t csid_8960_vreg_info[] = {
{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
};
-static int msm_csid_init(struct v4l2_subdev *sd, uint32_t *csid_version)
+static struct camera_vreg_t csid_8974_vreg_info[] = {
+ {"mipi_csi_vdd", REG_LDO, 1800000, 1800000, 12000},
+};
+
+static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version)
{
int rc = 0;
- struct csid_device *csid_dev;
- csid_dev = v4l2_get_subdevdata(sd);
- if (csid_dev == NULL) {
- rc = -ENOMEM;
+
+ if (!csid_version) {
+ pr_err("%s:%d csid_version NULL\n", __func__, __LINE__);
+ rc = -EINVAL;
return rc;
}
-
csid_dev->base = ioremap(csid_dev->mem->start,
resource_size(csid_dev->mem));
if (!csid_dev->base) {
+ pr_err("%s csid_dev->base NULL\n", __func__);
rc = -ENOMEM;
return rc;
}
- rc = msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
- ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1);
- if (rc < 0) {
- pr_err("%s: regulator on failed\n", __func__);
- goto vreg_config_failed;
- }
+ if (CSID_VERSION <= CSID_VERSION_V2) {
+ rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
+ csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 1);
+ if (rc < 0) {
+ pr_err("%s: regulator on failed\n", __func__);
+ goto vreg_config_failed;
+ }
- rc = msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
- ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 1);
- if (rc < 0) {
- pr_err("%s: regulator enable failed\n", __func__);
- goto vreg_enable_failed;
- }
+ rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
+ csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 1);
+ if (rc < 0) {
+ pr_err("%s: regulator enable failed\n", __func__);
+ goto vreg_enable_failed;
+ }
- rc = msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
- csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 1);
- if (rc < 0) {
- pr_err("%s: regulator enable failed\n", __func__);
- goto clk_enable_failed;
+ rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
+ 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__);
+ goto clk_enable_failed;
+ }
+ } else if (CSID_VERSION == CSID_VERSION_V3) {
+ rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
+ csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 1);
+ if (rc < 0) {
+ pr_err("%s: regulator on failed\n", __func__);
+ goto vreg_config_failed;
+ }
+
+ rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
+ csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 1);
+ if (rc < 0) {
+ pr_err("%s: regulator enable failed\n", __func__);
+ goto vreg_enable_failed;
+ }
+
+ rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
+ csid_8974_clk_info, csid_dev->csid_clk,
+ ARRAY_SIZE(csid_8974_clk_info), 1);
+ if (rc < 0) {
+ pr_err("%s: regulator enable failed\n", __func__);
+ goto clk_enable_failed;
+ }
}
csid_dev->hw_version =
@@ -186,68 +259,155 @@
init_completion(&csid_dev->reset_complete);
- rc = request_irq(csid_dev->irq->start, msm_csid_irq,
- IRQF_TRIGGER_RISING, "csid", csid_dev);
+ enable_irq(csid_dev->irq->start);
msm_csid_reset(csid_dev);
return rc;
clk_enable_failed:
- msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
- ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+ if (CSID_VERSION <= CSID_VERSION_V2) {
+ msm_camera_enable_vreg(&csid_dev->pdev->dev,
+ csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 0);
+ } else if (CSID_VERSION == CSID_VERSION_V3) {
+ msm_camera_enable_vreg(&csid_dev->pdev->dev,
+ csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 0);
+ }
vreg_enable_failed:
- msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
- ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+ if (CSID_VERSION <= CSID_VERSION_V2) {
+ msm_camera_config_vreg(&csid_dev->pdev->dev,
+ csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 0);
+ } else if (CSID_VERSION == CSID_VERSION_V3) {
+ msm_camera_config_vreg(&csid_dev->pdev->dev,
+ csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 0);
+ }
vreg_config_failed:
iounmap(csid_dev->base);
csid_dev->base = NULL;
return rc;
}
-static int msm_csid_release(struct v4l2_subdev *sd)
+static int msm_csid_release(struct csid_device *csid_dev)
{
uint32_t irq;
- struct csid_device *csid_dev;
- csid_dev = v4l2_get_subdevdata(sd);
irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
msm_camera_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
msm_camera_io_w(0, csid_dev->base + CSID_IRQ_MASK_ADDR);
- free_irq(csid_dev->irq->start, csid_dev);
+ disable_irq(csid_dev->irq->start);
- msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
- csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0);
+ if (csid_dev->hw_version <= CSID_VERSION_V2) {
+ msm_cam_clk_enable(&csid_dev->pdev->dev, csid_8960_clk_info,
+ csid_dev->csid_clk, ARRAY_SIZE(csid_8960_clk_info), 0);
- msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
- ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+ msm_camera_enable_vreg(&csid_dev->pdev->dev,
+ csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 0);
- msm_camera_config_vreg(&csid_dev->pdev->dev, csid_vreg_info,
- ARRAY_SIZE(csid_vreg_info), &csid_dev->csi_vdd, 0);
+ msm_camera_config_vreg(&csid_dev->pdev->dev,
+ 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);
+
+ msm_camera_enable_vreg(&csid_dev->pdev->dev,
+ csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 0);
+
+ msm_camera_config_vreg(&csid_dev->pdev->dev,
+ csid_8974_vreg_info, ARRAY_SIZE(csid_8974_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 0);
+ }
iounmap(csid_dev->base);
csid_dev->base = NULL;
return 0;
}
+static long msm_csid_cmd(struct csid_device *csid_dev, void *arg)
+{
+ int rc = 0;
+ struct csid_cfg_data cdata;
+
+ if (!csid_dev) {
+ pr_err("%s:%d csid_dev NULL\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&cdata,
+ (void *)arg,
+ sizeof(struct csid_cfg_data))) {
+ pr_err("%s: %d failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ CDBG("%s cfgtype = %d\n", __func__, cdata.cfgtype);
+ switch (cdata.cfgtype) {
+ case CSID_INIT:
+ rc = msm_csid_init(csid_dev, &cdata.cfg.csid_version);
+ if (copy_to_user((void *)arg,
+ &cdata,
+ sizeof(struct csid_cfg_data))) {
+ pr_err("%s: %d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ }
+ break;
+ case CSID_CFG: {
+ struct msm_camera_csid_params csid_params;
+ struct msm_camera_csid_vc_cfg *vc_cfg = NULL;
+ if (copy_from_user(&csid_params,
+ (void *)cdata.cfg.csid_params,
+ sizeof(struct msm_camera_csid_params))) {
+ pr_err("%s: %d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ vc_cfg = kzalloc(csid_params.lut_params.num_cid *
+ sizeof(struct msm_camera_csid_vc_cfg),
+ GFP_KERNEL);
+ if (!vc_cfg) {
+ pr_err("%s: %d failed\n", __func__, __LINE__);
+ rc = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(vc_cfg,
+ (void *)csid_params.lut_params.vc_cfg,
+ (csid_params.lut_params.num_cid *
+ sizeof(struct msm_camera_csid_vc_cfg)))) {
+ pr_err("%s: %d failed\n", __func__, __LINE__);
+ kfree(vc_cfg);
+ rc = -EFAULT;
+ break;
+ }
+ csid_params.lut_params.vc_cfg = vc_cfg;
+ rc = msm_csid_config(csid_dev, &csid_params);
+ kfree(vc_cfg);
+ break;
+ }
+ default:
+ pr_err("%s: %d failed\n", __func__, __LINE__);
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+ return rc;
+}
+
static long msm_csid_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
int rc = -ENOIOCTLCMD;
- struct csid_cfg_params cfg_params;
struct csid_device *csid_dev = v4l2_get_subdevdata(sd);
mutex_lock(&csid_dev->mutex);
switch (cmd) {
case VIDIOC_MSM_CSID_CFG:
- cfg_params.subdev = sd;
- cfg_params.parms = arg;
- rc = msm_csid_config((struct csid_cfg_params *)&cfg_params);
- break;
- case VIDIOC_MSM_CSID_INIT:
- rc = msm_csid_init(sd, (uint32_t *)arg);
+ rc = msm_csid_cmd(csid_dev, arg);
break;
case VIDIOC_MSM_CSID_RELEASE:
- rc = msm_csid_release(sd);
+ rc = msm_csid_release(csid_dev);
break;
default:
pr_err("%s: command not found\n", __func__);
@@ -261,6 +421,7 @@
static struct v4l2_subdev_core_ops msm_csid_subdev_core_ops = {
.g_chip_ident = &msm_csid_subdev_g_chip_ident,
.ioctl = &msm_csid_subdev_ioctl,
+ .interrupt_service_routine = msm_csid_irq_routine,
};
static const struct v4l2_subdev_ops msm_csid_subdev_ops = {
@@ -271,9 +432,10 @@
{
struct csid_device *new_csid_dev;
struct msm_cam_subdev_info sd_info;
+ struct intr_table_entry irq_req;
int rc = 0;
- CDBG("%s: device id = %d\n", __func__, pdev->id);
+ CDBG("%s:%d called\n", __func__, __LINE__);
new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL);
if (!new_csid_dev) {
pr_err("%s: no enough memory\n", __func__);
@@ -293,6 +455,7 @@
of_property_read_u32((&pdev->dev)->of_node,
"cell-index", &pdev->id);
+ CDBG("%s device id %d\n", __func__, pdev->id);
new_csid_dev->mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "csid");
if (!new_csid_dev->mem) {
@@ -327,6 +490,44 @@
new_csid_dev->subdev.entity.name = pdev->name;
new_csid_dev->subdev.entity.revision =
new_csid_dev->subdev.devnode->num;
+
+ /* Request for this device irq from the camera server. If the
+ * IRQ Router is present on this target, the interrupt will be
+ * handled by the camera server and the interrupt service
+ * routine called. If the request_irq call returns ENXIO, then
+ * the IRQ Router hardware is not present on this target. We
+ * have to request for the irq ourselves and register the
+ * appropriate interrupt handler. */
+ irq_req.cam_hw_idx = MSM_CAM_HW_CSI0 + pdev->id;
+ irq_req.dev_name = "csid";
+ irq_req.irq_idx = CAMERA_SS_IRQ_2 + pdev->id;
+ irq_req.irq_num = new_csid_dev->irq->start;
+ irq_req.is_composite = 0;
+ irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+ irq_req.num_hwcore = 1;
+ irq_req.subdev_list[0] = &new_csid_dev->subdev;
+ irq_req.data = (void *)new_csid_dev;
+ rc = msm_cam_server_request_irq(&irq_req);
+ if (rc == -ENXIO) {
+ /* IRQ Router hardware is not present on this hardware.
+ * Request for the IRQ and register the interrupt handler. */
+ rc = request_irq(new_csid_dev->irq->start, msm_csid_irq,
+ IRQF_TRIGGER_RISING, "csid", new_csid_dev);
+ if (rc < 0) {
+ release_mem_region(new_csid_dev->mem->start,
+ resource_size(new_csid_dev->mem));
+ pr_err("%s: irq request fail\n", __func__);
+ rc = -EBUSY;
+ goto csid_no_resource;
+ }
+ disable_irq(new_csid_dev->irq->start);
+ } else if (rc < 0) {
+ release_mem_region(new_csid_dev->mem->start,
+ resource_size(new_csid_dev->mem));
+ pr_err("%s Error registering irq ", __func__);
+ goto csid_no_resource;
+ }
+
return 0;
csid_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csid.h b/drivers/media/video/msm/csi/msm_csid.h
index 2eae49c..398acbc 100644
--- a/drivers/media/video/msm/csi/msm_csid.h
+++ b/drivers/media/video/msm/csi/msm_csid.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <media/v4l2-subdev.h>
+#include <media/msm_camera.h>
struct csid_device {
struct platform_device *pdev;
@@ -32,19 +33,10 @@
struct clk *csid_clk[5];
};
-struct csid_cfg_params {
- struct v4l2_subdev *subdev;
- void *parms;
-};
-
#define VIDIOC_MSM_CSID_CFG \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csid_cfg_params)
-
-#define VIDIOC_MSM_CSID_INIT \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csic_cfg_data*)
#define VIDIOC_MSM_CSID_RELEASE \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_subdev*)
-
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
#endif
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index bec7ae3..3113295 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -16,7 +16,6 @@
#include <linux/of.h>
#include <linux/module.h>
#include <mach/board.h>
-#include <mach/camera.h>
#include <mach/vreg.h>
#include <media/msm_isp.h>
#include "msm_csiphy.h"
@@ -27,31 +26,35 @@
#define V4L2_IDENT_CSIPHY 50003
#define CSIPHY_VERSION_V3 0x10
-int msm_csiphy_config(struct csiphy_cfg_params *cfg_params)
+int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev,
+ struct msm_camera_csiphy_params *csiphy_params)
{
int rc = 0;
int j = 0;
uint32_t val = 0;
uint8_t lane_cnt = 0;
uint16_t lane_mask = 0;
- struct csiphy_device *csiphy_dev;
- struct msm_camera_csiphy_params *csiphy_params;
void __iomem *csiphybase;
- csiphy_dev = v4l2_get_subdevdata(cfg_params->subdev);
csiphybase = csiphy_dev->base;
- if (csiphybase == NULL)
- return -ENOMEM;
+ if (!csiphybase) {
+ pr_err("%s: csiphybase NULL\n", __func__);
+ return -EINVAL;
+ }
- csiphy_params = cfg_params->parms;
csiphy_dev->lane_mask[csiphy_dev->pdev->id] |= csiphy_params->lane_mask;
lane_mask = csiphy_dev->lane_mask[csiphy_dev->pdev->id];
lane_cnt = csiphy_params->lane_cnt;
if (csiphy_params->lane_cnt < 1 || csiphy_params->lane_cnt > 4) {
- CDBG("%s: unsupported lane cnt %d\n",
+ pr_err("%s: unsupported lane cnt %d\n",
__func__, csiphy_params->lane_cnt);
return rc;
}
+ CDBG("%s csiphy_params, mask = %x, cnt = %d, settle cnt = %x\n",
+ __func__,
+ csiphy_params->lane_mask,
+ csiphy_params->lane_cnt,
+ csiphy_params->settle_cnt);
msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR);
msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
@@ -75,6 +78,7 @@
csiphybase + MIPI_CSIPHY_GLBL_RESET_ADDR);
}
+ lane_mask &= 0x1f;
while (lane_mask & 0x1f) {
if (!(lane_mask & 0x1)) {
j++;
@@ -92,7 +96,7 @@
j++;
lane_mask >>= 1;
}
-
+ msleep(20);
return rc;
}
@@ -102,18 +106,23 @@
int i;
struct csiphy_device *csiphy_dev = data;
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < 8; i++) {
irq = msm_camera_io_r(
csiphy_dev->base +
MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR + 0x4*i);
msm_camera_io_w(irq,
csiphy_dev->base +
MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR + 0x4*i);
- CDBG("%s MIPI_CSIPHY%d_INTERRUPT_STATUS%d = 0x%x\n",
+ pr_err("%s MIPI_CSIPHY%d_INTERRUPT_STATUS%d = 0x%x\n",
__func__, csiphy_dev->pdev->id, i, irq);
+ msm_camera_io_w(0x1, csiphy_dev->base +
+ MIPI_CSIPHY_GLBL_IRQ_CMD_ADDR);
+ msm_camera_io_w(0x0, csiphy_dev->base +
+ MIPI_CSIPHY_GLBL_IRQ_CMD_ADDR);
+ msm_camera_io_w(0x0,
+ csiphy_dev->base +
+ MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR + 0x4*i);
}
- msm_camera_io_w(0x1, csiphy_dev->base + 0x164);
- msm_camera_io_w(0x0, csiphy_dev->base + 0x164);
return IRQ_HANDLED;
}
@@ -133,17 +142,22 @@
return 0;
}
-static struct msm_cam_clk_info csiphy_clk_info[] = {
+static struct msm_cam_clk_info csiphy_8960_clk_info[] = {
{"csiphy_timer_src_clk", 177780000},
{"csiphy_timer_clk", -1},
};
-static int msm_csiphy_init(struct v4l2_subdev *sd)
+static struct msm_cam_clk_info csiphy_8974_clk_info[] = {
+ {"ispif_ahb_clk", -1},
+ {"csiphy_timer_src_clk", 200000000},
+ {"csiphy_timer_clk", -1},
+};
+
+static int msm_csiphy_init(struct csiphy_device *csiphy_dev)
{
int rc = 0;
- struct csiphy_device *csiphy_dev;
- csiphy_dev = v4l2_get_subdevdata(sd);
if (csiphy_dev == NULL) {
+ pr_err("%s: csiphy_dev NULL\n", __func__);
rc = -ENOMEM;
return rc;
}
@@ -157,15 +171,23 @@
csiphy_dev->base = ioremap(csiphy_dev->mem->start,
resource_size(csiphy_dev->mem));
if (!csiphy_dev->base) {
+ pr_err("%s: csiphy_dev->base NULL\n", __func__);
csiphy_dev->ref_count--;
rc = -ENOMEM;
return rc;
}
- rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev, csiphy_clk_info,
- csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 1);
+ if (CSIPHY_VERSION != CSIPHY_VERSION_V3)
+ rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+ csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
+ ARRAY_SIZE(csiphy_8960_clk_info), 1);
+ else
+ rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+ csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
+ ARRAY_SIZE(csiphy_8974_clk_info), 1);
if (rc < 0) {
+ pr_err("%s: csiphy clk enable failed\n", __func__);
csiphy_dev->ref_count--;
iounmap(csiphy_dev->base);
csiphy_dev->base = NULL;
@@ -183,13 +205,11 @@
return 0;
}
-static int msm_csiphy_release(struct v4l2_subdev *sd, void *arg)
+static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg)
{
- struct csiphy_device *csiphy_dev;
int i = 0;
struct msm_camera_csi_lane_params *csi_lane_params;
uint16_t csi_lane_mask;
- csiphy_dev = v4l2_get_subdevdata(sd);
csi_lane_params = (struct msm_camera_csi_lane_params *)arg;
csi_lane_mask = csi_lane_params->csi_lane_mask;
@@ -197,6 +217,10 @@
pr_err("%s csiphy dev NULL / ref_count ZERO\n", __func__);
return 0;
}
+ CDBG("%s csiphy_params, lane assign %x mask = %x\n",
+ __func__,
+ csi_lane_params->csi_lane_assign,
+ csi_lane_params->csi_lane_mask);
if (csiphy_dev->hw_version != CSIPHY_VERSION_V3) {
csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
@@ -229,33 +253,69 @@
#if DBG_CSIPHY
disable_irq(csiphy_dev->irq->start);
#endif
- msm_cam_clk_enable(&csiphy_dev->pdev->dev, csiphy_clk_info,
- csiphy_dev->csiphy_clk, ARRAY_SIZE(csiphy_clk_info), 0);
+ if (CSIPHY_VERSION != CSIPHY_VERSION_V3)
+ msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+ csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
+ ARRAY_SIZE(csiphy_8960_clk_info), 0);
+ else
+ msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+ csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
+ ARRAY_SIZE(csiphy_8974_clk_info), 0);
iounmap(csiphy_dev->base);
csiphy_dev->base = NULL;
return 0;
}
+static long msm_csiphy_cmd(struct csiphy_device *csiphy_dev, void *arg)
+{
+ int rc = 0;
+ struct csiphy_cfg_data cdata;
+ struct msm_camera_csiphy_params csiphy_params;
+ if (!csiphy_dev) {
+ pr_err("%s: csiphy_dev NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (copy_from_user(&cdata,
+ (void *)arg,
+ sizeof(struct csiphy_cfg_data))) {
+ pr_err("%s: %d failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ switch (cdata.cfgtype) {
+ case CSIPHY_INIT:
+ rc = msm_csiphy_init(csiphy_dev);
+ break;
+ case CSIPHY_CFG:
+ if (copy_from_user(&csiphy_params,
+ (void *)cdata.csiphy_params,
+ sizeof(struct msm_camera_csiphy_params))) {
+ pr_err("%s: %d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = msm_csiphy_lane_config(csiphy_dev, &csiphy_params);
+ break;
+ default:
+ pr_err("%s: %d failed\n", __func__, __LINE__);
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+ return rc;
+}
+
static long msm_csiphy_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
int rc = -ENOIOCTLCMD;
- struct csiphy_cfg_params cfg_params;
struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd);
mutex_lock(&csiphy_dev->mutex);
switch (cmd) {
case VIDIOC_MSM_CSIPHY_CFG:
- cfg_params.subdev = sd;
- cfg_params.parms = arg;
- rc = msm_csiphy_config(
- (struct csiphy_cfg_params *)&cfg_params);
- break;
- case VIDIOC_MSM_CSIPHY_INIT:
- rc = msm_csiphy_init(sd);
+ rc = msm_csiphy_cmd(csiphy_dev, arg);
break;
case VIDIOC_MSM_CSIPHY_RELEASE:
- rc = msm_csiphy_release(sd, arg);
+ rc = msm_csiphy_release(csiphy_dev, arg);
break;
default:
pr_err("%s: command not found\n", __func__);
@@ -281,7 +341,6 @@
int rc = 0;
struct msm_cam_subdev_info sd_info;
- CDBG("%s: device id = %d\n", __func__, pdev->id);
new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL);
if (!new_csiphy_dev) {
pr_err("%s: no enough memory\n", __func__);
@@ -301,6 +360,7 @@
if (pdev->dev.of_node)
of_property_read_u32((&pdev->dev)->of_node,
"cell-index", &pdev->id);
+ CDBG("%s: device id = %d\n", __func__, pdev->id);
new_csiphy_dev->mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "csiphy");
diff --git a/drivers/media/video/msm/csi/msm_csiphy.h b/drivers/media/video/msm/csi/msm_csiphy.h
index 1fab9c1..4b2e68e 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.h
+++ b/drivers/media/video/msm/csi/msm_csiphy.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <media/v4l2-subdev.h>
+#include <media/msm_camera.h>
#define MAX_CSIPHY 3
@@ -29,23 +30,14 @@
struct mutex mutex;
uint32_t hw_version;
- struct clk *csiphy_clk[2];
+ struct clk *csiphy_clk[3];
uint8_t ref_count;
uint16_t lane_mask[MAX_CSIPHY];
};
-struct csiphy_cfg_params {
- struct v4l2_subdev *subdev;
- void *parms;
-};
-
#define VIDIOC_MSM_CSIPHY_CFG \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 7, void *)
-
-#define VIDIOC_MSM_CSIPHY_INIT \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct v4l2_subdev*)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct csiphy_cfg_data*)
#define VIDIOC_MSM_CSIPHY_RELEASE \
_IOWR('V', BASE_VIDIOC_PRIVATE + 9, void *)
-
#endif
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index 092ee90..ab97138 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -29,6 +29,7 @@
static atomic_t ispif_irq_cnt;
static spinlock_t ispif_tasklet_lock;
+static spinlock_t ispif_sof_lock;
static struct list_head ispif_tasklet_q;
static int msm_ispif_intf_reset(struct ispif_device *ispif,
@@ -36,7 +37,6 @@
{
int rc = 0;
uint32_t data = (0x1 << STROBED_RST_EN);
- uint32_t data1 = (0x1 << STROBED_RST_EN);
uint16_t intfnum = 0, mask = intfmask;
while (mask != 0) {
@@ -47,49 +47,29 @@
}
switch (intfnum) {
case PIX0:
- if (vfe_intf == VFE0)
- data |= (0x1 << PIX_0_VFE_RST_STB) |
- (0x1 << PIX_0_CSID_RST_STB);
- else
- data1 |= (0x1 << PIX_0_VFE_RST_STB) |
- (0x1 << PIX_0_CSID_RST_STB);
+ data |= (0x1 << PIX_0_VFE_RST_STB) |
+ (0x1 << PIX_0_CSID_RST_STB);
ispif->pix_sof_count = 0;
break;
case RDI0:
- if (vfe_intf == VFE0)
- data |= (0x1 << RDI_0_VFE_RST_STB) |
- (0x1 << RDI_0_CSID_RST_STB);
- else
- data1 |= (0x1 << RDI_0_VFE_RST_STB) |
- (0x1 << RDI_0_CSID_RST_STB);
+ data |= (0x1 << RDI_0_VFE_RST_STB) |
+ (0x1 << RDI_0_CSID_RST_STB);
break;
case PIX1:
- if (vfe_intf == VFE0)
- data |= (0x1 << PIX_1_VFE_RST_STB) |
- (0x1 << PIX_1_CSID_RST_STB);
- else
- data1 |= (0x1 << PIX_1_VFE_RST_STB) |
- (0x1 << PIX_1_CSID_RST_STB);
+ data |= (0x1 << PIX_1_VFE_RST_STB) |
+ (0x1 << PIX_1_CSID_RST_STB);
break;
case RDI1:
- if (vfe_intf == VFE0)
- data |= (0x1 << RDI_1_VFE_RST_STB) |
- (0x1 << RDI_1_CSID_RST_STB);
- else
- data1 |= (0x1 << RDI_1_VFE_RST_STB) |
- (0x1 << RDI_1_CSID_RST_STB);
+ data |= (0x1 << RDI_1_VFE_RST_STB) |
+ (0x1 << RDI_1_CSID_RST_STB);
break;
case RDI2:
- if (vfe_intf == VFE0)
- data |= (0x1 << RDI_2_VFE_RST_STB) |
- (0x1 << RDI_2_CSID_RST_STB);
- else
- data1 |= (0x1 << RDI_2_VFE_RST_STB) |
- (0x1 << RDI_2_CSID_RST_STB);
+ data |= (0x1 << RDI_2_VFE_RST_STB) |
+ (0x1 << RDI_2_CSID_RST_STB);
break;
default:
@@ -99,43 +79,26 @@
mask >>= 1;
intfnum++;
} /*end while */
- msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
- rc = wait_for_completion_interruptible(&ispif->reset_complete);
- if (ispif->csid_version >= CSID_VERSION_V3 && data1 > 0x1) {
- msm_camera_io_w(data1,
- ispif->base + ISPIF_RST_CMD_1_ADDR);
- rc = wait_for_completion_interruptible(&ispif->
- reset_complete);
+ if (data > 0x1) {
+ if (vfe_intf == VFE0)
+ msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
+ else
+ msm_camera_io_w(data, ispif->base +
+ ISPIF_RST_CMD_1_ADDR);
+ rc = wait_for_completion_interruptible(&ispif->reset_complete);
}
-
return rc;
}
static int msm_ispif_reset(struct ispif_device *ispif)
{
int rc = 0;
- uint32_t data = (0x1 << STROBED_RST_EN) |
- (0x1 << SW_REG_RST_STB) |
- (0x1 << MISC_LOGIC_RST_STB) |
- (0x1 << PIX_0_VFE_RST_STB) |
- (0x1 << PIX_0_CSID_RST_STB) |
- (0x1 << RDI_0_VFE_RST_STB) |
- (0x1 << RDI_0_CSID_RST_STB) |
- (0x1 << RDI_1_VFE_RST_STB) |
- (0x1 << RDI_1_CSID_RST_STB);
-
- if (ispif->csid_version >= CSID_VERSION_V2)
- data |= (0x1 << PIX_1_VFE_RST_STB) |
- (0x1 << PIX_1_CSID_RST_STB) |
- (0x1 << RDI_2_VFE_RST_STB) |
- (0x1 << RDI_2_CSID_RST_STB);
ispif->pix_sof_count = 0;
- msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_ADDR);
+ msm_camera_io_w(ISPIF_RST_CMD_MASK, ispif->base + ISPIF_RST_CMD_ADDR);
+ if (ispif->csid_version == CSID_VERSION_V3)
+ msm_camera_io_w(ISPIF_RST_CMD_1_MASK, ispif->base +
+ ISPIF_RST_CMD_1_ADDR);
rc = wait_for_completion_interruptible(&ispif->reset_complete);
- if (ispif->csid_version >= CSID_VERSION_V3) {
- msm_camera_io_w(data, ispif->base + ISPIF_RST_CMD_1_ADDR);
- rc = wait_for_completion_interruptible(&ispif->reset_complete);
- }
return rc;
}
@@ -154,35 +117,40 @@
int rc = 0;
uint32_t data;
- if (ispif->ispif_clk[intftype] == NULL) {
- pr_err("%s: ispif NULL clk\n", __func__);
- return;
+ if (ispif->csid_version <= CSID_VERSION_V2) {
+ if (ispif->ispif_clk[intftype] == NULL) {
+ pr_err("%s: ispif NULL clk\n", __func__);
+ return;
+ }
+ rc = clk_set_rate(ispif->ispif_clk[intftype], csid);
+ if (rc < 0)
+ pr_err("%s: clk_set_rate failed %d\n", __func__, rc);
}
-
- rc = clk_set_rate(ispif->ispif_clk[intftype], csid);
- if (rc < 0)
- pr_err("%s: clk_set_rate failed %d\n", __func__, rc);
-
data = msm_camera_io_r(ispif->base + ISPIF_INPUT_SEL_ADDR +
(0x200 * vfe_intf));
switch (intftype) {
case PIX0:
+ data &= ~(0x3);
data |= csid;
break;
case RDI0:
+ data &= ~(0x3 << 4);
data |= (csid << 4);
break;
case PIX1:
+ data &= ~(0x3 << 8);
data |= (csid << 8);
break;
case RDI1:
+ data &= ~(0x3 << 12);
data |= (csid << 12);
break;
case RDI2:
+ data &= ~(0x3 << 20);
data |= (csid << 20);
break;
}
@@ -289,6 +257,8 @@
ispif_params = params_list->params;
CDBG("Enable interface\n");
msm_camera_io_w(0x00000000, ispif->base + ISPIF_IRQ_MASK_ADDR);
+ msm_camera_io_w(0x00000000, ispif->base + ISPIF_IRQ_MASK_1_ADDR);
+ msm_camera_io_w(0x00000000, ispif->base + ISPIF_IRQ_MASK_2_ADDR);
for (i = 0; i < params_len; i++) {
intftype = ispif_params[i].intftype;
vfe_intf = ispif_params[i].vfe_intf;
@@ -319,6 +289,14 @@
ISPIF_IRQ_MASK_ADDR);
msm_camera_io_w(ISPIF_IRQ_STATUS_MASK, ispif->base +
ISPIF_IRQ_CLEAR_ADDR);
+ msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
+ ISPIF_IRQ_MASK_1_ADDR);
+ msm_camera_io_w(ISPIF_IRQ_STATUS_1_MASK, ispif->base +
+ ISPIF_IRQ_CLEAR_1_ADDR);
+ msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
+ ISPIF_IRQ_MASK_2_ADDR);
+ msm_camera_io_w(ISPIF_IRQ_STATUS_2_MASK, ispif->base +
+ ISPIF_IRQ_CLEAR_2_ADDR);
msm_camera_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
return rc;
@@ -534,13 +512,24 @@
return rc;
}
+static void send_rdi_sof(struct ispif_device *ispif,
+ enum msm_ispif_intftype interface, int count)
+{
+ struct rdi_count_msg sof_msg;
+ sof_msg.rdi_interface = interface;
+ sof_msg.count = count;
+ v4l2_subdev_notify(&ispif->subdev, NOTIFY_AXI_RDI_SOF_COUNT,
+ (void *)&sof_msg);
+}
+
static void ispif_do_tasklet(unsigned long data)
{
unsigned long flags;
struct ispif_isr_queue_cmd *qcmd = NULL;
- CDBG("=== ispif_do_tasklet start ===\n");
+ struct ispif_device *ispif;
+ ispif = (struct ispif_device *)data;
while (atomic_read(&ispif_irq_cnt)) {
spin_lock_irqsave(&ispif_tasklet_lock, flags);
qcmd = list_first_entry(&ispif_tasklet_q,
@@ -555,28 +544,37 @@
list_del(&qcmd->list);
spin_unlock_irqrestore(&ispif_tasklet_lock,
flags);
+
+ spin_lock_irqsave(&ispif_sof_lock, flags);
if (qcmd->ispifInterruptStatus0 &
- ISPIF_IRQ_STATUS_RDI_SOF_MASK) {
- CDBG("ispif rdi irq status\n");
+ ISPIF_IRQ_STATUS_RDI0_SOF_MASK) {
+ CDBG("%s: ispif RDI0 irq status", __func__);
+ ispif->rdi0_sof_count++;
+ send_rdi_sof(ispif, RDI_0, ispif->rdi0_sof_count);
}
if (qcmd->ispifInterruptStatus1 &
- ISPIF_IRQ_STATUS_RDI_SOF_MASK) {
- CDBG("ispif rdi1 irq status\n");
+ ISPIF_IRQ_STATUS_RDI1_SOF_MASK) {
+ CDBG("%s: ispif RDI1 irq status", __func__);
+ ispif->rdi1_sof_count++;
+ send_rdi_sof(ispif, RDI_1, ispif->rdi1_sof_count);
}
+ if (qcmd->ispifInterruptStatus2 &
+ ISPIF_IRQ_STATUS_RDI2_SOF_MASK) {
+ CDBG("%s: ispif RDI2 irq status", __func__);
+ ispif->rdi2_sof_count++;
+ send_rdi_sof(ispif, RDI_2, ispif->rdi2_sof_count);
+ }
+ spin_unlock_irqrestore(&ispif_sof_lock, flags);
kfree(qcmd);
}
- CDBG("=== ispif_do_tasklet end ===\n");
}
-DECLARE_TASKLET(ispif_tasklet, ispif_do_tasklet, 0);
-
static void ispif_process_irq(struct ispif_device *ispif,
struct ispif_irq_status *out)
{
unsigned long flags;
struct ispif_isr_queue_cmd *qcmd;
- CDBG("ispif_process_irq\n");
qcmd = kzalloc(sizeof(struct ispif_isr_queue_cmd),
GFP_ATOMIC);
if (!qcmd) {
@@ -585,12 +583,14 @@
}
qcmd->ispifInterruptStatus0 = out->ispifIrqStatus0;
qcmd->ispifInterruptStatus1 = out->ispifIrqStatus1;
-
- if (qcmd->ispifInterruptStatus0 & ISPIF_IRQ_STATUS_PIX_SOF_MASK) {
- CDBG("%s: ispif PIX sof irq\n", __func__);
- ispif->pix_sof_count++;
- v4l2_subdev_notify(&ispif->subdev, NOTIFY_VFE_SOF_COUNT,
- (void *)&ispif->pix_sof_count);
+ qcmd->ispifInterruptStatus2 = out->ispifIrqStatus2;
+ if (qcmd->ispifInterruptStatus0 &
+ ISPIF_IRQ_STATUS_PIX_SOF_MASK) {
+ CDBG("%s: ispif PIX irq status", __func__);
+ ispif->pix_sof_count++;
+ v4l2_subdev_notify(&ispif->subdev,
+ NOTIFY_VFE_PIX_SOF_COUNT,
+ (void *)&ispif->pix_sof_count);
}
spin_lock_irqsave(&ispif_tasklet_lock, flags);
@@ -598,25 +598,31 @@
atomic_add(1, &ispif_irq_cnt);
spin_unlock_irqrestore(&ispif_tasklet_lock, flags);
- tasklet_schedule(&ispif_tasklet);
+ tasklet_schedule(&ispif->ispif_tasklet);
return;
}
static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out,
void *data)
{
+ uint32_t status0 = 0, status1 = 0, status2 = 0;
struct ispif_device *ispif = (struct ispif_device *)data;
out->ispifIrqStatus0 = msm_camera_io_r(ispif->base +
ISPIF_IRQ_STATUS_ADDR);
out->ispifIrqStatus1 = msm_camera_io_r(ispif->base +
ISPIF_IRQ_STATUS_1_ADDR);
+ out->ispifIrqStatus2 = msm_camera_io_r(ispif->base +
+ ISPIF_IRQ_STATUS_2_ADDR);
msm_camera_io_w(out->ispifIrqStatus0,
ispif->base + ISPIF_IRQ_CLEAR_ADDR);
msm_camera_io_w(out->ispifIrqStatus1,
ispif->base + ISPIF_IRQ_CLEAR_1_ADDR);
+ msm_camera_io_w(out->ispifIrqStatus2,
+ ispif->base + ISPIF_IRQ_CLEAR_2_ADDR);
- CDBG("%s: irq ispif->irq: Irq_status0 = 0x%x\n", __func__,
- out->ispifIrqStatus0);
+ CDBG("%s: irq vfe0 Irq_status0 = 0x%x, 1 = 0x%x, 2 = 0x%x\n",
+ __func__, out->ispifIrqStatus0, out->ispifIrqStatus1,
+ out->ispifIrqStatus2);
if (out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_MASK) {
if (out->ispifIrqStatus0 & (0x1 << RESET_DONE_IRQ))
complete(&ispif->reset_complete);
@@ -624,11 +630,30 @@
pr_err("%s: pix intf 0 overflow.\n", __func__);
if (out->ispifIrqStatus0 & (0x1 << RAW_INTF_0_OVERFLOW_IRQ))
pr_err("%s: rdi intf 0 overflow.\n", __func__);
+ if (out->ispifIrqStatus1 & (0x1 << RAW_INTF_1_OVERFLOW_IRQ))
+ pr_err("%s: rdi intf 1 overflow.\n", __func__);
+ if (out->ispifIrqStatus2 & (0x1 << RAW_INTF_2_OVERFLOW_IRQ))
+ pr_err("%s: rdi intf 2 overflow.\n", __func__);
if ((out->ispifIrqStatus0 & ISPIF_IRQ_STATUS_SOF_MASK) ||
- (out->ispifIrqStatus1 &
- ISPIF_IRQ_STATUS_SOF_MASK)) {
+ (out->ispifIrqStatus1 & ISPIF_IRQ_STATUS_SOF_MASK) ||
+ (out->ispifIrqStatus2 & ISPIF_IRQ_STATUS_RDI2_SOF_MASK))
ispif_process_irq(ispif, out);
- }
+ }
+ if (ispif->csid_version == CSID_VERSION_V3) {
+ status0 = msm_camera_io_r(ispif->base +
+ ISPIF_IRQ_STATUS_ADDR + 0x200);
+ msm_camera_io_w(status0,
+ ispif->base + ISPIF_IRQ_CLEAR_ADDR + 0x200);
+ status1 = msm_camera_io_r(ispif->base +
+ ISPIF_IRQ_STATUS_1_ADDR + 0x200);
+ msm_camera_io_w(status1,
+ ispif->base + ISPIF_IRQ_CLEAR_1_ADDR + 0x200);
+ status2 = msm_camera_io_r(ispif->base +
+ ISPIF_IRQ_STATUS_2_ADDR + 0x200);
+ msm_camera_io_w(status2,
+ ispif->base + ISPIF_IRQ_CLEAR_2_ADDR + 0x200);
+ CDBG("%s: irq vfe1 Irq_status0 = 0x%x, 1 = 0x%x, 2 = 0x%x\n",
+ __func__, status0, status1, status2);
}
msm_camera_io_w(ISPIF_IRQ_GLOBAL_CLEAR_CMD, ispif->base +
ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
@@ -641,7 +666,7 @@
return IRQ_HANDLED;
}
-static struct msm_cam_clk_info ispif_clk_info[] = {
+static struct msm_cam_clk_info ispif_8960_clk_info[] = {
{"csi_pix_clk", 0},
{"csi_rdi_clk", 0},
{"csi_pix1_clk", 0},
@@ -660,15 +685,18 @@
IRQF_TRIGGER_RISING, "ispif", ispif);
init_completion(&ispif->reset_complete);
+ tasklet_init(&ispif->ispif_tasklet,
+ ispif_do_tasklet, (unsigned long)ispif);
+
ispif->csid_version = *csid_version;
- if (ispif->csid_version >= CSID_VERSION_V2) {
- rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info,
- ispif->ispif_clk, ARRAY_SIZE(ispif_clk_info), 1);
+ if (ispif->csid_version < CSID_VERSION_V2) {
+ rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
+ ispif->ispif_clk, 2, 1);
if (rc < 0)
return rc;
- } else {
- rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info,
- ispif->ispif_clk, 2, 1);
+ } else if (ispif->csid_version == CSID_VERSION_V2) {
+ rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
+ ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 1);
if (rc < 0)
return rc;
}
@@ -679,15 +707,16 @@
static void msm_ispif_release(struct ispif_device *ispif)
{
CDBG("%s, free_irq\n", __func__);
- free_irq(ispif->irq->start, 0);
- tasklet_kill(&ispif_tasklet);
+ free_irq(ispif->irq->start, ispif);
+ tasklet_kill(&ispif->ispif_tasklet);
- if (ispif->csid_version == CSID_VERSION_V2)
- msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info,
- ispif->ispif_clk, ARRAY_SIZE(ispif_clk_info), 0);
- else
- msm_cam_clk_enable(&ispif->pdev->dev, ispif_clk_info,
+ if (ispif->csid_version < CSID_VERSION_V2) {
+ msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
ispif->ispif_clk, 2, 0);
+ } else if (ispif->csid_version == CSID_VERSION_V2) {
+ msm_cam_clk_enable(&ispif->pdev->dev, ispif_8960_clk_info,
+ ispif->ispif_clk, ARRAY_SIZE(ispif_8960_clk_info), 0);
+ }
}
static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
diff --git a/drivers/media/video/msm/csi/msm_ispif.h b/drivers/media/video/msm/csi/msm_ispif.h
index f4ad661..a581a37 100644
--- a/drivers/media/video/msm/csi/msm_ispif.h
+++ b/drivers/media/video/msm/csi/msm_ispif.h
@@ -20,6 +20,7 @@
struct ispif_irq_status {
uint32_t ispifIrqStatus0;
uint32_t ispifIrqStatus1;
+ uint32_t ispifIrqStatus2;
};
struct ispif_device {
@@ -35,12 +36,17 @@
uint32_t csid_version;
struct clk *ispif_clk[5];
uint32_t pix_sof_count;
+ uint32_t rdi0_sof_count;
+ uint32_t rdi1_sof_count;
+ uint32_t rdi2_sof_count;
+ struct tasklet_struct ispif_tasklet;
};
struct ispif_isr_queue_cmd {
struct list_head list;
uint32_t ispifInterruptStatus0;
uint32_t ispifInterruptStatus1;
+ uint32_t ispifInterruptStatus2;
};
#define VIDIOC_MSM_ISPIF_CFG \
diff --git a/drivers/media/video/msm/eeprom/imx074_eeprom.c b/drivers/media/video/msm/eeprom/imx074_eeprom.c
index 21cbafa..a99b17e 100644
--- a/drivers/media/video/msm/eeprom/imx074_eeprom.c
+++ b/drivers/media/video/msm/eeprom/imx074_eeprom.c
@@ -47,14 +47,15 @@
.core = &imx074_eeprom_subdev_core_ops,
};
-uint8_t imx074_wbcalib_data[6];
-struct msm_calib_wb imx074_wb_data;
+static uint8_t imx074_wbcalib_data[6];
+static struct msm_calib_wb imx074_wb_data;
static struct msm_camera_eeprom_info_t imx074_calib_supp_info = {
{FALSE, 0, 0, 1},
{TRUE, 6, 0, 1024},
{FALSE, 0, 0, 1},
{FALSE, 0, 0, 1},
+ {FALSE, 0, 0, 1},
};
static struct msm_camera_eeprom_read_t imx074_eeprom_read_tbl[] = {
diff --git a/drivers/media/video/msm/eeprom/imx091_eeprom.c b/drivers/media/video/msm/eeprom/imx091_eeprom.c
index 68a2361..c53eb20 100644
--- a/drivers/media/video/msm/eeprom/imx091_eeprom.c
+++ b/drivers/media/video/msm/eeprom/imx091_eeprom.c
@@ -47,16 +47,17 @@
.core = &imx091_eeprom_subdev_core_ops,
};
-uint8_t imx091_wbcalib_data[6];
-uint8_t imx091_afcalib_data[6];
-struct msm_calib_wb imx091_wb_data;
-struct msm_calib_af imx091_af_data;
+static uint8_t imx091_wbcalib_data[6];
+static uint8_t imx091_afcalib_data[6];
+static struct msm_calib_wb imx091_wb_data;
+static struct msm_calib_af imx091_af_data;
static struct msm_camera_eeprom_info_t imx091_calib_supp_info = {
{TRUE, 6, 1, 1},
{TRUE, 6, 0, 32768},
{FALSE, 0, 0, 1},
{FALSE, 0, 0, 1},
+ {FALSE, 0, 0, 1},
};
static struct msm_camera_eeprom_read_t imx091_eeprom_read_tbl[] = {
diff --git a/drivers/media/video/msm/eeprom/msm_camera_eeprom.c b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
index 96a6e04..effae8b 100644
--- a/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
+++ b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
@@ -100,7 +100,7 @@
}
rc = e_ctrl->func_tbl.eeprom_get_info(e_ctrl,
&cdata.cfg.get_info);
-
+ cdata.is_eeprom_supported = 1;
if (copy_to_user((void *)argp,
&cdata,
sizeof(struct msm_eeprom_cfg_data)))
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.c b/drivers/media/video/msm/io/msm_camera_i2c.c
index 82bca02..27ebac5 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.c
+++ b/drivers/media/video/msm/io/msm_camera_i2c.c
@@ -84,6 +84,7 @@
cci_ctrl.cci_info = client->cci_client;
cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = ®_conf_tbl;
cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
+ cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
cci_ctrl.cfg.cci_i2c_write_cfg.size = 1;
rc = v4l2_subdev_call(client->cci_client->cci_subdev,
core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
@@ -336,6 +337,39 @@
return rc;
}
+int32_t msm_camera_i2c_write_bayer_table(
+ struct msm_camera_i2c_client *client,
+ struct msm_camera_i2c_reg_setting *write_setting)
+{
+ int i;
+ int32_t rc = -EFAULT;
+ struct msm_camera_i2c_reg_array *reg_setting;
+
+ if (!client || !write_setting)
+ return rc;
+
+ reg_setting = write_setting->reg_setting;
+ client->addr_type = write_setting->addr_type;
+ if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
+ && write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
+ || (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+ && write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
+ return rc;
+ for (i = 0; i < write_setting->size; i++) {
+ rc = msm_camera_i2c_write(client, reg_setting->reg_addr,
+ reg_setting->reg_data, write_setting->data_type);
+ if (rc < 0)
+ break;
+ reg_setting++;
+ }
+ if (write_setting->delay > 20)
+ msleep(write_setting->delay);
+ else if (write_setting->delay)
+ usleep_range(write_setting->delay * 1000, (write_setting->delay
+ * 1000) + 1000);
+ return rc;
+}
+
int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type)
@@ -348,6 +382,7 @@
cci_ctrl.cci_info = client->cci_client;
cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = reg_conf_tbl;
cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
+ cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
cci_ctrl.cfg.cci_i2c_write_cfg.size = size;
rc = v4l2_subdev_call(client->cci_client->cci_subdev,
core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.h b/drivers/media/video/msm/io/msm_camera_i2c.h
index 169a0b3..35b3bd4 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.h
+++ b/drivers/media/video/msm/io/msm_camera_i2c.h
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <mach/camera.h>
#include <media/v4l2-subdev.h>
+#include <media/msm_camera.h>
#define CONFIG_MSM_CAMERA_I2C_DBG 0
@@ -92,6 +93,10 @@
struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type);
+int32_t msm_camera_i2c_write_bayer_table(
+ struct msm_camera_i2c_client *client,
+ struct msm_camera_i2c_reg_setting *write_setting);
+
int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type);
diff --git a/drivers/media/video/msm/io/msm_camera_io_util.c b/drivers/media/video/msm/io/msm_camera_io_util.c
index 4049266..5dfa6a2 100644
--- a/drivers/media/video/msm/io/msm_camera_io_util.c
+++ b/drivers/media/video/msm/io/msm_camera_io_util.c
@@ -20,6 +20,7 @@
#include <mach/gpiomux.h>
#define BUFF_SIZE_128 128
+static int gpio_ref_count;
void msm_camera_io_w(u32 data, void __iomem *addr)
{
@@ -133,6 +134,12 @@
clk_info[i].clk_name);
goto cam_clk_enable_err;
}
+ if (clk_info[i].delay > 20) {
+ msleep(clk_info[i].delay);
+ } else if (clk_info[i].delay) {
+ usleep_range(clk_info[i].delay * 1000,
+ (clk_info[i].delay * 1000) + 1000);
+ }
}
} else {
for (i = num_clk - 1; i >= 0; i--) {
@@ -163,26 +170,41 @@
}
int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
- int num_vreg, struct regulator **reg_ptr, int config)
+ int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+ int num_vreg_seq, struct regulator **reg_ptr, int config)
{
- int i = 0;
+ int i = 0, j = 0;
int rc = 0;
struct camera_vreg_t *curr_vreg;
+
+ if (num_vreg_seq > num_vreg) {
+ pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ if (!num_vreg_seq)
+ num_vreg_seq = num_vreg;
+
if (config) {
- for (i = 0; i < num_vreg; i++) {
- curr_vreg = &cam_vreg[i];
- reg_ptr[i] = regulator_get(dev,
+ for (i = 0; i < num_vreg_seq; i++) {
+ if (vreg_seq) {
+ j = vreg_seq[i];
+ if (j >= num_vreg)
+ continue;
+ } else
+ j = i;
+ curr_vreg = &cam_vreg[j];
+ reg_ptr[j] = regulator_get(dev,
curr_vreg->reg_name);
- if (IS_ERR(reg_ptr[i])) {
+ if (IS_ERR(reg_ptr[j])) {
pr_err("%s: %s get failed\n",
__func__,
curr_vreg->reg_name);
- reg_ptr[i] = NULL;
+ reg_ptr[j] = NULL;
goto vreg_get_fail;
}
if (curr_vreg->type == REG_LDO) {
rc = regulator_set_voltage(
- reg_ptr[i],
+ reg_ptr[j],
curr_vreg->min_voltage,
curr_vreg->max_voltage);
if (rc < 0) {
@@ -193,7 +215,7 @@
}
if (curr_vreg->op_mode >= 0) {
rc = regulator_set_optimum_mode(
- reg_ptr[i],
+ reg_ptr[j],
curr_vreg->op_mode);
if (rc < 0) {
pr_err(
@@ -206,20 +228,26 @@
}
}
} else {
- for (i = num_vreg-1; i >= 0; i--) {
- curr_vreg = &cam_vreg[i];
- if (reg_ptr[i]) {
+ for (i = num_vreg_seq-1; i >= 0; i--) {
+ if (vreg_seq) {
+ j = vreg_seq[i];
+ if (j >= num_vreg)
+ continue;
+ } else
+ j = i;
+ curr_vreg = &cam_vreg[j];
+ if (reg_ptr[j]) {
if (curr_vreg->type == REG_LDO) {
if (curr_vreg->op_mode >= 0) {
regulator_set_optimum_mode(
- reg_ptr[i], 0);
+ reg_ptr[j], 0);
}
regulator_set_voltage(
- reg_ptr[i], 0, curr_vreg->
+ reg_ptr[j], 0, curr_vreg->
max_voltage);
}
- regulator_put(reg_ptr[i]);
- reg_ptr[i] = NULL;
+ regulator_put(reg_ptr[j]);
+ reg_ptr[j] = NULL;
}
}
}
@@ -227,52 +255,100 @@
vreg_unconfig:
if (curr_vreg->type == REG_LDO)
- regulator_set_optimum_mode(reg_ptr[i], 0);
+ regulator_set_optimum_mode(reg_ptr[j], 0);
vreg_set_opt_mode_fail:
if (curr_vreg->type == REG_LDO)
- regulator_set_voltage(reg_ptr[i], 0,
+ regulator_set_voltage(reg_ptr[j], 0,
curr_vreg->max_voltage);
vreg_set_voltage_fail:
- regulator_put(reg_ptr[i]);
- reg_ptr[i] = NULL;
+ regulator_put(reg_ptr[j]);
+ reg_ptr[j] = NULL;
vreg_get_fail:
for (i--; i >= 0; i--) {
- curr_vreg = &cam_vreg[i];
+ if (vreg_seq) {
+ j = vreg_seq[i];
+ if (j >= num_vreg)
+ continue;
+ } else
+ j = i;
+ curr_vreg = &cam_vreg[j];
goto vreg_unconfig;
}
return -ENODEV;
}
int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
- int num_vreg, struct regulator **reg_ptr, int enable)
+ int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
+ int num_vreg_seq, struct regulator **reg_ptr, int enable)
{
- int i = 0, rc = 0;
+ int i = 0, j = 0, rc = 0;
+
+ if (num_vreg_seq > num_vreg) {
+ pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ if (!num_vreg_seq)
+ num_vreg_seq = num_vreg;
+
if (enable) {
- for (i = 0; i < num_vreg; i++) {
- if (IS_ERR(reg_ptr[i])) {
+ for (i = 0; i < num_vreg_seq; i++) {
+ if (vreg_seq) {
+ j = vreg_seq[i];
+ if (j >= num_vreg)
+ continue;
+ } else
+ j = i;
+ if (IS_ERR(reg_ptr[j])) {
pr_err("%s: %s null regulator\n",
- __func__, cam_vreg[i].reg_name);
+ __func__, cam_vreg[j].reg_name);
goto disable_vreg;
}
- rc = regulator_enable(reg_ptr[i]);
+ rc = regulator_enable(reg_ptr[j]);
if (rc < 0) {
pr_err("%s: %s enable failed\n",
- __func__, cam_vreg[i].reg_name);
+ __func__, cam_vreg[j].reg_name);
goto disable_vreg;
}
+ if (cam_vreg[j].delay > 20)
+ msleep(cam_vreg[j].delay);
+ else if (cam_vreg[j].delay)
+ usleep_range(cam_vreg[j].delay * 1000,
+ (cam_vreg[j].delay * 1000) + 1000);
}
} else {
- for (i = num_vreg-1; i >= 0; i--)
- regulator_disable(reg_ptr[i]);
+ for (i = num_vreg_seq-1; i >= 0; i--) {
+ if (vreg_seq) {
+ j = vreg_seq[i];
+ if (j >= num_vreg)
+ continue;
+ } else
+ j = i;
+ regulator_disable(reg_ptr[j]);
+ if (cam_vreg[j].delay > 20)
+ msleep(cam_vreg[j].delay);
+ else if (cam_vreg[j].delay)
+ usleep_range(cam_vreg[j].delay * 1000,
+ (cam_vreg[j].delay * 1000) + 1000);
+ }
}
return rc;
disable_vreg:
for (i--; i >= 0; i--) {
- regulator_disable(reg_ptr[i]);
- goto disable_vreg;
+ if (vreg_seq) {
+ j = vreg_seq[i];
+ if (j >= num_vreg)
+ continue;
+ } else
+ j = i;
+ regulator_disable(reg_ptr[j]);
+ if (cam_vreg[j].delay > 20)
+ msleep(cam_vreg[j].delay);
+ else if (cam_vreg[j].delay)
+ usleep_range(cam_vreg[j].delay * 1000,
+ (cam_vreg[j].delay * 1000) + 1000);
}
return rc;
}
@@ -319,7 +395,7 @@
config_gpio_table(gpio_conf);
if (gpio_en) {
- if (!gpio_conf->gpio_no_mux) {
+ if (!gpio_conf->gpio_no_mux && !gpio_ref_count) {
if (gpio_conf->cam_gpiomux_conf_tbl != NULL) {
msm_gpiomux_install(
(struct msm_gpiomux_config *)
@@ -334,6 +410,7 @@
return rc;
}
}
+ gpio_ref_count++;
if (gpio_conf->cam_gpio_req_tbl_size) {
rc = gpio_request_array(gpio_conf->cam_gpio_req_tbl,
gpio_conf->cam_gpio_req_tbl_size);
@@ -346,9 +423,10 @@
}
}
} else {
+ gpio_ref_count--;
gpio_free_array(gpio_conf->cam_gpio_req_tbl,
gpio_conf->cam_gpio_req_tbl_size);
- if (!gpio_conf->gpio_no_mux)
+ if (!gpio_conf->gpio_no_mux && !gpio_ref_count)
gpio_free_array(gpio_conf->cam_gpio_common_tbl,
gpio_conf->cam_gpio_common_tbl_size);
}
diff --git a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index 7e80145..9549dcc 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -21,7 +21,7 @@
#include <mach/clk.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
-
+#include <mach/dal_axi.h>
#define MSM_AXI_QOS_PREVIEW 200000
#define MSM_AXI_QOS_SNAPSHOT 200000
@@ -142,6 +142,7 @@
break;
case S_PREVIEW:
update_axi_qos(MSM_AXI_QOS_PREVIEW);
+ axi_allocate(AXI_FLOW_VIEWFINDER_HI);
break;
case S_VIDEO:
update_axi_qos(MSM_AXI_QOS_RECORDING);
@@ -153,6 +154,7 @@
update_axi_qos(PM_QOS_DEFAULT_VALUE);
break;
case S_EXIT:
+ axi_free(AXI_FLOW_VIEWFINDER_HI);
release_axi_qos();
break;
default:
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index e5c1091..98b2372 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -92,6 +92,20 @@
return rc;
}
+static int msm_camera_v4l2_private_general(struct file *f, void *pctx,
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+ int rc = 0;
+ struct msm_cam_v4l2_device *pcam = video_drvdata(f);
+
+ WARN_ON(pctx != f->private_data);
+
+ rc = msm_server_private_general(pcam, ioctl_ptr);
+ if (rc < 0)
+ pr_err("%s: Private command failed rc %d\n", __func__, rc);
+ return rc;
+}
+
static int msm_camera_v4l2_private_g_ctrl(struct file *f, void *pctx,
struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
{
@@ -690,6 +704,16 @@
return OUTPUT_TYPE_R;
case MSM_V4L2_EXT_CAPTURE_MODE_RDI1:
return OUTPUT_TYPE_R1;
+ case MSM_V4L2_EXT_CAPTURE_MODE_AEC:
+ return OUTPUT_TYPE_SAEC;
+ case MSM_V4L2_EXT_CAPTURE_MODE_AF:
+ return OUTPUT_TYPE_SAFC;
+ case MSM_V4L2_EXT_CAPTURE_MODE_AWB:
+ return OUTPUT_TYPE_SAWB;
+ case MSM_V4L2_EXT_CAPTURE_MODE_IHIST:
+ return OUTPUT_TYPE_IHST;
+ case MSM_V4L2_EXT_CAPTURE_MODE_CSTA:
+ return OUTPUT_TYPE_CSTA;
case MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT:
case MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW:
default:
@@ -761,6 +785,7 @@
{
int rc = -EINVAL;
struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+ struct msm_cam_v4l2_device *pcam = video_drvdata(file);
D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
switch (cmd) {
@@ -770,6 +795,47 @@
case MSM_CAM_V4L2_IOCTL_PRIVATE_G_CTRL:
rc = msm_camera_v4l2_private_g_ctrl(file, fh, ioctl_ptr);
break;
+ case MSM_CAM_V4L2_IOCTL_PRIVATE_GENERAL:
+ rc = msm_camera_v4l2_private_general(file, fh, ioctl_ptr);
+ break;
+ case MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD: {
+ struct msm_queue_cmd *event_cmd;
+ void *payload;
+ mutex_lock(&pcam->event_lock);
+ event_cmd = msm_dequeue(&pcam->eventData_q, list_eventdata);
+ if (!event_cmd) {
+ pr_err("%s: No event payload\n", __func__);
+ rc = -EINVAL;
+ mutex_unlock(&pcam->event_lock);
+ return rc;
+ }
+ payload = event_cmd->command;
+ if (event_cmd->trans_code != ioctl_ptr->trans_code) {
+ pr_err("%s: Events don't match\n", __func__);
+ kfree(payload);
+ kfree(event_cmd);
+ rc = -EINVAL;
+ mutex_unlock(&pcam->event_lock);
+ break;
+ }
+ if (ioctl_ptr->len > 0) {
+ if (copy_to_user(ioctl_ptr->ioctl_ptr, payload,
+ ioctl_ptr->len)) {
+ pr_err("%s Copy to user failed for cmd %d",
+ __func__, cmd);
+ kfree(payload);
+ kfree(event_cmd);
+ rc = -EINVAL;
+ mutex_unlock(&pcam->event_lock);
+ break;
+ }
+ }
+ kfree(payload);
+ kfree(event_cmd);
+ mutex_unlock(&pcam->event_lock);
+ rc = 0;
+ break;
+ }
default:
pr_err("%s Unsupported ioctl cmd %d ", __func__, cmd);
break;
@@ -873,7 +939,6 @@
server_q_idx = msm_find_free_queue();
if (server_q_idx < 0)
return server_q_idx;
-
rc = msm_server_begin_session(pcam, server_q_idx);
if (rc < 0) {
pr_err("%s error starting server session ", __func__);
@@ -908,6 +973,8 @@
msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
pcam->pvdev);
+ mutex_init(&pcam->event_lock);
+ msm_queue_init(&pcam->eventData_q, "eventData");
}
pcam_inst->vbqueue_initialized = 0;
rc = 0;
@@ -930,6 +997,7 @@
return rc;
msm_send_open_server_failed:
+ msm_drain_eventq(&pcam->eventData_q);
msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
if (pmctl->mctl_release)
@@ -1071,8 +1139,13 @@
D("%s index %d nodeid %d count %d\n", __func__, pcam_inst->my_index,
pcam->vnode_id, pcam->use_count);
pcam->dev_inst[pcam_inst->my_index] = NULL;
- if (pcam_inst->my_index == 0)
+ if (pcam_inst->my_index == 0) {
+ mutex_lock(&pcam->event_lock);
+ msm_drain_eventq(&pcam->eventData_q);
+ mutex_unlock(&pcam->event_lock);
+ mutex_destroy(&pcam->event_lock);
msm_destroy_v4l2_event_queue(&pcam_inst->eventHandle);
+ }
CLR_VIDEO_INST_IDX(pcam_inst->inst_handle);
CLR_IMG_MODE(pcam_inst->inst_handle);
@@ -1135,24 +1208,60 @@
unsigned int cmd, unsigned long evt)
{
struct v4l2_event v4l2_ev;
+ struct v4l2_event_and_payload evt_payload;
struct msm_cam_v4l2_device *pcam = NULL;
-
+ int rc = 0;
+ struct msm_queue_cmd *event_qcmd;
+ void *payload;
if (!mctl) {
pr_err("%s: mctl is NULL\n", __func__);
return -EINVAL;
}
- if (copy_from_user(&v4l2_ev, (void __user *)evt,
- sizeof(struct v4l2_event))) {
+ if (copy_from_user(&evt_payload, (void __user *)evt,
+ sizeof(struct v4l2_event_and_payload))) {
ERR_COPY_FROM_USER();
return -EFAULT;
}
+ v4l2_ev = evt_payload.evt;
v4l2_ev.id = 0;
pcam = mctl->pcam_ptr;
ktime_get_ts(&v4l2_ev.timestamp);
+ if (evt_payload.payload_length > 0 && evt_payload.payload != NULL) {
+ mutex_lock(&pcam->event_lock);
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+ if (!event_qcmd) {
+ pr_err("%s Insufficient memory. return", __func__);
+ rc = -ENOMEM;
+ goto event_qcmd_alloc_fail;
+ }
+ payload = kzalloc(evt_payload.payload_length, GFP_KERNEL);
+ if (!payload) {
+ pr_err("%s Insufficient memory. return", __func__);
+ rc = -ENOMEM;
+ goto payload_alloc_fail;
+ }
+ if (copy_from_user(payload,
+ (void __user *)evt_payload.payload,
+ evt_payload.payload_length)) {
+ ERR_COPY_FROM_USER();
+ rc = -EFAULT;
+ goto copy_from_user_failed;
+ }
+ event_qcmd->command = payload;
+ event_qcmd->trans_code = evt_payload.transaction_id;
+ msm_enqueue(&pcam->eventData_q, &event_qcmd->list_eventdata);
+ mutex_unlock(&pcam->event_lock);
+ }
v4l2_event_queue(pcam->pvdev, &v4l2_ev);
- return 0;
+ return rc;
+copy_from_user_failed:
+ kfree(payload);
+payload_alloc_fail:
+ kfree(event_qcmd);
+event_qcmd_alloc_fail:
+ return rc;
}
@@ -1169,11 +1278,21 @@
{
int rc = -ENOMEM;
struct video_device *pvdev = NULL;
- struct i2c_client *client = v4l2_get_subdevdata(pcam->sensor_sdev);
+ struct i2c_client *client = NULL;
+ struct platform_device *pdev = NULL;
D("%s\n", __func__);
/* first register the v4l2 device */
- pcam->v4l2_dev.dev = &client->dev;
+ if (pcam->sensor_sdev->flags & V4L2_SUBDEV_FL_IS_I2C) {
+ client = v4l2_get_subdevdata(pcam->sensor_sdev);
+ pcam->v4l2_dev.dev = &client->dev;
+ pcam->media_dev.dev = &client->dev;
+ } else {
+ pdev = v4l2_get_subdevdata(pcam->sensor_sdev);
+ pcam->v4l2_dev.dev = &pdev->dev;
+ pcam->media_dev.dev = &pdev->dev;
+ }
+
rc = v4l2_device_register(pcam->v4l2_dev.dev, &pcam->v4l2_dev);
if (rc < 0)
return -EINVAL;
@@ -1190,7 +1309,6 @@
strlcpy(pcam->media_dev.model, QCAMERA_NAME,
sizeof(pcam->media_dev.model));
- pcam->media_dev.dev = &client->dev;
rc = media_device_register(&pcam->media_dev);
pvdev->v4l2_dev = &pcam->v4l2_dev;
pcam->v4l2_dev.mdev = &pcam->media_dev;
@@ -1249,7 +1367,7 @@
D("%s called\n", __func__);
- if (!actuator_info)
+ if (!actuator_info || !actuator_info->board_info)
goto probe_fail;
adapter = i2c_get_adapter(actuator_info->bus_id);
@@ -1292,7 +1410,7 @@
D("%s called\n", __func__);
- if (!eeprom_info)
+ if (!eeprom_info || !eeprom_info->board_info)
goto probe_fail;
adapter = i2c_get_adapter(eeprom_info->bus_id);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index a2c21bd..3dc0fe7 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -31,6 +31,7 @@
#include <media/videobuf2-msm-mem.h>
#include <media/msm_isp.h>
#include <mach/camera.h>
+#include <mach/iommu.h>
#include <media/msm_isp.h>
#include <linux/ion.h>
#include <linux/iommu.h>
@@ -140,6 +141,11 @@
uint32_t frameCounter;
};
+struct rdi_count_msg {
+ uint32_t rdi_interface;
+ uint32_t count;
+};
+
/* message id for v4l2_subdev_notify*/
enum msm_camera_v4l2_subdev_notify {
NOTIFY_ISP_MSG_EVT, /* arg = enum ISP_MESSAGE_ID */
@@ -148,11 +154,9 @@
NOTIFY_VFE_MSG_COMP_STATS, /* arg = struct msm_stats_buf */
NOTIFY_VFE_BUF_EVT, /* arg = struct msm_vfe_resp */
NOTIFY_VFE_CAMIF_ERROR,
- NOTIFY_VFE_SOF_COUNT, /*arg = int*/
+ NOTIFY_VFE_PIX_SOF_COUNT, /*arg = int*/
+ NOTIFY_AXI_RDI_SOF_COUNT, /*arg = struct rdi_count_msg*/
NOTIFY_PCLK_CHANGE, /* arg = pclk */
- NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */
- NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */
- NOTIFY_CSIC_CFG, /* arg = msm_camera_csic_params */
NOTIFY_VFE_IRQ,
NOTIFY_AXI_IRQ,
NOTIFY_GESTURE_EVT, /* arg = v4l2_event */
@@ -201,10 +205,36 @@
enum v4l2_colorspace colorspace;
};
+struct msm_cam_return_frame_info {
+ int dirty;
+ int node_type;
+ struct timeval timestamp;
+};
+
+struct msm_cam_timestamp {
+ uint8_t present;
+ struct timeval timestamp;
+};
+
+struct msm_cam_buf_map_info {
+ int fd;
+ uint32_t data_offset;
+ unsigned long paddr;
+ unsigned long len;
+ struct file *file;
+ struct ion_handle *handle;
+};
+
+struct msm_cam_meta_frame {
+ struct msm_pp_frame frame;
+ /* Mapping information per plane */
+ struct msm_cam_buf_map_info map[VIDEO_MAX_PLANES];
+};
+
struct msm_mctl_pp_frame_info {
int user_cmd;
- struct msm_pp_frame src_frame;
- struct msm_pp_frame dest_frame;
+ struct msm_cam_meta_frame src_frame;
+ struct msm_cam_meta_frame dest_frame;
struct msm_mctl_pp_frame_cmd pp_frame_cmd;
struct msm_cam_media_controller *p_mctl;
};
@@ -242,6 +272,10 @@
int (*mctl_vbqueue_init)(struct msm_cam_v4l2_dev_inst *pcam,
struct vb2_queue *q, enum v4l2_buf_type type);
int (*mctl_ufmt_init)(struct msm_cam_media_controller *p_mctl);
+ int (*isp_config)(struct msm_cam_media_controller *pmctl,
+ unsigned int cmd, unsigned long arg);
+ int (*isp_notify)(struct msm_cam_media_controller *pmctl,
+ struct v4l2_subdev *sd, unsigned int notification, void *arg);
/* the following reflect the HW topology information*/
struct v4l2_subdev *sensor_sdev; /* sensor sub device */
@@ -253,10 +287,10 @@
struct v4l2_subdev *gemini_sdev; /* gemini sub device */
struct v4l2_subdev *vpe_sdev; /* vpe sub device */
struct v4l2_subdev *axi_sdev; /* axi sub device */
+ struct v4l2_subdev *vfe_sdev; /* vfe sub device */
struct v4l2_subdev *eeprom_sdev; /* eeprom sub device */
struct v4l2_subdev *cpp_sdev;/*cpp sub device*/
- struct msm_isp_ops *isp_sdev; /* isp sub device : camif/VFE */
struct msm_cam_config_dev *config_device;
/*mctl session control information*/
@@ -282,21 +316,10 @@
uint32_t ping_imem_cbcr;
uint32_t pong_imem_y;
uint32_t pong_imem_cbcr;
-};
-/* abstract camera device represents a VFE and connected sensor */
-struct msm_isp_ops {
- char *config_dev_name;
-
- int (*isp_config)(struct msm_cam_media_controller *pmctl,
- unsigned int cmd, unsigned long arg);
- int (*isp_notify)(struct v4l2_subdev *sd,
- unsigned int notification, void *arg);
- int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
- struct msm_mctl_pp_cmd, void *data);
-
- /* vfe subdevice */
- struct v4l2_subdev *sd;
+ /*IOMMU domain for this session*/
+ int domain_num;
+ struct iommu_domain *domain;
};
struct msm_isp_buf_info {
@@ -309,7 +332,7 @@
uint32_t data_offset;
};
-#define MSM_DEV_INST_MAX 16
+#define MSM_DEV_INST_MAX 24
struct msm_cam_v4l2_dev_inst {
struct v4l2_fh eventHandle;
struct vb2_queue vid_bufq;
@@ -373,6 +396,9 @@
struct v4l2_subdev *act_sdev; /* actuator sub device */
struct v4l2_subdev *eeprom_sdev; /* actuator sub device */
struct msm_camera_sensor_info *sdata;
+
+ struct msm_device_queue eventData_q; /*payload for events sent to app*/
+ struct mutex event_lock;
};
static inline struct msm_cam_v4l2_device *to_pcam(
@@ -396,6 +422,8 @@
struct msm_cam_media_controller *p_mctl;
struct msm_mem_map_info mem_map;
int dev_num;
+ int domain_num;
+ struct iommu_domain *domain;
};
struct msm_cam_subdev_info {
@@ -555,6 +583,10 @@
* dispatch the irq to the corresponding subdev. */
struct v4l2_subdev *subdev_table[MSM_CAM_HW_MAX];
struct msm_cam_server_irqmap_entry hw_irqmap[CAMERA_SS_IRQ_MAX];
+
+ /*IOMMU domain (Page table)*/
+ int domain_num;
+ struct iommu_domain *domain;
};
enum msm_cam_buf_lookup_type {
@@ -571,11 +603,13 @@
/* ISP related functions */
void msm_isp_vfe_dev_init(struct v4l2_subdev *vd);
+int msm_isp_config(struct msm_cam_media_controller *pmctl,
+ unsigned int cmd, unsigned long arg);
+int msm_isp_notify(struct msm_cam_media_controller *pmctl,
+ struct v4l2_subdev *sd, unsigned int notification, void *arg);
/*
int msm_isp_register(struct msm_cam_v4l2_device *pcam);
*/
-int msm_isp_register(struct msm_cam_server_dev *psvr);
-void msm_isp_unregister(struct msm_cam_server_dev *psvr);
int msm_sensor_register(struct v4l2_subdev *);
int msm_isp_init_module(int g_num_config_nodes);
@@ -589,7 +623,8 @@
uint32_t frame_id);
int msm_mctl_buf_done_pp(struct msm_cam_media_controller *pmctl,
struct msm_cam_buf_handle *buf_handle,
- struct msm_free_buf *frame, int dirty, int node_type);
+ struct msm_free_buf *frame,
+ struct msm_cam_return_frame_info *ret_frame);
int msm_mctl_reserve_free_buf(struct msm_cam_media_controller *pmctl,
struct msm_cam_v4l2_dev_inst *pcam_inst,
struct msm_cam_buf_handle *buf_handle,
@@ -599,9 +634,9 @@
struct msm_free_buf *free_buf);
/*Memory(PMEM) functions*/
int msm_register_pmem(struct hlist_head *ptype, void __user *arg,
- struct ion_client *client);
+ struct ion_client *client, int domain_num);
int msm_pmem_table_del(struct hlist_head *ptype, void __user *arg,
- struct ion_client *client);
+ struct ion_client *client, int domain_num);
int msm_pmem_region_get_phy_addr(struct hlist_head *ptype,
struct msm_mem_map_info *mem_map, int32_t *phyaddr);
uint8_t msm_pmem_region_lookup(struct hlist_head *ptype,
@@ -623,7 +658,7 @@
struct msm_vfe_cfg_cmd *cfgcmd, void *data);
int msm_vpe_subdev_init(struct v4l2_subdev *sd);
int msm_gemini_subdev_init(struct v4l2_subdev *gemini_sd);
-void msm_vpe_subdev_release(void);
+void msm_vpe_subdev_release(struct v4l2_subdev *sd);
void msm_gemini_subdev_release(struct v4l2_subdev *gemini_sd);
int msm_mctl_is_pp_msg_type(struct msm_cam_media_controller *p_mctl,
int msg_type);
@@ -670,6 +705,10 @@
struct msm_cam_buf_handle *buf_handle);
int msm_mctl_buf_return_buf(struct msm_cam_media_controller *pmctl,
int image_mode, struct msm_frame_buffer *buf);
+int msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
+ struct ion_client *client, int domain_num);
+int msm_mctl_unmap_user_frame(struct msm_cam_meta_frame *meta_frame,
+ struct ion_client *client, int domain_num);
int msm_mctl_pp_mctl_divert_done(struct msm_cam_media_controller *p_mctl,
void __user *arg);
void msm_release_ion_client(struct kref *ref);
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 3d94afd..83f762c 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -73,7 +73,7 @@
struct msm_camvfe_params vfe_params;
int rc;
- cfgcmd.cmd_type = CMD_VFE_SOF_COUNT_UPDATE;
+ cfgcmd.cmd_type = CMD_VFE_PIX_SOF_COUNT_UPDATE;
cfgcmd.value = NULL;
vfe_params.vfe_cfg = &cfgcmd;
vfe_params.data = arg;
@@ -156,15 +156,14 @@
return image_mode;
}
-static int msm_isp_notify_VFE_BUF_EVT(struct v4l2_subdev *sd, void *arg)
+static int msm_isp_notify_VFE_BUF_EVT(struct msm_cam_media_controller *pmctl,
+ struct v4l2_subdev *sd, void *arg)
{
int rc = -EINVAL;
struct msm_vfe_resp *vdata = (struct msm_vfe_resp *)arg;
struct msm_free_buf free_buf, temp_free_buf;
struct msm_camvfe_params vfe_params;
struct msm_vfe_cfg_cmd cfgcmd;
- struct msm_cam_media_controller *pmctl =
- (struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
struct msm_frame_info *frame_info =
(struct msm_frame_info *)vdata->evt_msg.data;
@@ -172,7 +171,7 @@
struct msm_cam_buf_handle buf_handle;
if (!pcam) {
- pr_debug("%s pcam is null. return\n", __func__);
+ pr_err("%s pcam is null. return\n", __func__);
msm_isp_sync_free(vdata);
return rc;
}
@@ -275,14 +274,12 @@
/*
* This function executes in interrupt context.
*/
-static int msm_isp_notify_vfe(struct v4l2_subdev *sd,
- unsigned int notification, void *arg)
+static int msm_isp_notify_vfe(struct msm_cam_media_controller *pmctl,
+ struct v4l2_subdev *sd, unsigned int notification, void *arg)
{
int rc = 0;
struct v4l2_event v4l2_evt;
struct msm_isp_event_ctrl *isp_event;
- struct msm_cam_media_controller *pmctl =
- (struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
struct msm_free_buf buf;
if (!pmctl) {
@@ -292,9 +289,9 @@
}
if (notification == NOTIFY_VFE_BUF_EVT)
- return msm_isp_notify_VFE_BUF_EVT(sd, arg);
+ return msm_isp_notify_VFE_BUF_EVT(pmctl, sd, arg);
- if (notification == NOTIFY_VFE_SOF_COUNT)
+ if (notification == NOTIFY_VFE_PIX_SOF_COUNT)
return msm_isp_notify_VFE_SOF_COUNT_EVT(sd, arg);
isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_ATOMIC);
@@ -493,11 +490,12 @@
return rc;
}
-static int msm_isp_notify(struct v4l2_subdev *sd,
- unsigned int notification, void *arg)
+int msm_isp_notify(struct msm_cam_media_controller *pmctl,
+ struct v4l2_subdev *sd, unsigned int notification, void *arg)
{
- return msm_isp_notify_vfe(sd, notification, arg);
+ return msm_isp_notify_vfe(pmctl, sd, notification, arg);
}
+EXPORT_SYMBOL(msm_isp_notify);
static int msm_config_vfe(struct v4l2_subdev *sd,
struct msm_cam_media_controller *mctl, void __user *arg)
@@ -703,13 +701,13 @@
return rc;
}
/* config function simliar to origanl msm_ioctl_config*/
-static int msm_isp_config(struct msm_cam_media_controller *pmctl,
+int msm_isp_config(struct msm_cam_media_controller *pmctl,
unsigned int cmd, unsigned long arg)
{
int rc = -EINVAL;
void __user *argp = (void __user *)arg;
- struct v4l2_subdev *sd = pmctl->isp_sdev->sd;
+ struct v4l2_subdev *sd = pmctl->vfe_sdev;
D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
switch (cmd) {
@@ -742,47 +740,7 @@
return rc;
}
-
-static struct msm_isp_ops isp_subdev[MSM_MAX_CAMERA_CONFIGS];
-
-/**/
-int msm_isp_init_module(int g_num_config_nodes)
-{
- int i = 0;
-
- for (i = 0; i < g_num_config_nodes; i++) {
- isp_subdev[i].isp_config = msm_isp_config;
- isp_subdev[i].isp_notify = msm_isp_notify;
- }
- return 0;
-}
-EXPORT_SYMBOL(msm_isp_init_module);
-
-/*
-*/
-int msm_isp_register(struct msm_cam_server_dev *psvr)
-{
- int i = 0;
-
- D("%s\n", __func__);
-
- BUG_ON(!psvr);
-
- /* Initialize notify function for v4l2_dev */
- for (i = 0; i < psvr->config_info.num_config_nodes; i++)
- psvr->isp_subdev[i] = &(isp_subdev[i]);
-
- return 0;
-}
-EXPORT_SYMBOL(msm_isp_register);
-
-/**/
-void msm_isp_unregister(struct msm_cam_server_dev *psvr)
-{
- int i = 0;
- for (i = 0; i < psvr->config_info.num_config_nodes; i++)
- psvr->isp_subdev[i] = NULL;
-}
+EXPORT_SYMBOL(msm_isp_config);
int msm_isp_subdev_ioctl(struct v4l2_subdev *isp_subdev,
struct msm_vfe_cfg_cmd *cfgcmd, void *data)
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index a8d74a7..0711ca5 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -138,7 +138,38 @@
.pxlcode = V4L2_MBUS_FMT_YUYV8_2X8, /* YUV sensor */
.colorspace = V4L2_COLORSPACE_JPEG,
},
-
+ {
+ .name = "SAEC",
+ .depth = 16,
+ .bitsperpxl = 16,
+ .fourcc = V4L2_PIX_FMT_STATS_AE,
+ .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* YUV sensor */
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
+ .name = "SAWB",
+ .depth = 16,
+ .bitsperpxl = 16,
+ .fourcc = V4L2_PIX_FMT_STATS_AWB,
+ .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* YUV sensor */
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
+ .name = "SAFC",
+ .depth = 16,
+ .bitsperpxl = 16,
+ .fourcc = V4L2_PIX_FMT_STATS_AF,
+ .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* YUV sensor */
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ {
+ .name = "SHST",
+ .depth = 16,
+ .bitsperpxl = 16,
+ .fourcc = V4L2_PIX_FMT_STATS_IHST,
+ .pxlcode = V4L2_MBUS_FMT_SBGGR10_1X10, /* YUV sensor */
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
};
static int msm_get_sensor_info(
@@ -197,6 +228,20 @@
return rc;
}
+static uint8_t msm_sensor_state_check(
+ struct msm_cam_media_controller *p_mctl)
+{
+ struct msm_sensor_ctrl_t *s_ctrl = NULL;
+ if (!p_mctl)
+ return 0;
+ if (!p_mctl->sensor_sdev)
+ return 0;
+ s_ctrl = get_sctrl(p_mctl->sensor_sdev);
+ if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP)
+ return 1;
+ return 0;
+}
+
/* called by the server or the config nodes to handle user space
commands*/
static int msm_mctl_cmd(struct msm_cam_media_controller *p_mctl,
@@ -327,7 +372,6 @@
case MSM_CAM_IOCTL_EEPROM_IO_CFG: {
struct msm_eeprom_cfg_data eeprom_data;
if (p_mctl->eeprom_sdev) {
- eeprom_data.is_eeprom_supported = 1;
rc = v4l2_subdev_call(p_mctl->eeprom_sdev,
core, ioctl, VIDIOC_MSM_EEPROM_CFG, argp);
} else {
@@ -370,7 +414,8 @@
ERR_COPY_FROM_USER();
rc = -EFAULT;
} else {
- rc = msm_flash_ctrl(p_mctl->sdata, &flash_info);
+ if (msm_sensor_state_check(p_mctl))
+ rc = msm_flash_ctrl(p_mctl->sdata, &flash_info);
}
break;
}
@@ -408,17 +453,36 @@
rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
VIDIOC_MSM_AXI_CFG, (void __user *)arg);
else
- rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg);
+ rc = p_mctl->isp_config(p_mctl, cmd, arg);
break;
case MSM_CAM_IOCTL_ISPIF_IO_CFG:
rc = v4l2_subdev_call(p_mctl->ispif_sdev,
core, ioctl, VIDIOC_MSM_ISPIF_CFG, argp);
break;
+
+ case MSM_CAM_IOCTL_CSIPHY_IO_CFG:
+ if (p_mctl->csiphy_sdev)
+ rc = v4l2_subdev_call(p_mctl->csiphy_sdev,
+ core, ioctl, VIDIOC_MSM_CSIPHY_CFG, argp);
+ break;
+
+ case MSM_CAM_IOCTL_CSIC_IO_CFG:
+ if (p_mctl->csic_sdev)
+ rc = v4l2_subdev_call(p_mctl->csic_sdev,
+ core, ioctl, VIDIOC_MSM_CSIC_CFG, argp);
+ break;
+
+ case MSM_CAM_IOCTL_CSID_IO_CFG:
+ if (p_mctl->csid_sdev)
+ rc = v4l2_subdev_call(p_mctl->csid_sdev,
+ core, ioctl, VIDIOC_MSM_CSID_CFG, argp);
+ break;
+
default:
/* ISP config*/
D("%s:%d: go to default. Calling msm_isp_config\n",
__func__, __LINE__);
- rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg);
+ rc = p_mctl->isp_config(p_mctl, cmd, arg);
break;
}
D("%s: !!! cmd = %d, rc = %d\n",
@@ -445,7 +509,6 @@
/* open sub devices - once only*/
if (!p_mctl->opencnt) {
struct msm_sensor_csi_info csi_info;
- uint32_t csid_version = 0;
wake_lock(&p_mctl->wake_lock);
csid_core = camdev->csid_core;
@@ -471,39 +534,10 @@
goto act_power_up_failed;
}
- if (p_mctl->csiphy_sdev) {
- rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
- VIDIOC_MSM_CSIPHY_INIT, NULL);
- if (rc < 0) {
- pr_err("%s: csiphy initialization failed %d\n",
- __func__, rc);
- goto csiphy_init_failed;
- }
- }
-
- if (p_mctl->csid_sdev) {
- rc = v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
- VIDIOC_MSM_CSID_INIT, &csid_version);
- if (rc < 0) {
- pr_err("%s: csid initialization failed %d\n",
- __func__, rc);
- goto csid_init_failed;
- }
- csi_info.is_csic = 0;
- }
-
- if (p_mctl->csic_sdev) {
- rc = v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
- VIDIOC_MSM_CSIC_INIT, &csid_version);
- if (rc < 0) {
- pr_err("%s: csic initialization failed %d\n",
- __func__, rc);
- goto csic_init_failed;
- }
+ if (p_mctl->csic_sdev)
csi_info.is_csic = 1;
- }
-
- csi_info.csid_version = csid_version;
+ else
+ csi_info.is_csic = 0;
rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, ioctl,
VIDIOC_MSM_SENSOR_CSID_INFO, &csi_info);
if (rc < 0) {
@@ -526,26 +560,6 @@
return rc;
msm_csi_version:
- if (p_mctl->csic_sdev)
- if (v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
- VIDIOC_MSM_CSIC_RELEASE, NULL) < 0)
- pr_err("%s: csic release failed %d\n", __func__, rc);
-csic_init_failed:
- if (p_mctl->csid_sdev)
- if (v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
- VIDIOC_MSM_CSID_RELEASE, NULL) < 0)
- pr_err("%s: csid release failed %d\n", __func__, rc);
-csid_init_failed:
- if (p_mctl->csiphy_sdev)
- if (v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
- VIDIOC_MSM_CSIPHY_RELEASE,
- sinfo->sensor_platform_info->csi_lane_params) < 0)
- pr_err("%s: csiphy release failed %d\n", __func__, rc);
-csiphy_init_failed:
- if (p_mctl->act_sdev)
- if (v4l2_subdev_call(p_mctl->act_sdev, core,
- s_power, 0) < 0)
- pr_err("%s: act power down failed:%d\n", __func__, rc);
act_power_up_failed:
if (v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0) < 0)
pr_err("%s: sensor powerdown failed: %d\n", __func__, rc);
@@ -693,6 +707,9 @@
pmctl->mctl_open = msm_mctl_open;
pmctl->mctl_cmd = msm_mctl_cmd;
pmctl->mctl_release = msm_mctl_release;
+ pmctl->isp_config = msm_isp_config;
+ pmctl->isp_notify = msm_isp_notify;
+
/* init mctl buf */
msm_mctl_buf_init(pcam);
memset(&pmctl->pp_info, 0, sizeof(pmctl->pp_info));
@@ -1584,12 +1601,20 @@
{
int rc = -EINVAL;
struct video_device *pvdev = NULL;
- struct i2c_client *client = v4l2_get_subdevdata(pcam->sensor_sdev);
-
+ struct i2c_client *client = NULL;
+ struct platform_device *pdev = NULL;
D("%s\n", __func__);
/* first register the v4l2 device */
- pcam->mctl_node.v4l2_dev.dev = &client->dev;
+ if (pcam->sensor_sdev->flags & V4L2_SUBDEV_FL_IS_I2C) {
+ client = v4l2_get_subdevdata(pcam->sensor_sdev);
+ pcam->mctl_node.v4l2_dev.dev = &client->dev;
+ } else {
+ pdev = v4l2_get_subdevdata(pcam->sensor_sdev);
+ pcam->mctl_node.v4l2_dev.dev = &pdev->dev;
+ }
+
+ /* first register the v4l2 device */
rc = v4l2_device_register(pcam->mctl_node.v4l2_dev.dev,
&pcam->mctl_node.v4l2_dev);
if (rc < 0)
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 9f7f689..953f042 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -130,7 +130,8 @@
rc = videobuf2_pmem_contig_user_get(mem, &offset,
buf_type,
pcam_inst->buf_offset[buf_idx][i].addr_offset,
- pcam_inst->path, pmctl->client);
+ pcam_inst->path, pmctl->client,
+ pmctl->domain_num);
else
rc = videobuf2_pmem_contig_mmap_get(mem, &offset,
buf_type, pcam_inst->path);
@@ -265,7 +266,8 @@
}
for (i = 0; i < vb->num_planes; i++) {
mem = vb2_plane_cookie(vb, i);
- videobuf2_pmem_contig_user_put(mem, pmctl->client);
+ videobuf2_pmem_contig_user_put(mem, pmctl->client,
+ pmctl->domain_num);
}
buf->state = MSM_BUFFER_STATE_UNUSED;
}
@@ -411,7 +413,8 @@
struct msm_cam_media_controller *pmctl,
struct msm_cam_v4l2_dev_inst *pcam_inst,
struct msm_free_buf *fbuf,
- uint32_t *frame_id, int gen_timestamp)
+ uint32_t *frame_id,
+ struct msm_cam_timestamp *cam_ts)
{
struct msm_frame_buffer *buf = NULL;
int del_buf = 1;
@@ -422,11 +425,15 @@
__func__, fbuf->ch_paddr[0]);
return -EINVAL;
}
- if (gen_timestamp) {
+ if (!cam_ts->present) {
if (frame_id)
buf->vidbuf.v4l2_buf.sequence = *frame_id;
msm_mctl_gettimeofday(
&buf->vidbuf.v4l2_buf.timestamp);
+ } else {
+ D("%s Copying timestamp as %ld.%ld", __func__,
+ cam_ts->timestamp.tv_sec, cam_ts->timestamp.tv_usec);
+ buf->vidbuf.v4l2_buf.timestamp = cam_ts->timestamp;
}
vb2_buffer_done(&buf->vidbuf, VB2_BUF_STATE_DONE);
return 0;
@@ -442,6 +449,7 @@
int idx, rc;
int pp_divert_type = 0, pp_type = 0;
uint32_t image_mode;
+ struct msm_cam_timestamp cam_ts;
if (!p_mctl || !buf_handle || !fbuf) {
pr_err("%s Invalid argument. ", __func__);
@@ -507,8 +515,9 @@
__func__);
return -EINVAL;
}
+ memset(&cam_ts, 0, sizeof(cam_ts));
rc = msm_mctl_buf_done_proc(p_mctl, pcam_inst,
- fbuf, &frame_id, 1);
+ fbuf, &frame_id, &cam_ts);
}
return rc;
}
@@ -752,12 +761,14 @@
int msm_mctl_buf_done_pp(struct msm_cam_media_controller *pmctl,
struct msm_cam_buf_handle *buf_handle,
- struct msm_free_buf *frame, int dirty, int node_type)
+ struct msm_free_buf *frame,
+ struct msm_cam_return_frame_info *ret_frame)
{
struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
int rc = 0, idx;
+ struct msm_cam_timestamp cam_ts;
- if (!pmctl || !buf_handle) {
+ if (!pmctl || !buf_handle || !ret_frame) {
pr_err("%s Invalid argument ", __func__);
return -EINVAL;
}
@@ -773,13 +784,13 @@
}
} else if (buf_handle->buf_lookup_type == BUF_LOOKUP_BY_IMG_MODE) {
idx = msm_mctl_img_mode_to_inst_index(pmctl,
- buf_handle->image_mode, node_type);
+ buf_handle->image_mode, ret_frame->node_type);
if (idx < 0) {
pr_err("%s Invalid instance, buffer not released\n",
__func__);
return idx;
}
- if (node_type)
+ if (ret_frame->node_type)
pcam_inst = pmctl->pcam_ptr->mctl_node.dev_inst[idx];
else
pcam_inst = pmctl->pcam_ptr->dev_inst[idx];
@@ -791,12 +802,15 @@
}
D("%s:inst=0x%p, paddr=0x%x, dirty=%d",
- __func__, pcam_inst, frame->ch_paddr[0], dirty);
- if (dirty)
+ __func__, pcam_inst, frame->ch_paddr[0], ret_frame->dirty);
+ cam_ts.present = 1;
+ cam_ts.timestamp = ret_frame->timestamp;
+ if (ret_frame->dirty)
/* the frame is dirty, not going to disptach to app */
rc = msm_mctl_release_free_buf(pmctl, pcam_inst, frame);
else
- rc = msm_mctl_buf_done_proc(pmctl, pcam_inst, frame, NULL, 0);
+ rc = msm_mctl_buf_done_proc(pmctl, pcam_inst, frame,
+ NULL, &cam_ts);
return rc;
}
@@ -840,3 +854,199 @@
spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
return -EINVAL;
}
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+/* Unmap using ION APIs */
+static void __msm_mctl_unmap_user_frame(struct msm_cam_meta_frame *meta_frame,
+ struct ion_client *client, int domain_num)
+{
+ int i = 0;
+ for (i = 0; i < meta_frame->frame.num_planes; i++) {
+ D("%s Plane %d handle %p", __func__, i,
+ meta_frame->map[i].handle);
+ ion_unmap_iommu(client, meta_frame->map[i].handle,
+ domain_num, 0);
+ ion_free(client, meta_frame->map[i].handle);
+ }
+}
+
+/* Map using ION APIs */
+static int __msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
+ struct ion_client *client, int domain_num)
+{
+ unsigned long paddr = 0;
+ unsigned long len = 0;
+ int i = 0, j = 0;
+
+ for (i = 0; i < meta_frame->frame.num_planes; i++) {
+ meta_frame->map[i].handle = ion_import_dma_buf(client,
+ meta_frame->frame.mp[i].fd);
+ if (IS_ERR_OR_NULL(meta_frame->map[i].handle)) {
+ pr_err("%s: ion_import failed for plane = %d fd = %d",
+ __func__, i, meta_frame->frame.mp[i].fd);
+ /* Roll back previous plane mappings, if any */
+ for (j = i-1; j >= 0; j--) {
+ ion_unmap_iommu(client,
+ meta_frame->map[j].handle,
+ domain_num, 0);
+ ion_free(client, meta_frame->map[j].handle);
+ }
+ return -EACCES;
+ }
+ D("%s Mapping fd %d plane %d handle %p", __func__,
+ meta_frame->frame.mp[i].fd, i,
+ meta_frame->map[i].handle);
+ if (ion_map_iommu(client, meta_frame->map[i].handle,
+ domain_num, 0, SZ_4K,
+ 0, &paddr, &len, UNCACHED, 0) < 0) {
+ pr_err("%s: cannot map address plane %d", __func__, i);
+ ion_free(client, meta_frame->map[i].handle);
+ /* Roll back previous plane mappings, if any */
+ for (j = i-1; j >= 0; j--) {
+ if (meta_frame->map[j].handle) {
+ ion_unmap_iommu(client,
+ meta_frame->map[j].handle,
+ domain_num, 0);
+ ion_free(client,
+ meta_frame->map[j].handle);
+ }
+ }
+ return -EFAULT;
+ }
+
+ /* Validate the offsets with the mapped length. */
+ if ((meta_frame->frame.mp[i].addr_offset > len) ||
+ (meta_frame->frame.mp[i].data_offset +
+ meta_frame->frame.mp[i].length > len)) {
+ pr_err("%s: Invalid offsets A %d D %d L %d len %ld",
+ __func__, meta_frame->frame.mp[i].addr_offset,
+ meta_frame->frame.mp[i].data_offset,
+ meta_frame->frame.mp[i].length, len);
+ /* Roll back previous plane mappings, if any */
+ for (j = i; j >= 0; j--) {
+ if (meta_frame->map[j].handle) {
+ ion_unmap_iommu(client,
+ meta_frame->map[j].handle,
+ domain_num, 0);
+ ion_free(client,
+ meta_frame->map[j].handle);
+ }
+ }
+ return -EINVAL;
+ }
+ meta_frame->map[i].data_offset =
+ meta_frame->frame.mp[i].data_offset;
+ /* Add the addr_offset to the paddr here itself. The addr_offset
+ * will be non-zero only if the user has allocated a buffer with
+ * a single fd, but logically partitioned it into
+ * multiple planes or buffers.*/
+ paddr += meta_frame->frame.mp[i].addr_offset;
+ meta_frame->map[i].paddr = paddr;
+ meta_frame->map[i].len = len;
+ D("%s Plane %d fd %d handle %p paddr %x", __func__,
+ i, meta_frame->frame.mp[i].fd,
+ meta_frame->map[i].handle,
+ (uint32_t)meta_frame->map[i].paddr);
+ }
+ D("%s Frame mapped successfully ", __func__);
+ return 0;
+}
+#else
+/* Unmap using PMEM APIs */
+static int __msm_mctl_unmap_user_frame(struct msm_cam_meta_frame *meta_frame,
+ struct ion_client *client, int domain_num)
+{
+ int i = 0, rc = 0;
+
+ for (i = 0; i < meta_frame->frame.num_planes; i++) {
+ D("%s Plane %d handle %p", __func__, i,
+ meta_frame->map[i].handle);
+ put_pmem_file(meta_frame->map[i].file);
+ }
+}
+
+/* Map using PMEM APIs */
+static int __msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
+ struct ion_client *client, int domain_num)
+{
+ unsigned long kvstart = 0;
+ unsigned long paddr = 0;
+ struct file *file = NULL;
+ unsigned long len;
+ int i = 0, j = 0;
+
+ for (i = 0; i < meta_frame->frame.num_planes; i++) {
+ rc = get_pmem_file(meta_frame->frame.mp[i].fd,
+ &paddr, &kvstart, &len, &file);
+ if (rc < 0) {
+ pr_err("%s: get_pmem_file fd %d error %d\n",
+ __func__, meta_frame->frame.mp[i].fd, rc);
+ /* Roll back previous plane mappings, if any */
+ for (j = i-1; j >= 0; j--)
+ if (meta_frame->map[j].file)
+ put_pmem_file(meta_frame->map[j].file);
+
+ return -EACCES;
+ }
+ D("%s Got pmem file for fd %d plane %d as %p", __func__,
+ meta_frame->frame.mp[i].fd, i, file);
+ meta_frame->map[i].file = file;
+ /* Validate the offsets with the mapped length. */
+ if ((meta_frame->frame.mp[i].addr_offset > len) ||
+ (meta_frame->frame.mp[i].data_offset +
+ meta_frame->frame.mp[i].length > len)) {
+ pr_err("%s: Invalid offsets A %d D %d L %d len %ld",
+ __func__, meta_frame->frame.mp[i].addr_offset,
+ meta_frame->frame.mp[i].data_offset,
+ meta_frame->frame.mp[i].length, len);
+ /* Roll back previous plane mappings, if any */
+ for (j = i; j >= 0; j--)
+ if (meta_frame->map[j].file)
+ put_pmem_file(meta_frame->map[j].file);
+
+ return -EINVAL;
+ }
+ meta_frame->map[i].data_offset =
+ meta_frame->frame.mp[i].data_offset;
+ /* Add the addr_offset to the paddr here itself. The addr_offset
+ * will be non-zero only if the user has allocated a buffer with
+ * a single fd, but logically partitioned it into
+ * multiple planes or buffers.*/
+ paddr += meta_frame->frame.mp[i].addr_offset;
+ meta_frame->map[i].paddr = paddr;
+ meta_frame->map[i].len = len;
+ D("%s Plane %d fd %d handle %p paddr %x", __func__,
+ i, meta_frame->frame.mp[i].fd,
+ meta_frame->map[i].handle,
+ (uint32_t)meta_frame->map[i].paddr);
+ }
+ D("%s Frame mapped successfully ", __func__);
+ return 0;
+}
+#endif
+
+int msm_mctl_map_user_frame(struct msm_cam_meta_frame *meta_frame,
+ struct ion_client *client, int domain_num)
+{
+
+ if ((NULL == meta_frame) || (NULL == client)) {
+ pr_err("%s Invalid input ", __func__);
+ return -EINVAL;
+ }
+
+ memset(&meta_frame->map[0], 0,
+ sizeof(struct msm_cam_buf_map_info) * VIDEO_MAX_PLANES);
+
+ return __msm_mctl_map_user_frame(meta_frame, client, domain_num);
+}
+
+int msm_mctl_unmap_user_frame(struct msm_cam_meta_frame *meta_frame,
+ struct ion_client *client, int domain_num)
+{
+ if ((NULL == meta_frame) || (NULL == client)) {
+ pr_err("%s Invalid input ", __func__);
+ return -EINVAL;
+ }
+ __msm_mctl_unmap_user_frame(meta_frame, client, domain_num);
+ return 0;
+}
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index dcb7c51..1f5b739 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -364,49 +364,6 @@
return 0;
}
-static int msm_mctl_pp_copy_timestamp_and_frame_id(
- uint32_t src_handle, uint32_t dest_handle)
-{
- struct msm_frame_buffer *src_vb;
- struct msm_frame_buffer *dest_vb;
-
- src_vb = (struct msm_frame_buffer *)src_handle;
- dest_vb = (struct msm_frame_buffer *)dest_handle;
- dest_vb->vidbuf.v4l2_buf.timestamp =
- src_vb->vidbuf.v4l2_buf.timestamp;
- dest_vb->vidbuf.v4l2_buf.sequence =
- src_vb->vidbuf.v4l2_buf.sequence;
- D("%s: timestamp=%ld:%ld,frame_id=0x%x", __func__,
- dest_vb->vidbuf.v4l2_buf.timestamp.tv_sec,
- dest_vb->vidbuf.v4l2_buf.timestamp.tv_usec,
- dest_vb->vidbuf.v4l2_buf.sequence);
- return 0;
-}
-
-static int msm_mctl_pp_path_to_inst_index(struct msm_cam_v4l2_device *pcam,
- int out_type)
-{
- int image_mode;
- switch (out_type) {
- case OUTPUT_TYPE_P:
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
- break;
- case OUTPUT_TYPE_V:
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
- break;
- case OUTPUT_TYPE_S:
- image_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
- break;
- default:
- image_mode = -1;
- break;
- }
- if ((image_mode >= 0) && pcam->dev_inst_map[image_mode])
- return pcam->dev_inst_map[image_mode]->my_index;
- else
- return -EINVAL;
-}
-
static int msm_mctl_pp_path_to_img_mode(int path)
{
switch (path) {
@@ -418,6 +375,16 @@
return MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
case OUTPUT_TYPE_T:
return MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL;
+ case OUTPUT_TYPE_SAEC:
+ return MSM_V4L2_EXT_CAPTURE_MODE_AEC;
+ case OUTPUT_TYPE_SAWB:
+ return MSM_V4L2_EXT_CAPTURE_MODE_AWB;
+ case OUTPUT_TYPE_SAFC:
+ return MSM_V4L2_EXT_CAPTURE_MODE_AF;
+ case OUTPUT_TYPE_IHST:
+ return MSM_V4L2_EXT_CAPTURE_MODE_IHIST;
+ case OUTPUT_TYPE_CSTA:
+ return MSM_V4L2_EXT_CAPTURE_MODE_CSTA;
default:
return -EINVAL;
}
@@ -615,6 +582,7 @@
struct msm_free_buf buf;
unsigned long flags;
struct msm_cam_buf_handle buf_handle;
+ struct msm_cam_return_frame_info ret_frame;
if (copy_from_user(&frame, arg, sizeof(frame))) {
ERR_COPY_FROM_USER();
@@ -657,7 +625,11 @@
buf.ch_paddr[0] = frame.sp.phy_addr + frame.sp.y_off;
}
spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
- rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, dirty, 0);
+
+ ret_frame.dirty = dirty;
+ ret_frame.node_type = 0;
+ ret_frame.timestamp = frame.timestamp;
+ rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, &ret_frame);
return rc;
}
@@ -667,10 +639,10 @@
{
struct msm_pp_frame frame;
int msg_type, image_mode, rc = 0;
- int dirty = 0;
struct msm_free_buf buf;
unsigned long flags;
struct msm_cam_buf_handle buf_handle;
+ struct msm_cam_return_frame_info ret_frame;
D("%s enter\n", __func__);
@@ -698,6 +670,22 @@
msg_type = VFE_MSG_OUTPUT_T;
image_mode = MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL;
break;
+ case OUTPUT_TYPE_SAEC:
+ msg_type = VFE_MSG_STATS_AEC;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_AEC;
+ break;
+ case OUTPUT_TYPE_SAWB:
+ msg_type = VFE_MSG_STATS_AWB;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_AWB;
+ break;
+ case OUTPUT_TYPE_SAFC:
+ msg_type = VFE_MSG_STATS_AF;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_AF;
+ break;
+ case OUTPUT_TYPE_IHST:
+ msg_type = VFE_MSG_STATS_IHIST;
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_IHIST;
+ break;
default:
rc = -EFAULT;
goto err;
@@ -718,9 +706,12 @@
buf.ch_paddr[0] = frame.sp.phy_addr + frame.sp.y_off;
spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
+
+ ret_frame.dirty = 0;
+ ret_frame.node_type = frame.node_type;
+ ret_frame.timestamp = frame.timestamp;
D("%s Frame done id: %d\n", __func__, frame.frame_id);
- rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle,
- &buf, dirty, frame.node_type);
+ rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, &ret_frame);
return rc;
err:
spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
@@ -755,54 +746,3 @@
return rc;
}
-
-int msm_mctl_pp_get_vpe_buf_info(struct msm_mctl_pp_frame_info *zoom)
-{
- struct msm_cam_media_controller *p_mctl;
- struct msm_cam_v4l2_dev_inst *pcam_inst;
- int rc = 0, idx;
-
- if (!zoom || !zoom->p_mctl) {
- pr_err("%s Invalid input, not sending buffer to VPE ",
- __func__);
- return -EINVAL;
- }
- p_mctl = zoom->p_mctl;
- idx = msm_mctl_pp_path_to_inst_index(p_mctl->pcam_ptr,
- zoom->pp_frame_cmd.path);
- if (idx < 0) {
- pr_err("%s Invalid path, returning\n", __func__);
- return idx;
- }
- pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
- if (!pcam_inst) {
- pr_err("%s Invalid instance, returning\n", __func__);
- return -EINVAL;
- }
-
- rc = msm_mctl_pp_get_phy_addr(pcam_inst,
- zoom->pp_frame_cmd.src_buf_handle, &zoom->src_frame);
- if (rc) {
- pr_err("%s Error getting buffer address for src frame\n",
- __func__);
- return rc;
- }
-
- rc = msm_mctl_pp_get_phy_addr(pcam_inst,
- zoom->pp_frame_cmd.dest_buf_handle, &zoom->dest_frame);
- if (rc) {
- pr_err("%s Error getting buffer address for dest frame\n",
- __func__);
- return rc;
- }
-
- rc = msm_mctl_pp_copy_timestamp_and_frame_id(
- zoom->pp_frame_cmd.src_buf_handle,
- zoom->pp_frame_cmd.dest_buf_handle);
- if (rc < 0) {
- pr_err("%s Error copying timestamp info\n",
- __func__);
- return rc;
- }
- return rc;
-}
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index e2e9d1b..5136d9d 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -116,7 +116,7 @@
}
static int msm_pmem_table_add(struct hlist_head *ptype,
- struct msm_pmem_info *info, struct ion_client *client)
+ struct msm_pmem_info *info, struct ion_client *client, int domain_num)
{
unsigned long paddr;
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -135,7 +135,7 @@
region->handle = ion_import_dma_buf(client, info->fd);
if (IS_ERR_OR_NULL(region->handle))
goto out1;
- if (ion_map_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL,
+ if (ion_map_iommu(client, region->handle, domain_num, 0,
SZ_4K, 0, &paddr, &len, UNCACHED, 0) < 0)
goto out2;
#elif CONFIG_ANDROID_PMEM
@@ -180,7 +180,7 @@
return 0;
out3:
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- ion_unmap_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL);
+ ion_unmap_iommu(client, region->handle, domain_num, 0);
#endif
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
out2:
@@ -195,7 +195,8 @@
}
static int __msm_register_pmem(struct hlist_head *ptype,
- struct msm_pmem_info *pinfo, struct ion_client *client)
+ struct msm_pmem_info *pinfo, struct ion_client *client,
+ int domain_num)
{
int rc = 0;
@@ -211,7 +212,7 @@
case MSM_PMEM_BAYER_GRID:
case MSM_PMEM_BAYER_FOCUS:
case MSM_PMEM_BAYER_HIST:
- rc = msm_pmem_table_add(ptype, pinfo, client);
+ rc = msm_pmem_table_add(ptype, pinfo, client, domain_num);
break;
default:
@@ -223,7 +224,8 @@
}
static int __msm_pmem_table_del(struct hlist_head *ptype,
- struct msm_pmem_info *pinfo, struct ion_client *client)
+ struct msm_pmem_info *pinfo, struct ion_client *client,
+ int domain_num)
{
int rc = 0;
struct msm_pmem_region *region;
@@ -250,7 +252,7 @@
hlist_del(node);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_unmap_iommu(client, region->handle,
- CAMERA_DOMAIN, GEN_POOL);
+ domain_num, 0);
ion_free(client, region->handle);
#else
put_pmem_file(region->file);
@@ -394,7 +396,8 @@
}
int msm_register_pmem(struct hlist_head *ptype, void __user *arg,
- struct ion_client *client)
+ struct ion_client *client,
+ int domain_num)
{
struct msm_pmem_info info;
@@ -403,12 +406,12 @@
return -EFAULT;
}
- return __msm_register_pmem(ptype, &info, client);
+ return __msm_register_pmem(ptype, &info, client, domain_num);
}
//EXPORT_SYMBOL(msm_register_pmem);
int msm_pmem_table_del(struct hlist_head *ptype, void __user *arg,
- struct ion_client *client)
+ struct ion_client *client, int domain_num)
{
struct msm_pmem_info info;
@@ -417,6 +420,6 @@
return -EFAULT;
}
- return __msm_pmem_table_del(ptype, &info, client);
+ return __msm_pmem_table_del(ptype, &info, client, domain_num);
}
//EXPORT_SYMBOL(msm_pmem_table_del);
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 5990ca7..ede0f7a 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -36,8 +36,8 @@
#define D(fmt, args...) do {} while (0)
#endif
-static int vpe_enable(uint32_t);
-static int vpe_disable(void);
+static int vpe_enable(uint32_t, struct msm_cam_media_controller *);
+static int vpe_disable(struct msm_cam_media_controller *);
static int vpe_update_scaler(struct msm_pp_crop *pcrop);
struct vpe_ctrl_type *vpe_ctrl;
static atomic_t vpe_init_done = ATOMIC_INIT(0);
@@ -425,29 +425,37 @@
int rc = 0;
unsigned long flags;
unsigned long srcP0, srcP1, outP0, outP1;
- struct msm_mctl_pp_frame_info *frame = vpe_ctrl->pp_frame_info;
+ struct msm_mctl_pp_frame_info *frame_info = vpe_ctrl->pp_frame_info;
+
+ if (!frame_info) {
+ pr_err("%s Invalid frame", __func__);
+ return -EINVAL;
+ }
spin_lock_irqsave(&vpe_ctrl->lock, flags);
- if (frame->src_frame.num_planes > 1) {
- srcP0 = vpe_ctrl->pp_frame_info->src_frame.mp[0].phy_addr +
- vpe_ctrl->pp_frame_info->src_frame.mp[0].data_offset;
- srcP1 = vpe_ctrl->pp_frame_info->src_frame.mp[1].phy_addr +
- vpe_ctrl->pp_frame_info->src_frame.mp[1].data_offset;
- outP0 = vpe_ctrl->pp_frame_info->dest_frame.mp[0].phy_addr +
- vpe_ctrl->pp_frame_info->dest_frame.mp[0].data_offset;
- outP1 = vpe_ctrl->pp_frame_info->dest_frame.mp[1].phy_addr +
- vpe_ctrl->pp_frame_info->dest_frame.mp[1].data_offset;
+
+ if (frame_info->src_frame.frame.num_planes > 1) {
+ srcP0 = frame_info->src_frame.map[0].paddr +
+ frame_info->src_frame.map[0].data_offset;
+ srcP1 = frame_info->src_frame.map[1].paddr +
+ frame_info->src_frame.map[1].data_offset;
+ outP0 = frame_info->dest_frame.map[0].paddr +
+ frame_info->dest_frame.map[0].data_offset;
+ outP1 = frame_info->dest_frame.map[1].paddr +
+ frame_info->dest_frame.map[1].data_offset;
} else {
- srcP0 = vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
- vpe_ctrl->pp_frame_info->src_frame.sp.y_off;
- srcP1 = vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
- vpe_ctrl->pp_frame_info->src_frame.sp.cbcr_off;
- outP0 = vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
- vpe_ctrl->pp_frame_info->dest_frame.sp.y_off;
- outP1 = vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
- vpe_ctrl->pp_frame_info->dest_frame.sp.cbcr_off;
+ srcP0 = frame_info->src_frame.map[0].paddr;
+ srcP1 = frame_info->src_frame.map[0].paddr +
+ frame_info->src_frame.map[0].data_offset;
+ outP0 = frame_info->dest_frame.map[0].paddr;
+ outP1 = frame_info->dest_frame.map[0].paddr +
+ frame_info->dest_frame.map[0].data_offset;
}
+ D("%s VPE Configured with Src %x, %x Dest %x, %x",
+ __func__, (uint32_t)srcP0, (uint32_t)srcP1,
+ (uint32_t)outP0, (uint32_t)outP1);
+
msm_camera_io_w(srcP0, vpe_ctrl->vpebase + VPE_SRCP0_ADDR_OFFSET);
msm_camera_io_w(srcP1, vpe_ctrl->vpebase + VPE_SRCP1_ADDR_OFFSET);
msm_camera_io_w(outP0, vpe_ctrl->vpebase + VPE_OUTP0_ADDR_OFFSET);
@@ -482,7 +490,6 @@
v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MCTL_PP_EVENT;
v4l2_evt.id = 0;
v4l2_event_queue(vpe_ctrl->subdev.devnode, &v4l2_evt);
-
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
}
@@ -513,7 +520,7 @@
{"vpe_pclk", -1},
};
-int vpe_enable(uint32_t clk_rate)
+int vpe_enable(uint32_t clk_rate, struct msm_cam_media_controller *mctl)
{
int rc = 0;
unsigned long flags = 0;
@@ -542,8 +549,27 @@
if (rc < 0)
goto vpe_clk_failed;
+#ifdef CONFIG_MSM_IOMMU
+ rc = iommu_attach_device(mctl->domain, vpe_ctrl->iommu_ctx_src);
+ if (rc < 0) {
+ pr_err("%s: Device attach failed\n", __func__);
+ goto src_attach_failed;
+ }
+ rc = iommu_attach_device(mctl->domain, vpe_ctrl->iommu_ctx_dst);
+ if (rc < 0) {
+ pr_err("%s: Device attach failed\n", __func__);
+ goto dst_attach_failed;
+ }
+#endif
return rc;
+#ifdef CONFIG_MSM_IOMMU
+dst_attach_failed:
+ iommu_detach_device(mctl->domain, vpe_ctrl->iommu_ctx_src);
+src_attach_failed:
+#endif
+ msm_cam_clk_enable(&vpe_ctrl->pdev->dev, vpe_clk_info,
+ vpe_ctrl->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0);
vpe_clk_failed:
if (vpe_ctrl->fs_vpe)
regulator_disable(vpe_ctrl->fs_vpe);
@@ -553,7 +579,7 @@
return rc;
}
-int vpe_disable(void)
+int vpe_disable(struct msm_cam_media_controller *mctl)
{
int rc = 0;
unsigned long flags = 0;
@@ -565,7 +591,10 @@
return rc;
}
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
-
+#ifdef CONFIG_MSM_IOMMU
+ iommu_detach_device(mctl->domain, vpe_ctrl->iommu_ctx_dst);
+ iommu_detach_device(mctl->domain, vpe_ctrl->iommu_ctx_src);
+#endif
disable_irq(vpe_ctrl->vpeirq->start);
tasklet_kill(&vpe_tasklet);
msm_cam_clk_enable(&vpe_ctrl->pdev->dev, vpe_clk_info,
@@ -596,8 +625,8 @@
msm_vpe_cfg_update(
&vpe_ctrl->pp_frame_info->pp_frame_cmd.crop);
D("%s Sending frame idx %d id %d to VPE ", __func__,
- pp_frame_info->src_frame.buf_idx,
- pp_frame_info->src_frame.frame_id);
+ pp_frame_info->src_frame.frame.buf_idx,
+ pp_frame_info->src_frame.frame.frame_id);
rc = msm_send_frame_to_vpe();
return rc;
}
@@ -648,23 +677,25 @@
return rc; /* this rc should have error code. */
}
-void msm_vpe_subdev_release(void)
+void msm_vpe_subdev_release(struct v4l2_subdev *sd)
{
+ struct msm_cam_media_controller *mctl;
+ mctl = v4l2_get_subdev_hostdata(sd);
if (!atomic_read(&vpe_init_done)) {
/* no VPE object created */
pr_err("%s: no VPE object to release", __func__);
return;
}
-
vpe_reset();
- vpe_disable();
+ vpe_disable(mctl);
iounmap(vpe_ctrl->vpebase);
vpe_ctrl->vpebase = NULL;
atomic_set(&vpe_init_done, 0);
}
EXPORT_SYMBOL(msm_vpe_subdev_release);
-static int msm_vpe_process_vpe_cmd(struct msm_vpe_cfg_cmd *vpe_cmd)
+static int msm_vpe_process_vpe_cmd(struct msm_vpe_cfg_cmd *vpe_cmd,
+ struct msm_cam_media_controller *mctl)
{
int rc = 0;
@@ -787,19 +818,35 @@
zoom->user_cmd = vpe_cmd->cmd_type;
zoom->p_mctl = v4l2_get_subdev_hostdata(&vpe_ctrl->subdev);
- D("%s: src=0x%x, dest=0x%x,cookie=0x%x,action=0x%x,path=0x%x",
- __func__, zoom->pp_frame_cmd.src_buf_handle,
- zoom->pp_frame_cmd.dest_buf_handle,
- zoom->pp_frame_cmd.cookie,
+ D("%s: cookie=0x%x,action=0x%x,path=0x%x",
+ __func__, zoom->pp_frame_cmd.cookie,
zoom->pp_frame_cmd.vpe_output_action,
zoom->pp_frame_cmd.path);
- rc = msm_mctl_pp_get_vpe_buf_info(zoom);
+
+ D("%s Mapping Source frame ", __func__);
+ zoom->src_frame.frame = zoom->pp_frame_cmd.src_frame;
+ rc = msm_mctl_map_user_frame(&zoom->src_frame,
+ zoom->p_mctl->client, mctl->domain_num);
if (rc < 0) {
- pr_err("%s Error getting buffer info from mctl rc = %d",
+ pr_err("%s Error mapping source buffer rc = %d",
__func__, rc);
kfree(zoom);
break;
}
+
+ D("%s Mapping Destination frame ", __func__);
+ zoom->dest_frame.frame = zoom->pp_frame_cmd.dest_frame;
+ rc = msm_mctl_map_user_frame(&zoom->dest_frame,
+ zoom->p_mctl->client, mctl->domain_num);
+ if (rc < 0) {
+ pr_err("%s Error mapping dest buffer rc = %d",
+ __func__, rc);
+ msm_mctl_unmap_user_frame(&zoom->src_frame,
+ zoom->p_mctl->client, mctl->domain_num);
+ kfree(zoom);
+ break;
+ }
+
rc = msm_vpe_do_pp(zoom);
break;
}
@@ -820,13 +867,13 @@
return -EFAULT;
}
turbo_mode = (int)clk_rate.rate;
- rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) :
- vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
+ rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE, mctl) :
+ vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE, mctl);
break;
}
case VPE_CMD_DISABLE:
- rc = vpe_disable();
+ rc = vpe_disable(mctl);
break;
default:
@@ -841,7 +888,8 @@
{
struct msm_vpe_cfg_cmd *vpe_cmd;
int rc = 0;
-
+ struct msm_cam_media_controller *mctl;
+ mctl = v4l2_get_subdev_hostdata(sd);
switch (cmd) {
case VIDIOC_MSM_VPE_INIT: {
msm_vpe_subdev_init(sd);
@@ -849,12 +897,12 @@
}
case VIDIOC_MSM_VPE_RELEASE:
- msm_vpe_subdev_release();
+ msm_vpe_subdev_release(sd);
break;
case MSM_CAM_V4L2_IOCTL_CFG_VPE: {
vpe_cmd = (struct msm_vpe_cfg_cmd *)arg;
- rc = msm_vpe_process_vpe_cmd(vpe_cmd);
+ rc = msm_vpe_process_vpe_cmd(vpe_cmd, mctl);
if (rc < 0) {
pr_err("%s Error processing VPE cmd %d ",
__func__, vpe_cmd->cmd_type);
@@ -876,6 +924,14 @@
return -EFAULT;
}
pp_frame_info = event_qcmd->command;
+
+ D("%s Unmapping source and destination buffers ",
+ __func__);
+ msm_mctl_unmap_user_frame(&pp_frame_info->src_frame,
+ pp_frame_info->p_mctl->client, mctl->domain_num);
+ msm_mctl_unmap_user_frame(&pp_frame_info->dest_frame,
+ pp_frame_info->p_mctl->client, mctl->domain_num);
+
pp_event_info.event = MCTL_PP_EVENT_CMD_ACK;
pp_event_info.ack.cmd = pp_frame_info->user_cmd;
pp_event_info.ack.status = 0;
@@ -884,10 +940,9 @@
pp_event_info.ack.cmd, pp_event_info.ack.status,
pp_event_info.ack.cookie);
if (copy_to_user((void __user *)v4l2_ioctl->ioctl_ptr,
- &pp_event_info,
- sizeof(struct msm_mctl_pp_event_info)))
- pr_err("%s EVENTPAYLOAD Copy to user failed ",
- __func__);
+ &pp_event_info, sizeof(struct msm_mctl_pp_event_info)))
+ pr_err("%s PAYLOAD Copy to user failed ", __func__);
+
kfree(pp_frame_info);
kfree(event_qcmd);
break;
@@ -942,12 +997,22 @@
struct v4l2_subdev_fh *fh)
{
struct vpe_ctrl_type *vpe_ctrl = v4l2_get_subdevdata(sd);
+ struct msm_mctl_pp_frame_info *frame_info = vpe_ctrl->pp_frame_info;
+ struct msm_cam_media_controller *mctl;
+ mctl = v4l2_get_subdev_hostdata(sd);
if (atomic_read(&vpe_ctrl->active) == 0) {
pr_err("%s already closed\n", __func__);
return -EINVAL;
}
D("%s E ", __func__);
+ if (frame_info) {
+ D("%s Unmap the pending item from the queue ", __func__);
+ msm_mctl_unmap_user_frame(&frame_info->src_frame,
+ frame_info->p_mctl->client, mctl->domain_num);
+ msm_mctl_unmap_user_frame(&frame_info->dest_frame,
+ frame_info->p_mctl->client, mctl->domain_num);
+ }
/* Drain the payload queue. */
msm_queue_drain(&vpe_ctrl->eventData_q, list_eventdata);
atomic_dec(&vpe_ctrl->active);
@@ -1027,6 +1092,19 @@
disable_irq(vpe_ctrl->vpeirq->start);
+#ifdef CONFIG_MSM_IOMMU
+ /*get device context for IOMMU*/
+ vpe_ctrl->iommu_ctx_src = msm_iommu_get_ctx("vpe_src"); /*re-confirm*/
+ vpe_ctrl->iommu_ctx_dst = msm_iommu_get_ctx("vpe_dst"); /*re-confirm*/
+ if (!vpe_ctrl->iommu_ctx_src || !vpe_ctrl->iommu_ctx_dst) {
+ release_mem_region(vpe_ctrl->vpemem->start,
+ resource_size(vpe_ctrl->vpemem));
+ pr_err("%s: No iommu fw context found\n", __func__);
+ rc = -ENODEV;
+ goto vpe_no_resource;
+ }
+#endif
+
atomic_set(&vpe_ctrl->active, 0);
vpe_ctrl->pdev = pdev;
sd_info.sdev_type = VPE_DEV;
diff --git a/drivers/media/video/msm/msm_vpe.h b/drivers/media/video/msm/msm_vpe.h
index 6516ea1..aad2380 100644
--- a/drivers/media/video/msm/msm_vpe.h
+++ b/drivers/media/video/msm/msm_vpe.h
@@ -121,6 +121,8 @@
struct msm_mctl_pp_frame_info *pp_frame_info;
atomic_t active;
struct msm_device_queue eventData_q; /*V4L2 Event Payload Queue*/
+ struct device *iommu_ctx_src;
+ struct device *iommu_ctx_dst;
};
/*
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 5f3f6dd..cd228a1 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -3,12 +3,11 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/io
EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
-obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
+obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor_common.o msm_sensor.o msm_sensor_bayer.o msm_sensor_init.o
obj-$(CONFIG_OV5647) += ov5647_v4l2.o
obj-$(CONFIG_OV8825) += ov8825_v4l2.o
obj-$(CONFIG_IMX074) += imx074_v4l2.o
obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
-obj-$(CONFIG_IMX091) += imx091.o
obj-$(CONFIG_OV2720) += ov2720.o
obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index ddf0754..91d4797 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -168,44 +168,6 @@
},
};
-static struct msm_camera_csi_params imx074_csic_params = {
- .data_format = CSI_10BIT,
- .lane_cnt = 4,
- .lane_assign = 0xe4,
- .dpcm_scheme = 0,
- .settle_cnt = 0x14,
-};
-
-static struct msm_camera_csi_params *imx074_csic_params_array[] = {
- &imx074_csic_params,
- &imx074_csic_params,
-};
-
-static struct msm_camera_csid_vc_cfg imx074_cid_cfg[] = {
- {0, CSI_RAW10, CSI_DECODE_10BIT},
- {1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
- {2, CSI_RESERVED_DATA_0, CSI_DECODE_8BIT},
-};
-
-static struct msm_camera_csi2_params imx074_csi_params = {
- .csid_params = {
- .lane_cnt = 4,
- .lut_params = {
- .num_cid = ARRAY_SIZE(imx074_cid_cfg),
- .vc_cfg = imx074_cid_cfg,
- },
- },
- .csiphy_params = {
- .lane_cnt = 4,
- .settle_cnt = 0x1B,
- },
-};
-
-static struct msm_camera_csi2_params *imx074_csi_params_array[] = {
- &imx074_csi_params,
- &imx074_csi_params,
-};
-
static struct msm_sensor_output_reg_addr_t imx074_reg_addr = {
.x_output = 0x34C,
.y_output = 0x34E,
@@ -224,6 +186,13 @@
.vert_offset = 3,
};
+static enum msm_camera_vreg_name_t imx074_veg_seq[] = {
+ CAM_VDIG,
+ CAM_VIO,
+ CAM_VANA,
+ CAM_VAF,
+};
+
static const struct i2c_device_id imx074_i2c_id[] = {
{SENSOR_NAME, (kernel_ulong_t)&imx074_s_ctrl},
{ }
@@ -302,12 +271,12 @@
.msm_sensor_reg = &imx074_regs,
.sensor_i2c_client = &imx074_sensor_i2c_client,
.sensor_i2c_addr = 0x34,
+ .vreg_seq = imx074_veg_seq,
+ .num_vreg_seq = ARRAY_SIZE(imx074_veg_seq),
.sensor_output_reg_addr = &imx074_reg_addr,
.sensor_id_info = &imx074_id_info,
.sensor_exp_gain_info = &imx074_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csic_params = &imx074_csic_params_array[0],
- .csi_params = &imx074_csi_params_array[0],
.msm_sensor_mutex = &imx074_mut,
.sensor_i2c_driver = &imx074_i2c_driver,
.sensor_v4l2_subdev_info = imx074_subdev_info,
diff --git a/drivers/media/video/msm/sensors/imx091.c b/drivers/media/video/msm/sensors/imx091.c
deleted file mode 100644
index 7fda037..0000000
--- a/drivers/media/video/msm/sensors/imx091.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/* 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_sensor.h"
-#define SENSOR_NAME "imx091"
-#define PLATFORM_DRIVER_NAME "msm_camera_imx091"
-#define imx091_obj imx091_##obj
-
-DEFINE_MUTEX(imx091_mut);
-static struct msm_sensor_ctrl_t imx091_s_ctrl;
-
-static struct msm_camera_i2c_reg_conf imx091_start_settings[] = {
- {0x0100, 0x01},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_stop_settings[] = {
- {0x0100, 0x00},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_groupon_settings[] = {
- {0x0104, 0x01},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_groupoff_settings[] = {
- {0x0104, 0x00},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_prev_settings[] = {
- /* 30fps 1/2 * 1/2 */
- /* PLL setting */
- {0x0305, 0x02}, /* pre_pll_clk_div[7:0] */
- {0x0307, 0x2F}, /* pll_multiplier[7:0] */
- {0x30A4, 0x02},
- {0x303C, 0x4B},
- /* mode setting */
- {0x0340, 0x06}, /* frame_length_lines[15:8] */
- {0x0341, 0x5A}, /* frame_length_lines[7:0] */
- {0x0342, 0x12}, /* line_length_pck[15:8] */
- {0x0343, 0x0C}, /* line_length_pck[7:0] */
- {0x0344, 0x00}, /* x_addr_start[15:8] */
- {0x0345, 0x08}, /* x_addr_start[7:0] */
- {0x0346, 0x00}, /* y_addr_start[15:8] */
- {0x0347, 0x30}, /* y_addr_start[7:0] */
- {0x0348, 0x10}, /* x_addr_end[15:8] */
- {0x0349, 0x77}, /* x_addr_end[7:0] */
- {0x034A, 0x0C}, /* y_addr_end[15:8] */
- {0x034B, 0x5F}, /* y_addr_end[7:0] */
- {0x034C, 0x08}, /* x_output_size[15:8] */
- {0x034D, 0x38}, /* x_output_size[7:0] */
- {0x034E, 0x06}, /* y_output_size[15:8] */
- {0x034F, 0x18}, /* y_output_size[7:0] */
- {0x0381, 0x01}, /* x_even_inc[3:0] */
- {0x0383, 0x03}, /* x_odd_inc[3:0] */
- {0x0385, 0x01}, /* y_even_inc[7:0] */
- {0x0387, 0x03}, /* y_odd_inc[7:0] */
- {0x3040, 0x08},
- {0x3041, 0x97},
- {0x3048, 0x01},
- {0x3064, 0x12},
- {0x309B, 0x28},
- {0x309E, 0x00},
- {0x30D5, 0x09},
- {0x30D6, 0x01},
- {0x30D7, 0x01},
- {0x30D8, 0x64},
- {0x30D9, 0x89},
- {0x30DE, 0x02},
- {0x3102, 0x10},
- {0x3103, 0x44},
- {0x3104, 0x40},
- {0x3105, 0x00},
- {0x3106, 0x0D},
- {0x3107, 0x01},
- {0x310A, 0x0A},
- {0x315C, 0x99},
- {0x315D, 0x98},
- {0x316E, 0x9A},
- {0x316F, 0x99},
- {0x3318, 0x73},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_snap_settings[] = {
- /* full size */
- /* PLL setting */
- {0x0305, 0x02}, /* pre_pll_clk_div[7:0] */
- {0x0307, 0x2B}, /* pll_multiplier[7:0] */
- {0x30A4, 0x02},
- {0x303C, 0x4B},
- /* mode setting */
- {0x0340, 0x0C}, /* frame_length_lines[15:8] */
- {0x0341, 0x8C}, /* frame_length_lines[7:0] */
- {0x0342, 0x12}, /* line_length_pck[15:8] */
- {0x0343, 0x0C}, /* line_length_pck[7:0] */
- {0x0344, 0x00}, /* x_addr_start[15:8] */
- {0x0345, 0x08}, /* x_addr_start[7:0] */
- {0x0346, 0x00}, /* y_addr_start[15:8] */
- {0x0347, 0x30}, /* y_addr_start[7:0] */
- {0x0348, 0x10}, /* x_addr_end[15:8] */
- {0x0349, 0x77}, /* x_addr_end[7:0] */
- {0x034A, 0x0C}, /* y_addr_end[15:8] */
- {0x034B, 0x5F}, /* y_addr_end[7:0] */
- {0x034C, 0x10}, /* x_output_size[15:8] */
- {0x034D, 0x70}, /* x_output_size[7:0] */
- {0x034E, 0x0C}, /* y_output_size[15:8] */
- {0x034F, 0x30}, /* y_output_size[7:0] */
- {0x0381, 0x01}, /* x_even_inc[3:0] */
- {0x0383, 0x01}, /* x_odd_inc[3:0] */
- {0x0385, 0x01}, /* y_even_inc[7:0] */
- {0x0387, 0x01}, /* y_odd_inc[7:0] */
- {0x3040, 0x08},
- {0x3041, 0x97},
- {0x3048, 0x00},
- {0x3064, 0x12},
- {0x309B, 0x20},
- {0x309E, 0x00},
- {0x30D5, 0x00},
- {0x30D6, 0x85},
- {0x30D7, 0x2A},
- {0x30D8, 0x64},
- {0x30D9, 0x89},
- {0x30DE, 0x00},
- {0x3102, 0x10},
- {0x3103, 0x44},
- {0x3104, 0x40},
- {0x3105, 0x00},
- {0x3106, 0x0D},
- {0x3107, 0x01},
- {0x310A, 0x0A},
- {0x315C, 0x99},
- {0x315D, 0x98},
- {0x316E, 0x9A},
- {0x316F, 0x99},
- {0x3318, 0x64},
-};
-
-static struct msm_camera_i2c_reg_conf imx091_recommend_settings[] = {
- /* global setting */
- {0x3087, 0x53},
- {0x309D, 0x94},
- {0x30A1, 0x08},
- {0x30C7, 0x00},
- {0x3115, 0x0E},
- {0x3118, 0x42},
- {0x311D, 0x34},
- {0x3121, 0x0D},
- {0x3212, 0xF2},
- {0x3213, 0x0F},
- {0x3215, 0x0F},
- {0x3217, 0x0B},
- {0x3219, 0x0B},
- {0x321B, 0x0D},
- {0x321D, 0x0D},
- /* black level setting */
- {0x3032, 0x40},
-};
-
-static struct v4l2_subdev_info imx091_subdev_info[] = {
- {
- .code = V4L2_MBUS_FMT_SBGGR10_1X10,
- .colorspace = V4L2_COLORSPACE_JPEG,
- .fmt = 1,
- .order = 0,
- },
- /* more can be supported, to be added later */
-};
-
-static struct msm_camera_i2c_conf_array imx091_init_conf[] = {
- {&imx091_recommend_settings[0],
- ARRAY_SIZE(imx091_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
-};
-
-static struct msm_camera_i2c_conf_array imx091_confs[] = {
- {&imx091_snap_settings[0],
- ARRAY_SIZE(imx091_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
- {&imx091_prev_settings[0],
- ARRAY_SIZE(imx091_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
-};
-
-static struct msm_sensor_output_info_t imx091_dimensions[] = {
- {
- /* full size */
- .x_output = 0x1070, /* 4208 */
- .y_output = 0x0C30, /* 3120 */
- .line_length_pclk = 0x120C, /* 4620 */
- .frame_length_lines = 0x0C8C, /* 3212 */
- .vt_pixel_clk = 206400000,
- .op_pixel_clk = 206400000,
- .binning_factor = 1,
- },
- {
- /* 30 fps 1/2 * 1/2 */
- .x_output = 0x0838, /* 2104 */
- .y_output = 0x0618, /* 1560 */
- .line_length_pclk = 0x120C, /* 4620 */
- .frame_length_lines = 0x065A, /* 1626 */
- .vt_pixel_clk = 225600000,
- .op_pixel_clk = 225600000,
- .binning_factor = 1,
- },
-};
-
-static struct msm_camera_csid_vc_cfg imx091_cid_cfg[] = {
- {0, CSI_RAW10, CSI_DECODE_10BIT},
- {1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
- {2, CSI_RESERVED_DATA_0, CSI_DECODE_8BIT},
-};
-
-static struct msm_camera_csi2_params imx091_csi_params = {
- .csid_params = {
- .lane_cnt = 4,
- .lut_params = {
- .num_cid = ARRAY_SIZE(imx091_cid_cfg),
- .vc_cfg = imx091_cid_cfg,
- },
- },
- .csiphy_params = {
- .lane_cnt = 4,
- .settle_cnt = 0x12,
- },
-};
-
-static struct msm_camera_csi2_params *imx091_csi_params_array[] = {
- &imx091_csi_params,
- &imx091_csi_params,
-};
-
-static struct msm_sensor_output_reg_addr_t imx091_reg_addr = {
- .x_output = 0x034C,
- .y_output = 0x034E,
- .line_length_pclk = 0x0342,
- .frame_length_lines = 0x0340,
-};
-
-static struct msm_sensor_id_info_t imx091_id_info = {
- .sensor_id_reg_addr = 0x0000,
- .sensor_id = 0x0091,
-};
-
-static struct msm_sensor_exp_gain_info_t imx091_exp_gain_info = {
- .coarse_int_time_addr = 0x0202,
- .global_gain_addr = 0x0204,
- .vert_offset = 5,
-};
-
-static const struct i2c_device_id imx091_i2c_id[] = {
- {SENSOR_NAME, (kernel_ulong_t)&imx091_s_ctrl},
- { }
-};
-
-static struct i2c_driver imx091_i2c_driver = {
- .id_table = imx091_i2c_id,
- .probe = msm_sensor_i2c_probe,
- .driver = {
- .name = SENSOR_NAME,
- },
-};
-
-static struct msm_camera_i2c_client imx091_sensor_i2c_client = {
- .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
-};
-
-
-static int __init imx091_sensor_init_module(void)
-{
- return i2c_add_driver(&imx091_i2c_driver);
-}
-
-static struct v4l2_subdev_core_ops imx091_subdev_core_ops = {
- .ioctl = msm_sensor_subdev_ioctl,
- .s_power = msm_sensor_power,
-};
-
-static struct v4l2_subdev_video_ops imx091_subdev_video_ops = {
- .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
-};
-
-static struct v4l2_subdev_ops imx091_subdev_ops = {
- .core = &imx091_subdev_core_ops,
- .video = &imx091_subdev_video_ops,
-};
-
-static struct msm_sensor_fn_t imx091_func_tbl = {
- .sensor_start_stream = msm_sensor_start_stream,
- .sensor_stop_stream = msm_sensor_stop_stream,
- .sensor_group_hold_on = msm_sensor_group_hold_on,
- .sensor_group_hold_off = msm_sensor_group_hold_off,
- .sensor_set_fps = msm_sensor_set_fps,
- .sensor_write_exp_gain = msm_sensor_write_exp_gain1,
- .sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1,
- .sensor_setting = msm_sensor_setting,
- .sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
- .sensor_mode_init = msm_sensor_mode_init,
- .sensor_get_output_info = msm_sensor_get_output_info,
- .sensor_config = msm_sensor_config,
- .sensor_power_up = msm_sensor_power_up,
- .sensor_power_down = msm_sensor_power_down,
- .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines1,
- .sensor_get_csi_params = msm_sensor_get_csi_params,
-};
-
-static struct msm_sensor_reg_t imx091_regs = {
- .default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
- .start_stream_conf = imx091_start_settings,
- .start_stream_conf_size = ARRAY_SIZE(imx091_start_settings),
- .stop_stream_conf = imx091_stop_settings,
- .stop_stream_conf_size = ARRAY_SIZE(imx091_stop_settings),
- .group_hold_on_conf = imx091_groupon_settings,
- .group_hold_on_conf_size = ARRAY_SIZE(imx091_groupon_settings),
- .group_hold_off_conf = imx091_groupoff_settings,
- .group_hold_off_conf_size = ARRAY_SIZE(imx091_groupoff_settings),
- .init_settings = &imx091_init_conf[0],
- .init_size = ARRAY_SIZE(imx091_init_conf),
- .mode_settings = &imx091_confs[0],
- .output_settings = &imx091_dimensions[0],
- .num_conf = ARRAY_SIZE(imx091_confs),
-};
-
-static struct msm_sensor_ctrl_t imx091_s_ctrl = {
- .msm_sensor_reg = &imx091_regs,
- .sensor_i2c_client = &imx091_sensor_i2c_client,
- .sensor_i2c_addr = 0x34,
- .sensor_output_reg_addr = &imx091_reg_addr,
- .sensor_id_info = &imx091_id_info,
- .sensor_exp_gain_info = &imx091_exp_gain_info,
- .cam_mode = MSM_SENSOR_MODE_INVALID,
- .csi_params = &imx091_csi_params_array[0],
- .msm_sensor_mutex = &imx091_mut,
- .sensor_i2c_driver = &imx091_i2c_driver,
- .sensor_v4l2_subdev_info = imx091_subdev_info,
- .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx091_subdev_info),
- .sensor_v4l2_subdev_ops = &imx091_subdev_ops,
- .func_tbl = &imx091_func_tbl,
- .clk_rate = MSM_SENSOR_MCLK_24HZ,
-};
-
-module_init(imx091_sensor_init_module);
-MODULE_DESCRIPTION("SONY 12MP Bayer sensor driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/imx091.h b/drivers/media/video/msm/sensors/imx091.h
new file mode 100644
index 0000000..862b43a
--- /dev/null
+++ b/drivers/media/video/msm/sensors/imx091.h
@@ -0,0 +1,100 @@
+/* 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.
+ *
+ */
+#define IMX091_SENSOR_NAME "imx091"
+DEFINE_MSM_MUTEX(imx091_mut);
+
+static struct msm_sensor_ctrl_t imx091_s_ctrl;
+
+static struct v4l2_subdev_info imx091_subdev_info[] = {
+ {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ },
+ /* more can be supported, to be added later */
+};
+
+static struct msm_sensor_id_info_t imx091_id_info = {
+ .sensor_id_reg_addr = 0x0000,
+ .sensor_id = 0x0091,
+};
+
+static enum msm_camera_vreg_name_t imx091_veg_seq[] = {
+ CAM_VANA,
+ CAM_VAF,
+ CAM_VDIG,
+ CAM_VIO,
+};
+
+static struct msm_camera_power_seq_t imx091_power_seq[] = {
+ {REQUEST_GPIO, 0},
+ {REQUEST_VREG, 0},
+ {ENABLE_VREG, 0},
+ {ENABLE_GPIO, 0},
+ {CONFIG_CLK, 0},
+};
+
+static const struct i2c_device_id imx091_i2c_id[] = {
+ {IMX091_SENSOR_NAME, (kernel_ulong_t)&imx091_s_ctrl},
+ { }
+};
+
+static struct i2c_driver imx091_i2c_driver = {
+ .id_table = imx091_i2c_id,
+ .probe = msm_sensor_bayer_i2c_probe,
+ .driver = {
+ .name = IMX091_SENSOR_NAME,
+ },
+};
+
+static struct msm_camera_i2c_client imx091_sensor_i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static struct v4l2_subdev_core_ops imx091_subdev_core_ops = {
+ .ioctl = msm_sensor_bayer_subdev_ioctl,
+ .s_power = msm_sensor_bayer_power,
+};
+
+static struct v4l2_subdev_video_ops imx091_subdev_video_ops = {
+ .enum_mbus_fmt = msm_sensor_bayer_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops imx091_subdev_ops = {
+ .core = &imx091_subdev_core_ops,
+ .video = &imx091_subdev_video_ops,
+};
+
+static struct msm_sensor_fn_t imx091_func_tbl = {
+ .sensor_config = msm_sensor_bayer_config,
+ .sensor_power_up = msm_sensor_bayer_power_up,
+ .sensor_power_down = msm_sensor_bayer_power_down,
+ .sensor_get_csi_params = msm_sensor_bayer_get_csi_params,
+};
+
+static struct msm_sensor_ctrl_t imx091_s_ctrl = {
+ .sensor_i2c_client = &imx091_sensor_i2c_client,
+ .sensor_i2c_addr = 0x34,
+ .vreg_seq = imx091_veg_seq,
+ .num_vreg_seq = ARRAY_SIZE(imx091_veg_seq),
+ .power_seq = &imx091_power_seq[0],
+ .num_power_seq = ARRAY_SIZE(imx091_power_seq),
+ .sensor_id_info = &imx091_id_info,
+ .msm_sensor_mutex = &imx091_mut,
+ .sensor_v4l2_subdev_info = imx091_subdev_info,
+ .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx091_subdev_info),
+ .sensor_v4l2_subdev_ops = &imx091_subdev_ops,
+ .func_tbl = &imx091_func_tbl,
+ .clk_rate = MSM_SENSOR_MCLK_24HZ,
+};
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index f687573..8fbcc01 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -9,26 +9,20 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
#include "msm_sensor.h"
+#include "msm_sensor_common.h"
#include "msm.h"
#include "msm_ispif.h"
#include "msm_camera_i2c_mux.h"
/*=============================================================*/
-int32_t msm_sensor_adjust_frame_lines1(struct msm_sensor_ctrl_t *s_ctrl,
- uint16_t res)
+void msm_sensor_adjust_frame_lines1(struct msm_sensor_ctrl_t *s_ctrl)
{
uint16_t cur_line = 0;
uint16_t exp_fl_lines = 0;
if (s_ctrl->sensor_exp_gain_info) {
- if (s_ctrl->prev_gain && s_ctrl->prev_line &&
- s_ctrl->func_tbl->sensor_write_exp_gain)
- s_ctrl->func_tbl->sensor_write_exp_gain(
- s_ctrl,
- s_ctrl->prev_gain,
- s_ctrl->prev_line);
-
msm_camera_i2c_read(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
&cur_line,
@@ -36,7 +30,7 @@
exp_fl_lines = cur_line +
s_ctrl->sensor_exp_gain_info->vert_offset;
if (exp_fl_lines > s_ctrl->msm_sensor_reg->
- output_settings[res].frame_length_lines)
+ output_settings[s_ctrl->curr_res].frame_length_lines)
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->
frame_length_lines,
@@ -44,26 +38,18 @@
MSM_CAMERA_I2C_WORD_DATA);
CDBG("%s cur_fl_lines %d, exp_fl_lines %d\n", __func__,
s_ctrl->msm_sensor_reg->
- output_settings[res].frame_length_lines,
+ output_settings[s_ctrl->curr_res].frame_length_lines,
exp_fl_lines);
}
- return 0;
+ return;
}
-int32_t msm_sensor_adjust_frame_lines2(struct msm_sensor_ctrl_t *s_ctrl,
- uint16_t res)
+void msm_sensor_adjust_frame_lines2(struct msm_sensor_ctrl_t *s_ctrl)
{
uint16_t cur_line = 0;
uint16_t exp_fl_lines = 0;
uint8_t int_time[3];
if (s_ctrl->sensor_exp_gain_info) {
- if (s_ctrl->prev_gain && s_ctrl->prev_line &&
- s_ctrl->func_tbl->sensor_write_exp_gain)
- s_ctrl->func_tbl->sensor_write_exp_gain(
- s_ctrl,
- s_ctrl->prev_gain,
- s_ctrl->prev_line);
-
msm_camera_i2c_read_seq(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_exp_gain_info->coarse_int_time_addr-1,
&int_time[0], 3);
@@ -73,7 +59,7 @@
exp_fl_lines = cur_line +
s_ctrl->sensor_exp_gain_info->vert_offset;
if (exp_fl_lines > s_ctrl->msm_sensor_reg->
- output_settings[res].frame_length_lines)
+ output_settings[s_ctrl->curr_res].frame_length_lines)
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->
frame_length_lines,
@@ -83,10 +69,32 @@
__func__,
cur_line,
s_ctrl->msm_sensor_reg->
- output_settings[res].frame_length_lines,
+ output_settings[s_ctrl->curr_res].frame_length_lines,
exp_fl_lines);
}
- return 0;
+ return;
+}
+
+static void msm_sensor_delay_frames(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ long fps = 0;
+ uint32_t delay = 0;
+
+ if (s_ctrl->curr_res < MSM_SENSOR_INVALID_RES &&
+ s_ctrl->wait_num_frames > 0) {
+ fps = s_ctrl->msm_sensor_reg->
+ output_settings[s_ctrl->curr_res].vt_pixel_clk /
+ s_ctrl->curr_frame_length_lines /
+ s_ctrl->curr_line_length_pclk;
+ delay = (1000 * s_ctrl->wait_num_frames) / fps / Q10;
+ }
+ CDBG("%s fps = %ld, delay = %d, min_delay %d\n", __func__, fps,
+ delay, s_ctrl->min_delay);
+ if (delay > s_ctrl->min_delay)
+ msleep(delay);
+ else if (s_ctrl->min_delay)
+ msleep(s_ctrl->min_delay);
+ return;
}
int32_t msm_sensor_write_init_settings(struct msm_sensor_ctrl_t *s_ctrl)
@@ -113,9 +121,6 @@
if (rc < 0)
return rc;
- if (s_ctrl->func_tbl->sensor_adjust_frame_lines)
- rc = s_ctrl->func_tbl->sensor_adjust_frame_lines(s_ctrl, res);
-
return rc;
}
@@ -145,11 +150,18 @@
void msm_sensor_start_stream(struct msm_sensor_ctrl_t *s_ctrl)
{
+ if (s_ctrl->curr_res >= s_ctrl->msm_sensor_reg->num_conf)
+ return;
+
+ if (s_ctrl->func_tbl->sensor_adjust_frame_lines)
+ s_ctrl->func_tbl->sensor_adjust_frame_lines(s_ctrl);
+
msm_camera_i2c_write_tbl(
s_ctrl->sensor_i2c_client,
s_ctrl->msm_sensor_reg->start_stream_conf,
s_ctrl->msm_sensor_reg->start_stream_conf_size,
s_ctrl->msm_sensor_reg->default_data_type);
+ msm_sensor_delay_frames(s_ctrl);
}
void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
@@ -159,6 +171,7 @@
s_ctrl->msm_sensor_reg->stop_stream_conf,
s_ctrl->msm_sensor_reg->stop_stream_conf_size,
s_ctrl->msm_sensor_reg->default_data_type);
+ msm_sensor_delay_frames(s_ctrl);
}
void msm_sensor_group_hold_on(struct msm_sensor_ctrl_t *s_ctrl)
@@ -244,78 +257,38 @@
int update_type, int res)
{
int32_t rc = 0;
- static int csi_config;
- s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
- msleep(30);
if (update_type == MSM_SENSOR_REG_INIT) {
CDBG("Register INIT\n");
- s_ctrl->curr_csi_params = NULL;
msm_sensor_enable_debugfs(s_ctrl);
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
msm_sensor_write_init_settings(s_ctrl);
- csi_config = 0;
} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
CDBG("PERIODIC : %d\n", res);
msm_sensor_write_conf_array(
s_ctrl->sensor_i2c_client,
s_ctrl->msm_sensor_reg->mode_settings, res);
msleep(30);
- if (!csi_config) {
- s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
- CDBG("CSI config in progress\n");
- v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
- NOTIFY_CSIC_CFG,
- s_ctrl->curr_csic_params);
- CDBG("CSI config is done\n");
- mb();
- msleep(30);
- csi_config = 1;
- }
v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_PCLK_CHANGE,
&s_ctrl->sensordata->pdata->ioclk.vfe_clk_rate);
-
- s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
- msleep(50);
}
return rc;
}
+
int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
int update_type, int res)
{
int32_t rc = 0;
- s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
- msleep(30);
+
if (update_type == MSM_SENSOR_REG_INIT) {
- s_ctrl->curr_csi_params = NULL;
- msm_sensor_enable_debugfs(s_ctrl);
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
msm_sensor_write_init_settings(s_ctrl);
} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
msm_sensor_write_res_settings(s_ctrl, res);
- if (s_ctrl->curr_csi_params != s_ctrl->csi_params[res]) {
- s_ctrl->curr_csi_params = s_ctrl->csi_params[res];
- s_ctrl->curr_csi_params->csid_params.lane_assign =
- s_ctrl->sensordata->sensor_platform_info->
- csi_lane_params->csi_lane_assign;
- s_ctrl->curr_csi_params->csiphy_params.lane_mask =
- s_ctrl->sensordata->sensor_platform_info->
- csi_lane_params->csi_lane_mask;
- v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
- NOTIFY_CSID_CFG,
- &s_ctrl->curr_csi_params->csid_params);
- mb();
- v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
- NOTIFY_CSIPHY_CFG,
- &s_ctrl->curr_csi_params->csiphy_params);
- mb();
- msleep(20);
- }
-
v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_PCLK_CHANGE, &s_ctrl->msm_sensor_reg->
output_settings[res].op_pixel_clk);
- s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
- msleep(30);
}
return rc;
}
@@ -385,21 +358,10 @@
return rc;
}
-int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl)
+static int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl)
{
- long fps = 0;
- uint32_t delay = 0;
CDBG("%s called\n", __func__);
s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
- if (s_ctrl->curr_res != MSM_SENSOR_INVALID_RES) {
- fps = s_ctrl->msm_sensor_reg->
- output_settings[s_ctrl->curr_res].vt_pixel_clk /
- s_ctrl->curr_frame_length_lines /
- s_ctrl->curr_line_length_pclk;
- delay = 1000 / fps;
- CDBG("%s fps = %ld, delay = %d\n", __func__, fps, delay);
- msleep(delay);
- }
return 0;
}
@@ -408,6 +370,8 @@
{
struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
void __user *argp = (void __user *)arg;
+ if (s_ctrl->sensor_state == MSM_SENSOR_POWER_DOWN)
+ return -EINVAL;
switch (cmd) {
case VIDIOC_MSM_SENSOR_CFG:
return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
@@ -416,7 +380,6 @@
case VIDIOC_MSM_SENSOR_CSID_INFO: {
struct msm_sensor_csi_info *csi_info =
(struct msm_sensor_csi_info *)arg;
- s_ctrl->csid_version = csi_info->csid_version;
s_ctrl->is_csic = csi_info->is_csic;
return 0;
}
@@ -428,14 +391,20 @@
int32_t msm_sensor_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
struct csi_lane_params_t *sensor_output_info)
{
- sensor_output_info->csi_lane_assign = s_ctrl->sensordata->
- sensor_platform_info->csi_lane_params->csi_lane_assign;
- sensor_output_info->csi_lane_mask = s_ctrl->sensordata->
- sensor_platform_info->csi_lane_params->csi_lane_mask;
+ uint8_t index;
+ struct msm_camera_csi_lane_params *csi_lane_params =
+ s_ctrl->sensordata->sensor_platform_info->csi_lane_params;
+ if (csi_lane_params) {
+ sensor_output_info->csi_lane_assign = csi_lane_params->
+ csi_lane_assign;
+ sensor_output_info->csi_lane_mask = csi_lane_params->
+ csi_lane_mask;
+ }
sensor_output_info->csi_if = s_ctrl->sensordata->csi_if;
- sensor_output_info->csid_core = s_ctrl->sensordata->
- pdata[0].csid_core;
- sensor_output_info->csid_version = s_ctrl->csid_version;
+ for (index = 0; index < sensor_output_info->csi_if; index++)
+ sensor_output_info->csid_core[index] = s_ctrl->sensordata->
+ pdata[index].csid_core;
+
return 0;
}
@@ -448,9 +417,9 @@
sizeof(struct sensor_cfg_data)))
return -EFAULT;
mutex_lock(s_ctrl->msm_sensor_mutex);
- CDBG("msm_sensor_config: cfgtype = %d\n",
- cdata.cfgtype);
- switch (cdata.cfgtype) {
+ CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__,
+ s_ctrl->sensordata->sensor_name, cdata.cfgtype);
+ switch (cdata.cfgtype) {
case CFG_SET_FPS:
case CFG_SET_PICT_FPS:
if (s_ctrl->func_tbl->
@@ -476,8 +445,6 @@
s_ctrl,
cdata.cfg.exp_gain.gain,
cdata.cfg.exp_gain.line);
- s_ctrl->prev_gain = cdata.cfg.exp_gain.gain;
- s_ctrl->prev_line = cdata.cfg.exp_gain.line;
break;
case CFG_SET_PICT_EXP_GAIN:
@@ -571,6 +538,22 @@
rc = -EFAULT;
break;
+ case CFG_POWER_UP:
+ pr_err("%s calling power up\n", __func__);
+ if (s_ctrl->func_tbl->sensor_power_up)
+ rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+ else
+ rc = -EFAULT;
+ break;
+
+ case CFG_POWER_DOWN:
+ if (s_ctrl->func_tbl->sensor_power_down)
+ rc = s_ctrl->func_tbl->sensor_power_down(
+ s_ctrl);
+ else
+ rc = -EFAULT;
+ break;
+
default:
rc = -EFAULT;
break;
@@ -581,10 +564,15 @@
return rc;
}
-static struct msm_cam_clk_info cam_clk_info[] = {
+static struct msm_cam_clk_info cam_8960_clk_info[] = {
{"cam_clk", MSM_SENSOR_MCLK_24HZ},
};
+static struct msm_cam_clk_info cam_8974_clk_info[] = {
+ {"cam_src_clk", 19200000},
+ {"cam_clk", -1},
+};
+
int32_t msm_sensor_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
{
struct v4l2_subdev *i2c_mux_sd =
@@ -618,8 +606,8 @@
return -ENOMEM;
}
- rc = of_property_read_u32(of_node, "flash_type", &val);
- CDBG("%s flash_type %d, rc %d\n", __func__, val, rc);
+ rc = of_property_read_u32(of_node, "qcom,flash-type", &val);
+ CDBG("%s qcom,flash-type %d, rc %d\n", __func__, val, rc);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR;
@@ -638,8 +626,8 @@
uint32_t count = 0;
uint32_t *val_array = NULL;
- count = of_property_count_strings(of_node, "cam_vreg_name");
- CDBG("%s cam_vreg_name count %d\n", __func__, count);
+ count = of_property_count_strings(of_node, "qcom,cam-vreg-name");
+ CDBG("%s qcom,cam-vreg-name count %d\n", __func__, count);
if (!count)
return 0;
@@ -653,8 +641,8 @@
pinfo->num_vreg = count;
for (i = 0; i < count; i++) {
- rc = of_property_read_string_index(of_node, "cam_vreg_name", i,
- &pinfo->cam_vreg[i].reg_name);
+ rc = of_property_read_string_index(of_node,
+ "qcom,cam-vreg-name", i, &pinfo->cam_vreg[i].reg_name);
CDBG("%s reg_name[%d] = %s\n", __func__, i,
pinfo->cam_vreg[i].reg_name);
if (rc < 0) {
@@ -670,8 +658,8 @@
goto ERROR1;
}
- rc = of_property_read_u32_array(of_node, "cam_vreg_type", val_array,
- count);
+ rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-type",
+ val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR2;
@@ -682,7 +670,7 @@
pinfo->cam_vreg[i].type);
}
- rc = of_property_read_u32_array(of_node, "cam_vreg_min_voltage",
+ rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-min-voltage",
val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
@@ -694,7 +682,7 @@
i, pinfo->cam_vreg[i].min_voltage);
}
- rc = of_property_read_u32_array(of_node, "cam_vreg_max_voltage",
+ rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-max-voltage",
val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
@@ -706,8 +694,8 @@
i, pinfo->cam_vreg[i].max_voltage);
}
- rc = of_property_read_u32_array(of_node, "cam_vreg_op_mode", val_array,
- count);
+ rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-op-mode",
+ val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR2;
@@ -729,19 +717,25 @@
}
static int32_t msm_sensor_init_gpio_common_tbl_data(struct device_node *of_node,
- struct msm_camera_gpio_conf *gconf)
+ struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+ uint16_t gpio_array_size)
{
int32_t rc = 0, i = 0;
uint32_t count = 0;
uint32_t *val_array = NULL;
- if (!of_get_property(of_node, "gpio_common_tbl_num", &count))
+ if (!of_get_property(of_node, "qcom,gpio-common-tbl-num", &count))
return 0;
count /= sizeof(uint32_t);
-
- if (!count)
+ if (!count) {
+ pr_err("%s qcom,gpio-common-tbl-num 0\n", __func__);
return 0;
+ } else if (count > gpio_array_size) {
+ pr_err("%s gpio common tbl size exceeds gpio array\n",
+ __func__);
+ return -EFAULT;
+ }
val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
if (!val_array) {
@@ -758,19 +752,24 @@
}
gconf->cam_gpio_common_tbl_size = count;
- rc = of_property_read_u32_array(of_node, "gpio_common_tbl_num",
+ rc = of_property_read_u32_array(of_node, "qcom,gpio-common-tbl-num",
val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR2;
}
for (i = 0; i < count; i++) {
- gconf->cam_gpio_common_tbl[i].gpio = val_array[i];
+ if (val_array[i] >= gpio_array_size) {
+ pr_err("%s gpio common tbl index %d invalid\n",
+ __func__, val_array[i]);
+ return -EINVAL;
+ }
+ gconf->cam_gpio_common_tbl[i].gpio = gpio_array[val_array[i]];
CDBG("%s cam_gpio_common_tbl[%d].gpio = %d\n", __func__, i,
gconf->cam_gpio_common_tbl[i].gpio);
}
- rc = of_property_read_u32_array(of_node, "gpio_common_tbl_flags",
+ rc = of_property_read_u32_array(of_node, "qcom,gpio-common-tbl-flags",
val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
@@ -784,7 +783,7 @@
for (i = 0; i < count; i++) {
rc = of_property_read_string_index(of_node,
- "gpio_common_tbl_label", i,
+ "qcom,gpio-common-tbl-label", i,
&gconf->cam_gpio_common_tbl[i].label);
CDBG("%s cam_gpio_common_tbl[%d].label = %s\n", __func__, i,
gconf->cam_gpio_common_tbl[i].label);
@@ -806,19 +805,21 @@
}
static int32_t msm_sensor_init_gpio_req_tbl_data(struct device_node *of_node,
- struct msm_camera_gpio_conf *gconf)
+ struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+ uint16_t gpio_array_size)
{
int32_t rc = 0, i = 0;
uint32_t count = 0;
uint32_t *val_array = NULL;
- if (!of_get_property(of_node, "gpio_req_tbl_num", &count))
+ if (!of_get_property(of_node, "qcom,gpio-req-tbl-num", &count))
return 0;
count /= sizeof(uint32_t);
-
- if (!count)
+ if (!count) {
+ pr_err("%s qcom,gpio-req-tbl-num 0\n", __func__);
return 0;
+ }
val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
if (!val_array) {
@@ -835,19 +836,24 @@
}
gconf->cam_gpio_req_tbl_size = count;
- rc = of_property_read_u32_array(of_node, "gpio_req_tbl_num",
+ rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-num",
val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR2;
}
for (i = 0; i < count; i++) {
- gconf->cam_gpio_req_tbl[i].gpio = val_array[i];
+ if (val_array[i] >= gpio_array_size) {
+ pr_err("%s gpio req tbl index %d invalid\n",
+ __func__, val_array[i]);
+ return -EINVAL;
+ }
+ gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]];
CDBG("%s cam_gpio_req_tbl[%d].gpio = %d\n", __func__, i,
gconf->cam_gpio_req_tbl[i].gpio);
}
- rc = of_property_read_u32_array(of_node, "gpio_req_tbl_flags",
+ rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-flags",
val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
@@ -861,7 +867,7 @@
for (i = 0; i < count; i++) {
rc = of_property_read_string_index(of_node,
- "gpio_req_tbl_label", i,
+ "qcom,gpio-req-tbl-label", i,
&gconf->cam_gpio_req_tbl[i].label);
CDBG("%s cam_gpio_req_tbl[%d].label = %s\n", __func__, i,
gconf->cam_gpio_req_tbl[i].label);
@@ -883,19 +889,21 @@
}
static int32_t msm_sensor_init_gpio_set_tbl_data(struct device_node *of_node,
- struct msm_camera_gpio_conf *gconf)
+ struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+ uint16_t gpio_array_size)
{
int32_t rc = 0, i = 0;
uint32_t count = 0;
uint32_t *val_array = NULL;
- if (!of_get_property(of_node, "gpio_set_tbl_num", &count))
+ if (!of_get_property(of_node, "qcom,gpio-set-tbl-num", &count))
return 0;
count /= sizeof(uint32_t);
-
- if (!count)
+ if (!count) {
+ pr_err("%s qcom,gpio-set-tbl-num 0\n", __func__);
return 0;
+ }
val_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
if (!val_array) {
@@ -912,19 +920,24 @@
}
gconf->cam_gpio_set_tbl_size = count;
- rc = of_property_read_u32_array(of_node, "gpio_set_tbl_num",
+ rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-num",
val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR2;
}
for (i = 0; i < count; i++) {
- gconf->cam_gpio_set_tbl[i].gpio = val_array[i];
+ if (val_array[i] >= gpio_array_size) {
+ pr_err("%s gpio set tbl index %d invalid\n",
+ __func__, val_array[i]);
+ return -EINVAL;
+ }
+ gconf->cam_gpio_set_tbl[i].gpio = gpio_array[val_array[i]];
CDBG("%s cam_gpio_set_tbl[%d].gpio = %d\n", __func__, i,
gconf->cam_gpio_set_tbl[i].gpio);
}
- rc = of_property_read_u32_array(of_node, "gpio_set_tbl_flags",
+ rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-flags",
val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
@@ -936,7 +949,7 @@
gconf->cam_gpio_set_tbl[i].flags);
}
- rc = of_property_read_u32_array(of_node, "gpio_set_tbl_delay",
+ rc = of_property_read_u32_array(of_node, "qcom,gpio-set-tbl-delay",
val_array, count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
@@ -960,7 +973,8 @@
}
static int32_t msm_sensor_init_gpio_tlmm_tbl_data(struct device_node *of_node,
- struct msm_camera_gpio_conf *gconf)
+ struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
+ uint16_t gpio_array_size)
{
int32_t rc = 0, i = 0;
uint32_t count = 0;
@@ -1011,7 +1025,12 @@
goto ERROR4;
}
for (i = 0; i < count; i++) {
- tlmm_cfg[i].gpio = val_array[i];
+ if (val_array[i] >= gpio_array_size) {
+ pr_err("%s gpio set tbl index %d invalid\n",
+ __func__, val_array[i]);
+ return -EINVAL;
+ }
+ tlmm_cfg[i].gpio = gpio_array[val_array[i]];
CDBG("%s tlmm_cfg[%d].gpio = %d\n", __func__, i,
tlmm_cfg[i].gpio);
}
@@ -1087,8 +1106,8 @@
struct msm_camera_sensor_platform_info *pinfo =
sensordata->sensor_platform_info;
- rc = of_property_read_u32(of_node, "csi_if", &count);
- CDBG("%s csi_if %d, rc %d\n", __func__, count, rc);
+ rc = of_property_read_u32(of_node, "qcom,csi-if", &count);
+ CDBG("%s qcom,csi-if %d, rc %d\n", __func__, count, rc);
if (rc < 0 || !count)
return rc;
sensordata->csi_if = count;
@@ -1107,25 +1126,27 @@
goto ERROR1;
}
- rc = of_property_read_u32_array(of_node, "csid_core", val_array, count);
+ rc = of_property_read_u32_array(of_node, "qcom,csid-core", val_array,
+ count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR2;
}
for (i = 0; i < count; i++) {
sensordata->pdata[i].csid_core = val_array[i];
- CDBG("%s csid_core[%d].csid_core = %d\n", __func__, i,
+ CDBG("%s csi_data[%d].csid_core = %d\n", __func__, i,
sensordata->pdata[i].csid_core);
}
- rc = of_property_read_u32_array(of_node, "is_vpe", val_array, count);
+ rc = of_property_read_u32_array(of_node, "qcom,is-vpe", val_array,
+ count);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR2;
}
for (i = 0; i < count; i++) {
sensordata->pdata[i].is_vpe = val_array[i];
- CDBG("%s csid_core[%d].is_vpe = %d\n", __func__, i,
+ CDBG("%s csi_data[%d].is_vpe = %d\n", __func__, i,
sensordata->pdata[i].is_vpe);
}
@@ -1137,16 +1158,16 @@
goto ERROR2;
}
- rc = of_property_read_u32(of_node, "csi_lane_assign", &val);
- CDBG("%s csi_lane_assign %x, rc %d\n", __func__, val, rc);
+ rc = of_property_read_u32(of_node, "qcom,csi-lane-assign", &val);
+ CDBG("%s qcom,csi-lane-assign %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_lane_assign = val;
- rc = of_property_read_u32(of_node, "csi_lane_mask", &val);
- CDBG("%s csi_lane_mask %x, rc %d\n", __func__, val, rc);
+ rc = of_property_read_u32(of_node, "qcom,csi-lane-mask", &val);
+ CDBG("%s qcom,csi-lane-mask %x, rc %d\n", __func__, val, rc);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR3;
@@ -1170,8 +1191,8 @@
int32_t rc = 0;
uint32_t val = 0;
- rc = of_property_read_u32(of_node, "actuator_cam_name", &val);
- CDBG("%s actuator_cam_name %d, rc %d\n", __func__, val, rc);
+ rc = of_property_read_u32(of_node, "qcom,actuator-cam-name", &val);
+ CDBG("%s qcom,actuator-cam-name %d, rc %d\n", __func__, val, rc);
if (rc < 0)
return 0;
@@ -1185,13 +1206,13 @@
sensordata->actuator_info->cam_name = val;
- rc = of_property_read_u32(of_node, "actuator_vcm_pwd", &val);
- CDBG("%s actuator_vcm_pwd %d, rc %d\n", __func__, val, rc);
+ rc = of_property_read_u32(of_node, "qcom,actuator-vcm-pwd", &val);
+ CDBG("%s qcom,actuator-vcm-pwd %d, rc %d\n", __func__, val, rc);
if (!rc)
sensordata->actuator_info->vcm_pwd = val;
- rc = of_property_read_u32(of_node, "actuator_vcm_enable", &val);
- CDBG("%s actuator_vcm_enable %d, rc %d\n", __func__, val, rc);
+ rc = of_property_read_u32(of_node, "qcom,actuator-vcm-enable", &val);
+ CDBG("%s qcom,actuator-vcm-enable %d, rc %d\n", __func__, val, rc);
if (!rc)
sensordata->actuator_info->vcm_enable = val;
@@ -1203,12 +1224,14 @@
static int32_t msm_sensor_init_sensor_data(struct platform_device *pdev,
struct msm_sensor_ctrl_t *s_ctrl)
{
- int32_t rc = 0;
+ int32_t rc = 0, i = 0;
uint32_t val = 0;
struct device_node *of_node = pdev->dev.of_node;
struct msm_camera_sensor_platform_info *pinfo = NULL;
struct msm_camera_gpio_conf *gconf = NULL;
struct msm_camera_sensor_info *sensordata = NULL;
+ uint16_t *gpio_array = NULL;
+ uint16_t gpio_array_size = 0;
s_ctrl->sensordata = kzalloc(sizeof(struct msm_camera_sensor_info),
GFP_KERNEL);
@@ -1218,25 +1241,26 @@
}
sensordata = s_ctrl->sensordata;
- rc = of_property_read_string(of_node, "sensor_name",
+
+ rc = of_property_read_string(of_node, "qcom,sensor-name",
&sensordata->sensor_name);
- CDBG("%s sensor_name %s, rc %d\n", __func__,
+ CDBG("%s qcom,sensor-name %s, rc %d\n", __func__,
sensordata->sensor_name, rc);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR1;
}
- rc = of_property_read_u32(of_node, "camera_type", &val);
- CDBG("%s camera_type %d, rc %d\n", __func__, val, rc);
+ rc = of_property_read_u32(of_node, "qcom,camera-type", &val);
+ CDBG("%s qcom,camera-type %d, rc %d\n", __func__, val, rc);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR1;
}
sensordata->camera_type = val;
- rc = of_property_read_u32(of_node, "sensor_type", &val);
- CDBG("%s sensor_type %d, rc %d\n", __func__, val, rc);
+ rc = of_property_read_u32(of_node, "qcom,sensor-type", &val);
+ CDBG("%s qcom,sensor-type %d, rc %d\n", __func__, val, rc);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR1;
@@ -1259,8 +1283,10 @@
pinfo = sensordata->sensor_platform_info;
- rc = of_property_read_u32(of_node, "mount_angle", &pinfo->mount_angle);
- CDBG("%s mount_angle %d, rc %d\n", __func__, pinfo->mount_angle, rc);
+ rc = of_property_read_u32(of_node, "qcom,mount-angle",
+ &pinfo->mount_angle);
+ CDBG("%s qcom,mount-angle %d, rc %d\n", __func__, pinfo->mount_angle,
+ rc);
if (rc < 0) {
/* Set default mount angle */
pinfo->mount_angle = 0;
@@ -1287,7 +1313,8 @@
goto ERROR4;
}
gconf = pinfo->gpio_conf;
- rc = of_property_read_u32(of_node, "gpio_no_mux", &gconf->gpio_no_mux);
+ rc = of_property_read_u32(of_node, "qcom,gpio-no-mux",
+ &gconf->gpio_no_mux);
CDBG("%s gconf->gpio_no_mux %d, rc %d\n", __func__,
gconf->gpio_no_mux, rc);
if (rc < 0) {
@@ -1295,36 +1322,57 @@
goto ERROR5;
}
- rc = msm_sensor_init_gpio_common_tbl_data(of_node, gconf);
- if (rc < 0) {
- pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR5;
- }
+ gpio_array_size = of_gpio_count(of_node);
+ CDBG("%s gpio count %d\n", __func__, gpio_array_size);
- rc = msm_sensor_init_gpio_req_tbl_data(of_node, gconf);
- if (rc < 0) {
- pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR6;
- }
+ if (gpio_array_size) {
+ gpio_array = kzalloc(sizeof(uint16_t) * gpio_array_size,
+ GFP_KERNEL);
+ if (!gpio_array) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto ERROR5;
+ }
+ for (i = 0; i < gpio_array_size; i++) {
+ gpio_array[i] = of_get_gpio(of_node, i);
+ CDBG("%s gpio_array[%d] = %d\n", __func__, i,
+ gpio_array[i]);
+ }
- rc = msm_sensor_init_gpio_set_tbl_data(of_node, gconf);
- if (rc < 0) {
- pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR7;
- }
+ rc = msm_sensor_init_gpio_common_tbl_data(of_node, gconf,
+ gpio_array, gpio_array_size);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto ERROR5;
+ }
- rc = msm_sensor_init_gpio_tlmm_tbl_data(of_node, gconf);
- if (rc < 0) {
- pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR8;
- }
+ rc = msm_sensor_init_gpio_req_tbl_data(of_node, gconf,
+ gpio_array, gpio_array_size);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto ERROR6;
+ }
+ rc = msm_sensor_init_gpio_set_tbl_data(of_node, gconf,
+ gpio_array, gpio_array_size);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto ERROR7;
+ }
+
+ rc = msm_sensor_init_gpio_tlmm_tbl_data(of_node, gconf,
+ gpio_array, gpio_array_size);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto ERROR8;
+ }
+ }
rc = msm_sensor_init_actuator_data(of_node, sensordata);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR9;
}
+ kfree(gpio_array);
return rc;
ERROR9:
@@ -1353,6 +1401,7 @@
kfree(s_ctrl->sensordata->flash_data);
ERROR1:
kfree(s_ctrl->sensordata);
+ kfree(gpio_array);
return rc;
}
@@ -1384,7 +1433,11 @@
{
int32_t rc = 0;
struct msm_camera_sensor_info *data = s_ctrl->sensordata;
- CDBG("%s: %d\n", __func__, __LINE__);
+ struct device *dev = NULL;
+ if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE)
+ dev = &s_ctrl->pdev->dev;
+ else
+ dev = &s_ctrl->sensor_i2c_client->client->dev;
s_ctrl->reg_ptr = kzalloc(sizeof(struct regulator *)
* data->sensor_platform_info->num_vreg, GFP_KERNEL);
if (!s_ctrl->reg_ptr) {
@@ -1399,19 +1452,23 @@
goto request_gpio_failed;
}
- rc = msm_camera_config_vreg(&s_ctrl->sensor_i2c_client->client->dev,
- s_ctrl->sensordata->sensor_platform_info->cam_vreg,
- s_ctrl->sensordata->sensor_platform_info->num_vreg,
- s_ctrl->reg_ptr, 1);
+ rc = msm_camera_config_vreg(dev,
+ s_ctrl->sensordata->sensor_platform_info->cam_vreg,
+ s_ctrl->sensordata->sensor_platform_info->num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
+ s_ctrl->reg_ptr, 1);
if (rc < 0) {
pr_err("%s: regulator on failed\n", __func__);
goto config_vreg_failed;
}
- rc = msm_camera_enable_vreg(&s_ctrl->sensor_i2c_client->client->dev,
- s_ctrl->sensordata->sensor_platform_info->cam_vreg,
- s_ctrl->sensordata->sensor_platform_info->num_vreg,
- s_ctrl->reg_ptr, 1);
+ rc = msm_camera_enable_vreg(dev,
+ s_ctrl->sensordata->sensor_platform_info->cam_vreg,
+ s_ctrl->sensordata->sensor_platform_info->num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
+ s_ctrl->reg_ptr, 1);
if (rc < 0) {
pr_err("%s: enable regulator failed\n", __func__);
goto enable_vreg_failed;
@@ -1423,17 +1480,33 @@
goto config_gpio_failed;
}
- if (s_ctrl->clk_rate != 0)
- cam_clk_info->clk_rate = s_ctrl->clk_rate;
+ if (s_ctrl->sensor_device_type == MSM_SENSOR_I2C_DEVICE) {
+ if (s_ctrl->clk_rate != 0)
+ cam_8960_clk_info->clk_rate = s_ctrl->clk_rate;
- rc = msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->dev,
- cam_clk_info, &s_ctrl->cam_clk, ARRAY_SIZE(cam_clk_info), 1);
- if (rc < 0) {
- pr_err("%s: clk enable failed\n", __func__);
- goto enable_clk_failed;
+ rc = msm_cam_clk_enable(dev, cam_8960_clk_info,
+ s_ctrl->cam_clk, ARRAY_SIZE(cam_8960_clk_info), 1);
+ if (rc < 0) {
+ pr_err("%s: clk enable failed\n", __func__);
+ goto enable_clk_failed;
+ }
+ } else {
+ rc = msm_cam_clk_enable(dev, cam_8974_clk_info,
+ s_ctrl->cam_clk, ARRAY_SIZE(cam_8974_clk_info), 1);
+ if (rc < 0) {
+ pr_err("%s: clk enable failed\n", __func__);
+ goto enable_clk_failed;
+ }
}
- usleep_range(1000, 2000);
+ if (!s_ctrl->power_seq_delay)
+ usleep_range(1000, 2000);
+ else if (s_ctrl->power_seq_delay < 20)
+ usleep_range((s_ctrl->power_seq_delay * 1000),
+ ((s_ctrl->power_seq_delay * 1000) + 1000));
+ else
+ msleep(s_ctrl->power_seq_delay);
+
if (data->sensor_platform_info->ext_power_ctrl != NULL)
data->sensor_platform_info->ext_power_ctrl(1);
@@ -1441,7 +1514,7 @@
data->sensor_platform_info->i2c_conf->use_i2c_mux)
msm_sensor_enable_i2c_mux(data->sensor_platform_info->i2c_conf);
- if (s_ctrl->sensor_i2c_client->cci_client) {
+ if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE) {
rc = msm_sensor_cci_util(s_ctrl->sensor_i2c_client,
MSM_CCI_INIT);
if (rc < 0) {
@@ -1449,6 +1522,7 @@
goto cci_init_failed;
}
}
+ s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
return rc;
cci_init_failed:
@@ -1459,15 +1533,19 @@
enable_clk_failed:
msm_camera_config_gpio_table(data, 0);
config_gpio_failed:
- msm_camera_enable_vreg(&s_ctrl->sensor_i2c_client->client->dev,
+ msm_camera_enable_vreg(dev,
s_ctrl->sensordata->sensor_platform_info->cam_vreg,
s_ctrl->sensordata->sensor_platform_info->num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
s_ctrl->reg_ptr, 0);
enable_vreg_failed:
- msm_camera_config_vreg(&s_ctrl->sensor_i2c_client->client->dev,
+ msm_camera_config_vreg(dev,
s_ctrl->sensordata->sensor_platform_info->cam_vreg,
s_ctrl->sensordata->sensor_platform_info->num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
s_ctrl->reg_ptr, 0);
config_vreg_failed:
msm_camera_request_gpio_table(data, 0);
@@ -1479,8 +1557,12 @@
int32_t msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
{
struct msm_camera_sensor_info *data = s_ctrl->sensordata;
- CDBG("%s\n", __func__);
- if (s_ctrl->sensor_i2c_client->cci_client) {
+ struct device *dev = NULL;
+ if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE)
+ dev = &s_ctrl->pdev->dev;
+ else
+ dev = &s_ctrl->sensor_i2c_client->client->dev;
+ if (s_ctrl->sensor_device_type == MSM_SENSOR_PLATFORM_DEVICE) {
msm_sensor_cci_util(s_ctrl->sensor_i2c_client,
MSM_CCI_RELEASE);
}
@@ -1492,19 +1574,28 @@
if (data->sensor_platform_info->ext_power_ctrl != NULL)
data->sensor_platform_info->ext_power_ctrl(0);
- msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->dev,
- cam_clk_info, &s_ctrl->cam_clk, ARRAY_SIZE(cam_clk_info), 0);
+ if (s_ctrl->sensor_device_type == MSM_SENSOR_I2C_DEVICE)
+ msm_cam_clk_enable(dev, cam_8960_clk_info, s_ctrl->cam_clk,
+ ARRAY_SIZE(cam_8960_clk_info), 0);
+ else
+ msm_cam_clk_enable(dev, cam_8974_clk_info, s_ctrl->cam_clk,
+ ARRAY_SIZE(cam_8974_clk_info), 0);
msm_camera_config_gpio_table(data, 0);
- msm_camera_enable_vreg(&s_ctrl->sensor_i2c_client->client->dev,
+ msm_camera_enable_vreg(dev,
s_ctrl->sensordata->sensor_platform_info->cam_vreg,
s_ctrl->sensordata->sensor_platform_info->num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
s_ctrl->reg_ptr, 0);
- msm_camera_config_vreg(&s_ctrl->sensor_i2c_client->client->dev,
+ msm_camera_config_vreg(dev,
s_ctrl->sensordata->sensor_platform_info->cam_vreg,
s_ctrl->sensordata->sensor_platform_info->num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
s_ctrl->reg_ptr, 0);
msm_camera_request_gpio_table(data, 0);
kfree(s_ctrl->reg_ptr);
+ s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
return 0;
}
@@ -1522,7 +1613,7 @@
return rc;
}
- CDBG("%s msm_sensor id: %x, exp id: %x\n", __func__, chipid,
+ CDBG("%s: read id: %x expected id %x:\n", __func__, chipid,
s_ctrl->sensor_id_info->sensor_id);
if (chipid != s_ctrl->sensor_id_info->sensor_id) {
pr_err("msm_sensor_match_id chip id doesnot match\n");
@@ -1531,11 +1622,6 @@
return rc;
}
-struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct msm_sensor_ctrl_t, sensor_v4l2_subdev);
-}
-
int32_t msm_sensor_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1550,6 +1636,7 @@
}
s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+ s_ctrl->sensor_device_type = MSM_SENSOR_I2C_DEVICE;
if (s_ctrl->sensor_i2c_client != NULL) {
s_ctrl->sensor_i2c_client->client = client;
if (s_ctrl->sensor_i2c_addr != 0)
@@ -1581,6 +1668,10 @@
if (rc < 0)
goto probe_fail;
+ if (!s_ctrl->wait_num_frames)
+ s_ctrl->wait_num_frames = 1 * Q10;
+
+ pr_err("%s %s probe succeeded\n", __func__, client->name);
snprintf(s_ctrl->sensor_v4l2_subdev.name,
sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
@@ -1601,6 +1692,7 @@
if (rc > 0)
rc = 0;
s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
return rc;
}
@@ -1630,6 +1722,7 @@
return rc;
}
}
+ s_ctrl->sensor_device_type = MSM_SENSOR_PLATFORM_DEVICE;
s_ctrl->sensor_i2c_client->cci_client = kzalloc(sizeof(
struct msm_camera_cci_client), GFP_KERNEL);
if (!s_ctrl->sensor_i2c_client->cci_client) {
@@ -1655,7 +1748,7 @@
s_ctrl->sensor_i2c_client->cci_client->cci_i2c_master = MASTER_0;
s_ctrl->sensor_i2c_client->cci_client->sid =
s_ctrl->sensor_i2c_addr >> 1;
- s_ctrl->sensor_i2c_client->cci_client->retries = 0;
+ s_ctrl->sensor_i2c_client->cci_client->retries = 3;
s_ctrl->sensor_i2c_client->cci_client->id_map = 0;
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
@@ -1698,6 +1791,7 @@
if (rc < 0) {
pr_err("%s: %s power_up failed rc = %d\n", __func__,
s_ctrl->sensordata->sensor_name, rc);
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
} else {
if (s_ctrl->func_tbl->sensor_match_id)
rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
@@ -1712,10 +1806,13 @@
pr_err("%s: %s power_down failed\n",
__func__,
s_ctrl->sensordata->sensor_name);
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
}
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_UP;
}
} else {
rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
}
mutex_unlock(s_ctrl->msm_sensor_mutex);
return rc;
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index dc394e1..7dd0602 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -24,179 +24,14 @@
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <mach/camera.h>
-#include <mach/gpio.h>
#include <media/msm_camera.h>
#include <media/v4l2-subdev.h>
#include "msm_camera_i2c.h"
#include "msm_camera_eeprom.h"
-#define Q8 0x00000100
-#define Q10 0x00000400
-
-#define MSM_SENSOR_MCLK_8HZ 8000000
-#define MSM_SENSOR_MCLK_16HZ 16000000
-#define MSM_SENSOR_MCLK_24HZ 24000000
-
-struct gpio_tlmm_cfg {
- uint32_t gpio;
- uint32_t dir;
- uint32_t pull;
- uint32_t drvstr;
-};
-
-enum msm_sensor_reg_update {
- /* Sensor egisters that need to be updated during initialization */
- MSM_SENSOR_REG_INIT,
- /* Sensor egisters that needs periodic I2C writes */
- MSM_SENSOR_UPDATE_PERIODIC,
- /* All the sensor Registers will be updated */
- MSM_SENSOR_UPDATE_ALL,
- /* Not valid update */
- MSM_SENSOR_UPDATE_INVALID
-};
-
-enum msm_sensor_cam_mode_t {
- MSM_SENSOR_MODE_2D_RIGHT,
- MSM_SENSOR_MODE_2D_LEFT,
- MSM_SENSOR_MODE_3D,
- MSM_SENSOR_MODE_INVALID
-};
-
-struct msm_sensor_output_reg_addr_t {
- uint16_t x_output;
- uint16_t y_output;
- uint16_t line_length_pclk;
- uint16_t frame_length_lines;
-};
-
-struct msm_sensor_id_info_t {
- uint16_t sensor_id_reg_addr;
- uint16_t sensor_id;
-};
-
-struct msm_sensor_exp_gain_info_t {
- uint16_t coarse_int_time_addr;
- uint16_t global_gain_addr;
- uint16_t vert_offset;
-};
-
-struct msm_sensor_reg_t {
- enum msm_camera_i2c_data_type default_data_type;
- struct msm_camera_i2c_reg_conf *start_stream_conf;
- uint8_t start_stream_conf_size;
- struct msm_camera_i2c_reg_conf *stop_stream_conf;
- uint8_t stop_stream_conf_size;
- struct msm_camera_i2c_reg_conf *group_hold_on_conf;
- uint8_t group_hold_on_conf_size;
- struct msm_camera_i2c_reg_conf *group_hold_off_conf;
- uint8_t group_hold_off_conf_size;
- struct msm_camera_i2c_conf_array *init_settings;
- uint8_t init_size;
- struct msm_camera_i2c_conf_array *mode_settings;
- struct msm_camera_i2c_conf_array *no_effect_settings;
- struct msm_sensor_output_info_t *output_settings;
- uint8_t num_conf;
-};
-
-struct v4l2_subdev_info {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_colorspace colorspace;
- uint16_t fmt;
- uint16_t order;
-};
-
-struct msm_sensor_ctrl_t;
-
-struct msm_sensor_v4l2_ctrl_info_t {
- uint32_t ctrl_id;
- int16_t min;
- int16_t max;
- int16_t step;
- struct msm_camera_i2c_enum_conf_array *enum_cfg_settings;
- int (*s_v4l2_ctrl) (struct msm_sensor_ctrl_t *,
- struct msm_sensor_v4l2_ctrl_info_t *, int);
-};
-
-struct msm_sensor_fn_t {
- void (*sensor_start_stream) (struct msm_sensor_ctrl_t *);
- void (*sensor_stop_stream) (struct msm_sensor_ctrl_t *);
- void (*sensor_group_hold_on) (struct msm_sensor_ctrl_t *);
- void (*sensor_group_hold_off) (struct msm_sensor_ctrl_t *);
-
- int32_t (*sensor_set_fps) (struct msm_sensor_ctrl_t *,
- struct fps_cfg *);
- int32_t (*sensor_write_exp_gain) (struct msm_sensor_ctrl_t *,
- uint16_t, uint32_t);
- int32_t (*sensor_write_snapshot_exp_gain) (struct msm_sensor_ctrl_t *,
- uint16_t, uint32_t);
- int32_t (*sensor_setting) (struct msm_sensor_ctrl_t *,
- int update_type, int rt);
- int32_t (*sensor_csi_setting) (struct msm_sensor_ctrl_t *,
- int update_type, int rt);
- int32_t (*sensor_set_sensor_mode)
- (struct msm_sensor_ctrl_t *, int, int);
- int32_t (*sensor_mode_init) (struct msm_sensor_ctrl_t *,
- int, struct sensor_init_cfg *);
- int32_t (*sensor_get_output_info) (struct msm_sensor_ctrl_t *,
- struct sensor_output_info_t *);
- int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
- int (*sensor_power_down)
- (struct msm_sensor_ctrl_t *);
- int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
- int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
- int (*sensor_adjust_frame_lines)
- (struct msm_sensor_ctrl_t *s_ctrl, uint16_t res);
- int32_t (*sensor_get_csi_params)(struct msm_sensor_ctrl_t *,
- struct csi_lane_params_t *);
-};
-
-struct msm_sensor_csi_info {
- uint32_t csid_version;
- uint8_t is_csic;
-};
-
-struct msm_sensor_ctrl_t {
- struct msm_camera_sensor_info *sensordata;
- struct i2c_client *msm_sensor_client;
- struct i2c_driver *sensor_i2c_driver;
- struct msm_camera_i2c_client *sensor_i2c_client;
- struct platform_device *pdev;
- uint16_t sensor_i2c_addr;
-
- struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr;
- struct msm_sensor_id_info_t *sensor_id_info;
- struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info;
- struct msm_sensor_reg_t *msm_sensor_reg;
- struct msm_sensor_v4l2_ctrl_info_t *msm_sensor_v4l2_ctrl_info;
- uint16_t num_v4l2_ctrl;
- uint32_t csid_version;
- uint8_t is_csic;
-
- uint16_t curr_line_length_pclk;
- uint16_t curr_frame_length_lines;
- uint16_t prev_gain;
- uint16_t prev_line;
-
- uint32_t fps_divider;
- enum msm_sensor_resolution_t curr_res;
- enum msm_sensor_cam_mode_t cam_mode;
-
- struct mutex *msm_sensor_mutex;
- struct msm_camera_csi2_params *curr_csi_params;
- struct msm_camera_csi2_params **csi_params;
- struct msm_camera_csi_params **csic_params;
- struct msm_camera_csi_params *curr_csic_params;
-
- struct v4l2_subdev sensor_v4l2_subdev;
- struct v4l2_subdev_info *sensor_v4l2_subdev_info;
- uint8_t sensor_v4l2_subdev_info_size;
- struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
- struct msm_sensor_fn_t *func_tbl;
- struct regulator **reg_ptr;
- struct clk *cam_clk;
- long clk_rate;
-};
+#include "msm_sensor_common.h"
void msm_sensor_start_stream(struct msm_sensor_ctrl_t *s_ctrl);
void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl);
@@ -250,11 +85,9 @@
int32_t msm_sensor_write_output_settings(struct msm_sensor_ctrl_t *s_ctrl,
uint16_t res);
-int32_t msm_sensor_adjust_frame_lines1(struct msm_sensor_ctrl_t *s_ctrl,
- uint16_t res);
+void msm_sensor_adjust_frame_lines1(struct msm_sensor_ctrl_t *s_ctrl);
-int32_t msm_sensor_adjust_frame_lines2(struct msm_sensor_ctrl_t *s_ctrl,
- uint16_t res);
+void msm_sensor_adjust_frame_lines2(struct msm_sensor_ctrl_t *s_ctrl);
int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
int update_type, int res);
@@ -270,12 +103,11 @@
int32_t msm_sensor_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
struct csi_lane_params_t *sensor_output_info);
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl);
-struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
-
#define VIDIOC_MSM_SENSOR_CFG \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 10, void __user *)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 4, void __user *)
#define VIDIOC_MSM_SENSOR_RELEASE \
_IO('V', BASE_VIDIOC_PRIVATE + 11)
diff --git a/drivers/media/video/msm/sensors/msm_sensor_bayer.c b/drivers/media/video/msm/sensors/msm_sensor_bayer.c
new file mode 100644
index 0000000..c867867
--- /dev/null
+++ b/drivers/media/video/msm/sensors/msm_sensor_bayer.c
@@ -0,0 +1,906 @@
+/* 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 "msm_sensor_bayer.h"
+#include "msm.h"
+#include "msm_ispif.h"
+#include "msm_camera_i2c_mux.h"
+/*=============================================================*/
+
+long msm_sensor_bayer_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+ void __user *argp = (void __user *)arg;
+ switch (cmd) {
+ case VIDIOC_MSM_SENSOR_CFG:
+ return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
+ case VIDIOC_MSM_SENSOR_RELEASE:
+ return 0;
+ case VIDIOC_MSM_SENSOR_CSID_INFO: {
+ struct msm_sensor_csi_info *csi_info =
+ (struct msm_sensor_csi_info *)arg;
+ s_ctrl->is_csic = csi_info->is_csic;
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+int32_t msm_sensor_bayer_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
+ struct csi_lane_params_t *sensor_output_info)
+{
+ uint8_t index;
+ struct msm_camera_csi_lane_params *csi_lane_params =
+ s_ctrl->sensordata->sensor_platform_info->csi_lane_params;
+ if (csi_lane_params) {
+ sensor_output_info->csi_lane_assign = csi_lane_params->
+ csi_lane_assign;
+ sensor_output_info->csi_lane_mask = csi_lane_params->
+ csi_lane_mask;
+ }
+ sensor_output_info->csi_if = s_ctrl->sensordata->csi_if;
+ for (index = 0; index < sensor_output_info->csi_if; index++)
+ sensor_output_info->csid_core[index] = s_ctrl->sensordata->
+ pdata[index].csid_core;
+
+ return 0;
+}
+
+int32_t msm_sensor_bayer_config(struct msm_sensor_ctrl_t *s_ctrl,
+ void __user *argp)
+{
+ struct sensor_cfg_data cdata;
+ long rc = 0;
+ if (copy_from_user(&cdata,
+ (void *)argp,
+ sizeof(struct sensor_cfg_data)))
+ return -EFAULT;
+ mutex_lock(s_ctrl->msm_sensor_mutex);
+ CDBG("%s:%d %s cfgtype = %d\n", __func__, __LINE__,
+ s_ctrl->sensordata->sensor_name, cdata.cfgtype);
+ switch (cdata.cfgtype) {
+ case CFG_WRITE_I2C_ARRAY: {
+ struct msm_camera_i2c_reg_setting conf_array;
+ struct msm_camera_i2c_reg_array *regs = NULL;
+
+ if (copy_from_user(&conf_array,
+ (void *)cdata.cfg.setting,
+ sizeof(struct msm_camera_i2c_reg_setting))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+
+ regs = kzalloc(conf_array.size * sizeof(
+ struct msm_camera_i2c_reg_array),
+ GFP_KERNEL);
+ if (!regs) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+
+ if (copy_from_user(regs, (void *)conf_array.reg_setting,
+ conf_array.size * sizeof(
+ struct msm_camera_i2c_reg_array))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ kfree(regs);
+ rc = -EFAULT;
+ break;
+ }
+
+ conf_array.reg_setting = regs;
+ rc = msm_camera_i2c_write_bayer_table(s_ctrl->sensor_i2c_client,
+ &conf_array);
+ kfree(regs);
+ break;
+ }
+ case CFG_READ_I2C_ARRAY: {
+ struct msm_camera_i2c_reg_setting conf_array;
+ struct msm_camera_i2c_reg_array *regs;
+ int index;
+
+ if (copy_from_user(&conf_array,
+ (void *)cdata.cfg.setting,
+ sizeof(struct msm_camera_i2c_reg_setting))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+
+ regs = kzalloc(conf_array.size * sizeof(
+ struct msm_camera_i2c_reg_array),
+ GFP_KERNEL);
+ if (!regs) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ kfree(regs);
+ break;
+ }
+
+ if (copy_from_user(regs, (void *)conf_array.reg_setting,
+ conf_array.size * sizeof(
+ struct msm_camera_i2c_reg_array))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ kfree(regs);
+ rc = -EFAULT;
+ break;
+ }
+
+ s_ctrl->sensor_i2c_client->addr_type = conf_array.addr_type;
+ for (index = 0; index < conf_array.size; index++) {
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client,
+ regs[index].reg_addr,
+ ®s[index].reg_data,
+ conf_array.data_type
+ );
+ }
+
+ if (copy_to_user(conf_array.reg_setting,
+ regs,
+ conf_array.size * sizeof(
+ struct msm_camera_i2c_reg_array))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ kfree(regs);
+ rc = -EFAULT;
+ break;
+ }
+ s_ctrl->sensor_i2c_client->addr_type = conf_array.addr_type;
+ kfree(regs);
+ break;
+ }
+ case CFG_PCLK_CHANGE: {
+ uint32_t pclk = cdata.cfg.pclk;
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+ NOTIFY_PCLK_CHANGE, &pclk);
+ break;
+ }
+ case CFG_GPIO_OP: {
+ struct msm_cam_gpio_operation gop;
+ if (copy_from_user(&gop,
+ (void *)cdata.cfg.setting,
+ sizeof(struct msm_cam_gpio_operation))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ }
+ switch (gop.op_type) {
+ case GPIO_GET_VALUE:
+ gop.value = gpio_get_value(gop.address);
+ if (copy_from_user((void *)cdata.cfg.setting,
+ &gop,
+ sizeof(struct msm_cam_gpio_operation))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ case GPIO_SET_VALUE:
+ gpio_set_value(gop.address, gop.value);
+ break;
+ case GPIO_SET_DIRECTION_INPUT:
+ gpio_direction_input(gop.address);
+ break;
+ case GPIO_SET_DIRECTION_OUTPUT:
+ gpio_direction_output(gop.address, gop.value);
+ break;
+ case GPIO_REQUEST:
+ gpio_request(gop.address, gop.tag);
+ break;
+ case GPIO_FREE:
+ gpio_free(gop.address);
+ break;
+ default:
+ break;
+ }
+
+ break;
+ }
+ case CFG_GET_CSI_PARAMS:
+ if (s_ctrl->func_tbl->sensor_get_csi_params == NULL) {
+ rc = -EFAULT;
+ break;
+ }
+ rc = s_ctrl->func_tbl->sensor_get_csi_params(
+ s_ctrl,
+ &cdata.cfg.csi_lane_params);
+
+ if (copy_to_user((void *)argp,
+ &cdata,
+ sizeof(struct sensor_cfg_data)))
+ rc = -EFAULT;
+ break;
+
+ case CFG_POWER_UP:
+ if (s_ctrl->func_tbl->sensor_power_up)
+ rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+ else
+ rc = -EFAULT;
+ break;
+
+ case CFG_POWER_DOWN:
+ if (s_ctrl->func_tbl->sensor_power_down)
+ rc = s_ctrl->func_tbl->sensor_power_down(
+ s_ctrl);
+ else
+ rc = -EFAULT;
+ break;
+
+ case CFG_CONFIG_VREG_ARRAY: {
+ struct msm_camera_vreg_setting vreg_setting;
+ struct camera_vreg_t *cam_vreg = NULL;
+
+ if (copy_from_user(&vreg_setting,
+ (void *)cdata.cfg.setting,
+ sizeof(struct msm_camera_vreg_setting))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+
+ cam_vreg = kzalloc(vreg_setting.num_vreg * sizeof(
+ struct camera_vreg_t),
+ GFP_KERNEL);
+ if (!cam_vreg) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+
+ if (copy_from_user(cam_vreg, (void *)vreg_setting.cam_vreg,
+ vreg_setting.num_vreg * sizeof(
+ struct camera_vreg_t))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ kfree(cam_vreg);
+ rc = -EFAULT;
+ break;
+ }
+ rc = msm_camera_config_vreg(
+ &s_ctrl->sensor_i2c_client->client->dev,
+ cam_vreg,
+ vreg_setting.num_vreg,
+ NULL,
+ 0,
+ s_ctrl->reg_ptr,
+ vreg_setting.enable);
+ if (rc < 0) {
+ kfree(cam_vreg);
+ pr_err("%s: regulator on failed\n", __func__);
+ break;
+ }
+
+ rc = msm_camera_enable_vreg(
+ &s_ctrl->sensor_i2c_client->client->dev,
+ cam_vreg,
+ vreg_setting.num_vreg,
+ NULL,
+ 0,
+ s_ctrl->reg_ptr,
+ vreg_setting.enable);
+ if (rc < 0) {
+ kfree(cam_vreg);
+ pr_err("%s: enable regulator failed\n", __func__);
+ break;
+ }
+ kfree(cam_vreg);
+ break;
+ }
+ case CFG_CONFIG_CLK_ARRAY: {
+ struct msm_cam_clk_setting clk_setting;
+ struct msm_cam_clk_info *clk_info = NULL;
+
+ if (copy_from_user(&clk_setting,
+ (void *)cdata.cfg.setting,
+ sizeof(struct msm_camera_vreg_setting))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+
+ clk_info = kzalloc(clk_setting.num_clk_info * sizeof(
+ struct msm_cam_clk_info),
+ GFP_KERNEL);
+ if (!clk_info) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+
+ if (copy_from_user(clk_info, (void *)clk_setting.clk_info,
+ clk_setting.num_clk_info * sizeof(
+ struct msm_cam_clk_info))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ kfree(clk_info);
+ rc = -EFAULT;
+ break;
+ }
+ rc = msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->dev,
+ clk_info, s_ctrl->cam_clk,
+ clk_setting.num_clk_info,
+ clk_setting.enable);
+ kfree(clk_info);
+ break;
+ }
+ case CFG_GET_EEPROM_DATA: {
+ if (copy_to_user((void *)cdata.cfg.eeprom_data.eeprom_data,
+ &s_ctrl->eeprom_data, s_ctrl->eeprom_data.length)) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ }
+ cdata.cfg.eeprom_data.index = s_ctrl->eeprom_data.length;
+ break;
+ }
+ default:
+ rc = -EFAULT;
+ break;
+ }
+
+ mutex_unlock(s_ctrl->msm_sensor_mutex);
+
+ return rc;
+}
+
+static struct msm_cam_clk_info cam_clk_info[] = {
+ {"cam_clk", MSM_SENSOR_MCLK_24HZ},
+};
+
+int32_t msm_sensor_bayer_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+{
+ struct v4l2_subdev *i2c_mux_sd =
+ dev_get_drvdata(&i2c_conf->mux_dev->dev);
+ v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+ VIDIOC_MSM_I2C_MUX_INIT, NULL);
+ v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+ VIDIOC_MSM_I2C_MUX_CFG, (void *)&i2c_conf->i2c_mux_mode);
+ return 0;
+}
+
+int32_t msm_sensor_bayer_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+{
+ struct v4l2_subdev *i2c_mux_sd =
+ dev_get_drvdata(&i2c_conf->mux_dev->dev);
+ v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+ VIDIOC_MSM_I2C_MUX_RELEASE, NULL);
+ return 0;
+}
+
+static struct msm_camera_power_seq_t sensor_power_seq[] = {
+ {REQUEST_GPIO, 0},
+ {REQUEST_VREG, 0},
+ {ENABLE_VREG, 0},
+ {ENABLE_GPIO, 0},
+ {CONFIG_CLK, 0},
+ {CONFIG_EXT_POWER_CTRL, 0},
+ {CONFIG_I2C_MUX, 0},
+};
+
+int32_t msm_sensor_bayer_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ int32_t rc = 0, size = 0, index = 0;
+ struct msm_camera_sensor_info *data = s_ctrl->sensordata;
+ struct msm_camera_power_seq_t *power_seq = NULL;
+ CDBG("%s: %d\n", __func__, __LINE__);
+ if (s_ctrl->power_seq) {
+ power_seq = s_ctrl->power_seq;
+ size = s_ctrl->num_power_seq;
+ } else {
+ power_seq = &sensor_power_seq[0];
+ size = ARRAY_SIZE(sensor_power_seq);
+ }
+
+ s_ctrl->reg_ptr = kzalloc(sizeof(struct regulator *)
+ * data->sensor_platform_info->num_vreg, GFP_KERNEL);
+ if (!s_ctrl->reg_ptr) {
+ pr_err("%s: could not allocate mem for regulators\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ for (index = 0; index < size; index++) {
+ switch (power_seq[index].power_config) {
+ case REQUEST_GPIO:
+ rc = msm_camera_request_gpio_table(data, 1);
+ if (rc < 0) {
+ pr_err("%s: request gpio failed\n", __func__);
+ goto ERROR;
+ }
+ if (power_seq[index].delay)
+ usleep_range(power_seq[index].delay * 1000,
+ (power_seq[index].delay * 1000) + 1000);
+ break;
+ case REQUEST_VREG:
+ rc = msm_camera_config_vreg(
+ &s_ctrl->sensor_i2c_client->client->dev,
+ s_ctrl->sensordata->sensor_platform_info->
+ cam_vreg,
+ s_ctrl->sensordata->sensor_platform_info->
+ num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
+ s_ctrl->reg_ptr, 1);
+ if (rc < 0) {
+ pr_err("%s: regulator on failed\n", __func__);
+ goto ERROR;
+ }
+ if (power_seq[index].delay)
+ usleep_range(power_seq[index].delay * 1000,
+ (power_seq[index].delay * 1000) + 1000);
+ break;
+ case ENABLE_VREG:
+ rc = msm_camera_enable_vreg(
+ &s_ctrl->sensor_i2c_client->client->dev,
+ s_ctrl->sensordata->sensor_platform_info->
+ cam_vreg,
+ s_ctrl->sensordata->sensor_platform_info->
+ num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
+ s_ctrl->reg_ptr, 1);
+ if (rc < 0) {
+ pr_err("%s: enable regulator failed\n",
+ __func__);
+ goto ERROR;
+ }
+ if (power_seq[index].delay)
+ usleep_range(power_seq[index].delay * 1000,
+ (power_seq[index].delay * 1000) + 1000);
+ break;
+ case ENABLE_GPIO:
+ rc = msm_camera_config_gpio_table(data, 1);
+ if (rc < 0) {
+ pr_err("%s: config gpio failed\n", __func__);
+ goto ERROR;
+ }
+ if (power_seq[index].delay)
+ usleep_range(power_seq[index].delay * 1000,
+ (power_seq[index].delay * 1000) + 1000);
+ break;
+ case CONFIG_CLK:
+ if (s_ctrl->clk_rate != 0)
+ cam_clk_info->clk_rate = s_ctrl->clk_rate;
+
+ rc = msm_cam_clk_enable(
+ &s_ctrl->sensor_i2c_client->client->dev,
+ cam_clk_info, s_ctrl->cam_clk,
+ ARRAY_SIZE(cam_clk_info), 1);
+ if (rc < 0) {
+ pr_err("%s: clk enable failed\n", __func__);
+ goto ERROR;
+ }
+ if (power_seq[index].delay)
+ usleep_range(power_seq[index].delay * 1000,
+ (power_seq[index].delay * 1000) + 1000);
+ break;
+ case CONFIG_EXT_POWER_CTRL:
+ if (data->sensor_platform_info->ext_power_ctrl != NULL)
+ data->sensor_platform_info->ext_power_ctrl(1);
+ if (power_seq[index].delay)
+ usleep_range(power_seq[index].delay * 1000,
+ (power_seq[index].delay * 1000) + 1000);
+ break;
+ case CONFIG_I2C_MUX:
+ if (data->sensor_platform_info->i2c_conf &&
+ data->sensor_platform_info->i2c_conf->
+ use_i2c_mux)
+ msm_sensor_bayer_enable_i2c_mux(
+ data->sensor_platform_info->i2c_conf);
+ if (power_seq[index].delay)
+ usleep_range(power_seq[index].delay * 1000,
+ (power_seq[index].delay * 1000) + 1000);
+ break;
+ default:
+ pr_err("%s error power config %d\n", __func__,
+ power_seq[index].power_config);
+ rc = -EINVAL;
+ break;
+ }
+ }
+
+ return rc;
+
+ERROR:
+ for (index--; index >= 0; index--) {
+ switch (power_seq[index].power_config) {
+ case CONFIG_I2C_MUX:
+ if (data->sensor_platform_info->i2c_conf &&
+ data->sensor_platform_info->i2c_conf->
+ use_i2c_mux)
+ msm_sensor_bayer_disable_i2c_mux(
+ data->sensor_platform_info->i2c_conf);
+ break;
+ case CONFIG_EXT_POWER_CTRL:
+ if (data->sensor_platform_info->ext_power_ctrl != NULL)
+ data->sensor_platform_info->ext_power_ctrl(0);
+ break;
+ case CONFIG_CLK:
+ msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->
+ dev, cam_clk_info, s_ctrl->cam_clk,
+ ARRAY_SIZE(cam_clk_info), 0);
+ break;
+ case ENABLE_GPIO:
+ msm_camera_config_gpio_table(data, 0);
+ break;
+ case ENABLE_VREG:
+ msm_camera_enable_vreg(&s_ctrl->sensor_i2c_client->
+ client->dev,
+ s_ctrl->sensordata->sensor_platform_info->
+ cam_vreg,
+ s_ctrl->sensordata->sensor_platform_info->
+ num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
+ s_ctrl->reg_ptr, 0);
+ break;
+ case REQUEST_VREG:
+ msm_camera_config_vreg(&s_ctrl->sensor_i2c_client->
+ client->dev,
+ s_ctrl->sensordata->sensor_platform_info->
+ cam_vreg,
+ s_ctrl->sensordata->sensor_platform_info->
+ num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
+ s_ctrl->reg_ptr, 0);
+ break;
+ case REQUEST_GPIO:
+ msm_camera_request_gpio_table(data, 0);
+ break;
+ default:
+ pr_err("%s error power config %d\n", __func__,
+ power_seq[index].power_config);
+ break;
+ }
+ }
+ kfree(s_ctrl->reg_ptr);
+ return rc;
+}
+
+int32_t msm_sensor_bayer_power_down(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ int32_t size = 0, index = 0;
+ struct msm_camera_sensor_info *data = s_ctrl->sensordata;
+ struct msm_camera_power_seq_t *power_seq = NULL;
+ CDBG("%s\n", __func__);
+
+ if (s_ctrl->power_seq) {
+ power_seq = s_ctrl->power_seq;
+ size = s_ctrl->num_power_seq;
+ } else {
+ power_seq = &sensor_power_seq[0];
+ size = ARRAY_SIZE(sensor_power_seq);
+ }
+
+ for (index = (size - 1); index >= 0; index--) {
+ switch (power_seq[index].power_config) {
+ case CONFIG_I2C_MUX:
+ if (data->sensor_platform_info->i2c_conf &&
+ data->sensor_platform_info->i2c_conf->
+ use_i2c_mux)
+ msm_sensor_bayer_disable_i2c_mux(
+ data->sensor_platform_info->i2c_conf);
+ break;
+ case CONFIG_EXT_POWER_CTRL:
+ if (data->sensor_platform_info->ext_power_ctrl != NULL)
+ data->sensor_platform_info->ext_power_ctrl(0);
+ break;
+ case CONFIG_CLK:
+ msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->
+ dev, cam_clk_info, s_ctrl->cam_clk,
+ ARRAY_SIZE(cam_clk_info), 0);
+ break;
+ case ENABLE_GPIO:
+ msm_camera_config_gpio_table(data, 0);
+ break;
+ case ENABLE_VREG:
+ msm_camera_enable_vreg(&s_ctrl->sensor_i2c_client->
+ client->dev,
+ s_ctrl->sensordata->sensor_platform_info->
+ cam_vreg,
+ s_ctrl->sensordata->sensor_platform_info->
+ num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
+ s_ctrl->reg_ptr, 0);
+ break;
+ case REQUEST_VREG:
+ msm_camera_config_vreg(&s_ctrl->sensor_i2c_client->
+ client->dev,
+ s_ctrl->sensordata->sensor_platform_info->
+ cam_vreg,
+ s_ctrl->sensordata->sensor_platform_info->
+ num_vreg,
+ s_ctrl->vreg_seq,
+ s_ctrl->num_vreg_seq,
+ s_ctrl->reg_ptr, 0);
+ break;
+ case REQUEST_GPIO:
+ msm_camera_request_gpio_table(data, 0);
+ break;
+ default:
+ pr_err("%s error power config %d\n", __func__,
+ power_seq[index].power_config);
+ break;
+ }
+ }
+ kfree(s_ctrl->reg_ptr);
+ return 0;
+}
+
+int32_t msm_sensor_bayer_match_id(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ int32_t rc = 0;
+ uint16_t chipid = 0;
+ rc = msm_camera_i2c_read(
+ s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_id_info->sensor_id_reg_addr, &chipid,
+ MSM_CAMERA_I2C_WORD_DATA);
+ if (rc < 0) {
+ pr_err("%s: %s: read id failed\n", __func__,
+ s_ctrl->sensordata->sensor_name);
+ return rc;
+ }
+
+ CDBG("%s: read id: %x expected id %x:\n", __func__, chipid,
+ s_ctrl->sensor_id_info->sensor_id);
+ if (chipid != s_ctrl->sensor_id_info->sensor_id) {
+ pr_err("msm_sensor_match_id chip id doesnot match\n");
+ return -ENODEV;
+ }
+ return rc;
+}
+
+static int32_t msm_sensor_bayer_eeprom_read(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ uint32_t reg_addr = 0;
+ uint8_t *data = s_ctrl->eeprom_data.data;
+ uint32_t num_byte = 0;
+ int rc = 0;
+ uint32_t i2c_addr;
+ struct msm_camera_sensor_info *sensor_info = s_ctrl->sensordata;
+ i2c_addr = sensor_info->eeprom_info->eeprom_i2c_slave_addr;
+ num_byte = s_ctrl->eeprom_data.length = sensor_info->eeprom_info->
+ eeprom_read_length;
+ reg_addr = sensor_info->eeprom_info->eeprom_reg_addr;
+
+ data = kzalloc(num_byte * sizeof(uint8_t), GFP_KERNEL);
+ if (!data) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ return rc;
+ }
+
+ s_ctrl->sensor_i2c_client->client->addr = i2c_addr;
+ CDBG("eeprom read: i2c addr is %x num byte %d reg addr %x\n",
+ i2c_addr, num_byte, reg_addr);
+ rc = msm_camera_i2c_read_seq(s_ctrl->sensor_i2c_client, reg_addr, data,
+ num_byte);
+ s_ctrl->sensor_i2c_client->client->addr = s_ctrl->sensor_i2c_addr;
+ return rc;
+}
+
+int32_t msm_sensor_bayer_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc = 0;
+ struct msm_sensor_ctrl_t *s_ctrl;
+ CDBG("%s %s_i2c_probe called\n", __func__, client->name);
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ pr_err("%s %s i2c_check_functionality failed\n",
+ __func__, client->name);
+ rc = -EFAULT;
+ return rc;
+ }
+
+ s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+ if (s_ctrl->sensor_i2c_client != NULL) {
+ s_ctrl->sensor_i2c_client->client = client;
+ if (s_ctrl->sensor_i2c_addr != 0)
+ s_ctrl->sensor_i2c_client->client->addr =
+ s_ctrl->sensor_i2c_addr;
+ } else {
+ pr_err("%s %s sensor_i2c_client NULL\n",
+ __func__, client->name);
+ rc = -EFAULT;
+ return rc;
+ }
+
+ s_ctrl->sensordata = client->dev.platform_data;
+ if (s_ctrl->sensordata == NULL) {
+ pr_err("%s %s NULL sensor data\n", __func__, client->name);
+ return -EFAULT;
+ }
+
+ rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+ if (rc < 0) {
+ pr_err("%s %s power up failed\n", __func__, client->name);
+ return rc;
+ }
+
+ if (s_ctrl->func_tbl->sensor_match_id)
+ rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
+ else
+ rc = msm_sensor_bayer_match_id(s_ctrl);
+ if (rc < 0)
+ goto probe_fail;
+
+ if (!s_ctrl->wait_num_frames)
+ s_ctrl->wait_num_frames = 1;
+
+ pr_err("%s %s probe succeeded\n", __func__, client->name);
+ snprintf(s_ctrl->sensor_v4l2_subdev.name,
+ sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
+ v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
+ s_ctrl->sensor_v4l2_subdev_ops);
+ s_ctrl->sensor_v4l2_subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ media_entity_init(&s_ctrl->sensor_v4l2_subdev.entity, 0, NULL, 0);
+ s_ctrl->sensor_v4l2_subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ s_ctrl->sensor_v4l2_subdev.entity.group_id = SENSOR_DEV;
+ s_ctrl->sensor_v4l2_subdev.entity.name =
+ s_ctrl->sensor_v4l2_subdev.name;
+ msm_sensor_register(&s_ctrl->sensor_v4l2_subdev);
+ s_ctrl->sensor_v4l2_subdev.entity.revision =
+ s_ctrl->sensor_v4l2_subdev.devnode->num;
+ msm_sensor_bayer_eeprom_read(s_ctrl);
+ goto power_down;
+probe_fail:
+ pr_err("%s %s_i2c_probe failed\n", __func__, client->name);
+power_down:
+ if (rc > 0)
+ rc = 0;
+ s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ return rc;
+}
+
+int32_t msm_sensor_delay_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc = 0;
+ struct msm_sensor_ctrl_t *s_ctrl;
+ CDBG("%s %s_delay_i2c_probe called\n", __func__, client->name);
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ pr_err("%s %s i2c_check_functionality failed\n",
+ __func__, client->name);
+ rc = -EFAULT;
+ return rc;
+ }
+
+ s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+ if (s_ctrl->sensor_i2c_client != NULL) {
+ s_ctrl->sensor_i2c_client->client = client;
+ if (s_ctrl->sensor_i2c_addr != 0)
+ s_ctrl->sensor_i2c_client->client->addr =
+ s_ctrl->sensor_i2c_addr;
+ } else {
+ pr_err("%s %s sensor_i2c_client NULL\n",
+ __func__, client->name);
+ rc = -EFAULT;
+ return rc;
+ }
+
+ s_ctrl->sensordata = client->dev.platform_data;
+ if (s_ctrl->sensordata == NULL) {
+ pr_err("%s %s NULL sensor data\n", __func__, client->name);
+ return -EFAULT;
+ }
+
+ if (!s_ctrl->wait_num_frames)
+ s_ctrl->wait_num_frames = 1;
+
+ pr_err("%s %s probe succeeded\n", __func__, client->name);
+ snprintf(s_ctrl->sensor_v4l2_subdev.name,
+ sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
+ v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
+ s_ctrl->sensor_v4l2_subdev_ops);
+ s_ctrl->sensor_v4l2_subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ media_entity_init(&s_ctrl->sensor_v4l2_subdev.entity, 0, NULL, 0);
+ s_ctrl->sensor_v4l2_subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ s_ctrl->sensor_v4l2_subdev.entity.group_id = SENSOR_DEV;
+ s_ctrl->sensor_v4l2_subdev.entity.name =
+ s_ctrl->sensor_v4l2_subdev.name;
+ msm_sensor_register(&s_ctrl->sensor_v4l2_subdev);
+ s_ctrl->sensor_v4l2_subdev.entity.revision =
+ s_ctrl->sensor_v4l2_subdev.devnode->num;
+ if (rc > 0)
+ rc = 0;
+ return rc;
+}
+
+int32_t msm_sensor_bayer_power(struct v4l2_subdev *sd, int on)
+{
+ int rc = 0;
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+ mutex_lock(s_ctrl->msm_sensor_mutex);
+ if (!on)
+ rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ mutex_unlock(s_ctrl->msm_sensor_mutex);
+ return rc;
+}
+
+int32_t msm_sensor_bayer_v4l2_enum_fmt(struct v4l2_subdev *sd,
+ unsigned int index, enum v4l2_mbus_pixelcode *code)
+{
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+
+ if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size)
+ return -EINVAL;
+
+ *code = s_ctrl->sensor_v4l2_subdev_info[index].code;
+ return 0;
+}
+
+int32_t msm_sensor_bayer_v4l2_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ int rc = -1, i = 0;
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+ struct msm_sensor_v4l2_ctrl_info_t *v4l2_ctrl =
+ s_ctrl->msm_sensor_v4l2_ctrl_info;
+
+ CDBG("%s\n", __func__);
+ CDBG("%d\n", ctrl->id);
+ if (v4l2_ctrl == NULL)
+ return rc;
+ for (i = 0; i < s_ctrl->num_v4l2_ctrl; i++) {
+ if (v4l2_ctrl[i].ctrl_id == ctrl->id) {
+ if (v4l2_ctrl[i].s_v4l2_ctrl != NULL) {
+ CDBG("\n calling msm_sensor_s_ctrl_by_enum\n");
+ rc = v4l2_ctrl[i].s_v4l2_ctrl(
+ s_ctrl,
+ &s_ctrl->msm_sensor_v4l2_ctrl_info[i],
+ ctrl->value);
+ }
+ break;
+ }
+ }
+
+ return rc;
+}
+
+int32_t msm_sensor_bayer_v4l2_query_ctrl(
+ struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
+{
+ int rc = -1, i = 0;
+ struct msm_sensor_ctrl_t *s_ctrl =
+ (struct msm_sensor_ctrl_t *) sd->dev_priv;
+
+ CDBG("%s\n", __func__);
+ CDBG("%s id: %d\n", __func__, qctrl->id);
+
+ if (s_ctrl->msm_sensor_v4l2_ctrl_info == NULL)
+ return rc;
+
+ for (i = 0; i < s_ctrl->num_v4l2_ctrl; i++) {
+ if (s_ctrl->msm_sensor_v4l2_ctrl_info[i].ctrl_id == qctrl->id) {
+ qctrl->minimum =
+ s_ctrl->msm_sensor_v4l2_ctrl_info[i].min;
+ qctrl->maximum =
+ s_ctrl->msm_sensor_v4l2_ctrl_info[i].max;
+ qctrl->flags = 1;
+ rc = 0;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+int msm_sensor_bayer_s_ctrl_by_enum(struct msm_sensor_ctrl_t *s_ctrl,
+ struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value)
+{
+ int rc = 0;
+ CDBG("%s enter\n", __func__);
+ rc = msm_sensor_write_enum_conf_array(
+ s_ctrl->sensor_i2c_client,
+ ctrl_info->enum_cfg_settings, value);
+ return rc;
+}
+
diff --git a/drivers/media/video/msm/sensors/msm_sensor_bayer.h b/drivers/media/video/msm/sensors/msm_sensor_bayer.h
new file mode 100644
index 0000000..d12244b
--- /dev/null
+++ b/drivers/media/video/msm/sensors/msm_sensor_bayer.h
@@ -0,0 +1,76 @@
+/* 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.
+ */
+
+#ifndef MSM_SENSOR_BAYER_H
+#define MSM_SENSOR_BAYER_H
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <mach/camera.h>
+#include <mach/gpio.h>
+#include <media/msm_camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_eeprom.h"
+#include "msm_sensor_common.h"
+
+struct sensor_driver_t {
+ struct platform_driver *platform_pdriver;
+ int32_t (*platform_probe)(struct platform_device *pdev);
+};
+
+int32_t msm_sensor_bayer_config(struct msm_sensor_ctrl_t *s_ctrl,
+ void __user *argp);
+int32_t msm_sensor_bayer_power_up(struct msm_sensor_ctrl_t *s_ctrl);
+int32_t msm_sensor_bayer_power_down(struct msm_sensor_ctrl_t *s_ctrl);
+
+int32_t msm_sensor_bayer_match_id(struct msm_sensor_ctrl_t *s_ctrl);
+int msm_sensor_bayer_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+int32_t msm_sensor_delay_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+int32_t msm_sensor_bayer_power(struct v4l2_subdev *sd, int on);
+
+int32_t msm_sensor_bayer_v4l2_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl);
+
+int32_t msm_sensor_bayer_v4l2_query_ctrl(
+ struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl);
+
+int msm_sensor_bayer_s_ctrl_by_enum(struct msm_sensor_ctrl_t *s_ctrl,
+ struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value);
+
+int msm_sensor_bayer_v4l2_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code);
+
+long msm_sensor_bayer_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg);
+
+int32_t msm_sensor_bayer_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
+ struct csi_lane_params_t *sensor_output_info);
+
+#define VIDIOC_MSM_SENSOR_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 4, void __user *)
+
+#define VIDIOC_MSM_SENSOR_RELEASE \
+ _IO('V', BASE_VIDIOC_PRIVATE + 11)
+
+#define VIDIOC_MSM_SENSOR_CSID_INFO\
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_sensor_csi_info *)
+#endif
diff --git a/drivers/media/video/msm/sensors/msm_sensor_common.c b/drivers/media/video/msm/sensors/msm_sensor_common.c
new file mode 100644
index 0000000..9dac632
--- /dev/null
+++ b/drivers/media/video/msm/sensors/msm_sensor_common.c
@@ -0,0 +1,18 @@
+/* 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 "msm_sensor_common.h"
+
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct msm_sensor_ctrl_t, sensor_v4l2_subdev);
+}
diff --git a/drivers/media/video/msm/sensors/msm_sensor_common.h b/drivers/media/video/msm/sensors/msm_sensor_common.h
new file mode 100644
index 0000000..79fe52e
--- /dev/null
+++ b/drivers/media/video/msm/sensors/msm_sensor_common.h
@@ -0,0 +1,226 @@
+/* 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.
+ */
+
+#ifndef MSM_SENSOR_COMMON_H
+#define MSM_SENSOR_COMMON_H
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <mach/camera.h>
+#include <media/msm_camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_eeprom.h"
+#define Q8 0x00000100
+#define Q10 0x00000400
+
+#define MSM_SENSOR_MCLK_8HZ 8000000
+#define MSM_SENSOR_MCLK_16HZ 16000000
+#define MSM_SENSOR_MCLK_24HZ 24000000
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+ static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+struct gpio_tlmm_cfg {
+ uint32_t gpio;
+ uint32_t dir;
+ uint32_t pull;
+ uint32_t drvstr;
+};
+
+enum msm_sensor_reg_update {
+ /* Sensor egisters that need to be updated during initialization */
+ MSM_SENSOR_REG_INIT,
+ /* Sensor egisters that needs periodic I2C writes */
+ MSM_SENSOR_UPDATE_PERIODIC,
+ /* All the sensor Registers will be updated */
+ MSM_SENSOR_UPDATE_ALL,
+ /* Not valid update */
+ MSM_SENSOR_UPDATE_INVALID
+};
+
+enum msm_sensor_cam_mode_t {
+ MSM_SENSOR_MODE_2D_RIGHT,
+ MSM_SENSOR_MODE_2D_LEFT,
+ MSM_SENSOR_MODE_3D,
+ MSM_SENSOR_MODE_INVALID
+};
+
+enum msm_camera_power_config_t {
+ REQUEST_GPIO,
+ ENABLE_GPIO,
+ REQUEST_VREG,
+ ENABLE_VREG,
+ CONFIG_CLK,
+ CONFIG_EXT_POWER_CTRL,
+ CONFIG_I2C_MUX,
+};
+
+struct msm_camera_power_seq_t {
+ enum msm_camera_power_config_t power_config;
+ uint32_t delay;
+};
+
+struct msm_sensor_id_info_t {
+ uint16_t sensor_id_reg_addr;
+ uint16_t sensor_id;
+};
+
+struct msm_sensor_reg_t {
+ enum msm_camera_i2c_data_type default_data_type;
+ struct msm_camera_i2c_reg_conf *start_stream_conf;
+ uint8_t start_stream_conf_size;
+ struct msm_camera_i2c_reg_conf *stop_stream_conf;
+ uint8_t stop_stream_conf_size;
+ struct msm_camera_i2c_reg_conf *group_hold_on_conf;
+ uint8_t group_hold_on_conf_size;
+ struct msm_camera_i2c_reg_conf *group_hold_off_conf;
+ uint8_t group_hold_off_conf_size;
+ struct msm_camera_i2c_conf_array *init_settings;
+ uint8_t init_size;
+ struct msm_camera_i2c_conf_array *mode_settings;
+ struct msm_camera_i2c_conf_array *no_effect_settings;
+ struct msm_sensor_output_info_t *output_settings;
+ uint8_t num_conf;
+};
+
+enum msm_sensor_device_type_t {
+ MSM_SENSOR_I2C_DEVICE,
+ MSM_SENSOR_PLATFORM_DEVICE,
+};
+
+struct v4l2_subdev_info {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+ uint16_t fmt;
+ uint16_t order;
+};
+
+struct msm_sensor_ctrl_t;
+
+struct msm_sensor_v4l2_ctrl_info_t {
+ uint32_t ctrl_id;
+ int16_t min;
+ int16_t max;
+ int16_t step;
+ struct msm_camera_i2c_enum_conf_array *enum_cfg_settings;
+ int (*s_v4l2_ctrl) (struct msm_sensor_ctrl_t *,
+ struct msm_sensor_v4l2_ctrl_info_t *, int);
+};
+
+struct msm_sensor_fn_t {
+ void (*sensor_start_stream) (struct msm_sensor_ctrl_t *);
+ void (*sensor_stop_stream) (struct msm_sensor_ctrl_t *);
+ void (*sensor_group_hold_on) (struct msm_sensor_ctrl_t *);
+ void (*sensor_group_hold_off) (struct msm_sensor_ctrl_t *);
+
+ int32_t (*sensor_set_fps) (struct msm_sensor_ctrl_t *,
+ struct fps_cfg *);
+ int32_t (*sensor_write_exp_gain) (struct msm_sensor_ctrl_t *,
+ uint16_t, uint32_t);
+ int32_t (*sensor_write_snapshot_exp_gain) (struct msm_sensor_ctrl_t *,
+ uint16_t, uint32_t);
+ int32_t (*sensor_setting) (struct msm_sensor_ctrl_t *,
+ int update_type, int rt);
+ int32_t (*sensor_csi_setting) (struct msm_sensor_ctrl_t *,
+ int update_type, int rt);
+ int32_t (*sensor_set_sensor_mode)
+ (struct msm_sensor_ctrl_t *, int, int);
+ int32_t (*sensor_mode_init) (struct msm_sensor_ctrl_t *,
+ int, struct sensor_init_cfg *);
+ int32_t (*sensor_get_output_info) (struct msm_sensor_ctrl_t *,
+ struct sensor_output_info_t *);
+ int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
+ int (*sensor_power_down)
+ (struct msm_sensor_ctrl_t *);
+ int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
+ int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
+ void (*sensor_adjust_frame_lines) (struct msm_sensor_ctrl_t *s_ctrl);
+ int32_t (*sensor_get_csi_params)(struct msm_sensor_ctrl_t *,
+ struct csi_lane_params_t *);
+};
+
+struct msm_sensor_csi_info {
+ uint8_t is_csic;
+};
+
+enum msm_sensor_state {
+ MSM_SENSOR_POWER_UP,
+ MSM_SENSOR_POWER_DOWN,
+};
+
+struct msm_sensor_eeprom_data {
+ uint8_t *data;
+ uint32_t length;
+};
+
+struct msm_sensor_ctrl_t {
+ struct msm_camera_sensor_info *sensordata;
+ struct i2c_client *msm_sensor_client;
+ struct i2c_driver *sensor_i2c_driver;
+ struct platform_device *pdev;
+ struct msm_camera_i2c_client *sensor_i2c_client;
+ uint16_t sensor_i2c_addr;
+ enum msm_camera_vreg_name_t *vreg_seq;
+ int num_vreg_seq;
+ struct msm_camera_power_seq_t *power_seq;
+ int num_power_seq;
+ enum msm_sensor_device_type_t sensor_device_type;
+
+ struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr;
+ struct msm_sensor_id_info_t *sensor_id_info;
+ struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info;
+ struct msm_sensor_reg_t *msm_sensor_reg;
+ struct msm_sensor_v4l2_ctrl_info_t *msm_sensor_v4l2_ctrl_info;
+ uint16_t num_v4l2_ctrl;
+ uint8_t is_csic;
+
+ uint16_t curr_line_length_pclk;
+ uint16_t curr_frame_length_lines;
+
+ uint32_t fps_divider;
+ enum msm_sensor_resolution_t curr_res;
+ enum msm_sensor_cam_mode_t cam_mode;
+
+ struct mutex *msm_sensor_mutex;
+
+ struct v4l2_subdev sensor_v4l2_subdev;
+ struct v4l2_subdev_info *sensor_v4l2_subdev_info;
+ uint8_t sensor_v4l2_subdev_info_size;
+ struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
+ struct msm_sensor_fn_t *func_tbl;
+ struct regulator **reg_ptr;
+ struct clk *cam_clk[2];
+ long clk_rate;
+ enum msm_sensor_state sensor_state;
+ /* Number of frames to delay after start / stop stream in Q10 format.
+ Initialize to -1 for this value to be ignored */
+ int16_t wait_num_frames;
+ /* minimum delay after stop / stop stream in ms */
+ uint16_t min_delay;
+ /* delay (in ms) after power up sequence */
+ uint16_t power_seq_delay;
+ struct msm_sensor_eeprom_data eeprom_data;
+};
+
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
+
+#endif
diff --git a/drivers/media/video/msm/sensors/msm_sensor_init.c b/drivers/media/video/msm/sensors/msm_sensor_init.c
new file mode 100644
index 0000000..41c00eb
--- /dev/null
+++ b/drivers/media/video/msm/sensors/msm_sensor_init.c
@@ -0,0 +1,35 @@
+/* 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_sensor.h"
+#include "msm.h"
+#include "msm_sensor_bayer.h"
+#include "imx091.h"
+
+static struct i2c_driver *sensor_i2c_driver[] = {
+ /* back camera */
+ &imx091_i2c_driver,
+ /* front camera */
+};
+
+static int __init msm_sensor_init_module(void)
+{
+ int index = 0;
+ for (index = 0; index < ARRAY_SIZE(sensor_i2c_driver); index++)
+ i2c_add_driver(sensor_i2c_driver[index]);
+ return 0;
+}
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Sensor driver probe");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/mt9e013_v4l2.c b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
index 69a5498..a38cb57 100644
--- a/drivers/media/video/msm/sensors/mt9e013_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
@@ -325,22 +325,6 @@
},
};
-static struct msm_camera_csi_params mt9e013_csi_params = {
- .data_format = CSI_10BIT,
- .lane_cnt = 2,
- .lane_assign = 0xe4,
- .dpcm_scheme = 0,
- .settle_cnt = 0x18,
-};
-
-static struct msm_camera_csi_params *mt9e013_csi_params_array[] = {
- &mt9e013_csi_params,
- &mt9e013_csi_params,
- &mt9e013_csi_params,
- &mt9e013_csi_params,
- &mt9e013_csi_params,
-};
-
static struct msm_sensor_output_reg_addr_t mt9e013_reg_addr = {
.x_output = 0x34C,
.y_output = 0x34E,
@@ -472,7 +456,6 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t mt9e013_regs = {
@@ -497,7 +480,6 @@
.sensor_id_info = &mt9e013_id_info,
.sensor_exp_gain_info = &mt9e013_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csic_params = &mt9e013_csi_params_array[0],
.msm_sensor_mutex = &mt9e013_mut,
.sensor_i2c_driver = &mt9e013_i2c_driver,
.sensor_v4l2_subdev_info = mt9e013_subdev_info,
diff --git a/drivers/media/video/msm/sensors/mt9m114_v4l2.c b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
index 806bcc2..cba9538 100644
--- a/drivers/media/video/msm/sensors/mt9m114_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
@@ -1184,30 +1184,6 @@
},
};
-static struct msm_camera_csid_vc_cfg mt9m114_cid_cfg[] = {
- {0, CSI_YUV422_8, CSI_DECODE_8BIT},
- {1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
-};
-
-static struct msm_camera_csi2_params mt9m114_csi_params = {
- .csid_params = {
- .lane_cnt = 1,
- .lut_params = {
- .num_cid = 2,
- .vc_cfg = mt9m114_cid_cfg,
- },
- },
- .csiphy_params = {
- .lane_cnt = 1,
- .settle_cnt = 0x14,
- },
-};
-
-static struct msm_camera_csi2_params *mt9m114_csi_params_array[] = {
- &mt9m114_csi_params,
- &mt9m114_csi_params,
-};
-
static struct msm_sensor_output_reg_addr_t mt9m114_reg_addr = {
.x_output = 0xC868,
.y_output = 0xC86A,
@@ -1215,6 +1191,12 @@
.frame_length_lines = 0xC86A,
};
+static enum msm_camera_vreg_name_t mt9m114_veg_seq[] = {
+ CAM_VIO,
+ CAM_VDIG,
+ CAM_VANA,
+};
+
static struct msm_sensor_id_info_t mt9m114_id_info = {
.sensor_id_reg_addr = 0x0,
.sensor_id = 0x2481,
@@ -1288,10 +1270,13 @@
.num_v4l2_ctrl = ARRAY_SIZE(mt9m114_v4l2_ctrl_info),
.sensor_i2c_client = &mt9m114_sensor_i2c_client,
.sensor_i2c_addr = 0x90,
+ .vreg_seq = mt9m114_veg_seq,
+ .num_vreg_seq = ARRAY_SIZE(mt9m114_veg_seq),
.sensor_output_reg_addr = &mt9m114_reg_addr,
.sensor_id_info = &mt9m114_id_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csi_params = &mt9m114_csi_params_array[0],
+ .min_delay = 30,
+ .power_seq_delay = 60,
.msm_sensor_mutex = &mt9m114_mut,
.sensor_i2c_driver = &mt9m114_i2c_driver,
.sensor_v4l2_subdev_info = mt9m114_subdev_info,
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index e08cd0a..1423063 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -658,34 +658,6 @@
},
};
-static struct msm_camera_csid_vc_cfg ov2720_cid_cfg[] = {
- {0, CSI_RAW10, CSI_DECODE_10BIT},
- {1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
-};
-
-static struct msm_camera_csi2_params ov2720_csi_params = {
- .csid_params = {
- .lane_cnt = 2,
- .lut_params = {
- .num_cid = 2,
- .vc_cfg = ov2720_cid_cfg,
- },
- },
- .csiphy_params = {
- .lane_cnt = 2,
- .settle_cnt = 0x1B,
- },
-};
-
-static struct msm_camera_csi2_params *ov2720_csi_params_array[] = {
- &ov2720_csi_params,
- &ov2720_csi_params,
- &ov2720_csi_params,
- &ov2720_csi_params,
- &ov2720_csi_params,
- &ov2720_csi_params,
-};
-
static struct msm_sensor_output_reg_addr_t ov2720_reg_addr = {
.x_output = 0x3808,
.y_output = 0x380a,
@@ -704,6 +676,12 @@
.vert_offset = 6,
};
+static enum msm_camera_vreg_name_t ov2720_veg_seq[] = {
+ CAM_VIO,
+ CAM_VANA,
+ CAM_VDIG,
+};
+
static int32_t ov2720_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
uint16_t gain, uint32_t line)
{
@@ -849,11 +827,12 @@
.msm_sensor_reg = &ov2720_regs,
.sensor_i2c_client = &ov2720_sensor_i2c_client,
.sensor_i2c_addr = 0x6C,
+ .vreg_seq = ov2720_veg_seq,
+ .num_vreg_seq = ARRAY_SIZE(ov2720_veg_seq),
.sensor_output_reg_addr = &ov2720_reg_addr,
.sensor_id_info = &ov2720_id_info,
.sensor_exp_gain_info = &ov2720_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csi_params = &ov2720_csi_params_array[0],
.msm_sensor_mutex = &ov2720_mut,
.sensor_i2c_driver = &ov2720_i2c_driver,
.sensor_v4l2_subdev_info = ov2720_subdev_info,
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index d192563..79aa7aa 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -343,14 +343,6 @@
ARRAY_SIZE(ov5647_zsl_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
};
-static struct msm_camera_csi_params ov5647_csi_params = {
- .data_format = CSI_8BIT,
- .lane_cnt = 2,
- .lane_assign = 0xe4,
- .dpcm_scheme = 0,
- .settle_cnt = 10,
-};
-
static struct v4l2_subdev_info ov5647_subdev_info[] = {
{
.code = V4L2_MBUS_FMT_SBGGR10_1X10,
@@ -417,14 +409,6 @@
.frame_length_lines = 0x380E,
};
-static struct msm_camera_csi_params *ov5647_csi_params_array[] = {
- &ov5647_csi_params, /* Snapshot */
- &ov5647_csi_params, /* Preview */
- &ov5647_csi_params, /* 60fps */
- &ov5647_csi_params, /* 90fps */
- &ov5647_csi_params, /* ZSL */
-};
-
static struct msm_sensor_id_info_t ov5647_id_info = {
.sensor_id_reg_addr = 0x300a,
.sensor_id = 0x5647,
@@ -572,7 +556,8 @@
s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
/* adjust frame rate */
- if (line > (fl_lines - offset))
+ if ((s_ctrl->curr_res < MSM_SENSOR_RES_2) &&
+ (line > (fl_lines - offset)))
fl_lines = line + offset;
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
@@ -733,13 +718,15 @@
static int32_t vfe_clk = 266667000;
-int32_t ov5647_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
- int update_type, int res)
+static void ov5647_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
{
- int32_t rc = 0;
- static int csi_config;
- s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
- if (csi_config == 0 || res == 0)
+ msm_camera_i2c_write_tbl(
+ s_ctrl->sensor_i2c_client,
+ s_ctrl->msm_sensor_reg->stop_stream_conf,
+ s_ctrl->msm_sensor_reg->stop_stream_conf_size,
+ s_ctrl->msm_sensor_reg->default_data_type);
+
+ if (s_ctrl->curr_res == MSM_SENSOR_RES_FULL)
msleep(66);
else
msleep(266);
@@ -748,37 +735,31 @@
s_ctrl->sensor_i2c_client,
0x4800, 0x25,
MSM_CAMERA_I2C_BYTE_DATA);
+}
+
+int32_t ov5647_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
+ int update_type, int res)
+{
+ int32_t rc = 0;
if (update_type == MSM_SENSOR_REG_INIT) {
CDBG("Register INIT\n");
- s_ctrl->curr_csi_params = NULL;
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
msm_camera_i2c_write(
s_ctrl->sensor_i2c_client,
0x103, 0x1,
MSM_CAMERA_I2C_BYTE_DATA);
msm_sensor_enable_debugfs(s_ctrl);
msm_sensor_write_init_settings(s_ctrl);
- csi_config = 0;
} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
CDBG("PERIODIC : %d\n", res);
msm_sensor_write_conf_array(
s_ctrl->sensor_i2c_client,
s_ctrl->msm_sensor_reg->mode_settings, res);
msleep(30);
- if (!csi_config) {
- s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
- CDBG("CSI config in progress\n");
- v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
- NOTIFY_CSIC_CFG,
- s_ctrl->curr_csic_params);
- CDBG("CSI config is done\n");
- mb();
- msleep(30);
- csi_config = 1;
msm_camera_i2c_write(
s_ctrl->sensor_i2c_client,
0x100, 0x1,
MSM_CAMERA_I2C_BYTE_DATA);
- }
msm_camera_i2c_write(
s_ctrl->sensor_i2c_client,
0x4800, 0x4,
@@ -788,14 +769,12 @@
v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_PCLK_CHANGE,
&vfe_clk);
- s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
- msleep(50);
}
return rc;
}
static struct msm_sensor_fn_t ov5647_func_tbl = {
.sensor_start_stream = msm_sensor_start_stream,
- .sensor_stop_stream = msm_sensor_stop_stream,
+ .sensor_stop_stream = ov5647_stop_stream,
.sensor_group_hold_on = msm_sensor_group_hold_on,
.sensor_group_hold_off = msm_sensor_group_hold_off,
.sensor_set_fps = msm_sensor_set_fps,
@@ -808,7 +787,6 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = ov5647_sensor_power_up,
.sensor_power_down = ov5647_sensor_power_down,
- .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t ov5647_regs = {
@@ -837,7 +815,6 @@
.sensor_id_info = &ov5647_id_info,
.sensor_exp_gain_info = &ov5647_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csic_params = &ov5647_csi_params_array[0],
.msm_sensor_mutex = &ov5647_mut,
.sensor_i2c_driver = &ov5647_i2c_driver,
.sensor_v4l2_subdev_info = ov5647_subdev_info,
diff --git a/drivers/media/video/msm/sensors/ov7692_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
index 71d436e..e0d4b53f 100644
--- a/drivers/media/video/msm/sensors/ov7692_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_v4l2.c
@@ -821,18 +821,6 @@
};
-static struct msm_camera_csi_params ov7692_csi_params = {
- .data_format = CSI_8BIT,
- .lane_cnt = 1,
- .lane_assign = 0xe4,
- .dpcm_scheme = 0,
- .settle_cnt = 0x14,
-};
-
-static struct msm_camera_csi_params *ov7692_csi_params_array[] = {
- &ov7692_csi_params,
-};
-
static struct msm_sensor_output_reg_addr_t ov7692_reg_addr = {
.x_output = 0xCC,
.y_output = 0xCE,
@@ -899,7 +887,6 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t ov7692_regs = {
@@ -925,7 +912,6 @@
.sensor_output_reg_addr = &ov7692_reg_addr,
.sensor_id_info = &ov7692_id_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csic_params = &ov7692_csi_params_array[0],
.msm_sensor_mutex = &ov7692_mut,
.sensor_i2c_driver = &ov7692_i2c_driver,
.sensor_v4l2_subdev_info = ov7692_subdev_info,
diff --git a/drivers/media/video/msm/sensors/ov8825_v4l2.c b/drivers/media/video/msm/sensors/ov8825_v4l2.c
index 1ae3dfd..092ee72 100644
--- a/drivers/media/video/msm/sensors/ov8825_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov8825_v4l2.c
@@ -510,19 +510,6 @@
},
};
-static struct msm_camera_csi_params ov8825_csi_params = {
- .data_format = CSI_10BIT,
- .lane_cnt = 2,
- .lane_assign = 0xe4,
- .dpcm_scheme = 0,
- .settle_cnt = 14,
-};
-
-static struct msm_camera_csi_params *ov8825_csi_params_array[] = {
- &ov8825_csi_params,
- &ov8825_csi_params,
-};
-
static struct msm_sensor_output_reg_addr_t ov8825_reg_addr = {
.x_output = 0x3808,
.y_output = 0x380a,
@@ -868,13 +855,10 @@
int update_type, int res)
{
int32_t rc = 0;
- static int csi_config;
- s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
- msleep(30);
if (update_type == MSM_SENSOR_REG_INIT) {
CDBG("Register INIT\n");
- s_ctrl->curr_csi_params = NULL;
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
msm_sensor_enable_debugfs(s_ctrl);
msm_sensor_write_init_settings(s_ctrl);
CDBG("Update OTP\n");
@@ -885,30 +869,15 @@
usleep_range(10000, 11000);
msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x100, 0x0,
MSM_CAMERA_I2C_BYTE_DATA);
- csi_config = 0;
} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
CDBG("PERIODIC : %d\n", res);
msm_sensor_write_conf_array(
s_ctrl->sensor_i2c_client,
s_ctrl->msm_sensor_reg->mode_settings, res);
msleep(30);
- if (!csi_config) {
- s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
- CDBG("CSI config in progress\n");
- v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
- NOTIFY_CSIC_CFG,
- s_ctrl->curr_csic_params);
- CDBG("CSI config is done\n");
- mb();
- msleep(30);
- csi_config = 1;
- }
v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_PCLK_CHANGE,
&s_ctrl->sensordata->pdata->ioclk.vfe_clk_rate);
-
- s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
- msleep(50);
}
return rc;
}
@@ -955,7 +924,6 @@
.sensor_id_info = &ov8825_id_info,
.sensor_exp_gain_info = &ov8825_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csic_params = &ov8825_csi_params_array[0],
.msm_sensor_mutex = &ov8825_mut,
.sensor_i2c_driver = &ov8825_i2c_driver,
.sensor_v4l2_subdev_info = ov8825_subdev_info,
diff --git a/drivers/media/video/msm/sensors/ov9726_v4l2.c b/drivers/media/video/msm/sensors/ov9726_v4l2.c
index 27a8b38..50c13c6 100644
--- a/drivers/media/video/msm/sensors/ov9726_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov9726_v4l2.c
@@ -155,18 +155,6 @@
},
};
-static struct msm_camera_csi_params ov9726_csi_params = {
- .data_format = CSI_10BIT,
- .lane_cnt = 1,
- .lane_assign = 0xe4,
- .dpcm_scheme = 0,
- .settle_cnt = 7,
-};
-
-static struct msm_camera_csi_params *ov9726_csi_params_array[] = {
- &ov9726_csi_params,
-};
-
static struct msm_sensor_output_reg_addr_t ov9726_reg_addr = {
.x_output = 0x034c,
.y_output = 0x034e,
@@ -236,7 +224,6 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t ov9726_regs = {
@@ -265,7 +252,6 @@
.sensor_id_info = &ov9726_id_info,
.sensor_exp_gain_info = &ov9726_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csic_params = &ov9726_csi_params_array[0],
.msm_sensor_mutex = &ov9726_mut,
.sensor_i2c_driver = &ov9726_i2c_driver,
.sensor_v4l2_subdev_info = ov9726_subdev_info,
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index 64b004e..fda59db 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -536,53 +536,6 @@
},
};
-static struct msm_camera_csid_vc_cfg s5k3l1yx_cid_cfg[] = {
- {0, CSI_RAW10, CSI_DECODE_10BIT},
- {1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
-};
-
-static struct msm_camera_csi2_params s5k3l1yx_csi_params = {
- .csid_params = {
- .lane_cnt = 4,
- .lut_params = {
- .num_cid = ARRAY_SIZE(s5k3l1yx_cid_cfg),
- .vc_cfg = s5k3l1yx_cid_cfg,
- },
- },
- .csiphy_params = {
- .lane_cnt = 4,
- .settle_cnt = 0x1B,
- },
-};
-
-static struct msm_camera_csid_vc_cfg s5k3l1yx_cid_dpcm_cfg[] = {
- {0, CSI_RAW8, CSI_DECODE_DPCM_10_8_10},
-};
-
-static struct msm_camera_csi2_params s5k3l1yx_csi_dpcm_params = {
- .csid_params = {
- .lane_assign = 0xe4,
- .lane_cnt = 4,
- .lut_params = {
- .num_cid = ARRAY_SIZE(s5k3l1yx_cid_dpcm_cfg),
- .vc_cfg = s5k3l1yx_cid_dpcm_cfg,
- },
- },
- .csiphy_params = {
- .lane_cnt = 4,
- .settle_cnt = 0x1B,
- },
-};
-
-static struct msm_camera_csi2_params *s5k3l1yx_csi_params_array[] = {
- &s5k3l1yx_csi_params,
- &s5k3l1yx_csi_params,
- &s5k3l1yx_csi_params,
- &s5k3l1yx_csi_params,
- &s5k3l1yx_csi_params,
- &s5k3l1yx_csi_dpcm_params,
-};
-
static struct msm_sensor_output_reg_addr_t s5k3l1yx_reg_addr = {
.x_output = 0x34C,
.y_output = 0x34E,
@@ -590,6 +543,13 @@
.frame_length_lines = 0x340,
};
+static enum msm_camera_vreg_name_t s5k3l1yx_veg_seq[] = {
+ CAM_VDIG,
+ CAM_VANA,
+ CAM_VIO,
+ CAM_VAF,
+};
+
static struct msm_sensor_id_info_t s5k3l1yx_id_info = {
.sensor_id_reg_addr = 0x0,
.sensor_id = 0x3121,
@@ -717,11 +677,12 @@
.msm_sensor_reg = &s5k3l1yx_regs,
.sensor_i2c_client = &s5k3l1yx_sensor_i2c_client,
.sensor_i2c_addr = 0x6E,
+ .vreg_seq = s5k3l1yx_veg_seq,
+ .num_vreg_seq = ARRAY_SIZE(s5k3l1yx_veg_seq),
.sensor_output_reg_addr = &s5k3l1yx_reg_addr,
.sensor_id_info = &s5k3l1yx_id_info,
.sensor_exp_gain_info = &s5k3l1yx_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csi_params = &s5k3l1yx_csi_params_array[0],
.msm_sensor_mutex = &s5k3l1yx_mut,
.sensor_i2c_driver = &s5k3l1yx_i2c_driver,
.sensor_v4l2_subdev_info = s5k3l1yx_subdev_info,
diff --git a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
index e90390e..8cdadd8 100644
--- a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -211,19 +211,6 @@
},
};
-static struct msm_camera_csi_params s5k4e1_csi_params = {
- .data_format = CSI_10BIT,
- .lane_cnt = 1,
- .lane_assign = 0xe4,
- .dpcm_scheme = 0,
- .settle_cnt = 24,
-};
-
-static struct msm_camera_csi_params *s5k4e1_csi_params_array[] = {
- &s5k4e1_csi_params,
- &s5k4e1_csi_params,
-};
-
static struct msm_sensor_output_reg_addr_t s5k4e1_reg_addr = {
.x_output = 0x034C,
.y_output = 0x034E,
@@ -487,7 +474,6 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t s5k4e1_regs = {
@@ -516,7 +502,6 @@
.sensor_id_info = &s5k4e1_id_info,
.sensor_exp_gain_info = &s5k4e1_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csic_params = &s5k4e1_csi_params_array[0],
.msm_sensor_mutex = &s5k4e1_mut,
.sensor_i2c_driver = &s5k4e1_i2c_driver,
.sensor_v4l2_subdev_info = s5k4e1_subdev_info,
diff --git a/drivers/media/video/msm/sensors/vx6953.c b/drivers/media/video/msm/sensors/vx6953.c
index b43782c..ddc6cee 100644
--- a/drivers/media/video/msm/sensors/vx6953.c
+++ b/drivers/media/video/msm/sensors/vx6953.c
@@ -848,19 +848,6 @@
},
};
-static struct msm_camera_csi_params vx6953_csi_params = {
- .data_format = CSI_8BIT,
- .lane_cnt = 1,
- .lane_assign = 0xe4,
- .dpcm_scheme = 0,
- .settle_cnt = 7,
-};
-
-static struct msm_camera_csi_params *vx6953_csi_params_array[] = {
- &vx6953_csi_params,
- &vx6953_csi_params,
-};
-
static struct msm_sensor_output_reg_addr_t vx6953_reg_addr = {
.x_output = 0x034C,
.y_output = 0x034E,
@@ -1880,13 +1867,6 @@
vx6953_s_ctrl.msm_sensor_reg->
default_data_type);
-
- vx6953_s_ctrl.curr_csic_params =
- vx6953_s_ctrl.csic_params[0];
- v4l2_subdev_notify(&vx6953_s_ctrl.sensor_v4l2_subdev,
- NOTIFY_CSIC_CFG,
- vx6953_s_ctrl.curr_csic_params);
-
msleep(vx6953_stm5m0edof_delay_msecs_stdby);
if (rt == RES_PREVIEW) {
CDBG("%s write mode_tbl for preview\n",
@@ -2042,7 +2022,6 @@
.sensor_id_info = &vx6953_id_info,
.sensor_exp_gain_info = &vx6953_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
- .csic_params = &vx6953_csi_params_array[0],
.msm_sensor_mutex = &vx6953_mut,
.sensor_i2c_driver = &vx6953_i2c_driver,
.sensor_v4l2_subdev_info = vx6953_subdev_info,
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 7d58091..db83621 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/of.h>
#include "msm_cam_server.h"
#include "msm_csid.h"
#include "msm_csic.h"
@@ -160,6 +161,16 @@
g_server_dev.interface_map_table[i].mctl_handle = 0;
}
+struct iommu_domain *msm_cam_server_get_domain()
+{
+ return g_server_dev.domain;
+}
+
+int msm_cam_server_get_domain_num()
+{
+ return g_server_dev.domain_num;
+}
+
uint32_t msm_cam_server_get_mctl_handle(void)
{
uint32_t i;
@@ -288,7 +299,7 @@
/* send control command to config and wait for results*/
static int msm_server_control(struct msm_cam_server_dev *server_dev,
- struct msm_ctrl_cmd *out)
+ uint32_t id, struct msm_ctrl_cmd *out)
{
int rc = 0;
void *value;
@@ -326,7 +337,7 @@
server_dev->server_queue[out->queue_idx].evt_id =
server_dev->server_evt_id;
v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2;
- v4l2_evt.id = 0;
+ v4l2_evt.id = id;
v4l2_evt.u.data[0] = out->queue_idx;
/* setup event object to transfer the command; */
isp_event->resptype = MSM_CAM_RESP_V4L2;
@@ -409,6 +420,49 @@
return rc;
}
+int msm_server_private_general(struct msm_cam_v4l2_device *pcam,
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+ struct msm_ctrl_cmd ctrlcmd;
+ void *temp_data;
+ int rc;
+ temp_data = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+ if (!temp_data) {
+ pr_err("%s could not allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+ if (copy_from_user((void *)temp_data,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len)) {
+ ERR_COPY_FROM_USER();
+ rc = -EFAULT;
+ goto copy_from_user_failed;
+ }
+
+ mutex_lock(&pcam->vid_lock);
+ ctrlcmd.type = MSM_V4L2_PRIVATE_CMD;
+ ctrlcmd.length = ioctl_ptr->len;
+ ctrlcmd.value = temp_data;
+ ctrlcmd.timeout_ms = 1000;
+ ctrlcmd.status = ioctl_ptr->id;
+ ctrlcmd.vnode_id = pcam->vnode_id;
+ ctrlcmd.queue_idx = pcam->server_queue_idx;
+ ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
+ /* send command to config thread in usersspace, and get return value */
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
+ if (rc < 0)
+ pr_err("%s: send event failed\n", __func__);
+ mutex_unlock(&pcam->vid_lock);
+
+ kfree(temp_data);
+ return rc;
+copy_from_user_failed:
+ kfree(temp_data);
+end:
+return rc;
+}
+
int msm_server_get_crop(struct msm_cam_v4l2_device *pcam,
int idx, struct v4l2_crop *crop)
{
@@ -428,7 +482,7 @@
pcam->server_queue_idx];
/* send command to config thread in userspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
D("%s: rc = %d\n", __func__, rc);
return rc;
@@ -452,7 +506,7 @@
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[idx];
/* send command to config thread in usersspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
return rc;
}
@@ -474,7 +528,7 @@
pcam->server_queue_idx];
/* send command to config thread in usersspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
return rc;
}
@@ -520,7 +574,7 @@
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
if (rc >= 0) {
pcam->dev_inst[idx]->vid_fmt = *pfmt;
@@ -586,7 +640,7 @@
ctrlcmd.queue_idx = pcam->server_queue_idx;
/* send command to config thread in usersspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
if (rc >= 0) {
pcam->dev_inst[idx]->vid_fmt = *pfmt;
pcam->dev_inst[idx]->sensor_pxlcode
@@ -617,7 +671,7 @@
/* send command to config thread in usersspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
return rc;
}
@@ -638,7 +692,7 @@
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
return rc;
}
@@ -696,7 +750,7 @@
ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
D("%s: msm_server_control rc=%d\n", __func__, rc);
if (rc == 0) {
if (tmp_cmd.value && tmp_cmd.length > 0 &&
@@ -750,7 +804,7 @@
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
return rc;
}
@@ -780,7 +834,7 @@
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
ctrl->value = ((struct v4l2_control *)ctrlcmd.value)->value;
@@ -807,7 +861,7 @@
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in userspace, and get return value */
- rc = msm_server_control(&g_server_dev, &ctrlcmd);
+ rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
D("%s: rc = %d\n", __func__, rc);
if (rc >= 0)
@@ -1013,7 +1067,7 @@
{
int rc = 0;
rc = msm_iommu_map_contig_buffer(
- (unsigned long)IMEM_Y_PING_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+ (unsigned long)IMEM_Y_PING_OFFSET, mctl->domain_num, 0,
((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
SZ_4K, IOMMU_WRITE | IOMMU_READ,
(unsigned long *)&mctl->ping_imem_y);
@@ -1025,7 +1079,7 @@
mctl->ping_imem_cbcr = 0;
}
msm_iommu_map_contig_buffer(
- (unsigned long)IMEM_Y_PONG_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+ (unsigned long)IMEM_Y_PONG_OFFSET, mctl->domain_num, 0,
((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
SZ_4K, IOMMU_WRITE | IOMMU_READ,
(unsigned long *)&mctl->pong_imem_y);
@@ -1042,10 +1096,10 @@
static void unmap_imem_addresses(struct msm_cam_media_controller *mctl)
{
msm_iommu_unmap_contig_buffer(mctl->ping_imem_y,
- CAMERA_DOMAIN, GEN_POOL,
+ mctl->domain_num, 0,
((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
msm_iommu_unmap_contig_buffer(mctl->pong_imem_y,
- CAMERA_DOMAIN, GEN_POOL,
+ mctl->domain_num, 0,
((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
mctl->ping_imem_y = 0;
mctl->ping_imem_cbcr = 0;
@@ -1428,6 +1482,10 @@
pr_err("%s: invalid mctl controller", __func__);
goto error;
}
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ pmctl->domain = msm_cam_server_get_domain();
+ pmctl->domain_num = msm_cam_server_get_domain_num();
+#endif
rc = map_imem_addresses(pmctl);
if (rc < 0) {
pr_err("%sFailed to map imem addresses %d\n", __func__, rc);
@@ -1539,10 +1597,14 @@
interface = PIX_0;
}
break;
+ case NOTIFY_AXI_RDI_SOF_COUNT: {
+ struct rdi_count_msg *msg = (struct rdi_count_msg *)arg;
+ interface = msg->rdi_interface;
+ }
+ break;
case NOTIFY_VFE_MSG_STATS:
case NOTIFY_VFE_MSG_COMP_STATS:
case NOTIFY_VFE_CAMIF_ERROR:
- case NOTIFY_VFE_IRQ:
default:
interface = PIX_0;
break;
@@ -1579,55 +1641,43 @@
switch (notification) {
case NOTIFY_ISP_MSG_EVT:
case NOTIFY_VFE_MSG_OUT:
- case NOTIFY_VFE_SOF_COUNT:
+ case NOTIFY_VFE_PIX_SOF_COUNT:
case NOTIFY_VFE_MSG_STATS:
case NOTIFY_VFE_MSG_COMP_STATS:
case NOTIFY_VFE_BUF_EVT:
p_mctl = msm_cam_server_get_mctl(mctl_handle);
- if (p_mctl->isp_sdev &&
- p_mctl->isp_sdev->isp_notify
- && p_mctl->isp_sdev->sd)
- rc = p_mctl->isp_sdev->isp_notify(
- p_mctl->isp_sdev->sd, notification, arg);
+ if (p_mctl->isp_notify && p_mctl->vfe_sdev)
+ rc = p_mctl->isp_notify(p_mctl,
+ p_mctl->vfe_sdev, notification, arg);
break;
case NOTIFY_VFE_IRQ:{
struct msm_vfe_cfg_cmd cfg_cmd;
struct msm_camvfe_params vfe_params;
- p_mctl = msm_cam_server_get_mctl(mctl_handle);
cfg_cmd.cmd_type = CMD_VFE_PROCESS_IRQ;
vfe_params.vfe_cfg = &cfg_cmd;
vfe_params.data = arg;
- rc = v4l2_subdev_call(p_mctl->isp_sdev->sd,
+ rc = v4l2_subdev_call(sd,
core, ioctl, 0, &vfe_params);
}
break;
case NOTIFY_AXI_IRQ:
rc = v4l2_subdev_call(sd, core, ioctl, VIDIOC_MSM_AXI_IRQ, arg);
break;
+ case NOTIFY_AXI_RDI_SOF_COUNT:
+ p_mctl = msm_cam_server_get_mctl(mctl_handle);
+ if (p_mctl->axi_sdev)
+ rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
+ VIDIOC_MSM_AXI_RDI_COUNT_UPDATE, arg);
+ break;
case NOTIFY_PCLK_CHANGE:
p_mctl = v4l2_get_subdev_hostdata(sd);
if (p_mctl->axi_sdev)
rc = v4l2_subdev_call(p_mctl->axi_sdev, video,
s_crystal_freq, *(uint32_t *)arg, 0);
else
- rc = v4l2_subdev_call(p_mctl->isp_sdev->sd, video,
+ rc = v4l2_subdev_call(p_mctl->vfe_sdev, video,
s_crystal_freq, *(uint32_t *)arg, 0);
break;
- case NOTIFY_CSIPHY_CFG:
- p_mctl = v4l2_get_subdev_hostdata(sd);
- rc = v4l2_subdev_call(p_mctl->csiphy_sdev,
- core, ioctl, VIDIOC_MSM_CSIPHY_CFG, arg);
- break;
- case NOTIFY_CSID_CFG:
- p_mctl = v4l2_get_subdev_hostdata(sd);
- rc = v4l2_subdev_call(p_mctl->csid_sdev,
- core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
- break;
- case NOTIFY_CSIC_CFG:
- p_mctl = v4l2_get_subdev_hostdata(sd);
- rc = v4l2_subdev_call(p_mctl->csic_sdev,
- core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
- break;
case NOTIFY_GESTURE_EVT:
rc = v4l2_subdev_call(g_server_dev.gesture_device,
core, ioctl, VIDIOC_MSM_GESTURE_EVT, arg);
@@ -2114,7 +2164,6 @@
}
cam_hw_idx = MSM_CAM_HW_VFE0 + index;
g_server_dev.vfe_device[index] = sd;
- g_server_dev.isp_subdev[index]->sd = sd;
if (g_server_dev.irqr_device) {
g_server_dev.subdev_table[cam_hw_idx] = sd;
err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
@@ -2132,7 +2181,7 @@
break;
case AXI_DEV:
- if (index >= MAX_NUM_VPE_DEV) {
+ if (index >= MAX_NUM_AXI_DEV) {
pr_err("%s Invalid AXI idx %d", __func__, index);
err = -EINVAL;
break;
@@ -2181,6 +2230,23 @@
return err;
}
+#ifdef CONFIG_MSM_IOMMU
+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_isp",
+ .domain_flags = 0,
+ };
+
+ return msm_register_domain(&camera_fw_layout);
+}
+#endif
static int msm_setup_server_dev(struct platform_device *pdev)
{
@@ -2257,6 +2323,21 @@
g_server_dev.interface_map_table[i].interface = 0x01 << i;
g_server_dev.interface_map_table[i].mctl_handle = 0;
}
+#ifdef CONFIG_MSM_IOMMU
+ g_server_dev.domain_num = camera_register_domain();
+ if (g_server_dev.domain_num < 0) {
+ pr_err("%s: could not register domain\n", __func__);
+ rc = -ENODEV;
+ return rc;
+ }
+ g_server_dev.domain =
+ msm_get_iommu_domain(g_server_dev.domain_num);
+ if (!g_server_dev.domain) {
+ pr_err("%s: cannot find domain\n", __func__);
+ rc = -ENODEV;
+ return rc;
+ }
+#endif
return rc;
}
@@ -2314,6 +2395,11 @@
return rc;
}
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ pmctl->domain = msm_cam_server_get_domain();
+ pmctl->domain_num = msm_cam_server_get_domain_num();
+#endif
+
D("%s: call mctl_open\n", __func__);
rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);
@@ -2586,6 +2672,7 @@
pr_err("%s: cannot find mctl\n", __func__);
return -ENODEV;
}
+
INIT_HLIST_HEAD(&config_cam->p_mctl->stats_info.pmem_stats_list);
spin_lock_init(&config_cam->p_mctl->stats_info.pmem_stats_spinlock);
@@ -2597,21 +2684,10 @@
return rc;
}
-static struct msm_isp_ops *find_isp_op(struct v4l2_subdev *sdev)
-{
- int i;
- for (i = 0; i < g_server_dev.config_info.num_config_nodes; i++) {
- if (g_server_dev.isp_subdev[i]->sd == sdev)
- return g_server_dev.isp_subdev[i];
- }
- return NULL;
-}
-
static int msm_set_mctl_subdev(struct msm_cam_media_controller *pmctl,
struct msm_mctl_set_sdev_data *set_data)
{
int rc = 0;
- struct v4l2_subdev *vfe_sdev = NULL;
struct v4l2_subdev *temp_sdev = NULL;
switch (set_data->sdev_type) {
case CSIPHY_DEV:
@@ -2635,11 +2711,9 @@
temp_sdev = pmctl->ispif_sdev;
break;
case VFE_DEV:
- vfe_sdev = msm_cam_find_subdev_node
+ pmctl->vfe_sdev = msm_cam_find_subdev_node
(&g_server_dev.vfe_device[0], set_data->revision);
- temp_sdev = vfe_sdev;
- pmctl->isp_sdev = find_isp_op(vfe_sdev);
- pmctl->isp_sdev->sd = vfe_sdev;
+ temp_sdev = pmctl->vfe_sdev;
break;
case AXI_DEV:
pmctl->axi_sdev = msm_cam_find_subdev_node
@@ -2680,7 +2754,7 @@
pmctl->ispif_sdev = NULL;
break;
case VFE_DEV:
- pmctl->isp_sdev = NULL;
+ pmctl->vfe_sdev = NULL;
break;
case AXI_DEV:
pmctl->axi_sdev = NULL;
@@ -2712,13 +2786,15 @@
case MSM_CAM_IOCTL_REGISTER_PMEM:
return msm_register_pmem(
&config_cam->p_mctl->stats_info.pmem_stats_list,
- (void __user *)arg, config_cam->p_mctl->client);
+ (void __user *)arg, config_cam->p_mctl->client,
+ config_cam->p_mctl->domain_num);
break;
case MSM_CAM_IOCTL_UNREGISTER_PMEM:
return msm_pmem_table_del(
&config_cam->p_mctl->stats_info.pmem_stats_list,
- (void __user *)arg, config_cam->p_mctl->client);
+ (void __user *)arg, config_cam->p_mctl->client,
+ config_cam->p_mctl->domain_num);
break;
case VIDIOC_SUBSCRIBE_EVENT:
@@ -3003,12 +3079,6 @@
put logic here later to know how many configs to create*/
g_server_dev.config_info.num_config_nodes = 2;
- rc = msm_isp_init_module(g_server_dev.config_info.num_config_nodes);
- if (rc < 0) {
- pr_err("Failed to initialize isp\n");
- return rc;
- }
-
if (!msm_class) {
rc = alloc_chrdev_region(&msm_devno, 0,
g_server_dev.config_info.num_config_nodes+1, "msm_camera");
@@ -3044,22 +3114,27 @@
}
}
- msm_isp_register(&g_server_dev);
return rc;
}
static int __exit msm_camera_exit(struct platform_device *pdev)
{
- msm_isp_unregister(&g_server_dev);
return 0;
}
+static const struct of_device_id msm_cam_server_dt_match[] = {
+ {.compatible = "qcom,cam_server"},
+}
+
+MODULE_DEVICE_TABLE(of, msm_cam_server_dt_match);
+
static struct platform_driver msm_cam_server_driver = {
.probe = msm_camera_probe,
.remove = msm_camera_exit,
.driver = {
.name = "msm_cam_server",
.owner = THIS_MODULE,
+ .of_match_table = msm_cam_server_dt_match,
},
};
diff --git a/drivers/media/video/msm/server/msm_cam_server.h b/drivers/media/video/msm/server/msm_cam_server.h
index 229e9c9..d38bb98 100644
--- a/drivers/media/video/msm/server/msm_cam_server.h
+++ b/drivers/media/video/msm/server/msm_cam_server.h
@@ -20,6 +20,8 @@
#include "msm.h"
uint32_t msm_cam_server_get_mctl_handle(void);
+struct iommu_domain *msm_cam_server_get_domain(void);
+int msm_cam_server_get_domain_num(void);
struct msm_cam_media_controller *msm_cam_server_get_mctl(uint32_t handle);
void msm_cam_server_free_mctl(uint32_t handle);
/* Server session control APIs */
@@ -37,6 +39,8 @@
int32_t msm_find_free_queue(void);
int msm_server_proc_ctrl_cmd(struct msm_cam_v4l2_device *pcam,
struct msm_camera_v4l2_ioctl_t *ioctl_ptr, int is_set_cmd);
+int msm_server_private_general(struct msm_cam_v4l2_device *pcam,
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr);
int msm_server_s_ctrl(struct msm_cam_v4l2_device *pcam,
struct v4l2_control *ctrl);
int msm_server_g_ctrl(struct msm_cam_v4l2_device *pcam,
@@ -65,5 +69,5 @@
int msm_cam_server_update_irqmap(
struct msm_cam_server_irqmap_entry *entry);
int msm_cam_server_config_interface_map(u32 extendedmode,
- uint32_t mctl_handle);
+ uint32_t mctl_handle);
#endif /* _MSM_CAM_SERVER_H */
diff --git a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
index 0bd7b94..de32f1b 100644
--- a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.c
@@ -367,7 +367,7 @@
rc = vfe31_ctrl->stats_ops.dqbuf(vfe31_ctrl->stats_ops.stats_ctrl,
stats_type, &buf);
if (rc < 0) {
- pr_err("%s: dq stats buf (type = %d) err = %d",
+ CDBG("%s: dq stats buf (type = %d) err = %d",
__func__, stats_type, rc);
return 0L;
}
@@ -401,7 +401,7 @@
stats_buf = &bufq->bufs[i];
rc = vfe31_ctrl->stats_ops.enqueue_buf(
vfe31_ctrl->stats_ops.stats_ctrl,
- &(stats_buf->info), NULL);
+ &(stats_buf->info), NULL, -1);
if (rc < 0) {
pr_err("%s: dq stats buf (type = %d) err = %d",
__func__, stats_type, rc);
@@ -412,7 +412,7 @@
}
static unsigned long vfe31_stats_unregbuf(
- struct msm_stats_reqbuf *req_buf)
+ struct msm_stats_reqbuf *req_buf, int domain_num)
{
int i = 0, rc = 0;
@@ -420,7 +420,7 @@
rc = vfe31_ctrl->stats_ops.buf_unprepare(
vfe31_ctrl->stats_ops.stats_ctrl,
req_buf->stats_type, i,
- vfe31_ctrl->stats_ops.client);
+ vfe31_ctrl->stats_ops.client, domain_num);
if (rc < 0) {
pr_err("%s: unreg stats buf (type = %d) err = %d",
__func__, req_buf->stats_type, rc);
@@ -3296,7 +3296,7 @@
}
static long vfe_stats_bufq_sub_ioctl(struct msm_vfe_cfg_cmd *cmd,
- void *ion_client)
+ void *ion_client, int domain_num)
{
long rc = 0;
switch (cmd->cmd_type) {
@@ -3344,7 +3344,7 @@
}
rc = vfe31_ctrl->stats_ops.enqueue_buf(&vfe31_ctrl->stats_ctrl,
(struct msm_stats_buf_info *)cmd->value,
- vfe31_ctrl->stats_ops.client);
+ vfe31_ctrl->stats_ops.client, domain_num);
break;
case VFE_CMD_STATS_FLUSH_BUFQ: {
struct msm_stats_flush_bufq *flush_req = NULL;
@@ -3376,7 +3376,7 @@
rc = -EINVAL ;
goto end;
}
- rc = vfe31_stats_unregbuf(req_buf);
+ rc = vfe31_stats_unregbuf(req_buf, domain_num);
}
break;
default:
@@ -3630,7 +3630,8 @@
case VFE_CMD_STATS_FLUSH_BUFQ:
case VFE_CMD_STATS_UNREGBUF:
/* for easy porting put in one envelope */
- rc = vfe_stats_bufq_sub_ioctl(cmd, vfe_params->data);
+ rc = vfe_stats_bufq_sub_ioctl(cmd, vfe_params->data,
+ pmctl->domain_num);
return rc;
default:
if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
@@ -4003,10 +4004,25 @@
vfe31_ctrl->vfe_camif_clk,
ARRAY_SIZE(vfe_camif_clk_info), 1);
if (rc < 0)
- goto vfe_clk_enable_failed;
+ goto vfe_camif_clk_enable_failed;
msm_vfe_camif_pad_reg_reset();
}
+#ifdef CONFIG_MSM_IOMMU
+ rc = iommu_attach_device(mctl->domain, vfe31_ctrl->iommu_ctx_imgwr);
+ if (rc < 0) {
+ rc = -ENODEV;
+ pr_err("%s: Device attach failed\n", __func__);
+ goto device_imgwr_attach_failed;
+ }
+ rc = iommu_attach_device(mctl->domain, vfe31_ctrl->iommu_ctx_misc);
+ if (rc < 0) {
+ rc = -ENODEV;
+ pr_err("%s: Device attach failed\n", __func__);
+ goto device_misc_attach_failed;
+ }
+#endif
+
msm_camio_bus_scale_cfg(
mctl->sdata->pdata->cam_bus_scale_table, S_INIT);
msm_camio_bus_scale_cfg(
@@ -4017,6 +4033,19 @@
return rc;
+#ifdef CONFIG_MSM_IOMMU
+device_misc_attach_failed:
+ iommu_detach_device(mctl->domain, vfe31_ctrl->iommu_ctx_imgwr);
+device_imgwr_attach_failed:
+#endif
+ if (!mctl->sdata->csi_if)
+ msm_cam_clk_enable(&vfe31_ctrl->pdev->dev,
+ vfe_camif_clk_info,
+ vfe31_ctrl->vfe_camif_clk,
+ ARRAY_SIZE(vfe_camif_clk_info), 0);
+vfe_camif_clk_enable_failed:
+ msm_cam_clk_enable(&vfe31_ctrl->pdev->dev, vfe_clk_info,
+ vfe31_ctrl->vfe_clk, ARRAY_SIZE(vfe_clk_info), 0);
vfe_clk_enable_failed:
regulator_disable(vfe31_ctrl->fs_vfe);
vfe_fs_failed:
@@ -4025,7 +4054,6 @@
camif_remap_failed:
iounmap(vfe31_ctrl->vfebase);
vfe_remap_failed:
- disable_irq(vfe31_ctrl->vfeirq->start);
mctl_failed:
return rc;
}
@@ -4037,6 +4065,11 @@
disable_irq(vfe31_ctrl->vfeirq->start);
tasklet_kill(&vfe31_tasklet);
+#ifdef CONFIG_MSM_IOMMU
+ iommu_detach_device(pmctl->domain, vfe31_ctrl->iommu_ctx_misc);
+ iommu_detach_device(pmctl->domain, vfe31_ctrl->iommu_ctx_imgwr);
+#endif
+
if (!pmctl->sdata->csi_if)
msm_cam_clk_enable(&vfe31_ctrl->pdev->dev,
vfe_camif_clk_info,
@@ -4140,6 +4173,25 @@
disable_irq(vfe31_ctrl->vfeirq->start);
+#ifdef CONFIG_MSM_IOMMU
+ /*get device context for IOMMU*/
+ vfe31_ctrl->iommu_ctx_imgwr =
+ msm_iommu_get_ctx("vfe_imgwr"); /*re-confirm*/
+ vfe31_ctrl->iommu_ctx_misc =
+ msm_iommu_get_ctx("vfe_misc"); /*re-confirm*/
+ if (!vfe31_ctrl->iommu_ctx_imgwr || !vfe31_ctrl->iommu_ctx_misc) {
+ if (vfe31_ctrl->camifmem) {
+ release_mem_region(vfe31_ctrl->camifmem->start,
+ resource_size(vfe31_ctrl->camifmem));
+ }
+ release_mem_region(vfe31_ctrl->vfemem->start,
+ resource_size(vfe31_ctrl->vfemem));
+ pr_err("%s: No iommu fw context found\n", __func__);
+ rc = -ENODEV;
+ goto vfe31_no_resource;
+ }
+#endif
+
vfe31_ctrl->pdev = pdev;
vfe31_ctrl->fs_vfe = regulator_get(&vfe31_ctrl->pdev->dev, "vdd");
if (IS_ERR(vfe31_ctrl->fs_vfe)) {
diff --git a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.h b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.h
index 60db8e5..97ecd6e 100644
--- a/drivers/media/video/msm/vfe/msm_vfe31_v4l2.h
+++ b/drivers/media/video/msm/vfe/msm_vfe31_v4l2.h
@@ -928,6 +928,8 @@
uint32_t snapshot_frame_cnt;
struct msm_stats_bufq_ctrl stats_ctrl;
struct msm_stats_ops stats_ops;
+ struct device *iommu_ctx_imgwr;
+ struct device *iommu_ctx_misc;
};
enum VFE31_STATS_NUM {
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index 3e01437..2740808 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -412,36 +412,116 @@
}
}
-static void axi_disable_irq(struct axi_ctrl_t *axi_ctrl)
+static void axi_enable_irq(struct vfe_share_ctrl_t *share_ctrl)
+{
+ uint32_t irq_mask, irq_mask1;
+ uint16_t vfe_operation_mode =
+ share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+ VFE_OUTPUTS_RDI1);
+ irq_mask1 =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_1);
+
+ irq_mask1 |= VFE_IMASK_WHILE_STOPPING_1;
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
+ irq_mask1 |= VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK;
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
+ irq_mask1 |= VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK;
+
+ msm_camera_io_w(irq_mask1, share_ctrl->vfebase +
+ VFE_IRQ_MASK_1);
+
+ if (vfe_operation_mode) {
+ irq_mask =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ irq_mask |= 0x00000021;
+ if (share_ctrl->stats_comp)
+ irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK;
+ else
+ irq_mask |= 0x000FE000;
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ atomic_set(&share_ctrl->vstate, 1);
+ }
+ atomic_set(&share_ctrl->handle_common_irq, 1);
+}
+
+static void axi_disable_irq(struct vfe_share_ctrl_t *share_ctrl)
{
/* disable all interrupts. */
- msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
- msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
- /* clear all pending interrupts*/
- msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
- msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
- /* Ensure the write order while writing
- to the command register using the barrier */
- msm_camera_io_w_mb(1,
- axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
+ uint32_t irq_mask, irq_mask1;
+ uint16_t vfe_operation_mode =
+ share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+ VFE_OUTPUTS_RDI1);
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+ irq_mask1 =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_1);
+ irq_mask1 &= ~(VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK);
+ msm_camera_io_w(irq_mask1, share_ctrl->vfebase +
+ VFE_IRQ_MASK_1);
+ msm_camera_io_w(VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK,
+ share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ }
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+ irq_mask1 =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_1);
+ irq_mask1 &= ~(VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK);
+ msm_camera_io_w(irq_mask1, share_ctrl->vfebase +
+ VFE_IRQ_MASK_1);
+ msm_camera_io_w(VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK,
+ share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ }
+ if (vfe_operation_mode) {
+ atomic_set(&share_ctrl->vstate, 0);
+ irq_mask =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ irq_mask &= ~(0x00000021);
+ if (share_ctrl->stats_comp)
+ irq_mask &= ~(VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK);
+ else
+ irq_mask &= ~0x000FE000;
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ }
+
+ if (share_ctrl->axi_ref_cnt == 1) {
+ atomic_set(&share_ctrl->handle_common_irq, 0);
+ msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+ share_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+ share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* clear all pending interrupts*/
+ msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+ share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+ share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ /* Ensure the write order while writing
+ *to the command register using the barrier */
+ msm_camera_io_w_mb(1,
+ share_ctrl->vfebase + VFE_IRQ_CMD);
+ }
}
static void vfe32_stop(struct vfe32_ctrl_type *vfe32_ctrl)
{
- atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
/* in either continuous or snapshot mode, stop command can be issued
* at any time. stop camif immediately. */
- msm_camera_io_w(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ msm_camera_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY,
vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
vfe32_ctrl->share_ctrl->operation_mode &=
~(vfe32_ctrl->share_ctrl->current_mode);
+ vfe32_ctrl->share_ctrl->current_mode = 0;
}
static void vfe32_subdev_notify(int id, int path, uint32_t inst_handle,
@@ -560,6 +640,16 @@
}
msm_camera_io_w(bus_cmd, axi_ctrl->share_ctrl->vfebase +
V32_AXI_BUS_CMD_OFF);
+ msm_camera_io_w(*ch_info++,
+ axi_ctrl->share_ctrl->vfebase + VFE_PIXEL_IF_CFG);
+ if (msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+ V32_GET_HW_VERSION_OFF) ==
+ VFE33_HW_NUMBER) {
+ msm_camera_io_w(*ch_info++,
+ axi_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
+ msm_camera_io_w(*ch_info++,
+ axi_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
+ }
return 0;
}
@@ -585,6 +675,8 @@
axi_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
atomic_set(&axi_ctrl->share_ctrl->vstate, 0);
+ atomic_set(&axi_ctrl->share_ctrl->handle_common_irq, 0);
+ atomic_set(&axi_ctrl->share_ctrl->pix0_update_ack_pending, 0);
atomic_set(&axi_ctrl->share_ctrl->rdi0_update_ack_pending, 0);
atomic_set(&axi_ctrl->share_ctrl->rdi1_update_ack_pending, 0);
atomic_set(&axi_ctrl->share_ctrl->rdi2_update_ack_pending, 0);
@@ -593,40 +685,14 @@
axi_ctrl->share_ctrl->operation_mode = 0;
axi_ctrl->share_ctrl->current_mode = 0;
axi_ctrl->share_ctrl->outpath.output_mode = 0;
+ axi_ctrl->share_ctrl->comp_output_mode = 0;
axi_ctrl->share_ctrl->vfe_capture_count = 0;
/* this is unsigned 32 bit integer. */
axi_ctrl->share_ctrl->vfeFrameId = 0;
-}
-
-static void vfe32_reset_internal_variables(
- struct vfe32_ctrl_type *vfe32_ctrl)
-{
- /* Stats control variables. */
- memset(&(vfe32_ctrl->afbfStatsControl), 0,
- sizeof(struct vfe_stats_control));
-
- memset(&(vfe32_ctrl->awbStatsControl), 0,
- sizeof(struct vfe_stats_control));
-
- memset(&(vfe32_ctrl->aecbgStatsControl), 0,
- sizeof(struct vfe_stats_control));
-
- memset(&(vfe32_ctrl->bhistStatsControl), 0,
- sizeof(struct vfe_stats_control));
-
- memset(&(vfe32_ctrl->ihistStatsControl), 0,
- sizeof(struct vfe_stats_control));
-
- memset(&(vfe32_ctrl->rsStatsControl), 0,
- sizeof(struct vfe_stats_control));
-
- memset(&(vfe32_ctrl->csStatsControl), 0,
- sizeof(struct vfe_stats_control));
-
- vfe32_ctrl->frame_skip_cnt = 31;
- vfe32_ctrl->frame_skip_pattern = 0xffffffff;
- vfe32_ctrl->snapshot_frame_cnt = 0;
+ axi_ctrl->share_ctrl->rdi0FrameId = 0;
+ axi_ctrl->share_ctrl->rdi1FrameId = 0;
+ axi_ctrl->share_ctrl->rdi2FrameId = 0;
}
static void vfe32_program_dmi_cfg(
@@ -685,6 +751,147 @@
vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
}
+static void vfe32_set_default_reg_values(
+ struct vfe32_ctrl_type *vfe32_ctrl)
+{
+ msm_camera_io_w(0x800080,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0);
+ msm_camera_io_w(0x800080,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1);
+ /* What value should we program CGC_OVERRIDE to? */
+ msm_camera_io_w(0xFFFFF,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+ /* default frame drop period and pattern */
+ msm_camera_io_w(0x1f,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+ msm_camera_io_w(0x1f,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+ msm_camera_io_w(0xFFFFFFFF,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+ msm_camera_io_w(0xFFFFFFFF,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+ msm_camera_io_w(0x1f,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y);
+ msm_camera_io_w(0x1f,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR);
+ msm_camera_io_w(0xFFFFFFFF,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+ msm_camera_io_w(0xFFFFFFFF,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+ msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MIN);
+ msm_camera_io_w(0xFFFFFF,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MAX);
+
+ /* stats UB config */
+ CDBG("%s: Use bayer stats = %d\n", __func__,
+ vfe32_use_bayer_stats(vfe32_ctrl));
+ if (!vfe32_use_bayer_stats(vfe32_ctrl)) {
+ msm_camera_io_w(0x3980007,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AEC_BG_UB_CFG);
+ msm_camera_io_w(0x3A00007,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AF_BF_UB_CFG);
+ msm_camera_io_w(0x3A8000F,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AWB_UB_CFG);
+ msm_camera_io_w(0x3B80007,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_RS_UB_CFG);
+ msm_camera_io_w(0x3C0001F,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_CS_UB_CFG);
+ msm_camera_io_w(0x3E0001F,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_HIST_UB_CFG);
+ } else {
+ msm_camera_io_w(0x350001F,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_HIST_UB_CFG);
+ msm_camera_io_w(0x370002F,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AEC_BG_UB_CFG);
+ msm_camera_io_w(0x3A0002F,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AF_BF_UB_CFG);
+ msm_camera_io_w(0x3D00007,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_RS_UB_CFG);
+ msm_camera_io_w(0x3D8001F,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_CS_UB_CFG);
+ msm_camera_io_w(0x3F80007,
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_SKIN_BHIST_UB_CFG);
+ }
+ vfe32_reset_dmi_tables(vfe32_ctrl);
+}
+
+static void vfe32_reset_internal_variables(
+ struct vfe32_ctrl_type *vfe32_ctrl)
+{
+ /* Stats control variables. */
+ memset(&(vfe32_ctrl->afbfStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe32_ctrl->awbStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe32_ctrl->aecbgStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe32_ctrl->bhistStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe32_ctrl->ihistStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe32_ctrl->rsStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe32_ctrl->csStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ vfe32_ctrl->frame_skip_cnt = 31;
+ vfe32_ctrl->frame_skip_pattern = 0xffffffff;
+ vfe32_ctrl->snapshot_frame_cnt = 0;
+ vfe32_set_default_reg_values(vfe32_ctrl);
+}
+
+
+static int vfe32_reset(struct vfe32_ctrl_type *vfe32_ctrl)
+{
+ uint32_t irq_mask1, irq_mask;
+ atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
+ msm_camera_io_w(VFE_MODULE_RESET_CMD,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_RESET);
+ msm_camera_io_w(0,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_RESET);
+
+ irq_mask =
+ msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+ irq_mask &= ~(0x000FE021|VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK);
+
+ msm_camera_io_w(irq_mask, vfe32_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ /* enable reset_ack interrupt. */
+ irq_mask1 = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+ irq_mask1 |= VFE_IMASK_WHILE_STOPPING_1;
+ msm_camera_io_w(irq_mask1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
+ msm_camera_io_w_mb(VFE_ONLY_RESET_CMD,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+
+ return wait_for_completion_interruptible(
+ &vfe32_ctrl->share_ctrl->reset_complete);
+}
+
static int axi_reset(struct axi_ctrl_t *axi_ctrl)
{
axi_reset_internal_variables(axi_ctrl);
@@ -729,7 +936,6 @@
{
uint32_t *p = cmd;
- vfe32_ctrl->share_ctrl->operation_mode = *p;
vfe32_ctrl->share_ctrl->stats_comp = *(++p);
vfe32_ctrl->hfr_mode = *(++p);
@@ -738,19 +944,6 @@
msm_camera_io_w(*(++p),
vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
msm_camera_io_w(*(++p),
- vfe32_ctrl->share_ctrl->vfebase + VFE_PIXEL_IF_CFG);
- if (msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
- V32_GET_HW_VERSION_OFF) ==
- VFE33_HW_NUMBER) {
- msm_camera_io_w(*(++p),
- vfe32_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
- msm_camera_io_w(*(++p),
- vfe32_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
- } else {
- ++p;
- ++p;
- }
- msm_camera_io_w(*(++p),
vfe32_ctrl->share_ctrl->vfebase + VFE_REALIGN_BUF);
msm_camera_io_w(*(++p),
vfe32_ctrl->share_ctrl->vfebase + VFE_CHROMA_UP);
@@ -767,7 +960,7 @@
rc = vfe32_ctrl->stats_ops.dqbuf(
vfe32_ctrl->stats_ops.stats_ctrl, stats_type, &buf);
if (rc < 0) {
- pr_err("%s: dq stats buf (type = %d) err = %d",
+ CDBG("%s: dq stats buf (type = %d) err = %d",
__func__, stats_type, rc);
return 0L;
}
@@ -802,7 +995,7 @@
stats_buf = &bufq->bufs[i];
rc = vfe32_ctrl->stats_ops.enqueue_buf(
vfe32_ctrl->stats_ops.stats_ctrl,
- &(stats_buf->info), NULL);
+ &(stats_buf->info), NULL, -1);
if (rc < 0) {
pr_err("%s: dq stats buf (type = %d) err = %d",
__func__, stats_type, rc);
@@ -815,7 +1008,7 @@
static unsigned long vfe32_stats_unregbuf(
struct vfe32_ctrl_type *vfe32_ctrl,
- struct msm_stats_reqbuf *req_buf)
+ struct msm_stats_reqbuf *req_buf, int domain_num)
{
int i = 0, rc = 0;
@@ -823,7 +1016,7 @@
rc = vfe32_ctrl->stats_ops.buf_unprepare(
vfe32_ctrl->stats_ops.stats_ctrl,
req_buf->stats_type, i,
- vfe32_ctrl->stats_ops.client);
+ vfe32_ctrl->stats_ops.client, domain_num);
if (rc < 0) {
pr_err("%s: unreg stats buf (type = %d) err = %d",
__func__, req_buf->stats_type, rc);
@@ -1063,70 +1256,17 @@
static void vfe32_start_common(struct vfe32_ctrl_type *vfe32_ctrl)
{
- uint32_t irq_mask = 0x00E00021, irq_mask1, reg_update;
uint16_t vfe_operation_mode =
vfe32_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
VFE_OUTPUTS_RDI1);
- vfe32_ctrl->share_ctrl->start_ack_pending = TRUE;
CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
vfe32_ctrl->share_ctrl->current_mode,
vfe32_ctrl->share_ctrl->outpath.output_mode);
- if (vfe32_ctrl->share_ctrl->stats_comp)
- irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK;
- else
- irq_mask |= 0x000FE000;
- irq_mask |=
- msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
- VFE_IRQ_MASK_0);
- msm_camera_io_w(irq_mask,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
- msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
- vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
- irq_mask1 =
- msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
- VFE_IRQ_MASK_1);
- reg_update =
- msm_camera_io_r_mb(vfe32_ctrl->share_ctrl->vfebase +
- VFE_REG_UPDATE_CMD);
-
- if (vfe32_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
- irq_mask1 |= VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK;
- msm_camera_io_w(irq_mask1, vfe32_ctrl->share_ctrl->vfebase +
- VFE_IRQ_MASK_1);
- if (!atomic_cmpxchg(
- &vfe32_ctrl->share_ctrl->rdi0_update_ack_pending,
- 0, 1)) {
- msm_camera_io_w_mb(reg_update|0x2,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_REG_UPDATE_CMD);
- }
- }
- if (vfe32_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
- irq_mask1 |= VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK;
- msm_camera_io_w(irq_mask1, vfe32_ctrl->share_ctrl->vfebase +
- VFE_IRQ_MASK_1);
- if (!atomic_cmpxchg(
- &vfe32_ctrl->share_ctrl->rdi1_update_ack_pending,
- 0, 1)) {
- msm_camera_io_w_mb(reg_update|0x4,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_REG_UPDATE_CMD);
- }
- msm_camera_io_w_mb(reg_update|0x4, vfe32_ctrl->share_ctrl->
- vfebase + VFE_REG_UPDATE_CMD);
- }
if (vfe_operation_mode) {
- msm_camera_io_w_mb(reg_update|0x1, vfe32_ctrl->share_ctrl->
- vfebase + VFE_REG_UPDATE_CMD);
msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
VFE_CAMIF_COMMAND);
}
- vfe32_ctrl->share_ctrl->operation_mode |=
- vfe32_ctrl->share_ctrl->current_mode;
- /* Ensure the write order while writing
- to the command register using the barrier */
- atomic_set(&vfe32_ctrl->share_ctrl->vstate, 1);
}
static int vfe32_start_recording(
@@ -1176,6 +1316,7 @@
struct msm_cam_media_controller *pmctl,
struct vfe32_ctrl_type *vfe32_ctrl)
{
+ vfe32_ctrl->share_ctrl->start_ack_pending = TRUE;
vfe32_start_common(vfe32_ctrl);
msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x18C);
@@ -1570,7 +1711,8 @@
case VFE_CMD_RESET:
pr_info("vfe32_proc_general: cmdID = %s\n",
vfe32_general_cmd[cmd->id]);
- vfe32_reset_internal_variables(vfe32_ctrl);
+ vfe32_ctrl->share_ctrl->vfe_reset_flag = true;
+ vfe32_reset(vfe32_ctrl);
break;
case VFE_CMD_START:
pr_info("vfe32_proc_general: cmdID = %s\n",
@@ -3026,221 +3168,479 @@
}
+void axi_stop_pix(struct vfe_share_ctrl_t *share_ctrl)
+{
+ uint32_t operation_mode =
+ share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+ VFE_OUTPUTS_RDI1);
+ uint32_t irq_comp_mask, irq_mask;
+ uint32_t reg_update = 0x1;
+
+ irq_comp_mask =
+ msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_COMP_MASK);
+ irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ switch (share_ctrl->cmd_type) {
+ case AXI_CMD_PREVIEW: {
+ switch (operation_mode) {
+ case VFE_OUTPUTS_PREVIEW:
+ case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+ if (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch1]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out0.ch0 |
+ 0x1 << share_ctrl->outpath.out0.ch1);
+ share_ctrl->outpath.output_mode |=
+ VFE32_OUTPUT_MODE_PRIMARY;
+ } else if (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch1]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch2]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out0.ch0 |
+ 0x1 << share_ctrl->outpath.out0.ch1 |
+ 0x1 << share_ctrl->outpath.out0.ch2);
+ share_ctrl->outpath.output_mode |=
+ VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+ }
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+ break;
+ default:
+ if (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch1]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out1.ch0 |
+ 0x1 << share_ctrl->outpath.out1.ch1);
+ share_ctrl->outpath.output_mode |=
+ VFE32_OUTPUT_MODE_SECONDARY;
+ } else if (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch1]);
+ msm_camera_io_w(0, share_ctrl->vfebase
+ + vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch2]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out1.ch0 |
+ 0x1 << share_ctrl->outpath.out1.ch1 |
+ 0x1 << share_ctrl->outpath.out1.ch2);
+ share_ctrl->outpath.output_mode |=
+ VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+ }
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+ break;
+ }
+ }
+ break;
+ default:
+ if (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch1]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out0.ch0 |
+ 0x1 << share_ctrl->outpath.out0.ch1);
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+ share_ctrl->outpath.output_mode |=
+ VFE32_OUTPUT_MODE_PRIMARY;
+ } else if (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch1]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out0.ch2]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out0.ch0 |
+ 0x1 << share_ctrl->outpath.out0.ch1 |
+ 0x1 << share_ctrl->outpath.out0.ch2);
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
+ share_ctrl->outpath.output_mode |=
+ VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+ }
+
+ if (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->
+ outpath.out1.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->outpath.out1.ch1]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out1.ch0 |
+ 0x1 << share_ctrl->outpath.out1.ch1);
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+ share_ctrl->outpath.output_mode |=
+ VFE32_OUTPUT_MODE_SECONDARY;
+ } else if (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->outpath.out1.ch2]);
+ irq_comp_mask &= ~(
+ 0x1 << share_ctrl->outpath.out1.ch0 |
+ 0x1 << share_ctrl->outpath.out1.ch1 |
+ 0x1 << share_ctrl->outpath.out1.ch2);
+ irq_mask &= ~VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
+ share_ctrl->outpath.output_mode |=
+ VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+ }
+ break;
+ }
+
+ msm_camera_io_w_mb(reg_update,
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w(irq_comp_mask,
+ share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_w(irq_mask, share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+}
+
+void axi_stop_rdi0(struct vfe_share_ctrl_t *share_ctrl)
+{
+ uint32_t reg_update = 0x2;
+ uint32_t irq_mask;
+ irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->outpath.out2.ch0]);
+ irq_mask &= ~(0x1 << (share_ctrl->outpath.out2.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 +
+ VFE_IRQ_MASK_0);
+}
+
+void axi_stop_rdi1(struct vfe_share_ctrl_t *share_ctrl)
+{
+ uint32_t reg_update = 0x4;
+ uint32_t irq_mask;
+ irq_mask = msm_camera_io_r(share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+ msm_camera_io_w(1, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[share_ctrl->outpath.out3.ch0]);
+ 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 +
+ VFE_IRQ_MASK_0);
+}
+
+void axi_stop_process(struct vfe_share_ctrl_t *share_ctrl)
+{
+ uint32_t operation_mode =
+ share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
+ VFE_OUTPUTS_RDI1);
+
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+ axi_stop_rdi0(share_ctrl);
+ share_ctrl->comp_output_mode &= ~VFE32_OUTPUT_MODE_TERTIARY1;
+ }
+ if (share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+ axi_stop_rdi1(share_ctrl);
+ share_ctrl->comp_output_mode &= ~VFE32_OUTPUT_MODE_TERTIARY2;
+ }
+ if (operation_mode) {
+ axi_stop_pix(share_ctrl);
+ share_ctrl->comp_output_mode &=
+ ~(share_ctrl->outpath.output_mode);
+ }
+}
+
static void vfe32_process_reg_update_irq(
struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
+ struct vfe_share_ctrl_t *share_ctrl = vfe32_ctrl->share_ctrl;
- if (vfe32_ctrl->share_ctrl->recording_state ==
- VFE_STATE_START_REQUESTED) {
- if (vfe32_ctrl->share_ctrl->operation_mode &
- VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
- msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch1]);
- } else if (vfe32_ctrl->share_ctrl->operation_mode &
- VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
- msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out1.ch1]);
- }
- vfe32_ctrl->share_ctrl->recording_state = VFE_STATE_STARTED;
- msm_camera_io_w_mb(1,
- vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- CDBG("start video triggered .\n");
- } else if (vfe32_ctrl->share_ctrl->recording_state ==
- VFE_STATE_STOP_REQUESTED) {
- if (vfe32_ctrl->share_ctrl->operation_mode &
- VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
- msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch1]);
- } else if (vfe32_ctrl->share_ctrl->operation_mode &
- VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
- msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out1.ch1]);
- }
- CDBG("stop video triggered .\n");
- }
-
- spin_lock_irqsave(&vfe32_ctrl->share_ctrl->start_ack_lock, flags);
- if (vfe32_ctrl->share_ctrl->start_ack_pending == TRUE) {
- vfe32_ctrl->share_ctrl->start_ack_pending = FALSE;
- spin_unlock_irqrestore(
- &vfe32_ctrl->share_ctrl->start_ack_lock, flags);
+ if (atomic_cmpxchg(
+ &share_ctrl->pix0_update_ack_pending, 2, 0) == 2) {
+ axi_stop_pix(share_ctrl);
+ msm_camera_io_w_mb(
+ CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ share_ctrl->vfebase + VFE_CAMIF_COMMAND);
+ axi_disable_irq(share_ctrl);
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
- vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
- } else {
- spin_unlock_irqrestore(
- &vfe32_ctrl->share_ctrl->start_ack_lock, flags);
- if (vfe32_ctrl->share_ctrl->recording_state ==
- VFE_STATE_STOP_REQUESTED) {
- vfe32_ctrl->share_ctrl->recording_state =
- VFE_STATE_STOPPED;
- /* request a reg update and send STOP_REC_ACK
- * when we process the next reg update irq.
- */
+ share_ctrl->vfeFrameId,
+ MSG_ID_PIX0_UPDATE_ACK);
+ share_ctrl->comp_output_mode &=
+ ~(share_ctrl->outpath.output_mode);
+ share_ctrl->current_mode &=
+ (VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI0);
+ } else {
+ if (share_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+ if (share_ctrl->operation_mode &
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ msm_camera_io_w(1,
+ share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1,
+ share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch1]);
+ } else if (share_ctrl->operation_mode &
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ msm_camera_io_w(1,
+ share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1,
+ share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out1.ch1]);
+ }
+ share_ctrl->recording_state = VFE_STATE_STARTED;
msm_camera_io_w_mb(1,
- vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- } else if (vfe32_ctrl->share_ctrl->recording_state ==
- VFE_STATE_STOPPED) {
- vfe32_send_isp_msg(&vfe32_ctrl->subdev,
- vfe32_ctrl->share_ctrl->vfeFrameId,
- MSG_ID_STOP_REC_ACK);
- vfe32_ctrl->share_ctrl->recording_state =
- VFE_STATE_IDLE;
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ CDBG("start video triggered .\n");
+ } else if (share_ctrl->recording_state ==
+ VFE_STATE_STOP_REQUESTED) {
+ if (share_ctrl->operation_mode &
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ msm_camera_io_w(0,
+ share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0,
+ share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch1]);
+ } else if (share_ctrl->operation_mode &
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ msm_camera_io_w(0,
+ share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0,
+ share_ctrl->vfebase + vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out1.ch1]);
+ }
+ CDBG("stop video triggered .\n");
}
- spin_lock_irqsave(
- &vfe32_ctrl->share_ctrl->update_ack_lock, flags);
- if (vfe32_ctrl->share_ctrl->update_ack_pending == TRUE) {
- vfe32_ctrl->share_ctrl->update_ack_pending = FALSE;
- spin_unlock_irqrestore(
- &vfe32_ctrl->share_ctrl->update_ack_lock,
- flags);
+
+ if (atomic_cmpxchg(
+ &share_ctrl->pix0_update_ack_pending, 1, 0) == 1) {
+ share_ctrl->comp_output_mode |=
+ (share_ctrl->outpath.output_mode
+ & ~(VFE32_OUTPUT_MODE_TERTIARY1|
+ VFE32_OUTPUT_MODE_TERTIARY2));
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
- vfe32_ctrl->share_ctrl->vfeFrameId,
- MSG_ID_UPDATE_ACK);
+ share_ctrl->vfeFrameId, MSG_ID_PIX0_UPDATE_ACK);
+ share_ctrl->current_mode &=
+ (VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI0);
} else {
- spin_unlock_irqrestore(
- &vfe32_ctrl->share_ctrl->update_ack_lock,
- flags);
+ if (share_ctrl->recording_state ==
+ VFE_STATE_STOP_REQUESTED) {
+ share_ctrl->recording_state = VFE_STATE_STOPPED;
+ /* request a reg update and send STOP_REC_ACK
+ * when we process the next reg update irq.
+ */
+ msm_camera_io_w_mb(1, share_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ } else if (share_ctrl->recording_state ==
+ VFE_STATE_STOPPED) {
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ share_ctrl->vfeFrameId,
+ MSG_ID_STOP_REC_ACK);
+ share_ctrl->recording_state = VFE_STATE_IDLE;
+ }
+ spin_lock_irqsave(
+ &share_ctrl->update_ack_lock,
+ flags);
+ if (share_ctrl->update_ack_pending == TRUE) {
+ share_ctrl->update_ack_pending = FALSE;
+ spin_unlock_irqrestore(
+ &share_ctrl->update_ack_lock, flags);
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ share_ctrl->vfeFrameId,
+ MSG_ID_UPDATE_ACK);
+ } else {
+ spin_unlock_irqrestore(
+ &share_ctrl->update_ack_lock, flags);
+ }
}
- }
- switch (vfe32_ctrl->share_ctrl->liveshot_state) {
- case VFE_STATE_START_REQUESTED:
- CDBG("%s enabling liveshot output\n", __func__);
- if (vfe32_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch1]);
+ switch (share_ctrl->liveshot_state) {
+ case VFE_STATE_START_REQUESTED:
+ CDBG("%s enabling liveshot output\n", __func__);
+ if (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(1, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch1]);
- vfe32_ctrl->share_ctrl->liveshot_state =
- VFE_STATE_STARTED;
+ share_ctrl->liveshot_state =
+ VFE_STATE_STARTED;
+ }
+ break;
+ case VFE_STATE_STARTED:
+ share_ctrl->vfe_capture_count--;
+ if (!share_ctrl->vfe_capture_count &&
+ (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY)) {
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch1]);
+ }
+ break;
+ case VFE_STATE_STOP_REQUESTED:
+ if (share_ctrl->comp_output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY) {
+ /* Stop requested, stop write masters, and
+ * trigger REG_UPDATE. Send STOP_LS_ACK in
+ * next reg update. */
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, share_ctrl->vfebase +
+ vfe32_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);
+ }
+ break;
+ case VFE_STATE_STOPPED:
+ CDBG("%s Sending STOP_LS ACK\n", __func__);
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ share_ctrl->vfeFrameId, MSG_ID_STOP_LS_ACK);
+ share_ctrl->liveshot_state = VFE_STATE_IDLE;
+ break;
+ default:
+ break;
}
- break;
- case VFE_STATE_STARTED:
- vfe32_ctrl->share_ctrl->vfe_capture_count--;
- if (!vfe32_ctrl->share_ctrl->vfe_capture_count &&
- (vfe32_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_PRIMARY)) {
- msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch1]);
- }
- break;
- case VFE_STATE_STOP_REQUESTED:
- if (vfe32_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_PRIMARY) {
- /* Stop requested, stop write masters, and
- * trigger REG_UPDATE. Send STOP_LS_ACK in
- * next reg update. */
- msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch1]);
- vfe32_ctrl->share_ctrl->liveshot_state =
- VFE_STATE_STOPPED;
- msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
- VFE_REG_UPDATE_CMD);
- }
- break;
- case VFE_STATE_STOPPED:
- CDBG("%s Sending STOP_LS ACK\n", __func__);
- vfe32_send_isp_msg(&vfe32_ctrl->subdev,
- vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_LS_ACK);
- vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
- break;
- default:
- break;
- }
-
- if ((vfe32_ctrl->share_ctrl->operation_mode &
- VFE_OUTPUTS_THUMB_AND_MAIN) ||
- (vfe32_ctrl->share_ctrl->operation_mode &
- VFE_OUTPUTS_MAIN_AND_THUMB) ||
- (vfe32_ctrl->share_ctrl->operation_mode &
- VFE_OUTPUTS_THUMB_AND_JPEG) ||
- (vfe32_ctrl->share_ctrl->operation_mode &
- VFE_OUTPUTS_JPEG_AND_THUMB)) {
- /* in snapshot mode */
- /* later we need to add check for live snapshot mode. */
- if (vfe32_ctrl->frame_skip_pattern & (0x1 <<
- (vfe32_ctrl->snapshot_frame_cnt %
- vfe32_ctrl->frame_skip_cnt))) {
- vfe32_ctrl->share_ctrl->vfe_capture_count--;
- /* if last frame to be captured: */
- if (vfe32_ctrl->share_ctrl->vfe_capture_count == 0) {
- /* stop the bus output:write master enable = 0*/
- if (vfe32_ctrl->share_ctrl->outpath.output_mode
- & VFE32_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(0,
- vfe32_ctrl->share_ctrl->vfebase+
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0,
- vfe32_ctrl->share_ctrl->vfebase+
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out0.ch1]);
- }
- if (vfe32_ctrl->share_ctrl->outpath.output_mode&
+ if ((share_ctrl->operation_mode & VFE_OUTPUTS_THUMB_AND_MAIN) ||
+ (share_ctrl->operation_mode &
+ VFE_OUTPUTS_MAIN_AND_THUMB) ||
+ (share_ctrl->operation_mode &
+ VFE_OUTPUTS_THUMB_AND_JPEG) ||
+ (share_ctrl->operation_mode &
+ VFE_OUTPUTS_JPEG_AND_THUMB)) {
+ /* in snapshot mode */
+ /* later we need to add check for live snapshot mode. */
+ if (vfe32_ctrl->frame_skip_pattern & (0x1 <<
+ (vfe32_ctrl->snapshot_frame_cnt %
+ vfe32_ctrl->frame_skip_cnt))) {
+ share_ctrl->vfe_capture_count--;
+ /* if last frame to be captured: */
+ if (share_ctrl->vfe_capture_count == 0) {
+ /* stop the bus output: */
+ if (share_ctrl->comp_output_mode
+ & VFE32_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(0,
+ share_ctrl->vfebase+
+ vfe32_AXI_WM_CFG[
+ share_ctrl->
+ outpath.out0.ch0]);
+ msm_camera_io_w(0,
+ share_ctrl->vfebase+
+ vfe32_AXI_WM_CFG[
+ share_ctrl->
+ outpath.out0.ch1]);
+ }
+ if (share_ctrl->comp_output_mode &
VFE32_OUTPUT_MODE_SECONDARY) {
- msm_camera_io_w(0,
- vfe32_ctrl->share_ctrl->vfebase+
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(0,
- vfe32_ctrl->share_ctrl->vfebase+
- vfe32_AXI_WM_CFG[vfe32_ctrl->
- share_ctrl->outpath.out1.ch1]);
- }
- msm_camera_io_w_mb
- (CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_CAMIF_COMMAND);
- vfe32_ctrl->snapshot_frame_cnt = -1;
- vfe32_ctrl->frame_skip_cnt = 31;
- vfe32_ctrl->frame_skip_pattern = 0xffffffff;
- } /*if snapshot count is 0*/
- } /*if frame is not being dropped*/
- vfe32_ctrl->snapshot_frame_cnt++;
- /* then do reg_update. */
- msm_camera_io_w(1,
- vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- } /* if snapshot mode. */
+ msm_camera_io_w(0,
+ share_ctrl->vfebase+
+ vfe32_AXI_WM_CFG[
+ share_ctrl->
+ outpath.out1.ch0]);
+ msm_camera_io_w(0,
+ share_ctrl->vfebase+
+ vfe32_AXI_WM_CFG[
+ share_ctrl->
+ outpath.out1.ch1]);
+ }
+ msm_camera_io_w_mb
+ (CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ share_ctrl->vfebase +
+ VFE_CAMIF_COMMAND);
+ vfe32_ctrl->snapshot_frame_cnt = -1;
+ vfe32_ctrl->frame_skip_cnt = 31;
+ vfe32_ctrl->frame_skip_pattern =
+ 0xffffffff;
+ } /*if snapshot count is 0*/
+ } /*if frame is not being dropped*/
+ vfe32_ctrl->snapshot_frame_cnt++;
+ /* then do reg_update. */
+ msm_camera_io_w(1,
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } /* if snapshot mode. */
+ }
}
static void vfe32_process_rdi0_reg_update_irq(
struct vfe32_ctrl_type *vfe32_ctrl)
{
if (atomic_cmpxchg(
- &vfe32_ctrl->share_ctrl->rdi0_update_ack_pending, 1, 0)) {
+ &vfe32_ctrl->share_ctrl->rdi0_update_ack_pending, 2, 0) == 2) {
+ axi_stop_rdi0(vfe32_ctrl->share_ctrl);
+ axi_disable_irq(vfe32_ctrl->share_ctrl);
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
vfe32_ctrl->share_ctrl->vfeFrameId,
MSG_ID_RDI0_UPDATE_ACK);
+ vfe32_ctrl->share_ctrl->comp_output_mode &=
+ ~VFE32_OUTPUT_MODE_TERTIARY1;
+ vfe32_ctrl->share_ctrl->current_mode &=
+ ~(VFE_OUTPUTS_RDI0);
+ }
+
+ if (atomic_cmpxchg(
+ &vfe32_ctrl->share_ctrl->rdi0_update_ack_pending, 1, 0) == 1) {
+ vfe32_ctrl->share_ctrl->comp_output_mode |=
+ VFE32_OUTPUT_MODE_TERTIARY1;
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_RDI0_UPDATE_ACK);
+ vfe32_ctrl->share_ctrl->current_mode &=
+ ~(VFE_OUTPUTS_RDI0);
}
}
@@ -3248,90 +3648,28 @@
struct vfe32_ctrl_type *vfe32_ctrl)
{
if (atomic_cmpxchg(
- &vfe32_ctrl->share_ctrl->rdi1_update_ack_pending, 1, 0)) {
+ &vfe32_ctrl->share_ctrl->rdi1_update_ack_pending, 2, 0) == 2) {
+ axi_stop_rdi1(vfe32_ctrl->share_ctrl);
+ axi_disable_irq(vfe32_ctrl->share_ctrl);
vfe32_send_isp_msg(&vfe32_ctrl->subdev,
vfe32_ctrl->share_ctrl->vfeFrameId,
MSG_ID_RDI1_UPDATE_ACK);
+ vfe32_ctrl->share_ctrl->comp_output_mode &=
+ ~VFE32_OUTPUT_MODE_TERTIARY2;
+ vfe32_ctrl->share_ctrl->current_mode &=
+ ~(VFE_OUTPUTS_RDI1);
}
-}
-static void vfe32_set_default_reg_values(
- struct vfe32_ctrl_type *vfe32_ctrl)
-{
- msm_camera_io_w(0x800080,
- vfe32_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0);
- msm_camera_io_w(0x800080,
- vfe32_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1);
- /* What value should we program CGC_OVERRIDE to? */
- msm_camera_io_w(0xFFFFF,
- vfe32_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
-
- /* default frame drop period and pattern */
- msm_camera_io_w(0x1f,
- vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
- msm_camera_io_w(0x1f,
- vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
- msm_camera_io_w(0xFFFFFFFF,
- vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
- msm_camera_io_w(0xFFFFFFFF,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_FRAMEDROP_ENC_CBCR_PATTERN);
- msm_camera_io_w(0x1f,
- vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y);
- msm_camera_io_w(0x1f,
- vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR);
- msm_camera_io_w(0xFFFFFFFF,
- vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
- msm_camera_io_w(0xFFFFFFFF,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
- msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MIN);
- msm_camera_io_w(0xFFFFFF,
- vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MAX);
-
- /* stats UB config */
- CDBG("%s: Use bayer stats = %d\n", __func__,
- vfe32_use_bayer_stats(vfe32_ctrl));
- if (!vfe32_use_bayer_stats(vfe32_ctrl)) {
- msm_camera_io_w(0x3980007,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_AEC_BG_UB_CFG);
- msm_camera_io_w(0x3A00007,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_AF_BF_UB_CFG);
- msm_camera_io_w(0x3A8000F,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_AWB_UB_CFG);
- msm_camera_io_w(0x3B80007,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_RS_UB_CFG);
- msm_camera_io_w(0x3C0001F,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_CS_UB_CFG);
- msm_camera_io_w(0x3E0001F,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_HIST_UB_CFG);
- } else {
- msm_camera_io_w(0x350001F,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_HIST_UB_CFG);
- msm_camera_io_w(0x370002F,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_AEC_BG_UB_CFG);
- msm_camera_io_w(0x3A0002F,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_AF_BF_UB_CFG);
- msm_camera_io_w(0x3D00007,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_RS_UB_CFG);
- msm_camera_io_w(0x3D8001F,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_CS_UB_CFG);
- msm_camera_io_w(0x3F80007,
- vfe32_ctrl->share_ctrl->vfebase +
- VFE_BUS_STATS_SKIN_BHIST_UB_CFG);
+ if (atomic_cmpxchg(
+ &vfe32_ctrl->share_ctrl->rdi1_update_ack_pending, 1, 0) == 1) {
+ vfe32_ctrl->share_ctrl->comp_output_mode |=
+ VFE32_OUTPUT_MODE_TERTIARY2;
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_RDI1_UPDATE_ACK);
+ vfe32_ctrl->share_ctrl->current_mode &=
+ ~(VFE_OUTPUTS_RDI1);
}
- vfe32_reset_dmi_tables(vfe32_ctrl);
}
static void vfe32_process_reset_irq(
@@ -3340,23 +3678,33 @@
unsigned long flags;
atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
+ atomic_set(&vfe32_ctrl->share_ctrl->handle_common_irq, 0);
spin_lock_irqsave(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
if (vfe32_ctrl->share_ctrl->stop_ack_pending) {
vfe32_ctrl->share_ctrl->stop_ack_pending = FALSE;
spin_unlock_irqrestore(
&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
- vfe32_send_isp_msg(&vfe32_ctrl->subdev,
- vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_ACK);
+ if (vfe32_ctrl->share_ctrl->sync_abort)
+ complete(&vfe32_ctrl->share_ctrl->reset_complete);
+ else
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_STOP_ACK);
} else {
spin_unlock_irqrestore(
&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
/* this is from reset command. */
- vfe32_set_default_reg_values(vfe32_ctrl);
-
- /* reload all write masters. (frame & line)*/
- msm_camera_io_w(0x7FFF,
- vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+ vfe32_reset_internal_variables(vfe32_ctrl);
+ if (vfe32_ctrl->share_ctrl->vfe_reset_flag) {
+ vfe32_ctrl->share_ctrl->vfe_reset_flag = false;
+ msm_camera_io_w(0x7F80,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+ } else {
+ /* reload all write masters. (frame & line)*/
+ msm_camera_io_w(0x7FFF,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+ }
complete(&vfe32_ctrl->share_ctrl->reset_complete);
}
}
@@ -3367,9 +3715,6 @@
if (vfe32_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_RAW) {
if (vfe32_ctrl->share_ctrl->start_ack_pending) {
- vfe32_send_isp_msg(&vfe32_ctrl->subdev,
- vfe32_ctrl->share_ctrl->vfeFrameId,
- MSG_ID_START_ACK);
vfe32_ctrl->share_ctrl->start_ack_pending = FALSE;
}
vfe32_ctrl->share_ctrl->vfe_capture_count--;
@@ -3411,6 +3756,12 @@
struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
{
uint32_t reg_value;
+ if (errStatus & VFE32_IMASK_VIOLATION) {
+ pr_err("vfe32_irq: violation interrupt\n");
+ reg_value = msm_camera_io_r(
+ axi_ctrl->share_ctrl->vfebase + VFE_VIOLATION_STATUS);
+ pr_err("%s: violationStatus = 0x%x\n", __func__, reg_value);
+ }
if (errStatus & VFE32_IMASK_CAMIF_ERROR) {
pr_err("vfe32_irq: camif errors\n");
@@ -3441,12 +3792,31 @@
if (errStatus & VFE32_IMASK_REALIGN_BUF_CR_OVFL)
pr_err("vfe32_irq: realign bug CR overflow\n");
- if (errStatus & VFE32_IMASK_VIOLATION) {
- pr_err("vfe32_irq: violation interrupt\n");
- reg_value = msm_camera_io_r(
- axi_ctrl->share_ctrl->vfebase + VFE_VIOLATION_STATUS);
- pr_err("%s: violationStatus = 0x%x\n", __func__, reg_value);
- }
+ if (errStatus & VFE32_IMASK_STATS_AE_BG_BUS_OVFL)
+ pr_err("vfe32_irq: ae/bg stats bus overflow\n");
+
+ if (errStatus & VFE32_IMASK_STATS_AF_BF_BUS_OVFL)
+ pr_err("vfe32_irq: af/bf stats bus overflow\n");
+
+ if (errStatus & VFE32_IMASK_STATS_AWB_BUS_OVFL)
+ pr_err("vfe32_irq: awb stats bus overflow\n");
+
+ if (errStatus & VFE32_IMASK_STATS_RS_BUS_OVFL)
+ pr_err("vfe32_irq: rs stats bus overflow\n");
+
+ if (errStatus & VFE32_IMASK_STATS_CS_BUS_OVFL)
+ pr_err("vfe32_irq: cs stats bus overflow\n");
+
+ if (errStatus & VFE32_IMASK_STATS_IHIST_BUS_OVFL)
+ pr_err("vfe32_irq: ihist stats bus overflow\n");
+
+ if (errStatus & VFE32_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
+ pr_err("vfe32_irq: skin/bhist stats bus overflow\n");
+}
+
+static void vfe32_process_common_error_irq(
+ struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
+{
if (errStatus & VFE32_IMASK_IMG_MAST_0_BUS_OVFL)
pr_err("vfe32_irq: image master 0 bus overflow\n");
@@ -3469,31 +3839,11 @@
if (errStatus & VFE32_IMASK_IMG_MAST_6_BUS_OVFL)
pr_err("vfe32_irq: image master 6 bus overflow\n");
- if (errStatus & VFE32_IMASK_STATS_AE_BG_BUS_OVFL)
- pr_err("vfe32_irq: ae/bg stats bus overflow\n");
-
- if (errStatus & VFE32_IMASK_STATS_AF_BF_BUS_OVFL)
- pr_err("vfe32_irq: af/bf stats bus overflow\n");
-
- if (errStatus & VFE32_IMASK_STATS_AWB_BUS_OVFL)
- pr_err("vfe32_irq: awb stats bus overflow\n");
-
- if (errStatus & VFE32_IMASK_STATS_RS_BUS_OVFL)
- pr_err("vfe32_irq: rs stats bus overflow\n");
-
- if (errStatus & VFE32_IMASK_STATS_CS_BUS_OVFL)
- pr_err("vfe32_irq: cs stats bus overflow\n");
-
- if (errStatus & VFE32_IMASK_STATS_IHIST_BUS_OVFL)
- pr_err("vfe32_irq: ihist stats bus overflow\n");
-
- if (errStatus & VFE32_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
- pr_err("vfe32_irq: skin/bhist stats bus overflow\n");
-
if (errStatus & VFE32_IMASK_AXI_ERROR)
pr_err("vfe32_irq: axi error\n");
}
+
static void vfe_send_outmsg(
struct axi_ctrl_t *axi_ctrl, uint8_t msgid,
uint32_t ch0_paddr, uint32_t ch1_paddr,
@@ -3506,7 +3856,17 @@
msg.buf.ch_paddr[0] = ch0_paddr;
msg.buf.ch_paddr[1] = ch1_paddr;
msg.buf.ch_paddr[2] = ch2_paddr;
- msg.frameCounter = axi_ctrl->share_ctrl->vfeFrameId;
+ switch (msgid) {
+ case MSG_ID_OUTPUT_TERTIARY1:
+ msg.frameCounter = axi_ctrl->share_ctrl->rdi0FrameId;
+ break;
+ case MSG_ID_OUTPUT_TERTIARY2:
+ msg.frameCounter = axi_ctrl->share_ctrl->rdi1FrameId;
+ break;
+ default:
+ msg.frameCounter = axi_ctrl->share_ctrl->vfeFrameId;
+ break;
+ }
v4l2_subdev_notify(&axi_ctrl->subdev,
NOTIFY_VFE_MSG_OUT,
@@ -3532,15 +3892,15 @@
free buffer.
*/
out_bool = (
- (axi_ctrl->share_ctrl->operation_mode ==
+ (axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_THUMB_AND_MAIN ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_MAIN_AND_THUMB ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_THUMB_AND_JPEG ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_JPEG_AND_THUMB ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_RAW ||
axi_ctrl->share_ctrl->liveshot_state ==
VFE_STATE_STARTED ||
@@ -3587,15 +3947,15 @@
axi_ctrl->share_ctrl->outpath.out0.ch2,
free_buf->ch_paddr[2]);
}
- if (axi_ctrl->share_ctrl->operation_mode ==
+ if (axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_THUMB_AND_MAIN ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_MAIN_AND_THUMB ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_THUMB_AND_JPEG ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_JPEG_AND_THUMB ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_RAW ||
axi_ctrl->share_ctrl->liveshot_state ==
VFE_STATE_STOPPED)
@@ -3623,13 +3983,13 @@
free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
VFE_MSG_OUTPUT_SECONDARY, axi_ctrl);
- out_bool = ((axi_ctrl->share_ctrl->operation_mode ==
+ out_bool = ((axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_THUMB_AND_MAIN ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_MAIN_AND_THUMB ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_RAW ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_JPEG_AND_THUMB) &&
(axi_ctrl->share_ctrl->vfe_capture_count <= 1)) ||
free_buf;
@@ -3669,13 +4029,13 @@
axi_ctrl->share_ctrl->outpath.out1.ch2,
free_buf->ch_paddr[2]);
}
- if (axi_ctrl->share_ctrl->operation_mode ==
+ if (axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_THUMB_AND_MAIN ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_MAIN_AND_THUMB ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_RAW ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_JPEG_AND_THUMB)
axi_ctrl->share_ctrl->outpath.out1.capture_cnt--;
@@ -4359,7 +4719,7 @@
VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
if (stat_interrupt)
vfe32_ctrl->simultaneous_sof_stat = 1;
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_CAMIF_SOF_MASK);
}
@@ -4367,41 +4727,51 @@
/* interrupt to be processed, *qcmd has the payload. */
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_REG_UPDATE_MASK)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_REG_UPDATE_MASK);
if (qcmd->vfeInterruptStatus1 &
VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS1_RDI0_REG_UPDATE);
if (qcmd->vfeInterruptStatus1 &
VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS1_RDI1_REG_UPDATE);
if (qcmd->vfeInterruptStatus1 &
VFE_IMASK_WHILE_STOPPING_1)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IMASK_WHILE_STOPPING_1);
- if (atomic_read(&axi_ctrl->share_ctrl->handle_axi_irq))
+ if (atomic_read(&axi_ctrl->share_ctrl->handle_common_irq)) {
+ if (qcmd->vfeInterruptStatus1 &
+ VFE32_IMASK_COMMON_ERROR_ONLY_1) {
+ pr_err("irq errorIrq\n");
+ vfe32_process_common_error_irq(
+ axi_ctrl,
+ qcmd->vfeInterruptStatus1 &
+ VFE32_IMASK_COMMON_ERROR_ONLY_1);
+ }
+
v4l2_subdev_notify(&axi_ctrl->subdev,
NOTIFY_AXI_IRQ,
(void *)qcmd->vfeInterruptStatus0);
+ }
if (atomic_read(&axi_ctrl->share_ctrl->vstate)) {
if (qcmd->vfeInterruptStatus1 &
- VFE32_IMASK_ERROR_ONLY_1) {
+ VFE32_IMASK_VFE_ERROR_ONLY_1) {
pr_err("irq errorIrq\n");
vfe32_process_error_irq(
axi_ctrl,
qcmd->vfeInterruptStatus1 &
- VFE32_IMASK_ERROR_ONLY_1);
+ VFE32_IMASK_VFE_ERROR_ONLY_1);
}
/* then process stats irq. */
@@ -4410,7 +4780,7 @@
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
CDBG("Stats composite irq occured.\n");
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)qcmd->vfeInterruptStatus0);
}
@@ -4418,60 +4788,60 @@
/* process individual stats interrupt. */
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AEC_BG)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_AEC_BG);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AWB)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_AWB);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_AF_BF)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_AF_BF);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_SK_BHIST)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_SK_BHIST);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_IHIST)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_IHIST);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_RS)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_RS);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_CS)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_CS);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_SYNC_TIMER0)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_SYNC_TIMER0);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_SYNC_TIMER1)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_SYNC_TIMER1);
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_SYNC_TIMER2)
- v4l2_subdev_notify(&axi_ctrl->subdev,
+ v4l2_subdev_notify(&vfe32_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_SYNC_TIMER2);
}
@@ -4540,7 +4910,7 @@
static long vfe_stats_bufq_sub_ioctl(
struct vfe32_ctrl_type *vfe_ctrl,
- struct msm_vfe_cfg_cmd *cmd, void *ion_client)
+ struct msm_vfe_cfg_cmd *cmd, void *ion_client, int domain_num)
{
long rc = 0;
switch (cmd->cmd_type) {
@@ -4589,7 +4959,7 @@
rc = vfe_ctrl->stats_ops.enqueue_buf(
&vfe_ctrl->stats_ctrl,
(struct msm_stats_buf_info *)cmd->value,
- vfe_ctrl->stats_ops.client);
+ vfe_ctrl->stats_ops.client, domain_num);
break;
case VFE_CMD_STATS_FLUSH_BUFQ:
{
@@ -4623,7 +4993,7 @@
rc = -EINVAL ;
goto end;
}
- rc = vfe32_stats_unregbuf(vfe_ctrl, req_buf);
+ rc = vfe32_stats_unregbuf(vfe_ctrl, req_buf, domain_num);
}
break;
default:
@@ -4678,7 +5048,7 @@
case VFE_CMD_STATS_UNREGBUF:
/* for easy porting put in one envelope */
rc = vfe_stats_bufq_sub_ioctl(vfe32_ctrl,
- cmd, vfe_params->data);
+ cmd, vfe_params->data, pmctl->domain_num);
return rc;
default:
if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
@@ -4693,8 +5063,8 @@
cmd->cmd_type != CMD_STATS_BG_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BF_BUF_RELEASE &&
cmd->cmd_type != CMD_STATS_BHIST_BUF_RELEASE &&
- cmd->cmd_type != CMD_VFE_SOF_COUNT_UPDATE &&
- cmd->cmd_type != CMD_VFE_COUNT_SOF_ENABLE) {
+ cmd->cmd_type != CMD_VFE_PIX_SOF_COUNT_UPDATE &&
+ cmd->cmd_type != CMD_VFE_COUNT_PIX_SOF_ENABLE) {
if (copy_from_user(&vfecmd,
(void __user *)(cmd->value),
sizeof(vfecmd))) {
@@ -4774,7 +5144,7 @@
case CMD_GENERAL:
rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
break;
- case CMD_VFE_COUNT_SOF_ENABLE: {
+ case CMD_VFE_COUNT_PIX_SOF_ENABLE: {
int enable = *((int *)cmd->value);
if (enable)
vfe32_ctrl->vfe_sof_count_enable = TRUE;
@@ -4782,7 +5152,7 @@
vfe32_ctrl->vfe_sof_count_enable = false;
}
break;
- case CMD_VFE_SOF_COUNT_UPDATE:
+ case CMD_VFE_PIX_SOF_COUNT_UPDATE:
if (!vfe32_ctrl->vfe_sof_count_enable)
vfe32_ctrl->share_ctrl->vfeFrameId =
*((uint32_t *)vfe_params->data);
@@ -4874,6 +5244,10 @@
rc = -EINVAL;
goto mctl_failed;
}
+ axi_ctrl->share_ctrl->axi_ref_cnt++;
+ if (axi_ctrl->share_ctrl->axi_ref_cnt > 1)
+ return rc;
+
spin_lock_init(&axi_ctrl->tasklet_lock);
INIT_LIST_HEAD(&axi_ctrl->tasklet_q);
spin_lock_init(&axi_ctrl->share_ctrl->sd_notify_lock);
@@ -4899,6 +5273,21 @@
if (rc < 0)
goto clk_enable_failed;
+#ifdef CONFIG_MSM_IOMMU
+ rc = iommu_attach_device(mctl->domain, axi_ctrl->iommu_ctx_imgwr);
+ if (rc < 0) {
+ pr_err("%s: imgwr attach failed rc = %d\n", __func__, rc);
+ rc = -ENODEV;
+ goto device_imgwr_attach_failed;
+ }
+ rc = iommu_attach_device(mctl->domain, axi_ctrl->iommu_ctx_misc);
+ if (rc < 0) {
+ pr_err("%s: misc attach failed rc = %d\n", __func__, rc);
+ rc = -ENODEV;
+ goto device_misc_attach_failed;
+ }
+#endif
+
msm_camio_bus_scale_cfg(
mctl->sdata->pdata->cam_bus_scale_table, S_INIT);
msm_camio_bus_scale_cfg(
@@ -4911,9 +5300,21 @@
else
axi_ctrl->share_ctrl->register_total = VFE33_REGISTER_TOTAL;
+ spin_lock_init(&axi_ctrl->share_ctrl->stop_flag_lock);
+ spin_lock_init(&axi_ctrl->share_ctrl->update_ack_lock);
+ spin_lock_init(&axi_ctrl->share_ctrl->start_ack_lock);
+
enable_irq(axi_ctrl->vfeirq->start);
return rc;
+
+#ifdef CONFIG_MSM_IOMMU
+device_misc_attach_failed:
+ iommu_detach_device(mctl->domain, axi_ctrl->iommu_ctx_imgwr);
+device_imgwr_attach_failed:
+#endif
+ msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe32_clk_info,
+ axi_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0);
clk_enable_failed:
if (axi_ctrl->fs_vfe)
regulator_disable(axi_ctrl->fs_vfe);
@@ -4921,7 +5322,6 @@
iounmap(axi_ctrl->share_ctrl->vfebase);
axi_ctrl->share_ctrl->vfebase = NULL;
remap_failed:
- disable_irq(axi_ctrl->vfeirq->start);
mctl_failed:
return rc;
}
@@ -4932,11 +5332,7 @@
struct vfe32_ctrl_type *vfe32_ctrl =
(struct vfe32_ctrl_type *)v4l2_get_subdevdata(sd);
- spin_lock_init(&vfe32_ctrl->share_ctrl->stop_flag_lock);
- spin_lock_init(&vfe32_ctrl->share_ctrl->abort_lock);
spin_lock_init(&vfe32_ctrl->state_lock);
- spin_lock_init(&vfe32_ctrl->share_ctrl->update_ack_lock);
- spin_lock_init(&vfe32_ctrl->share_ctrl->start_ack_lock);
spin_lock_init(&vfe32_ctrl->stats_bufq_lock);
vfe32_ctrl->update_linear = false;
@@ -4946,7 +5342,8 @@
vfe32_ctrl->vfe_sof_count_enable = false;
vfe32_ctrl->hfr_mode = HFR_MODE_OFF;
- memset(&vfe32_ctrl->stats_ctrl, 0, sizeof(struct msm_stats_bufq_ctrl));
+ memset(&vfe32_ctrl->stats_ctrl, 0,
+ sizeof(struct msm_stats_bufq_ctrl));
memset(&vfe32_ctrl->stats_ops, 0, sizeof(struct msm_stats_ops));
return rc;
@@ -4963,8 +5360,15 @@
}
CDBG("%s, free_irq\n", __func__);
+ axi_ctrl->share_ctrl->axi_ref_cnt--;
+ if (axi_ctrl->share_ctrl->axi_ref_cnt > 0)
+ return;
disable_irq(axi_ctrl->vfeirq->start);
tasklet_kill(&axi_ctrl->vfe32_tasklet);
+#ifdef CONFIG_MSM_IOMMU
+ iommu_detach_device(pmctl->domain, axi_ctrl->iommu_ctx_misc);
+ iommu_detach_device(pmctl->domain, axi_ctrl->iommu_ctx_imgwr);
+#endif
msm_cam_clk_enable(&axi_ctrl->pdev->dev, vfe32_clk_info,
axi_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0);
if (axi_ctrl->fs_vfe)
@@ -4978,20 +5382,26 @@
msm_camio_bus_scale_cfg(
pmctl->sdata->pdata->cam_bus_scale_table, S_EXIT);
+
}
void msm_vfe_subdev_release(struct v4l2_subdev *sd)
{
struct vfe32_ctrl_type *vfe32_ctrl =
(struct vfe32_ctrl_type *)v4l2_get_subdevdata(sd);
- if (!vfe32_ctrl->share_ctrl->vfebase)
- vfe32_ctrl->share_ctrl->vfebase = NULL;
+ CDBG("vfe subdev release %p\n",
+ vfe32_ctrl->share_ctrl->vfebase);
}
void axi_abort(struct axi_ctrl_t *axi_ctrl)
{
uint8_t axi_busy_flag = true;
+ unsigned long flags;
/* axi halt command. */
+
+ spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+ axi_ctrl->share_ctrl->stop_ack_pending = TRUE;
+ spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
msm_camera_io_w(AXI_HALT,
axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
wmb();
@@ -5017,6 +5427,9 @@
* to the command register using the barrier */
msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
+ if (axi_ctrl->share_ctrl->sync_abort)
+ wait_for_completion_interruptible(
+ &axi_ctrl->share_ctrl->reset_complete);
}
int axi_config_buffers(struct axi_ctrl_t *axi_ctrl,
@@ -5167,8 +5580,12 @@
void axi_start(struct msm_cam_media_controller *pmctl,
struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
{
- uint32_t irq_comp_mask = 0, irq_mask = 0;
+ uint32_t irq_comp_mask = 0, irq_mask = 0, irq_mask1 = 0;
int rc = 0;
+ uint32_t reg_update = 0;
+ uint16_t operation_mode =
+ (axi_ctrl->share_ctrl->current_mode &
+ ~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1));
rc = axi_config_buffers(axi_ctrl, vfe_params);
if (rc < 0)
return;
@@ -5202,59 +5619,55 @@
irq_comp_mask =
msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
VFE_IRQ_COMP_MASK);
+ irq_mask = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY) {
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 &
VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
irq_comp_mask |= (
0x1 << axi_ctrl->share_ctrl->outpath.out0.ch0 |
0x1 << axi_ctrl->share_ctrl->outpath.out0.ch1 |
0x1 << axi_ctrl->share_ctrl->outpath.out0.ch2);
+ irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK;
}
if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_SECONDARY) {
irq_comp_mask |= (
0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch1 + 8));
+ irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
} else if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
irq_comp_mask |= (
0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch1 + 8) |
0x1 << (axi_ctrl->share_ctrl->outpath.out1.ch2 + 8));
+ irq_mask |= VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK;
}
if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_TERTIARY1) {
- irq_mask = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
- VFE_IRQ_MASK_0);
irq_mask |= (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0 +
VFE_WM_OFFSET));
- msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
- VFE_IRQ_MASK_0);
}
if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_TERTIARY2) {
- irq_mask = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
- VFE_IRQ_MASK_0);
irq_mask |= (0x1 << (axi_ctrl->share_ctrl->outpath.out3.ch0 +
VFE_WM_OFFSET));
- msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
- VFE_IRQ_MASK_0);
}
msm_camera_io_w(irq_comp_mask,
axi_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_w(irq_mask, axi_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_0);
switch (vfe_params.cmd_type) {
case AXI_CMD_PREVIEW: {
- uint16_t operation_mode =
- (axi_ctrl->share_ctrl->operation_mode &
- ~(VFE_OUTPUTS_RDI0|VFE_OUTPUTS_RDI1));
-
switch (operation_mode) {
case VFE_OUTPUTS_PREVIEW:
case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
@@ -5356,14 +5769,46 @@
msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
vfe32_AXI_WM_CFG[axi_ctrl->share_ctrl->
outpath.out3.ch0]);
- atomic_set(&axi_ctrl->share_ctrl->handle_axi_irq, 1);
+
+ irq_mask1 =
+ msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_1);
+
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+ irq_mask1 |= VFE_IRQ_STATUS1_RDI0_REG_UPDATE_MASK;
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->rdi0_update_ack_pending,
+ 0, 1))
+ reg_update |= 0x2;
+ }
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+ irq_mask1 |= VFE_IRQ_STATUS1_RDI1_REG_UPDATE_MASK;
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->rdi1_update_ack_pending,
+ 0, 1))
+ reg_update |= 0x4;
+ }
+ msm_camera_io_w(irq_mask1, axi_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_MASK_1);
+ if (operation_mode) {
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->pix0_update_ack_pending,
+ 0, 1))
+ reg_update |= 0x1;
+ }
+
+ msm_camera_io_w_mb(reg_update,
+ axi_ctrl->share_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ axi_ctrl->share_ctrl->operation_mode |=
+ axi_ctrl->share_ctrl->current_mode;
+ axi_enable_irq(axi_ctrl->share_ctrl);
}
void axi_stop(struct msm_cam_media_controller *pmctl,
struct axi_ctrl_t *axi_ctrl, struct msm_camera_vfe_params_t vfe_params)
{
uint32_t reg_update = 0;
- unsigned long flags;
uint32_t operation_mode =
axi_ctrl->share_ctrl->current_mode & ~(VFE_OUTPUTS_RDI0|
VFE_OUTPUTS_RDI1);
@@ -5386,130 +5831,32 @@
return;
}
- if (!axi_ctrl->share_ctrl->skip_abort) {
- atomic_set(&axi_ctrl->share_ctrl->handle_axi_irq, 0);
- axi_disable_irq(axi_ctrl);
+ if (axi_ctrl->share_ctrl->stop_immediately) {
+ axi_disable_irq(axi_ctrl->share_ctrl);
+ axi_stop_process(axi_ctrl->share_ctrl);
+ return;
}
- spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
- axi_ctrl->share_ctrl->stop_ack_pending = TRUE;
- spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
- switch (vfe_params.cmd_type) {
- case AXI_CMD_PREVIEW: {
- switch (operation_mode) {
- case VFE_OUTPUTS_PREVIEW:
- case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
- if (axi_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
- + vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
- + vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch1]);
- } else if (axi_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
- + vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
- + vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch1]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
- + vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch2]);
- }
- break;
- default:
- if (axi_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_SECONDARY) {
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
- + vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
- + vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out1.ch1]);
- } else if (axi_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
- + vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
- + vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out1.ch1]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase
- + vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out1.ch2]);
- }
- break;
- }
- }
- break;
- default:
- if (axi_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch1]);
- } else if (axi_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch1]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out0.ch2]);
- }
-
- if (axi_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_SECONDARY) {
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out1.ch1]);
- } else if (axi_ctrl->share_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out1.ch1]);
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->
- share_ctrl->outpath.out1.ch2]);
- }
- break;
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0) {
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->rdi0_update_ack_pending,
+ 0, 2))
+ reg_update |= 0x2;
}
- if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->share_ctrl->
- outpath.out2.ch0]);
- if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
- msm_camera_io_w(0, axi_ctrl->share_ctrl->vfebase +
- vfe32_AXI_WM_CFG[axi_ctrl->share_ctrl->
- outpath.out3.ch0]);
-
- if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI0)
- reg_update |= 0x2;
- if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1)
- reg_update |= 0x4;
-
- if (operation_mode)
- reg_update |= 0x1;
+ if (axi_ctrl->share_ctrl->current_mode & VFE_OUTPUTS_RDI1) {
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->rdi1_update_ack_pending,
+ 0, 2))
+ reg_update |= 0x4;
+ }
+ if (operation_mode) {
+ if (!atomic_cmpxchg(
+ &axi_ctrl->share_ctrl->pix0_update_ack_pending,
+ 0, 2))
+ reg_update |= 0x1;
+ }
msm_camera_io_w_mb(reg_update,
axi_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- if (!axi_ctrl->share_ctrl->skip_abort)
- axi_abort(axi_ctrl);
-
}
static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
@@ -5520,7 +5867,6 @@
struct msm_cam_media_controller *pmctl =
(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
int rc = 0, vfe_cmd_type = 0, rdi_mode = 0;
- unsigned long flags;
if (!axi_ctrl->share_ctrl->vfebase) {
pr_err("%s: base address unmapped\n", __func__);
@@ -5716,11 +6062,6 @@
}
axi_ctrl->share_ctrl->current_mode =
vfe_params.operation_mode;
- spin_lock_irqsave(&axi_ctrl->share_ctrl->abort_lock, flags);
- axi_ctrl->share_ctrl->skip_abort =
- vfe_params.skip_abort;
- spin_unlock_irqrestore(&axi_ctrl->share_ctrl->abort_lock,
- flags);
axi_start(pmctl, axi_ctrl, vfe_params);
}
break;
@@ -5733,17 +6074,22 @@
}
axi_ctrl->share_ctrl->current_mode =
vfe_params.operation_mode;
- spin_lock_irqsave(&axi_ctrl->share_ctrl->abort_lock, flags);
- axi_ctrl->share_ctrl->skip_abort =
- vfe_params.skip_abort;
- spin_unlock_irqrestore(&axi_ctrl->share_ctrl->abort_lock,
- flags);
+ axi_ctrl->share_ctrl->stop_immediately =
+ vfe_params.stop_immediately;
axi_stop(pmctl, axi_ctrl, vfe_params);
}
break;
case CMD_AXI_RESET:
axi_reset(axi_ctrl);
break;
+ case CMD_AXI_ABORT:
+ if (copy_from_user(&axi_ctrl->share_ctrl->sync_abort,
+ (void __user *)(vfecmd.value),
+ sizeof(uint8_t))) {
+ return -EFAULT;
+ }
+ axi_abort(axi_ctrl);
+ break;
default:
pr_err("%s Unsupported AXI configuration %x ", __func__,
cfgcmd.cmd_type);
@@ -5756,12 +6102,12 @@
{
struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
uint32_t irqstatus = (uint32_t) arg;
- unsigned long flags;
if (!axi_ctrl->share_ctrl->vfebase) {
pr_err("%s: base address unmapped\n", __func__);
return;
}
+
/* next, check output path related interrupts. */
if (irqstatus &
VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
@@ -5774,12 +6120,12 @@
vfe32_process_output_path_irq_1(axi_ctrl);
}
- if (axi_ctrl->share_ctrl->outpath.output_mode &
+ if (axi_ctrl->share_ctrl->comp_output_mode &
VFE32_OUTPUT_MODE_TERTIARY1)
if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out2.ch0
+ VFE_WM_OFFSET)))
vfe32_process_output_path_irq_rdi0(axi_ctrl);
- if (axi_ctrl->share_ctrl->outpath.output_mode &
+ if (axi_ctrl->share_ctrl->comp_output_mode &
VFE32_OUTPUT_MODE_TERTIARY2)
if (irqstatus & (0x1 << (axi_ctrl->share_ctrl->outpath.out3.ch0
+ VFE_WM_OFFSET)))
@@ -5788,15 +6134,15 @@
/* in snapshot mode if done then send
snapshot done message */
if (
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_THUMB_AND_MAIN ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_MAIN_AND_THUMB ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_THUMB_AND_JPEG ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_JPEG_AND_THUMB ||
- axi_ctrl->share_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode &
VFE_OUTPUTS_RAW) {
if ((axi_ctrl->share_ctrl->outpath.out0.capture_cnt == 0)
&& (axi_ctrl->share_ctrl->outpath.out1.
@@ -5805,17 +6151,10 @@
CAMIF_COMMAND_STOP_IMMEDIATELY,
axi_ctrl->share_ctrl->vfebase +
VFE_CAMIF_COMMAND);
- spin_lock_irqsave(&axi_ctrl->share_ctrl->abort_lock,
- flags);
- if (axi_ctrl->share_ctrl->skip_abort) {
- spin_unlock_irqrestore(&axi_ctrl->share_ctrl->
- abort_lock, flags);
- atomic_set(&axi_ctrl->share_ctrl->
- handle_axi_irq, 0);
- axi_disable_irq(axi_ctrl);
- } else
- spin_unlock_irqrestore(&axi_ctrl->share_ctrl->
- abort_lock, flags);
+ axi_disable_irq(axi_ctrl->share_ctrl);
+ vfe32_send_isp_msg(&axi_ctrl->subdev,
+ axi_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_PIX0_UPDATE_ACK);
vfe32_send_isp_msg(&axi_ctrl->subdev,
axi_ctrl->share_ctrl->vfeFrameId,
MSG_ID_SNAPSHOT_DONE);
@@ -5893,6 +6232,29 @@
msm_axi_subdev_release(sd);
rc = 0;
break;
+ case VIDIOC_MSM_AXI_RDI_COUNT_UPDATE: {
+ struct rdi_count_msg *msg = (struct rdi_count_msg *)arg;
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ switch (msg->rdi_interface) {
+ case RDI_0:
+ axi_ctrl->share_ctrl->rdi0FrameId = msg->count;
+ rc = 0;
+ break;
+ case RDI_1:
+ axi_ctrl->share_ctrl->rdi1FrameId = msg->count;
+ rc = 0;
+ break;
+ case RDI_2:
+ axi_ctrl->share_ctrl->rdi2FrameId = msg->count;
+ rc = 0;
+ break;
+ default:
+ pr_err("%s: Incorrect interface sent\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ break;
+ }
default:
pr_err("%s: command %d not found\n", __func__,
_IOC_NR(cmd));
@@ -5953,7 +6315,7 @@
share_ctrl->vfe32_ctrl = vfe32_ctrl;
axi_ctrl->share_ctrl = share_ctrl;
vfe32_ctrl->share_ctrl = share_ctrl;
-
+ axi_ctrl->share_ctrl->axi_ref_cnt = 0;
v4l2_subdev_init(&axi_ctrl->subdev, &msm_axi_subdev_ops);
axi_ctrl->subdev.internal_ops = &msm_axi_internal_ops;
axi_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -6059,6 +6421,21 @@
goto vfe32_no_resource;
}
+#ifdef CONFIG_MSM_IOMMU
+ /*get device context for IOMMU*/
+ axi_ctrl->iommu_ctx_imgwr =
+ msm_iommu_get_ctx("vfe_imgwr"); /*re-confirm*/
+ axi_ctrl->iommu_ctx_misc =
+ msm_iommu_get_ctx("vfe_misc"); /*re-confirm*/
+ if (!axi_ctrl->iommu_ctx_imgwr || !axi_ctrl->iommu_ctx_misc) {
+ release_mem_region(axi_ctrl->vfemem->start,
+ resource_size(axi_ctrl->vfemem));
+ pr_err("%s: No iommu fw context found\n", __func__);
+ rc = -ENODEV;
+ goto vfe32_no_resource;
+ }
+#endif
+
tasklet_init(&axi_ctrl->vfe32_tasklet,
axi32_do_tasklet, (unsigned long)axi_ctrl);
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.h b/drivers/media/video/msm/vfe/msm_vfe32.h
index f4b7edb..985493e 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.h
+++ b/drivers/media/video/msm/vfe/msm_vfe32.h
@@ -62,6 +62,12 @@
* bit 26-32 = 0, domain reset, bit 0-9 = 1 for module reset. */
#define VFE_RESET_UPON_RESET_CMD 0x000003ff
+/* reset the vfe only when reset command*/
+#define VFE_ONLY_RESET_CMD 0x00000002
+
+/*Vfe module reset command*/
+#define VFE_MODULE_RESET_CMD 0x07ffffff
+
/* bit 5 is for axi status idle or busy.
* 1 = halted, 0 = busy */
#define AXI_STATUS_BUSY_MASK 0x00000020
@@ -244,11 +250,11 @@
#define V32_OUT_CLAMP_OFF 0x00000524
#define V32_OUT_CLAMP_LEN 8
-#define V32_OPERATION_CFG_LEN 44
+#define V32_OPERATION_CFG_LEN 32
#define V32_AXI_BUS_CMD_OFF 0x00000038
#define V32_AXI_OUT_OFF 0x0000003C
-#define V32_AXI_OUT_LEN 240
+#define V32_AXI_OUT_LEN 252
#define V32_AXI_CFG_LEN 47
#define V32_AXI_BUS_FMT_OFF 1
#define V32_AXI_BUS_FMT_LEN 4
@@ -787,7 +793,8 @@
#define VFE32_IMASK_ERROR_ONLY_0 0x0
/* when normal case, don't want to block error status. */
/* bit 0-21 are error irq bits */
-#define VFE32_IMASK_ERROR_ONLY_1 0x005FFFFF
+#define VFE32_IMASK_COMMON_ERROR_ONLY_1 0x00407F00
+#define VFE32_IMASK_VFE_ERROR_ONLY_1 0x001F80FF
#define VFE32_IMASK_CAMIF_ERROR (0x00000001<<0)
#define VFE32_IMASK_BHIST_OVWR (0x00000001<<1)
#define VFE32_IMASK_STATS_CS_OVWR (0x00000001<<2)
@@ -941,11 +948,14 @@
uint32_t register_total;
atomic_t vstate;
- atomic_t handle_axi_irq;
+ atomic_t handle_common_irq;
uint32_t vfeFrameId;
+ uint32_t rdi0FrameId;
+ uint32_t rdi1FrameId;
+ uint32_t rdi2FrameId;
uint32_t stats_comp;
+ spinlock_t sd_notify_lock;
spinlock_t stop_flag_lock;
- spinlock_t abort_lock;
int8_t stop_ack_pending;
enum vfe_output_state liveshot_state;
uint32_t vfe_capture_count;
@@ -955,8 +965,13 @@
struct vfe32_output_path outpath;
uint16_t port_info;
- uint32_t skip_abort;
- spinlock_t sd_notify_lock;
+ uint8_t stop_immediately;
+ uint8_t sync_abort;
+ uint16_t cmd_type;
+ uint8_t vfe_reset_flag;
+
+ uint8_t axi_ref_cnt;
+ uint16_t comp_output_mode;
struct completion reset_complete;
@@ -969,9 +984,11 @@
int8_t update_ack_pending;
enum vfe_output_state recording_state;
+ atomic_t pix0_update_ack_pending;
atomic_t rdi0_update_ack_pending;
atomic_t rdi1_update_ack_pending;
atomic_t rdi2_update_ack_pending;
+
};
struct axi_ctrl_t {
@@ -989,6 +1006,8 @@
struct clk *vfe_clk[3];
struct tasklet_struct vfe32_tasklet;
struct vfe_share_ctrl_t *share_ctrl;
+ struct device *iommu_ctx_imgwr;
+ struct device *iommu_ctx_misc;
};
struct vfe32_ctrl_type {
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index 5a1d488..875e034 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -364,19 +364,6 @@
msm_camera_io_w(*(++p),
vfe40_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
msm_camera_io_w(*(++p),
- vfe40_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
- if (msm_camera_io_r(vfe40_ctrl->share_ctrl->vfebase +
- V40_GET_HW_VERSION_OFF) ==
- VFE40_HW_NUMBER) {
- msm_camera_io_w(*(++p),
- vfe40_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
- msm_camera_io_w(*(++p),
- vfe40_ctrl->share_ctrl->vfebase + VFE_RDI2_CFG);
- } else {
- ++p;
- ++p;
- }
- msm_camera_io_w(*(++p),
vfe40_ctrl->share_ctrl->vfebase + VFE_REALIGN_BUF);
msm_camera_io_w(*(++p),
vfe40_ctrl->share_ctrl->vfebase + VFE_CHROMA_UP);
@@ -428,7 +415,7 @@
stats_buf = &bufq->bufs[i];
rc = vfe40_ctrl->stats_ops.enqueue_buf(
vfe40_ctrl->stats_ops.stats_ctrl,
- &(stats_buf->info), NULL);
+ &(stats_buf->info), NULL, -1);
if (rc < 0) {
pr_err("%s: dq stats buf (type = %d) err = %d",
__func__, stats_type, rc);
@@ -3321,7 +3308,7 @@
static long vfe_stats_bufq_sub_ioctl(
struct vfe40_ctrl_type *vfe_ctrl,
- struct msm_vfe_cfg_cmd *cmd, void *ion_client)
+ struct msm_vfe_cfg_cmd *cmd, void *ion_client, int domain_num)
{
long rc = 0;
switch (cmd->cmd_type) {
@@ -3370,7 +3357,7 @@
rc = vfe_ctrl->stats_ops.enqueue_buf(
&vfe_ctrl->stats_ctrl,
(struct msm_stats_buf_info *)cmd->value,
- vfe_ctrl->stats_ops.client);
+ vfe_ctrl->stats_ops.client, domain_num);
break;
case VFE_CMD_STATS_FLUSH_BUFQ:
{
@@ -3432,7 +3419,7 @@
case VFE_CMD_STATS_FLUSH_BUFQ:
/* for easy porting put in one envelope */
rc = vfe_stats_bufq_sub_ioctl(vfe40_ctrl,
- cmd, vfe_params->data);
+ cmd, vfe_params->data, pmctl->domain_num);
return rc;
default:
if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.h b/drivers/media/video/msm/vfe/msm_vfe40.h
index c8b0cb8..ab913e2 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.h
+++ b/drivers/media/video/msm/vfe/msm_vfe40.h
@@ -173,10 +173,10 @@
#define V40_OUT_CLAMP_OFF 0x00000874
#define V40_OUT_CLAMP_LEN 16
-#define V40_OPERATION_CFG_LEN 44
+#define V40_OPERATION_CFG_LEN 32
#define V40_AXI_OUT_OFF 0x0000004C
-#define V40_AXI_OUT_LEN 412
+#define V40_AXI_OUT_LEN 424
#define V40_AXI_CH_INF_LEN 32
#define V40_AXI_CFG_LEN 71
diff --git a/drivers/media/video/msm/vfe/msm_vfe40_axi.c b/drivers/media/video/msm/vfe/msm_vfe40_axi.c
index 35d5207..41d1cdd 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40_axi.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40_axi.c
@@ -193,6 +193,16 @@
msm_camera_io_memcpy(axi_ctrl->share_ctrl->vfebase +
vfe40_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
vfe40_cmd[VFE_CMD_AXI_OUT_CFG].length - V40_AXI_CH_INF_LEN);
+ msm_camera_io_w(*ch_info++,
+ axi_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
+ if (msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
+ V40_GET_HW_VERSION_OFF) ==
+ VFE40_HW_NUMBER) {
+ msm_camera_io_w(*ch_info++,
+ axi_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
+ msm_camera_io_w(*ch_info++,
+ axi_ctrl->share_ctrl->vfebase + VFE_RDI2_CFG);
+ }
return 0;
}
@@ -331,6 +341,8 @@
case CMD_AXI_STOP:
axi_stop(axi_ctrl);
break;
+ case CMD_AXI_RESET:
+ break;
default:
pr_err("%s Unsupported AXI configuration %x ", __func__,
cfgcmd.cmd_type);
diff --git a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
index e1d8b48..15c38af 100644
--- a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
@@ -360,7 +360,7 @@
rc = vfe2x_ctrl->stats_ops.dqbuf(vfe2x_ctrl->stats_ops.stats_ctrl,
stats_type, &buf);
if (rc < 0) {
- pr_err("%s: dq stats buf (type = %d) err = %d",
+ CDBG("%s: dq stats buf (type = %d) err = %d",
__func__, stats_type, rc);
return 0;
}
@@ -395,7 +395,7 @@
stats_buf = &bufq->bufs[i];
rc = vfe2x_ctrl->stats_ops.enqueue_buf(
vfe2x_ctrl->stats_ops.stats_ctrl,
- &(stats_buf->info), NULL);
+ &(stats_buf->info), NULL, -1);
if (rc < 0) {
pr_err("%s: dq stats buf (type = %d) err = %d",
__func__, stats_type, rc);
@@ -414,7 +414,7 @@
rc = vfe2x_ctrl->stats_ops.buf_unprepare(
vfe2x_ctrl->stats_ops.stats_ctrl,
req_buf->stats_type, i,
- vfe2x_ctrl->stats_ops.client);
+ vfe2x_ctrl->stats_ops.client, -1);
if (rc < 0) {
pr_err("%s: unreg stats buf (type = %d) err = %d",
__func__, req_buf->stats_type, rc);
@@ -473,7 +473,7 @@
stats_buf->state == MSM_STATS_BUFFER_STATE_PREPARED) {
rc = vfe2x_ctrl->stats_ops.enqueue_buf(
&vfe2x_ctrl->stats_ctrl,
- info, vfe2x_ctrl->stats_ops.client);
+ info, vfe2x_ctrl->stats_ops.client, -1);
if (rc < 0) {
pr_err("%s: enqueue_buf (type = %d), index : %d, err = %d",
__func__, info->type, info->buf_idx, rc);
@@ -555,7 +555,7 @@
rc = vfe2x_ctrl->stats_ops.enqueue_buf(
&vfe2x_ctrl->stats_ctrl,
(struct msm_stats_buf_info *)cmd->value,
- vfe2x_ctrl->stats_ops.client);
+ vfe2x_ctrl->stats_ops.client, -1);
}
break;
case VFE_CMD_STATS_FLUSH_BUFQ: {
@@ -696,7 +696,6 @@
switch (id) {
case MSG_SNAPSHOT:
- msm_camio_set_perf_lvl(S_PREVIEW);
while (vfe2x_ctrl->snap.frame_cnt <
vfe2x_ctrl->num_snap) {
vfe_7x_ops(driver_data, MSG_OUTPUT_S, len,
@@ -2353,7 +2352,7 @@
return 0;
}
-void msm_vpe_subdev_release(void)
+void msm_vpe_subdev_release(struct v4l2_subdev *sd)
{
return;
}
diff --git a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
index 5fbcdb1..a813e09 100644
--- a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
+++ b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
@@ -182,7 +182,8 @@
#endif
static int msm_stats_buf_prepare(struct msm_stats_bufq_ctrl *stats_ctrl,
- struct msm_stats_buf_info *info, struct ion_client *client)
+ struct msm_stats_buf_info *info, struct ion_client *client,
+ int domain_num)
{
unsigned long paddr;
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
@@ -219,7 +220,7 @@
goto out1;
}
if (ion_map_iommu(client, stats_buf->handle,
- CAMERA_DOMAIN, GEN_POOL, SZ_4K,
+ domain_num, 0, SZ_4K,
0, &paddr, &len, UNCACHED, 0) < 0) {
rc = -EINVAL;
pr_err("%s: cannot map address", __func__);
@@ -257,7 +258,7 @@
return 0;
out3:
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- ion_unmap_iommu(client, stats_buf->handle, CAMERA_DOMAIN, GEN_POOL);
+ ion_unmap_iommu(client, stats_buf->handle, domain_num, 0);
#endif
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
out2:
@@ -270,7 +271,7 @@
}
static int msm_stats_buf_unprepare(struct msm_stats_bufq_ctrl *stats_ctrl,
enum msm_stats_enum_type stats_type, int buf_idx,
- struct ion_client *client)
+ struct ion_client *client, int domain_num)
{
int rc = 0;
struct msm_stats_bufq *bufq = NULL;
@@ -292,7 +293,7 @@
}
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_unmap_iommu(client, stats_buf->handle,
- CAMERA_DOMAIN, GEN_POOL);
+ domain_num, 0);
ion_free(client, stats_buf->handle);
#else
put_pmem_file(stats_buf->file);
@@ -362,7 +363,7 @@
}
}
if (!(*pp_stats_buf)) {
- pr_err("%s: no free stats buf, type = %d",
+ D("%s: no free stats buf, type = %d",
__func__, stats_type);
rc = -1;
return rc;
@@ -472,12 +473,13 @@
return rc;
}
static int msm_stats_enqueue_buf(struct msm_stats_bufq_ctrl *stats_ctrl,
- struct msm_stats_buf_info *info, struct ion_client *client)
+ struct msm_stats_buf_info *info, struct ion_client *client,
+ int domain_num)
{
int rc = 0;
D("%s: stats type : %d, idx : %d\n", __func__,
info->type, info->buf_idx);
- rc = msm_stats_buf_prepare(stats_ctrl, info, client);
+ rc = msm_stats_buf_prepare(stats_ctrl, info, client, domain_num);
if (rc < 0) {
pr_err("%s: buf_prepare failed, rc = %d", __func__, rc);
return -EINVAL;
diff --git a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.h b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.h
index 18fd425..bf3e70e 100644
--- a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.h
+++ b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.h
@@ -55,8 +55,8 @@
struct msm_stats_bufq_ctrl *stats_ctrl;
struct ion_client *client;
int (*enqueue_buf) (struct msm_stats_bufq_ctrl *stats_ctrl,
- struct msm_stats_buf_info *info,
- struct ion_client *client);
+ struct msm_stats_buf_info *info,
+ struct ion_client *client, int domain_num);
int (*qbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
enum msm_stats_enum_type stats_type,
int buf_idx);
@@ -69,10 +69,10 @@
int (*buf_unprepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
enum msm_stats_enum_type stats_type,
int buf_idx,
- struct ion_client *client);
+ struct ion_client *client, int domain_num);
int (*buf_prepare) (struct msm_stats_bufq_ctrl *stats_ctrl,
- struct msm_stats_buf_info *info,
- struct ion_client *client);
+ struct msm_stats_buf_info *info,
+ struct ion_client *client, int domain_num);
int (*reqbuf) (struct msm_stats_bufq_ctrl *stats_ctrl,
struct msm_stats_reqbuf *reqbuf,
struct ion_client *client);
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index ff12a5c..b7b12cb 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -26,7 +26,6 @@
unsigned long *buffer_size, unsigned long flags)
{
int rc;
-
if (!iova || !buffer_size || !hndl || !clnt) {
pr_err("Invalid params: %p, %p, %p, %p\n",
clnt, hndl, iova, buffer_size);
@@ -34,9 +33,10 @@
}
if (align < 4096)
align = 4096;
- flags |= UNCACHED;
+ pr_debug("\n In %s domain: %d, Partition: %d\n",
+ __func__, domain_num, partition_num);
rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
- 0, iova, buffer_size, flags, 0);
+ 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);
@@ -45,9 +45,9 @@
}
static void put_device_address(struct ion_client *clnt,
- struct ion_handle *hndl, int domain_num)
+ struct ion_handle *hndl, int domain_num, int partition_num)
{
- ion_unmap_iommu(clnt, hndl, domain_num, 0);
+ ion_unmap_iommu(clnt, hndl, domain_num, partition_num);
}
static int ion_user_to_kernel(struct smem_client *client,
@@ -71,26 +71,22 @@
pr_err("Failed to get ion flags: %d", rc);
goto fail_map;
}
- mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
- if (!mem->kvaddr) {
- pr_err("Failed to map shared mem in kernel\n");
- rc = -EIO;
- goto fail_map;
- }
+ mem->kvaddr = NULL;
mem->domain = domain;
mem->partition_num = partition;
rc = get_device_address(client->clnt, hndl, mem->domain,
- mem->partition_num, 4096, &iova, &buffer_size, UNCACHED);
+ mem->partition_num, 4096, &iova, &buffer_size, ionflag);
if (rc) {
pr_err("Failed to get device address: %d\n", rc);
goto fail_device_address;
}
- mem->kvaddr += offset;
mem->mem_type = client->mem_type;
mem->smem_priv = hndl;
- mem->device_addr = iova + offset;
+ mem->device_addr = iova;
mem->size = buffer_size;
+ pr_err("NOTE: Buffer device address: 0x%lx, size: %d\n",
+ mem->device_addr, mem->size);
return rc;
fail_device_address:
ion_unmap_kernel(client->clnt, hndl);
@@ -102,20 +98,28 @@
static int alloc_ion_mem(struct smem_client *client, size_t size,
u32 align, u32 flags, int domain, int partition,
- struct msm_smem *mem)
+ struct msm_smem *mem, int map_kernel)
{
struct ion_handle *hndl;
unsigned long iova = 0;
unsigned long buffer_size = 0;
+ unsigned long ionflags = 0;
int rc = 0;
- flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
+ if (flags == SMEM_CACHED)
+ ionflags |= ION_SET_CACHE(CACHED);
+ else
+ ionflags |= ION_SET_CACHE(UNCACHED);
+
+ ionflags = ionflags | ION_HEAP(ION_CP_MM_HEAP_ID);
if (align < 4096)
align = 4096;
size = (size + 4095) & (~4095);
- hndl = ion_alloc(client->clnt, size, align, flags);
+ pr_debug("\n in %s domain: %d, Partition: %d\n",
+ __func__, 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%x\n",
- client, size, align, flags);
+ pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%lx\n",
+ client, size, align, ionflags);
rc = -ENOMEM;
goto fail_shared_mem_alloc;
}
@@ -123,12 +127,16 @@
mem->smem_priv = hndl;
mem->domain = domain;
mem->partition_num = partition;
- mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
- if (!mem->kvaddr) {
- pr_err("Failed to map shared mem in kernel\n");
- rc = -EIO;
- goto fail_map;
- }
+ 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");
+ rc = -EIO;
+ goto fail_map;
+ }
+ } else
+ mem->kvaddr = NULL;
+
rc = get_device_address(client->clnt, hndl, mem->domain,
mem->partition_num, align, &iova, &buffer_size, UNCACHED);
if (rc) {
@@ -136,8 +144,8 @@
goto fail_device_address;
}
mem->device_addr = iova;
- pr_err("device_address = 0x%lx, kvaddr = 0x%p\n",
- mem->device_addr, mem->kvaddr);
+ pr_err("NOTE: device_address = 0x%lx, kvaddr = 0x%p, size = %d\n",
+ mem->device_addr, mem->kvaddr, size);
mem->size = size;
return rc;
fail_device_address:
@@ -150,10 +158,13 @@
static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
{
- put_device_address(client->clnt,
- mem->smem_priv, mem->domain);
- ion_unmap_kernel(client->clnt, mem->smem_priv);
- ion_free(client->clnt, mem->smem_priv);
+ if (mem->device_addr)
+ put_device_address(client->clnt,
+ mem->smem_priv, mem->domain, mem->partition_num);
+ if (mem->kvaddr)
+ ion_unmap_kernel(client->clnt, mem->smem_priv);
+ if (mem->smem_priv)
+ ion_free(client->clnt, mem->smem_priv);
}
static void *ion_new_client(void)
@@ -203,6 +214,36 @@
return mem;
}
+static int ion_mem_clean_invalidate(struct smem_client *clt,
+ struct msm_smem *mem)
+{
+ /*
+ * Note: We're always mapping into iommu as uncached
+ * as a result we don't need to flush/clean anything
+ */
+ return 0;
+}
+
+int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem)
+{
+ struct smem_client *client = clt;
+ int rc;
+ if (!client || !mem) {
+ pr_err("Invalid client/handle passed\n");
+ return -EINVAL;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ rc = ion_mem_clean_invalidate(client, mem);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
void *msm_smem_new_client(enum smem_type mtype)
{
struct smem_client *client = NULL;
@@ -228,7 +269,7 @@
};
struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
- int domain, int partition)
+ int domain, int partition, int map_kernel)
{
struct smem_client *client;
int rc = 0;
@@ -250,7 +291,7 @@
switch (client->mem_type) {
case SMEM_ION:
rc = alloc_ion_mem(client, size, align, flags,
- domain, partition, mem);
+ domain, partition, mem, map_kernel);
break;
default:
pr_err("Mem type not supported\n");
diff --git a/drivers/media/video/msm_vidc/msm_smem.h b/drivers/media/video/msm_vidc/msm_smem.h
index b742c79..37816e1 100644
--- a/drivers/media/video/msm_vidc/msm_smem.h
+++ b/drivers/media/video/msm_vidc/msm_smem.h
@@ -20,6 +20,11 @@
SMEM_ION,
};
+enum smem_cache_prop {
+ SMEM_CACHED,
+ SMEM_UNCACHED,
+};
+
struct msm_smem {
int mem_type;
size_t size;
@@ -32,9 +37,10 @@
void *msm_smem_new_client(enum smem_type mtype);
struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
- int domain, int partition);
+ int domain, int partition, int map_kernel);
void msm_smem_free(void *clt, struct msm_smem *mem);
void msm_smem_delete_client(void *clt);
struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, int
domain, int partition);
+int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
#endif
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index cf1ebbb..4e810dc 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -31,6 +31,7 @@
#define BASE_DEVICE_NUMBER 32
#define MAX_EVENTS 30
+#define SHARED_QSIZE 0x1000000
static struct msm_bus_vectors ocmem_init_vectors[] = {
@@ -164,6 +165,7 @@
int buff_off;
int size;
u32 uvaddr;
+ u32 device_addr;
struct msm_smem *handle;
};
@@ -229,6 +231,28 @@
return ret;
}
+struct buffer_info *get_same_fd_buffer(struct list_head *list,
+ int fd)
+{
+ struct buffer_info *temp;
+ struct buffer_info *ret = NULL;
+ if (!list || fd < 0) {
+ pr_err("%s Invalid input\n", __func__);
+ 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");
+ ret = temp;
+ break;
+ }
+ }
+ }
+err_invalid_input:
+ return ret;
+}
+
static int msm_v4l2_open(struct file *filp)
{
int rc = 0;
@@ -361,8 +385,9 @@
rc = msm_vidc_release_buf(&v4l2_inst->vidc_inst,
&buffer_info);
list_del(&bi->list);
- msm_smem_free(v4l2_inst->mem_client,
- bi->handle);
+ if (bi->handle)
+ msm_smem_free(v4l2_inst->mem_client,
+ bi->handle);
kfree(bi);
}
}
@@ -373,8 +398,9 @@
int msm_v4l2_prepare_buf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
- struct msm_smem *handle;
+ struct msm_smem *handle = NULL;
struct buffer_info *binfo;
+ struct buffer_info *temp;
struct msm_vidc_inst *vidc_inst;
struct msm_v4l2_vid_inst *v4l2_inst;
int i, rc = 0;
@@ -401,28 +427,43 @@
rc = -ENOMEM;
goto exit;
}
- handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
+ temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
+ b->m.planes[i].reserved[0]);
+ if (temp) {
+ binfo->type = b->type;
+ binfo->fd = b->m.planes[i].reserved[0];
+ binfo->buff_off = b->m.planes[i].reserved[1];
+ binfo->size = b->m.planes[i].length;
+ binfo->uvaddr = b->m.planes[i].m.userptr;
+ binfo->device_addr =
+ temp->handle->device_addr + binfo->buff_off;
+ binfo->handle = NULL;
+ } else {
+ handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
b->m.planes[i].reserved[0],
b->m.planes[i].reserved[1],
vidc_inst->core->resources.io_map[NS_MAP].domain,
0);
- if (!handle) {
- pr_err("Failed to get device buffer address\n");
- kfree(binfo);
- goto exit;
+ if (!handle) {
+ pr_err("Failed to get device buffer address\n");
+ kfree(binfo);
+ goto exit;
+ }
+ binfo->type = b->type;
+ binfo->fd = b->m.planes[i].reserved[0];
+ binfo->buff_off = b->m.planes[i].reserved[1];
+ binfo->size = b->m.planes[i].length;
+ binfo->uvaddr = b->m.planes[i].m.userptr;
+ binfo->device_addr =
+ handle->device_addr + binfo->buff_off;
+ binfo->handle = handle;
+ pr_debug("Registering buffer: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
}
- binfo->type = b->type;
- binfo->fd = b->m.planes[i].reserved[0];
- binfo->buff_off = b->m.planes[i].reserved[1];
- binfo->size = b->m.planes[i].length;
- binfo->uvaddr = b->m.planes[i].m.userptr;
- binfo->handle = handle;
- pr_debug("Registering buffer: %d, %d, %d\n",
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length);
list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
- b->m.planes[i].m.userptr = handle->device_addr;
+ b->m.planes[i].m.userptr = binfo->device_addr;
}
rc = msm_vidc_prepare_buf(&v4l2_inst->vidc_inst, b);
exit:
@@ -452,9 +493,17 @@
rc = -EINVAL;
goto err_invalid_buff;
}
- b->m.planes[i].m.userptr = binfo->handle->device_addr;
- pr_debug("Queueing device address = %ld\n",
- binfo->handle->device_addr);
+ b->m.planes[i].m.userptr = binfo->device_addr;
+ pr_debug("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);
+ goto err_invalid_buff;
+ }
+ }
}
rc = msm_vidc_qbuf(&v4l2_inst->vidc_inst, b);
err_invalid_buff:
@@ -505,6 +554,13 @@
return msm_vidc_decoder_cmd((void *)vidc_inst, dec);
}
+static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
+ struct v4l2_encoder_cmd *enc)
+{
+ struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ return msm_vidc_encoder_cmd((void *)vidc_inst, enc);
+}
+
static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
.vidioc_querycap = msm_v4l2_querycap,
.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
@@ -524,6 +580,7 @@
.vidioc_subscribe_event = msm_v4l2_subscribe_event,
.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
+ .vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
};
static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
@@ -583,7 +640,7 @@
struct msm_vidc_core *core)
{
size_t len;
- struct msm_iova_partition partition;
+ struct msm_iova_partition partition[2];
struct msm_iova_layout layout;
int rc = 0;
int i;
@@ -606,14 +663,28 @@
rc = -EINVAL;
break;
}
- partition.start = io_map[i].addr_range[0];
- partition.size = io_map[i].addr_range[1];
- layout.partitions = &partition;
- layout.npartitions = 1;
+ partition[0].start = io_map[i].addr_range[0];
+ if (i == NS_MAP) {
+ partition[0].size =
+ io_map[i].addr_range[1] - SHARED_QSIZE;
+ partition[1].start =
+ partition[0].start + io_map[i].addr_range[1]
+ - SHARED_QSIZE;
+ partition[1].size = SHARED_QSIZE;
+ layout.npartitions = 2;
+ } else {
+ partition[0].size = io_map[i].addr_range[1];
+ layout.npartitions = 1;
+ }
+ layout.partitions = &partition[0];
layout.client_name = io_map[i].name;
layout.domain_flags = 0;
- pr_debug("Registering domain with: %lx, %lx, %s\n",
- partition.start, partition.size, layout.client_name);
+ pr_debug("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",
+ 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");
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index c87211a..cae486f 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -156,11 +156,23 @@
static u32 get_frame_size_nv12(int plane,
u32 height, u32 width)
{
- int luma_stride = ALIGN(width, 32);
- int luma_slice = ALIGN(height, 32);
- int chroma_stride = ALIGN(roundup(width, 2)/2, 32);
- int chroma_slice = ALIGN(roundup(height, 2)/2, 32);
- return (luma_stride * luma_slice) + (chroma_stride * chroma_slice) * 2;
+ int size;
+ int luma_h, luma_w, luma_stride, luma_scanl, luma_size;
+ int chroma_h, chroma_w, chroma_stride, chroma_scanl, chroma_size;
+
+ luma_w = width;
+ luma_h = height;
+
+ chroma_w = luma_w;
+ chroma_h = luma_h/2;
+ NV12_IL_CALC_Y_STRIDE(luma_stride, luma_w, 32);
+ NV12_IL_CALC_Y_BUFHEIGHT(luma_scanl, luma_h, 32);
+ NV12_IL_CALC_UV_STRIDE(chroma_stride, chroma_w, 32);
+ NV12_IL_CALC_UV_BUFHEIGHT(chroma_scanl, luma_h, 32);
+ NV12_IL_CALC_BUF_SIZE(size, luma_size, luma_stride,
+ luma_scanl, chroma_size, chroma_stride, chroma_scanl, 32);
+ size = ALIGN(size, SZ_4K);
+ return size;
}
static u32 get_frame_size_nv21(int plane,
u32 height, u32 width)
@@ -312,9 +324,9 @@
if (!inst->extradata_handle) {
inst->extradata_handle =
msm_smem_alloc(inst->mem_client,
- 4096 * 1024, 1, 0,
+ 4096 * 1024, 1, SMEM_UNCACHED,
inst->core->resources.io_map[NS_MAP].domain,
- 0);
+ 0, 0);
if (!inst->extradata_handle) {
pr_err("Failed to allocate extradta memory\n");
rc = -ENOMEM;
@@ -469,8 +481,8 @@
return -EINVAL;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- inst->prop.width = f->fmt.pix_mp.width;
- inst->prop.height = f->fmt.pix_mp.height;
+ struct hal_frame_size frame_sz;
+
fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
CAPTURE_PORT);
@@ -480,6 +492,21 @@
rc = -EINVAL;
goto err_invalid_fmt;
}
+
+ inst->prop.width = f->fmt.pix_mp.width;
+ inst->prop.height = f->fmt.pix_mp.height;
+
+ 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);
+ 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");
+ goto err_invalid_fmt;
+ }
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
@@ -570,7 +597,6 @@
{
int i, rc = 0;
struct msm_vidc_inst *inst;
- struct hal_frame_size frame_sz;
unsigned long flags;
if (!q || !q->drv_priv) {
pr_err("Invalid input, q = %p\n", q);
@@ -595,27 +621,42 @@
pr_err("Failed to open instance\n");
break;
}
- 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);
- 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");
- break;
- }
+
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
pr_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[1].buffer_count_actual;
+ if (*num_buffers && *num_buffers >
+ inst->buff_req.buffer[HAL_BUFFER_OUTPUT].
+ buffer_count_actual) {
+ struct hal_buffer_count_actual new_buf_count;
+ enum hal_property property_id =
+ HAL_PARAM_BUFFER_COUNT_ACTUAL;
+
+ new_buf_count.buffer_type = HAL_BUFFER_OUTPUT;
+ new_buf_count.buffer_count_actual = *num_buffers;
+ rc = vidc_hal_session_set_property(inst->session,
+ property_id, &new_buf_count);
+
+ spin_unlock_irqrestore(&inst->lock, flags);
+ if (!rc && msm_comm_try_get_bufreqs(inst)) {
+ /* We are allowed to reject clients' request for
+ * more buffers and suggest our own bufreq */
+ pr_warn("Unable to increase the number of output buffers to %d\n",
+ *num_buffers);
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ }
+ *num_buffers = inst->buff_req.buffer[HAL_BUFFER_OUTPUT].
+ buffer_count_actual;
spin_unlock_irqrestore(&inst->lock, flags);
- pr_debug("size = %d, alignment = %d\n",
+
+ pr_debug("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);
for (i = 0; i < *num_planes; i++) {
@@ -648,6 +689,11 @@
pr_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);
+ goto fail_start;
+ }
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
pr_err("Failed to move inst: %p to start done state\n",
@@ -717,11 +763,13 @@
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
- rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ rc = msm_comm_try_state(inst,
+ MSM_VIDC_RELEASE_RESOURCES_DONE);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
- rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ rc = msm_comm_try_state(inst,
+ MSM_VIDC_RELEASE_RESOURCES_DONE);
break;
default:
pr_err("Q-type is not supported: %d\n", q->type);
@@ -730,7 +778,7 @@
}
if (rc)
pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
- inst, q->type, MSM_VIDC_CLOSE_DONE);
+ inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
return rc;
}
@@ -742,6 +790,74 @@
pr_err("Failed to queue buffer: %d\n", rc);
}
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec)
+{
+ int rc = 0;
+ bool ip_flush = false,
+ op_flush = false;
+
+ switch (dec->cmd) {
+ case V4L2_DEC_QCOM_CMD_FLUSH:
+ mutex_lock(&inst->sync_lock);
+ ip_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
+ op_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
+ /* Only support flush on decoder (for now)*/
+ if (inst->session_type == MSM_VIDC_ENCODER) {
+ pr_err("Buffer flushing not supported for encoder\n");
+ rc = -ENOTSUPP;
+ mutex_unlock(&inst->sync_lock);
+ break;
+ }
+
+ /* Certain types of flushes aren't supported such as: */
+ /* 1) Input only flush */
+ if (ip_flush && !op_flush) {
+ pr_err("Input only flush not supported\n");
+ rc = -ENOTSUPP;
+ mutex_unlock(&inst->sync_lock);
+ break;
+ }
+
+ /* 2) Output only flush when in reconfig */
+ if (!ip_flush && op_flush && !inst->in_reconfig) {
+ pr_err("Output only flush only supported when reconfiguring\n");
+ rc = -ENOTSUPP;
+ mutex_unlock(&inst->sync_lock);
+ break;
+ }
+
+ /* Finally flush */
+ if (op_flush && ip_flush)
+ rc = vidc_hal_session_flush(inst->session,
+ HAL_FLUSH_ALL);
+ else if (ip_flush)
+ rc = vidc_hal_session_flush(inst->session,
+ HAL_FLUSH_INPUT);
+ else if (op_flush)
+ rc = vidc_hal_session_flush(inst->session,
+ HAL_FLUSH_OUTPUT);
+ mutex_unlock(&inst->sync_lock);
+ break;
+ case V4L2_DEC_CMD_STOP:
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ if (rc)
+ pr_err("Failed to close instance\n");
+ break;
+ default:
+ pr_err("Unknown Decoder Command\n");
+ rc = -ENOTSUPP;
+ goto exit;
+ }
+
+ if (rc) {
+ pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
+ goto exit;
+ }
+exit:
+ return rc;
+}
+
+
static const struct vb2_ops msm_vdec_vb2q_ops = {
.queue_setup = msm_vdec_queue_setup,
.start_streaming = msm_vdec_start_streaming,
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
index 1242fb4..b8326d8 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.h
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -31,6 +31,7 @@
int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_cmd(struct msm_vidc_inst *inst, struct v4l2_decoder_cmd *dec);
struct vb2_ops *msm_vdec_get_vb2q_ops(void);
#endif
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index 14baf79..74f1415 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -22,13 +22,13 @@
#define DEFAULT_WIDTH 1280
#define MIN_NUM_OUTPUT_BUFFERS 2
#define MAX_NUM_OUTPUT_BUFFERS 8
-#define MIN_BIT_RATE 64
-#define MAX_BIT_RATE 160000
-#define DEFAULT_BIT_RATE 64
-#define BIT_RATE_STEP 1
-#define MIN_FRAME_RATE 1
-#define MAX_FRAME_RATE 240
-#define DEFAULT_FRAME_RATE 30
+#define MIN_BIT_RATE 64000
+#define MAX_BIT_RATE 160000000
+#define DEFAULT_BIT_RATE 64000
+#define BIT_RATE_STEP 100
+#define MIN_FRAME_RATE 65536
+#define MAX_FRAME_RATE 15728640
+#define DEFAULT_FRAME_RATE 1966080
#define DEFAULT_IR_MBS 30
#define MAX_SLICE_BYTE_SIZE 1024
#define MIN_SLICE_BYTE_SIZE 1024
@@ -449,7 +449,23 @@
static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
{
- return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
+ int size;
+ int luma_h, luma_w, luma_stride, luma_scanl, luma_size;
+ int chroma_h, chroma_w, chroma_stride, chroma_scanl, chroma_size;
+
+ luma_w = width;
+ luma_h = height;
+
+ chroma_w = luma_w;
+ chroma_h = luma_h/2;
+ NV12_IL_CALC_Y_STRIDE(luma_stride, luma_w, 32);
+ NV12_IL_CALC_Y_BUFHEIGHT(luma_scanl, luma_h, 32);
+ NV12_IL_CALC_UV_STRIDE(chroma_stride, chroma_w, 32);
+ NV12_IL_CALC_UV_BUFHEIGHT(chroma_scanl, luma_h, 32);
+ NV12_IL_CALC_BUF_SIZE(size, luma_size, luma_stride,
+ luma_scanl, chroma_size, chroma_stride, chroma_scanl, 32);
+ size = ALIGN(size, SZ_4K);
+ return size;
}
static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
@@ -560,7 +576,7 @@
*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
for (i = 0; i < *num_planes; i++) {
- sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+ sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
i, inst->prop.height, inst->prop.width);
}
break;
@@ -602,7 +618,7 @@
inst->buff_req.buffer[0].buffer_alignment,
inst->buff_req.buffer[0].buffer_count_actual);
for (i = 0; i < *num_planes; i++) {
- sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+ sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
i, inst->prop.height, inst->prop.width);
}
@@ -621,11 +637,21 @@
unsigned long flags;
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ pr_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);
goto fail_start;
}
+ rc = msm_comm_set_persist_buffers(inst);
+ if (rc) {
+ pr_err("Failed to set persist buffers: %d\n", rc);
+ goto fail_start;
+ }
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
pr_err("Failed to move inst: %p to start done state\n",
@@ -696,7 +722,7 @@
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
break;
default:
pr_err("Q-type is not supported: %d\n", q->type);
@@ -752,7 +778,12 @@
void *pdata;
struct msm_vidc_inst *inst = container_of(ctrl->handler,
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);
+ goto failed_open_done;
+ }
control.id = ctrl->id;
control.value = ctrl->val;
@@ -1172,6 +1203,7 @@
}
if (rc)
pr_err("Failed to set hal property for framesize\n");
+failed_open_done:
return rc;
}
static int msm_venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -1214,6 +1246,15 @@
return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
}
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc)
+{
+ int rc = 0;
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ if (rc)
+ pr_err("Failed to close instance\n");
+ return rc;
+}
+
int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
{
if (!inst || !cap) {
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
index 4a156dd..83610b3 100644
--- a/drivers/media/video/msm_vidc/msm_venc.h
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -30,6 +30,7 @@
int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_cmd(struct msm_vidc_inst *inst, struct v4l2_encoder_cmd *enc);
struct vb2_ops *msm_venc_get_vb2q_ops(void);
#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index 4d4cec5..7c9b6db 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -29,11 +29,6 @@
struct vb2_buffer *out_vb = NULL;
struct vb2_buffer *cap_vb = NULL;
unsigned long flags;
- if (!outq->streaming && !capq->streaming) {
- pr_err("Returning POLLERR from here: %d, %d\n",
- outq->streaming, capq->streaming);
- return POLLERR;
- }
poll_wait(filp, &inst->event_handler.wait, wait);
poll_wait(filp, &capq->done_wq, wait);
poll_wait(filp, &outq->done_wq, wait);
@@ -140,6 +135,22 @@
return -EINVAL;
}
+int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_cmd(instance, enc);
+ return -EINVAL;
+}
+
+int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_cmd(instance, dec);
+ return -EINVAL;
+}
+
int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
{
struct msm_vidc_inst *inst = instance;
@@ -243,6 +254,7 @@
inst->session_type = session_type;
INIT_LIST_HEAD(&inst->pendingq);
INIT_LIST_HEAD(&inst->internalbufs);
+ INIT_LIST_HEAD(&inst->persistbufs);
inst->state = MSM_VIDC_CORE_UNINIT_DONE;
inst->core = core;
for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
@@ -316,6 +328,15 @@
kfree(buf);
}
}
+ if (!list_empty(&inst->persistbufs)) {
+ list_for_each_safe(ptr, next, &inst->persistbufs) {
+ buf = list_entry(ptr, struct internal_buf,
+ list);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ }
if (inst->extradata_handle)
msm_smem_free(inst->mem_client, inst->extradata_handle);
spin_unlock_irqrestore(&inst->lock, flags);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index b07c63b..b6dce2c 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/iommu.h>
+#include <asm/div64.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
#include <mach/peripheral-loader.h>
@@ -22,7 +23,7 @@
#include "vidc_hal_api.h"
#include "msm_smem.h"
-#define HW_RESPONSE_TIMEOUT 5000
+#define HW_RESPONSE_TIMEOUT (5 * 60 * 1000)
#define IS_ALREADY_IN_STATE(__p, __d) ({\
int __rc = (__p >= __d);\
@@ -430,6 +431,7 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
unsigned long flags;
+ int i;
if (!response || !response->data) {
pr_err("Failed to get valid response for prop info\n");
return;
@@ -439,6 +441,12 @@
memcpy(&inst->buff_req, response->data,
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",
+ inst->buff_req.buffer[i].buffer_type,
+ inst->buff_req.buffer[i].buffer_count_actual,
+ inst->buff_req.buffer[i].buffer_size);
+ }
signal_session_msg_receipt(cmd, inst);
}
@@ -572,9 +580,41 @@
(u32)fill_buf_done->packet_buffer1);
if (vb) {
vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
- pr_debug("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
+
+ if (!(fill_buf_done->flags1 &
+ HAL_BUFFERFLAG_TIMESTAMPINVALID)) {
+ int64_t time_usec = fill_buf_done->timestamp_hi;
+ time_usec = (time_usec << 32) |
+ fill_buf_done->timestamp_lo;
+
+ vb->v4l2_buf.timestamp =
+ ns_to_timeval(time_usec * NSEC_PER_USEC);
+ }
+
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+
+ switch (fill_buf_done->picture_type) {
+ case HAL_PICTURE_IDR:
+ case HAL_PICTURE_I:
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case HAL_PICTURE_P:
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+ break;
+ case HAL_PICTURE_B:
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME;
+ break;
+ case HAL_FRAME_NOTCODED:
+ case HAL_UNUSED_PICT:
+ /* Do we need to care about these? */
+ case HAL_FRAME_YUV:
+ break;
+ }
+
+ pr_debug("Filled length = %d; flags %x\n",
+ vb->v4l2_planes[0].bytesused,
+ vb->v4l2_buf.flags);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
} else {
/*
@@ -1352,11 +1392,14 @@
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;
frame_data.device_addr = vb->v4l2_planes[0].m.userptr;
- frame_data.timestamp = vb->v4l2_buf.timestamp.tv_usec;
+ frame_data.timestamp = time_usec;
frame_data.clnt_data = (u32)vb;
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
frame_data.buffer_type = HAL_BUFFER_INPUT;
@@ -1421,67 +1464,6 @@
return rc;
}
-int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
-{
- int rc = 0;
- struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance;
- bool ip_flush = false,
- op_flush = false;
-
- mutex_lock(&inst->sync_lock);
-
- switch (dec->cmd) {
- case V4L2_DEC_QCOM_CMD_FLUSH:
- ip_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT;
- op_flush = dec->flags & V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE;
- /* Only support flush on decoder (for now)*/
- if (inst->session_type == MSM_VIDC_ENCODER) {
- pr_err("Buffer flushing not supported for encoder\n");
- rc = -ENOTSUPP;
- break;
- }
-
- /* Certain types of flushes aren't supported such as: */
- /* 1) Input only flush */
- if (ip_flush && !op_flush) {
- pr_err("Input only flush not supported\n");
- rc = -ENOTSUPP;
- break;
- }
-
- /* 2) Output only flush when in reconfig */
- if (!ip_flush && op_flush && !inst->in_reconfig) {
- pr_err("Output only flush only supported when reconfiguring\n");
- rc = -ENOTSUPP;
- break;
- }
-
- /* Finally flush */
- if (op_flush && ip_flush)
- rc = vidc_hal_session_flush(inst->session,
- HAL_FLUSH_ALL);
- else if (ip_flush)
- rc = vidc_hal_session_flush(inst->session,
- HAL_FLUSH_INPUT);
- else if (op_flush)
- rc = vidc_hal_session_flush(inst->session,
- HAL_FLUSH_OUTPUT);
-
- break;
- default:
- rc = -ENOTSUPP;
- goto exit;
- }
-
- if (rc) {
- pr_err("Failed to exec decoder cmd %d\n", dec->cmd);
- goto exit;
- }
-exit:
- mutex_unlock(&inst->sync_lock);
- return rc;
-}
-
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
@@ -1512,8 +1494,9 @@
for (i = 0; i < scratch_buf->buffer_count_actual;
i++) {
handle = msm_smem_alloc(inst->mem_client,
- scratch_buf->buffer_size, 1, 0,
- inst->core->resources.io_map[NS_MAP].domain, 0);
+ scratch_buf->buffer_size, 1, SMEM_UNCACHED,
+ inst->core->resources.io_map[NS_MAP].domain,
+ 0, 0);
if (!handle) {
pr_err("Failed to allocate scratch memory\n");
rc = -ENOMEM;
@@ -1549,3 +1532,63 @@
err_no_mem:
return rc;
}
+
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_smem *handle;
+ struct internal_buf *binfo;
+ struct vidc_buffer_addr_info buffer_info;
+ unsigned long flags;
+ struct hal_buffer_requirements *persist_buf =
+ &inst->buff_req.buffer[HAL_BUFFER_INTERNAL_PERSIST];
+ int i;
+ pr_debug("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");
+ return rc;
+ }
+
+ if (persist_buf->buffer_size) {
+ for (i = 0; i < persist_buf->buffer_count_actual; i++) {
+ handle = msm_smem_alloc(inst->mem_client,
+ persist_buf->buffer_size, 1, SMEM_UNCACHED,
+ inst->core->resources.io_map[NS_MAP].domain,
+ 0, 0);
+ if (!handle) {
+ pr_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");
+ rc = -ENOMEM;
+ goto fail_kzalloc;
+ }
+ binfo->handle = handle;
+ buffer_info.buffer_size = persist_buf->buffer_size;
+ buffer_info.buffer_type = HAL_BUFFER_INTERNAL_PERSIST;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ rc = vidc_hal_session_set_buffers(
+ (void *) inst->session, &buffer_info);
+ if (rc) {
+ pr_err("vidc_hal_session_set_buffers failed");
+ goto fail_set_buffers;
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&binfo->list, &inst->persistbufs);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ }
+ }
+ return rc;
+fail_set_buffers:
+ kfree(binfo);
+fail_kzalloc:
+ msm_smem_free(inst->mem_client, handle);
+err_no_mem:
+ return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 2009ca6..9430d5f 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -28,6 +28,7 @@
int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct vb2_buffer *vb);
int msm_comm_scale_clocks(struct msm_vidc_core *core);
#define IS_PRIV_CTRL(idx) (\
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 8c11de8..d01b1d1 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -47,6 +47,32 @@
#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
#define MAX_NAME_LENGTH 64
+
+#define NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \
+ { stride = (frame_width + stride_multiple - 1) & \
+ (0xffffffff - (stride_multiple - 1)); }
+
+#define NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height,\
+ min_buf_height_multiple) \
+ { buf_height = (frame_height + min_buf_height_multiple - 1) & \
+ (0xffffffff - (min_buf_height_multiple - 1)); }
+
+#define NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \
+ { stride = ((((frame_width + 1) >> 1) + stride_multiple - 1) & \
+ (0xffffffff - (stride_multiple - 1))) << 1; }
+
+#define NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height,\
+ min_buf_height_multiple) \
+ { buf_height = ((((frame_height + 1) >> 1) + \
+ min_buf_height_multiple - 1) & (0xffffffff - \
+ (min_buf_height_multiple - 1))); }
+
+#define NV12_IL_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride, \
+ y_buf_height, uv_buf_size, uv_stride, uv_buf_height, uv_alignment) \
+ { y_buf_size = (y_stride * y_buf_height); \
+ uv_buf_size = (uv_stride * uv_buf_height) + uv_alignment; \
+ buf_size = y_buf_size + uv_buf_size; }
+
enum vidc_ports {
OUTPUT_PORT,
CAPTURE_PORT,
@@ -207,6 +233,7 @@
spinlock_t lock;
struct list_head pendingq;
struct list_head internalbufs;
+ struct list_head persistbufs;
struct buffer_requirements buff_req;
void *mem_client;
struct v4l2_ctrl_handler ctrl_handler;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 16a3ecd..2021ec6 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -308,6 +308,7 @@
{
struct vidc_mem_addr *vmem;
struct msm_smem *alloc;
+ int rc = 0;
if (!mem || !clnt || !size) {
HAL_MSG_ERROR("Invalid Params in %s", __func__);
@@ -316,20 +317,29 @@
vmem = (struct vidc_mem_addr *)mem;
HAL_MSG_HIGH("start to alloc: size:%d, Flags: %d", size, flags);
- alloc = msm_smem_alloc(clnt, size, align, flags, domain, 0);
+ alloc = msm_smem_alloc(clnt, size, align, flags, domain, 1, 1);
HAL_MSG_LOW("Alloc done");
if (!alloc) {
HAL_MSG_HIGH("Alloc fail in %s", __func__);
- return -ENOMEM;
- } else {
- HAL_MSG_MEDIUM("vidc_hal_alloc:ptr=%p,size=%d",
- alloc->kvaddr, size);
- vmem->mem_size = alloc->size;
- vmem->mem_data = alloc;
- vmem->align_virtual_addr = (u8 *) alloc->kvaddr;
- vmem->align_device_addr = (u8 *)alloc->device_addr;
+ rc = -ENOMEM;
+ goto fail_smem_alloc;
}
- return 0;
+ rc = msm_smem_clean_invalidate(clnt, alloc);
+ if (rc) {
+ pr_err("NOTE: Failed to clean caches\n");
+ goto fail_clean_cache;
+ }
+ HAL_MSG_MEDIUM("vidc_hal_alloc:ptr=%p,size=%d",
+ alloc->kvaddr, size);
+ vmem->mem_size = alloc->size;
+ vmem->mem_data = alloc;
+ vmem->align_virtual_addr = (u8 *) alloc->kvaddr;
+ vmem->align_device_addr = (u8 *)alloc->device_addr;
+ return rc;
+fail_clean_cache:
+ msm_smem_free(clnt, alloc);
+fail_smem_alloc:
+ return rc;
}
static void vidc_hal_free(struct smem_client *clnt, struct msm_smem *mem)
@@ -476,7 +486,7 @@
{
q_hdr->qhdr_status = 0x1;
q_hdr->qhdr_type = VIDC_IFACEQ_DFLT_QHDR;
- q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE;
+ q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE / 4;
q_hdr->qhdr_pkt_size = 0;
q_hdr->qhdr_rx_wm = 0x1;
q_hdr->qhdr_tx_wm = 0x1;
@@ -517,7 +527,7 @@
rc = vidc_hal_alloc((void *) &dev->iface_q_table,
dev->hal_client,
- VIDC_IFACEQ_TABLE_SIZE, 1, 0, domain);
+ VIDC_IFACEQ_TABLE_SIZE, 1, SMEM_UNCACHED, domain);
if (rc) {
HAL_MSG_ERROR("%s:iface_q_table_alloc_fail", __func__);
return -ENOMEM;
@@ -537,7 +547,7 @@
iface_q = &dev->iface_queues[i];
rc = vidc_hal_alloc((void *) &iface_q->q_array,
dev->hal_client, VIDC_IFACEQ_QUEUE_SIZE,
- 1, 0, domain);
+ 1, SMEM_UNCACHED, domain);
if (rc) {
HAL_MSG_ERROR("%s:iface_q_table_alloc[%d]_fail",
__func__, i);
@@ -614,6 +624,10 @@
spin_lock_init(&dev->read_lock);
spin_lock_init(&dev->write_lock);
+ /*Disable Dynamic clock gating for Venus VBIF*/
+ write_register(dev->hal_data->register_base_addr,
+ VIDC_VENUS_VBIF_CLK_ON, 1, 0);
+
if (!dev->hal_client) {
dev->hal_client = msm_smem_new_client(SMEM_ION);
if (dev->hal_client == NULL) {
@@ -1201,9 +1215,11 @@
}
case HAL_PARAM_VENC_RATE_CONTROL:
{
+ u32 *rc_mode;
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
- switch ((enum hal_rate_control)pdata) {
+ rc_mode = (u32 *)pdata;
+ switch ((enum hal_rate_control) *rc_mode) {
case HAL_RATE_CONTROL_OFF:
pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF;
break;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_io.h b/drivers/media/video/msm_vidc/vidc_hal_io.h
index 05a4c60..c1058e6 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_io.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_io.h
@@ -98,6 +98,7 @@
#define VIDC_WRAPPER_AXI_HALT (VIDC_WRAPPER_BASE_OFFS + 0x2008)
#define VIDC_WRAPPER_AXI_HALT_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x200C)
#define VIDC_WRAPPER_CPU_CGC_DIS (VIDC_WRAPPER_BASE_OFFS + 0x2010)
+#define VIDC_VENUS_VBIF_CLK_ON 0x80004
#endif
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 9f2ead4..ba053f2 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -320,7 +320,7 @@
}
dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
- if (!(irq & (VP_PIC_DONE || VP_MODE_CHANGE))) {
+ if (!(irq & (VP_PIC_DONE | VP_MODE_CHANGE))) {
writel_relaxed(irq, VCAP_VP_INT_CLEAR);
pr_err("VP IRQ shows some error\n");
return IRQ_HANDLED;
@@ -789,7 +789,7 @@
top_field = 1;
#endif
vp_act->vp_state = VP_FRAME2;
- writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
+ writel_relaxed(0x01100001, VCAP_VP_INTERRUPT_ENABLE);
#ifdef TOP_FIELD_FIX
writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
writel_iowmb(0x00010000 | vp_act->top_field << 0, VCAP_VP_CTRL);
@@ -836,7 +836,7 @@
#endif
/* Config VP & Enable Interrupt */
- writel_relaxed(0x01100101, VCAP_VP_INTERRUPT_ENABLE);
+ writel_relaxed(0x01100001, VCAP_VP_INTERRUPT_ENABLE);
#ifdef TOP_FIELD_FIX
writel_iowmb(0x00000000 | vp_act->top_field << 0, VCAP_VP_CTRL);
writel_iowmb(0x00010000 | vp_act->top_field << 0, VCAP_VP_CTRL);
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 2bc0938..a7d13a8 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -1330,12 +1330,14 @@
return -EINVAL;
}
+ mutex_lock(&q->q_lock);
ret = __vb2_get_done_vb(q, &vb, nonblocking);
if (ret < 0) {
dprintk(1, "dqbuf: error getting next done buffer\n");
+ mutex_unlock(&q->q_lock);
return ret;
}
-
+ mutex_unlock(&q->q_lock);
ret = call_qop(q, buf_finish, vb);
if (ret) {
dprintk(1, "dqbuf: buffer finish failed\n");
@@ -1447,15 +1449,17 @@
/*
* Let driver notice that streaming state has been enabled.
*/
+ mutex_lock(&q->q_lock);
ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
if (ret) {
dprintk(1, "streamon: driver refused to start streaming\n");
__vb2_queue_cancel(q);
+ mutex_unlock(&q->q_lock);
return ret;
}
q->streaming = 1;
-
+ mutex_unlock(&q->q_lock);
dprintk(3, "Streamon successful\n");
return 0;
}
@@ -1729,6 +1733,7 @@
INIT_LIST_HEAD(&q->queued_list);
INIT_LIST_HEAD(&q->done_list);
spin_lock_init(&q->done_lock);
+ mutex_init(&q->q_lock);
init_waitqueue_head(&q->done_wq);
if (q->buf_struct_size == 0)
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index 740d183..c1a392e2 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -62,7 +62,7 @@
goto alloc_failed;
}
rc = ion_map_iommu(mem->client, mem->ion_handle,
- CAMERA_DOMAIN, GEN_POOL, SZ_4K, 0,
+ -1, 0, SZ_4K, 0,
(unsigned long *)&phyaddr,
(unsigned long *)&len, UNCACHED, 0);
if (rc < 0) {
@@ -87,7 +87,7 @@
{
int32_t rc = 0;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- ion_unmap_iommu(mem->client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL);
+ ion_unmap_iommu(mem->client, mem->ion_handle, -1, 0);
ion_free(mem->client, mem->ion_handle);
ion_client_destroy(mem->client);
#else
@@ -174,7 +174,8 @@
struct videobuf2_msm_offset *offset,
enum videobuf2_buffer_type buffer_type,
uint32_t addr_offset, int path,
- struct ion_client *client)
+ struct ion_client *client,
+ int domain_num)
{
unsigned long len;
int rc = 0;
@@ -190,7 +191,7 @@
pr_err("%s ION import failed\n", __func__);
return PTR_ERR(mem->ion_handle);
}
- rc = ion_map_iommu(client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL,
+ rc = ion_map_iommu(client, mem->ion_handle, domain_num, 0,
SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, UNCACHED, 0);
if (rc < 0)
ion_free(client, mem->ion_handle);
@@ -220,12 +221,12 @@
EXPORT_SYMBOL_GPL(videobuf2_pmem_contig_user_get);
void videobuf2_pmem_contig_user_put(struct videobuf2_contig_pmem *mem,
- struct ion_client *client)
+ struct ion_client *client, int domain_num)
{
if (mem->is_userptr) {
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
ion_unmap_iommu(client, mem->ion_handle,
- CAMERA_DOMAIN, GEN_POOL);
+ domain_num, 0);
ion_free(client, mem->ion_handle);
#elif CONFIG_ANDROID_PMEM
put_pmem_file(mem->file);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 05707fd..b56f081 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -338,18 +338,26 @@
WCD9XXX_A_CHIP_VERSION) & 0x1F;
pr_info("%s : Codec version %u initialized\n",
__func__, wcd9xxx->version);
+ pr_info("idbyte_0[%08x] idbyte_1[%08x] idbyte_2[%08x] idbyte_3[%08x]\n",
+ wcd9xxx->idbyte_0, wcd9xxx->idbyte_1,
+ wcd9xxx->idbyte_2, wcd9xxx->idbyte_3);
- if (wcd9xxx->idbyte_0 == 0x2) {
+ if (wcd9xxx->idbyte_0 == 0x2 && wcd9xxx->idbyte_1 == 0x0 &&
+ wcd9xxx->idbyte_2 == 0x0 && wcd9xxx->idbyte_3 == 0x1) {
wcd9xxx_dev = tabla_devs;
wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
- } else if (wcd9xxx->idbyte_0 == 0x1) {
+ } else if (wcd9xxx->idbyte_0 == 0x1 && wcd9xxx->idbyte_1 == 0x0 &&
+ wcd9xxx->idbyte_2 == 0x0 && wcd9xxx->idbyte_3 == 0x1) {
wcd9xxx_dev = tabla1x_devs;
wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
} else if (wcd9xxx->idbyte_0 == 0x0 && wcd9xxx->idbyte_1 == 0x0 &&
wcd9xxx->idbyte_2 == 0x2 && wcd9xxx->idbyte_3 == 0x1) {
wcd9xxx_dev = taiko_devs;
wcd9xxx_dev_size = ARRAY_SIZE(taiko_devs);
- } else if (wcd9xxx->idbyte_0 == 0x0) {
+ } else if ((wcd9xxx->idbyte_0 == 0x0 && wcd9xxx->idbyte_1 == 0x0 &&
+ wcd9xxx->idbyte_2 == 0x0 && wcd9xxx->idbyte_3 == 0x1) ||
+ (wcd9xxx->idbyte_0 == 0x1 && wcd9xxx->idbyte_1 == 0x0 &&
+ wcd9xxx->idbyte_2 == 0x1 && wcd9xxx->idbyte_3 == 0x1)) {
wcd9xxx_dev = sitar_devs;
wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
}
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 71c68ac..b4cf435 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -535,7 +535,6 @@
unsigned int ch_cnt)
{
u16 grph = 0;
- u32 sph[SLIM_MAX_RX_PORTS] = {0};
int i = 0 , idx = 0;
int ret = 0;
struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
@@ -549,10 +548,9 @@
ret = -EINVAL;
goto err;
}
- sph[i] = rx[idx].sph;
grph = rx[idx].grph;
- pr_debug("%s: ch_num[%d] %d, idx %d, sph[%d] %x, grph %x\n",
- __func__, i, ch_num[i], idx, i, sph[i], grph);
+ pr_debug("%s: ch_num[%d] %d, idx %d, grph %x\n",
+ __func__, i, ch_num[i], idx, grph);
}
/* slim_control_ch (REMOVE) */
@@ -561,12 +559,6 @@
pr_err("%s: slim_control_ch failed ret[%d]\n", __func__, ret);
goto err;
}
- /* slim_disconnect_port */
- ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
- if (ret < 0) {
- pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
- __func__, ret);
- }
for (i = 0; i < ch_cnt; i++) {
idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
rx[idx].grph = 0;
@@ -580,7 +572,6 @@
unsigned int ch_cnt)
{
u16 grph = 0;
- u32 sph[SLIM_MAX_TX_PORTS] = {0};
int ret = 0;
int i = 0 , idx = 0;
struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
@@ -594,15 +585,8 @@
ret = -EINVAL;
goto err;
}
- sph[i] = tx[idx].sph;
grph = tx[idx].grph;
}
- /* slim_disconnect_port */
- ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
- if (ret < 0) {
- pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
- __func__, ret);
- }
/* slim_control_ch (REMOVE) */
ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
if (ret < 0) {
@@ -633,3 +617,48 @@
return ret;
}
EXPORT_SYMBOL_GPL(wcd9xxx_get_slave_port);
+
+int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
+ unsigned int ch_cnt, unsigned int rx_tx)
+{
+ u32 sph[SLIM_MAX_TX_PORTS] = {0};
+ int i = 0 , idx = 0;
+ int ret = 0;
+ struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
+ struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
+
+ pr_debug("%s: ch_cnt[%d], rx_tx flag = %d\n", __func__, ch_cnt, rx_tx);
+ for (i = 0; i < ch_cnt; i++) {
+ /* rx_tx will be 1 for rx, 0 for tx */
+ if (rx_tx) {
+ idx = (ch_num[i] - BASE_CH_NUM -
+ sh_ch.rx_port_start_offset);
+ if (idx < 0) {
+ pr_err("%s: Invalid index found for RX = %d\n",
+ __func__, idx);
+ ret = -EINVAL;
+ goto err;
+ }
+ sph[i] = rx[idx].sph;
+ } else {
+ idx = (ch_num[i] - BASE_CH_NUM);
+ if (idx < 0) {
+ pr_err("%s:Invalid index found for TX = %d\n",
+ __func__, idx);
+ ret = -EINVAL;
+ goto err;
+ }
+ sph[i] = tx[idx].sph;
+ }
+ }
+
+ /* slim_disconnect_port */
+ ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
+ if (ret < 0) {
+ pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
+ __func__, ret);
+ }
+err:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_disconnect_port);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 8354aa8..696f16d 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -522,7 +522,6 @@
return 0;
}
-
static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
{
int ret;
@@ -771,21 +770,20 @@
int ret = 0;
struct qseecom_command_scm_resp resp;
struct qseecom_registered_app_list *ptr_app;
- uint32_t unload = 0;
+ bool unload = false;
+ bool found_app = false;
if (qseecom.qseos_version == QSEOS_VERSION_14) {
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
list) {
if (ptr_app->app_id == data->client.app_id) {
+ found_app = true;
if (ptr_app->ref_cnt == 1) {
- unload = __qseecom_cleanup_app(data);
- list_del(&ptr_app->list);
- kzfree(ptr_app);
+ unload = true;
break;
} else {
ptr_app->ref_cnt--;
- data->released = true;
pr_warn("Can't unload app with id %d (it is inuse)\n",
ptr_app->app_id);
break;
@@ -795,14 +793,20 @@
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags);
}
- if (!IS_ERR_OR_NULL(data->client.ihandle)) {
- ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
- ion_free(qseecom.ion_clnt, data->client.ihandle);
+ if (found_app == false) {
+ pr_err("Cannot find app with id = %d\n", data->client.app_id);
+ return -EINVAL;
}
if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
struct qseecom_unload_app_ireq req;
+ __qseecom_cleanup_app(data);
+ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
+ list_del(&ptr_app->list);
+ kzfree(ptr_app);
+ spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+ flags);
/* Populate the structure for sending scm call to load image */
req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
req.app_id = data->client.app_id;
@@ -840,6 +844,11 @@
}
}
}
+ if (!IS_ERR_OR_NULL(data->client.ihandle)) {
+ ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
+ ion_free(qseecom.ion_clnt, data->client.ihandle);
+ data->client.ihandle = NULL;
+ }
data->released = true;
return ret;
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index b5ffe94..b1b8892 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1414,31 +1414,6 @@
}
/*
- * Save ios settings
- */
-static void mmc_save_ios(struct mmc_host *host)
-{
- BUG_ON(!host);
-
- mmc_host_clk_hold(host);
-
- memcpy(&host->saved_ios, &host->ios, sizeof(struct mmc_ios));
-
- mmc_host_clk_release(host);
-}
-
-/*
- * Restore ios setting
- */
-static void mmc_restore_ios(struct mmc_host *host)
-{
- BUG_ON(!host);
-
- memcpy(&host->ios, &host->saved_ios, sizeof(struct mmc_ios));
- mmc_set_ios(host);
-}
-
-/*
* Suspend callback from host.
*/
static int mmc_suspend(struct mmc_host *host)
@@ -1449,7 +1424,6 @@
BUG_ON(!host->card);
mmc_claim_host(host);
- mmc_save_ios(host);
if (mmc_can_poweroff_notify(host->card) &&
(host->caps2 & MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND)) {
err = mmc_poweroff_notify(host, MMC_PW_OFF_NOTIFY_SHORT);
@@ -1489,11 +1463,7 @@
BUG_ON(!host->card);
mmc_claim_host(host);
- if (mmc_card_is_sleep(host->card)) {
- mmc_restore_ios(host);
- err = mmc_card_awake(host);
- } else
- err = mmc_init_card(host, host->ocr, host->card);
+ err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return err;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 590aa58..d82c353 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -409,7 +409,6 @@
if (index == EXT_CSD_BKOPS_START)
return 0;
- mmc_delay(1);
/* Must check status to be sure of no errors */
do {
err = mmc_send_status(card, &status);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index b22e2f0..2b278be 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -725,12 +725,6 @@
mmc_hostname(host->mmc), __func__,
notify->event_id);
- if (msmsdcc_is_dml_busy(host)) {
- /* oops !!! this should never happen. */
- pr_err("%s: %s: Received SPS EOT event"
- " but DML HW is still busy !!!\n",
- mmc_hostname(host->mmc), __func__);
- }
/*
* Got End of transfer event!!! Check if all of the data
* has been transferred?
@@ -1241,25 +1235,12 @@
if (is_dma_mode(host) && !msmsdcc_config_dma(host, data)) {
datactrl |= MCI_DPSM_DMAENABLE;
} else if (is_sps_mode(host)) {
- if (!msmsdcc_is_dml_busy(host)) {
- if (!msmsdcc_sps_start_xfer(host, data)) {
- /* Now kick start DML transfer */
- mb();
- msmsdcc_dml_start_xfer(host, data);
- datactrl |= MCI_DPSM_DMAENABLE;
- host->sps.busy = 1;
- }
- } else {
- /*
- * Can't proceed with new transfer as
- * previous trasnfer is already in progress.
- * There is no point of going into PIO mode
- * as well. Is this a time to do kernel panic?
- */
- pr_err("%s: %s: DML HW is busy!!!"
- " Can't perform new SPS transfers"
- " now\n", mmc_hostname(host->mmc),
- __func__);
+ if (!msmsdcc_sps_start_xfer(host, data)) {
+ /* Now kick start DML transfer */
+ mb();
+ msmsdcc_dml_start_xfer(host, data);
+ datactrl |= MCI_DPSM_DMAENABLE;
+ host->sps.busy = 1;
}
}
}
@@ -2191,6 +2172,18 @@
return rc;
}
+static inline int msmsdcc_vreg_get_voltage(struct msm_mmc_reg_data *vreg)
+{
+ int rc = 0;
+
+ rc = regulator_get_voltage(vreg->reg);
+ if (rc < 0)
+ pr_err("%s: regulator_get_voltage(%s) failed. rc=%d\n",
+ __func__, vreg->name, rc);
+
+ return rc;
+}
+
static inline int msmsdcc_vreg_set_optimum_mode(struct msm_mmc_reg_data *vreg,
int uA_load)
{
@@ -2435,6 +2428,82 @@
VDD_IO_SET_LEVEL,
};
+/*
+ * This function returns the current VDD IO voltage level.
+ * Returns negative value if it fails to read the voltage level
+ * Returns 0 if regulator was disabled or if VDD_IO (and VDD)
+ * regulator were not defined for host.
+ */
+static int msmsdcc_get_vdd_io_vol(struct msmsdcc_host *host)
+{
+ int rc = 0;
+
+ if (host->plat->vreg_data) {
+ struct msm_mmc_reg_data *io_reg =
+ host->plat->vreg_data->vdd_io_data;
+
+ /*
+ * If vdd_io is not defined, then we can consider that
+ * IO voltage is same as VDD.
+ */
+ if (!io_reg)
+ io_reg = host->plat->vreg_data->vdd_data;
+
+ if (io_reg && io_reg->is_enabled)
+ rc = msmsdcc_vreg_get_voltage(io_reg);
+ }
+
+ return rc;
+}
+
+/*
+ * This function updates the IO pad power switch bit in MCI_CLK register
+ * based on currrent IO pad voltage level.
+ * NOTE: This function assumes that host lock was not taken by caller.
+ */
+static void msmsdcc_update_io_pad_pwr_switch(struct msmsdcc_host *host)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ if (!is_io_pad_pwr_switch(host))
+ return;
+
+ rc = msmsdcc_get_vdd_io_vol(host);
+
+ spin_lock_irqsave(&host->lock, flags);
+ /*
+ * Dual voltage pad is the SDCC's (chipset) functionality and not all
+ * the SDCC instances support the dual voltage pads.
+ * For dual-voltage pad (1.8v/3.3v), SW should set IO_PAD_PWR_SWITCH
+ * bit before using the pads in 1.8V mode.
+ * For regular, not dual-voltage pads (including eMMC 1.2v/1.8v pads),
+ * IO_PAD_PWR_SWITCH bit is a don't care.
+ * But we don't have an option to know (by reading some SDCC register)
+ * that a particular SDCC instance supports dual voltage pads or not,
+ * so we simply set the IO_PAD_PWR_SWITCH bit for low voltage IO
+ * (1.8v/1.2v). For regular (not dual-voltage pads), this bit value
+ * is anyway ignored.
+ */
+ if (rc > 0 && rc < 2700000)
+ host->io_pad_pwr_switch = 1;
+ else
+ host->io_pad_pwr_switch = 0;
+
+ if (atomic_read(&host->clks_on)) {
+ if (host->io_pad_pwr_switch)
+ writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
+ IO_PAD_PWR_SWITCH),
+ host->base + MMCICLOCK);
+ else
+ writel_relaxed((readl_relaxed(host->base + MMCICLOCK) &
+ ~IO_PAD_PWR_SWITCH),
+ host->base + MMCICLOCK);
+ msmsdcc_sync_reg_wr(host);
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
enum vdd_io_level level,
unsigned int voltage_level)
@@ -2736,6 +2805,7 @@
* present or during system suspend).
*/
msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
+ msmsdcc_update_io_pad_pwr_switch(host);
msmsdcc_setup_pins(host, false);
break;
case MMC_POWER_UP:
@@ -2744,6 +2814,7 @@
msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
+ msmsdcc_update_io_pad_pwr_switch(host);
msmsdcc_setup_pins(host, true);
break;
case MMC_POWER_ON:
@@ -3156,10 +3227,6 @@
/* Select free running MCLK as input clock of cm_dll_sdc4 */
clk |= (2 << 23);
- /* Clear IO_PAD_PWR_SWITCH while powering off the card */
- if (!ios->vdd)
- host->io_pad_pwr_switch = 0;
-
if (host->io_pad_pwr_switch)
clk |= IO_PAD_PWR_SWITCH;
@@ -3291,6 +3358,9 @@
{
struct device *dev = mmc_dev(host->mmc);
+ pr_info("%s: PM: sdcc_suspended=%d, pending_resume=%d, sdcc_suspending=%d\n",
+ mmc_hostname(host->mmc), host->sdcc_suspended,
+ host->pending_resume, host->sdcc_suspending);
pr_info("%s: RPM: runtime_status=%d, usage_count=%d,"
" is_suspended=%d, disable_depth=%d, runtime_error=%d,"
" request_pending=%d, request=%d\n",
@@ -3312,8 +3382,7 @@
if (mmc->card && mmc_card_sdio(mmc->card))
goto out;
- if (host->sdcc_suspended && host->pending_resume &&
- !pm_runtime_suspended(dev)) {
+ if (host->sdcc_suspended && host->pending_resume) {
host->pending_resume = false;
pm_runtime_get_noresume(dev);
rc = msmsdcc_runtime_resume(dev);
@@ -3334,8 +3403,8 @@
skip_get_sync:
if (rc < 0) {
- pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
- __func__, rc);
+ WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
+ __func__, rc);
msmsdcc_print_rpm_info(host);
return rc;
}
@@ -3361,15 +3430,9 @@
rc = pm_runtime_put_sync(mmc->parent);
- /*
- * Ignore -EAGAIN as that is not fatal, it means that
- * either runtime usage count is non-zero or the runtime
- * pm itself is disabled or not in proper state to process
- * idle notification.
- */
- if (rc < 0 && (rc != -EAGAIN)) {
- pr_info("%s: %s: failed with error %d", mmc_hostname(mmc),
- __func__, rc);
+ if (rc < 0) {
+ WARN(1, "%s: %s: failed with error %d\n", mmc_hostname(mmc),
+ __func__, rc);
msmsdcc_print_rpm_info(host);
return rc;
}
@@ -3448,14 +3511,12 @@
unsigned long flags;
int rc = 0;
- spin_lock_irqsave(&host->lock, flags);
- host->io_pad_pwr_switch = 0;
- spin_unlock_irqrestore(&host->lock, flags);
-
switch (ios->signal_voltage) {
case MMC_SIGNAL_VOLTAGE_330:
/* Set VDD IO to high voltage range (2.7v - 3.6v) */
rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
+ if (!rc)
+ msmsdcc_update_io_pad_pwr_switch(host);
goto out;
case MMC_SIGNAL_VOLTAGE_180:
break;
@@ -3466,6 +3527,8 @@
* DDR 1.2V mode.
*/
rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
+ if (!rc)
+ msmsdcc_update_io_pad_pwr_switch(host);
goto out;
default:
/* invalid selection. don't do anything */
@@ -3504,12 +3567,7 @@
if (rc)
goto out;
- spin_lock_irqsave(&host->lock, flags);
- writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
- IO_PAD_PWR_SWITCH), host->base + MMCICLOCK);
- msmsdcc_sync_reg_wr(host);
- host->io_pad_pwr_switch = 1;
- spin_unlock_irqrestore(&host->lock, flags);
+ msmsdcc_update_io_pad_pwr_switch(host);
/* Wait 5 ms for the voltage regulater in the card to become stable. */
usleep_range(5000, 5500);
@@ -5123,7 +5181,9 @@
pdata->status_gpio = of_get_named_gpio_flags(np,
"cd-gpios", 0, &flags);
if (gpio_is_valid(pdata->status_gpio)) {
- pdata->status_irq = gpio_to_irq(pdata->status_gpio);
+ struct platform_device *pdev = container_of(dev,
+ struct platform_device, dev);
+ pdata->status_irq = platform_get_irq_byname(pdev, "status_irq");
pdata->is_status_gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
}
@@ -6262,6 +6322,7 @@
wake_unlock(&host->sdio_suspend_wlock);
}
+ host->pending_resume = false;
pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
return 0;
}
@@ -6334,7 +6395,13 @@
if (mmc->card && mmc_card_sdio(mmc->card))
rc = msmsdcc_runtime_resume(dev);
- else
+ /*
+ * As runtime PM is enabled before calling the device's platform resume
+ * callback, we use the pm_runtime_suspended API to know if SDCC is
+ * really runtime suspended or not and set the pending_resume flag only
+ * if its not runtime suspended.
+ */
+ else if (!pm_runtime_suspended(dev))
host->pending_resume = true;
if (host->plat->status_irq) {
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 3b1dbc7..236785d 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -428,6 +428,7 @@
#define MSMSDCC_SW_RST (1 << 5)
#define MSMSDCC_SW_RST_CFG (1 << 6)
#define MSMSDCC_WAIT_FOR_TX_RX (1 << 7)
+#define MSMSDCC_IO_PAD_PWR_SWITCH (1 << 8)
#define set_hw_caps(h, val) ((h)->hw_caps |= val)
#define is_sps_mode(h) ((h)->hw_caps & MSMSDCC_SPS_BAM_SUP)
@@ -438,6 +439,7 @@
#define is_sw_hard_reset(h) ((h)->hw_caps & MSMSDCC_SW_RST)
#define is_sw_reset_save_config(h) ((h)->hw_caps & MSMSDCC_SW_RST_CFG)
#define is_wait_for_tx_rx_active(h) ((h)->hw_caps & MSMSDCC_WAIT_FOR_TX_RX)
+#define is_io_pad_pwr_switch(h) ((h)->hw_caps & MSMSDCC_IO_PAD_PWR_SWITCH)
/* Set controller capabilities based on version */
static inline void set_default_hw_caps(struct msmsdcc_host *host)
@@ -457,7 +459,7 @@
if (version) /* SDCC v4 and greater */
host->hw_caps |= MSMSDCC_AUTO_PROG_DONE |
MSMSDCC_SOFT_RESET | MSMSDCC_REG_WR_ACTIVE
- | MSMSDCC_WAIT_FOR_TX_RX;
+ | MSMSDCC_WAIT_FOR_TX_RX | MSMSDCC_IO_PAD_PWR_SWITCH;
if (version >= 0x2D) /* SDCC v4 2.1.0 and greater */
host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_SW_RST_CFG;
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index 186d07d..f6e4b00 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -271,7 +271,7 @@
__func__, status);
}
-static int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev)
+int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev)
{
int retval = 0;
@@ -298,18 +298,6 @@
return 0;
}
-int rmnet_usb_ctrl_start(struct rmnet_ctrl_dev *dev)
-{
- int status = 0;
-
- mutex_lock(&dev->dev_lock);
- if (dev->is_opened)
- status = rmnet_usb_ctrl_start_rx(dev);
- mutex_unlock(&dev->dev_lock);
-
- return status;
-}
-
static int rmnet_usb_ctrl_alloc_rx(struct rmnet_ctrl_dev *dev)
{
int retval = -ENOMEM;
diff --git a/drivers/net/usb/rmnet_usb_ctrl.h b/drivers/net/usb/rmnet_usb_ctrl.h
index 3259940..7a84817 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.h
+++ b/drivers/net/usb/rmnet_usb_ctrl.h
@@ -73,7 +73,7 @@
extern struct rmnet_ctrl_dev *ctrl_dev[];
-extern int rmnet_usb_ctrl_start(struct rmnet_ctrl_dev *);
+extern int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *);
extern int rmnet_usb_ctrl_stop_rx(struct rmnet_ctrl_dev *);
extern int rmnet_usb_ctrl_init(void);
extern void rmnet_usb_ctrl_exit(void);
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 4f8039e..b8c6140 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -151,7 +151,7 @@
retval = usbnet_resume(iface);
if (!retval) {
if (oldstate & PM_EVENT_SUSPEND)
- retval = rmnet_usb_ctrl_start(dev);
+ retval = rmnet_usb_ctrl_start_rx(dev);
}
fail:
return retval;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index d26c845..1867fe2 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -89,6 +89,8 @@
static struct workqueue_struct *usbnet_wq;
+static DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup);
+
/* use ethtool to change the level for any given device */
static int msg_level = -1;
module_param (msg_level, int, 0);
@@ -664,7 +666,6 @@
// precondition: never called in_interrupt
static void usbnet_terminate_urbs(struct usbnet *dev)
{
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup);
DECLARE_WAITQUEUE(wait, current);
int temp;
@@ -1240,7 +1241,7 @@
// waiting for all pending urbs to complete?
if (dev->wait) {
if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
- wake_up (dev->wait);
+ wake_up(&unlink_wakeup);
}
// or are we maybe short a few urbs?
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
index 23365ff..2d9ad82 100644
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ b/drivers/net/wireless/wcnss/wcnss_riva.c
@@ -64,7 +64,7 @@
{"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, 1200000, 10000, NULL},
+ {"iris_vdddig", VREG_NULL_CONFIG, 1200000, 0, 1225000, 10000, NULL},
};
static struct vregs_info riva_vregs[] = {
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index d75cac4..34e1d40 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -67,4 +67,13 @@
This driver supports the power-on functionality on Qualcomm
PNP PMIC. It currently supports reporting the change in status of
the KPDPWR_N line (connected to the power-key).
+
+config QPNP_CLKDIV
+ tristate "QPNP PMIC clkdiv driver"
+ depends on OF_SPMI && SPMI
+ help
+ This driver supports the clkdiv functionality on the Qualcomm
+ PNP PMIC. It configures the frequency of clkdiv outputs on the
+ PMIC. These clocks are typically wired through alternate functions
+ on gpio pins.
endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index 2b6b806..35efd91 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -6,3 +6,4 @@
obj-$(CONFIG_SPS) += sps/
obj-$(CONFIG_QPNP_PWM) += qpnp-pwm.o
obj-$(CONFIG_QPNP_POWER_ON) += qpnp-power-on.o
+obj-$(CONFIG_QPNP_CLKDIV) += qpnp-clkdiv.o
diff --git a/drivers/platform/msm/qpnp-clkdiv.c b/drivers/platform/msm/qpnp-clkdiv.c
new file mode 100644
index 0000000..2a9ba90
--- /dev/null
+++ b/drivers/platform/msm/qpnp-clkdiv.c
@@ -0,0 +1,287 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/types.h>
+#include <linux/spmi.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/time.h>
+#include <linux/qpnp/clkdiv.h>
+
+#define Q_MAX_DT_PROP_SIZE 32
+
+#define Q_REG_ADDR(q_clkdiv, reg_offset) \
+ ((q_clkdiv)->offset + reg_offset)
+
+#define Q_REG_DIV_CTL1 0x43
+#define Q_REG_EN_CTL 0x46
+
+#define Q_SET_EN BIT(7)
+
+#define Q_CXO_PERIOD_NS(_cxo_clk) (NSEC_PER_SEC / _cxo_clk)
+#define Q_DIV_PERIOD_NS(_cxo_clk, _div) (NSEC_PER_SEC / (_cxo_clk / _div))
+#define Q_ENABLE_DELAY_NS(_cxo_clk, _div) (2 * Q_CXO_PERIOD_NS(_cxo_clk) + \
+ 3 * Q_DIV_PERIOD_NS(_cxo_clk, _div))
+#define Q_DISABLE_DELAY_NS(_cxo_clk, _div) (3 * Q_DIV_PERIOD_NS(_cxo_clk, _div))
+
+struct q_clkdiv {
+ uint32_t cxo_hz;
+ enum q_clkdiv_cfg cxo_div;
+ struct device_node *node;
+ uint16_t offset;
+ struct spmi_controller *ctrl;
+ bool enabled;
+ struct mutex lock;
+ struct list_head list;
+ uint8_t slave;
+};
+
+static LIST_HEAD(qpnp_clkdiv_devs);
+
+/**
+ * qpnp_clkdiv_get - get a clkdiv handle
+ * @dev: client device pointer.
+ * @name: client specific name for the clock in question.
+ *
+ * Return a clkdiv handle given a client specific name. This name be a prefix
+ * for a property naming that takes a phandle to the actual clkdiv device.
+ */
+struct q_clkdiv *qpnp_clkdiv_get(struct device *dev, const char *name)
+{
+ struct q_clkdiv *q_clkdiv;
+ struct device_node *divclk_node;
+ char prop_name[Q_MAX_DT_PROP_SIZE];
+ int n;
+
+ n = snprintf(prop_name, Q_MAX_DT_PROP_SIZE, "%s-clk", name);
+ if (n == Q_MAX_DT_PROP_SIZE)
+ return ERR_PTR(-EINVAL);
+
+ divclk_node = of_parse_phandle(dev->of_node, prop_name, 0);
+ if (divclk_node == NULL)
+ return ERR_PTR(-ENODEV);
+
+ list_for_each_entry(q_clkdiv, &qpnp_clkdiv_devs, list)
+ if (q_clkdiv->node == divclk_node)
+ return q_clkdiv;
+ return ERR_PTR(-EPROBE_DEFER);
+}
+EXPORT_SYMBOL(qpnp_clkdiv_get);
+
+static int __clkdiv_enable(struct q_clkdiv *q_clkdiv, bool enable)
+{
+ int rc;
+ char buf[1];
+
+ buf[0] = enable ? Q_SET_EN : 0;
+
+ mutex_lock(&q_clkdiv->lock);
+ rc = spmi_ext_register_writel(q_clkdiv->ctrl, q_clkdiv->slave,
+ Q_REG_ADDR(q_clkdiv, Q_REG_EN_CTL),
+ &buf[0], 1);
+ if (!rc)
+ q_clkdiv->enabled = enable;
+
+ mutex_unlock(&q_clkdiv->lock);
+
+ if (enable)
+ ndelay(Q_ENABLE_DELAY_NS(q_clkdiv->cxo_hz, q_clkdiv->cxo_div));
+ else
+ ndelay(Q_DISABLE_DELAY_NS(q_clkdiv->cxo_hz, q_clkdiv->cxo_div));
+
+ return rc;
+}
+
+/**
+ * qpnp_clkdiv_enable - enable a clkdiv
+ * @q_clkdiv: pointer to clkdiv handle
+ */
+int qpnp_clkdiv_enable(struct q_clkdiv *q_clkdiv)
+{
+ return __clkdiv_enable(q_clkdiv, true);
+}
+EXPORT_SYMBOL(qpnp_clkdiv_enable);
+
+/**
+ * qpnp_clkdiv_disable - disable a clkdiv
+ * @q_clkdiv: pointer to clkdiv handle
+ */
+int qpnp_clkdiv_disable(struct q_clkdiv *q_clkdiv)
+{
+ return __clkdiv_enable(q_clkdiv, false);
+}
+EXPORT_SYMBOL(qpnp_clkdiv_disable);
+
+/**
+ * @q_clkdiv: pointer to clkdiv handle
+ * @cfg: setting used to configure the output frequency
+ *
+ * Given a q_clkdiv_cfg setting, configure the corresponding clkdiv device
+ * for the desired output frequency.
+ */
+int qpnp_clkdiv_config(struct q_clkdiv *q_clkdiv, enum q_clkdiv_cfg cfg)
+{
+ int rc;
+ char buf[1];
+
+ if (cfg < 0 || cfg >= Q_CLKDIV_INVALID)
+ return -EINVAL;
+
+ buf[0] = cfg;
+
+ mutex_lock(&q_clkdiv->lock);
+
+ if (q_clkdiv->enabled) {
+ rc = __clkdiv_enable(q_clkdiv, false);
+ if (rc) {
+ pr_err("unable to disable clock\n");
+ goto cfg_err;
+ }
+ }
+
+ rc = spmi_ext_register_writel(q_clkdiv->ctrl, q_clkdiv->slave,
+ Q_REG_ADDR(q_clkdiv, Q_REG_DIV_CTL1), &buf[0], 1);
+ if (rc) {
+ pr_err("enable to write config\n");
+ q_clkdiv->enabled = 0;
+ goto cfg_err;
+ }
+
+ q_clkdiv->cxo_div = cfg;
+
+ if (q_clkdiv->enabled) {
+ rc = __clkdiv_enable(q_clkdiv, true);
+ if (rc) {
+ pr_err("unable to re-enable clock\n");
+ goto cfg_err;
+ }
+ }
+
+cfg_err:
+ mutex_unlock(&q_clkdiv->lock);
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_clkdiv_config);
+
+static int __devinit qpnp_clkdiv_probe(struct spmi_device *spmi)
+{
+ struct q_clkdiv *q_clkdiv;
+ struct device_node *node = spmi->dev.of_node;
+ int rc;
+ uint32_t en;
+ struct resource *res;
+
+ q_clkdiv = devm_kzalloc(&spmi->dev, sizeof(*q_clkdiv), GFP_ATOMIC);
+ if (!q_clkdiv)
+ return -ENOMEM;
+
+ rc = of_property_read_u32(node, "qcom,cxo-freq",
+ &q_clkdiv->cxo_hz);
+ if (rc) {
+ dev_err(&spmi->dev,
+ "%s: unable to get qcom,cxo-freq property\n", __func__);
+ return rc;
+ }
+
+ res = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&spmi->dev, "%s: unable to get device reg resource\n",
+ __func__);
+ }
+
+ q_clkdiv->slave = spmi->sid;
+ q_clkdiv->offset = res->start;
+ q_clkdiv->ctrl = spmi->ctrl;
+ q_clkdiv->node = node;
+ mutex_init(&q_clkdiv->lock);
+
+ rc = of_property_read_u32(node, "qcom,cxo-div",
+ &q_clkdiv->cxo_div);
+ if (rc && rc != -EINVAL) {
+ dev_err(&spmi->dev,
+ "%s: error getting qcom,cxo-div property\n",
+ __func__);
+ return rc;
+ }
+
+ if (!rc) {
+ rc = qpnp_clkdiv_config(q_clkdiv, q_clkdiv->cxo_div);
+ if (rc) {
+ dev_err(&spmi->dev,
+ "%s: unable to set default divide config\n",
+ __func__);
+ return rc;
+ }
+ }
+
+ rc = of_property_read_u32(node, "qcom,enable", &en);
+ if (rc && rc != -EINVAL) {
+ dev_err(&spmi->dev,
+ "%s: error getting qcom,enable property\n", __func__);
+ return rc;
+ }
+ if (!rc) {
+ rc = __clkdiv_enable(q_clkdiv, en);
+ dev_err(&spmi->dev,
+ "%s: unable to set default config\n", __func__);
+ return rc;
+ }
+
+ dev_set_drvdata(&spmi->dev, q_clkdiv);
+ list_add(&q_clkdiv->list, &qpnp_clkdiv_devs);
+
+ return 0;
+}
+
+static int __devexit qpnp_clkdiv_remove(struct spmi_device *spmi)
+{
+ struct q_clkdiv *q_clkdiv = dev_get_drvdata(&spmi->dev);
+ list_del(&q_clkdiv->list);
+ return 0;
+}
+
+static struct of_device_id spmi_match_table[] = {
+ { .compatible = "qcom,qpnp-clkdiv",
+ },
+ {}
+};
+
+static struct spmi_driver qpnp_clkdiv_driver = {
+ .driver = {
+ .name = "qcom,qpnp-clkdiv",
+ .of_match_table = spmi_match_table,
+ },
+ .probe = qpnp_clkdiv_probe,
+ .remove = __devexit_p(qpnp_clkdiv_remove),
+};
+
+static int __init qpnp_clkdiv_init(void)
+{
+ return spmi_driver_register(&qpnp_clkdiv_driver);
+}
+
+static void __exit qpnp_clkdiv_exit(void)
+{
+ return spmi_driver_unregister(&qpnp_clkdiv_driver);
+}
+
+MODULE_DESCRIPTION("QPNP PMIC clkdiv driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(qpnp_clkdiv_init);
+module_exit(qpnp_clkdiv_exit);
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index d8bb884..0119ebe 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -16,141 +16,635 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/spmi.h>
+#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/interrupt.h>
#include <linux/input.h>
+#include <linux/log2.h>
+/* PON common register addresses */
#define QPNP_PON_RT_STS(base) (base + 0x10)
#define QPNP_PON_PULL_CTL(base) (base + 0x70)
#define QPNP_PON_DBC_CTL(base) (base + 0x71)
-#define QPNP_PON_CNTL_PULL_UP BIT(1)
-#define QPNP_PON_CNTL_TRIG_DELAY_MASK (0x7)
+/* PON/RESET sources register addresses */
+#define QPNP_PON_KPDPWR_S1_TIMER(base) (base + 0x40)
+#define QPNP_PON_KPDPWR_S2_TIMER(base) (base + 0x41)
+#define QPNP_PON_KPDPWR_S2_CNTL(base) (base + 0x42)
+#define QPNP_PON_RESIN_S1_TIMER(base) (base + 0x44)
+#define QPNP_PON_RESIN_S2_TIMER(base) (base + 0x45)
+#define QPNP_PON_RESIN_S2_CNTL(base) (base + 0x46)
+
+#define QPNP_PON_RESIN_PULL_UP BIT(0)
+#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
+#define QPNP_PON_S2_CNTL_EN BIT(7)
+#define QPNP_PON_S2_RESET_ENABLE BIT(7)
+
+#define QPNP_PON_S1_TIMER_MASK (0xF)
+#define QPNP_PON_S2_TIMER_MASK (0x7)
+#define QPNP_PON_S2_CNTL_TYPE_MASK (0xF)
+
+#define QPNP_PON_DBC_DELAY_MASK (0x7)
#define QPNP_PON_KPDPWR_N_SET BIT(0)
+#define QPNP_PON_RESIN_N_SET BIT(1)
+#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
+
+/* Ranges */
+#define QPNP_PON_S1_TIMER_MAX 10256
+#define QPNP_PON_S2_TIMER_MAX 2000
+#define QPNP_PON_RESET_TYPE_MAX 0xF
+#define PON_S1_COUNT_MAX 0xF
+
+#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(500)
+
+enum pon_type {
+ PON_KPDPWR,
+ PON_RESIN,
+};
+
+struct qpnp_pon_config {
+ u32 pon_type;
+ u32 support_reset;
+ u32 key_code;
+ u32 s1_timer;
+ u32 s2_timer;
+ u32 s2_type;
+ u32 pull_up;
+ u32 state_irq;
+ u32 bark_irq;
+};
struct qpnp_pon {
struct spmi_device *spmi;
struct input_dev *pon_input;
- u32 key_status_irq;
+ struct qpnp_pon_config *pon_cfg;
+ int num_pon_config;
u16 base;
+ struct delayed_work bark_work;
};
-static irqreturn_t qpnp_pon_key_irq(int irq, void *_pon)
-{
- u8 pon_rt_sts;
- int rc;
- struct qpnp_pon *pon = _pon;
+static u32 s1_delay[PON_S1_COUNT_MAX + 1] = {
+ 0 , 32, 56, 80, 138, 184, 272, 408, 608, 904, 1352, 2048,
+ 3072, 4480, 6720, 10256
+};
+static int
+qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val)
+{
+ int rc;
+ u8 reg;
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ addr, ®, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read from addr=%x, rc(%d)\n", addr, rc);
+ return rc;
+ }
+
+ reg &= ~mask;
+ reg |= val & mask;
+ rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
+ addr, ®, 1);
+ if (rc)
+ dev_err(&pon->spmi->dev,
+ "Unable to write to addr=%x, rc(%d)\n", addr, rc);
+ return rc;
+}
+
+static struct qpnp_pon_config *
+qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
+{
+ int i;
+
+ for (i = 0; i < pon->num_pon_config; i++) {
+ if (pon_type == pon->pon_cfg[i].pon_type)
+ return &pon->pon_cfg[i];
+ }
+
+ return NULL;
+}
+
+static int
+qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type)
+{
+ int rc;
+ struct qpnp_pon_config *cfg = NULL;
+ u8 pon_rt_sts = 0, pon_rt_bit = 0;
+
+ cfg = qpnp_get_cfg(pon, pon_type);
+ if (!cfg)
+ return -EINVAL;
+
+ /* Check if key reporting is supported */
+ if (!cfg->key_code)
+ return 0;
+
+ /* check the RT status to get the current status of the line */
rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
if (rc) {
dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
- return IRQ_HANDLED;
+ return rc;
}
- input_report_key(pon->pon_input, KEY_POWER,
- !(pon_rt_sts & QPNP_PON_KPDPWR_N_SET));
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ pon_rt_bit = QPNP_PON_KPDPWR_N_SET;
+ break;
+ case PON_RESIN:
+ pon_rt_bit = QPNP_PON_RESIN_N_SET;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ input_report_key(pon->pon_input, cfg->key_code,
+ (pon_rt_sts & pon_rt_bit));
input_sync(pon->pon_input);
+ return 0;
+}
+
+static irqreturn_t qpnp_kpdpwr_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+
+ rc = qpnp_pon_input_dispatch(pon, PON_KPDPWR);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to send input event\n");
+
return IRQ_HANDLED;
}
-static int __devinit qpnp_pon_key_init(struct qpnp_pon *pon)
+static irqreturn_t qpnp_kpdpwr_bark_irq(int irq, void *_pon)
+{
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qpnp_resin_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+
+ rc = qpnp_pon_input_dispatch(pon, PON_RESIN);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to send input event\n");
+ return IRQ_HANDLED;
+}
+
+static void bark_work_func(struct work_struct *work)
+{
+ int rc;
+ u8 pon_rt_sts = 0;
+ struct qpnp_pon_config *cfg;
+ struct qpnp_pon *pon =
+ container_of(work, struct qpnp_pon, bark_work.work);
+
+ /* enable reset */
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
+ QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ goto err_return;
+ }
+ /* bark RT status update delay */
+ msleep(100);
+ /* read the bark RT status */
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
+ goto err_return;
+ }
+
+ if (!(pon_rt_sts & QPNP_PON_RESIN_BARK_N_SET)) {
+ cfg = qpnp_get_cfg(pon, PON_RESIN);
+ if (!cfg) {
+ dev_err(&pon->spmi->dev, "Invalid config pointer\n");
+ goto err_return;
+ }
+ /* report the key event and enable the bark IRQ */
+ input_report_key(pon->pon_input, cfg->key_code, 0);
+ input_sync(pon->pon_input);
+ enable_irq(cfg->bark_irq);
+ } else {
+ /* disable reset */
+ rc = qpnp_pon_masked_write(pon,
+ QPNP_PON_RESIN_S2_CNTL(pon->base),
+ QPNP_PON_S2_CNTL_EN, 0);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to configure S2 enable\n");
+ goto err_return;
+ }
+ /* re-arm the work */
+ schedule_delayed_work(&pon->bark_work, QPNP_KEY_STATUS_DELAY);
+ }
+
+err_return:
+ return;
+}
+
+static irqreturn_t qpnp_resin_bark_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+ struct qpnp_pon_config *cfg;
+
+ /* disable the bark interrupt */
+ disable_irq_nosync(irq);
+
+ /* disable reset */
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
+ QPNP_PON_S2_CNTL_EN, 0);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ goto err_exit;
+ }
+
+ cfg = qpnp_get_cfg(pon, PON_RESIN);
+ if (!cfg) {
+ dev_err(&pon->spmi->dev, "Invalid config pointer\n");
+ goto err_exit;
+ }
+
+ /* report the key event */
+ input_report_key(pon->pon_input, cfg->key_code, 1);
+ input_sync(pon->pon_input);
+ /* schedule work to check the bark status for key-release */
+ schedule_delayed_work(&pon->bark_work, QPNP_KEY_STATUS_DELAY);
+err_exit:
+ return IRQ_HANDLED;
+}
+
+static int __devinit
+qpnp_config_pull(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+ int rc;
+ u8 pull_bit;
+
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ pull_bit = QPNP_PON_KPDPWR_PULL_UP;
+ break;
+ case PON_RESIN:
+ pull_bit = QPNP_PON_RESIN_PULL_UP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_PULL_CTL(pon->base),
+ pull_bit, cfg->pull_up ? pull_bit : 0);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
+
+ return rc;
+}
+
+static int __devinit
+qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+ int rc;
+ u8 i;
+ u16 s1_timer_addr, s2_cntl_addr, s2_timer_addr;
+
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ s1_timer_addr = QPNP_PON_KPDPWR_S1_TIMER(pon->base);
+ s2_timer_addr = QPNP_PON_KPDPWR_S2_TIMER(pon->base);
+ s2_cntl_addr = QPNP_PON_KPDPWR_S2_CNTL(pon->base);
+ break;
+ case PON_RESIN:
+ s1_timer_addr = QPNP_PON_RESIN_S1_TIMER(pon->base);
+ s2_timer_addr = QPNP_PON_RESIN_S2_TIMER(pon->base);
+ s2_cntl_addr = QPNP_PON_RESIN_S2_CNTL(pon->base);
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* disable S2 reset */
+ rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ QPNP_PON_S2_CNTL_EN, 0);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ return rc;
+ }
+
+ usleep(100);
+
+ /* configure s1 timer, s2 timer and reset type */
+ for (i = 0; i < PON_S1_COUNT_MAX + 1; i++) {
+ if (cfg->s1_timer <= s1_delay[i])
+ break;
+ }
+ rc = qpnp_pon_masked_write(pon, s1_timer_addr,
+ QPNP_PON_S1_TIMER_MASK, i);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S1 timer\n");
+ return rc;
+ }
+
+ i = 0;
+ if (cfg->s2_timer) {
+ i = cfg->s2_timer / 10;
+ i = ilog2(i + 1);
+ }
+
+ rc = qpnp_pon_masked_write(pon, s2_timer_addr,
+ QPNP_PON_S2_TIMER_MASK, i);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 timer\n");
+ return rc;
+ }
+
+ rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 reset type\n");
+ return rc;
+ }
+
+ /* enable S2 reset */
+ rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int __devinit
+qpnp_pon_request_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
{
int rc = 0;
- u32 pullup, delay;
- u8 pon_cntl;
- pon->key_status_irq = spmi_get_irq_byname(pon->spmi,
- NULL, "power-key");
- if (pon->key_status_irq < 0) {
- dev_err(&pon->spmi->dev, "Unable to get pon key irq\n");
- return -ENXIO;
- }
-
- rc = of_property_read_u32(pon->spmi->dev.of_node,
- "qcom,pon-key-dbc-delay", &delay);
- if (rc) {
- delay = (delay << 6) / USEC_PER_SEC;
- delay = ilog2(delay);
-
- rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
- QPNP_PON_DBC_CTL(pon->base));
- return rc;
- }
- pon_cntl &= ~QPNP_PON_CNTL_TRIG_DELAY_MASK;
- pon_cntl |= (delay & QPNP_PON_CNTL_TRIG_DELAY_MASK);
- rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi write addre=%x failed\n",
- QPNP_PON_DBC_CTL(pon->base));
- return rc;
- }
- }
-
- rc = of_property_read_u32(pon->spmi->dev.of_node,
- "qcom,pon-key-pull-up", &pullup);
- if (!rc) {
- rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
- QPNP_PON_PULL_CTL(pon->base));
- return rc;
- }
- if (pullup)
- pon_cntl |= QPNP_PON_CNTL_PULL_UP;
- else
- pon_cntl &= ~QPNP_PON_CNTL_PULL_UP;
-
- rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi write addr=%x failed\n",
- QPNP_PON_PULL_CTL(pon->base));
- return rc;
- }
- }
-
- pon->pon_input = input_allocate_device();
- if (!pon->pon_input) {
- dev_err(&pon->spmi->dev, "Can't allocate pon button\n");
- return -ENOMEM;
- }
-
- input_set_capability(pon->pon_input, EV_KEY, KEY_POWER);
- pon->pon_input->name = "qpnp_pon_key";
- pon->pon_input->phys = "qpnp_pon_key/input0";
-
- rc = input_register_device(pon->pon_input);
- if (rc) {
- dev_err(&pon->spmi->dev, "Can't register pon key: %d\n", rc);
- goto free_input_dev;
- }
-
- rc = request_any_context_irq(pon->key_status_irq, qpnp_pon_key_irq,
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+ qpnp_kpdpwr_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "qpnp_pon_key_status", pon);
- if (rc < 0) {
- dev_err(&pon->spmi->dev, "Can't request %d IRQ for pon: %d\n",
- pon->key_status_irq, rc);
- goto unreg_input_dev;
+ "qpnp_kpdpwr_status", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+ cfg->state_irq);
+ return rc;
+ }
+ if (cfg->support_reset) {
+ rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
+ qpnp_kpdpwr_bark_irq,
+ IRQF_TRIGGER_RISING,
+ "qpnp_kpdpwr_bark", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev,
+ "Can't request %d IRQ\n",
+ cfg->bark_irq);
+ return rc;
+ }
+ }
+ break;
+ case PON_RESIN:
+ rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+ qpnp_resin_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "qpnp_resin_status", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+ cfg->state_irq);
+ return rc;
+ }
+ if (cfg->support_reset) {
+ rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
+ qpnp_resin_bark_irq,
+ IRQF_TRIGGER_RISING,
+ "qpnp_resin_bark", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev,
+ "Can't request %d IRQ\n",
+ cfg->bark_irq);
+ return rc;
+ }
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int __devinit
+qpnp_pon_config_input(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+ if (!pon->pon_input) {
+ pon->pon_input = input_allocate_device();
+ if (!pon->pon_input) {
+ dev_err(&pon->spmi->dev,
+ "Can't allocate pon input device\n");
+ return -ENOMEM;
+ }
+ pon->pon_input->name = "qpnp_pon";
+ pon->pon_input->phys = "qpnp_pon/input0";
+ }
+
+ input_set_capability(pon->pon_input, EV_KEY, cfg->key_code);
+
+ return 0;
+}
+
+static int __devinit qpnp_pon_config_init(struct qpnp_pon *pon)
+{
+ int rc = 0, i = 0;
+ struct device_node *pp = NULL;
+ struct qpnp_pon_config *cfg;
+
+ /* iterate through the list of pon configs */
+ while ((pp = of_get_next_child(pon->spmi->dev.of_node, pp))) {
+
+ cfg = &pon->pon_cfg[i++];
+
+ rc = of_property_read_u32(pp, "qcom,pon-type", &cfg->pon_type);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "PON type not specified\n");
+ return rc;
+ }
+
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "kpdpwr");
+ if (cfg->state_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get kpdpwr irq\n");
+ return cfg->state_irq;
+ }
+
+ rc = of_property_read_u32(pp, "qcom,support-reset",
+ &cfg->support_reset);
+ if (rc && rc != -EINVAL) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read 'support-reset'\n");
+ return rc;
+ }
+
+ if (cfg->support_reset) {
+ cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "kpdpwr-bark");
+ if (cfg->bark_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get kpdpwr-bark irq\n");
+ return cfg->bark_irq;
+ }
+ }
+ break;
+ case PON_RESIN:
+ cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "resin");
+ if (cfg->state_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get resin irq\n");
+ return cfg->bark_irq;
+ }
+
+ rc = of_property_read_u32(pp, "qcom,support-reset",
+ &cfg->support_reset);
+ if (rc && rc != -EINVAL) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read 'support-reset'\n");
+ return rc;
+ }
+
+ if (cfg->support_reset) {
+ cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "resin-bark");
+ if (cfg->bark_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get resin-bark irq\n");
+ return cfg->bark_irq;
+ }
+ }
+ break;
+ default:
+ dev_err(&pon->spmi->dev, "PON RESET %d not supported",
+ cfg->pon_type);
+ return -EINVAL;
+ }
+
+ if (cfg->support_reset) {
+ /*
+ * Get the reset parameters (bark debounce time and
+ * reset debounce time) for the reset line.
+ */
+ rc = of_property_read_u32(pp, "qcom,s1-timer",
+ &cfg->s1_timer);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read s1-timer\n");
+ return rc;
+ }
+ if (cfg->s1_timer > QPNP_PON_S1_TIMER_MAX) {
+ dev_err(&pon->spmi->dev,
+ "Incorrect S1 debounce time\n");
+ return -EINVAL;
+ }
+ rc = of_property_read_u32(pp, "qcom,s2-timer",
+ &cfg->s2_timer);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read s2-timer\n");
+ return rc;
+ }
+ if (cfg->s2_timer > QPNP_PON_S2_TIMER_MAX) {
+ dev_err(&pon->spmi->dev,
+ "Incorrect S2 debounce time\n");
+ return -EINVAL;
+ }
+ rc = of_property_read_u32(pp, "qcom,s2-type",
+ &cfg->s2_type);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read s2-type\n");
+ return rc;
+ }
+ if (cfg->s2_type > QPNP_PON_RESET_TYPE_MAX) {
+ dev_err(&pon->spmi->dev,
+ "Incorrect reset type specified\n");
+ return -EINVAL;
+ }
+ }
+ /*
+ * Get the standard-key parameters. This might not be
+ * specified if there is no key mapping on the reset line.
+ */
+ rc = of_property_read_u32(pp, "linux,code", &cfg->key_code);
+ if (rc && rc == -EINVAL) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read key-code\n");
+ return rc;
+ }
+ /* Register key configuration */
+ if (cfg->key_code) {
+ rc = qpnp_pon_config_input(pon, cfg);
+ if (rc < 0)
+ return rc;
+ }
+ /* get the pull-up configuration */
+ rc = of_property_read_u32(pp, "qcom,pull-up", &cfg->pull_up);
+ if (rc && rc != -EINVAL) {
+ dev_err(&pon->spmi->dev, "Unable to read pull-up\n");
+ return rc;
+ }
+ }
+
+ /* register the input device */
+ if (pon->pon_input) {
+ rc = input_register_device(pon->pon_input);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Can't register pon key: %d\n", rc);
+ goto free_input_dev;
+ }
+ }
+
+ for (i = 0; i < pon->num_pon_config; i++) {
+ cfg = &pon->pon_cfg[i];
+ /* Configure the pull-up */
+ rc = qpnp_config_pull(pon, cfg);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
+ goto unreg_input_dev;
+ }
+ /* Configure the reset-configuration */
+ if (cfg->support_reset) {
+ rc = qpnp_config_reset(pon, cfg);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to config pon reset\n");
+ goto unreg_input_dev;
+ }
+ }
+ rc = qpnp_pon_request_irqs(pon, cfg);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to request-irq's\n");
+ goto unreg_input_dev;
+ }
}
device_init_wakeup(&pon->spmi->dev, 1);
- enable_irq_wake(pon->key_status_irq);
return rc;
unreg_input_dev:
- input_unregister_device(pon->pon_input);
+ if (pon->pon_input)
+ input_unregister_device(pon->pon_input);
free_input_dev:
- input_free_device(pon->pon_input);
+ if (pon->pon_input)
+ input_free_device(pon->pon_input);
return rc;
}
@@ -158,7 +652,8 @@
{
struct qpnp_pon *pon;
struct resource *pon_resource;
- u32 pon_key_enable = 0;
+ struct device_node *itr = NULL;
+ u32 delay = 0;
int rc = 0;
pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
@@ -170,6 +665,20 @@
pon->spmi = spmi;
+ /* get the total number of pon configurations */
+ while ((itr = of_get_next_child(spmi->dev.of_node, itr)))
+ pon->num_pon_config++;
+
+ if (!pon->num_pon_config) {
+ /* No PON config., do not register the driver */
+ dev_err(&spmi->dev, "No PON config. specified\n");
+ return -EINVAL;
+ }
+
+ pon->pon_cfg = devm_kzalloc(&spmi->dev,
+ sizeof(struct qpnp_pon_config) * pon->num_pon_config,
+ GFP_KERNEL);
+
pon_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
if (!pon_resource) {
dev_err(&spmi->dev, "Unable to get PON base address\n");
@@ -177,36 +686,45 @@
}
pon->base = pon_resource->start;
- dev_set_drvdata(&spmi->dev, pon);
-
- /* pon-key-enable property must be set to register pon key */
- rc = of_property_read_u32(spmi->dev.of_node, "qcom,pon-key-enable",
- &pon_key_enable);
+ rc = of_property_read_u32(pon->spmi->dev.of_node,
+ "qcom,pon-dbc-delay", &delay);
if (rc && rc != -EINVAL) {
- dev_err(&spmi->dev,
- "Error reading 'pon-key-enable' property (%d)", rc);
+ dev_err(&spmi->dev, "Unable to read debounce delay\n");
return rc;
- }
-
- if (pon_key_enable) {
- rc = qpnp_pon_key_init(pon);
- if (rc < 0) {
- dev_err(&spmi->dev, "Failed to register pon-key\n");
+ } else {
+ delay = (delay << 6) / USEC_PER_SEC;
+ delay = ilog2(delay);
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
+ QPNP_PON_DBC_DELAY_MASK, delay);
+ if (rc) {
+ dev_err(&spmi->dev, "Unable to set PON debounce\n");
return rc;
}
}
- return 0;
+ dev_set_drvdata(&spmi->dev, pon);
+
+ INIT_DELAYED_WORK(&pon->bark_work, bark_work_func);
+
+ /* register the PON configurations */
+ rc = qpnp_pon_config_init(pon);
+ if (rc) {
+ dev_err(&spmi->dev,
+ "Unable to intialize PON configurations\n");
+ return rc;
+ }
+
+ return rc;
}
static int qpnp_pon_remove(struct spmi_device *spmi)
{
struct qpnp_pon *pon = dev_get_drvdata(&spmi->dev);
- if (pon->pon_input) {
- free_irq(pon->key_status_irq, pon);
+ cancel_delayed_work_sync(&pon->bark_work);
+
+ if (pon->pon_input)
input_unregister_device(pon->pon_input);
- }
return 0;
}
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 31b405a..7924578 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -643,10 +643,10 @@
*/
int bam_init(void *base, u32 ee,
u16 summing_threshold,
- u32 irq_mask, u32 *version, u32 *num_pipes)
+ u32 irq_mask, u32 *version,
+ u32 *num_pipes, u32 p_rst)
{
- /* disable bit#11 because of HW bug */
- u32 cfg_bits = 0xffffffff & ~(1 << 11);
+ u32 cfg_bits;
u32 ver = 0;
SPS_DBG2("sps:%s:bam=0x%x(va).ee=%d.", __func__, (u32) base, ee);
@@ -658,7 +658,7 @@
(u32) base, ver);
return -ENODEV;
} else
- SPS_INFO("sps:REVISION of BAM 0x%x is 0x%x.\n",
+ SPS_DBG2("sps:REVISION of BAM 0x%x is 0x%x.\n",
(u32) base, ver);
if (summing_threshold == 0) {
@@ -667,6 +667,11 @@
"use default 4.\n", (u32) base);
}
+ if (p_rst)
+ cfg_bits = 0xffffffff & ~(3 << 11);
+ else
+ cfg_bits = 0xffffffff & ~(1 << 11);
+
bam_write_reg_field(base, CTRL, BAM_SW_RST, 1);
/* No delay needed */
bam_write_reg_field(base, CTRL, BAM_SW_RST, 0);
diff --git a/drivers/platform/msm/sps/bam.h b/drivers/platform/msm/sps/bam.h
index 3521ffa..c183fcd 100644
--- a/drivers/platform/msm/sps/bam.h
+++ b/drivers/platform/msm/sps/bam.h
@@ -102,13 +102,16 @@
*
* @num_pipes - return number of pipes
*
+ * @p_rst - ignore external block pipe reset
+ *
* @return 0 on success, negative value on error
*
*/
int bam_init(void *base,
u32 ee,
u16 summing_threshold,
- u32 irq_mask, u32 *version, u32 *num_pipes);
+ u32 irq_mask, u32 *version,
+ u32 *num_pipes, u32 p_rst);
/**
* Initialize BAM device security execution environment
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index 245ccd2..e3be11d 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -254,7 +254,8 @@
dev->props.ee,
(u16) dev->props.summing_threshold,
irq_mask,
- &dev->version, &num_pipes);
+ &dev->version, &num_pipes,
+ dev->props.options & SPS_BAM_NO_EXT_P_RST);
else
/* No, so just verify that it is enabled */
rc = bam_check(dev->base, &dev->version, &num_pipes);
@@ -401,7 +402,7 @@
}
dev->state |= BAM_STATE_ENABLED;
- SPS_DBG2("sps:BAM 0x%x enabled: ver: %d, number of pipes: %d",
+ SPS_INFO("sps:BAM 0x%x enabled: ver:0x%x, number of pipes:%d",
BAM_ID(dev), dev->version, dev->props.num_pipes);
return 0;
}
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index b7c73de..a347984 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <linux/io.h>
#include <linux/stat.h>
#include <linux/module.h>
@@ -23,6 +24,7 @@
#include <mach/usb_bam.h>
#include <mach/sps.h>
#include <linux/workqueue.h>
+#include <linux/dma-mapping.h>
#define USB_SUMMING_THRESHOLD 512
#define CONNECTIONS_NUM 4
@@ -53,26 +55,22 @@
static struct usb_bam_connect_info usb_bam_connections[CONNECTIONS_NUM];
static struct usb_bam_pipe_connect ***msm_usb_bam_connections_info;
static struct usb_bam_pipe_connect *bam_connection_arr;
-
-static bool device_tree_enabled;
-
-static inline int bam_offset(struct msm_usb_bam_platform_data *pdata)
-{
- return pdata->usb_active_bam * CONNECTIONS_NUM * 2;
-}
+void __iomem *qscratch_ram1_reg;
+struct clk *mem_clk;
+struct clk *mem_iface_clk;
static int connect_pipe(u8 conn_idx, enum usb_bam_pipe_dir pipe_dir,
u32 *usb_pipe_idx)
{
- int ret;
+ int ret, ram1_value;
struct sps_pipe **pipe = &sps_pipes[conn_idx][pipe_dir];
struct sps_connect *connection =
&sps_connections[conn_idx][pipe_dir];
struct msm_usb_bam_platform_data *pdata =
usb_bam_pdev->dev.platform_data;
struct usb_bam_pipe_connect *pipe_connection =
- (struct usb_bam_pipe_connect *)(pdata->connections +
- bam_offset(pdata) + (2*conn_idx+pipe_dir));
+ &msm_usb_bam_connections_info
+ [pdata->usb_active_bam][conn_idx][pipe_dir];
*pipe = sps_alloc_endpoint();
if (*pipe == NULL) {
@@ -83,13 +81,13 @@
ret = sps_get_config(*pipe, connection);
if (ret) {
pr_err("%s: tx get config failed %d\n", __func__, ret);
- goto get_config_failed;
+ goto free_sps_endpoint;
}
ret = sps_phy2h(pipe_connection->src_phy_addr, &(connection->source));
if (ret) {
pr_err("%s: sps_phy2h failed (src BAM) %d\n", __func__, ret);
- goto get_config_failed;
+ goto free_sps_endpoint;
}
connection->src_pipe_index = pipe_connection->src_pipe_index;
@@ -97,7 +95,7 @@
&(connection->destination));
if (ret) {
pr_err("%s: sps_phy2h failed (dst BAM) %d\n", __func__, ret);
- goto get_config_failed;
+ goto free_sps_endpoint;
}
connection->dest_pipe_index = pipe_connection->dst_pipe_index;
@@ -109,7 +107,9 @@
*usb_pipe_idx = connection->dest_pipe_index;
}
- if (!device_tree_enabled) {
+ /* If BAM is using dedicated SPS pipe memory, get it */
+ if (pipe_connection->mem_type == SPS_PIPE_MEM) {
+ pr_debug("%s: USB BAM using SPS pipe memory\n", __func__);
ret = sps_setup_bam2bam_fifo(
&data_mem_buf[conn_idx][pipe_dir],
pipe_connection->data_fifo_base_offset,
@@ -117,7 +117,7 @@
if (ret) {
pr_err("%s: data fifo setup failure %d\n", __func__,
ret);
- goto fifo_setup_error;
+ goto free_sps_endpoint;
}
ret = sps_setup_bam2bam_fifo(
@@ -127,9 +127,33 @@
if (ret) {
pr_err("%s: desc. fifo setup failure %d\n", __func__,
ret);
- goto fifo_setup_error;
+ goto free_sps_endpoint;
}
- } else {
+ } else if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+ pr_debug("%s: USB BAM using private memory\n", __func__);
+
+ if (IS_ERR(mem_clk) || IS_ERR(mem_iface_clk)) {
+ pr_err("%s: Failed to enable USB mem_clk\n", __func__);
+ ret = IS_ERR(mem_clk);
+ goto free_sps_endpoint;
+ }
+
+ clk_prepare_enable(mem_clk);
+ clk_prepare_enable(mem_iface_clk);
+
+ /*
+ * Enable USB PRIVATE RAM to be used for BAM FIFOs
+ * HSUSB: Only RAM13 is used for BAM FIFOs
+ * SSUSB: RAM11, 12, 13 are used for BAM FIFOs
+ */
+ if (pdata->usb_active_bam == HSUSB_BAM)
+ ram1_value = 0x4;
+ else
+ ram1_value = 0x7;
+
+ pr_debug("Writing 0x%x to QSCRATCH_RAM1\n", ram1_value);
+ writel_relaxed(ram1_value, qscratch_ram1_reg);
+
data_mem_buf[conn_idx][pipe_dir].phys_base =
pipe_connection->data_fifo_base_offset +
pdata->usb_base_address;
@@ -151,6 +175,28 @@
desc_mem_buf[conn_idx][pipe_dir].size);
memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
desc_mem_buf[conn_idx][pipe_dir].size);
+ } else {
+ pr_debug("%s: USB BAM using system memory\n", __func__);
+ /* BAM would use system memory, allocate FIFOs */
+ data_mem_buf[conn_idx][pipe_dir].size =
+ pipe_connection->data_fifo_size;
+ data_mem_buf[conn_idx][pipe_dir].base =
+ dma_alloc_coherent(&usb_bam_pdev->dev,
+ pipe_connection->data_fifo_size,
+ &data_mem_buf[conn_idx][pipe_dir].phys_base,
+ 0);
+ memset(data_mem_buf[conn_idx][pipe_dir].base, 0,
+ pipe_connection->data_fifo_size);
+
+ desc_mem_buf[conn_idx][pipe_dir].size =
+ pipe_connection->desc_fifo_size;
+ desc_mem_buf[conn_idx][pipe_dir].base =
+ dma_alloc_coherent(&usb_bam_pdev->dev,
+ pipe_connection->desc_fifo_size,
+ &desc_mem_buf[conn_idx][pipe_dir].phys_base,
+ 0);
+ memset(desc_mem_buf[conn_idx][pipe_dir].base, 0,
+ pipe_connection->desc_fifo_size);
}
connection->data = data_mem_buf[conn_idx][pipe_dir];
@@ -167,8 +213,7 @@
error:
sps_disconnect(*pipe);
-fifo_setup_error:
-get_config_failed:
+free_sps_endpoint:
sps_free_endpoint(*pipe);
return ret;
}
@@ -177,6 +222,11 @@
static int disconnect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir,
u32 *usb_pipe_idx)
{
+ struct msm_usb_bam_platform_data *pdata =
+ usb_bam_pdev->dev.platform_data;
+ struct usb_bam_pipe_connect *pipe_connection =
+ &msm_usb_bam_connections_info
+ [pdata->usb_active_bam][connection_idx][pipe_dir];
struct sps_pipe *pipe = sps_pipes[connection_idx][pipe_dir];
struct sps_connect *connection =
&sps_connections[connection_idx][pipe_dir];
@@ -184,6 +234,21 @@
sps_disconnect(pipe);
sps_free_endpoint(pipe);
+ if (pipe_connection->mem_type == SYSTEM_MEM) {
+ pr_debug("%s: Freeing system memory used by PIPE\n", __func__);
+ dma_free_coherent(&usb_bam_pdev->dev, connection->data.size,
+ connection->data.base, connection->data.phys_base);
+ dma_free_coherent(&usb_bam_pdev->dev, connection->desc.size,
+ connection->desc.base, connection->desc.phys_base);
+ } else if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+ pr_debug("Freeing USB private memory used by BAM PIPE\n");
+ writel_relaxed(0x0, qscratch_ram1_reg);
+ iounmap(connection->data.base);
+ iounmap(connection->desc.base);
+ clk_disable_unprepare(mem_clk);
+ clk_disable_unprepare(mem_iface_clk);
+ }
+
connection->options &= ~SPS_O_AUTO_ENABLE;
return 0;
}
@@ -328,7 +393,7 @@
}
static int update_connections_info(struct device_node *node, int bam,
- int conn_num, int dir)
+ int conn_num, int dir, enum usb_pipe_mem_type mem_type)
{
u32 rc;
char *key = NULL;
@@ -338,6 +403,8 @@
pipe_connection = &msm_usb_bam_connections_info[bam][conn_num][dir];
+ pipe_connection->mem_type = mem_type;
+
key = "qcom,src-bam-physical-address";
rc = of_property_read_u32(node, key, &val);
if (rc)
@@ -394,18 +461,49 @@
return -EFAULT;
}
+static int usb_bam_update_conn_array_index(struct platform_device *pdev,
+ void *buff, int bam_max, int conn_max, int pipe_dirs)
+{
+ int bam_num, conn_num;
+ struct usb_bam_pipe_connect *bam_connection_arr = buff;
+
+ msm_usb_bam_connections_info = devm_kzalloc(&pdev->dev,
+ bam_max * sizeof(struct usb_bam_pipe_connect **),
+ GFP_KERNEL);
+
+ if (!msm_usb_bam_connections_info)
+ return -ENOMEM;
+
+ for (bam_num = 0; bam_num < bam_max; bam_num++) {
+ msm_usb_bam_connections_info[bam_num] =
+ devm_kzalloc(&pdev->dev, conn_max *
+ sizeof(struct usb_bam_pipe_connect *),
+ GFP_KERNEL);
+ if (!msm_usb_bam_connections_info[bam_num])
+ return -ENOMEM;
+
+ for (conn_num = 0; conn_num < conn_max; conn_num++)
+ msm_usb_bam_connections_info[bam_num][conn_num] =
+ bam_connection_arr +
+ (bam_num * conn_max * pipe_dirs) +
+ (conn_num * pipe_dirs);
+ }
+
+ return 0;
+}
+
static struct msm_usb_bam_platform_data *usb_bam_dt_to_pdata(
struct platform_device *pdev)
{
struct msm_usb_bam_platform_data *pdata;
struct device_node *node = pdev->dev.of_node;
- u32 i, j;
int conn_num, bam;
u8 dir;
u8 ncolumns = 2;
int bam_amount, rc = 0;
u32 pipe_entry = 0;
char *key = NULL;
+ enum usb_pipe_mem_type mem_type;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
@@ -451,79 +549,79 @@
conn_num = pipe_entry / 2;
bam_amount = pdata->total_bam_num;
- if (conn_num > 0 && conn_num < pdata->usb_bam_num_pipes) {
- /* alloc msm_usb_bam_connections_info */
- bam_connection_arr = devm_kzalloc(&pdev->dev, bam_amount *
- conn_num * ncolumns *
- sizeof(struct usb_bam_pipe_connect), GFP_KERNEL);
-
- if (!bam_connection_arr)
- goto err;
-
- msm_usb_bam_connections_info = devm_kzalloc(&pdev->dev,
- bam_amount * sizeof(struct usb_bam_pipe_connect **),
- GFP_KERNEL);
-
- if (!msm_usb_bam_connections_info)
- goto err;
-
- for (j = 0; j < bam_amount; j++) {
- msm_usb_bam_connections_info[j] =
- devm_kzalloc(&pdev->dev, conn_num *
- sizeof(struct usb_bam_pipe_connect *),
- GFP_KERNEL);
- for (i = 0; i < conn_num; i++)
- msm_usb_bam_connections_info[j][i] =
- bam_connection_arr +
- (j * conn_num * ncolumns) +
- (i * ncolumns);
- }
-
- /* retrieve device tree parameters */
- for_each_child_of_node(pdev->dev.of_node, node) {
- const char *str;
-
- key = "qcom,usb-bam-type";
- rc = of_property_read_u32(node, key, &bam);
- if (rc)
- goto err;
-
- rc = of_property_read_string(node, "label", &str);
- if (rc) {
- pr_err("Cannot read string\n");
- goto err;
- }
-
- if (strstr(str, "usb-to-peri"))
- dir = USB_TO_PEER_PERIPHERAL;
- else if (strstr(str, "peri-to-usb"))
- dir = PEER_PERIPHERAL_TO_USB;
- else
- goto err;
-
- if (!strcmp(str, "usb-to-peri-qdss-dwc3") ||
- !strcmp(str, "peri-to-usb-qdss-dwc3"))
- conn_num = 0;
- else
- goto err;
-
- rc = update_connections_info(node, bam, conn_num, dir);
- if (rc)
- goto err;
- }
-
- pdata->connections = &msm_usb_bam_connections_info[0][0][0];
-
- } else {
+ if (conn_num <= 0 || conn_num >= pdata->usb_bam_num_pipes)
goto err;
+
+
+ /* alloc msm_usb_bam_connections_info */
+ bam_connection_arr = devm_kzalloc(&pdev->dev, bam_amount *
+ conn_num * ncolumns *
+ sizeof(struct usb_bam_pipe_connect), GFP_KERNEL);
+
+ if (!bam_connection_arr)
+ goto err;
+
+ rc = usb_bam_update_conn_array_index(pdev, bam_connection_arr,
+ bam_amount, conn_num, ncolumns);
+ if (rc)
+ goto err;
+
+ /* retrieve device tree parameters */
+ for_each_child_of_node(pdev->dev.of_node, node) {
+ const char *str;
+
+ key = "qcom,usb-bam-type";
+ rc = of_property_read_u32(node, key, &bam);
+ if (rc)
+ goto err;
+
+ key = "qcom,usb-bam-mem-type";
+ rc = of_property_read_u32(node, key, &mem_type);
+ if (rc)
+ goto err;
+
+ rc = of_property_read_string(node, "label", &str);
+ if (rc) {
+ pr_err("Cannot read string\n");
+ goto err;
+ }
+
+ if (strstr(str, "usb-to-peri"))
+ dir = USB_TO_PEER_PERIPHERAL;
+ else if (strstr(str, "peri-to-usb"))
+ dir = PEER_PERIPHERAL_TO_USB;
+ else
+ goto err;
+
+ /* Check if connection type is suported */
+ if (!strcmp(str, "usb-to-peri-qdss-dwc3") ||
+ !strcmp(str, "peri-to-usb-qdss-dwc3") ||
+ !strcmp(str, "usb-to-peri-qdss-hsusb") ||
+ !strcmp(str, "peri-to-usb-qdss-hsusb"))
+ conn_num = 0;
+ else
+ goto err;
+
+ rc = update_connections_info(node, bam, conn_num,
+ dir, mem_type);
+ if (rc)
+ goto err;
}
+ pdata->connections = &msm_usb_bam_connections_info[0][0][0];
+
return pdata;
err:
pr_err("%s: failed\n", __func__);
return NULL;
}
+static char *bam_enable_strings[3] = {
+ [SSUSB_BAM] = "ssusb",
+ [HSUSB_BAM] = "hsusb",
+ [HSIC_BAM] = "hsic",
+};
+
static int usb_bam_init(void)
{
u32 h_usb;
@@ -531,27 +629,54 @@
void *usb_virt_addr;
struct msm_usb_bam_platform_data *pdata =
usb_bam_pdev->dev.platform_data;
- struct resource *res;
+ struct usb_bam_pipe_connect *pipe_connection =
+ &msm_usb_bam_connections_info[pdata->usb_active_bam][0][0];
+ struct resource *res, *ram_resource;
int irq;
- res = platform_get_resource(usb_bam_pdev, IORESOURCE_MEM,
- pdata->usb_active_bam);
+ res = platform_get_resource_byname(usb_bam_pdev, IORESOURCE_MEM,
+ bam_enable_strings[pdata->usb_active_bam]);
if (!res) {
dev_err(&usb_bam_pdev->dev, "Unable to get memory resource\n");
return -ENODEV;
}
- irq = platform_get_irq(usb_bam_pdev, pdata->usb_active_bam);
+ irq = platform_get_irq_byname(usb_bam_pdev,
+ bam_enable_strings[pdata->usb_active_bam]);
if (irq < 0) {
dev_err(&usb_bam_pdev->dev, "Unable to get IRQ resource\n");
return irq;
}
- usb_virt_addr = ioremap(res->start, resource_size(res));
+ usb_virt_addr = devm_ioremap(&usb_bam_pdev->dev, res->start,
+ resource_size(res));
if (!usb_virt_addr) {
pr_err("%s: ioremap failed\n", __func__);
return -ENOMEM;
}
+
+ /* Check if USB3 pipe memory needs to be enabled */
+ if (pipe_connection->mem_type == USB_PRIVATE_MEM) {
+ pr_debug("%s: Enabling USB private memory for: %s\n", __func__,
+ bam_enable_strings[pdata->usb_active_bam]);
+
+ ram_resource = platform_get_resource_byname(usb_bam_pdev,
+ IORESOURCE_MEM, "qscratch_ram1_reg");
+ if (!res) {
+ dev_err(&usb_bam_pdev->dev, "Unable to get qscratch\n");
+ ret = -ENODEV;
+ goto free_bam_regs;
+ }
+
+ qscratch_ram1_reg = devm_ioremap(&usb_bam_pdev->dev,
+ ram_resource->start,
+ resource_size(ram_resource));
+ if (!qscratch_ram1_reg) {
+ pr_err("%s: ioremap failed for qscratch\n", __func__);
+ ret = -ENOMEM;
+ goto free_bam_regs;
+ }
+ }
usb_props.phys_addr = res->start;
usb_props.virt_addr = usb_virt_addr;
usb_props.virt_size = resource_size(res);
@@ -563,16 +688,19 @@
ret = sps_register_bam_device(&usb_props, &h_usb);
if (ret < 0) {
pr_err("%s: register bam error %d\n", __func__, ret);
- return -EFAULT;
+ ret = -EFAULT;
+ goto free_qscratch_reg;
}
return 0;
-}
-static char *bam_enable_strings[2] = {
- [HSUSB_BAM] = "hsusb",
- [HSIC_BAM] = "hsic",
-};
+free_qscratch_reg:
+ iounmap(qscratch_ram1_reg);
+free_bam_regs:
+ iounmap(usb_virt_addr);
+
+ return ret;
+}
static ssize_t
usb_bam_show_enable(struct device *dev, struct device_attribute *attr,
@@ -636,9 +764,16 @@
usb_bam_wake_work);
}
+ mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
+ if (IS_ERR(mem_clk))
+ dev_dbg(&pdev->dev, "failed to get mem_clock\n");
+
+ mem_iface_clk = devm_clk_get(&pdev->dev, "mem_iface_clk");
+ if (IS_ERR(mem_iface_clk))
+ dev_dbg(&pdev->dev, "failed to get mem_iface_clock\n");
+
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
- device_tree_enabled = 1;
pdata = usb_bam_dt_to_pdata(pdev);
if (!pdata)
return -ENOMEM;
@@ -648,7 +783,12 @@
return -ENODEV;
} else {
pdata = pdev->dev.platform_data;
- device_tree_enabled = 0;
+ ret = usb_bam_update_conn_array_index(pdev, pdata->connections,
+ MAX_BAMS, CONNECTIONS_NUM, 2);
+ if (ret) {
+ pr_err("usb_bam_update_conn_array_index failed\n");
+ return ret;
+ }
}
usb_bam_pdev = pdev;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 304dc6b..2868d61 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -20,6 +20,7 @@
#include <linux/mfd/pm8xxx/pm8921-bms.h>
#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
+#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/ccadc.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
@@ -27,6 +28,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/rtc.h>
#define BMS_CONTROL 0x224
#define BMS_S1_DELAY 0x225
@@ -49,6 +51,9 @@
#define TEMP_SOC_STORAGE 0x107
+#define TEMP_IAVG_STORAGE 0x105
+#define TEMP_IAVG_STORAGE_USE_MASK 0x0F
+
enum pmic_bms_interrupts {
PM8921_BMS_SBI_WRITE_OK,
PM8921_BMS_CC_THR,
@@ -67,16 +72,6 @@
int last_good_ocv_uv;
};
-struct pm8921_rbatt_params {
- uint16_t ocv_for_rbatt_raw;
- uint16_t vsense_for_rbatt_raw;
- uint16_t vbatt_for_rbatt_raw;
-
- int ocv_for_rbatt_uv;
- int vsense_for_rbatt_uv;
- int vbatt_for_rbatt_uv;
-};
-
/**
* struct pm8921_bms_chip -
* @bms_output_lock: lock to prevent concurrent bms reads
@@ -92,8 +87,7 @@
struct device *dev;
struct dentry *dent;
unsigned int r_sense;
- unsigned int i_test;
- unsigned int v_failure;
+ unsigned int v_cutoff;
unsigned int fcc;
struct single_row_lut *fcc_temp_lut;
struct single_row_lut *fcc_sf_lut;
@@ -102,6 +96,8 @@
struct sf_lut *rbatt_sf_lut;
int delta_rbatt_mohm;
struct work_struct calib_hkadc_work;
+ struct delayed_work calib_hkadc_delayed_work;
+ struct mutex calib_mutex;
unsigned int revision;
unsigned int xoadc_v0625_usb_present;
unsigned int xoadc_v0625_usb_absent;
@@ -119,29 +115,45 @@
unsigned int charging_began;
unsigned int start_percent;
unsigned int end_percent;
+ int charge_time_us;
+ int catch_up_time_us;
enum battery_type batt_type;
uint16_t ocv_reading_at_100;
int cc_reading_at_100;
int max_voltage_uv;
- int batt_temp_suspend;
- int soc_rbatt_suspend;
+ int chg_term_ua;
int default_rbatt_mohm;
int amux_2_trim_delta;
uint16_t prev_last_good_ocv_raw;
unsigned int rconn_mohm;
struct mutex last_ocv_uv_mutex;
int last_ocv_uv;
+ int pon_ocv_uv;
int last_cc_uah;
- struct timeval t;
- int last_uuc_uah;
+ unsigned long tm_sec;
int enable_fcc_learning;
int shutdown_soc;
- int timer_uuc_expired;
- struct delayed_work uuc_timer_work;
- int uuc_uah_iavg_prev;
+ int shutdown_iavg_ua;
+ struct delayed_work calculate_soc_delayed_work;
+ struct timespec t_soc_queried;
+ int shutdown_soc_valid_limit;
+ int ignore_shutdown_soc;
+ int prev_iavg_ua;
+ int prev_uuc_iavg_ma;
+ int prev_pc_unusable;
+ int adjust_soc_low_threshold;
+
+ int ibat_at_cv_ua;
+ int soc_at_cv;
+ int prev_chg_soc;
};
+/*
+ * protects against simultaneous adjustment of ocv based on shutdown soc and
+ * invalidating the shutdown soc
+ */
+static DEFINE_MUTEX(soc_invalidation_mutex);
static int shutdown_soc_invalid;
static struct pm8921_bms_chip *the_chip;
@@ -157,7 +169,7 @@
module_param(last_chargecycles, int, 0644);
module_param(last_charge_increase, int, 0644);
-static int last_rbatt = -EINVAL;
+static int calculated_soc = -EINVAL;
static int last_soc = -EINVAL;
static int last_real_fcc_mah = -EINVAL;
static int last_real_fcc_batt_temp = -EINVAL;
@@ -175,7 +187,6 @@
.get = param_get_int,
};
-module_param_cb(last_rbatt, &bms_param_ops, &last_rbatt, 0644);
module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
/*
@@ -337,19 +348,13 @@
static int usb_chg_plugged_in(void)
{
- union power_supply_propval ret = {0,};
- static struct power_supply *psy;
+ int val = pm8921_is_usb_chg_plugged_in();
- if (psy == NULL) {
- psy = power_supply_get_by_name("usb");
- if (psy == NULL)
- return 0;
- }
+ /* treat as if usb is not present in case of error */
+ if (val == -EINVAL)
+ val = 0;
- if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret))
- return 0;
-
- return ret.intval;
+ return val;
}
#define HOLD_OREG_DATA BIT(1)
@@ -483,8 +488,8 @@
return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
}
-#define CC_READING_TICKS 55
-#define SLEEP_CLK_HZ 32768
+#define CC_READING_TICKS 56
+#define SLEEP_CLK_HZ 32764
#define SECONDS_PER_HOUR 3600
/**
* ccmicrovolt_to_nvh -
@@ -732,6 +737,82 @@
return 0;
}
+/* get ocv given a soc -- reverse lookup */
+static int interpolate_ocv(struct pm8921_bms_chip *chip,
+ int batt_temp_degc, int pc)
+{
+ int i, ocvrow1, ocvrow2, ocv;
+ int rows, cols;
+ int row1 = 0;
+ int row2 = 0;
+
+ rows = chip->pc_temp_ocv_lut->rows;
+ cols = chip->pc_temp_ocv_lut->cols;
+ if (pc > chip->pc_temp_ocv_lut->percent[0]) {
+ pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
+ row1 = 0;
+ row2 = 0;
+ }
+ if (pc < chip->pc_temp_ocv_lut->percent[rows - 1]) {
+ pr_debug("pc %d less than known pc ranges for sf\n", pc);
+ row1 = rows - 1;
+ row2 = rows - 1;
+ }
+ for (i = 0; i < rows; i++) {
+ if (pc == chip->pc_temp_ocv_lut->percent[i]) {
+ row1 = i;
+ row2 = i;
+ break;
+ }
+ if (pc > chip->pc_temp_ocv_lut->percent[i]) {
+ row1 = i - 1;
+ row2 = i;
+ break;
+ }
+ }
+
+ if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0])
+ batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
+ if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1])
+ batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
+
+ for (i = 0; i < cols; i++)
+ if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[i])
+ break;
+ if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[i]) {
+ ocv = linear_interpolate(
+ chip->pc_temp_ocv_lut->ocv[row1][i],
+ chip->pc_temp_ocv_lut->percent[row1],
+ chip->pc_temp_ocv_lut->ocv[row2][i],
+ chip->pc_temp_ocv_lut->percent[row2],
+ pc);
+ return ocv;
+ }
+
+ ocvrow1 = linear_interpolate(
+ chip->pc_temp_ocv_lut->ocv[row1][i - 1],
+ chip->pc_temp_ocv_lut->temp[i - 1],
+ chip->pc_temp_ocv_lut->ocv[row1][i],
+ chip->pc_temp_ocv_lut->temp[i],
+ batt_temp_degc);
+
+ ocvrow2 = linear_interpolate(
+ chip->pc_temp_ocv_lut->ocv[row2][i - 1],
+ chip->pc_temp_ocv_lut->temp[i - 1],
+ chip->pc_temp_ocv_lut->ocv[row2][i],
+ chip->pc_temp_ocv_lut->temp[i],
+ batt_temp_degc);
+
+ ocv = linear_interpolate(
+ ocvrow1,
+ chip->pc_temp_ocv_lut->percent[row1],
+ ocvrow2,
+ chip->pc_temp_ocv_lut->percent[row2],
+ pc);
+
+ return ocv;
+}
+
static int interpolate_pc(struct pm8921_bms_chip *chip,
int batt_temp, int ocv)
{
@@ -836,7 +917,7 @@
#define BMS_MODE_BIT BIT(6)
#define EN_VBAT_BIT BIT(5)
#define OVERRIDE_MODE_DELAY_MS 20
-int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
+int override_mode_simultaneous_battery_voltage_and_current(int *ibat_ua,
int *vbat_uv)
{
int16_t vsense_raw;
@@ -844,11 +925,6 @@
int vsense_uv;
int usb_chg;
- if (the_chip == NULL) {
- pr_err("Called to early\n");
- return -EINVAL;
- }
-
mutex_lock(&the_chip->bms_output_lock);
pm8xxx_writeb(the_chip->dev->parent, BMS_S1_DELAY, 0x00);
@@ -880,42 +956,6 @@
*ibat_ua, *vbat_uv);
return 0;
}
-EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
-
-static int read_rbatt_params_raw(struct pm8921_bms_chip *chip,
- struct pm8921_rbatt_params *raw)
-{
- int usb_chg;
-
- mutex_lock(&chip->bms_output_lock);
- pm_bms_lock_output_data(chip);
-
- pm_bms_read_output_data(chip,
- OCV_FOR_RBATT, &raw->ocv_for_rbatt_raw);
- pm_bms_read_output_data(chip,
- VBATT_FOR_RBATT, &raw->vbatt_for_rbatt_raw);
- pm_bms_read_output_data(chip,
- VSENSE_FOR_RBATT, &raw->vsense_for_rbatt_raw);
-
- pm_bms_unlock_output_data(chip);
- mutex_unlock(&chip->bms_output_lock);
-
- usb_chg = usb_chg_plugged_in();
- convert_vbatt_raw_to_uv(chip, usb_chg,
- raw->vbatt_for_rbatt_raw, &raw->vbatt_for_rbatt_uv);
- convert_vbatt_raw_to_uv(chip, usb_chg,
- raw->ocv_for_rbatt_raw, &raw->ocv_for_rbatt_uv);
- convert_vsense_to_uv(chip, raw->vsense_for_rbatt_raw,
- &raw->vsense_for_rbatt_uv);
-
- pr_debug("vbatt_for_rbatt_raw = 0x%x, vbatt_for_rbatt= %duV\n",
- raw->vbatt_for_rbatt_raw, raw->vbatt_for_rbatt_uv);
- pr_debug("ocv_for_rbatt_raw = 0x%x, ocv_for_rbatt= %duV\n",
- raw->ocv_for_rbatt_raw, raw->ocv_for_rbatt_uv);
- pr_debug("vsense_for_rbatt_raw = 0x%x, vsense_for_rbatt= %duV\n",
- raw->vsense_for_rbatt_raw, raw->vsense_for_rbatt_uv);
- return 0;
-}
#define MBG_TRANSIENT_ERROR_RAW 51
static void adjust_pon_ocv_raw(struct pm8921_bms_chip *chip,
@@ -953,6 +993,7 @@
convert_vbatt_raw_to_uv(chip, usb_chg,
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
chip->last_ocv_uv = raw->last_good_ocv_uv;
+ pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
convert_vbatt_raw_to_uv(chip, usb_chg,
@@ -988,7 +1029,7 @@
{
int rbatt, scalefactor;
- rbatt = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
+ rbatt = chip->default_rbatt_mohm;
pr_debug("rbatt before scaling = %d\n", rbatt);
if (chip->rbatt_sf_lut == NULL) {
pr_debug("RBATT = %d\n", rbatt);
@@ -1017,27 +1058,6 @@
return rbatt;
}
-static int calculate_rbatt_resume(struct pm8921_bms_chip *chip,
- struct pm8921_rbatt_params *raw)
-{
- unsigned int r_batt;
-
- if (raw->ocv_for_rbatt_uv <= 0
- || raw->ocv_for_rbatt_uv <= raw->vbatt_for_rbatt_uv
- || raw->vsense_for_rbatt_raw <= 0) {
- pr_debug("rbatt readings unavailable ocv = %d, vbatt = %d,"
- "vsen = %d\n",
- raw->ocv_for_rbatt_uv,
- raw->vbatt_for_rbatt_uv,
- raw->vsense_for_rbatt_raw);
- return -EINVAL;
- }
- r_batt = ((raw->ocv_for_rbatt_uv - raw->vbatt_for_rbatt_uv)
- * chip->r_sense) / raw->vsense_for_rbatt_uv;
- pr_debug("r_batt = %umilliOhms", r_batt);
- return r_batt;
-}
-
static int calculate_fcc_uah(struct pm8921_bms_chip *chip, int batt_temp,
int chargecycles)
{
@@ -1090,7 +1110,7 @@
return rc;
}
- rbatt = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
+ rbatt = chip->default_rbatt_mohm;
*ocv = vbatt + (ibatt_ua * rbatt)/1000;
return 0;
}
@@ -1141,185 +1161,230 @@
*val = cc_uah;
}
-static int calculate_uuc_uah_at_given_current(struct pm8921_bms_chip *chip,
+static int calculate_termination_uuc(struct pm8921_bms_chip *chip,
int batt_temp, int chargecycles,
- int rbatt, int fcc_uah, int i_ma)
+ int fcc_uah, int i_ma,
+ int *ret_pc_unusable)
{
int unusable_uv, pc_unusable, uuc;
+ int i = 0;
+ int ocv_mv;
+ int batt_temp_degc = batt_temp / 10;
+ int rbatt_mohm;
+ int delta_uv;
+ int prev_delta_uv = 0;
+ int prev_rbatt_mohm = 0;
+ int prev_ocv_mv = 0;
+ int uuc_rbatt_uv;
- /* calculate unusable charge with itest */
- unusable_uv = (rbatt * i_ma) + (chip->v_failure * 1000);
+ for (i = 0; i <= 100; i++) {
+ ocv_mv = interpolate_ocv(chip, batt_temp_degc, i);
+ rbatt_mohm = get_rbatt(chip, i, batt_temp);
+ unusable_uv = (rbatt_mohm * i_ma) + (chip->v_cutoff * 1000);
+ delta_uv = ocv_mv * 1000 - unusable_uv;
+
+ pr_debug("soc = %d ocv = %d rbat = %d u_uv = %d delta_v = %d\n",
+ i, ocv_mv, rbatt_mohm, unusable_uv, delta_uv);
+
+ if (delta_uv > 0)
+ break;
+
+ prev_delta_uv = delta_uv;
+ prev_rbatt_mohm = rbatt_mohm;
+ prev_ocv_mv = ocv_mv;
+ }
+
+ uuc_rbatt_uv = linear_interpolate(rbatt_mohm, delta_uv,
+ prev_rbatt_mohm, prev_delta_uv,
+ 0);
+
+ unusable_uv = (uuc_rbatt_uv * i_ma) + (chip->v_cutoff * 1000);
+
pc_unusable = calculate_pc(chip, unusable_uv, batt_temp, chargecycles);
uuc = (fcc_uah * pc_unusable) / 100;
- pr_debug("For i_ma = %d, unusable_uv = %d unusable_pc = %d uuc = %d\n",
- i_ma, unusable_uv, pc_unusable, uuc);
+ pr_debug("For i_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d uuc = %d\n",
+ i_ma, uuc_rbatt_uv, unusable_uv,
+ pc_unusable, uuc);
+ *ret_pc_unusable = pc_unusable;
return uuc;
}
-#define SOC_RBATT_CHG 70
-#define SOC_RBATT_DISCHG 20
-
-static int uuc_iavg_div = 150;
-module_param(uuc_iavg_div, int, 0644);
-
-static int uuc_min_step_size = 120;
-module_param(uuc_min_step_size, int, 0644);
-
-static int uuc_multiplier = 1000;
-module_param(uuc_multiplier, int, 0644);
-
-#define UUC_TIMER_MS 120000
-
-static void uuc_timer_work(struct work_struct *work)
+static int adjust_uuc(struct pm8921_bms_chip *chip, int fcc_uah,
+ int new_pc_unusable,
+ int new_uuc,
+ int batt_temp,
+ int rbatt,
+ int *iavg_ma)
{
- struct pm8921_bms_chip *chip = container_of(work,
- struct pm8921_bms_chip, uuc_timer_work.work);
+ int new_unusable_mv;
+ int batt_temp_degc = batt_temp / 10;
- pr_debug("UUC Timer expired\n");
- /* indicates the system is done with the high load during bootup */
- chip->timer_uuc_expired = 1;
+ if (chip->prev_pc_unusable == -EINVAL
+ || abs(chip->prev_pc_unusable - new_pc_unusable) <= 1) {
+ chip->prev_pc_unusable = new_pc_unusable;
+ return new_uuc;
+ }
+
+ /* the uuc is trying to change more than 1% restrict it */
+ if (new_pc_unusable > chip->prev_pc_unusable)
+ chip->prev_pc_unusable++;
+ else
+ chip->prev_pc_unusable--;
+
+ new_uuc = (fcc_uah * chip->prev_pc_unusable) / 100;
+
+ /* also find update the iavg_ma accordingly */
+ new_unusable_mv = interpolate_ocv(chip, batt_temp_degc,
+ chip->prev_pc_unusable);
+ if (new_unusable_mv < chip->v_cutoff)
+ new_unusable_mv = chip->v_cutoff;
+
+ *iavg_ma = (new_unusable_mv - chip->v_cutoff) * 1000 / rbatt;
+ if (*iavg_ma == 0)
+ *iavg_ma = 1;
+ pr_debug("Restricting UUC to %d (%d%%) unusable_mv = %d iavg_ma = %d\n",
+ new_uuc, chip->prev_pc_unusable,
+ new_unusable_mv, *iavg_ma);
+
+ return new_uuc;
}
static void calculate_iavg_ua(struct pm8921_bms_chip *chip, int cc_uah,
- int *iavg_ua, int *delta_time_us)
+ int *iavg_ua, int *delta_time_s)
{
int delta_cc_uah;
- struct timeval now;
+ struct rtc_time tm;
+ struct rtc_device *rtc;
+ unsigned long now_tm_sec = 0;
+ int rc = 0;
- delta_cc_uah = cc_uah - chip->last_cc_uah;
- do_gettimeofday(&now);
- if (chip->t.tv_sec != 0) {
- *delta_time_us = (now.tv_sec - chip->t.tv_sec) * USEC_PER_SEC
- + now.tv_usec - chip->t.tv_usec;
- } else {
- /* calculation for the first time */
- *delta_time_us = 0;
+ /* if anything fails report the previous iavg_ua */
+ *iavg_ua = chip->prev_iavg_ua;
+
+ rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+ if (rtc == NULL) {
+ pr_err("%s: unable to open rtc device (%s)\n",
+ __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+ goto out;
}
- if (*delta_time_us != 0)
- *iavg_ua = div_s64((s64)delta_cc_uah * 3600 * 1000000,
- *delta_time_us);
- else
- *iavg_ua = 0;
+ rc = rtc_read_time(rtc, &tm);
+ if (rc) {
+ pr_err("Error reading rtc device (%s) : %d\n",
+ CONFIG_RTC_HCTOSYS_DEVICE, rc);
+ goto out;
+ }
- pr_debug("t.tv_sec = %d, now.tv_sec = %d delta_us = %d iavg_ua = %d\n",
- (int)chip->t.tv_sec, (int)now.tv_sec,
- *delta_time_us, (int)*iavg_ua);
+ rc = rtc_valid_tm(&tm);
+ if (rc) {
+ pr_err("Invalid RTC time (%s): %d\n",
+ CONFIG_RTC_HCTOSYS_DEVICE, rc);
+ goto out;
+ }
+ rtc_tm_to_time(&tm, &now_tm_sec);
+
+ if (chip->tm_sec == 0) {
+ *delta_time_s = 0;
+ pm8921_bms_get_battery_current(iavg_ua);
+ goto out;
+ }
+
+ *delta_time_s = (now_tm_sec - chip->tm_sec);
+
+ /* use the previous iavg if called within 15 seconds */
+ if (*delta_time_s < 15) {
+ *iavg_ua = chip->prev_iavg_ua;
+ goto out;
+ }
+
+ delta_cc_uah = cc_uah - chip->last_cc_uah;
+
+ *iavg_ua = div_s64((s64)delta_cc_uah * 3600, *delta_time_s);
+
+ pr_debug("tm_sec = %ld, now_tm_sec = %ld delta_s = %d delta_cc = %d iavg_ua = %d\n",
+ chip->tm_sec, now_tm_sec,
+ *delta_time_s, delta_cc_uah, (int)*iavg_ua);
+
+out:
+ /* remember the iavg */
+ chip->prev_iavg_ua = *iavg_ua;
+
/* remember cc_uah */
chip->last_cc_uah = cc_uah;
/* remember this time */
- chip->t = now;
+ chip->tm_sec = now_tm_sec;
}
-#define UUC_IAVG_THRESHOLD_UAH 50000
-static int scale_unusable_charge_uah(struct pm8921_bms_chip *chip,
- bool charging, int uuc_uah_iavg, int uuc_uah_itest,
- int uuc_uah_iavg_prev)
-{
- int stepsize = 0;
- int delta_uuc = 0;
- int uuc_reported = 0;
-
- if (charging) {
- stepsize = max(uuc_min_step_size,
- uuc_multiplier * (SOC_RBATT_CHG - last_soc));
- /*
- * set the delta only if uuc is decreasing. If it has increased
- * simply report the last uuc since we don't want to report a
- * higher uuc as charging progresses
- */
- if (chip->last_uuc_uah > uuc_uah_iavg)
- delta_uuc = (chip->last_uuc_uah - uuc_uah_iavg)
- / stepsize;
- uuc_reported = chip->last_uuc_uah - delta_uuc;
- } else {
- stepsize = max(uuc_min_step_size,
- uuc_multiplier * (last_soc - SOC_RBATT_DISCHG));
- if (uuc_uah_itest > uuc_uah_iavg) {
- if ((uuc_uah_iavg > uuc_uah_iavg_prev
- + UUC_IAVG_THRESHOLD_UAH)
- && chip->timer_uuc_expired)
- /*
- * there is a big jump in iavg current way past
- * the bootup increase uuc to this high iavg
- * based uuc in steps
- */
- delta_uuc = (uuc_uah_iavg - uuc_uah_iavg_prev)
- / uuc_iavg_div;
- else
- /* increase uuc towards itest based uuc */
- delta_uuc = (uuc_uah_itest - uuc_uah_iavg)
- / stepsize;
- } else {
- /*
- * the iavg based uuc was higher than itest based
- * uuc. This means that iavg > itest. Itest represents
- * the max current drawn from the device at anytime.
- * If we find iavg > itest, ignore iavg and simply step
- * up the uuc based on itest
- */
- delta_uuc = uuc_uah_itest / stepsize;
- }
- uuc_reported = min(uuc_uah_itest,
- chip->last_uuc_uah + delta_uuc);
- }
- pr_debug("uuc_prev = %d stepsize = %d d_uuc = %d uuc_reported = %d\n",
- chip->last_uuc_uah, (int)stepsize, delta_uuc,
- uuc_reported);
- return uuc_reported;
-}
-
+#define IAVG_SAMPLES 16
+#define CHARGING_IAVG_MA 250
+#define MIN_SECONDS_FOR_VALID_SAMPLE 20
static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
int rbatt, int fcc_uah, int cc_uah,
int soc_rbatt, int batt_temp, int chargecycles,
- int iavg_ua)
+ int iavg_ua, int delta_time_s)
{
- int uuc_uah_itest, uuc_uah_iavg, uuc_reported;
- static int firsttime = 1;
+ int uuc_uah_iavg;
+ int i;
int iavg_ma = iavg_ua / 1000;
+ static int iavg_samples[IAVG_SAMPLES];
+ static int iavg_index;
+ static int iavg_num_samples;
+ static int firsttime = 1;
+ int pc_unusable;
- /* calculate unusable charge with itest */
- uuc_uah_itest = calculate_uuc_uah_at_given_current(chip,
+ /*
+ * if we are called first time fill all the
+ * samples with the the shutdown_iavg_ua
+ */
+ if (firsttime && chip->shutdown_iavg_ua != 0) {
+ pr_emerg("Using shutdown_iavg_ua = %d in all samples\n",
+ chip->shutdown_iavg_ua);
+ for (i = 0; i < IAVG_SAMPLES; i++)
+ iavg_samples[i] = chip->shutdown_iavg_ua;
+
+ iavg_index = 0;
+ iavg_num_samples = IAVG_SAMPLES;
+ }
+
+ /*
+ * if we are charging use a nominal avg current so that we keep
+ * a reasonable UUC while charging
+ */
+ if (iavg_ma < 0)
+ iavg_ma = CHARGING_IAVG_MA;
+ iavg_samples[iavg_index] = iavg_ma;
+ iavg_index = (iavg_index + 1) % IAVG_SAMPLES;
+ iavg_num_samples++;
+ if (iavg_num_samples >= IAVG_SAMPLES)
+ iavg_num_samples = IAVG_SAMPLES;
+
+ /* now that this sample is added calcualte the average */
+ iavg_ma = 0;
+ if (iavg_num_samples != 0) {
+ for (i = 0; i < iavg_num_samples; i++) {
+ pr_debug("iavg_samples[%d] = %d\n", i, iavg_samples[i]);
+ iavg_ma += iavg_samples[i];
+ }
+
+ iavg_ma = DIV_ROUND_CLOSEST(iavg_ma, iavg_num_samples);
+ }
+
+ uuc_uah_iavg = calculate_termination_uuc(chip,
batt_temp, chargecycles,
- rbatt, fcc_uah, chip->i_test);
-
- pr_debug("itest = %d uuc_itest = %d\n", chip->i_test, uuc_uah_itest);
-
- /* calculate unusable charge with iavg */
- iavg_ma = max(0, iavg_ma);
- uuc_uah_iavg = calculate_uuc_uah_at_given_current(chip,
- batt_temp, chargecycles,
- rbatt, fcc_uah, iavg_ma);
+ fcc_uah, iavg_ma,
+ &pc_unusable);
pr_debug("iavg = %d uuc_iavg = %d\n", iavg_ma, uuc_uah_iavg);
- if (firsttime) {
- chip->uuc_uah_iavg_prev = uuc_uah_iavg;
+ /* restrict the uuc such that it can increase only by one percent */
+ uuc_uah_iavg = adjust_uuc(chip, fcc_uah, pc_unusable, uuc_uah_iavg,
+ batt_temp, rbatt, &iavg_ma);
- if (cc_uah < chip->last_cc_uah)
- chip->last_uuc_uah = uuc_uah_itest;
- else
- chip->last_uuc_uah = uuc_uah_iavg;
- pr_debug("firsttime uuc_prev = %d\n", chip->last_uuc_uah);
- }
+ /* find out what the avg current should be for this uuc */
+ chip->prev_uuc_iavg_ma = iavg_ma;
- uuc_reported = scale_unusable_charge_uah(chip,
- cc_uah < chip->last_cc_uah,
- uuc_uah_iavg, uuc_uah_itest,
- chip->uuc_uah_iavg_prev);
-
- /* remember the last uuc_uah_iavg */
- chip->uuc_uah_iavg_prev = uuc_uah_iavg;
-
- /* remember the reported uuc */
- chip->last_uuc_uah = uuc_reported;
-
- if (firsttime == 1) {
- /* uuc calculation for the first time is done */
- firsttime = 0;
- }
-
- return uuc_reported;
+ firsttime = 0;
+ return uuc_uah_iavg;
}
/* calculate remainging charge at the time of ocv */
@@ -1345,7 +1410,7 @@
int *cc_uah,
int *rbatt,
int *iavg_ua,
- int *delta_time_us)
+ int *delta_time_s)
{
int soc_rbatt;
@@ -1371,11 +1436,12 @@
soc_rbatt = 0;
*rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
- calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_us);
+ calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_s);
*unusable_charge_uah = calculate_unusable_charge_uah(chip, *rbatt,
*fcc_uah, *cc_uah, soc_rbatt,
- batt_temp, chargecycles, *iavg_ua);
+ batt_temp, chargecycles, *iavg_ua,
+ *delta_time_s);
pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
}
@@ -1390,7 +1456,7 @@
int real_fcc_uah;
int rbatt;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
@@ -1399,7 +1465,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
real_fcc_uah = remaining_charge_uah - cc_uah;
*ret_fcc_uah = fcc_uah;
@@ -1408,6 +1474,107 @@
return real_fcc_uah;
}
+int pm8921_bms_get_simultaneous_battery_voltage_and_current(int *ibat_ua,
+ int *vbat_uv)
+{
+ int rc;
+
+ if (the_chip == NULL) {
+ pr_err("Called too early\n");
+ return -EINVAL;
+ }
+
+ if (pm8921_is_batfet_closed()) {
+ return override_mode_simultaneous_battery_voltage_and_current(
+ ibat_ua,
+ vbat_uv);
+ } else {
+ pr_debug("batfet is open using separate vbat and ibat meas\n");
+ rc = get_battery_uvolts(the_chip, vbat_uv);
+ if (rc < 0) {
+ pr_err("adc vbat failed err = %d\n", rc);
+ return rc;
+ }
+ rc = pm8921_bms_get_battery_current(ibat_ua);
+ if (rc < 0) {
+ pr_err("bms ibat failed err = %d\n", rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
+
+static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
+ int batt_temp,
+ int chargecycles,
+ int fcc_uah,
+ int uuc_uah,
+ int cc_uah,
+ int shutdown_soc,
+ int *rc_uah,
+ int *ocv_uv)
+{
+ s64 rc;
+ int pc, new_pc;
+ int batt_temp_degc = batt_temp / 10;
+ int ocv;
+
+ rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
+ rc = div_s64(rc, 100) + cc_uah + uuc_uah;
+ pc = DIV_ROUND_CLOSEST((int)rc * 100, fcc_uah);
+ pc = clamp(pc, 0, 100);
+
+ ocv = interpolate_ocv(chip, batt_temp_degc, pc);
+
+ pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
+ shutdown_soc, fcc_uah, uuc_uah, (int)rc, pc, ocv);
+ new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+
+ while (abs(new_pc - pc) > 1) {
+ int delta_mv = 5;
+
+ if (new_pc > pc)
+ delta_mv = -1 * delta_mv;
+
+ ocv = ocv + delta_mv;
+ new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+ }
+
+ *ocv_uv = ocv * 1000;
+ *rc_uah = (int)rc;
+}
+
+static void adjust_rc_and_uuc_for_specific_soc(
+ struct pm8921_bms_chip *chip,
+ int batt_temp,
+ int chargecycles,
+ int soc,
+ int fcc_uah,
+ int uuc_uah,
+ int cc_uah,
+ int rc_uah,
+ int rbatt,
+ int *ret_ocv,
+ int *ret_rc,
+ int *ret_uuc,
+ int *ret_rbatt)
+{
+ int ocv_uv;
+
+ find_ocv_for_soc(chip, batt_temp, chargecycles,
+ fcc_uah, uuc_uah, cc_uah,
+ soc,
+ &rc_uah, &ocv_uv);
+
+ *ret_ocv = ocv_uv;
+ *ret_rbatt = rbatt;
+ *ret_rc = rc_uah;
+ *ret_uuc = uuc_uah;
+}
static int bound_soc(int soc)
{
soc = max(0, soc);
@@ -1415,9 +1582,73 @@
return soc;
}
+static int charging_adjustments(struct pm8921_bms_chip *chip,
+ int soc, int vbat_uv, int ibat_ua,
+ int batt_temp, int chargecycles,
+ int fcc_uah, int cc_uah, int uuc_uah)
+{
+ int chg_soc;
+
+ if (chip->soc_at_cv == -EINVAL) {
+ /* In constant current charging return the calc soc */
+ if (vbat_uv <= chip->max_voltage_uv)
+ pr_debug("CC CHG SOC %d\n", soc);
+
+ /* Note the CC to CV point */
+ if (vbat_uv >= chip->max_voltage_uv) {
+ chip->soc_at_cv = soc;
+ chip->prev_chg_soc = soc;
+ chip->ibat_at_cv_ua = ibat_ua;
+ pr_debug("CC_TO_CV ibat_ua = %d CHG SOC %d\n",
+ ibat_ua, soc);
+ }
+ return soc;
+ }
+
+ /*
+ * battery is in CV phase - begin liner inerpolation of soc based on
+ * battery charge current
+ */
+
+ /*
+ * if voltage lessened (possibly because of a system load)
+ * keep reporting the prev chg soc
+ */
+ if (vbat_uv <= chip->max_voltage_uv) {
+ pr_debug("vbat %d < max = %d CC CHG SOC %d\n",
+ vbat_uv, chip->max_voltage_uv, chip->prev_chg_soc);
+ return chip->prev_chg_soc;
+ }
+
+ chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua,
+ 100, -100000,
+ ibat_ua);
+
+ /* always report a higher soc */
+ if (chg_soc > chip->prev_chg_soc) {
+ int new_ocv_uv;
+ int new_rc;
+
+ chip->prev_chg_soc = chg_soc;
+
+ find_ocv_for_soc(chip, batt_temp, chargecycles,
+ fcc_uah, uuc_uah, cc_uah,
+ chg_soc,
+ &new_rc, &new_ocv_uv);
+ the_chip->last_ocv_uv = new_ocv_uv;
+ pr_debug("CC CHG ADJ OCV = %d CHG SOC %d\n",
+ new_ocv_uv,
+ chip->prev_chg_soc);
+ }
+
+ pr_debug("Reporting CHG SOC %d\n", chip->prev_chg_soc);
+ return chip->prev_chg_soc;
+}
+
static int last_soc_est = -EINVAL;
-static int adjust_soc(struct pm8921_bms_chip *chip, int soc, int batt_temp,
- int rbatt , int fcc_uah, int uuc_uah, int cc_uah)
+static int adjust_soc(struct pm8921_bms_chip *chip, int soc,
+ int batt_temp, int chargecycles,
+ int rbatt, int fcc_uah, int uuc_uah, int cc_uah)
{
int ibat_ua = 0, vbat_uv = 0;
int ocv_est_uv = 0, soc_est = 0, pc_est = 0, pc = 0;
@@ -1427,23 +1658,47 @@
int pc_new = 0;
int soc_new = 0;
int m = 0;
+ int rc = 0;
+ int delta_ocv_uv_limit = 0;
- pm8921_bms_get_simultaneous_battery_voltage_and_current(&ibat_ua,
- &vbat_uv);
-
- if (ibat_ua < 0)
+ rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+ &ibat_ua,
+ &vbat_uv);
+ if (rc < 0) {
+ pr_err("simultaneous vbat ibat failed err = %d\n", rc);
goto out;
+ }
+
+
+ delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
+
ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000;
pc_est = calculate_pc(chip, ocv_est_uv, batt_temp, last_chargecycles);
soc_est = div_s64((s64)fcc_uah * pc_est - uuc_uah*100,
(s64)fcc_uah - uuc_uah);
soc_est = bound_soc(soc_est);
+ if (ibat_ua < 0) {
+ soc = charging_adjustments(chip, soc, vbat_uv, ibat_ua,
+ batt_temp, chargecycles,
+ fcc_uah, cc_uah, uuc_uah);
+ goto out;
+ }
+
/*
- * do not adjust if soc_est is between 45 and 25 OR soc_est is
- * same as what bms calculated
+ * do not adjust
+ * if soc is same as what bms calculated
+ * if soc_est is between 45 and 25, this is the flat portion of the
+ * curve where soc_est is not so accurate. We generally don't want to
+ * adjust when soc_est is inaccurate except for the cases when soc is
+ * way far off (higher than 50 or lesser than 20).
+ * Also don't adjust soc if it is above 90 becuase we might pull it low
+ * and cause a bad user experience
*/
- if (is_between(45, 25, soc_est) || soc_est == soc)
+ if (soc_est == soc
+ || (is_between(45, chip->adjust_soc_low_threshold, soc_est)
+ && is_between(50, chip->adjust_soc_low_threshold - 5, soc))
+ || soc >= 90)
goto out;
if (last_soc_est == -EINVAL)
@@ -1477,6 +1732,18 @@
delta_ocv_uv = div_s64((soc - soc_est) * (s64)m * 1000,
n * (pc - pc_new));
+
+ if (abs(delta_ocv_uv) > delta_ocv_uv_limit) {
+ pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
+ delta_ocv_uv_limit);
+
+ if (delta_ocv_uv > 0)
+ delta_ocv_uv = delta_ocv_uv_limit;
+ else
+ delta_ocv_uv = -1 * delta_ocv_uv_limit;
+ pr_debug("new delta ocv = %d\n", delta_ocv_uv);
+ }
+
chip->last_ocv_uv -= delta_ocv_uv;
if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -1501,79 +1768,156 @@
out:
pr_debug("ibat_ua = %d, vbat_uv = %d, ocv_est_uv = %d, pc_est = %d, "
"soc_est = %d, n = %d, delta_ocv_uv = %d, last_ocv_uv = %d, "
- "pc_new = %d, soc_new = %d\n",
+ "pc_new = %d, soc_new = %d, rbatt = %d, m = %d\n",
ibat_ua, vbat_uv, ocv_est_uv, pc_est,
soc_est, n, delta_ocv_uv, chip->last_ocv_uv,
- pc_new, soc_new);
+ pc_new, soc_new, rbatt, m);
return soc;
}
-#define MAX_SHUTDOWN_ADJUST_SECONDS 1800
-static int adjust_for_shutdown_soc(struct pm8921_bms_chip *chip, int soc)
+#define IGNORE_SOC_TEMP_DECIDEG 50
+#define IAVG_STEP_SIZE_MA 50
+#define IAVG_START 600
+#define SOC_ZERO 0xFF
+static void backup_soc_and_iavg(struct pm8921_bms_chip *chip, int batt_temp,
+ int soc)
{
- struct timespec uptime;
- int val;
+ u8 temp;
+ int iavg_ma = chip->prev_uuc_iavg_ma;
- /* value of zero means the shutdown soc should not be used */
- if (chip->shutdown_soc == 0)
- return soc;
+ if (iavg_ma > IAVG_START)
+ temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+ else
+ temp = 0;
- if (shutdown_soc_invalid) {
- chip->shutdown_soc = 0;
- return soc;
- }
+ pm_bms_masked_write(chip, TEMP_IAVG_STORAGE,
+ TEMP_IAVG_STORAGE_USE_MASK, temp);
- do_posix_clock_monotonic_gettime(&uptime);
+ /* since only 6 bits are available for SOC, we store half the soc */
+ if (soc == 0)
+ temp = SOC_ZERO;
+ else
+ temp = soc;
- if (uptime.tv_sec >= MAX_SHUTDOWN_ADJUST_SECONDS) {
- /*
- * adjusted for a long time now, switch to reporting the
- * calculated soc
- */
- chip->shutdown_soc = 0;
- return soc;
- }
-
- val = ((MAX_SHUTDOWN_ADJUST_SECONDS - uptime.tv_sec)
- * chip->shutdown_soc
- + uptime.tv_sec * soc);
- val /= MAX_SHUTDOWN_ADJUST_SECONDS;
- pr_debug("shutdown_soc = %d, adj soc = %d, calc soc = %d\n",
- chip->shutdown_soc, val, soc);
-
- return val;
+ /* don't store soc if temperature is below 5degC */
+ if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
+ pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, temp);
}
-static void backup_soc(struct pm8921_bms_chip *chip, int last_soc)
-{
- /* TODO: if 0x107 is free for all variants 8917, 8038 etc */
- pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, last_soc);
-}
-
-static void read_shutdown_soc(struct pm8921_bms_chip *chip)
+static void read_shutdown_soc_and_iavg(struct pm8921_bms_chip *chip)
{
int rc;
u8 temp;
+ rc = pm8xxx_readb(chip->dev->parent, TEMP_IAVG_STORAGE, &temp);
+ if (rc) {
+ pr_err("failed to read addr = %d %d assuming %d\n",
+ TEMP_IAVG_STORAGE, rc, IAVG_START);
+ chip->shutdown_iavg_ua = IAVG_START;
+ } else {
+ temp &= TEMP_IAVG_STORAGE_USE_MASK;
+
+ if (temp == 0) {
+ chip->shutdown_iavg_ua = IAVG_START;
+ } else {
+ chip->shutdown_iavg_ua = IAVG_START
+ + IAVG_STEP_SIZE_MA * (temp + 1);
+ }
+ }
+
rc = pm8xxx_readb(chip->dev->parent, TEMP_SOC_STORAGE, &temp);
- if (rc)
+ if (rc) {
pr_err("failed to read addr = %d %d\n", TEMP_SOC_STORAGE, rc);
- else
+ } else {
chip->shutdown_soc = temp;
- pr_debug("shutdown_soc = %d\n", chip->shutdown_soc);
+ if (chip->shutdown_soc == 0) {
+ pr_debug("No shutdown soc available\n");
+ shutdown_soc_invalid = 1;
+ chip->shutdown_iavg_ua = 0;
+ } else if (chip->shutdown_soc == SOC_ZERO) {
+ chip->shutdown_soc = 0;
+ }
+ }
+
+ if (chip->ignore_shutdown_soc) {
+ shutdown_soc_invalid = 1;
+ chip->shutdown_soc = 0;
+ chip->shutdown_iavg_ua = 0;
+ }
+
+ pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d\n",
+ chip->shutdown_soc,
+ chip->shutdown_iavg_ua,
+ shutdown_soc_invalid);
}
-void pm8921_bms_invalidate_shutdown_soc(void)
+#define SOC_CATCHUP_SEC_MAX 600
+#define SOC_CATCHUP_SEC_PER_PERCENT 60
+#define MAX_CATCHUP_SOC (SOC_CATCHUP_SEC_MAX/SOC_CATCHUP_SEC_PER_PERCENT)
+static int scale_soc_while_chg(struct pm8921_bms_chip *chip,
+ int delta_time_us, int new_soc, int prev_soc)
{
- pr_debug("Invalidating shutdown soc - the battery was removed\n");
- shutdown_soc_invalid = 1;
- if (the_chip)
- the_chip->shutdown_soc = 0;
-}
-EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
+ int chg_time_sec;
+ int catch_up_sec;
+ int scaled_soc;
+ int numerator;
+ /*
+ * The device must be charging for reporting a higher soc, if
+ * not ignore this soc and continue reporting the prev_soc.
+ * Also don't report a high value immediately slowly scale the
+ * value from prev_soc to the new soc based on a charge time
+ * weighted average
+ */
+
+ /* if we are not charging return last soc */
+ if (the_chip->start_percent == -EINVAL)
+ return prev_soc;
+
+ /* if soc is called in quick succession return the last soc */
+ if (delta_time_us < USEC_PER_SEC)
+ return prev_soc;
+
+ chg_time_sec = DIV_ROUND_UP(the_chip->charge_time_us, USEC_PER_SEC);
+ catch_up_sec = DIV_ROUND_UP(the_chip->catch_up_time_us, USEC_PER_SEC);
+ pr_debug("cts= %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
+
+ /*
+ * if we have been charging for more than catch_up time simply return
+ * new soc
+ */
+ if (chg_time_sec > catch_up_sec)
+ return new_soc;
+
+ numerator = (catch_up_sec - chg_time_sec) * prev_soc
+ + chg_time_sec * new_soc;
+ scaled_soc = numerator / catch_up_sec;
+
+ pr_debug("cts = %d new_soc = %d prev_soc = %d scaled_soc = %d\n",
+ chg_time_sec, new_soc, prev_soc, scaled_soc);
+
+ return scaled_soc;
+}
+
+static bool is_shutdown_soc_within_limits(struct pm8921_bms_chip *chip, int soc)
+{
+ if (shutdown_soc_invalid) {
+ pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
+ return 0;
+ }
+
+ if (abs(chip->shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
+ pr_debug("rejecting shutdown soc = %d, soc = %d limit = %d\n",
+ chip->shutdown_soc, soc,
+ chip->shutdown_soc_valid_limit);
+ shutdown_soc_invalid = 1;
+ return 0;
+ }
+
+ return 1;
+}
/*
* Remaining Usable Charge = remaining_charge (charge at ocv instance)
* - coloumb counter charge
@@ -1588,9 +1932,14 @@
int remaining_charge_uah, soc;
int cc_uah;
int rbatt;
- int shutdown_adjusted_soc;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
+ int new_ocv;
+ int new_rc_uah;
+ int new_ucc_uah;
+ int new_rbatt;
+ int shutdown_soc;
+ static int firsttime = 1;
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
@@ -1599,7 +1948,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
/* calculate remaining usable charge */
remaining_usable_charge_uah = remaining_charge_uah
@@ -1612,18 +1961,43 @@
fcc_uah, unusable_charge_uah);
soc = 0;
} else {
- soc = (remaining_usable_charge_uah * 100)
- / (fcc_uah - unusable_charge_uah);
+ soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+ (fcc_uah - unusable_charge_uah));
+ }
+
+ if (firsttime && soc < 0) {
+ /*
+ * first time calcualtion and the pon ocv is too low resulting
+ * in a bad soc. Adjust ocv such that we get 0 soc
+ */
+ pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
+ adjust_rc_and_uuc_for_specific_soc(
+ chip,
+ batt_temp, chargecycles,
+ 0,
+ fcc_uah, unusable_charge_uah,
+ cc_uah, remaining_charge_uah,
+ rbatt,
+ &new_ocv,
+ &new_rc_uah, &new_ucc_uah,
+ &new_rbatt);
+ chip->last_ocv_uv = new_ocv;
+ remaining_charge_uah = new_rc_uah;
+ unusable_charge_uah = new_ucc_uah;
+ rbatt = new_rbatt;
+
+ remaining_usable_charge_uah = remaining_charge_uah
+ - cc_uah
+ - unusable_charge_uah;
+
+ soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+ (fcc_uah - unusable_charge_uah));
+ pr_debug("DONE for O soc is %d, pon ocv adjusted to %duV\n",
+ soc, chip->last_ocv_uv);
}
if (soc > 100)
soc = 100;
- pr_debug("SOC = %u%%\n", soc);
-
- if (bms_fake_battery != -EINVAL) {
- pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
- return bms_fake_battery;
- }
if (soc < 0) {
pr_err("bad rem_usb_chg = %d rem_chg %d,"
@@ -1640,30 +2014,215 @@
soc = 0;
}
- soc = adjust_soc(chip, soc, batt_temp, rbatt,
- fcc_uah, unusable_charge_uah, cc_uah);
+ mutex_lock(&soc_invalidation_mutex);
+ shutdown_soc = chip->shutdown_soc;
- if (last_soc == -EINVAL || soc <= last_soc) {
- last_soc = soc;
- } else {
+ if (firsttime && soc != shutdown_soc
+ && is_shutdown_soc_within_limits(chip, soc)) {
/*
- * soc > last_soc
- * the device must be charging for reporting a higher soc, if
- * not ignore this soc and continue reporting the last_soc
+ * soc for the first time - use shutdown soc
+ * to adjust pon ocv since it is a small percent away from
+ * the real soc
*/
- if (the_chip->start_percent != -EINVAL)
- last_soc = soc;
- else
- pr_debug("soc = %d reporting last_soc = %d\n", soc,
- last_soc);
+ pr_debug("soc = %d before forcing shutdown_soc = %d\n",
+ soc, shutdown_soc);
+ adjust_rc_and_uuc_for_specific_soc(
+ chip,
+ batt_temp, chargecycles,
+ shutdown_soc,
+ fcc_uah, unusable_charge_uah,
+ cc_uah, remaining_charge_uah,
+ rbatt,
+ &new_ocv,
+ &new_rc_uah, &new_ucc_uah,
+ &new_rbatt);
+
+ chip->pon_ocv_uv = chip->last_ocv_uv;
+ chip->last_ocv_uv = new_ocv;
+ remaining_charge_uah = new_rc_uah;
+ unusable_charge_uah = new_ucc_uah;
+ rbatt = new_rbatt;
+
+ remaining_usable_charge_uah = remaining_charge_uah
+ - cc_uah
+ - unusable_charge_uah;
+
+ soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+ (fcc_uah - unusable_charge_uah));
+
+ pr_debug("DONE for shutdown_soc = %d soc is %d, adjusted ocv to %duV\n",
+ shutdown_soc, soc, chip->last_ocv_uv);
+ }
+ mutex_unlock(&soc_invalidation_mutex);
+
+ pr_debug("SOC before adjustment = %d\n", soc);
+ calculated_soc = adjust_soc(chip, soc, batt_temp, chargecycles,
+ rbatt, fcc_uah, unusable_charge_uah, cc_uah);
+
+ pr_debug("calculated SOC = %d\n", calculated_soc);
+ firsttime = 0;
+ return calculated_soc;
+}
+
+#define CALCULATE_SOC_MS 20000
+static void calculate_soc_work(struct work_struct *work)
+{
+ struct pm8921_bms_chip *chip = container_of(work,
+ struct pm8921_bms_chip,
+ calculate_soc_delayed_work.work);
+ int batt_temp, rc;
+ struct pm8xxx_adc_chan_result result;
+ struct pm8921_soc_params raw;
+ int soc;
+
+ rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+ if (rc) {
+ pr_err("error reading adc channel = %d, rc = %d\n",
+ chip->batt_temp_channel, rc);
+ return;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ result.measurement);
+ batt_temp = (int)result.physical;
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ read_soc_params_raw(chip, &raw);
+
+ soc = calculate_state_of_charge(chip, &raw,
+ batt_temp, last_chargecycles);
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+
+ schedule_delayed_work(&chip->calculate_soc_delayed_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (CALCULATE_SOC_MS)));
+}
+
+static int report_state_of_charge(struct pm8921_bms_chip *chip)
+{
+ int soc = calculated_soc;
+ int delta_time_us;
+ struct timespec now;
+ struct pm8xxx_adc_chan_result result;
+ int batt_temp;
+ int rc;
+
+ if (bms_fake_battery != -EINVAL) {
+ pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
+ return bms_fake_battery;
}
- shutdown_adjusted_soc = adjust_for_shutdown_soc(chip, last_soc);
- backup_soc(chip, shutdown_adjusted_soc);
+ rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
+ if (rc) {
+ pr_err("error reading adc channel = %d, rc = %d\n",
+ the_chip->batt_temp_channel, rc);
+ return rc;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ result.measurement);
+ batt_temp = (int)result.physical;
- return shutdown_adjusted_soc;
+ do_posix_clock_monotonic_gettime(&now);
+ if (chip->t_soc_queried.tv_sec != 0) {
+ delta_time_us
+ = (now.tv_sec - chip->t_soc_queried.tv_sec) * USEC_PER_SEC
+ + (now.tv_nsec - chip->t_soc_queried.tv_nsec) / 1000;
+ } else {
+ /* calculation for the first time */
+ delta_time_us = 0;
+ }
+
+ /*
+ * account for charge time - limit it to SOC_CATCHUP_SEC to
+ * avoid overflows when charging continues for extended periods
+ */
+ if (the_chip->start_percent != -EINVAL) {
+ if (the_chip->charge_time_us == 0) {
+ /*
+ * calculating soc for the first time
+ * after start of chg. Initialize catchup time
+ */
+ if (abs(soc - last_soc) < MAX_CATCHUP_SOC)
+ the_chip->catch_up_time_us =
+ (soc - last_soc) * SOC_CATCHUP_SEC_PER_PERCENT
+ * USEC_PER_SEC;
+ else
+ the_chip->catch_up_time_us =
+ SOC_CATCHUP_SEC_MAX * USEC_PER_SEC;
+
+ if (the_chip->catch_up_time_us < 0)
+ the_chip->catch_up_time_us = 0;
+ }
+
+ /* add charge time */
+ if (the_chip->charge_time_us
+ < SOC_CATCHUP_SEC_MAX * USEC_PER_SEC)
+ chip->charge_time_us += delta_time_us;
+
+ /* end catchup if calculated soc and last soc are same */
+ if (last_soc == soc)
+ the_chip->catch_up_time_us = 0;
+ }
+
+ /* last_soc < soc ... scale and catch up */
+ if (last_soc != -EINVAL && last_soc < soc && soc != 100)
+ soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
+
+ last_soc = soc;
+ backup_soc_and_iavg(chip, batt_temp, last_soc);
+ pr_debug("Reported SOC = %d\n", last_soc);
+ chip->t_soc_queried = now;
+
+ return last_soc;
}
+void pm8921_bms_invalidate_shutdown_soc(void)
+{
+ int calculate_soc = 0;
+ struct pm8921_bms_chip *chip = the_chip;
+ int batt_temp, rc;
+ struct pm8xxx_adc_chan_result result;
+ struct pm8921_soc_params raw;
+ int soc;
+
+ pr_debug("Invalidating shutdown soc - the battery was removed\n");
+ if (shutdown_soc_invalid)
+ return;
+
+ mutex_lock(&soc_invalidation_mutex);
+ shutdown_soc_invalid = 1;
+ last_soc = -EINVAL;
+ if (the_chip) {
+ /* reset to pon ocv undoing what the adjusting did */
+ if (the_chip->pon_ocv_uv) {
+ the_chip->last_ocv_uv = the_chip->pon_ocv_uv;
+ calculate_soc = 1;
+ pr_debug("resetting ocv to pon_ocv = %d\n",
+ the_chip->pon_ocv_uv);
+ }
+ }
+ mutex_unlock(&soc_invalidation_mutex);
+ if (!calculate_soc)
+ return;
+
+ rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+ if (rc) {
+ pr_err("error reading adc channel = %d, rc = %d\n",
+ chip->batt_temp_channel, rc);
+ return;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ result.measurement);
+ batt_temp = (int)result.physical;
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ read_soc_params_raw(chip, &raw);
+
+ soc = calculate_state_of_charge(chip, &raw,
+ batt_temp, last_chargecycles);
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
+
#define MIN_DELTA_625_UV 1000
static void calib_hkadc(struct pm8921_bms_chip *chip)
{
@@ -1672,10 +2231,11 @@
int usb_chg;
int this_delta;
+ mutex_lock(&chip->calib_mutex);
rc = pm8xxx_adc_read(the_chip->ref1p25v_channel, &result);
if (rc) {
pr_err("ADC failed for 1.25volts rc = %d\n", rc);
- return;
+ goto out;
}
voltage = xoadc_reading_to_microvolt(result.adc_code);
@@ -1687,7 +2247,7 @@
rc = pm8xxx_adc_read(the_chip->ref625mv_channel, &result);
if (rc) {
pr_err("ADC failed for 1.25volts rc = %d\n", rc);
- return;
+ goto out;
}
voltage = xoadc_reading_to_microvolt(result.adc_code);
@@ -1714,6 +2274,8 @@
chip->xoadc_v0625_usb_absent,
last_usb_cal_delta_uv);
}
+out:
+ mutex_unlock(&chip->calib_mutex);
}
static void calibrate_hkadc_work(struct work_struct *work)
@@ -1729,6 +2291,19 @@
schedule_work(&the_chip->calib_hkadc_work);
}
+#define HKADC_CALIB_DELAY_MS 600000
+static void calibrate_hkadc_delayed_work(struct work_struct *work)
+{
+ struct pm8921_bms_chip *chip = container_of(work,
+ struct pm8921_bms_chip,
+ calib_hkadc_delayed_work.work);
+
+ calib_hkadc(chip);
+ schedule_delayed_work(&chip->calib_hkadc_delayed_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (HKADC_CALIB_DELAY_MS)));
+}
+
int pm8921_bms_get_vsense_avg(int *result)
{
int rc = -EINVAL;
@@ -1774,33 +2349,12 @@
int pm8921_bms_get_percent_charge(void)
{
- int batt_temp, rc;
- struct pm8xxx_adc_chan_result result;
- struct pm8921_soc_params raw;
- int soc;
-
if (!the_chip) {
pr_err("called before initialization\n");
return -EINVAL;
}
- rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
- if (rc) {
- pr_err("error reading adc channel = %d, rc = %d\n",
- the_chip->batt_temp_channel, rc);
- return rc;
- }
- pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
- result.measurement);
- batt_temp = (int)result.physical;
-
- mutex_lock(&the_chip->last_ocv_uv_mutex);
- read_soc_params_raw(the_chip, &raw);
-
- soc = calculate_state_of_charge(the_chip, &raw,
- batt_temp, last_chargecycles);
- mutex_unlock(&the_chip->last_ocv_uv_mutex);
- return soc;
+ return report_state_of_charge(the_chip);
}
EXPORT_SYMBOL_GPL(pm8921_bms_get_percent_charge);
@@ -1815,7 +2369,7 @@
int cc_uah;
int rbatt;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
if (!the_chip) {
pr_err("called before initialization\n");
@@ -1843,7 +2397,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
mutex_unlock(&the_chip->last_ocv_uv_mutex);
return rbatt;
@@ -1881,32 +2435,24 @@
#define OCV_TOL_NO_OCV 0x00
void pm8921_bms_charging_began(void)
{
- int batt_temp, rc;
- struct pm8xxx_adc_chan_result result;
struct pm8921_soc_params raw;
- rc = pm8xxx_adc_read(the_chip->batt_temp_channel, &result);
- if (rc) {
- pr_err("error reading adc channel = %d, rc = %d\n",
- the_chip->batt_temp_channel, rc);
- return;
- }
- pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
- result.measurement);
- batt_temp = (int)result.physical;
-
mutex_lock(&the_chip->last_ocv_uv_mutex);
read_soc_params_raw(the_chip, &raw);
-
- the_chip->start_percent = calculate_state_of_charge(the_chip, &raw,
- batt_temp, last_chargecycles);
mutex_unlock(&the_chip->last_ocv_uv_mutex);
+ the_chip->start_percent = report_state_of_charge(the_chip);
+
bms_start_percent = the_chip->start_percent;
bms_start_ocv_uv = raw.last_good_ocv_uv;
calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah);
pm_bms_masked_write(the_chip, BMS_TOLERANCES,
IBAT_TOL_MASK, IBAT_TOL_DEFAULT);
+ the_chip->charge_time_us = 0;
+ the_chip->catch_up_time_us = 0;
+
+ the_chip->soc_at_cv = -EINVAL;
+ the_chip->prev_chg_soc = -EINVAL;
pr_debug("start_percent = %u%%\n", the_chip->start_percent);
}
EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
@@ -1971,7 +2517,6 @@
last_real_fcc_mah = new_fcc_uah/1000;
last_real_fcc_batt_temp = batt_temp;
readjust_fcc_table();
-
}
if (is_battery_full) {
@@ -1985,7 +2530,7 @@
* forget the old cc value
*/
the_chip->last_cc_uah = 0;
- pr_debug("EOC ocv_reading = 0x%x cc = 0x%x\n",
+ pr_debug("EOC BATT_FULL ocv_reading = 0x%x cc = 0x%x\n",
the_chip->ocv_reading_at_100,
the_chip->cc_reading_at_100);
}
@@ -2011,6 +2556,10 @@
last_chargecycles);
the_chip->start_percent = -EINVAL;
the_chip->end_percent = -EINVAL;
+ the_chip->charge_time_us = 0;
+ the_chip->catch_up_time_us = 0;
+ the_chip->soc_at_cv = -EINVAL;
+ the_chip->prev_chg_soc = -EINVAL;
pm_bms_masked_write(the_chip, BMS_TOLERANCES,
IBAT_TOL_MASK, IBAT_TOL_NOCHG);
}
@@ -2157,94 +2706,6 @@
return -EINVAL;
}
-static int pm8921_bms_suspend(struct device *dev)
-{
- int rc;
- struct pm8xxx_adc_chan_result result;
- struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
- struct pm8921_soc_params raw;
- int fcc_uah;
- int remaining_charge_uah;
- int cc_uah;
-
- chip->batt_temp_suspend = 0;
- rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
- if (rc) {
- pr_err("error reading adc channel = %d, rc = %d\n",
- chip->batt_temp_channel, rc);
- }
- chip->batt_temp_suspend = (int)result.physical;
-
- mutex_lock(&chip->last_ocv_uv_mutex);
- read_soc_params_raw(chip, &raw);
-
- fcc_uah = calculate_fcc_uah(chip,
- chip->batt_temp_suspend, last_chargecycles);
- pr_debug("FCC = %uuAh batt_temp = %d, cycles = %d\n",
- fcc_uah, chip->batt_temp_suspend, last_chargecycles);
- /* calculate remainging charge */
- remaining_charge_uah = calculate_remaining_charge_uah(chip, &raw,
- fcc_uah, chip->batt_temp_suspend,
- last_chargecycles);
- pr_debug("RC = %uuAh\n", remaining_charge_uah);
-
- /* calculate cc micro_volt_hour */
- calculate_cc_uah(chip, raw.cc, &cc_uah);
- pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n",
- cc_uah, raw.cc,
- (int64_t)raw.cc - chip->cc_reading_at_100,
- chip->cc_reading_at_100);
- chip->soc_rbatt_suspend = ((remaining_charge_uah - cc_uah) * 100)
- / fcc_uah;
- mutex_unlock(&chip->last_ocv_uv_mutex);
-
- return 0;
-}
-
-#define DELTA_RBATT_PERCENT 10
-static int pm8921_bms_resume(struct device *dev)
-{
- struct pm8921_rbatt_params raw;
- struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
- int rbatt;
- int expected_rbatt;
- int scalefactor;
- int delta_rbatt;
-
- read_rbatt_params_raw(chip, &raw);
- rbatt = calculate_rbatt_resume(chip, &raw);
-
- if (rbatt < 0)
- return 0;
-
- expected_rbatt
- = (last_rbatt < 0) ? chip->default_rbatt_mohm : last_rbatt;
-
- if (chip->rbatt_sf_lut) {
- scalefactor = interpolate_scalingfactor(chip,
- chip->rbatt_sf_lut,
- chip->batt_temp_suspend / 10,
- chip->soc_rbatt_suspend);
- rbatt = rbatt * 100 / scalefactor;
- }
-
- delta_rbatt = expected_rbatt - rbatt;
- if (delta_rbatt)
- delta_rbatt = -delta_rbatt;
- /*
- * only update last_rbatt if rbatt is within some
- * percent of expected_rbatt
- */
- if (delta_rbatt * 100 <= DELTA_RBATT_PERCENT * expected_rbatt)
- last_rbatt = rbatt;
-
- return 0;
-}
-
-static const struct dev_pm_ops pm8921_pm_ops = {
- .suspend = pm8921_bms_suspend,
- .resume = pm8921_bms_resume,
-};
#define EN_BMS_BIT BIT(7)
#define EN_PON_HS_BIT BIT(0)
static int __devinit pm8921_bms_hw_init(struct pm8921_bms_chip *chip)
@@ -2359,7 +2820,6 @@
}
enum bms_request_operation {
- CALC_RBATT,
CALC_FCC,
CALC_PC,
CALC_SOC,
@@ -2420,18 +2880,13 @@
int ret = 0;
int ibat_ua, vbat_uv;
struct pm8921_soc_params raw;
- struct pm8921_rbatt_params rraw;
read_soc_params_raw(the_chip, &raw);
- read_rbatt_params_raw(the_chip, &rraw);
*val = 0;
/* global irq number passed in via data */
switch (param) {
- case CALC_RBATT:
- *val = calculate_rbatt_resume(the_chip, &rraw);
- break;
case CALC_FCC:
*val = calculate_fcc_uah(the_chip, test_batt_temp,
test_chargecycle);
@@ -2490,10 +2945,8 @@
int param = (int)data;
int ret = 0;
struct pm8921_soc_params raw;
- struct pm8921_rbatt_params rraw;
read_soc_params_raw(the_chip, &raw);
- read_rbatt_params_raw(the_chip, &rraw);
*val = 0;
@@ -2505,15 +2958,6 @@
case LAST_GOOD_OCV_VALUE:
*val = raw.last_good_ocv_uv;
break;
- case VBATT_FOR_RBATT:
- *val = rraw.vbatt_for_rbatt_uv;
- break;
- case VSENSE_FOR_RBATT:
- *val = rraw.vsense_for_rbatt_uv;
- break;
- case OCV_FOR_RBATT:
- *val = rraw.ocv_for_rbatt_uv;
- break;
case VSENSE_AVG:
read_vsense_avg(the_chip, (uint *)val);
break;
@@ -2609,8 +3053,6 @@
debugfs_create_file("read_vsense_avg", 0644, chip->dent,
(void *)VSENSE_AVG, &reading_fops);
- debugfs_create_file("show_rbatt", 0644, chip->dent,
- (void *)CALC_RBATT, &calc_fops);
debugfs_create_file("show_fcc", 0644, chip->dent,
(void *)CALC_FCC, &calc_fops);
debugfs_create_file("show_pc", 0644, chip->dent,
@@ -2716,13 +3158,22 @@
mutex_init(&chip->last_ocv_uv_mutex);
chip->dev = &pdev->dev;
chip->r_sense = pdata->r_sense;
- chip->i_test = pdata->i_test;
- chip->v_failure = pdata->v_failure;
+ chip->v_cutoff = pdata->v_cutoff;
chip->max_voltage_uv = pdata->max_voltage_uv;
+ chip->chg_term_ua = pdata->chg_term_ua;
chip->batt_type = pdata->battery_type;
chip->rconn_mohm = pdata->rconn_mohm;
chip->start_percent = -EINVAL;
chip->end_percent = -EINVAL;
+ chip->shutdown_soc_valid_limit = pdata->shutdown_soc_valid_limit;
+ chip->adjust_soc_low_threshold = pdata->adjust_soc_low_threshold;
+ if (chip->adjust_soc_low_threshold >= 45)
+ chip->adjust_soc_low_threshold = 45;
+
+ chip->prev_pc_unusable = -EINVAL;
+ chip->soc_at_cv = -EINVAL;
+
+ chip->ignore_shutdown_soc = pdata->ignore_shutdown_soc;
rc = set_battery_data(chip);
if (rc) {
pr_err("%s bad battery data %d\n", __func__, rc);
@@ -2746,7 +3197,14 @@
chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
chip->revision = pm8xxx_get_revision(chip->dev->parent);
chip->enable_fcc_learning = pdata->enable_fcc_learning;
+
+ mutex_init(&chip->calib_mutex);
INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
+ INIT_DELAYED_WORK(&chip->calib_hkadc_delayed_work,
+ calibrate_hkadc_delayed_work);
+
+ INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
+ calculate_soc_work);
rc = request_irqs(chip, pdev);
if (rc) {
@@ -2760,7 +3218,7 @@
goto free_irqs;
}
- read_shutdown_soc(chip);
+ read_shutdown_soc_and_iavg(chip);
platform_set_drvdata(pdev, chip);
the_chip = chip;
@@ -2773,20 +3231,20 @@
}
check_initial_ocv(chip);
- /* initial hkadc calibration */
- schedule_work(&chip->calib_hkadc_work);
+ /* start periodic hkadc calibration */
+ schedule_delayed_work(&chip->calib_hkadc_delayed_work, 0);
+
/* enable the vbatt reading interrupts for scheduling hkadc calib */
pm8921_bms_enable_irq(chip, PM8921_BMS_GOOD_OCV);
pm8921_bms_enable_irq(chip, PM8921_BMS_OCV_FOR_R);
- INIT_DELAYED_WORK(&chip->uuc_timer_work, uuc_timer_work);
- schedule_delayed_work(&chip->uuc_timer_work,
- msecs_to_jiffies(UUC_TIMER_MS));
+ calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
get_battery_uvolts(chip, &vbatt);
pr_info("OK battery_capacity_at_boot=%d volt = %d ocv = %d\n",
pm8921_bms_get_percent_charge(),
vbatt, chip->last_ocv_uv);
+
return 0;
free_irqs:
@@ -2814,7 +3272,6 @@
.driver = {
.name = PM8921_BMS_DEV_NAME,
.owner = THIS_MODULE,
- .pm = &pm8921_pm_ops
},
};
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 85b653d..6a4e50c 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -271,6 +271,7 @@
enum pm8921_chg_led_src_config led_src_config;
bool host_mode;
u8 active_path;
+ int recent_reported_soc;
};
/* user space parameter to limit usb current */
@@ -327,6 +328,10 @@
return pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
}
+static int is_batfet_closed(struct pm8921_chg_chip *chip)
+{
+ return pm_chg_get_rt_status(chip, BATFET_IRQ);
+}
#define CAPTURE_FSM_STATE_CMD 0xC2
#define READ_BANK_7 0x70
#define READ_BANK_4 0x40
@@ -1400,6 +1405,7 @@
if (percent_soc <= 10)
pr_warn("low battery charge = %d%%\n", percent_soc);
+ chip->recent_reported_soc = percent_soc;
return percent_soc;
}
@@ -1663,8 +1669,11 @@
*/
if (!get_prop_batt_present(the_chip)
&& !is_dc_chg_plugged_in(the_chip)) {
- pr_err("rejected: no other power source connected\n");
- return;
+ if (get_prop_batt_current(the_chip) <
+ the_chip->min_voltage_mv) {
+ pr_err("rejected: no other power source connected\n");
+ return;
+ }
}
if (usb_max_current && mA > usb_max_current) {
@@ -1741,6 +1750,15 @@
}
EXPORT_SYMBOL(pm8921_is_battery_present);
+int pm8921_is_batfet_closed(void)
+{
+ if (!the_chip) {
+ pr_err("called before init\n");
+ return -EINVAL;
+ }
+ return is_batfet_closed(the_chip);
+}
+EXPORT_SYMBOL(pm8921_is_batfet_closed);
/*
* Disabling the charge current limit causes current
* current limits to have no monitoring. An adequate charger
@@ -2768,6 +2786,7 @@
* per update_time minutes
*
*/
+#define LOW_SOC_HEARTBEAT_MS 20000
static void update_heartbeat(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
@@ -2776,7 +2795,12 @@
pm_chg_failed_clear(chip, 1);
power_supply_changed(&chip->batt_psy);
- schedule_delayed_work(&chip->update_heartbeat_work,
+ if (chip->recent_reported_soc <= 20)
+ schedule_delayed_work(&chip->update_heartbeat_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (LOW_SOC_HEARTBEAT_MS)));
+ else
+ schedule_delayed_work(&chip->update_heartbeat_work,
round_jiffies_relative(msecs_to_jiffies
(chip->update_time)));
}
@@ -2787,6 +2811,8 @@
static int ichg_threshold_ua = -400000;
module_param(ichg_threshold_ua, int, 0644);
+
+#define PM8921_CHG_VDDMAX_RES_MV 10
static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
{
int ichg_meas_ua, vbat_uv;
@@ -2846,9 +2872,11 @@
return;
}
+ adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
+ * PM8921_CHG_VDDMAX_RES_MV;
+
if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
-
pr_debug("adjusting vdd_max_mv to %d to make "
"vbat_batt_termial_uv = %d to %d\n",
adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
@@ -3669,24 +3697,9 @@
chip->led_src_config, rc);
}
- /* Workarounds for die 1.1 and 1.0 */
- if (pm8xxx_get_revision(chip->dev->parent) < PM8XXX_REVISION_8921_2p0) {
- pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST2, 0xF1);
- pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xCE);
- pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xD8);
-
- /* software workaround for correct battery_id detection */
- pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_0, 0xFF);
- pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_1, 0xFF);
- pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_2, 0xFF);
- pm8xxx_writeb(chip->dev->parent, PSI_TXRX_SAMPLE_DATA_3, 0xFF);
- pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0D);
- udelay(100);
- pm8xxx_writeb(chip->dev->parent, PSI_CONFIG_STATUS, 0x0C);
- }
-
/* Workarounds for die 3.0 */
- if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0)
+ if (pm8xxx_get_revision(chip->dev->parent) == PM8XXX_REVISION_8921_3p0
+ && pm8xxx_get_version(chip->dev->parent) == PM8XXX_VERSION_8921)
pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0xAC);
/* Enable isub_fine resolution AICL for PM8917 */
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index 861bac8..e48257a 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -685,13 +685,13 @@
goto free_chip;
}
- INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
- schedule_delayed_work(&chip->calib_ccadc_work, 0);
disable_irq_nosync(chip->eoc_irq);
platform_set_drvdata(pdev, chip);
the_chip = chip;
+ INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
+ schedule_delayed_work(&chip->calib_ccadc_work, 0);
create_debugfs_entries(chip);
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index 0e836c7..44fdbc1 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -56,7 +56,7 @@
};
enum qpnp_regulator_type {
- QPNP_REGULATOR_TYPE_HF_BUCK = 0x03,
+ QPNP_REGULATOR_TYPE_BUCK = 0x03,
QPNP_REGULATOR_TYPE_LDO = 0x04,
QPNP_REGULATOR_TYPE_VS = 0x05,
QPNP_REGULATOR_TYPE_BOOST = 0x1B,
@@ -87,6 +87,7 @@
};
enum qpnp_common_regulator_registers {
+ QPNP_COMMON_REG_DIG_MAJOR_REV = 0x01,
QPNP_COMMON_REG_TYPE = 0x04,
QPNP_COMMON_REG_SUBTYPE = 0x05,
QPNP_COMMON_REG_VOLTAGE_RANGE = 0x40,
@@ -106,7 +107,7 @@
};
enum qpnp_boost_registers {
- QPNP_BOOST_REG_CURRENT_LIMIT = 0x40,
+ QPNP_BOOST_REG_CURRENT_LIMIT = 0x4A,
};
/* Used for indexing into ctrl_reg. These are offets from 0x40 */
@@ -117,10 +118,6 @@
QPNP_COMMON_IDX_ENABLE = 6,
};
-enum qpnp_boost_control_register_index {
- QPNP_BOOST_IDX_CURRENT_LIMIT = 0,
-};
-
/* Common regulator control register layout */
#define QPNP_COMMON_ENABLE_MASK 0x80
#define QPNP_COMMON_ENABLE 0x80
@@ -190,6 +187,8 @@
enum qpnp_regulator_type type;
enum qpnp_regulator_subtype subtype;
enum qpnp_regulator_logical_type logical_type;
+ u32 revision_min;
+ u32 revision_max;
struct regulator_ops *ops;
struct qpnp_voltage_set_points *set_points;
int hpm_min_load;
@@ -213,11 +212,13 @@
u8 ctrl_reg[8];
};
-#define QPNP_VREG_MAP(_type, _subtype, _logical_type, _ops_val, \
- _set_points_val, _hpm_min_load) \
+#define QPNP_VREG_MAP(_type, _subtype, _dig_major_min, _dig_major_max, \
+ _logical_type, _ops_val, _set_points_val, _hpm_min_load) \
{ \
.type = QPNP_REGULATOR_TYPE_##_type, \
.subtype = QPNP_REGULATOR_SUBTYPE_##_subtype, \
+ .revision_min = _dig_major_min, \
+ .revision_max = _dig_major_max, \
.logical_type = QPNP_REGULATOR_LOGICAL_TYPE_##_logical_type, \
.ops = &qpnp_##_ops_val##_ops, \
.set_points = &_set_points_val##_set_points, \
@@ -262,6 +263,10 @@
VOLTAGE_RANGE(2, 750000, 775000, 1537500, 12500),
};
+static struct qpnp_voltage_range nldo3_ranges[] = {
+ VOLTAGE_RANGE(0, 375000, 375000, 1537500, 12500),
+};
+
static struct qpnp_voltage_range smps_ranges[] = {
VOLTAGE_RANGE(0, 375000, 375000, 1562500, 12500),
VOLTAGE_RANGE(1, 1550000, 1575000, 3125000, 25000),
@@ -281,6 +286,8 @@
= SET_POINTS(nldo1_ranges);
static struct qpnp_voltage_set_points nldo2_set_points
= SET_POINTS(nldo2_ranges);
+static struct qpnp_voltage_set_points nldo3_set_points
+ = SET_POINTS(nldo3_ranges);
static struct qpnp_voltage_set_points smps_set_points = SET_POINTS(smps_ranges);
static struct qpnp_voltage_set_points ftsmps_set_points
= SET_POINTS(ftsmps_ranges);
@@ -292,6 +299,7 @@
&pldo_set_points,
&nldo1_set_points,
&nldo2_set_points,
+ &nldo3_set_points,
&smps_set_points,
&ftsmps_set_points,
&boost_set_points,
@@ -959,24 +967,30 @@
.enable_time = qpnp_regulator_common_enable_time,
};
+/* Maximum possible digital major revision value */
+#define INF 0xFF
+
static const struct qpnp_regulator_mapping supported_regulators[] = {
- QPNP_VREG_MAP(HF_BUCK, GP_CTL, SMPS, smps, smps, 100000),
- QPNP_VREG_MAP(LDO, N300, LDO, ldo, nldo1, 10000),
- QPNP_VREG_MAP(LDO, N600, LDO, ldo, nldo2, 10000),
- QPNP_VREG_MAP(LDO, N1200, LDO, ldo, nldo2, 10000),
- QPNP_VREG_MAP(LDO, P50, LDO, ldo, pldo, 5000),
- QPNP_VREG_MAP(LDO, P150, LDO, ldo, pldo, 10000),
- QPNP_VREG_MAP(LDO, P300, LDO, ldo, pldo, 10000),
- QPNP_VREG_MAP(LDO, P600, LDO, ldo, pldo, 10000),
- QPNP_VREG_MAP(LDO, P1200, LDO, ldo, pldo, 10000),
- QPNP_VREG_MAP(VS, LV100, VS, vs, none, 0),
- QPNP_VREG_MAP(VS, LV300, VS, vs, none, 0),
- QPNP_VREG_MAP(VS, MV300, VS, vs, none, 0),
- QPNP_VREG_MAP(VS, MV500, VS, vs, none, 0),
- QPNP_VREG_MAP(VS, HDMI, VS, vs, none, 0),
- QPNP_VREG_MAP(VS, OTG, VS, vs, none, 0),
- QPNP_VREG_MAP(BOOST, 5V_BOOST, BOOST, boost, boost, 0),
- QPNP_VREG_MAP(FTS, FTS_CTL, FTSMPS, ftsmps, ftsmps, 100000),
+ /* type subtype dig_min dig_max ltype ops setpoints hpm_min */
+ QPNP_VREG_MAP(BUCK, GP_CTL, 0, INF, SMPS, smps, smps, 100000),
+ QPNP_VREG_MAP(LDO, N300, 0, INF, LDO, ldo, nldo1, 10000),
+ QPNP_VREG_MAP(LDO, N600, 0, 0, LDO, ldo, nldo2, 10000),
+ QPNP_VREG_MAP(LDO, N1200, 0, 0, LDO, ldo, nldo2, 10000),
+ QPNP_VREG_MAP(LDO, N600, 1, INF, LDO, ldo, nldo3, 10000),
+ QPNP_VREG_MAP(LDO, N1200, 1, INF, LDO, ldo, nldo3, 10000),
+ QPNP_VREG_MAP(LDO, P50, 0, INF, LDO, ldo, pldo, 5000),
+ QPNP_VREG_MAP(LDO, P150, 0, INF, LDO, ldo, pldo, 10000),
+ QPNP_VREG_MAP(LDO, P300, 0, INF, LDO, ldo, pldo, 10000),
+ QPNP_VREG_MAP(LDO, P600, 0, INF, LDO, ldo, pldo, 10000),
+ QPNP_VREG_MAP(LDO, P1200, 0, INF, LDO, ldo, pldo, 10000),
+ QPNP_VREG_MAP(VS, LV100, 0, INF, VS, vs, none, 0),
+ QPNP_VREG_MAP(VS, LV300, 0, INF, VS, vs, none, 0),
+ QPNP_VREG_MAP(VS, MV300, 0, INF, VS, vs, none, 0),
+ QPNP_VREG_MAP(VS, MV500, 0, INF, VS, vs, none, 0),
+ QPNP_VREG_MAP(VS, HDMI, 0, INF, VS, vs, none, 0),
+ QPNP_VREG_MAP(VS, OTG, 0, INF, VS, vs, none, 0),
+ QPNP_VREG_MAP(BOOST, 5V_BOOST, 0, INF, BOOST, boost, boost, 0),
+ QPNP_VREG_MAP(FTS, FTS_CTL, 0, INF, FTSMPS, ftsmps, ftsmps, 100000),
};
static int qpnp_regulator_match(struct qpnp_regulator *vreg)
@@ -984,29 +998,39 @@
const struct qpnp_regulator_mapping *mapping;
struct device_node *node = vreg->spmi_dev->dev.of_node;
int rc, i;
- u8 raw_type[2], type, subtype;
- u32 type_reg[2];
+ u32 type_reg[2], dig_major_rev;
+ u8 version[QPNP_COMMON_REG_SUBTYPE - QPNP_COMMON_REG_DIG_MAJOR_REV + 1];
+ u8 type, subtype;
- rc = of_property_read_u32_array(node, "qcom,force-type",
- type_reg, 2);
+ rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_DIG_MAJOR_REV, version,
+ ARRAY_SIZE(version));
+ if (rc) {
+ vreg_err(vreg, "could not read version registers, rc=%d\n", rc);
+ return rc;
+ }
+ dig_major_rev = version[QPNP_COMMON_REG_DIG_MAJOR_REV
+ - QPNP_COMMON_REG_DIG_MAJOR_REV];
+ type = version[QPNP_COMMON_REG_TYPE
+ - QPNP_COMMON_REG_DIG_MAJOR_REV];
+ subtype = version[QPNP_COMMON_REG_SUBTYPE
+ - QPNP_COMMON_REG_DIG_MAJOR_REV];
+
+ /*
+ * Override type and subtype register values if qcom,force-type is
+ * present in the device tree node.
+ */
+ rc = of_property_read_u32_array(node, "qcom,force-type", type_reg, 2);
if (!rc) {
type = type_reg[0];
subtype = type_reg[1];
- } else {
- rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_TYPE, raw_type, 2);
- if (rc) {
- vreg_err(vreg,
- "could not read type register, rc=%d\n", rc);
- return rc;
- }
- type = raw_type[0];
- subtype = raw_type[1];
}
rc = -ENODEV;
for (i = 0; i < ARRAY_SIZE(supported_regulators); i++) {
mapping = &supported_regulators[i];
- if (mapping->type == type && mapping->subtype == subtype) {
+ if (mapping->type == type && mapping->subtype == subtype
+ && mapping->revision_min <= dig_major_rev
+ && mapping->revision_max >= dig_major_rev) {
vreg->logical_type = mapping->logical_type;
vreg->set_points = mapping->set_points;
vreg->hpm_min_load = mapping->hpm_min_load;
@@ -1096,10 +1120,14 @@
if (type == QPNP_REGULATOR_LOGICAL_TYPE_BOOST
&& pdata->boost_current_limit
!= QPNP_BOOST_CURRENT_LIMIT_HW_DEFAULT) {
- ctrl_reg[QPNP_BOOST_IDX_CURRENT_LIMIT] &=
- ~QPNP_BOOST_CURRENT_LIMIT_MASK;
- ctrl_reg[QPNP_BOOST_IDX_CURRENT_LIMIT] |=
- pdata->boost_current_limit & QPNP_BOOST_CURRENT_LIMIT_MASK;
+ reg = pdata->boost_current_limit;
+ mask = QPNP_BOOST_CURRENT_LIMIT_MASK;
+ rc = qpnp_vreg_masked_read_write(vreg,
+ QPNP_BOOST_REG_CURRENT_LIMIT, reg, mask);
+ if (rc) {
+ vreg_err(vreg, "spmi write failed, rc=%d\n", rc);
+ return rc;
+ }
}
/* Write back any control register values that were modified. */
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 6eb5d60..14d554c 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -232,6 +232,7 @@
CLK_GEAR = 7,
ROOT_FREQ = 11,
REF_CLK_GEAR = 15,
+ INTR_WAKE = 19,
};
enum msm_ctrl_state {
@@ -279,6 +280,7 @@
struct completion rx_msgq_notify;
struct task_struct *rx_msgq_thread;
struct clk *rclk;
+ struct clk *hclk;
struct mutex tx_lock;
u8 pgdla;
bool use_rx_msgqs;
@@ -1955,6 +1957,12 @@
dev->irq = irq->start;
dev->bam.irq = bam_irq->start;
+ dev->hclk = clk_get(dev->dev, "iface_clk");
+ if (IS_ERR(dev->hclk))
+ dev->hclk = NULL;
+ else
+ clk_prepare_enable(dev->hclk);
+
ret = msm_slim_sps_init(dev, bam_mem);
if (ret != 0) {
dev_err(dev->dev, "error SPS init\n");
@@ -2024,8 +2032,8 @@
wmb();
/* Framer register initialization */
- writel_relaxed((0xA << REF_CLK_GEAR) | (0xA << CLK_GEAR) |
- (1 << ROOT_FREQ) | (1 << FRM_ACTIVE) | 1,
+ writel_relaxed((1 << INTR_WAKE) | (0xA << REF_CLK_GEAR) |
+ (0xA << CLK_GEAR) | (1 << ROOT_FREQ) | (1 << FRM_ACTIVE) | 1,
dev->base + FRM_CFG);
/*
* Make sure that framer wake-up and enabling writes go through
@@ -2084,6 +2092,10 @@
err_request_irq_failed:
msm_slim_sps_exit(dev);
err_sps_init_failed:
+ if (dev->hclk) {
+ clk_disable_unprepare(dev->hclk);
+ clk_put(dev->hclk);
+ }
err_of_init_failed:
iounmap(dev->bam.base);
err_ioremap_bam_failed:
@@ -2120,6 +2132,8 @@
free_irq(dev->irq, dev);
slim_del_controller(&dev->ctrl);
clk_put(dev->rclk);
+ if (dev->hclk)
+ clk_put(dev->hclk);
msm_slim_sps_exit(dev);
kthread_stop(dev->rx_msgq_thread);
iounmap(dev->bam.base);
@@ -2191,8 +2205,14 @@
{
int ret = 0;
if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
dev_dbg(dev, "system suspend");
ret = msm_slim_runtime_suspend(dev);
+ if (!ret) {
+ if (cdev->hclk)
+ clk_disable_unprepare(cdev->hclk);
+ }
}
if (ret == -EBUSY) {
/*
@@ -2212,8 +2232,12 @@
{
/* If runtime_pm is enabled, this resume shouldn't do anything */
if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
int ret;
dev_dbg(dev, "system resume");
+ if (cdev->hclk)
+ clk_prepare_enable(cdev->hclk);
ret = msm_slim_runtime_resume(dev);
if (!ret) {
pm_runtime_mark_last_busy(dev);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 2198954..d0b5817 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -176,16 +176,27 @@
static int slim_drv_probe(struct device *dev)
{
const struct slim_driver *sdrv = to_slim_driver(dev->driver);
+ struct slim_device *sbdev = to_slim_device(dev);
+ struct slim_controller *ctrl = sbdev->ctrl;
- if (sdrv->probe)
- return sdrv->probe(to_slim_device(dev));
+ if (sdrv->probe) {
+ int ret;
+ ret = sdrv->probe(sbdev);
+ if (ret)
+ return ret;
+ if (sdrv->device_up)
+ queue_work(ctrl->wq, &sbdev->wd);
+ return 0;
+ }
return -ENODEV;
}
static int slim_drv_remove(struct device *dev)
{
const struct slim_driver *sdrv = to_slim_driver(dev->driver);
+ struct slim_device *sbdev = to_slim_device(dev);
+ sbdev->notified = false;
if (sdrv->remove)
return sdrv->remove(to_slim_device(dev));
return -ENODEV;
@@ -263,6 +274,23 @@
.release = slim_dev_release,
};
+static void slim_report_present(struct work_struct *work)
+{
+ u8 laddr;
+ int ret;
+ struct slim_driver *sbdrv;
+ struct slim_device *sbdev =
+ container_of(work, struct slim_device, wd);
+ if (sbdev->notified || !sbdev->dev.driver)
+ return;
+ ret = slim_get_logical_addr(sbdev, sbdev->e_addr, 6, &laddr);
+ sbdrv = to_slim_driver(sbdev->dev.driver);
+ if (!ret && sbdrv->device_up) {
+ sbdev->notified = true;
+ sbdrv->device_up(sbdev);
+ }
+}
+
/*
* slim_add_device: Add a new device without register board info.
* @ctrl: Controller to which this device is to be added to.
@@ -271,25 +299,23 @@
*/
int slim_add_device(struct slim_controller *ctrl, struct slim_device *sbdev)
{
- int ret = 0;
-
sbdev->dev.bus = &slimbus_type;
sbdev->dev.parent = ctrl->dev.parent;
sbdev->dev.type = &slim_dev_type;
+ sbdev->dev.driver = NULL;
sbdev->ctrl = ctrl;
slim_ctrl_get(ctrl);
dev_set_name(&sbdev->dev, "%s", sbdev->name);
- /* probe slave on this controller */
- ret = device_register(&sbdev->dev);
-
- if (ret)
- return ret;
-
mutex_init(&sbdev->sldev_reconf);
INIT_LIST_HEAD(&sbdev->mark_define);
INIT_LIST_HEAD(&sbdev->mark_suspend);
INIT_LIST_HEAD(&sbdev->mark_removal);
- return 0;
+ INIT_WORK(&sbdev->wd, slim_report_present);
+ mutex_lock(&ctrl->m_ctrl);
+ list_add_tail(&sbdev->dev_list, &ctrl->devs);
+ mutex_unlock(&ctrl->m_ctrl);
+ /* probe slave on this controller */
+ return device_register(&sbdev->dev);
}
EXPORT_SYMBOL_GPL(slim_add_device);
@@ -431,6 +457,11 @@
ctrl->sched.slots = kzalloc(SLIM_SL_PER_SUPERFRAME, GFP_KERNEL);
#endif
init_completion(&ctrl->pause_comp);
+
+ INIT_LIST_HEAD(&ctrl->devs);
+ ctrl->wq = create_singlethread_workqueue(dev_name(&ctrl->dev));
+ if (!ctrl->wq)
+ goto err_workq_failed;
/*
* If devices on a controller were registered before controller,
* this will make sure that they get probed now that controller is up
@@ -443,6 +474,10 @@
return 0;
+err_workq_failed:
+ kfree(ctrl->sched.chc3);
+ kfree(ctrl->sched.chc1);
+ kfree(ctrl->chans);
err_chan_failed:
kfree(ctrl->ports);
err_port_failed:
@@ -495,6 +530,7 @@
wait_for_completion(&ctrl->dev_released);
list_del(&ctrl->list);
+ destroy_workqueue(ctrl->wq);
/* free bus id */
mutex_lock(&slim_lock);
idr_remove(&ctrl_idr, ctrl->nr);
@@ -665,7 +701,8 @@
u8 e_len, u8 *laddr)
{
int ret;
- u8 i;
+ u8 i = 0;
+ struct slim_device *sbdev;
mutex_lock(&ctrl->m_ctrl);
/* already assigned */
if (ctrl_getlogical_addr(ctrl, e_addr, e_len, laddr) == 0)
@@ -704,7 +741,25 @@
dev_dbg(&ctrl->dev, "setting slimbus l-addr:%x\n", i);
ret_assigned_laddr:
mutex_unlock(&ctrl->m_ctrl);
- return ret;
+ if (ret)
+ return ret;
+
+ pr_info("slimbus laddr:0x%x, EAPC:0x%x:0x%x", i,
+ e_addr[1], e_addr[2]);
+ mutex_lock(&ctrl->m_ctrl);
+ list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
+ if (memcmp(sbdev->e_addr, e_addr, 6) == 0) {
+ struct slim_driver *sbdrv;
+ if (sbdev->dev.driver) {
+ sbdrv = to_slim_driver(sbdev->dev.driver);
+ if (sbdrv->device_up)
+ queue_work(ctrl->wq, &sbdev->wd);
+ }
+ break;
+ }
+ }
+ mutex_unlock(&ctrl->m_ctrl);
+ return 0;
}
EXPORT_SYMBOL_GPL(slim_assign_laddr);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index f2c881d..9f3327a 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1818,6 +1818,14 @@
goto err_probe_exit;
}
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "cell-index", &pdev->id);
+ if (rc)
+ dev_warn(&pdev->dev,
+ "using default bus_num %d\n", pdev->id);
+ else
+ master->bus_num = pdev->id;
+
for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
i, &flags);
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
index b6dfd51..24e35e4 100644
--- a/drivers/spmi/qpnp-int.c
+++ b/drivers/spmi/qpnp-int.c
@@ -253,12 +253,19 @@
return rc;
}
+static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ return 0;
+}
+
static struct irq_chip qpnpint_chip = {
.name = "qpnp-int",
.irq_mask = qpnpint_irq_mask,
.irq_mask_ack = qpnpint_irq_mask_ack,
.irq_unmask = qpnpint_irq_unmask,
.irq_set_type = qpnpint_irq_set_type,
+ .irq_set_wake = qpnpint_irq_set_wake,
+ .flags = IRQCHIP_MASK_ON_SUSPEND,
};
static int qpnpint_init_irq_data(struct q_chip_data *chip_d,
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 78a1292..daf0564 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -159,6 +159,7 @@
enum platform_type hw_type;
int pm_tsens_thr_data;
int pm_tsens_cntl;
+ struct work_struct tsens_work;
struct tsens_tm_device_sensor sensor[0];
};
@@ -610,9 +611,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 threshold, threshold_low, i, code, reg, sensor, mask;
unsigned int sensor_addr;
bool upper_th_x, lower_th_x;
@@ -627,6 +629,7 @@
writel_relaxed(reg | TSENS_LOWER_STATUS_CLR |
TSENS_UPPER_STATUS_CLR, TSENS_CNTL_ADDR);
}
+
mask = ~(TSENS_LOWER_STATUS_CLR | TSENS_UPPER_STATUS_CLR);
threshold = readl_relaxed(TSENS_THRESHOLD_ADDR);
threshold_low = (threshold & TSENS_THRESHOLD_LOWER_LIMIT_MASK)
@@ -658,9 +661,7 @@
/* Notify user space */
schedule_work(&tm->sensor[i].work);
adc_code = readl_relaxed(sensor_addr);
- pr_info("\nTrip point triggered by "
- "current temperature (%d degrees) "
- "measured by Temperature-Sensor %d\n",
+ pr_debug("Trigger (%d degrees) for sensor %d\n",
tsens_tz_code_to_degC(adc_code, i), i);
}
}
@@ -672,6 +673,12 @@
else
writel_relaxed(reg & mask, TSENS_CNTL_ADDR);
mb();
+}
+
+static irqreturn_t tsens_isr(int irq, void *data)
+{
+ schedule_work(&tmdev->tsens_work);
+
return IRQ_HANDLED;
}
@@ -869,8 +876,7 @@
tmdev->sensor[TSENS_MAIN_SENSOR].calib_data =
tmdev->sensor[TSENS_MAIN_SENSOR].calib_data_backup;
if (!tmdev->sensor[TSENS_MAIN_SENSOR].calib_data) {
- pr_err("%s: No temperature sensor data for calibration"
- " in QFPROM!\n", __func__);
+ pr_err("QFPROM TSENS calibration data not present\n");
return -ENODEV;
}
@@ -901,8 +907,7 @@
tmdev->sensor[i].calib_data =
tmdev->sensor[i].calib_data_backup;
if (!tmdev->sensor[i].calib_data) {
- WARN(1, "%s: No temperature sensor:%d data for"
- " calibration in QFPROM!\n", __func__, i);
+ pr_err("QFPROM TSENS calibration data not present\n");
return -ENODEV;
}
tmdev->sensor[i].offset = (TSENS_CAL_DEGC *
@@ -1026,6 +1031,7 @@
thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
goto fail;
}
+ INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
pr_debug("%s: OK\n", __func__);
mb();
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 2dd698a..3366bba 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -60,19 +60,40 @@
#define TSENS2_POINT1_MASK 0x3f00000
#define TSENS3_POINT1_MASK 0xfc000000
#define TSENS4_POINT1_MASK 0x3f
-#define TSENS5_POINT1_MASK 0xfc00
+#define TSENS5_POINT1_MASK 0xfc0
#define TSENS6_POINT1_MASK 0x3f000
#define TSENS7_POINT1_MASK 0xfc0000
#define TSENS8_POINT1_MASK 0x3f000000
#define TSENS9_POINT1_MASK 0x3f
#define TSENS10_POINT1_MASK 0xfc00
#define TSENS_CAL_SEL_0_1 0xc0000000
-#define TSENS_CAL_SEL_2 BIT(30)
+#define TSENS_CAL_SEL_2 0x40000000
#define TSENS_CAL_SEL_SHIFT 30
#define TSENS_CAL_SEL_SHIFT_2 28
-#define TSENS_ONE_POINT_CALIB 0x3
+#define TSENS_ONE_POINT_CALIB 0x1
#define TSENS_TWO_POINT_CALIB 0x2
+#define TSENS0_POINT1_SHIFT 8
+#define TSENS1_POINT1_SHIFT 14
+#define TSENS2_POINT1_SHIFT 20
+#define TSENS3_POINT1_SHIFT 26
+#define TSENS5_POINT1_SHIFT 6
+#define TSENS6_POINT1_SHIFT 12
+#define TSENS7_POINT1_SHIFT 18
+#define TSENS8_POINT1_SHIFT 24
+#define TSENS10_POINT1_SHIFT 6
+
+#define TSENS_POINT2_BASE_SHIFT 12
+#define TSENS0_POINT2_SHIFT 20
+#define TSENS1_POINT2_SHIFT 26
+#define TSENS3_POINT2_SHIFT 6
+#define TSENS4_POINT2_SHIFT 12
+#define TSENS5_POINT2_SHIFT 18
+#define TSENS6_POINT2_SHIFT 24
+#define TSENS8_POINT2_SHIFT 6
+#define TSENS9_POINT2_SHIFT 12
+#define TSENS10_POINT2_SHIFT 18
+
#define TSENS_BASE2_MASK 0xff000
#define TSENS0_POINT2_MASK 0x3f00000
#define TSENS1_POINT2_MASK 0xfc000000
@@ -97,7 +118,7 @@
#define TSENS_THRESHOLD_MAX_CODE 0x3ff
#define TSENS_THRESHOLD_MIN_CODE 0x0
-#define TSENS_CTRL_INIT_DATA1 0x3fffff9
+#define TSENS_CTRL_INIT_DATA1 0x1cfff9
#define TSENS_GLOBAL_INIT_DATA 0x302f16c
#define TSENS_S0_MAIN_CFG_INIT_DATA 0x1c3
#define TSENS_SN_MIN_MAX_STATUS_CTRL_DATA 0x3ffc00
@@ -141,27 +162,26 @@
static int tsens_tz_code_to_degc(int adc_code, int sensor_num)
{
int degcbeforefactor, degc;
- degcbeforefactor = (adc_code *
- tmdev->sensor[sensor_num].slope_mul_tsens_factor
- + tmdev->sensor[sensor_num].offset);
+ degcbeforefactor = ((adc_code * tmdev->tsens_factor) -
+ tmdev->sensor[sensor_num].offset)/
+ tmdev->sensor[sensor_num].slope_mul_tsens_factor;
if (degcbeforefactor == 0)
degc = degcbeforefactor;
else if (degcbeforefactor > 0)
- degc = (degcbeforefactor + tmdev->tsens_factor/2)
- / tmdev->tsens_factor;
+ degc = ((degcbeforefactor * tmdev->tsens_factor) +
+ tmdev->tsens_factor/2)/tmdev->tsens_factor;
else
- degc = (degcbeforefactor - tmdev->tsens_factor/2)
- / tmdev->tsens_factor;
+ degc = ((degcbeforefactor * tmdev->tsens_factor) -
+ tmdev->tsens_factor/2)/tmdev->tsens_factor;
+
return degc;
}
static int tsens_tz_degc_to_code(int degc, int sensor_num)
{
- int code = (degc * tmdev->tsens_factor -
- tmdev->sensor[sensor_num].offset
- + tmdev->sensor[sensor_num].slope_mul_tsens_factor/2)
- / tmdev->sensor[sensor_num].slope_mul_tsens_factor;
+ int code = ((degc * tmdev->sensor[sensor_num].slope_mul_tsens_factor)
+ + tmdev->sensor[sensor_num].offset)/tmdev->tsens_factor;
if (code > TSENS_THRESHOLD_MAX_CODE)
code = TSENS_THRESHOLD_MAX_CODE;
@@ -482,60 +502,80 @@
int tsens3_point2 = 0, tsens4_point2 = 0, tsens5_point2 = 0;
int tsens6_point2 = 0, tsens7_point2 = 0, tsens8_point2 = 0;
int tsens9_point2 = 0, tsens10_point2 = 0;
- int tsens_base2_data = 0, tsens_calibration_mode = 0, temp;
+ int tsens_base2_data = 0, tsens_calibration_mode = 0, temp = 0;
uint32_t calib_data[5];
for (i = 0; i < 5; i++)
calib_data[i] = readl_relaxed(tmdev->tsens_calib_addr
+ (i * TSENS_SN_ADDR_OFFSET));
- tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1
- >> TSENS_CAL_SEL_SHIFT);
- temp = (calib_data[3] & TSENS_CAL_SEL_2
- >> TSENS_CAL_SEL_SHIFT_2);
+ tsens_calibration_mode = (calib_data[1] & TSENS_CAL_SEL_0_1)
+ >> TSENS_CAL_SEL_SHIFT;
+ temp = (calib_data[3] & TSENS_CAL_SEL_2)
+ >> TSENS_CAL_SEL_SHIFT_2;
tsens_calibration_mode |= temp;
- if (!tsens_calibration_mode) {
+ if (tsens_calibration_mode == 0) {
pr_debug("TSENS is calibrationless mode\n");
for (i = 0; i < tmdev->tsens_num_sensor; i++) {
- tmdev->sensor[i].calib_data_point2 = 78000;
- tmdev->sensor[i].calib_data_point1 = 49200;
- goto compute_intercept_slope;
+ tmdev->sensor[i].calib_data_point2 = 780;
+ tmdev->sensor[i].calib_data_point1 = 492;
}
+ goto compute_intercept_slope;
} else if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
TSENS_TWO_POINT_CALIB) {
- tsens_base1_data = calib_data[0] & TSENS_BASE1_MASK;
- tsens0_point1 = calib_data[0] & TSENS0_POINT1_MASK;
- tsens1_point1 = calib_data[0] & TSENS1_POINT1_MASK;
- tsens2_point1 = calib_data[0] & TSENS2_POINT1_MASK;
- tsens3_point1 = calib_data[0] & TSENS3_POINT1_MASK;
- tsens4_point1 = calib_data[1] & TSENS4_POINT1_MASK;
- tsens5_point1 = calib_data[1] & TSENS5_POINT1_MASK;
- tsens6_point1 = calib_data[1] & TSENS6_POINT1_MASK;
- tsens7_point1 = calib_data[1] & TSENS7_POINT1_MASK;
- tsens8_point1 = calib_data[1] & TSENS8_POINT1_MASK;
- tsens9_point1 = calib_data[2] & TSENS9_POINT1_MASK;
- tsens10_point1 = calib_data[2] & TSENS10_POINT1_MASK;
+ tsens_base1_data = (calib_data[0] & TSENS_BASE1_MASK);
+ tsens0_point1 = (calib_data[0] & TSENS0_POINT1_MASK) >>
+ TSENS0_POINT1_SHIFT;
+ tsens1_point1 = (calib_data[0] & TSENS1_POINT1_MASK) >>
+ TSENS1_POINT1_SHIFT;
+ tsens2_point1 = (calib_data[0] & TSENS2_POINT1_MASK) >>
+ TSENS2_POINT1_SHIFT;
+ tsens3_point1 = (calib_data[0] & TSENS3_POINT1_MASK) >>
+ TSENS3_POINT1_SHIFT;
+ tsens4_point1 = (calib_data[1] & TSENS4_POINT1_MASK);
+ tsens5_point1 = (calib_data[1] & TSENS5_POINT1_MASK) >>
+ TSENS5_POINT1_SHIFT;
+ tsens6_point1 = (calib_data[1] & TSENS6_POINT1_MASK) >>
+ TSENS6_POINT1_SHIFT;
+ tsens7_point1 = (calib_data[1] & TSENS7_POINT1_MASK) >>
+ TSENS7_POINT1_SHIFT;
+ tsens8_point1 = (calib_data[1] & TSENS8_POINT1_MASK) >>
+ TSENS8_POINT1_SHIFT;
+ tsens9_point1 = (calib_data[2] & TSENS9_POINT1_MASK);
+ tsens10_point1 = (calib_data[2] & TSENS10_POINT1_MASK) >>
+ TSENS10_POINT1_SHIFT;
} else if (tsens_calibration_mode == TSENS_TWO_POINT_CALIB) {
- tsens_base2_data = calib_data[2] & TSENS_BASE2_MASK;
- tsens0_point2 = calib_data[2] & TSENS0_POINT2_MASK;
- tsens1_point2 = calib_data[2] & TSENS1_POINT2_MASK;
- tsens2_point2 = calib_data[3] & TSENS2_POINT2_MASK;
- tsens3_point2 = calib_data[3] & TSENS3_POINT2_MASK;
- tsens4_point2 = calib_data[3] & TSENS4_POINT2_MASK;
- tsens5_point2 = calib_data[3] & TSENS5_POINT2_MASK;
- tsens6_point2 = calib_data[3] & TSENS6_POINT2_MASK;
- tsens7_point2 = calib_data[4] & TSENS7_POINT2_MASK;
- tsens8_point2 = calib_data[4] & TSENS8_POINT2_MASK;
- tsens9_point2 = calib_data[4] & TSENS9_POINT2_MASK;
- tsens10_point2 = calib_data[4] & TSENS10_POINT2_MASK;
+ tsens_base2_data = (calib_data[2] & TSENS_BASE2_MASK) >>
+ TSENS_POINT2_BASE_SHIFT;
+ tsens0_point2 = (calib_data[2] & TSENS0_POINT2_MASK) >>
+ TSENS0_POINT2_SHIFT;
+ tsens1_point2 = (calib_data[2] & TSENS1_POINT2_MASK) >>
+ TSENS1_POINT2_SHIFT;
+ tsens2_point2 = (calib_data[3] & TSENS2_POINT2_MASK);
+ tsens3_point2 = (calib_data[3] & TSENS3_POINT2_MASK) >>
+ TSENS3_POINT2_SHIFT;
+ tsens4_point2 = (calib_data[3] & TSENS4_POINT2_MASK) >>
+ TSENS4_POINT2_SHIFT;
+ tsens5_point2 = (calib_data[3] & TSENS5_POINT2_MASK) >>
+ TSENS5_POINT2_SHIFT;
+ tsens6_point2 = (calib_data[3] & TSENS6_POINT2_MASK) >>
+ TSENS6_POINT2_SHIFT;
+ tsens7_point2 = (calib_data[4] & TSENS7_POINT2_MASK);
+ tsens8_point2 = (calib_data[4] & TSENS8_POINT2_MASK) >>
+ TSENS8_POINT2_SHIFT;
+ tsens9_point2 = (calib_data[4] & TSENS9_POINT2_MASK) >>
+ TSENS9_POINT2_SHIFT;
+ tsens10_point2 = (calib_data[4] & TSENS10_POINT2_MASK) >>
+ TSENS10_POINT2_SHIFT;
} else {
pr_debug("Calibration mode is unknown: %d\n",
tsens_calibration_mode);
return -ENODEV;
}
- if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB) {
+ if (tsens_calibration_mode == TSENS_ONE_POINT_CALIB ||
+ TSENS_TWO_POINT_CALIB) {
tmdev->sensor[0].calib_data_point1 =
(((tsens_base1_data + tsens0_point1) << 2) | TSENS_BIT_APPEND);
tmdev->sensor[1].calib_data_point1 =
@@ -580,7 +620,7 @@
tmdev->sensor[8].calib_data_point2 =
(((tsens_base2_data + tsens8_point2) << 2) | TSENS_BIT_APPEND);
tmdev->sensor[9].calib_data_point2 =
- (((tsens_base2_data + tsens9_point2) < 2) | TSENS_BIT_APPEND);
+ (((tsens_base2_data + tsens9_point2) << 2) | TSENS_BIT_APPEND);
tmdev->sensor[10].calib_data_point2 =
(((tsens_base2_data + tsens10_point2) << 2) | TSENS_BIT_APPEND);
}
@@ -595,10 +635,9 @@
num *= tmdev->tsens_factor;
tmdev->sensor[i].slope_mul_tsens_factor = num/den;
}
- tmdev->sensor[i].offset = (TSENS_CAL_DEGC_POINT1 *
- tmdev->tsens_factor)
- - (tmdev->sensor[i].calib_data_point1 *
- tmdev->sensor[i].slope_mul_tsens_factor);
+ tmdev->sensor[i].offset = (tmdev->sensor[i].calib_data_point1 *
+ tmdev->tsens_factor) - (TSENS_CAL_DEGC_POINT1 *
+ tmdev->sensor[i].slope_mul_tsens_factor);
INIT_WORK(&tmdev->sensor[i].work, notify_uspace_tsens_fn);
tmdev->prev_reading_avail = false;
}
@@ -747,6 +786,7 @@
goto fail;
tsens_hw_init();
+
tmdev->prev_reading_avail = true;
platform_set_drvdata(pdev, tmdev);
@@ -796,6 +836,7 @@
goto fail;
}
}
+
rc = request_irq(tmdev->tsens_irq, tsens_isr,
IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
if (rc < 0) {
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 1904706..9386804 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -2122,7 +2122,6 @@
free_irq(uport->irq, msm_uport);
if (use_low_power_wakeup(msm_uport))
free_irq(msm_uport->wakeup.irq, msm_uport);
- mutex_destroy(&msm_uport->clk_mutex);
}
static void __exit msm_serial_hs_exit(void)
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 6c9b7cd..3d29607 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -185,25 +185,19 @@
/* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */
}
-
/**
- * tty_buffer_request_room - grow tty buffer if needed
+ * __tty_buffer_request_room - grow tty buffer if needed
* @tty: tty structure
* @size: size desired
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
- *
- * Locking: Takes tty->buf.lock
+ * Locking: Caller must hold tty->buf.lock
*/
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
struct tty_buffer *b, *n;
int left;
- unsigned long flags;
-
- spin_lock_irqsave(&tty->buf.lock, flags);
-
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
remove this conditional if its worth it. This would be invisible
to the callers */
@@ -225,9 +219,30 @@
size = left;
}
- spin_unlock_irqrestore(&tty->buf.lock, flags);
return size;
}
+
+
+/**
+ * tty_buffer_request_room - grow tty buffer if needed
+ * @tty: tty structure
+ * @size: size desired
+ *
+ * Make at least size bytes of linear space available for the tty
+ * buffer. If we fail return the size we managed to find.
+ *
+ * Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+ unsigned long flags;
+ int length;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ length = __tty_buffer_request_room(tty, size);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+ return length;
+}
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
/**
@@ -249,14 +264,22 @@
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
- int space = tty_buffer_request_room(tty, goal);
- struct tty_buffer *tb = tty->buf.tail;
+ int space;
+ unsigned long flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ space = __tty_buffer_request_room(tty, goal);
+ tb = tty->buf.tail;
/* If there is no space then tb may be NULL */
- if (unlikely(space == 0))
+ if (unlikely(space == 0)) {
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
break;
+ }
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space;
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
copied += space;
chars += space;
/* There is a small chance that we need to split the data over
@@ -286,14 +309,22 @@
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
- int space = tty_buffer_request_room(tty, goal);
- struct tty_buffer *tb = tty->buf.tail;
+ int space;
+ unsigned long __flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, __flags);
+ space = __tty_buffer_request_room(tty, goal);
+ tb = tty->buf.tail;
/* If there is no space then tb may be NULL */
- if (unlikely(space == 0))
+ if (unlikely(space == 0)) {
+ spin_unlock_irqrestore(&tty->buf.lock, __flags);
break;
+ }
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memcpy(tb->flag_buf_ptr + tb->used, flags, space);
tb->used += space;
+ spin_unlock_irqrestore(&tty->buf.lock, __flags);
copied += space;
chars += space;
flags += space;
@@ -344,13 +375,20 @@
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
size_t size)
{
- int space = tty_buffer_request_room(tty, size);
+ int space;
+ unsigned long flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ space = __tty_buffer_request_room(tty, size);
+
+ tb = tty->buf.tail;
if (likely(space)) {
- struct tty_buffer *tb = tty->buf.tail;
*chars = tb->char_buf_ptr + tb->used;
memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
tb->used += space;
}
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
@@ -374,13 +412,20 @@
int tty_prepare_flip_string_flags(struct tty_struct *tty,
unsigned char **chars, char **flags, size_t size)
{
- int space = tty_buffer_request_room(tty, size);
+ int space;
+ unsigned long __flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, __flags);
+ space = __tty_buffer_request_room(tty, size);
+
+ tb = tty->buf.tail;
if (likely(space)) {
- struct tty_buffer *tb = tty->buf.tail;
*chars = tb->char_buf_ptr + tb->used;
*flags = tb->flag_buf_ptr + tb->used;
tb->used += space;
}
+ spin_unlock_irqrestore(&tty->buf.lock, __flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
@@ -418,6 +463,8 @@
int count;
char *char_buf;
unsigned char *flag_buf;
+ unsigned int left = 0;
+ unsigned int max_space;
count = head->commit - head->read;
if (!count) {
@@ -432,10 +479,33 @@
line discipline as we want to empty the queue */
if (test_bit(TTY_FLUSHPENDING, &tty->flags))
break;
+
+ /* update receive room */
+ spin_lock(&tty->read_lock);
+ if (tty->update_room_in_ldisc) {
+ if ((tty->read_cnt == N_TTY_BUF_SIZE - 1) &&
+ (tty->receive_room ==
+ N_TTY_BUF_SIZE - 1))
+ tty->rr_bug++;
+ left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+ }
+ spin_unlock(&tty->read_lock);
+
if (!tty->receive_room)
break;
- if (count > tty->receive_room)
- count = tty->receive_room;
+
+ if (tty->update_room_in_ldisc && !left) {
+ schedule_work(&tty->buf.work);
+ break;
+ }
+
+ if (tty->update_room_in_ldisc)
+ max_space = min(left, tty->receive_room);
+ else
+ max_space = tty->receive_room;
+
+ if (count > max_space)
+ count = max_space;
char_buf = head->char_buf_ptr + head->read;
flag_buf = head->flag_buf_ptr + head->read;
head->read += count;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index c95f82d..de9a7aa 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -1121,15 +1121,4 @@
help
Data SMD channel for transferring network data
-config USB_ANDROID_RMNET_CTRL_SMD
- boolean "RmNet(BAM) control over SMD driver"
- depends on MSM_SMD
- help
- Enabling this option adds rmnet control over SMD
- support to the android gadget. Rmnet is an
- alternative to CDC-ECM and Windows RNDIS.
- It uses QUALCOMM MSM Interface for control
- transfers. This option enables only control interface.
- Data interface used is BAM.
-
endif # USB_GADGET
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index b997a3f..9778673 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -48,7 +48,6 @@
atomic_t read_excl;
atomic_t write_excl;
atomic_t open_excl;
- struct delayed_work adb_release_w;
struct list_head tx_idle;
@@ -410,11 +409,6 @@
return r;
}
-static void adb_release_work(struct work_struct *w)
-{
- adb_closed_callback();
-}
-
static int adb_open(struct inode *ip, struct file *fp)
{
pr_info("adb_open\n");
@@ -429,8 +423,7 @@
/* clear the error latch */
atomic_set(&_adb_dev->error, 0);
- if (!cancel_delayed_work_sync(&_adb_dev->adb_release_w))
- adb_ready_callback();
+ adb_ready_callback();
return 0;
}
@@ -439,16 +432,7 @@
{
pr_info("adb_release\n");
- /*
- * When USB cable is plugged out, adb reader is unblocked and
- * -EIO is returned to user space. adb daemon reopen the port
- * which would disable and enable USB configuration unnecessarily.
- *
- * Delay notifying the adb close event to android by 1 sec. If
- * ADB daemon opens the port with in 1 sec, USB configuration
- * re-enable does not happen.
- */
- schedule_delayed_work(&_adb_dev->adb_release_w, msecs_to_jiffies(1000));
+ adb_closed_callback();
adb_unlock(&_adb_dev->open_excl);
return 0;
@@ -624,7 +608,6 @@
atomic_set(&dev->read_excl, 0);
atomic_set(&dev->write_excl, 0);
- INIT_DELAYED_WORK(&dev->adb_release_w, adb_release_work);
INIT_LIST_HEAD(&dev->tx_idle);
_adb_dev = dev;
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 7309438..8d967cd 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -691,8 +691,7 @@
hw->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
/* clear interrupt enables, set irq latency */
- if (ehci->max_log2_irq_thresh)
- log2_irq_thresh = ehci->max_log2_irq_thresh;
+ log2_irq_thresh = ehci->log2_irq_thresh;
if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
log2_irq_thresh = 0;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 4dd6d68..b396593 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -47,6 +47,8 @@
#define USB_REG_START_OFFSET 0x90
#define USB_REG_END_OFFSET 0x250
+static struct workqueue_struct *ehci_wq;
+
struct msm_hsic_hcd {
struct ehci_hcd ehci;
struct device *dev;
@@ -66,6 +68,9 @@
uint32_t bus_perf_client;
uint32_t wakeup_int_cnt;
enum usb_vdd_type vdd_type;
+
+ struct work_struct bus_vote_w;
+ bool bus_vote;
};
struct msm_hsic_hcd *__mehci;
@@ -349,21 +354,33 @@
static int ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
{
struct usb_hcd *hcd = hsic_to_hcd(mehci);
- unsigned long timeout;
+ int cnt = 0;
/* initiate read operation */
writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg),
USB_ULPI_VIEWPORT);
/* wait for completion */
- timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USEC);
- while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) {
- if (time_after(jiffies, timeout)) {
- dev_err(mehci->dev, "ulpi_read: timeout %08x\n",
- readl_relaxed(USB_ULPI_VIEWPORT));
- return -ETIMEDOUT;
- }
+ while (cnt < ULPI_IO_TIMEOUT_USEC) {
+ if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
+ break;
udelay(1);
+ cnt++;
+ }
+
+ if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+ dev_err(mehci->dev, "ulpi_read: timeout ULPI_VIEWPORT: %08x\n",
+ readl_relaxed(USB_ULPI_VIEWPORT));
+ dev_err(mehci->dev, "PORTSC: %08x USBCMD: %08x FRINDEX: %08x\n",
+ readl_relaxed(USB_PORTSC),
+ readl_relaxed(USB_USBCMD),
+ readl_relaxed(USB_FRINDEX));
+
+ /*frame counter increments afte 125us*/
+ udelay(130);
+ dev_err(mehci->dev, "ulpi_read: FRINDEX: %08x\n",
+ readl_relaxed(USB_FRINDEX));
+ return -ETIMEDOUT;
}
return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT));
@@ -388,7 +405,17 @@
}
if (cnt >= ULPI_IO_TIMEOUT_USEC) {
- dev_err(mehci->dev, "ulpi_write: timeout\n");
+ dev_err(mehci->dev, "ulpi_write: timeout ULPI_VIEWPORT: %08x\n",
+ readl_relaxed(USB_ULPI_VIEWPORT));
+ dev_err(mehci->dev, "PORTSC: %08x USBCMD: %08x FRINDEX: %08x\n",
+ readl_relaxed(USB_PORTSC),
+ readl_relaxed(USB_USBCMD),
+ readl_relaxed(USB_FRINDEX));
+
+ /*frame counter increments afte 125us*/
+ udelay(130);
+ dev_err(mehci->dev, "ulpi_write: FRINDEX: %08x\n",
+ readl_relaxed(USB_FRINDEX));
return -ETIMEDOUT;
}
@@ -658,11 +685,8 @@
dev_err(mehci->dev, "unable to set vddcx voltage for VDD MIN\n");
if (mehci->bus_perf_client && debug_bus_voting_enabled) {
- ret = msm_bus_scale_client_update_request(
- mehci->bus_perf_client, 0);
- if (ret)
- dev_err(mehci->dev, "%s: Failed to dvote for "
- "bus bandwidth %d\n", __func__, ret);
+ mehci->bus_vote = false;
+ queue_work(ehci_wq, &mehci->bus_vote_w);
}
atomic_set(&mehci->in_lpm, 1);
@@ -697,11 +721,8 @@
}
if (mehci->bus_perf_client && debug_bus_voting_enabled) {
- ret = msm_bus_scale_client_update_request(
- mehci->bus_perf_client, 1);
- if (ret)
- dev_err(mehci->dev, "%s: Failed to vote for "
- "bus bandwidth %d\n", __func__, ret);
+ mehci->bus_vote = true;
+ queue_work(ehci_wq, &mehci->bus_vote_w);
}
min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
@@ -769,6 +790,19 @@
}
#endif
+static void ehci_hsic_bus_vote_w(struct work_struct *w)
+{
+ struct msm_hsic_hcd *mehci =
+ container_of(w, struct msm_hsic_hcd, bus_vote_w);
+ int ret;
+
+ ret = msm_bus_scale_client_update_request(mehci->bus_perf_client,
+ mehci->bus_vote);
+ if (ret)
+ dev_err(mehci->dev, "%s: Failed to vote for bus bandwidth %d\n",
+ __func__, ret);
+}
+
static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
{
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -1253,13 +1287,15 @@
mehci = hcd_to_hsic(hcd);
mehci->dev = &pdev->dev;
+ pdata = mehci->dev->platform_data;
mehci->ehci.susp_sof_bug = 1;
mehci->ehci.reset_sof_bug = 1;
mehci->ehci.resume_sof_bug = 1;
- mehci->ehci.max_log2_irq_thresh = 6;
+ if (pdata)
+ mehci->ehci.log2_irq_thresh = pdata->log2_irq_thresh;
res = platform_get_resource_byname(pdev,
IORESOURCE_IRQ,
@@ -1294,6 +1330,15 @@
goto deinit_vddcx;
}
+ ehci_wq = create_singlethread_workqueue("ehci_wq");
+ if (!ehci_wq) {
+ dev_err(&pdev->dev, "unable to create workqueue\n");
+ ret = -ENOMEM;
+ goto deinit_vddcx;
+ }
+
+ INIT_WORK(&mehci->bus_vote_w, ehci_hsic_bus_vote_w);
+
ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
if (ret) {
dev_err(&pdev->dev, "unable to register HCD\n");
@@ -1333,17 +1378,13 @@
dev_dbg(&pdev->dev, "mode debugfs file is"
"not available\n");
- pdata = mehci->dev->platform_data;
if (pdata && pdata->bus_scale_table) {
mehci->bus_perf_client =
msm_bus_scale_register_client(pdata->bus_scale_table);
/* Configure BUS performance parameters for MAX bandwidth */
if (mehci->bus_perf_client) {
- ret = msm_bus_scale_client_update_request(
- mehci->bus_perf_client, 1);
- if (ret)
- dev_err(&pdev->dev, "%s: Failed to vote for "
- "bus bandwidth %d\n", __func__, ret);
+ mehci->bus_vote = true;
+ queue_work(ehci_wq, &mehci->bus_vote_w);
} else {
dev_err(&pdev->dev, "%s: Failed to register BUS "
"scaling client!!\n", __func__);
@@ -1369,6 +1410,7 @@
return 0;
unconfig_gpio:
+ destroy_workqueue(ehci_wq);
msm_hsic_config_gpios(mehci, 0);
deinit_vddcx:
msm_hsic_init_vddcx(mehci, 0);
@@ -1396,6 +1438,14 @@
free_irq(mehci->wakeup_irq, mehci);
}
+ /*
+ * If the update request is called after unregister, the request will
+ * fail. Results are undefined if unregister is called in the middle of
+ * update request.
+ */
+ mehci->bus_vote = false;
+ cancel_work_sync(&mehci->bus_vote_w);
+
if (mehci->bus_perf_client)
msm_bus_scale_unregister_client(mehci->bus_perf_client);
@@ -1403,6 +1453,8 @@
device_init_wakeup(&pdev->dev, 0);
pm_runtime_set_suspended(&pdev->dev);
+ destroy_workqueue(ehci_wq);
+
usb_remove_hcd(hcd);
msm_hsic_config_gpios(mehci, 0);
msm_hsic_init_vddcx(mehci, 0);
@@ -1436,12 +1488,26 @@
return ret;
}
+static int msm_hsic_pm_suspend_noirq(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+
+ if (mehci->async_int) {
+ dev_dbg(dev, "suspend_noirq: Aborting due to pending interrupt\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
static int msm_hsic_pm_resume(struct device *dev)
{
int ret;
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ dev_dbg(dev, "ehci-msm-hsic PM resume\n");
dbg_log_event(NULL, "PM Resume", 0);
if (device_may_wakeup(dev))
@@ -1495,6 +1561,7 @@
#ifdef CONFIG_PM
static const struct dev_pm_ops msm_hsic_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(msm_hsic_pm_suspend, msm_hsic_pm_resume)
+ .suspend_noirq = msm_hsic_pm_suspend_noirq,
SET_RUNTIME_PM_OPS(msm_hsic_runtime_suspend, msm_hsic_runtime_resume,
msm_hsic_runtime_idle)
};
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index c612cb9..34d90fb 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -59,6 +59,7 @@
uint32_t pmic_gpio_int_cnt;
atomic_t pm_usage_cnt;
struct wake_lock wlock;
+ struct work_struct phy_susp_fail_work;
};
static inline struct msm_hcd *hcd_to_mhcd(struct usb_hcd *hcd)
@@ -539,6 +540,19 @@
return 0;
}
+static void msm_ehci_phy_susp_fail_work(struct work_struct *w)
+{
+ struct msm_hcd *mhcd = container_of(w, struct msm_hcd,
+ phy_susp_fail_work);
+ struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+
+ msm_ehci_vbus_power(mhcd, 0);
+ usb_remove_hcd(hcd);
+ msm_hsusb_reset(mhcd);
+ usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+ msm_ehci_vbus_power(mhcd, 1);
+}
+
#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
@@ -571,8 +585,8 @@
while (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD)) {
if (time_after(jiffies, timeout)) {
dev_err(mhcd->dev, "Unable to suspend PHY\n");
- msm_hsusb_reset(mhcd);
- break;
+ schedule_work(&mhcd->phy_susp_fail_work);
+ return -ETIMEDOUT;
}
udelay(1);
}
@@ -992,6 +1006,7 @@
device_init_wakeup(&pdev->dev, 1);
wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
wake_lock(&mhcd->wlock);
+ INIT_WORK(&mhcd->phy_susp_fail_work, msm_ehci_phy_susp_fail_work);
/*
* This pdev->dev is assigned parent of root-hub by USB core,
* hence, runtime framework automatically calls this driver's
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index a0f995c..f8b884a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -135,7 +135,7 @@
ktime_t last_periodic_enable;
u32 command;
- unsigned max_log2_irq_thresh;
+ unsigned log2_irq_thresh;
/* SILICON QUIRKS */
unsigned no_selective_suspend:1;
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 10cbe59..be8b58b 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -58,6 +58,7 @@
struct list_head to_mdm_list;
struct list_head to_ks_list;
wait_queue_head_t ks_wait_q;
+ struct miscdevice *fs_dev;
/* usb specific */
struct usb_device *udev;
@@ -531,7 +532,6 @@
struct usb_endpoint_descriptor *ep_desc;
int i;
struct ks_bridge *ksb;
- struct miscdevice *fs_dev;
ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
@@ -585,8 +585,8 @@
dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
- fs_dev = (struct miscdevice *)id->driver_info;
- misc_register(fs_dev);
+ ksb->fs_dev = (struct miscdevice *)id->driver_info;
+ misc_register(ksb->fs_dev);
usb_enable_autosuspend(ksb->udev);
@@ -649,6 +649,7 @@
}
spin_unlock_irqrestore(&ksb->lock, flags);
+ misc_deregister(ksb->fs_dev);
usb_put_dev(ksb->udev);
ksb->ifc = NULL;
usb_set_intfdata(ifc, NULL);
@@ -713,7 +714,8 @@
ksb = kzalloc(sizeof(struct ks_bridge), GFP_KERNEL);
if (!ksb) {
pr_err("unable to allocat mem for ks_bridge");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto dev_free;
}
__ksb[i] = ksb;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 355990a..0ef8249 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -879,6 +879,8 @@
if (device_may_wakeup(phy->dev)) {
enable_irq_wake(motg->irq);
+ if (motg->async_irq)
+ enable_irq_wake(motg->async_irq);
if (motg->pdata->pmic_id_irq)
enable_irq_wake(motg->pdata->pmic_id_irq);
if (pdata->otg_control == OTG_PHY_CONTROL &&
@@ -889,6 +891,9 @@
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
atomic_set(&motg->in_lpm, 1);
+ /* Enable ASYNC IRQ (if present) during LPM */
+ if (motg->async_irq)
+ enable_irq(motg->async_irq);
enable_irq(motg->irq);
wake_unlock(&motg->wlock);
@@ -979,6 +984,8 @@
skip_phy_resume:
if (device_may_wakeup(phy->dev)) {
disable_irq_wake(motg->irq);
+ if (motg->async_irq)
+ disable_irq_wake(motg->async_irq);
if (motg->pdata->pmic_id_irq)
disable_irq_wake(motg->pdata->pmic_id_irq);
if (pdata->otg_control == OTG_PHY_CONTROL &&
@@ -991,10 +998,15 @@
atomic_set(&motg->in_lpm, 0);
if (motg->async_int) {
+ /* Match the disable_irq call from ISR */
+ enable_irq(motg->async_int);
motg->async_int = 0;
- enable_irq(motg->irq);
}
+ /* If ASYNC IRQ is present then keep it enabled only during LPM */
+ if (motg->async_irq)
+ disable_irq(motg->async_irq);
+
dev_info(phy->dev, "USB exited from low power mode\n");
return 0;
@@ -2728,17 +2740,11 @@
irqreturn_t ret = IRQ_HANDLED;
if (atomic_read(&motg->in_lpm)) {
- pr_debug("OTG IRQ: in LPM\n");
+ pr_debug("OTG IRQ: %d in LPM\n", irq);
disable_irq_nosync(irq);
- motg->async_int = 1;
- if (atomic_read(&motg->pm_suspended)) {
- motg->sm_work_pending = true;
- if ((otg->phy->state == OTG_STATE_A_SUSPEND) ||
- (otg->phy->state == OTG_STATE_A_WAIT_BCON))
- set_bit(A_BUS_REQ, &motg->inputs);
- } else {
+ motg->async_int = irq;
+ if (!atomic_read(&motg->pm_suspended))
pm_request_resume(otg->phy->dev);
- }
return IRQ_HANDLED;
}
@@ -3397,7 +3403,7 @@
static int __init msm_otg_probe(struct platform_device *pdev)
{
- int ret = 0, disable_lpm = 0;
+ int ret = 0;
struct resource *res;
struct msm_otg *motg;
struct usb_phy *phy;
@@ -3415,8 +3421,6 @@
dev_err(&pdev->dev, "devices setup failed\n");
return ret;
}
- /* LPM not supported on targets using DT */
- disable_lpm = 1;
} else if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "No platform data given. Bailing out\n");
return -ENODEV;
@@ -3516,6 +3520,12 @@
goto free_regs;
}
+ motg->async_irq = platform_get_irq_byname(pdev, "async_irq");
+ if (motg->async_irq < 0) {
+ dev_dbg(&pdev->dev, "platform_get_irq for async_int failed\n");
+ motg->async_irq = 0;
+ }
+
motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
if (IS_ERR(motg->xo_handle)) {
dev_err(&pdev->dev, "%s not able to get the handle "
@@ -3602,6 +3612,16 @@
goto destroy_wlock;
}
+ if (motg->async_irq) {
+ ret = request_irq(motg->async_irq, msm_otg_irq, IRQF_SHARED,
+ "msm_otg", motg);
+ if (ret) {
+ dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
+ goto free_irq;
+ }
+ disable_irq(motg->async_irq);
+ }
+
if (pdata->otg_control == OTG_PHY_CONTROL && pdata->mpm_otgsessvld_int)
msm_mpm_enable_pin(pdata->mpm_otgsessvld_int, 1);
@@ -3620,7 +3640,7 @@
ret = usb_set_transceiver(&motg->phy);
if (ret) {
dev_err(&pdev->dev, "usb_set_transceiver failed\n");
- goto free_irq;
+ goto free_async_irq;
}
if (motg->pdata->mode == USB_OTG &&
@@ -3672,8 +3692,7 @@
wake_lock(&motg->wlock);
pm_runtime_set_active(&pdev->dev);
- if (!disable_lpm)
- pm_runtime_enable(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
if (motg->pdata->bus_scale_table) {
motg->bus_perf_client =
@@ -3689,6 +3708,9 @@
remove_phy:
usb_set_transceiver(NULL);
+free_async_irq:
+ if (motg->async_irq)
+ free_irq(motg->async_irq, motg);
free_irq:
free_irq(motg->irq, motg);
destroy_wlock:
@@ -3861,9 +3883,7 @@
dev_dbg(dev, "OTG PM resume\n");
atomic_set(&motg->pm_suspended, 0);
- if (motg->sm_work_pending) {
- motg->sm_work_pending = false;
-
+ if (motg->async_int || motg->sm_work_pending) {
pm_runtime_get_noresume(dev);
ret = msm_otg_resume(motg);
@@ -3872,7 +3892,10 @@
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- queue_work(system_nrt_wq, &motg->sm_work);
+ if (motg->sm_work_pending) {
+ motg->sm_work_pending = false;
+ queue_work(system_nrt_wq, &motg->sm_work);
+ }
}
return ret;
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 366df67..c3f741b 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -495,6 +495,7 @@
/* explicitly set the driver mode to raw */
tty->raw = 1;
tty->real_raw = 1;
+ tty->update_room_in_ldisc = 1;
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
dbg("%s", __func__);
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 0976fc6..c6ffaf2 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -1418,7 +1418,7 @@
video_format, video_format_2string(video_format),
supported ? "Supported" : "Not-Supported");
if (supported) {
- if (mhl_is_connected()) {
+ if (mhl_is_enabled()) {
const struct hdmi_disp_mode_timing_type *mhl_timing =
hdmi_mhl_get_supported_mode(video_format);
boolean mhl_supported = mhl_timing != NULL;
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 26e5687..ade9691 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -917,22 +917,34 @@
*/
if (external_common_state->present_hdcp) {
hdcp_deauthenticate();
+ mutex_lock(&hdcp_auth_state_mutex);
+ hdmi_msm_state->reauth = TRUE;
+ mutex_unlock(&hdcp_auth_state_mutex);
mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
}
}
static void hdmi_msm_hdcp_work(struct work_struct *work)
{
-
/* Only re-enable if cable still connected */
mutex_lock(&external_common_state_hpd_mutex);
if (external_common_state->hpd_state &&
!(hdmi_msm_state->full_auth_done)) {
mutex_unlock(&external_common_state_hpd_mutex);
- hdmi_msm_state->reauth = TRUE;
- hdmi_msm_turn_on();
- } else
+ if (hdmi_msm_state->reauth == TRUE) {
+ DEV_DBG("%s: Starting HDCP re-authentication\n",
+ __func__);
+ hdmi_msm_turn_on();
+ } else {
+ DEV_DBG("%s: Starting HDCP authentication\n", __func__);
+ hdmi_msm_hdcp_enable();
+ }
+ } else {
mutex_unlock(&external_common_state_hpd_mutex);
+ DEV_DBG("%s: HDMI not connected or HDCP already active\n",
+ __func__);
+ hdmi_msm_state->reauth = FALSE;
+ }
}
#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
@@ -4342,15 +4354,6 @@
DEV_INFO("power: ON (%dx%d %d)\n", mfd->var_xres, mfd->var_yres,
mfd->var_pixclock);
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- mutex_lock(&hdmi_msm_state_mutex);
- if (hdmi_msm_state->hdcp_activating) {
- hdmi_msm_state->panel_power_on = TRUE;
- DEV_INFO("HDCP: activating, returning\n");
- }
- mutex_unlock(&hdmi_msm_state_mutex);
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
-
changed = hdmi_common_get_video_format_from_drv_data(mfd);
hdmi_msm_audio_info_setup(TRUE, 0, 0, 0, FALSE);
@@ -4360,7 +4363,13 @@
DEV_DBG("%s: Turning HDMI on\n", __func__);
mutex_unlock(&external_common_state_hpd_mutex);
hdmi_msm_turn_on();
- hdmi_msm_hdcp_enable();
+
+ /* Kick off HDCP Authentication */
+ mutex_lock(&hdcp_auth_state_mutex);
+ hdmi_msm_state->reauth = FALSE;
+ hdmi_msm_state->full_auth_done = FALSE;
+ mutex_unlock(&hdcp_auth_state_mutex);
+ mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
} else
mutex_unlock(&external_common_state_hpd_mutex);
@@ -4448,6 +4457,11 @@
return 0;
}
+bool mhl_is_enabled(void)
+{
+ return hdmi_msm_state->is_mhl_enabled;
+}
+
static int __devinit hdmi_msm_probe(struct platform_device *pdev)
{
int rc;
@@ -4620,6 +4634,12 @@
if (switch_dev_register(&external_common_state->sdev) < 0)
DEV_ERR("Hdmi switch registration failed\n");
+ /* Set the default video resolution for MHL-enabled display */
+ if (hdmi_msm_state->is_mhl_enabled) {
+ DEV_DBG("MHL Enabled. Restricting default video resolution\n");
+ external_common_state->video_resolution =
+ HDMI_VFRMT_1920x1080p30_16_9;
+ }
return 0;
error:
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
index 2987e2f..13bb9e3 100644
--- a/drivers/video/msm/lvds.c
+++ b/drivers/video/msm/lvds.c
@@ -173,7 +173,7 @@
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
- MDP_OUTP(MDP_BASE + 0xc2024, 0x151a191a);
+ MDP_OUTP(MDP_BASE + 0xc2024, 0x1518191a);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index d911b62..6d14ec1 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -50,6 +50,7 @@
static struct clk *mdp_lut_clk;
int mdp_rev;
int mdp_iommu_split_domain;
+u32 mdp_max_clk = 200000000;
static struct platform_device *mdp_init_pdev;
static struct regulator *footswitch;
@@ -2178,33 +2179,6 @@
__func__, mdp_hw_revision);
}
-#ifdef CONFIG_FB_MSM_MDP40
-static void configure_mdp_core_clk_table(uint32 min_clk_rate)
-{
- uint8 count;
- uint32 current_rate;
- if (mdp_clk && mdp_pdata && mdp_pdata->mdp_core_clk_table) {
- min_clk_rate = clk_round_rate(mdp_clk, min_clk_rate);
- if (clk_set_rate(mdp_clk, min_clk_rate) < 0)
- printk(KERN_ERR "%s: clk_set_rate failed\n",
- __func__);
- else {
- count = 0;
- current_rate = clk_get_rate(mdp_clk);
- while (count < mdp_pdata->num_mdp_clk) {
- if (mdp_pdata->mdp_core_clk_table[count]
- < current_rate) {
- mdp_pdata->
- mdp_core_clk_table[count] =
- current_rate;
- }
- count++;
- }
- }
- }
-}
-#endif
-
#ifdef CONFIG_MSM_BUS_SCALING
static uint32_t mdp_bus_scale_handle;
int mdp_bus_scale_update_request(uint32_t index)
@@ -2223,29 +2197,24 @@
}
#endif
DEFINE_MUTEX(mdp_clk_lock);
-int mdp_set_core_clk(uint16 perf_level)
+int mdp_set_core_clk(u32 rate)
{
int ret = -EINVAL;
- if (mdp_clk && mdp_pdata
- && mdp_pdata->mdp_core_clk_table) {
- if (perf_level > mdp_pdata->num_mdp_clk)
- printk(KERN_ERR "%s invalid perf level\n", __func__);
- else {
- mutex_lock(&mdp_clk_lock);
- ret = clk_set_rate(mdp_clk,
- mdp_pdata->
- mdp_core_clk_table[mdp_pdata->num_mdp_clk
- - perf_level]);
- mutex_unlock(&mdp_clk_lock);
- if (ret) {
- printk(KERN_ERR "%s unable to set mdp_core_clk rate\n",
- __func__);
- }
- }
- }
+ if (mdp_clk)
+ ret = clk_set_rate(mdp_clk, rate);
+ if (ret)
+ pr_err("%s unable to set mdp clk rate", __func__);
+ else
+ pr_debug("%s mdp clk rate to be set %d: actual rate %ld\n",
+ __func__, rate, clk_get_rate(mdp_clk));
return ret;
}
+int mdp_clk_round_rate(u32 rate)
+{
+ return clk_round_rate(mdp_clk, rate);
+}
+
unsigned long mdp_get_core_clk(void)
{
unsigned long clk_rate = 0;
@@ -2258,25 +2227,6 @@
return clk_rate;
}
-unsigned long mdp_perf_level2clk_rate(uint32 perf_level)
-{
- unsigned long clk_rate = 0;
-
- if (mdp_pdata && mdp_pdata->mdp_core_clk_table) {
- if (perf_level > mdp_pdata->num_mdp_clk) {
- printk(KERN_ERR "%s invalid perf level\n", __func__);
- clk_rate = mdp_get_core_clk();
- } else {
- clk_rate = mdp_pdata->
- mdp_core_clk_table[mdp_pdata->num_mdp_clk
- - perf_level];
- }
- } else
- clk_rate = mdp_get_core_clk();
-
- return clk_rate;
-}
-
static int mdp_irq_clk_setup(struct platform_device *pdev,
char cont_splashScreen)
{
@@ -2333,21 +2283,25 @@
}
#ifdef CONFIG_FB_MSM_MDP40
- /*
- * mdp_clk should greater than mdp_pclk always
- */
- if (mdp_pdata && mdp_pdata->mdp_core_clk_rate) {
- if (cont_splashScreen)
- mdp_clk_rate = clk_get_rate(mdp_clk);
- else
- mdp_clk_rate = mdp_pdata->mdp_core_clk_rate;
- mutex_lock(&mdp_clk_lock);
- clk_set_rate(mdp_clk, mdp_clk_rate);
- if (mdp_lut_clk != NULL)
- clk_set_rate(mdp_lut_clk, mdp_clk_rate);
- mutex_unlock(&mdp_clk_lock);
- }
+ if (mdp_pdata)
+ mdp_max_clk = mdp_pdata->mdp_max_clk;
+ else
+ pr_err("%s cannot get mdp max clk!\n", __func__);
+
+ if (!mdp_max_clk)
+ pr_err("%s mdp max clk is zero!\n", __func__);
+
+ if (cont_splashScreen)
+ mdp_clk_rate = clk_get_rate(mdp_clk);
+ else
+ mdp_clk_rate = mdp_max_clk;
+
+ mutex_lock(&mdp_clk_lock);
+ clk_set_rate(mdp_clk, mdp_clk_rate);
+ if (mdp_lut_clk != NULL)
+ clk_set_rate(mdp_lut_clk, mdp_clk_rate);
+ mutex_unlock(&mdp_clk_lock);
MSM_FB_DEBUG("mdp_clk: mdp_clk=%d\n", (int)clk_get_rate(mdp_clk));
#endif
@@ -2468,8 +2422,6 @@
mfd->ov1_wb_buf->size = 0;
mfd->mem_hid = 0;
}
- mfd->ov0_blt_state = 0;
- mfd->use_ov0_blt = 0 ;
/* initialize Post Processing data*/
mdp_hist_lut_init();
@@ -2568,7 +2520,6 @@
case MIPI_VIDEO_PANEL:
#ifndef CONFIG_FB_MSM_MDP303
mipi = &mfd->panel_info.mipi;
- configure_mdp_core_clk_table((mipi->dsi_pclk_rate) * 23 / 20);
mdp4_dsi_vsync_init(0);
mfd->hw_refresh = TRUE;
mfd->dma_fnc = mdp4_dsi_video_overlay;
@@ -2613,7 +2564,6 @@
#ifndef CONFIG_FB_MSM_MDP303
mfd->dma_fnc = mdp4_dsi_cmd_overlay;
mipi = &mfd->panel_info.mipi;
- configure_mdp_core_clk_table((mipi->dsi_pclk_rate) * 3 / 2);
mdp4_dsi_rdptr_init(0);
if (mfd->panel_info.pdest == DISPLAY_1) {
if_no = PRIMARY_INTF_SEL;
@@ -2698,8 +2648,6 @@
#ifdef CONFIG_FB_MSM_MDP40
mdp4_lcdc_vsync_init(0);
- configure_mdp_core_clk_table((mfd->panel_info.clk_rate)
- * 23 / 20);
if (mfd->panel.type == HDMI_PANEL) {
mfd->dma = &dma_e_data;
mdp4_display_intf_sel(EXTERNAL_INTF_SEL, LCDC_RGB_INTF);
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 76d06a0..293bd9b 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -812,7 +812,9 @@
void mdp_disable_irq_nosync(uint32 term);
int mdp_get_bytes_per_pixel(uint32_t format,
struct msm_fb_data_type *mfd);
-int mdp_set_core_clk(uint16 perf_level);
+int mdp_set_core_clk(u32 rate);
+int mdp_clk_round_rate(u32 rate);
+
unsigned long mdp_get_core_clk(void);
unsigned long mdp_perf_level2clk_rate(uint32 perf_level);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 767332a..13a922f 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -27,6 +27,7 @@
extern uint32 mdp4_extn_disp;
extern char *mmss_cc_base; /* mutimedia sub system clock control */
extern spinlock_t dsi_clk_lock;
+extern u32 mdp_max_clk;
#define MDP4_OVERLAYPROC0_BASE 0x10000
#define MDP4_OVERLAYPROC1_BASE 0x18000
@@ -361,6 +362,8 @@
uint32 blt_ov_done;
uint32 blt_dmap_koff;
uint32 blt_dmap_done;
+ uint32 req_clk;
+ uint32 req_bw;
uint32 luma_align_size;
struct mdp_overlay_pp_params pp_cfg;
struct mdp_overlay req_data;
@@ -554,6 +557,7 @@
int mdp4_overlay_commit(struct fb_info *info, int mixer);
int mdp4_dsi_video_pipe_commit(void);
int mdp4_dsi_cmd_pipe_commit(void);
+int mdp4_dsi_cmd_update_cnt(int cndx);
int mdp4_lcdc_pipe_commit(void);
int mdp4_dtv_pipe_commit(void);
void mdp4_dsi_rdptr_init(int cndx);
@@ -610,9 +614,6 @@
void mdp4_lcdc_wait4vsync(int cndx, long long *vtime);
void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
-void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd);
-void mdp4_update_perf_level(u32 perf_level);
-void mdp4_set_perf_level(void);
void mdp4_mddi_overlay_dmas_restore(void);
#ifndef CONFIG_FB_MSM_MIPI_DSI
@@ -728,6 +729,12 @@
{
/* empty */
}
+static inline void mdp4_dsi_cmd_blt_start(struct msm_fb_data_type *mfd)
+{
+}
+static inline void mdp4_dsi_cmd_blt_stop(struct msm_fb_data_type *mfd)
+{
+}
#endif /* CONFIG_FB_MSM_MIPI_DSI */
void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd,
@@ -847,9 +854,6 @@
void mdp4_dsi_video_3d_sbys(struct msm_fb_data_type *mfd,
struct msmfb_overlay_3d *r3d);
-void mdp4_backlight_init(int cndx);
-void mdp4_backlight_put_level(int cndx, int level);
-
int mdp4_mixer_info(int mixer_num, struct mdp_mixer_info *info);
void mdp_dmap_vsync_set(int enable);
@@ -874,9 +878,6 @@
int mdp4_overlay_writeback_on(struct platform_device *pdev);
int mdp4_overlay_writeback_off(struct platform_device *pdev);
void mdp4_writeback_overlay(struct msm_fb_data_type *mfd);
-void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe);
-void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd);
void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma);
int mdp4_writeback_start(struct fb_info *info);
@@ -917,5 +918,26 @@
int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe,
unsigned long srcp0_addr, unsigned long srcp1_addr,
unsigned long srcp2_addr);
+int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe,
+ struct msm_fb_data_type *mfd);
+int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *plist);
+void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd, int flag);
+
+#ifndef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+static inline void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd)
+{
+ /* empty */
+}
+static inline void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
+{
+ /* empty */
+}
+#else
+void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd);
+void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe);
+#endif
#endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 9fe5214..31e62b2 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -104,7 +104,21 @@
static DEFINE_MUTEX(iommu_mutex);
static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db;
-static int new_perf_level;
+
+struct mdp4_overlay_perf {
+ u32 mdp_clk_rate;
+ u32 use_ov0_blt;
+ u32 use_ov1_blt;
+ u32 mdp_bw;
+};
+
+struct mdp4_overlay_perf perf_request = {
+ .mdp_bw = OVERLAY_PERF_LEVEL4,
+};
+struct mdp4_overlay_perf perf_current = {
+ .mdp_bw = OVERLAY_PERF_LEVEL4,
+};
+
static struct ion_client *display_iclient;
@@ -136,6 +150,9 @@
ion_unmap_iommu(display_iclient, ihdl, DISPLAY_READ_DOMAIN,
GEN_POOL);
mdp4_stat.iommu_unmap++;
+ pr_debug("%s: map=%d unmap=%d drop=%d\n", __func__,
+ (int)mdp4_stat.iommu_map, (int)mdp4_stat.iommu_unmap,
+ (int)mdp4_stat.iommu_drop);
ion_free(display_iclient, ihdl);
flist->ihdl[i] = NULL;
}
@@ -1594,8 +1611,8 @@
data |= ctrl->mixer_cfg[num];
off = 0x10100;
}
- pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
- mixer, data, ctrl->flush[mixer]);
+ pr_debug("%s: mixer=%d data=%x flush=%x pid=%d\n", __func__,
+ mixer, data, ctrl->flush[mixer], current->pid);
}
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -2114,79 +2131,6 @@
}
-static int mdp4_overlay_validate_downscale(struct mdp_overlay *req,
- struct msm_fb_data_type *mfd, uint32 perf_level, uint32 pclk_rate)
-{
- __u32 panel_clk_khz, mdp_clk_khz;
- __u32 num_hsync_pix_clks, mdp_clks_per_hsync, src_wh;
- __u32 hsync_period_ps, mdp_period_ps, total_hsync_period_ps;
- unsigned long fill_rate_y_dir, fill_rate_x_dir;
- unsigned long fillratex100, mdp_pixels_produced;
- unsigned long mdp_clk_hz;
-
- pr_debug("%s: LCDC Mode Downscale validation with MDP Core"
- " Clk rate\n", __func__);
- pr_debug("src_w %u, src_h %u, dst_w %u, dst_h %u\n",
- req->src_rect.w, req->src_rect.h, req->dst_rect.w,
- req->dst_rect.h);
-
-
- panel_clk_khz = pclk_rate/1000;
- mdp_clk_hz = mdp_perf_level2clk_rate(perf_level);
-
- if (!mdp_clk_hz || !req->dst_rect.w || !req->dst_rect.h) {
- pr_debug("mdp_perf_level2clk_rate returned 0,"
- "or dst_rect height/width is 0,"
- "Downscale Validation incomplete\n");
- return 0;
- }
-
- mdp_clk_khz = mdp_clk_hz/1000;
-
- num_hsync_pix_clks = mfd->panel_info.lcdc.h_back_porch +
- mfd->panel_info.lcdc.h_front_porch +
- mfd->panel_info.lcdc.h_pulse_width +
- mfd->panel_info.xres;
-
- hsync_period_ps = 1000000000/panel_clk_khz;
- mdp_period_ps = 1000000000/mdp_clk_khz;
-
- total_hsync_period_ps = num_hsync_pix_clks * hsync_period_ps;
- mdp_clks_per_hsync = total_hsync_period_ps/mdp_period_ps;
-
- pr_debug("hsync_period_ps %u, mdp_period_ps %u,"
- "total_hsync_period_ps %u\n", hsync_period_ps,
- mdp_period_ps, total_hsync_period_ps);
-
- src_wh = req->src_rect.w * req->src_rect.h;
- if (src_wh % req->dst_rect.h)
- fill_rate_y_dir = (src_wh / req->dst_rect.h) + 1;
- else
- fill_rate_y_dir = (src_wh / req->dst_rect.h);
-
- fill_rate_x_dir = (mfd->panel_info.xres - req->dst_rect.w)
- + req->src_rect.w;
-
- if (fill_rate_y_dir >= fill_rate_x_dir)
- fillratex100 = 100 * fill_rate_y_dir / mfd->panel_info.xres;
- else
- fillratex100 = 100 * fill_rate_x_dir / mfd->panel_info.xres;
-
- pr_debug("mdp_clks_per_hsync %u, fill_rate_y_dir %lu,"
- "fill_rate_x_dir %lu\n", mdp_clks_per_hsync,
- fill_rate_y_dir, fill_rate_x_dir);
-
- mdp_pixels_produced = 100 * mdp_clks_per_hsync/fillratex100;
- pr_debug("fillratex100 %lu, mdp_pixels_produced %lu\n",
- fillratex100, mdp_pixels_produced);
- if (mdp_pixels_produced <= mfd->panel_info.xres) {
- mdp4_stat.err_underflow++;
- return -ERANGE;
- }
-
- return 0;
-}
-
static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer,
struct mdp4_overlay_pipe **ppipe,
struct msm_fb_data_type *mfd)
@@ -2428,11 +2372,447 @@
pipe->transp = req->transp_mask;
+ pipe->flags = req->flags;
+
*ppipe = pipe;
return 0;
}
+static int mdp4_calc_pipe_mdp_clk(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
+{
+ u32 pclk;
+ u32 xscale, yscale;
+ u32 hsync = 0;
+ u32 shift = 16;
+ u64 rst;
+ int ret = -EINVAL;
+
+ if (!pipe) {
+ pr_err("%s: pipe is null!\n", __func__);
+ pipe->req_bw = OVERLAY_PERF_LEVEL4;
+ return ret;
+ }
+ if (!mfd) {
+ pr_err("%s: mfd is null!\n", __func__);
+ pipe->req_bw = OVERLAY_PERF_LEVEL4;
+ return ret;
+ }
+
+ /*
+ * Serveral special cases require the max mdp clk but cannot
+ * be explained by mdp clk equation.
+ */
+ if (pipe->flags & MDP_DEINTERLACE) {
+ pr_info("%s deinterlace requires max mdp clk.\n",
+ __func__);
+ pipe->req_clk = mdp_max_clk;
+ return 0;
+ }
+
+ pr_debug("%s: pipe sets: panel res(x,y)=(%d,%d)\n",
+ __func__, mfd->panel_info.xres, mfd->panel_info.yres);
+ pr_debug("%s: src(w,h)(%d,%d),src(x,y)(%d,%d)\n",
+ __func__, pipe->src_w, pipe->src_h, pipe->src_x, pipe->src_y);
+ pr_debug("%s: dst(w,h)(%d,%d),dst(x,y)(%d,%d)\n",
+ __func__, pipe->dst_w, pipe->dst_h, pipe->dst_x, pipe->dst_y);
+
+ pclk = (mfd->panel_info.type == MIPI_VIDEO_PANEL ||
+ mfd->panel_info.type == MIPI_CMD_PANEL) ?
+ mfd->panel_info.mipi.dsi_pclk_rate :
+ mfd->panel_info.clk_rate;
+ if (!pclk) {
+ pipe->req_clk = mdp_max_clk;
+ pr_err("%s panel pixel clk is zero!\n", __func__);
+ return ret;
+ }
+ pr_debug("%s: mdp panel pixel clk is %d.\n",
+ __func__, pclk);
+
+ if (!pipe->dst_h) {
+ pr_err("%s: pipe dst_h is zero!\n", __func__);
+ pipe->req_clk = mdp_max_clk;
+ return ret;
+ }
+
+ if (!pipe->src_h) {
+ pr_err("%s: pipe src_h is zero!\n", __func__);
+ pipe->req_clk = mdp_max_clk;
+ return ret;
+ }
+
+ if (!pipe->dst_w) {
+ pr_err("%s: pipe dst_w is zero!\n", __func__);
+ pipe->req_clk = mdp_max_clk;
+ return ret;
+ }
+
+ if (!pipe->dst_h) {
+ pr_err("%s: pipe dst_h is zero!\n", __func__);
+ pipe->req_clk = mdp_max_clk;
+ return ret;
+ }
+
+ /*
+ * For the scaling cases, make more margin by removing porch
+ * values and adding extra 20%.
+ */
+ if ((pipe->src_h != pipe->dst_h) ||
+ (pipe->src_w != pipe->dst_w)) {
+ hsync = mfd->panel_info.xres;
+ hsync *= 100;
+ hsync /= 120;
+ pr_debug("%s: panel hsync is %d. with scaling\n",
+ __func__, hsync);
+
+ } else {
+ hsync = mfd->panel_info.lcdc.h_back_porch +
+ mfd->panel_info.lcdc.h_front_porch +
+ mfd->panel_info.lcdc.h_pulse_width +
+ mfd->panel_info.xres;
+ pr_debug("%s: panel hsync is %d.\n",
+ __func__, hsync);
+ }
+
+ if (!hsync) {
+ pipe->req_clk = mdp_max_clk;
+ pr_err("%s: panel hsync is zero!\n", __func__);
+ return 0;
+ }
+
+ xscale = mfd->panel_info.xres;
+ xscale += pipe->src_w;
+
+ if (xscale < pipe->dst_w) {
+ pipe->req_clk = mdp_max_clk;
+ pr_err("%s: xres+src_w cannot be less than dst_w!\n",
+ __func__);
+ return ret;
+ }
+
+ xscale -= pipe->dst_w;
+ xscale <<= shift;
+ xscale /= hsync;
+ pr_debug("%s: the right %d shifted xscale is %d.\n",
+ __func__, shift, xscale);
+
+ if (pipe->src_h > pipe->dst_h) {
+ yscale = pipe->src_h;
+ yscale <<= shift;
+ yscale /= pipe->dst_h;
+ } else { /* upscale */
+ yscale = pipe->dst_h;
+ yscale <<= shift;
+ yscale /= pipe->src_h;
+ }
+
+ yscale *= pipe->src_w;
+ yscale /= hsync;
+
+ pr_debug("%s: the right %d shifted yscale is %d.\n",
+ __func__, shift, yscale);
+
+ rst = pclk;
+ if (yscale > xscale)
+ rst *= yscale;
+ else
+ rst *= xscale;
+
+ rst >>= shift;
+
+ /*
+ * If the calculated mdp clk is less than panel pixel clk,
+ * most likely due to upscaling, mdp clk rate will be set to
+ * greater than pclk. Now the driver uses 1.15 as the
+ * factor. Ideally this factor is passed from board file.
+ */
+ if (rst < pclk) {
+ rst = ((pclk >> shift) * 23 / 20) << shift;
+ pr_debug("%s calculated mdp clk is less than pclk.\n",
+ __func__);
+ }
+
+ pipe->req_clk = (u32) rst;
+
+ pr_debug("%s: required mdp clk %d mixer %d pipe ndx %d\n",
+ __func__, pipe->req_clk, pipe->mixer_num, pipe->pipe_ndx);
+
+ return 0;
+}
+
+#define OVERLAY_VGA_SIZE 0x04B000
+#define OVERLAY_720P_TILE_SIZE 0x0E6000
+#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
+
+#define OVERLAY_BUS_SCALE_TABLE_BASE 6
+
+
+static int mdp4_calc_pipe_mdp_bw(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
+{
+ u32 res;
+ int ret = -EINVAL;
+
+ if (!pipe) {
+ pr_err("%s: pipe is null!\n", __func__);
+ return ret;
+ }
+ if (!mfd) {
+ pr_err("%s: mfd is null!\n", __func__);
+ return ret;
+ }
+
+ if (pipe->flags & MDP_DEINTERLACE) {
+ pr_info("%s deinterlace requires max mdp bw.\n",
+ __func__);
+ pipe->req_bw = OVERLAY_PERF_LEVEL1;
+ return 0;
+ }
+
+ if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+ pipe->req_bw = OVERLAY_PERF_LEVEL4;
+ return 0;
+ }
+
+ res = pipe->src_w * pipe->src_h;
+
+ if (res <= OVERLAY_WSVGA_SIZE)
+ pipe->req_bw = OVERLAY_PERF_LEVEL4;
+ else if (res <= OVERLAY_VGA_SIZE)
+ pipe->req_bw = OVERLAY_PERF_LEVEL3;
+ else if (res <= OVERLAY_720P_TILE_SIZE)
+ pipe->req_bw = OVERLAY_PERF_LEVEL2;
+ else
+ pipe->req_bw = OVERLAY_PERF_LEVEL1;
+
+ return 0;
+}
+
+int mdp4_overlay_mdp_perf_req(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *plist)
+{
+ u32 worst_mdp_clk = 0;
+ u32 worst_mdp_bw = OVERLAY_PERF_LEVEL4;
+ int i;
+ struct mdp4_overlay_perf *perf_req = &perf_request;
+ struct mdp4_overlay_pipe *pipe = plist;
+ u32 cnt = 0;
+ int ret = -EINVAL;
+
+ if (!mfd) {
+ pr_err("%s: mfd is null!\n", __func__);
+ return ret;
+ }
+
+ if (!plist) {
+ pr_err("%s: plist is null!\n", __func__);
+ return ret;
+ }
+
+ perf_req->use_ov0_blt = 0;
+ perf_req->use_ov1_blt = 0;
+
+ for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
+
+ if (!pipe)
+ return ret;
+
+ if (!pipe->pipe_used)
+ continue;
+ cnt++;
+ if (worst_mdp_clk < pipe->req_clk)
+ worst_mdp_clk = pipe->req_clk;
+ if (pipe->req_clk > mdp_max_clk) {
+ if (pipe->mixer_num == MDP4_MIXER0)
+ perf_req->use_ov0_blt = 1;
+ if (pipe->mixer_num == MDP4_MIXER1)
+ perf_req->use_ov1_blt = 1;
+ }
+
+ if (!pipe->req_bw) {
+ pr_err("%s mdp pipe bw request should not be zero!\n",
+ __func__);
+ pr_debug("%s %d pid %d num %d idx %d mix %d bw %d\n",
+ __func__, __LINE__, current->pid,
+ pipe->pipe_num, pipe->pipe_ndx,
+ pipe->mixer_num, pipe->req_bw);
+ pipe->req_bw = OVERLAY_PERF_LEVEL4;
+ }
+
+ if (pipe->req_bw < worst_mdp_bw)
+ worst_mdp_bw = pipe->req_bw;
+
+ if (mfd->mdp_rev == MDP_REV_41) {
+ /*
+ * writeback (blt) mode to provide work around
+ * for dsi cmd mode interface hardware bug.
+ */
+ if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+ if (pipe->dst_x != 0)
+ perf_req->use_ov0_blt = 1;
+ }
+ if ((mfd->panel_info.xres > 1280) &&
+ (mfd->panel_info.type != DTV_PANEL)) {
+ perf_req->use_ov0_blt = 1;
+ }
+ }
+ }
+
+ perf_req->mdp_clk_rate = worst_mdp_clk;
+ if (perf_req->mdp_clk_rate > mdp_max_clk)
+ perf_req->mdp_clk_rate = mdp_max_clk;
+
+ perf_req->mdp_clk_rate = mdp_clk_round_rate(perf_req->mdp_clk_rate);
+
+ perf_req->mdp_bw = worst_mdp_bw;
+
+ if (cnt >= 3)
+ perf_req->mdp_bw = OVERLAY_PERF_LEVEL1;
+
+ pr_debug("%s %d pid %d cnt %d clk %d ov0_blt %d, ov1_blt %d bw %d\n",
+ __func__, __LINE__, current->pid, cnt,
+ perf_req->mdp_clk_rate,
+ perf_req->use_ov0_blt,
+ perf_req->use_ov1_blt,
+ perf_req->mdp_bw);
+
+ return 0;
+}
+
+int mdp4_overlay_mdp_pipe_req(struct mdp4_overlay_pipe *pipe,
+ struct msm_fb_data_type *mfd)
+{
+ int ret = 0;
+
+ if (mdp4_calc_pipe_mdp_clk(mfd, pipe)) {
+ pr_err("%s unable to calc mdp pipe clk rate ret=%d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ }
+ if (mdp4_calc_pipe_mdp_bw(mfd, pipe)) {
+ pr_err("%s unable to calc mdp pipe bandwidth ret=%d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+void mdp4_overlay_mdp_perf_upd(struct msm_fb_data_type *mfd,
+ int flag)
+{
+ struct mdp4_overlay_perf *perf_req = &perf_request;
+ struct mdp4_overlay_perf *perf_cur = &perf_current;
+
+ pr_debug("%s %d: req mdp clk %d, cur mdp clk %d flag %d\n",
+ __func__, __LINE__,
+ perf_req->mdp_clk_rate,
+ perf_cur->mdp_clk_rate,
+ flag);
+
+ if (!mdp4_extn_disp)
+ perf_cur->use_ov1_blt = 0;
+
+ if (flag) {
+ if (perf_req->mdp_clk_rate > perf_cur->mdp_clk_rate) {
+ mdp_set_core_clk(perf_req->mdp_clk_rate);
+ pr_info("%s mdp clk is changed [%d] from %d to %d\n",
+ __func__,
+ flag,
+ perf_cur->mdp_clk_rate,
+ perf_req->mdp_clk_rate);
+ perf_cur->mdp_clk_rate =
+ perf_req->mdp_clk_rate;
+ }
+ if (perf_req->mdp_bw < perf_cur->mdp_bw) {
+ mdp_bus_scale_update_request
+ (OVERLAY_BUS_SCALE_TABLE_BASE -
+ perf_req->mdp_bw);
+ pr_info("%s mdp bw is changed [%d] from %d to %d\n",
+ __func__,
+ flag,
+ perf_cur->mdp_bw,
+ perf_req->mdp_bw);
+ perf_cur->mdp_bw = perf_req->mdp_bw;
+ }
+ if (mfd->panel_info.pdest == DISPLAY_1 &&
+ perf_req->use_ov0_blt && !perf_cur->use_ov0_blt) {
+ if (mfd->panel_info.type == LCDC_PANEL ||
+ mfd->panel_info.type == LVDS_PANEL)
+ mdp4_lcdc_overlay_blt_start(mfd);
+ else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+ mdp4_dsi_video_blt_start(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
+ mdp4_dsi_cmd_blt_start(mfd);
+ pr_info("%s mixer0 start blt [%d] from %d to %d.\n",
+ __func__,
+ flag,
+ perf_cur->use_ov0_blt,
+ perf_req->use_ov0_blt);
+ perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
+ }
+ if (mfd->panel_info.pdest == DISPLAY_2 &&
+ perf_req->use_ov1_blt && !perf_cur->use_ov1_blt) {
+ mdp4_dtv_overlay_blt_start(mfd);
+ pr_info("%s mixer1 start blt [%d] from %d to %d.\n",
+ __func__,
+ flag,
+ perf_cur->use_ov1_blt,
+ perf_req->use_ov1_blt);
+ perf_cur->use_ov1_blt = perf_req->use_ov1_blt;
+ }
+ } else {
+ if (perf_req->mdp_clk_rate < perf_cur->mdp_clk_rate) {
+ pr_info("%s mdp clk is changed [%d] from %d to %d\n",
+ __func__,
+ flag,
+ perf_cur->mdp_clk_rate,
+ perf_req->mdp_clk_rate);
+ mdp_set_core_clk(perf_req->mdp_clk_rate);
+ perf_cur->mdp_clk_rate =
+ perf_req->mdp_clk_rate;
+ }
+ if (perf_req->mdp_bw > perf_cur->mdp_bw) {
+ pr_info("%s mdp bw is changed [%d] from %d to %d\n",
+ __func__,
+ flag,
+ perf_cur->mdp_bw,
+ perf_req->mdp_bw);
+ mdp_bus_scale_update_request
+ (OVERLAY_BUS_SCALE_TABLE_BASE -
+ perf_req->mdp_bw);
+ perf_cur->mdp_bw = perf_req->mdp_bw;
+ }
+ if (mfd->panel_info.pdest == DISPLAY_1 &&
+ !perf_req->use_ov0_blt && perf_cur->use_ov0_blt) {
+ if (mfd->panel_info.type == LCDC_PANEL ||
+ mfd->panel_info.type == LVDS_PANEL)
+ mdp4_lcdc_overlay_blt_stop(mfd);
+ else if (mfd->panel_info.type == MIPI_VIDEO_PANEL)
+ mdp4_dsi_video_blt_stop(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
+ mdp4_dsi_cmd_blt_stop(mfd);
+ pr_info("%s mixer0 stop blt [%d] from %d to %d.\n",
+ __func__,
+ flag,
+ perf_cur->use_ov0_blt,
+ perf_req->use_ov0_blt);
+ perf_cur->use_ov0_blt = perf_req->use_ov0_blt;
+ }
+ if (mfd->panel_info.pdest == DISPLAY_2 &&
+ !perf_req->use_ov1_blt && perf_cur->use_ov1_blt) {
+ mdp4_dtv_overlay_blt_stop(mfd);
+ pr_info("%s mixer1 stop blt [%d] from %d to %d.\n",
+ __func__,
+ flag,
+ perf_cur->use_ov1_blt,
+ perf_req->use_ov1_blt);
+ perf_cur->use_ov1_blt = perf_req->use_ov1_blt;
+ }
+ }
+ return;
+}
+
static int get_img(struct msmfb_data *img, struct fb_info *info,
struct mdp4_overlay_pipe *pipe, unsigned int plane,
unsigned long *start, unsigned long *len, struct file **srcp_file,
@@ -2555,154 +2935,10 @@
return 0;
}
-#define OVERLAY_VGA_SIZE 0x04B000
-#define OVERLAY_720P_TILE_SIZE 0x0E6000
-#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
-
-#define OVERLAY_BUS_SCALE_TABLE_BASE 6
-
-static int mdp4_overlay_is_rgb_type(int format)
-{
- switch (format) {
- case MDP_RGB_565:
- case MDP_RGB_888:
- case MDP_BGR_565:
- case MDP_XRGB_8888:
- case MDP_ARGB_8888:
- case MDP_RGBA_8888:
- case MDP_BGRA_8888:
- case MDP_RGBX_8888:
- return 1;
- default:
- return 0;
- }
-}
-
-static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req,
- struct msm_fb_data_type *mfd)
-{
- int is_fg = 0, i, cnt;
-
- if (req->is_fg && ((req->alpha & 0x0ff) == 0xff))
- is_fg = 1;
-
- if (mdp4_extn_disp)
- return OVERLAY_PERF_LEVEL1;
-
- if (req->flags & (MDP_DEINTERLACE | MDP_BACKEND_COMPOSITION))
- return OVERLAY_PERF_LEVEL1;
-
- for (i = 0, cnt = 0; i < OVERLAY_PIPE_MAX; i++) {
- if (ctrl->plist[i].pipe_used && ++cnt > 2)
- return OVERLAY_PERF_LEVEL1;
- }
-
- if (mdp4_overlay_is_rgb_type(req->src.format) && is_fg &&
- ((req->src.width * req->src.height) <= OVERLAY_WSVGA_SIZE))
- return OVERLAY_PERF_LEVEL4;
- else if (mdp4_overlay_is_rgb_type(req->src.format))
- return OVERLAY_PERF_LEVEL1;
-
- if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE) {
- if (mfd->mdp_rev >= MDP_REV_42)
- return OVERLAY_PERF_LEVEL4;
- else
- return OVERLAY_PERF_LEVEL3;
-
- } else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE) {
- u32 max, min;
- max = (req->dst_rect.h > req->dst_rect.w) ?
- req->dst_rect.h : req->dst_rect.w;
- min = (mfd->panel_info.yres > mfd->panel_info.xres) ?
- mfd->panel_info.xres : mfd->panel_info.yres;
- if (max > min) /* landscape mode */
- return OVERLAY_PERF_LEVEL3;
- else /* potrait mode */
- return OVERLAY_PERF_LEVEL2;
- }
- else
- return OVERLAY_PERF_LEVEL1;
-}
-
-void mdp4_update_perf_level(u32 perf_level)
-{
- static int first = 1;
-
- new_perf_level = perf_level;
-
- if (first) {
- first = 0;
- mdp4_set_perf_level();
- }
-}
-
-void mdp4_set_perf_level(void)
-{
- static int old_perf_level;
- int cur_perf_level;
-
- if (mdp4_extn_disp)
- cur_perf_level = OVERLAY_PERF_LEVEL1;
- else
- cur_perf_level = new_perf_level;
-
- if (old_perf_level != cur_perf_level) {
- mdp_set_core_clk(cur_perf_level);
- old_perf_level = cur_perf_level;
- mdp_bus_scale_update_request(OVERLAY_BUS_SCALE_TABLE_BASE
- - cur_perf_level);
- }
-}
-
-static u32 mdp4_overlay_blt_enable(struct mdp_overlay *req,
- struct msm_fb_data_type *mfd, uint32 perf_level)
-{
- u32 clk_rate = mfd->panel_info.clk_rate;
- u32 blt_chq_req = 0, use_blt = 0;
-
- if ((mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
- (mfd->panel_info.type == MIPI_CMD_PANEL))
- clk_rate = (&mfd->panel_info.mipi)->dsi_pclk_rate;
-
- if ((mfd->panel_info.type == LCDC_PANEL) ||
- (mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
- (mfd->panel_info.type == DTV_PANEL) ||
- (mfd->panel_info.type == MIPI_CMD_PANEL))
- blt_chq_req = 1;
-
- if (blt_chq_req && (req->src_rect.h > req->dst_rect.h ||
- req->src_rect.w > req->dst_rect.w)) {
- if (mdp4_overlay_validate_downscale(req, mfd, perf_level,
- clk_rate))
- use_blt = 1;
- }
-
- if (mfd->panel_info.type == MDDI_PANEL) {
- if ((req->src_rect.h/2) >= req->dst_rect.h ||
- (req->src_rect.w/2) >= req->dst_rect.w)
- use_blt = 1;
- }
-
- if (mfd->mdp_rev == MDP_REV_41) {
- /*
- * writeback (blt) mode to provide work around for
- * dsi cmd mode interface hardware bug.
- */
- if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
- if (req->dst_rect.x != 0)
- use_blt = 1;
- }
- if ((mfd->panel_info.xres > 1280) &&
- (mfd->panel_info.type != DTV_PANEL))
- use_blt = 1;
- }
- return use_blt;
-}
-
int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- int ret, mixer, perf_level;
+ int ret, mixer;
struct mdp4_overlay_pipe *pipe;
if (mfd == NULL) {
@@ -2732,20 +2968,10 @@
return ret;
}
- perf_level = mdp4_overlay_get_perf_level(req, mfd);
-
- if (mixer == MDP4_MIXER0) {
- u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
- mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
- mfd->use_ov0_blt |= (use_blt << (pipe->pipe_ndx-1));
- }
-
/* return id back to user */
req->id = pipe->pipe_ndx; /* pipe_ndx start from 1 */
pipe->req_data = *req; /* keep original req */
- pipe->flags = req->flags;
-
if (!IS_ERR_OR_NULL(mfd->iclient)) {
pr_debug("pipe->flags 0x%x\n", pipe->flags);
if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) {
@@ -2768,47 +2994,8 @@
__func__);
}
- if (ctrl->panel_mode & MDP4_PANEL_DTV &&
- pipe->mixer_num == MDP4_MIXER1) {
- u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
+ mdp4_overlay_mdp_pipe_req(pipe, mfd);
- if (hdmi_prim_display) {
- if (!mdp4_overlay_is_rgb_type(req->src.format) &&
- pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
- (req->src_rect.h > req->dst_rect.h ||
- req->src_rect.w > req->dst_rect.w))
- use_blt = 1;
- }
-
- mdp4_overlay_dtv_set(mfd, pipe);
- mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
- mfd->use_ov1_blt |= (use_blt << (pipe->pipe_ndx-1));
- }
-
- if (new_perf_level != perf_level) {
- u32 old_level = new_perf_level;
- mdp4_update_perf_level(perf_level);
-
- /* change clck base on perf level */
- if (pipe->mixer_num == MDP4_MIXER0) {
- if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
- if (old_level > perf_level)
- mdp4_set_perf_level();
- } else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
- mdp4_set_perf_level();
- } else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
- if (old_level > perf_level)
- mdp4_set_perf_level();
- } else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
- mdp4_mddi_dma_busy_wait(mfd);
- mdp4_mddi_blt_dmap_busy_wait(mfd);
- mdp4_set_perf_level();
- }
- } else {
- if (ctrl->panel_mode & MDP4_PANEL_DTV)
- mdp4_overlay_dtv_set_perf(mfd);
- }
- }
mutex_unlock(&mfd->dma->ov_mutex);
return 0;
@@ -2819,7 +3006,8 @@
struct mdp4_overlay_pipe *pipe;
int i, cnt = 0;
- for (i = MDP4_MIXER_STAGE3; i >= MDP4_MIXER_STAGE_BASE; i--) {
+ /* free pipe besides base layer pipe */
+ for (i = MDP4_MIXER_STAGE3; i > MDP4_MIXER_STAGE_BASE; i--) {
pipe = ctrl->stage[mixer][i];
if (pipe == NULL)
continue;
@@ -2864,7 +3052,6 @@
else {
/* mixer 0 */
ctrl->mixer0_played = 0;
-
if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
if (mfd->panel_power_on)
mdp4_mddi_blt_dmap_busy_wait(mfd);
@@ -2879,13 +3066,9 @@
if (mfd->panel_power_on)
mdp4_mddi_overlay_restore();
}
-
- mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
} else { /* mixer1, DTV, ATV */
- if (ctrl->panel_mode & MDP4_PANEL_DTV) {
+ if (ctrl->panel_mode & MDP4_PANEL_DTV)
mdp4_overlay_dtv_unset(mfd, pipe);
- mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
- }
}
mdp4_stat.overlay_unset[pipe->mixer_num]++;
@@ -3002,7 +3185,6 @@
pr_debug("%s: pipe=%x ndx=%d num=%d used=%d\n", __func__,
(int) pipe, pipe->pipe_ndx, pipe->pipe_num, pipe->pipe_used);
-
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
}
@@ -3036,10 +3218,12 @@
if (pipe->pipe_type == OVERLAY_TYPE_BF) {
mdp4_overlay_borderfill_stage_up(pipe);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
return 0;
}
- if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ if (pipe->mixer_num == MDP4_MIXER2 ||
+ ctrl->panel_mode & MDP4_PANEL_MDDI)
mutex_lock(&mfd->dma->ov_mutex);
img = &req->data;
@@ -3147,7 +3331,10 @@
}
}
- if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_overlay_mdp_perf_req(mfd, ctrl->plist);
+
+ if (pipe->mixer_num == MDP4_MIXER2 ||
+ ctrl->panel_mode & MDP4_PANEL_MDDI)
goto mddi;
if (pipe->mixer_num == MDP4_MIXER0) {
@@ -3170,32 +3357,27 @@
return ret;
mddi:
-
if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
} else {
mdp4_overlay_rgb_setup(pipe); /* rgb pipe */
}
- if (pipe->mixer_num != MDP4_MIXER2) {
- if ((ctrl->panel_mode & MDP4_PANEL_DTV) ||
- (ctrl->panel_mode & MDP4_PANEL_LCDC) ||
- (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO))
- mdp4_overlay_reg_flush(pipe, 1);
- }
-
mdp4_mixer_stage_up(pipe);
- if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
+
+ if (pipe->mixer_num == MDP4_MIXER2) {
+ ctrl->mixer2_played++;
+ if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
+ mdp4_writeback_dma_busy_wait(mfd);
+ mdp4_writeback_kickoff_video(mfd, pipe);
+ }
+ } else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
+ if (pipe->flags & MDP_OV_PLAY_NOWAIT) {
+ mdp4_stat.overlay_play[pipe->mixer_num]++;
+ mutex_unlock(&mfd->dma->ov_mutex);
+ goto end;
+ }
mdp4_mixer_stage_commit(pipe->mixer_num);
-
-
- if (pipe->flags & MDP_OV_PLAY_NOWAIT) {
- mdp4_stat.overlay_play[pipe->mixer_num]++;
- mutex_unlock(&mfd->dma->ov_mutex);
- goto end;
- }
-
- if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
mdp4_mddi_dma_busy_wait(mfd);
mdp4_mddi_kickoff_video(mfd, pipe);
}
@@ -3402,7 +3584,7 @@
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
#ifdef V4L2_VSYNC
/*
* TODO: incorporate v4l2 into vsycn driven mechanism
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index 753ff23..c133831 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -110,14 +110,13 @@
mdp4_overlay_dmae_xy(pipe); /* dma_e */
mdp4_overlay_dmae_cfg(mfd, 1);
-
mdp4_overlay_rgb_setup(pipe);
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
if (ret == 0)
mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -183,10 +182,12 @@
} else {
pipe->srcp0_addr = (uint32)(buf + buf_offset);
}
+ mdp4_overlay_mdp_perf_req(pipe, mfd);
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
mdp4_overlay_rgb_setup(pipe);
mdp4_overlay_reg_flush(pipe, 0);
mdp4_mixer_stage_up(pipe);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n",
(int)pipe, pipe->pipe_ndx);
@@ -201,10 +202,7 @@
spin_unlock_irqrestore(&mdp_spin_lock, flag);
wait_for_completion_killable(&atv_pipe->comp);
mdp_disable_irq(MDP_OVERLAY1_TERM);
-
- /* change mdp clk while mdp is idle` */
- mdp4_set_perf_level();
-
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
mdp4_stat.kickoff_atv++;
mutex_unlock(&mfd->dma->ov_mutex);
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index e1fa02e..6f78305 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -28,8 +28,8 @@
#include "mdp.h"
#include "msm_fb.h"
-#include "mdp4.h"
#include "mipi_dsi.h"
+#include "mdp4.h"
static int dsi_state;
@@ -40,14 +40,6 @@
#define MAX_CONTROLLER 1
#define VSYNC_EXPIRE_TICK 4
-#define BACKLIGHT_MAX 4
-
-struct backlight {
- int put;
- int get;
- int tot;
- int blist[BACKLIGHT_MAX];
-};
static struct vsycn_ctrl {
struct device *dev;
@@ -75,7 +67,6 @@
struct msm_fb_data_type *mfd;
struct mdp4_overlay_pipe *base_pipe;
struct vsync_update vlist[2];
- struct backlight blight;
int vsync_enabled;
int clk_enabled;
int clk_control;
@@ -108,68 +99,6 @@
spin_unlock_irqrestore(&mdp_spin_lock, flag);
}
-static int mdp4_backlight_get_level(struct vsycn_ctrl *vctrl)
-{
- int level = -1;
-
- mutex_lock(&vctrl->update_lock);
- if (vctrl->blight.tot) {
- level = vctrl->blight.blist[vctrl->blight.get];
- vctrl->blight.get++;
- vctrl->blight.get %= BACKLIGHT_MAX;
- vctrl->blight.tot--;
- pr_debug("%s: tot=%d put=%d get=%d level=%d\n", __func__,
- vctrl->blight.tot, vctrl->blight.put, vctrl->blight.get, level);
- }
- mutex_unlock(&vctrl->update_lock);
- return level;
-}
-
-void mdp4_backlight_put_level(int cndx, int level)
-{
- struct vsycn_ctrl *vctrl;
-
- if (cndx >= MAX_CONTROLLER) {
- pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
- return;
- }
-
- vctrl = &vsync_ctrl_db[cndx];
- mutex_lock(&vctrl->update_lock);
- vctrl->blight.blist[vctrl->blight.put] = level;
- vctrl->blight.put++;
- vctrl->blight.put %= BACKLIGHT_MAX;
- if (vctrl->blight.tot == BACKLIGHT_MAX) {
- /* drop the oldest one */
- vctrl->blight.get++;
- vctrl->blight.get %= BACKLIGHT_MAX;
- } else {
- vctrl->blight.tot++;
- }
- mutex_unlock(&vctrl->update_lock);
- pr_debug("%s: tot=%d put=%d get=%d level=%d\n", __func__,
- vctrl->blight.tot, vctrl->blight.put, vctrl->blight.get, level);
-
- if (mdp4_overlay_dsi_state_get() <= ST_DSI_SUSPEND)
- return;
-}
-
-static int mdp4_backlight_commit_level(struct vsycn_ctrl *vctrl)
-{
- int level;
- int cnt = 0;
-
- if (vctrl->blight.tot) { /* has new backlight */
- if (mipi_dsi_ctrl_lock(0)) {
- level = mdp4_backlight_get_level(vctrl);
- mipi_dsi_cmd_backlight_tx(level);
- cnt++;
- }
- }
-
- return cnt;
-}
-
static void mdp4_dsi_cmd_blt_ov_update(struct mdp4_overlay_pipe *pipe)
{
uint32 off, addr;
@@ -327,6 +256,7 @@
struct vsycn_ctrl *vctrl;
struct vsync_update *vp;
struct mdp4_overlay_pipe *pipe;
+ struct mdp4_overlay_pipe *real_pipe;
unsigned long flags;
int need_dmap_wait = 0;
int need_ov_wait = 0;
@@ -355,9 +285,6 @@
}
mutex_unlock(&vctrl->update_lock);
-
- mdp4_backlight_commit_level(vctrl);
-
/* free previous committed iommu back to pool */
mdp4_overlay_iommu_unmap_freelist(mixer);
@@ -410,7 +337,11 @@
for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
if (pipe->pipe_used) {
cnt++;
- mdp4_overlay_vsync_commit(pipe);
+ real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+ if (real_pipe && real_pipe->pipe_used) {
+ /* pipe not unset */
+ mdp4_overlay_vsync_commit(pipe);
+ }
/* free previous iommu to freelist
* which will be freed at next
* pipe_commit
@@ -420,6 +351,9 @@
}
}
+ /* tx dcs command if had any */
+ mipi_dsi_cmdlist_commit(1);
+
mdp4_mixer_stage_commit(mixer);
pipe = vctrl->base_pipe;
@@ -687,9 +621,6 @@
vctrl->inited = 1;
vctrl->update_ndx = 0;
- vctrl->blight.put = 0;
- vctrl->blight.get = 0;
- vctrl->blight.tot = 0;
mutex_init(&vctrl->update_lock);
init_completion(&vctrl->ov_comp);
init_completion(&vctrl->dmap_comp);
@@ -864,6 +795,7 @@
/* disable dsi trigger */
MDP_OUTP(MDP_BASE + 0x000a4, 0x00);
+
mdp4_overlay_setup_pipe_addr(mfd, pipe);
mdp4_overlay_rgb_setup(pipe);
@@ -878,6 +810,7 @@
mdp4_overlay_dmap_cfg(mfd, 0);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
/* MDP cmd block disable */
mdp_clk_ctrl(0);
}
@@ -955,6 +888,7 @@
mdp4_overlay_dmap_cfg(mfd, 0);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
@@ -1026,8 +960,8 @@
atomic_set(&vctrl->suspend, 1);
- mipi_dsi_cmd_backlight_tx(150);
-
+ /* sanity check, free pipes besides base layer */
+ mdp4_overlay_unset_mixer(pipe->mixer_num);
mdp4_mixer_stage_down(pipe);
mdp4_overlay_pipe_free(pipe);
vctrl->base_pipe = NULL;
@@ -1098,18 +1032,14 @@
mdp4_dsi_cmd_pipe_queue(0, pipe);
}
- if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
-
- if (mfd->use_ov0_blt)
- mdp4_dsi_cmd_do_blt(mfd, 1);
- else
- mdp4_dsi_cmd_do_blt(mfd, 0);
-
- mfd->ov0_blt_state = mfd->use_ov0_blt;
- }
-
+ 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 340faa2..a461c3b 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -122,9 +122,6 @@
return;
}
- /* start timing generator & mmu if they are not started yet */
- mdp4_overlay_dsi_video_start();
-
vctrl = &vsync_ctrl_db[cndx];
if (atomic_read(&vctrl->suspend) > 0)
@@ -140,7 +137,7 @@
__func__, undx, (int)pipe, pipe->pipe_ndx, pipe->pipe_num,
current->pid);
- *pp = *pipe; /* keep it */
+ *pp = *pipe; /* clone it */
vp->update_cnt++;
mutex_unlock(&vctrl->update_lock);
mdp4_stat.overlay_play[pipe->mixer_num]++;
@@ -158,6 +155,7 @@
struct vsycn_ctrl *vctrl;
struct vsync_update *vp;
struct mdp4_overlay_pipe *pipe;
+ struct mdp4_overlay_pipe *real_pipe;
unsigned long flags;
int cnt = 0;
@@ -196,6 +194,8 @@
}
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ mdp4_overlay_mdp_perf_upd(vctrl->mfd, 1);
+
if (vctrl->blt_change) {
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -209,10 +209,15 @@
}
pipe = vp->plist;
+
for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
if (pipe->pipe_used) {
cnt++;
- mdp4_overlay_vsync_commit(pipe);
+ real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+ if (real_pipe && real_pipe->pipe_used) {
+ /* pipe not unset */
+ mdp4_overlay_vsync_commit(pipe);
+ }
/* free previous iommu to freelist
* which will be freed at next
* pipe_commit
@@ -224,6 +229,9 @@
mdp4_mixer_stage_commit(mixer);
+ /* start timing generator & mmu if they are not started yet */
+ mdp4_overlay_dsi_video_start();
+
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (pipe->ov_blt_addr) {
@@ -329,6 +337,27 @@
wait_for_completion(&vctrl->dmap_comp);
}
+
+static void mdp4_dsi_video_wait4dmap_done(int cndx)
+{
+ unsigned long flags;
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+ vctrl = &vsync_ctrl_db[cndx];
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ INIT_COMPLETION(vctrl->dmap_comp);
+ vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ mdp4_dsi_video_wait4dmap(cndx);
+ vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+}
+
+
static void mdp4_dsi_video_wait4ov(int cndx)
{
struct vsycn_ctrl *vctrl;
@@ -492,20 +521,13 @@
pipe = vctrl->base_pipe;
}
-#ifdef CONTINUOUS_SPLASH
- /* MDP cmd block enable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-
if (!(mfd->cont_splash_done)) {
mfd->cont_splash_done = 1;
- mdp_pipe_ctrl(MDP_CMD_BLOCK,
- MDP_BLOCK_POWER_OFF, FALSE);
- mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE);
- /* disable timing generator */
+ mdp4_dsi_video_wait4dmap_done(0);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
mipi_dsi_controller_cfg(0);
}
-#endif
+
pipe->src_height = fbi->var.yres;
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
@@ -525,6 +547,8 @@
pipe->dst_h = fbi->var.yres;
pipe->dst_w = fbi->var.xres;
+ mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
atomic_set(&vctrl->suspend, 0);
mdp4_overlay_dmap_xy(pipe); /* dma_p */
@@ -534,8 +558,7 @@
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
-
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
/*
* DSI timing setting
*/
@@ -633,19 +656,19 @@
while (vctrl->wait_vsync_cnt)
msleep(20); /* >= 17 ms */
+ mdp_histogram_ctrl_all(FALSE);
+
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
dsi_video_enabled = 0;
- mdp_histogram_ctrl_all(FALSE);
-
if (pipe) {
+ /* sanity check, free pipes besides base layer */
+ mdp4_overlay_unset_mixer(pipe->mixer_num);
if (mfd->ref_cnt == 0) {
/* adb stop */
if (pipe->pipe_type == OVERLAY_TYPE_BF)
mdp4_overlay_borderfill_stage_down(pipe);
-
- mdp4_overlay_unset_mixer(pipe->mixer_num);
vctrl->base_pipe = NULL;
} else {
/* system suspending */
@@ -755,6 +778,8 @@
mdp4_mixer_stage_up(pipe);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
+
mb();
}
@@ -806,13 +831,6 @@
MDP_OUTP(MDP_BASE + 0x90008, addr);
}
-void mdp4_overlay_dsi_video_set_perf(struct msm_fb_data_type *mfd)
-{
- /* change mdp clk while mdp is idle */
- mdp4_set_perf_level();
-}
-
-
/*
* mdp4_primary_vsync_dsi_video: called from isr
*/
@@ -997,21 +1015,17 @@
mdp4_dsi_video_pipe_queue(0, pipe);
}
- if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
- if (mfd->use_ov0_blt)
- mdp4_dsi_video_do_blt(mfd, 1);
- else
- mdp4_dsi_video_do_blt(mfd, 0);
-
- mfd->ov0_blt_state = mfd->use_ov0_blt;
- }
-
+ mutex_lock(&mfd->dma->ov_mutex);
mdp4_dsi_video_pipe_commit();
+ mutex_unlock(&mfd->dma->ov_mutex);
if (pipe->ov_blt_addr)
mdp4_dsi_video_wait4ov(0);
else
mdp4_dsi_video_wait4dmap(0);
+
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
}
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index d0d4f40..00f44d4 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -141,9 +141,6 @@
return;
}
- /* start timing generator & mmu if they are not started yet */
- mdp4_overlay_dtv_start();
-
vctrl = &vsync_ctrl_db[cndx];
if (atomic_read(&vctrl->suspend) > 0)
@@ -158,13 +155,14 @@
pr_debug("%s: vndx=%d pipe_ndx=%d flags=%x pid=%d\n",
__func__, undx, pipe->pipe_ndx, pipe->flags, current->pid);
- *pp = *pipe; /* keep it */
+ *pp = *pipe; /* clone it */
vp->update_cnt++;
mutex_unlock(&vctrl->update_lock);
mdp4_stat.overlay_play[pipe->mixer_num]++;
}
static void mdp4_dtv_blt_ov_update(struct mdp4_overlay_pipe *pipe);
+static void mdp4_dtv_wait4dmae(int cndx);
int mdp4_dtv_pipe_commit(void)
{
@@ -174,6 +172,7 @@
struct vsycn_ctrl *vctrl;
struct vsync_update *vp;
struct mdp4_overlay_pipe *pipe;
+ struct mdp4_overlay_pipe *real_pipe;
unsigned long flags;
int cnt = 0;
@@ -199,7 +198,11 @@
for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
if (pipe->pipe_used) {
cnt++;
- mdp4_overlay_vsync_commit(pipe);
+ real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+ if (real_pipe && real_pipe->pipe_used) {
+ /* pipe not unset */
+ mdp4_overlay_vsync_commit(pipe);
+ }
/* free previous iommu to freelist
* which will be freed at next
* pipe_commit
@@ -210,6 +213,9 @@
}
mdp4_mixer_stage_commit(mixer);
+ /* start timing generator & mmu if they are not started yet */
+ mdp4_overlay_dtv_start();
+
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (pipe->ov_blt_addr) {
@@ -221,7 +227,7 @@
/* kickoff overlay1 engine */
mdp4_stat.kickoff_ov1++;
outpdw(MDP_BASE + 0x0008, 0);
- } else if (vctrl->dmae_intr_cnt == 0) {
+ } else {
/* schedule second phase update at dmap */
INIT_COMPLETION(vctrl->dmae_comp);
vsync_irq_enable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
@@ -570,13 +576,14 @@
pipe = vctrl->base_pipe;
if (pipe != NULL) {
mdp4_dtv_stop(mfd);
+ /* sanity check, free pipes besides base layer */
+ mdp4_overlay_unset_mixer(pipe->mixer_num);
if (hdmi_prim_display && mfd->ref_cnt == 0) {
/* adb stop */
if (pipe->pipe_type == OVERLAY_TYPE_BF)
mdp4_overlay_borderfill_stage_down(pipe);
/* pipe == rgb2 */
- mdp4_overlay_unset_mixer(pipe->mixer_num);
vctrl->base_pipe = NULL;
} else {
mdp4_mixer_stage_down(pipe);
@@ -647,8 +654,7 @@
void mdp4_overlay_dtv_set_perf(struct msm_fb_data_type *mfd)
{
- /* change mdp clk while mdp is idle` */
- mdp4_set_perf_level();
+
}
static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd,
@@ -701,12 +707,16 @@
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
pipe->src_w = fbi->var.xres;
+ pipe->dst_h = fbi->var.yres;
+ pipe->dst_w = fbi->var.xres;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = fbi->var.yres;
pipe->dst_w = fbi->var.xres;
pipe->srcp0_ystride = fbi->fix.line_length;
+ mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
ret = mdp4_overlay_format2pipe(pipe);
if (ret < 0)
pr_warn("%s: format2type failed\n", __func__);
@@ -721,7 +731,7 @@
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
vctrl->base_pipe = pipe; /* keep it */
}
@@ -786,8 +796,6 @@
vctrl->vsync_time = ktime_get();
schedule_work(&vctrl->vsync_work);
- pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
-
spin_lock(&vctrl->spin_lock);
if (vctrl->wait_vsync_cnt) {
complete_all(&vctrl->vsync_comp);
@@ -813,6 +821,7 @@
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
+ pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
spin_lock(&vctrl->spin_lock);
if (vctrl->blt_change) {
@@ -831,13 +840,8 @@
vctrl->blt_change = 0;
}
- vctrl->dmae_intr_cnt--;
- if (vctrl->dmae_wait_cnt) {
- complete_all(&vctrl->dmae_comp);
- vctrl->dmae_wait_cnt = 0; /* reset */
- } else {
- mdp4_overlay_dma_commit(MDP4_MIXER1);
- }
+ complete_all(&vctrl->dmae_comp);
+ mdp4_overlay_dma_commit(MDP4_MIXER1);
vsync_irq_disable(INTR_DMA_E_DONE, MDP_DMA_E_TERM);
spin_unlock(&vctrl->spin_lock);
}
@@ -894,6 +898,7 @@
MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
mdp4_overlay_reg_flush(vctrl->base_pipe, 1);
mdp4_mixer_stage_up(vctrl->base_pipe);
+ mdp4_mixer_stage_commit(vctrl->base_pipe->mixer_num);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
@@ -1000,5 +1005,8 @@
pipe->srcp0_addr = (uint32)mfd->ibuf.buf;
mdp4_dtv_pipe_queue(0, pipe);
}
+
+ mutex_lock(&mfd->dma->ov_mutex);
mdp4_dtv_pipe_commit();
+ mutex_unlock(&mfd->dma->ov_mutex);
}
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index feba8b8..08c3815 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -128,9 +128,6 @@
return;
}
- /* start timing generator & mmu if they are not started yet */
- mdp4_overlay_lcdc_start();
-
vctrl = &vsync_ctrl_db[cndx];
if (atomic_read(&vctrl->suspend) > 0)
@@ -145,7 +142,7 @@
pr_debug("%s: vndx=%d pipe_ndx=%d pid=%d\n", __func__,
undx, pipe->pipe_ndx, current->pid);
- *pp = *pipe; /* keep it */
+ *pp = *pipe; /* clone it */
vp->update_cnt++;
mutex_unlock(&vctrl->update_lock);
mdp4_stat.overlay_play[pipe->mixer_num]++;
@@ -163,6 +160,7 @@
struct vsycn_ctrl *vctrl;
struct vsync_update *vp;
struct mdp4_overlay_pipe *pipe;
+ struct mdp4_overlay_pipe *real_pipe;
unsigned long flags;
int cnt = 0;
@@ -201,6 +199,8 @@
}
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ mdp4_overlay_mdp_perf_upd(vctrl->mfd, 1);
+
if (vctrl->blt_change) {
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
@@ -217,7 +217,11 @@
for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
if (pipe->pipe_used) {
cnt++;
- mdp4_overlay_vsync_commit(pipe);
+ real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+ if (real_pipe && real_pipe->pipe_used) {
+ /* pipe not unset */
+ mdp4_overlay_vsync_commit(pipe);
+ }
/* free previous iommu to freelist
* which will be freed at next
* pipe_commit
@@ -229,6 +233,9 @@
mdp4_mixer_stage_commit(mixer);
+ /* start timing generator & mmu if they are not started yet */
+ mdp4_overlay_lcdc_start();
+
pipe = vctrl->base_pipe;
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (pipe->ov_blt_addr) {
@@ -513,6 +520,8 @@
pipe->srcp0_ystride = fbi->fix.line_length;
pipe->bpp = bpp;
+ mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
atomic_set(&vctrl->suspend, 0);
mdp4_overlay_dmap_xy(pipe);
@@ -636,19 +645,19 @@
while (vctrl->wait_vsync_cnt)
msleep(20); /* >= 17 ms */
+ mdp_histogram_ctrl_all(FALSE);
+
MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
lcdc_enabled = 0;
- mdp_histogram_ctrl_all(FALSE);
-
if (pipe) {
+ /* sanity check, free pipes besides base layer */
+ mdp4_overlay_unset_mixer(pipe->mixer_num);
if (mfd->ref_cnt == 0) {
/* adb stop */
if (pipe->pipe_type == OVERLAY_TYPE_BF)
mdp4_overlay_borderfill_stage_down(pipe);
-
- mdp4_overlay_unset_mixer(pipe->mixer_num);
vctrl->base_pipe = NULL;
} else {
/* system suspending */
@@ -714,12 +723,6 @@
MDP_OUTP(MDP_BASE + 0x90008, addr);
}
-void mdp4_overlay_lcdc_set_perf(struct msm_fb_data_type *mfd)
-{
- /* change mdp clk while mdp is idle */
- mdp4_set_perf_level();
-}
-
/*
* mdp4_primary_vsync_lcdc: called from isr
*/
@@ -900,20 +903,16 @@
mdp4_lcdc_pipe_queue(0, pipe);
}
- if (mfd->use_ov0_blt != mfd->ov0_blt_state) {
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
- if (mfd->use_ov0_blt)
- mdp4_lcdc_do_blt(mfd, 1);
- else
- mdp4_lcdc_do_blt(mfd, 0);
-
- mfd->ov0_blt_state = mfd->use_ov0_blt;
- }
-
+ mutex_lock(&mfd->dma->ov_mutex);
mdp4_lcdc_pipe_commit();
+ mutex_unlock(&mfd->dma->ov_mutex);
if (pipe->ov_blt_addr)
mdp4_lcdc_wait4ov(0);
else
mdp4_lcdc_wait4dmap(0);
+
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
}
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index 103419e..e6ff9ef 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -243,7 +243,7 @@
mdp4_overlay_dmap_xy(pipe);
mdp4_overlay_dmap_cfg(mfd, 0);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
mdp4_mddi_vsync_enable(mfd, pipe, 0);
/* MDP cmd block disable */
@@ -574,8 +574,6 @@
struct mdp4_overlay_pipe *pipe)
{
unsigned long flag;
- /* change mdp clk while mdp is idle` */
- mdp4_set_perf_level();
mdp_enable_irq(MDP_OVERLAY0_TERM);
spin_lock_irqsave(&mdp_spin_lock, flag);
@@ -660,9 +658,6 @@
void mdp4_mddi_dma_s_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
- /* change mdp clk while mdp is idle` */
- mdp4_set_perf_level();
-
mdp_enable_irq(MDP_DMA_S_TERM);
if (mddi_pipe->ov_blt_addr == 0)
@@ -698,9 +693,10 @@
if (mddi_pipe && mddi_pipe->ov_blt_addr)
mdp4_mddi_blt_dmap_busy_wait(mfd);
-
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
mdp4_overlay_update_lcd(mfd);
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
if (mdp_hw_revision < MDP4_REVISION_V2_1) {
/* dmas dmap switch */
if (mdp4_overlay_mixer_play(mddi_pipe->mixer_num)
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 32fe141..940aea8 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -174,6 +174,8 @@
pipe->dst_y = 0;
pipe->dst_x = 0;
+ mdp4_overlay_mdp_pipe_req(pipe, mfd);
+
if (mfd->display_iova)
pipe->srcp0_addr = mfd->display_iova + buf_offset;
else
@@ -182,7 +184,7 @@
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
-
+ mdp4_mixer_stage_commit(pipe->mixer_num);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -286,6 +288,8 @@
pr_debug("%s: pid=%d\n", __func__, current->pid);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
+
mdp4_writeback_overlay_kickoff(mfd, pipe);
mutex_lock(&mfd->writeback_mutex);
@@ -299,6 +303,7 @@
void mdp4_writeback_kickoff_ui(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
+ mdp4_mixer_stage_commit(pipe->mixer_num);
pr_debug("%s: pid=%d\n", __func__, current->pid);
mdp4_writeback_overlay_kickoff(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index e76b8ba..ca73a70 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -249,7 +249,7 @@
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
+ mdp_bus_scale_update_request(5);
#ifdef MDP4_ERROR
/*
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 6145d67..675df03 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -18,10 +18,9 @@
#include <linux/types.h>
#include <linux/workqueue.h>
-#define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_reg_base + addr)
-#define MDSS_REG_READ(addr) readl_relaxed(mdss_reg_base + addr)
+#define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_res->mdp_base + addr)
+#define MDSS_REG_READ(addr) readl_relaxed(mdss_res->mdp_base + addr)
-extern unsigned char *mdss_reg_base;
extern spinlock_t dsi_clk_lock;
enum mdss_mdp_clk_type {
@@ -34,7 +33,7 @@
MDSS_MAX_CLK
};
-struct mdss_res_type {
+struct mdss_data_type {
u32 rev;
u32 mdp_rev;
struct clk *mdp_clk[MDSS_MAX_CLK];
@@ -42,6 +41,9 @@
struct workqueue_struct *clk_ctrl_wq;
struct delayed_work clk_ctrl_worker;
+ struct platform_device *pdev;
+ char __iomem *mdp_base;
+ char __iomem *vbif_base;
u32 irq;
u32 irq_mask;
@@ -69,7 +71,7 @@
u32 *pipe_type_map;
u32 *mixer_type_map;
};
-extern struct mdss_res_type *mdss_res;
+extern struct mdss_data_type *mdss_res;
enum mdss_hw_index {
MDSS_HW_MDP,
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index d051828..8c61be9 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -17,14 +17,154 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of_device.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
#include "mdss.h"
#include "mdss_panel.h"
#include "mdss_dsi.h"
-static struct mdss_panel_common_pdata *panel_pdata;
+static struct mdss_dsi_drv_pdata dsi_drv;
static unsigned char *mdss_dsi_base;
+static unsigned char *mmss_cc_base;
+
+static int mdss_dsi_regulator_init(struct platform_device *pdev)
+{
+ int ret;
+ dsi_drv.vdd_vreg = devm_regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(dsi_drv.vdd_vreg)) {
+ pr_err("could not get 8941_l22, rc = %ld\n",
+ PTR_ERR(dsi_drv.vdd_vreg));
+ return -ENODEV;
+ }
+
+ ret = regulator_set_voltage(dsi_drv.vdd_vreg, 3000000, 3000000);
+ if (ret) {
+ pr_err("vdd_vreg->set_voltage failed, rc=%d\n", ret);
+ return -EINVAL;
+ }
+
+ dsi_drv.vdd_io_vreg = devm_regulator_get(&pdev->dev, "vdd_io");
+ if (IS_ERR(dsi_drv.vdd_io_vreg)) {
+ pr_err("could not get 8941_l12, rc = %ld\n",
+ PTR_ERR(dsi_drv.vdd_io_vreg));
+ return -ENODEV;
+ }
+
+ ret = regulator_set_voltage(dsi_drv.vdd_io_vreg, 1800000, 1800000);
+ if (ret) {
+ pr_err("vdd_io_vreg->set_voltage failed, rc=%d\n", ret);
+ return -EINVAL;
+ }
+
+ dsi_drv.dsi_vreg = devm_regulator_get(&pdev->dev, "vreg");
+ if (IS_ERR(dsi_drv.dsi_vreg)) {
+ pr_err("could not get 8941_l2, rc = %ld\n",
+ PTR_ERR(dsi_drv.dsi_vreg));
+ return -ENODEV;
+ }
+
+ ret = regulator_set_voltage(dsi_drv.dsi_vreg, 1200000, 1200000);
+ if (ret) {
+ pr_err("dsi_vreg->set_voltage failed, rc=%d\n", ret);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mdss_dsi_panel_power_on(int enable)
+{
+ int ret;
+ pr_debug("%s: enable=%d\n", __func__, enable);
+
+ if (enable) {
+ ret = regulator_set_optimum_mode(dsi_drv.vdd_vreg, 100000);
+ if (ret < 0) {
+ pr_err("%s: vdd_vreg set regulator mode failed.\n",
+ __func__);
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode(dsi_drv.vdd_io_vreg, 100000);
+ if (ret < 0) {
+ pr_err("%s: vdd_io_vreg set regulator mode failed.\n",
+ __func__);
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode(dsi_drv.dsi_vreg, 100000);
+ if (ret < 0) {
+ pr_err("%s: dsi_vreg set regulator mode failed.\n",
+ __func__);
+ return ret;
+ }
+
+ ret = regulator_enable(dsi_drv.vdd_vreg);
+ if (ret) {
+ pr_err("%s: Failed to enable regulator.\n", __func__);
+ return ret;
+ }
+
+ ret = regulator_enable(dsi_drv.vdd_io_vreg);
+ if (ret) {
+ pr_err("%s: Failed to enable regulator.\n", __func__);
+ return ret;
+ }
+
+ ret = regulator_enable(dsi_drv.dsi_vreg);
+ if (ret) {
+ pr_err("%s: Failed to enable regulator.\n", __func__);
+ return ret;
+ }
+
+ mdss_dsi_panel_reset(1);
+
+ } else {
+
+ mdss_dsi_panel_reset(0);
+
+ ret = regulator_disable(dsi_drv.vdd_vreg);
+ if (ret) {
+ pr_err("%s: Failed to disable regulator.\n", __func__);
+ return ret;
+ }
+
+ ret = regulator_disable(dsi_drv.vdd_io_vreg);
+ if (ret) {
+ pr_err("%s: Failed to disable regulator.\n", __func__);
+ return ret;
+ }
+
+ ret = regulator_disable(dsi_drv.dsi_vreg);
+ if (ret) {
+ pr_err("%s: Failed to disable regulator.\n", __func__);
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode(dsi_drv.vdd_vreg, 100);
+ if (ret < 0) {
+ pr_err("%s: vdd_vreg set regulator mode failed.\n",
+ __func__);
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode(dsi_drv.vdd_io_vreg, 100);
+ if (ret < 0) {
+ pr_err("%s: vdd_io_vreg set regulator mode failed.\n",
+ __func__);
+ return ret;
+ }
+ ret = regulator_set_optimum_mode(dsi_drv.dsi_vreg, 100);
+ if (ret < 0) {
+ pr_err("%s: dsi_vreg set regulator mode failed.\n",
+ __func__);
+ return ret;
+ }
+ }
+ return 0;
+}
static int mdss_dsi_off(struct mdss_panel_data *pdata)
{
@@ -38,14 +178,14 @@
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
- ret = panel_pdata->off(pdata);
+ ret = dsi_drv.off(pdata);
if (ret) {
pr_err("%s: Panel OFF failed\n", __func__);
return ret;
}
spin_lock_bh(&dsi_clk_lock);
- mdss_dsi_clk_disable();
+ mdss_dsi_clk_disable(pdata);
/* disable dsi engine */
MIPI_OUTP(mdss_dsi_base + 0x0004, 0);
@@ -54,6 +194,12 @@
mdss_dsi_unprepare_clocks();
+ ret = mdss_dsi_panel_power_on(0);
+ if (ret) {
+ pr_err("%s: Panel power off failed\n", __func__);
+ return ret;
+ }
+
pr_debug("%s-:\n", __func__);
return ret;
@@ -71,15 +217,18 @@
pinfo = &pdata->panel_info;
- cont_splash_clk_ctrl(0);
+ MIPI_OUTP(mdss_dsi_base + 0x118, 1);
+ MIPI_OUTP(mdss_dsi_base + 0x118, 0);
+
+ mdss_dsi_phy_sw_reset(pdata);
+ mdss_dsi_phy_enable(pdata, 1);
+ mdss_dsi_phy_init(pdata);
+
mdss_dsi_prepare_clocks();
spin_lock_bh(&dsi_clk_lock);
- MIPI_OUTP(mdss_dsi_base + 0x118, 1);
- MIPI_OUTP(mdss_dsi_base + 0x118, 0);
-
- mdss_dsi_clk_enable();
+ mdss_dsi_clk_enable(pdata);
spin_unlock_bh(&dsi_clk_lock);
clk_rate = pdata->panel_info.clk_rate;
@@ -148,7 +297,13 @@
wmb();
}
- ret = panel_pdata->on(pdata);
+ ret = mdss_dsi_panel_power_on(1);
+ if (ret) {
+ pr_err("%s: Panel power on failed\n", __func__);
+ return ret;
+ }
+
+ ret = dsi_drv.on(pdata);
if (ret) {
pr_err("%s: unable to initialize the panel\n", __func__);
return ret;
@@ -167,7 +322,7 @@
unsigned char *mdss_dsi_get_clk_base(void)
{
- return mdss_dsi_base;
+ return mmss_cc_base;
}
static int mdss_dsi_resource_initialized;
@@ -196,8 +351,35 @@
}
}
+ mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!mdss_dsi_mres) {
+ pr_err("%s:%d unable to get the MDSS resources",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+ if (mdss_dsi_mres) {
+ mmss_cc_base = ioremap(mdss_dsi_mres->start,
+ resource_size(mdss_dsi_mres));
+ if (!mmss_cc_base) {
+ pr_err("%s:%d unable to remap dsi resources",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+ }
+
+ rc = mdss_dsi_regulator_init(pdev);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "%s: failed to init regulator, rc=%d\n",
+ __func__, rc);
+ iounmap(mdss_dsi_base);
+ iounmap(mmss_cc_base);
+ return rc;
+ }
+
if (mdss_dsi_clk_init(pdev)) {
iounmap(mdss_dsi_base);
+ iounmap(mmss_cc_base);
return -EPERM;
}
@@ -208,6 +390,7 @@
"%s: failed to add child nodes, rc=%d\n",
__func__, rc);
iounmap(mdss_dsi_base);
+ iounmap(mmss_cc_base);
return rc;
}
@@ -240,21 +423,19 @@
u32 h_period, v_period, dsi_pclk_rate;
struct mdss_panel_data *pdata = NULL;
- panel_pdata = panel_data;
+ h_period = ((panel_data->panel_info.lcdc.h_pulse_width)
+ + (panel_data->panel_info.lcdc.h_back_porch)
+ + (panel_data->panel_info.xres)
+ + (panel_data->panel_info.lcdc.h_front_porch));
- h_period = ((panel_pdata->panel_info.lcdc.h_pulse_width)
- + (panel_pdata->panel_info.lcdc.h_back_porch)
- + (panel_pdata->panel_info.xres)
- + (panel_pdata->panel_info.lcdc.h_front_porch));
+ v_period = ((panel_data->panel_info.lcdc.v_pulse_width)
+ + (panel_data->panel_info.lcdc.v_back_porch)
+ + (panel_data->panel_info.yres)
+ + (panel_data->panel_info.lcdc.v_front_porch));
- v_period = ((panel_pdata->panel_info.lcdc.v_pulse_width)
- + (panel_pdata->panel_info.lcdc.v_back_porch)
- + (panel_pdata->panel_info.yres)
- + (panel_pdata->panel_info.lcdc.v_front_porch));
+ mipi = &panel_data->panel_info.mipi;
- mipi = &panel_pdata->panel_info.mipi;
-
- panel_pdata->panel_info.type =
+ panel_data->panel_info.type =
((mipi->mode == DSI_VIDEO_MODE)
? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
@@ -278,23 +459,23 @@
else
bpp = 3; /* Default format set to RGB888 */
- if (panel_pdata->panel_info.type == MIPI_VIDEO_PANEL &&
- !panel_pdata->panel_info.clk_rate) {
- h_period += panel_pdata->panel_info.lcdc.xres_pad;
- v_period += panel_pdata->panel_info.lcdc.yres_pad;
+ if (panel_data->panel_info.type == MIPI_VIDEO_PANEL &&
+ !panel_data->panel_info.clk_rate) {
+ h_period += panel_data->panel_info.lcdc.xres_pad;
+ v_period += panel_data->panel_info.lcdc.yres_pad;
if (lanes > 0) {
- panel_pdata->panel_info.clk_rate =
+ panel_data->panel_info.clk_rate =
((h_period * v_period * (mipi->frame_rate) * bpp * 8)
/ lanes);
} else {
pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
- panel_pdata->panel_info.clk_rate =
+ panel_data->panel_info.clk_rate =
(h_period * v_period
* (mipi->frame_rate) * bpp * 8);
}
}
- pll_divider_config.clk_rate = panel_pdata->panel_info.clk_rate;
+ pll_divider_config.clk_rate = panel_data->panel_info.clk_rate;
rc = mdss_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
if (rc) {
@@ -306,6 +487,9 @@
dsi_pclk_rate = 35000000;
mipi->dsi_pclk_rate = dsi_pclk_rate;
+ dsi_drv.on = panel_data->on;
+ dsi_drv.off = panel_data->off;
+
/*
* data chain
*/
@@ -315,10 +499,12 @@
pdata->on = mdss_dsi_on;
pdata->off = mdss_dsi_off;
- memcpy(&(pdata->panel_info), &(panel_pdata->panel_info),
+ memcpy(&(pdata->panel_info), &(panel_data->panel_info),
sizeof(struct mdss_panel_info));
pdata->dsi_base = mdss_dsi_base;
+ pdata->mmss_cc_base = mmss_cc_base;
+ pdata->set_backlight = panel_data->bl_ctrl;
/*
* register in mdp driver
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 57fce1a..6acb8d5 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -19,7 +19,6 @@
#include "mdss_panel.h"
-#define MMSS_MDSS_CC_BASE_PHY 0xFD8C2300 /* mmss clcok control */
#define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */
#define MIPI_OUTP(addr, data) writel_relaxed((data), (addr))
@@ -77,6 +76,12 @@
DSI_CMD_MODE_MDP,
};
+enum dsi_panel_bl_ctrl {
+ BL_PWM,
+ BL_WLED,
+ BL_DCS_CMD,
+};
+
#define DSI_NON_BURST_SYNCH_PULSE 0
#define DSI_NON_BURST_SYNCH_EVENT 1
#define DSI_BURST_MODE 2
@@ -242,8 +247,16 @@
struct mdss_panel_info panel_info;
int (*on) (struct mdss_panel_data *pdata);
int (*off) (struct mdss_panel_data *pdata);
+ void (*bl_ctrl) (u32 bl_level);
};
+struct mdss_dsi_drv_pdata {
+ struct regulator *vdd_vreg;
+ struct regulator *vdd_io_vreg;
+ struct regulator *dsi_vreg;
+ int (*on) (struct mdss_panel_data *pdata);
+ int (*off) (struct mdss_panel_data *pdata);
+};
int dsi_panel_device_register(struct platform_device *pdev,
struct mdss_panel_common_pdata *panel_data);
@@ -273,8 +286,8 @@
void mdss_dsi_cmd_mdp_start(void);
void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
void mdss_dsi_ack_err_status(unsigned char *dsi_base);
-void mdss_dsi_clk_enable(void);
-void mdss_dsi_clk_disable(void);
+void mdss_dsi_clk_enable(struct mdss_panel_data *pdata);
+void mdss_dsi_clk_disable(struct mdss_panel_data *pdata);
void mdss_dsi_controller_cfg(int enable,
struct mdss_panel_data *pdata);
void mdss_dsi_sw_reset(struct mdss_panel_data *pdata);
@@ -288,7 +301,10 @@
void mdss_dsi_clk_deinit(struct device *dev);
void mdss_dsi_prepare_clocks(void);
void mdss_dsi_unprepare_clocks(void);
-void cont_splash_clk_ctrl(int enable);
unsigned char *mdss_dsi_get_base_adr(void);
+void mdss_dsi_panel_reset(int enable);
+void mdss_dsi_phy_enable(struct mdss_panel_data *pdata, int on);
+void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
+void mdss_dsi_phy_sw_reset(struct mdss_panel_data *pdata);
#endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index bfb7fae..e4b1867 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -13,7 +13,12 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/qpnp/pin.h>
+#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/leds.h>
#include "mdss_dsi.h"
@@ -28,6 +33,68 @@
static int num_of_off_cmds;
static char *on_cmds, *off_cmds;
+static char bl_ctrl;
+DEFINE_LED_TRIGGER(bl_led_trigger);
+
+static struct mdss_dsi_phy_ctrl phy_params;
+
+static int rst_gpio;
+static int disp_en;
+
+struct qpnp_pin_cfg param = {
+ .mode = QPNP_PIN_MODE_DIG_OUT,
+ .output_type = QPNP_PIN_OUT_BUF_OPEN_DRAIN_NMOS,
+ .invert = QPNP_PIN_INVERT_ENABLE,
+ .pull = QPNP_PIN_MPP_PULL_UP_30KOHM,
+ .vin_sel = QPNP_PIN_VIN3,
+ .out_strength = QPNP_PIN_OUT_STRENGTH_HIGH,
+ .select = QPNP_PIN_SEL_DTEST3,
+ .master_en = QPNP_PIN_MASTER_ENABLE,
+ .aout_ref = QPNP_PIN_AOUT_0V625,
+ .ain_route = QPNP_PIN_AIN_AMUX_CH7,
+ .cs_out = QPNP_PIN_CS_OUT_20MA,
+};
+
+void mdss_dsi_panel_reset(int enable)
+{
+ if (!disp_en)
+ pr_debug("%s:%d, reset line not configured\n",
+ __func__, __LINE__);
+
+ if (!rst_gpio)
+ pr_debug("%s:%d, reset line not configured\n",
+ __func__, __LINE__);
+
+ if (enable) {
+ gpio_set_value(disp_en, 1);
+ gpio_set_value(rst_gpio, 1);
+ usleep(10);
+ gpio_set_value(rst_gpio, 0);
+ usleep(200);
+ gpio_set_value(rst_gpio, 1);
+ } else {
+ gpio_set_value(rst_gpio, 0);
+ gpio_set_value(disp_en, 0);
+ }
+}
+
+static void mdss_dsi_panel_bl_ctrl(u32 bl_level)
+{
+ if (bl_ctrl) {
+ switch (bl_ctrl) {
+ case BL_WLED:
+ led_trigger_event(bl_led_trigger, bl_level);
+ break;
+
+ default:
+ pr_err("%s: Unknown bl_ctrl configuration\n",
+ __func__);
+ break;
+ }
+ } else
+ pr_err("%s:%d, bl_ctrl not configured", __func__, __LINE__);
+}
+
static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
{
struct mipi_panel_info *mipi;
@@ -37,6 +104,8 @@
pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
mipi->mode);
+ mdss_dsi_panel_reset(1);
+
if (mipi->mode == DSI_VIDEO_MODE) {
mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_on_cmds,
num_of_on_cmds);
@@ -64,6 +133,8 @@
return -EINVAL;
}
+ mdss_dsi_panel_reset(0);
+
return 0;
}
@@ -75,6 +146,7 @@
int rc, i, len;
int cmd_plen, data_offset;
const char *data;
+ static const char *bl_ctrl_type;
rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
if (rc) {
@@ -85,6 +157,59 @@
panel_data->panel_info.xres = (!rc ? res[0] : 640);
panel_data->panel_info.yres = (!rc ? res[1] : 480);
+ rc = of_property_read_u32_array(np, "qcom,mdss-pan-active-res", res, 2);
+ if (rc == 0) {
+ panel_data->panel_info.lcdc.xres_pad =
+ panel_data->panel_info.xres - res[0];
+ panel_data->panel_info.lcdc.yres_pad =
+ panel_data->panel_info.yres - res[1];
+ }
+
+ disp_en = of_get_named_gpio(np, "qcom,enable-gpio", 0);
+ if (!gpio_is_valid(disp_en)) {
+ pr_err("%s:%d, Disp_en gpio not specified\n",
+ __func__, __LINE__);
+ return -ENODEV;
+ }
+
+ rc = gpio_request(disp_en, "disp_enable");
+ if (rc) {
+ pr_err("request reset gpio failed, rc=%d\n",
+ rc);
+ gpio_free(disp_en);
+ return -ENODEV;
+ }
+ rc = gpio_direction_output(disp_en, 1);
+ if (rc) {
+ pr_err("set_direction for disp_en gpio failed, rc=%d\n",
+ rc);
+ gpio_free(disp_en);
+ return -ENODEV;
+ }
+
+ rst_gpio = of_get_named_gpio(np, "qcom,rst-gpio", 0);
+ if (!gpio_is_valid(rst_gpio)) {
+ pr_err("%s:%d, reset gpio not specified\n",
+ __func__, __LINE__);
+ } else {
+ rc = qpnp_pin_config(rst_gpio, ¶m);
+ if (rc) {
+ pr_err("request reset gpio failed, rc=%d\n",
+ rc);
+ gpio_free(disp_en);
+ return rc;
+ }
+
+ rc = gpio_request(rst_gpio, "disp_rst_n");
+ if (rc) {
+ pr_err("request reset gpio failed, rc=%d\n",
+ rc);
+ gpio_free(rst_gpio);
+ gpio_free(disp_en);
+ return -ENODEV;
+ }
+ }
+
rc = of_property_read_u32(np, "qcom,mdss-pan-bpp", &tmp);
if (rc) {
pr_err("%s:%d, panel bpp not specified\n",
@@ -106,6 +231,14 @@
"qcom,mdss-pan-underflow-clr", &tmp);
panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
+ bl_ctrl_type = of_get_property(pdev->dev.of_node,
+ "qcom,mdss-pan-bl-ctrl", NULL);
+ if (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12)) {
+ led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
+ pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
+ bl_ctrl = BL_WLED;
+ }
+
rc = of_property_read_u32_array(np,
"qcom,mdss-pan-bl-levels", res, 2);
panel_data->panel_info.bl_min = (!rc ? res[0] : 0);
@@ -184,6 +317,53 @@
rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp);
panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60);
+ data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len);
+ if ((!data) || (len != 8)) {
+ pr_err("%s:%d, Unable to read Phy regulator settings",
+ __func__, __LINE__);
+ goto error;
+ }
+ for (i = 0; i < len; i++)
+ phy_params.regulator[i] = data[i];
+
+ data = of_get_property(np, "qcom,panel-phy-timingSettings", &len);
+ if ((!data) || (len != 12)) {
+ pr_err("%s:%d, Unable to read Phy timing settings",
+ __func__, __LINE__);
+ goto error;
+ }
+ for (i = 0; i < len; i++)
+ phy_params.timing[i] = data[i];
+
+ data = of_get_property(np, "qcom,panel-phy-strengthCtrl", &len);
+ if ((!data) || (len != 2)) {
+ pr_err("%s:%d, Unable to read Phy Strength ctrl settings",
+ __func__, __LINE__);
+ goto error;
+ }
+ phy_params.strength[0] = data[0];
+ phy_params.strength[1] = data[1];
+
+ data = of_get_property(np, "qcom,panel-phy-bistCtrl", &len);
+ if ((!data) || (len != 6)) {
+ pr_err("%s:%d, Unable to read Phy Bist Ctrl settings",
+ __func__, __LINE__);
+ goto error;
+ }
+ for (i = 0; i < len; i++)
+ phy_params.bistCtrl[i] = data[i];
+
+ data = of_get_property(np, "qcom,panel-phy-laneConfig", &len);
+ if ((!data) || (len != 45)) {
+ pr_err("%s:%d, Unable to read Phy lane configure settings",
+ __func__, __LINE__);
+ goto error;
+ }
+ for (i = 0; i < len; i++)
+ phy_params.laneCfg[i] = data[i];
+
+ panel_data->panel_info.mipi.dsi_phy_db = &phy_params;
+
data = of_get_property(np, "qcom,panel-on-cmds", &len);
if (!data) {
pr_err("%s:%d, Unable to read ON cmds", __func__, __LINE__);
@@ -288,6 +468,10 @@
kfree(dsi_panel_off_cmds);
kfree(on_cmds);
kfree(off_cmds);
+ if (rst_gpio)
+ gpio_free(rst_gpio);
+ if (disp_en)
+ gpio_free(disp_en);
return -EINVAL;
}
@@ -295,7 +479,7 @@
static int __devinit mdss_dsi_panel_probe(struct platform_device *pdev)
{
int rc = 0;
- struct mdss_panel_common_pdata *vendor_pdata = NULL;
+ static struct mdss_panel_common_pdata vendor_pdata;
static const char *panel_name;
if (pdev->dev.parent == NULL) {
@@ -314,21 +498,15 @@
else
pr_info("%s: Panel Name = %s\n", __func__, panel_name);
- vendor_pdata = devm_kzalloc(&pdev->dev,
- sizeof(*vendor_pdata), GFP_KERNEL);
- if (!vendor_pdata)
- return -ENOMEM;
-
- rc = mdss_panel_parse_dt(pdev, vendor_pdata);
- if (rc) {
- devm_kfree(&pdev->dev, vendor_pdata);
- vendor_pdata = NULL;
+ rc = mdss_panel_parse_dt(pdev, &vendor_pdata);
+ if (rc)
return rc;
- }
- vendor_pdata->on = mdss_dsi_panel_on;
- vendor_pdata->off = mdss_dsi_panel_off;
- rc = dsi_panel_device_register(pdev, vendor_pdata);
+ vendor_pdata.on = mdss_dsi_panel_on;
+ vendor_pdata.off = mdss_dsi_panel_off;
+ vendor_pdata.bl_ctrl = mdss_dsi_panel_bl_ctrl;
+
+ rc = dsi_panel_device_register(pdev, &vendor_pdata);
if (rc)
return rc;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index ee086ad..1a1bb07 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -276,9 +276,8 @@
if ((!mfd) || (mfd->key != MFD_KEY))
return 0;
- /*
- * suspend this channel
- */
+ pr_debug("mdss_fb suspend index=%d\n", mfd->index);
+
mfd->suspend.op_enable = mfd->op_enable;
mfd->suspend.panel_power_on = mfd->panel_power_on;
@@ -295,7 +294,6 @@
return 0;
}
-#if defined(CONFIG_PM)
static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd)
{
int ret = 0;
@@ -303,6 +301,8 @@
if ((!mfd) || (mfd->key != MFD_KEY))
return 0;
+ pr_debug("mdss_fb resume index=%d\n", mfd->index);
+
/* resume state var recover */
mfd->op_enable = mfd->suspend.op_enable;
@@ -316,59 +316,43 @@
return ret;
}
-static int mdss_fb_suspend(struct platform_device *pdev, pm_message_t state)
+int mdss_fb_suspend_all(void)
{
- struct msm_fb_data_type *mfd;
- int ret = 0;
-
- pr_debug("mdss_fb_suspend\n");
-
- mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-
- if ((!mfd) || (mfd->key != MFD_KEY))
- return 0;
-
+ struct fb_info *fbi;
+ int ret, i;
+ int result = 0;
console_lock();
- fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED);
+ for (i = 0; i < fbi_list_index; i++) {
+ fbi = fbi_list[i];
+ fb_set_suspend(fbi, FBINFO_STATE_SUSPENDED);
- ret = mdss_fb_suspend_sub(mfd);
- if (ret != 0) {
- pr_err("failed to suspend! %d\n", ret);
- fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
- } else {
- pdev->dev.power.power_state = state;
+ ret = mdss_fb_suspend_sub(fbi->par);
+ if (ret != 0) {
+ fb_set_suspend(fbi, FBINFO_STATE_RUNNING);
+ result = ret;
+ }
}
-
console_unlock();
- return ret;
+ return result;
}
-static int mdss_fb_resume(struct platform_device *pdev)
+int mdss_fb_resume_all(void)
{
- /* This resume function is called when interrupt is enabled.
- */
- int ret = 0;
- struct msm_fb_data_type *mfd;
-
- pr_debug("mdss_fb_resume\n");
-
- mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-
- if ((!mfd) || (mfd->key != MFD_KEY))
- return 0;
+ struct fb_info *fbi;
+ int ret, i;
+ int result = 0;
console_lock();
- ret = mdss_fb_resume_sub(mfd);
- pdev->dev.power.power_state = PMSG_ON;
- fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
- console_unlock();
+ for (i = 0; i < fbi_list_index; i++) {
+ fbi = fbi_list[i];
- return ret;
+ ret = mdss_fb_resume_sub(fbi->par);
+ if (ret == 0)
+ fb_set_suspend(fbi, FBINFO_STATE_RUNNING);
+ }
+ console_unlock();
+ return result;
}
-#else
-#define mdss_fb_suspend NULL
-#define mdss_fb_resume NULL
-#endif
#if defined(CONFIG_PM) && defined(CONFIG_SUSPEND)
static int mdss_fb_ext_suspend(struct device *dev)
@@ -413,9 +397,6 @@
static struct platform_driver mdss_fb_driver = {
.probe = mdss_fb_probe,
.remove = mdss_fb_remove,
- .suspend = mdss_fb_suspend,
- .resume = mdss_fb_resume,
- .shutdown = NULL,
.driver = {
.name = "mdss_fb",
.pm = &mdss_fb_dev_pm_ops,
@@ -611,11 +592,27 @@
size *= mfd->fb_page;
if (mfd->index == 0) {
- virt = dma_alloc_coherent(NULL, size, (dma_addr_t *) &phys,
- GFP_KERNEL);
- if (!virt) {
- pr_err("unable to alloc fb memory size=%u\n", size);
- return -ENOMEM;
+ struct ion_client *iclient = mfd->iclient;
+
+ if (iclient) {
+ mfd->ihdl = ion_alloc(iclient, size, SZ_4K,
+ ION_HEAP(ION_CP_MM_HEAP_ID) |
+ ION_HEAP(ION_SF_HEAP_ID));
+ if (IS_ERR_OR_NULL(mfd->ihdl)) {
+ pr_err("unable to alloc fbmem from ion (%p)\n",
+ mfd->ihdl);
+ return -ENOMEM;
+ }
+
+ virt = ion_map_kernel(iclient, mfd->ihdl, 0);
+ ion_phys(iclient, mfd->ihdl, &phys, &size);
+ } else {
+ virt = dma_alloc_coherent(NULL, size,
+ (dma_addr_t *) &phys, GFP_KERNEL);
+ if (!virt) {
+ pr_err("unable to alloc fbmem size=%u\n", size);
+ return -ENOMEM;
+ }
}
pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
@@ -813,15 +810,6 @@
mfd->op_enable = true;
- /* cursor memory allocation */
- if (mfd->cursor_update) {
- mfd->cursor_buf = dma_alloc_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
- (dma_addr_t *) &mfd->cursor_buf_phys,
- GFP_KERNEL);
- if (!mfd->cursor_buf)
- mfd->cursor_update = 0;
- }
-
if (mfd->lut_update) {
ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
if (ret)
@@ -832,11 +820,6 @@
if (mfd->lut_update)
fb_dealloc_cmap(&fbi->cmap);
- if (mfd->cursor_buf)
- dma_free_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
- mfd->cursor_buf,
- (dma_addr_t) mfd->cursor_buf_phys);
-
mfd->op_enable = false;
return -EPERM;
}
@@ -1107,7 +1090,7 @@
if (ret)
return ret;
- return mfd->cursor_update(info, &cursor);
+ return mfd->cursor_update(mfd, &cursor);
}
static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
@@ -1123,7 +1106,7 @@
if (ret)
return ret;
- mfd->lut_update(info, &cmap);
+ mfd->lut_update(mfd, &cmap);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index ac6c213..ab140fe 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -69,12 +69,13 @@
int (*kickoff_fnc) (struct mdss_mdp_ctl *ctl);
int (*ioctl_handler) (struct msm_fb_data_type *mfd, u32 cmd, void *arg);
void (*dma_fnc) (struct msm_fb_data_type *mfd);
- int (*cursor_update) (struct fb_info *info,
+ int (*cursor_update) (struct msm_fb_data_type *mfd,
struct fb_cursor *cursor);
- int (*lut_update) (struct fb_info *info,
- struct fb_cmap *cmap);
- int (*do_histogram) (struct fb_info *info,
+ int (*lut_update) (struct msm_fb_data_type *mfd, struct fb_cmap *cmap);
+ int (*do_histogram) (struct msm_fb_data_type *mfd,
struct mdp_histogram *hist);
+
+ struct ion_handle *ihdl;
void *cursor_buf;
void *cursor_buf_phys;
@@ -97,4 +98,6 @@
int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
+int mdss_fb_suspend_all(void);
+int mdss_fb_resume_all(void);
#endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 46e49da..695ca1c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -25,6 +25,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/memory_alloc.h>
@@ -46,10 +47,7 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
-unsigned char *mdss_reg_base;
-
-struct mdss_res_type *mdss_res;
-static struct msm_panel_common_pdata *mdp_pdata;
+struct mdss_data_type *mdss_res;
static DEFINE_SPINLOCK(mdp_lock);
static DEFINE_MUTEX(mdp_clk_lock);
@@ -74,30 +72,18 @@
MDSS_MDP_MIXER_TYPE_WRITEBACK,
};
-#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
- { \
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
+ { \
.src = MSM_BUS_MASTER_MDP_PORT0, \
.dst = MSM_BUS_SLAVE_EBI_CH0, \
.ab = (ab_val), \
.ib = (ib_val), \
}
-#define MDP_BUS_VECTOR_ENTRY_NDX(n) \
- MDP_BUS_VECTOR_ENTRY((n) * 100000000, (n) * 200000000)
-
static struct msm_bus_vectors mdp_bus_vectors[] = {
- MDP_BUS_VECTOR_ENTRY_NDX(0),
- MDP_BUS_VECTOR_ENTRY_NDX(1),
- MDP_BUS_VECTOR_ENTRY_NDX(2),
- MDP_BUS_VECTOR_ENTRY_NDX(3),
- MDP_BUS_VECTOR_ENTRY_NDX(4),
- MDP_BUS_VECTOR_ENTRY_NDX(5),
- MDP_BUS_VECTOR_ENTRY_NDX(6),
- MDP_BUS_VECTOR_ENTRY_NDX(7),
- MDP_BUS_VECTOR_ENTRY_NDX(8),
- MDP_BUS_VECTOR_ENTRY_NDX(9),
- MDP_BUS_VECTOR_ENTRY_NDX(10),
- MDP_BUS_VECTOR_ENTRY(200000000, 200000000)
+ MDP_BUS_VECTOR_ENTRY(0, 0),
+ MDP_BUS_VECTOR_ENTRY(SZ_128M, SZ_256M),
+ MDP_BUS_VECTOR_ENTRY(SZ_256M, SZ_512M),
};
static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
static struct msm_bus_scale_pdata mdp_bus_scale_table = {
@@ -129,9 +115,13 @@
static irqreturn_t mdss_irq_handler(int irq, void *ptr)
{
+ struct mdss_data_type *mdata = ptr;
u32 intr = MDSS_MDP_REG_READ(MDSS_REG_HW_INTR_STATUS);
- mdss_res->irq_buzy = true;
+ if (!mdata)
+ return IRQ_NONE;
+
+ mdata->irq_buzy = true;
if (intr & MDSS_INTR_MDP)
mdss_irq_dispatch(MDSS_HW_MDP, irq, ptr);
@@ -148,7 +138,7 @@
if (intr & MDSS_INTR_HDMI)
mdss_irq_dispatch(MDSS_HW_HDMI, irq, ptr);
- mdss_res->irq_buzy = false;
+ mdata->irq_buzy = false;
return IRQ_HANDLED;
}
@@ -240,9 +230,9 @@
}
EXPORT_SYMBOL(mdss_disable_irq_nosync);
-static int mdss_mdp_bus_scale_register(void)
+static int mdss_mdp_bus_scale_register(struct mdss_data_type *mdata)
{
- if (!mdss_res->bus_hdl) {
+ if (!mdata->bus_hdl) {
struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
int i;
@@ -251,53 +241,58 @@
mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i];
}
- mdss_res->bus_hdl = msm_bus_scale_register_client(bus_pdata);
- if (!mdss_res->bus_hdl) {
+ mdata->bus_hdl = msm_bus_scale_register_client(bus_pdata);
+ if (!mdata->bus_hdl) {
pr_err("not able to get bus scale\n");
return -ENOMEM;
}
- pr_debug("register bus_hdl=%x\n", mdss_res->bus_hdl);
+ pr_debug("register bus_hdl=%x\n", mdata->bus_hdl);
}
return 0;
}
-static void mdss_mdp_bus_scale_unregister(void)
+static void mdss_mdp_bus_scale_unregister(struct mdss_data_type *mdata)
{
- pr_debug("unregister bus_hdl=%x\n", mdss_res->bus_hdl);
+ pr_debug("unregister bus_hdl=%x\n", mdata->bus_hdl);
- if (mdss_res->bus_hdl)
- msm_bus_scale_unregister_client(mdss_res->bus_hdl);
+ if (mdata->bus_hdl)
+ msm_bus_scale_unregister_client(mdata->bus_hdl);
}
-int mdss_mdp_bus_scale_set_min_quota(u32 quota)
+int mdss_mdp_bus_scale_set_quota(u32 ab_quota, u32 ib_quota)
{
- struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
- struct msm_bus_vectors *vect = NULL;
- int lvl;
+ static int current_bus_idx;
+ int bus_idx;
if (mdss_res->bus_hdl < 1) {
pr_err("invalid bus handle %d\n", mdss_res->bus_hdl);
return -EINVAL;
}
- for (lvl = 0; lvl < bus_pdata->num_usecases; lvl++) {
- if (bus_pdata->usecase[lvl].num_paths) {
- vect = &bus_pdata->usecase[lvl].vectors[0];
- if (vect->ab >= quota) {
- pr_debug("lvl=%d quota=%u ab=%u\n", lvl, quota,
- vect->ab);
- break;
- }
+ if ((ab_quota | ib_quota) == 0) {
+ bus_idx = 0;
+ } else {
+ int num_cases = mdp_bus_scale_table.num_usecases;
+ struct msm_bus_vectors *vect = NULL;
+
+ bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
+
+ vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
+ if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
+ pr_debug("skip bus scaling, no change in vectors\n");
+ return 0;
}
- }
- if (lvl == bus_pdata->num_usecases) {
- pr_warn("cannot match quota=%u try with max level\n", quota);
- lvl--;
- }
+ vect = mdp_bus_scale_table.usecase[bus_idx].vectors;
+ vect->ab = ab_quota;
+ vect->ib = ib_quota;
- return msm_bus_scale_client_update_request(mdss_res->bus_hdl, lvl);
+ pr_debug("bus scale idx=%d ab=%u ib=%u\n", bus_idx,
+ vect->ab, vect->ib);
+ }
+ current_bus_idx = bus_idx;
+ return msm_bus_scale_client_update_request(mdss_res->bus_hdl, bus_idx);
}
static inline u32 mdss_mdp_irq_mask(u32 intr_type, u32 intf_num)
@@ -348,9 +343,11 @@
irq, mdss_res->mdp_irq_mask);
} else {
mdss_res->mdp_irq_mask &= ~irq;
+
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
mdss_res->mdp_irq_mask);
- mdss_disable_irq(&mdss_mdp_hw);
+ if (mdss_res->mdp_irq_mask == 0)
+ mdss_disable_irq(&mdss_mdp_hw);
}
spin_unlock_irqrestore(&mdp_lock, irq_flags);
}
@@ -369,7 +366,8 @@
mdss_res->mdp_irq_mask &= ~irq;
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
mdss_res->mdp_irq_mask);
- mdss_disable_irq_nosync(&mdss_mdp_hw);
+ if (mdss_res->mdp_irq_mask == 0)
+ mdss_disable_irq_nosync(&mdss_mdp_hw);
}
spin_unlock(&mdp_lock);
}
@@ -427,6 +425,8 @@
pr_debug("mdp clk rate=%lu\n", clk_rate);
}
mutex_unlock(&mdp_clk_lock);
+ } else {
+ pr_err("mdp src clk not setup properly\n");
}
}
@@ -466,7 +466,7 @@
static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
{
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
}
void mdss_mdp_clk_ctrl(int enable, int isr)
@@ -485,13 +485,19 @@
*/
WARN_ON(isr == true && enable);
- if (enable) {
+ if (enable == MDP_BLOCK_POWER_ON) {
atomic_inc(&clk_ref);
} else if (!atomic_add_unless(&clk_ref, -1, 0)) {
- pr_debug("master power-off req\n");
- force_off = 1;
+ if (enable == MDP_BLOCK_MASTER_OFF) {
+ pr_debug("master power-off req\n");
+ force_off = 1;
+ } else {
+ WARN(1, "too many mdp clock off call\n");
+ }
}
+ WARN_ON(enable == MDP_BLOCK_MASTER_OFF && !force_off);
+
if (isr) {
/* if it's power off send workqueue to turn off clocks */
if (mdss_res->clk_ena && !atomic_read(&clk_ref))
@@ -521,7 +527,7 @@
}
}
-static inline int mdss_mdp_irq_clk_register(struct platform_device *pdev,
+static inline int mdss_mdp_irq_clk_register(struct mdss_data_type *mdata,
char *clk_name, int clk_idx)
{
struct clk *tmp;
@@ -530,181 +536,191 @@
return -EINVAL;
}
-
- tmp = clk_get(&pdev->dev, clk_name);
+ tmp = devm_clk_get(&mdata->pdev->dev, clk_name);
if (IS_ERR(tmp)) {
pr_err("unable to get clk: %s\n", clk_name);
return PTR_ERR(tmp);
}
- mdss_res->mdp_clk[clk_idx] = tmp;
+ mdata->mdp_clk[clk_idx] = tmp;
return 0;
}
-static int mdss_mdp_irq_clk_setup(struct platform_device *pdev)
+static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata)
{
int ret;
- int i;
- ret = request_irq(mdss_res->irq, mdss_irq_handler, IRQF_DISABLED,
- "MDSS", 0);
+ ret = devm_request_irq(&mdata->pdev->dev, mdata->irq, mdss_irq_handler,
+ IRQF_DISABLED, "MDSS", mdata);
if (ret) {
pr_err("mdp request_irq() failed!\n");
return ret;
}
- disable_irq(mdss_res->irq);
+ disable_irq(mdata->irq);
- mdss_res->fs = regulator_get(&pdev->dev, "vdd");
- if (IS_ERR_OR_NULL(mdss_res->fs)) {
- mdss_res->fs = NULL;
+ mdata->fs = devm_regulator_get(&mdata->pdev->dev, "vdd");
+ if (IS_ERR_OR_NULL(mdata->fs)) {
+ mdata->fs = NULL;
pr_err("unable to get gdsc regulator\n");
- goto error;
+ return -EINVAL;
}
- regulator_enable(mdss_res->fs);
+ regulator_enable(mdata->fs);
+ mdata->fs_ena = true;
- if (mdss_mdp_irq_clk_register(pdev, "bus_clk", MDSS_CLK_AXI) ||
- mdss_mdp_irq_clk_register(pdev, "iface_clk", MDSS_CLK_AHB) ||
- mdss_mdp_irq_clk_register(pdev, "core_clk_src", MDSS_CLK_MDP_SRC) ||
- mdss_mdp_irq_clk_register(pdev, "core_clk", MDSS_CLK_MDP_CORE) ||
- mdss_mdp_irq_clk_register(pdev, "lut_clk", MDSS_CLK_MDP_LUT) ||
- mdss_mdp_irq_clk_register(pdev, "vsync_clk", MDSS_CLK_MDP_VSYNC))
- goto error;
+ if (mdss_mdp_irq_clk_register(mdata, "bus_clk", MDSS_CLK_AXI) ||
+ mdss_mdp_irq_clk_register(mdata, "iface_clk", MDSS_CLK_AHB) ||
+ mdss_mdp_irq_clk_register(mdata, "core_clk_src",
+ MDSS_CLK_MDP_SRC) ||
+ mdss_mdp_irq_clk_register(mdata, "core_clk",
+ MDSS_CLK_MDP_CORE) ||
+ mdss_mdp_irq_clk_register(mdata, "lut_clk", MDSS_CLK_MDP_LUT) ||
+ mdss_mdp_irq_clk_register(mdata, "vsync_clk", MDSS_CLK_MDP_VSYNC))
+ return -EINVAL;
mdss_mdp_set_clk_rate(MDP_CLK_DEFAULT_RATE);
pr_debug("mdp clk rate=%ld\n", mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC));
return 0;
-error:
- for (i = 0; i < MDSS_MAX_CLK; i++) {
- if (mdss_res->mdp_clk[i])
- clk_put(mdss_res->mdp_clk[i]);
- }
- if (mdss_res->fs)
- regulator_put(mdss_res->fs);
- if (mdss_res->irq)
- free_irq(mdss_res->irq, 0);
-
- return -EINVAL;
-
}
-static struct msm_panel_common_pdata *mdss_mdp_populate_pdata(
- struct device *dev)
+static int mdss_hw_init(struct mdss_data_type *mdata)
{
- struct msm_panel_common_pdata *pdata;
-
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- dev_err(dev, "could not allocate memory for pdata\n");
- return pdata;
-}
-
-static u32 mdss_mdp_res_init(struct platform_device *pdev)
-{
- u32 rc;
-
- rc = mdss_mdp_irq_clk_setup(pdev);
- if (rc)
- return rc;
-
- mdss_res->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
- INIT_DELAYED_WORK(&mdss_res->clk_ctrl_worker,
- mdss_mdp_clk_ctrl_workqueue_handler);
+ char *base = mdata->vbif_base;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- mdss_res->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
- mdss_res->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+ /* Setup VBIF QoS settings*/
+ MDSS_MDP_REG_WRITE(0x2E0, 0x000000AA);
+ MDSS_MDP_REG_WRITE(0x2E4, 0x00000055);
+ writel_relaxed(0x00000001, base + 0x004);
+ writel_relaxed(0x00000707, base + 0x0D8);
+ writel_relaxed(0x00000030, base + 0x0F0);
+ writel_relaxed(0x00000001, base + 0x124);
+ writel_relaxed(0x00000FFF, base + 0x178);
+ writel_relaxed(0x0FFF0FFF, base + 0x17C);
+ writel_relaxed(0x22222222, base + 0x160);
+ writel_relaxed(0x00002222, base + 0x164);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-
- mdss_res->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
- mdss_res->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
- mdss_res->pipe_type_map = mdss_mdp_pipe_type_map;
- mdss_res->mixer_type_map = mdss_mdp_mixer_type_map;
-
- pr_info("mdss_revision=%x\n", mdss_res->rev);
- pr_info("mdp_hw_revision=%x\n", mdss_res->mdp_rev);
-
- mdss_res->res_init = true;
- mdss_res->timeout = HZ/20;
- mdss_res->clk_ena = false;
- mdss_res->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK;
- mdss_res->suspend = false;
- mdss_res->prim_ptype = NO_PANEL;
- mdss_res->irq_ena = false;
+ pr_debug("MDP hw init done\n");
return 0;
}
+static u32 mdss_mdp_res_init(struct mdss_data_type *mdata)
+{
+ u32 rc;
+
+ rc = mdss_mdp_irq_clk_setup(mdata);
+ if (rc)
+ return rc;
+
+ mdata->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
+ INIT_DELAYED_WORK(&mdata->clk_ctrl_worker,
+ mdss_mdp_clk_ctrl_workqueue_handler);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdata->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
+ mdata->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ mdata->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
+ mdata->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
+ mdata->pipe_type_map = mdss_mdp_pipe_type_map;
+ mdata->mixer_type_map = mdss_mdp_mixer_type_map;
+
+ pr_info("mdss_revision=%x\n", mdata->rev);
+ pr_info("mdp_hw_revision=%x\n", mdata->mdp_rev);
+
+ mdata->res_init = true;
+ mdata->timeout = HZ/20;
+ mdata->clk_ena = false;
+ mdata->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK;
+ mdata->suspend = false;
+ mdata->prim_ptype = NO_PANEL;
+ mdata->irq_ena = false;
+
+ rc = mdss_hw_init(mdata);
+
+ return rc;
+}
+
static int mdss_mdp_probe(struct platform_device *pdev)
{
- struct resource *mdss_mdp_mres;
- struct resource *mdss_mdp_ires;
- resource_size_t size;
+ struct resource *res;
int rc;
+ struct mdss_data_type *mdata;
- if (!mdss_res) {
- mdss_res = devm_kzalloc(&pdev->dev, sizeof(*mdss_res),
- GFP_KERNEL);
- if (mdss_res == NULL)
- return -ENOMEM;
+ if (!pdev->dev.of_node) {
+ pr_err("MDP driver only supports device tree probe\n");
+ return -ENOTSUPP;
}
- if (pdev->dev.of_node) {
- pdev->id = 0;
- mdp_pdata = mdss_mdp_populate_pdata(&pdev->dev);
- mdss_mdp_mres = platform_get_resource(pdev,
- IORESOURCE_MEM, 0);
- mdss_mdp_ires = platform_get_resource(pdev,
- IORESOURCE_IRQ, 0);
- if (!mdss_mdp_mres || !mdss_mdp_ires) {
- pr_err("unable to get the MDSS resources");
- rc = -ENOMEM;
- goto probe_done;
- }
- mdss_reg_base = ioremap(mdss_mdp_mres->start,
- resource_size(mdss_mdp_mres));
-
- pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
- (int) mdss_mdp_mres->start,
- (int) mdss_reg_base);
-
- mdss_res->irq = mdss_mdp_ires->start;
- } else if ((pdev->id == 0) && (pdev->num_resources > 0)) {
- mdp_pdata = pdev->dev.platform_data;
-
- size = resource_size(&pdev->resource[0]);
- mdss_reg_base = ioremap(pdev->resource[0].start, size);
-
- pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
- (int) pdev->resource[0].start,
- (int) mdss_reg_base);
-
- mdss_res->irq = platform_get_irq(pdev, 0);
- if (mdss_res->irq < 0) {
- pr_err("can not get mdp irq\n");
- rc = -ENOMEM;
- goto probe_done;
- }
+ if (mdss_res) {
+ pr_err("MDP already initialized\n");
+ return -EINVAL;
}
- if (unlikely(!mdss_reg_base)) {
+ mdata = devm_kzalloc(&pdev->dev, sizeof(*mdata), GFP_KERNEL);
+ if (mdata == NULL)
+ return -ENOMEM;
+
+ pdev->id = 0;
+ mdata->pdev = pdev;
+ platform_set_drvdata(pdev, mdata);
+ mdss_res = mdata;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdp_phys");
+ if (!res) {
+ pr_err("unable to get MDP base address\n");
rc = -ENOMEM;
goto probe_done;
}
- rc = mdss_mdp_res_init(pdev);
+ mdata->mdp_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (unlikely(!mdata->mdp_base)) {
+ pr_err("unable to map MDP base\n");
+ rc = -ENOMEM;
+ goto probe_done;
+ }
+ pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
+ (int) res->start,
+ (int) mdata->mdp_base);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vbif_phys");
+ if (!res) {
+ pr_err("unable to get MDSS VBIF base address\n");
+ rc = -ENOMEM;
+ goto probe_done;
+ }
+
+ mdata->vbif_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (unlikely(!mdata->vbif_base)) {
+ pr_err("unable to map MDSS VBIF base\n");
+ rc = -ENOMEM;
+ goto probe_done;
+ }
+ pr_info("MDSS VBIF HW Base phy_Address=0x%x virt=0x%x\n",
+ (int) res->start,
+ (int) mdata->vbif_base);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ pr_err("unable to get MDSS irq\n");
+ rc = -ENOMEM;
+ goto probe_done;
+ }
+ mdata->irq = res->start;
+
+ rc = mdss_mdp_res_init(mdata);
if (rc) {
pr_err("unable to initialize mdss mdp resources\n");
goto probe_done;
}
- rc = mdss_mdp_bus_scale_register();
+ rc = mdss_mdp_bus_scale_register(mdata);
probe_done:
- if (IS_ERR_VALUE(rc)) {
- if (mdss_res) {
- devm_kfree(&pdev->dev, mdss_res);
- mdss_res = NULL;
- }
- }
+ if (IS_ERR_VALUE(rc))
+ mdss_res = NULL;
return rc;
}
@@ -736,7 +752,7 @@
flush_workqueue(mdss_res->clk_ctrl_wq);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
mutex_lock(&mdp_suspend_mutex);
mdss_res->suspend = true;
@@ -745,24 +761,44 @@
static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
{
- if (pdev->id == 0) {
- mdss_mdp_suspend_sub();
- if (mdss_res->clk_ena) {
- pr_err("MDP suspend failed\n");
- return -EBUSY;
- }
- mdss_mdp_footswitch_ctrl(false);
+ int ret;
+ pr_debug("display suspend");
+
+ ret = mdss_fb_suspend_all();
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("Unable to suspend all fb panels (%d)\n", ret);
+ return ret;
}
+ mdss_mdp_suspend_sub();
+ if (mdss_res->clk_ena) {
+ pr_err("MDP suspend failed\n");
+ return -EBUSY;
+ }
+ mdss_mdp_footswitch_ctrl(false);
+
return 0;
}
static int mdss_mdp_resume(struct platform_device *pdev)
{
+ struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ if (!mdata)
+ return -ENODEV;
+
+ pr_debug("resume display");
+
mdss_mdp_footswitch_ctrl(true);
mutex_lock(&mdp_suspend_mutex);
mdss_res->suspend = false;
mutex_unlock(&mdp_suspend_mutex);
- return 0;
+ ret = mdss_fb_resume_all();
+ if (IS_ERR_VALUE(ret))
+ pr_err("Unable to resume all fb panels (%d)\n", ret);
+
+ mdss_hw_init(mdata);
+ return ret;
}
#else
#define mdss_mdp_suspend NULL
@@ -771,11 +807,11 @@
static int mdss_mdp_remove(struct platform_device *pdev)
{
- if (mdss_res->fs != NULL)
- regulator_put(mdss_res->fs);
- iounmap(mdss_reg_base);
+ struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+ if (!mdata)
+ return -ENODEV;
pm_runtime_disable(&pdev->dev);
- mdss_mdp_bus_scale_unregister();
+ mdss_mdp_bus_scale_unregister(mdata);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 4489fbb..17281d5 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -40,6 +40,11 @@
#define MAX_DOWNSCALE_RATIO 4
#define MAX_UPSCALE_RATIO 20
+#define C3_ALPHA 3 /* alpha */
+#define C2_R_Cr 2 /* R/Cr */
+#define C1_B_Cb 1 /* B/Cb */
+#define C0_G_Y 0 /* G/luma */
+
#ifdef MDSS_MDP_DEBUG_REG
static inline void mdss_mdp_reg_write(u32 addr, u32 val)
{
@@ -61,8 +66,9 @@
#endif
enum mdss_mdp_block_power_state {
- MDP_BLOCK_POWER_OFF,
- MDP_BLOCK_POWER_ON
+ MDP_BLOCK_MASTER_OFF = -1,
+ MDP_BLOCK_POWER_OFF = 0,
+ MDP_BLOCK_POWER_ON = 1,
};
enum mdss_mdp_mixer_type {
@@ -118,7 +124,10 @@
u16 height;
u32 dst_format;
+ u32 bus_ab_quota;
+ u32 bus_ib_quota;
u32 bus_quota;
+ u32 clk_rate;
struct msm_fb_data_type *mfd;
struct mdss_mdp_mixer *mixer_left;
@@ -144,8 +153,6 @@
u8 cursor_enabled;
u8 rotator_mode;
- u32 bus_quota;
-
struct mdss_mdp_ctl *ctl;
struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
};
@@ -171,23 +178,8 @@
u8 bpp;
u8 alpha_enable; /* source has alpha */
- /*
- * number of bits for source component,
- * 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
- */
- u8 a_bit; /* component 3, alpha */
- u8 r_bit; /* component 2, R_Cr */
- u8 b_bit; /* component 1, B_Cb */
- u8 g_bit; /* component 0, G_lumz */
-
- /*
- * unpack pattern
- * A = C3, R = C2, B = C1, G = C0
- */
- u8 element3;
- u8 element2;
- u8 element1;
- u8 element0;
+ u8 bits[MAX_PLANES];
+ u8 element[MAX_PLANES];
};
struct mdss_mdp_plane_sizes {
@@ -231,7 +223,6 @@
struct mdss_mdp_format_params *src_fmt;
struct mdss_mdp_plane_sizes src_planes;
- u32 bus_quota;
u8 mixer_stage;
u8 is_fg;
u8 alpha;
@@ -273,7 +264,7 @@
int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
void (*fnc_ptr)(void *), void *arg);
-int mdss_mdp_bus_scale_set_min_quota(u32 quota);
+int mdss_mdp_bus_scale_set_quota(u32 ab_quota, u32 ib_quota);
void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
int mdss_mdp_vsync_clk_enable(int enable);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index c80527d..d29ecd6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -20,122 +20,177 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
+/* 1.10 bus fudge factor */
+#define MDSS_MDP_BUS_FUDGE_FACTOR(val) ALIGN((((val) * 11) / 10), SZ_16M)
+/* 1.25 clock fudge factor */
+#define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
+
enum {
- MDSS_MDP_BUS_UPDATE_SKIP,
- MDSS_MDP_BUS_UPDATE_EARLY,
- MDSS_MDP_BUS_UPDATE_LATE,
+ MDSS_MDP_PERF_UPDATE_SKIP,
+ MDSS_MDP_PERF_UPDATE_EARLY,
+ MDSS_MDP_PERF_UPDATE_LATE,
};
+#define MDSS_MDP_PERF_UPDATE_CLK BIT(0)
+#define MDSS_MDP_PERF_UPDATE_BUS BIT(1)
+#define MDSS_MDP_PERF_UPDATE_ALL -1
+
static DEFINE_MUTEX(mdss_mdp_ctl_lock);
static struct mdss_mdp_ctl mdss_mdp_ctl_list[MDSS_MDP_MAX_CTL];
static struct mdss_mdp_mixer mdss_mdp_mixer_list[MDSS_MDP_MAX_LAYERMIXER];
-static int mdss_mdp_ctl_update_clk_rate(void)
+static int mdss_mdp_ctl_perf_commit(u32 flags)
{
struct mdss_mdp_ctl *ctl;
int cnum;
- unsigned long clk_rate = MDP_CLK_DEFAULT_RATE;
+ unsigned long clk_rate = 0;
+ u32 bus_ab_quota = 0, bus_ib_quota = 0;
+
+ if (!flags) {
+ pr_err("nothing to update\n");
+ return -EINVAL;
+ }
mutex_lock(&mdss_mdp_ctl_lock);
for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
ctl = &mdss_mdp_ctl_list[cnum];
- if (ctl->power_on && ctl->mfd) {
- unsigned long tmp;
- pr_debug("ctl=%d pclk_rate=%u\n", ctl->num,
- ctl->mfd->panel_info.clk_rate);
- tmp = (ctl->mfd->panel_info.clk_rate * 23) / 20;
- if (tmp > clk_rate)
- clk_rate = tmp;
+ if (ctl->power_on) {
+ bus_ab_quota += ctl->bus_ab_quota;
+ bus_ib_quota += ctl->bus_ib_quota;
+
+ if (ctl->clk_rate > clk_rate)
+ clk_rate = ctl->clk_rate;
}
}
- mdss_mdp_set_clk_rate(clk_rate);
- mutex_unlock(&mdss_mdp_ctl_lock);
-
- return 0;
-}
-
-static int mdss_mdp_ctl_update_bus_scale(void)
-{
- struct mdss_mdp_ctl *ctl;
- int cnum;
- u32 bus_quota = 0;
-
- mutex_lock(&mdss_mdp_ctl_lock);
- for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
- ctl = &mdss_mdp_ctl_list[cnum];
- if (ctl->power_on)
- bus_quota += ctl->bus_quota;
+ if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
+ bus_ab_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ab_quota);
+ bus_ib_quota = MDSS_MDP_BUS_FUDGE_FACTOR(bus_ib_quota);
+ mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
}
- mdss_mdp_bus_scale_set_min_quota(bus_quota);
+ if (flags & MDSS_MDP_PERF_UPDATE_CLK) {
+ clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(clk_rate);
+ pr_debug("update clk rate = %lu\n", clk_rate);
+ mdss_mdp_set_clk_rate(clk_rate);
+ }
mutex_unlock(&mdss_mdp_ctl_lock);
return 0;
}
-static void mdss_mdp_bus_update_pipe_quota(struct mdss_mdp_pipe *pipe)
-{
- u32 quota;
-
- quota = pipe->img_width * pipe->img_height * 60 * pipe->src_fmt->bpp;
- quota *= 5 / 4; /* 1.25 factor */
-
- pr_debug("pipe=%d quota old=%u new=%u\n", pipe->num,
- pipe->bus_quota, quota);
- pipe->bus_quota = quota;
-}
-
-static int mdss_mdp_bus_update_mixer_quota(struct mdss_mdp_mixer *mixer)
+static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer,
+ u32 *bus_ab_quota, u32 *bus_ib_quota,
+ u32 *clk_rate)
{
struct mdss_mdp_pipe *pipe;
- u32 quota, stage;
+ const int fps = 60;
+ u32 quota, rate;
+ u32 v_total, v_active;
+ int i;
- if (!mixer)
- return 0;
+ *bus_ab_quota = 0;
+ *bus_ib_quota = 0;
+ *clk_rate = 0;
- quota = 0;
- for (stage = 0; stage < MDSS_MDP_MAX_STAGE; stage++) {
- pipe = mixer->stage_pipe[stage];
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+ struct mdss_panel_info *pinfo = &mixer->ctl->mfd->panel_info;
+ v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
+ pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width);
+ v_active = pinfo->yres;
+ } else if (mixer->rotator_mode) {
+ pipe = mixer->stage_pipe[0]; /* rotator pipe */
+ v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
+ v_active = v_total;
+ } else {
+ v_total = mixer->height;
+ v_active = v_total;
+ }
+
+ for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
+ u32 ib_quota;
+ pipe = mixer->stage_pipe[i];
if (pipe == NULL)
continue;
- quota += pipe->bus_quota;
+ quota = fps * pipe->src.w * pipe->src.h;
+ if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
+ quota = (quota * 3) / 2;
+ else
+ quota *= pipe->src_fmt->bpp;
+
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+ quota = (quota / v_active) * v_total;
+ else
+ quota *= 2; /* bus read + write */
+
+ rate = pipe->dst.w;
+ if (pipe->src.h > pipe->dst.h) {
+ rate = (rate * pipe->src.h) / pipe->dst.h;
+ ib_quota = (quota / pipe->dst.h) * pipe->src.h;
+ } else {
+ ib_quota = quota;
+ }
+ rate *= v_total * fps;
+ if (mixer->rotator_mode)
+ rate /= 4; /* block mode fetch at 4 pix/clk */
+
+ *bus_ab_quota += quota;
+ *bus_ib_quota += ib_quota;
+ if (rate > *clk_rate)
+ *clk_rate = rate;
+
+ pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
+ mixer->num, pipe->num, rate, quota, ib_quota);
}
- pr_debug("mixer=%d quota old=%u new=%u\n", mixer->num,
- mixer->bus_quota, quota);
-
- if (quota != mixer->bus_quota) {
- mixer->bus_quota = quota;
- return 1;
- }
-
- return 0;
+ pr_debug("final mixer=%d clk_rate=%u bus ab=%u ib=%u\n", mixer->num,
+ *clk_rate, *bus_ab_quota, *bus_ib_quota);
}
-static int mdss_mdp_bus_update_ctl_quota(struct mdss_mdp_ctl *ctl)
+static int mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl, u32 *flags)
{
- int ret = MDSS_MDP_BUS_UPDATE_SKIP;
+ int ret = MDSS_MDP_PERF_UPDATE_SKIP;
+ u32 clk_rate, ab_quota, ib_quota;
+ u32 max_clk_rate = 0, total_ab_quota = 0, total_ib_quota = 0;
- if (mdss_mdp_bus_update_mixer_quota(ctl->mixer_left) ||
- mdss_mdp_bus_update_mixer_quota(ctl->mixer_right)) {
- u32 quota = 0;
+ if (ctl->mixer_left) {
+ mdss_mdp_perf_mixer_update(ctl->mixer_left, &ab_quota,
+ &ib_quota, &clk_rate);
+ total_ab_quota += ab_quota;
+ total_ib_quota += ib_quota;
+ max_clk_rate = clk_rate;
+ }
- if (ctl->mixer_left)
- quota += ctl->mixer_left->bus_quota;
- if (ctl->mixer_right)
- quota += ctl->mixer_right->bus_quota;
+ if (ctl->mixer_right) {
+ mdss_mdp_perf_mixer_update(ctl->mixer_right, &ab_quota,
+ &ib_quota, &clk_rate);
+ total_ab_quota += ab_quota;
+ total_ib_quota += ib_quota;
+ if (clk_rate > max_clk_rate)
+ max_clk_rate = clk_rate;
+ }
- pr_debug("ctl=%d quota old=%u new=%u\n",
- ctl->num, ctl->bus_quota, quota);
+ *flags = 0;
- if (quota != ctl->bus_quota) {
- if (quota > ctl->bus_quota)
- ret = MDSS_MDP_BUS_UPDATE_EARLY;
+ if (max_clk_rate != ctl->clk_rate) {
+ if (max_clk_rate > ctl->clk_rate)
+ ret = MDSS_MDP_PERF_UPDATE_EARLY;
+ else
+ ret = MDSS_MDP_PERF_UPDATE_LATE;
+ ctl->clk_rate = max_clk_rate;
+ *flags |= MDSS_MDP_PERF_UPDATE_CLK;
+ }
+
+ if ((total_ab_quota != ctl->bus_ab_quota) ||
+ (total_ib_quota != ctl->bus_ib_quota)) {
+ if (ret == MDSS_MDP_PERF_UPDATE_SKIP) {
+ if (total_ib_quota > ctl->bus_ib_quota)
+ ret = MDSS_MDP_PERF_UPDATE_EARLY;
else
- ret = MDSS_MDP_BUS_UPDATE_LATE;
-
- ctl->bus_quota = quota;
+ ret = MDSS_MDP_PERF_UPDATE_LATE;
}
+ ctl->bus_ab_quota = total_ab_quota;
+ ctl->bus_ib_quota = total_ib_quota;
+ *flags |= MDSS_MDP_PERF_UPDATE_BUS;
}
return ret;
@@ -261,6 +316,7 @@
mixer->ctl = ctl;
ctl->start_fnc = mdss_mdp_writeback_start;
+ ctl->power_on = true;
if (ctl->start_fnc)
ctl->start_fnc(ctl);
@@ -442,7 +498,6 @@
mutex_lock(&ctl->lock);
ctl->power_on = true;
- mdss_mdp_ctl_update_clk_rate();
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (ctl->start_fnc)
@@ -531,8 +586,7 @@
ctl->play_cnt = 0;
- mdss_mdp_ctl_update_bus_scale();
- mdss_mdp_ctl_update_clk_rate();
+ mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
mutex_unlock(&ctl->lock);
@@ -705,7 +759,6 @@
if (params_changed) {
mixer->params_changed++;
mixer->stage_pipe[pipe->mixer_stage] = pipe;
- mdss_mdp_bus_update_pipe_quota(pipe);
}
if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
@@ -764,14 +817,18 @@
{
int mixer1_changed, mixer2_changed;
int ret = 0;
- int bus_update = MDSS_MDP_BUS_UPDATE_SKIP;
+ int perf_update = MDSS_MDP_PERF_UPDATE_SKIP;
+ u32 update_flags = 0;
if (!ctl) {
pr_err("display function not set\n");
return -ENODEV;
}
- pr_debug("commit ctl=%d\n", ctl->num);
+ if (!ctl->power_on)
+ return 0;
+
+ pr_debug("commit ctl=%d play_cnt=%d\n", ctl->num, ctl->play_cnt);
if (mutex_lock_interruptible(&ctl->lock))
return -EINTR;
@@ -781,7 +838,7 @@
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (mixer1_changed || mixer2_changed) {
- bus_update = mdss_mdp_bus_update_ctl_quota(ctl);
+ perf_update = mdss_mdp_ctl_perf_update(ctl, &update_flags);
if (ctl->prepare_fnc)
ret = ctl->prepare_fnc(ctl, arg);
@@ -790,8 +847,8 @@
goto done;
}
- if (bus_update == MDSS_MDP_BUS_UPDATE_EARLY)
- mdss_mdp_ctl_update_bus_scale();
+ if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY)
+ mdss_mdp_ctl_perf_commit(update_flags);
if (mixer1_changed)
mdss_mdp_mixer_update(ctl->mixer_left);
@@ -813,8 +870,8 @@
ctl->play_cnt++;
- if (bus_update == MDSS_MDP_BUS_UPDATE_LATE)
- mdss_mdp_ctl_update_bus_scale();
+ if (perf_update == MDSS_MDP_PERF_UPDATE_LATE)
+ mdss_mdp_ctl_perf_commit(update_flags);
done:
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/msm/mdss/mdss_mdp_formats.h b/drivers/video/msm/mdss/mdss_mdp_formats.h
index 07eefc1..d8ae531 100644
--- a/drivers/video/msm/mdss/mdss_mdp_formats.h
+++ b/drivers/video/msm/mdss/mdss_mdp_formats.h
@@ -18,311 +18,147 @@
#include "mdss_mdp.h"
-#define C3_ALPHA 3 /* alpha */
-#define C2_R_Cr 2 /* R/Cr */
-#define C1_B_Cb 1 /* B/Cb */
-#define C0_G_Y 0 /* G/luma */
+ /*
+ * number of bits for source component,
+ * 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
+ */
+enum {
+ COLOR_4BIT,
+ COLOR_5BIT,
+ COLOR_6BIT,
+ COLOR_8BIT,
+};
-static struct mdss_mdp_format_params mdss_mdp_format_map[MDP_IMGTYPE_LIMIT] = {
- [MDP_RGB_565] = {
- .format = MDP_RGB_565,
+#define FMT_RGB_565(fmt, e0, e1, e2) \
+ { \
+ .format = (fmt), \
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED, \
+ .unpack_tight = 1, \
+ .unpack_align_msb = 0, \
+ .alpha_enable = 0, \
+ .unpack_count = 3, \
+ .bpp = 2, \
+ .element = { (e0), (e1), (e2) }, \
+ .bits = { \
+ [C2_R_Cr] = COLOR_5BIT, \
+ [C0_G_Y] = COLOR_6BIT, \
+ [C1_B_Cb] = COLOR_5BIT, \
+ }, \
+ }
+
+#define FMT_RGB_888(fmt, e0, e1, e2) \
+ { \
+ .format = (fmt), \
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED, \
+ .unpack_tight = 1, \
+ .unpack_align_msb = 0, \
+ .alpha_enable = 0, \
+ .unpack_count = 3, \
+ .bpp = 3, \
+ .element = { (e0), (e1), (e2) }, \
+ .bits = { \
+ [C2_R_Cr] = COLOR_8BIT, \
+ [C0_G_Y] = COLOR_8BIT, \
+ [C1_B_Cb] = COLOR_8BIT, \
+ }, \
+ }
+
+#define FMT_RGB_8888(fmt, alpha_en, e0, e1, e2, e3) \
+ { \
+ .format = (fmt), \
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED, \
+ .unpack_tight = 1, \
+ .unpack_align_msb = 0, \
+ .alpha_enable = (alpha_en), \
+ .unpack_count = 4, \
+ .bpp = 4, \
+ .element = { (e0), (e1), (e2), (e3) }, \
+ .bits = { \
+ [C3_ALPHA] = COLOR_8BIT, \
+ [C2_R_Cr] = COLOR_8BIT, \
+ [C0_G_Y] = COLOR_8BIT, \
+ [C1_B_Cb] = COLOR_8BIT, \
+ }, \
+ }
+
+#define FMT_YUV_COMMON(fmt) \
+ .format = (fmt), \
+ .is_yuv = 1, \
+ .bits = { \
+ [C2_R_Cr] = COLOR_8BIT, \
+ [C0_G_Y] = COLOR_8BIT, \
+ [C1_B_Cb] = COLOR_8BIT, \
+ }, \
+ .alpha_enable = 0, \
+ .unpack_tight = 1, \
+ .unpack_align_msb = 0
+
+#define FMT_YUV_PSEUDO(fmt, samp, e0, e1) \
+ { \
+ FMT_YUV_COMMON(fmt), \
+ .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR, \
+ .chroma_sample = samp, \
+ .unpack_count = 2, \
+ .bpp = 2, \
+ .element = { (e0), (e1) }, \
+ }
+
+#define FMT_YUV_PLANR(fmt, samp, e0, e1) \
+ { \
+ FMT_YUV_COMMON(fmt), \
+ .fetch_planes = MDSS_MDP_PLANE_PLANAR, \
+ .chroma_sample = samp, \
+ .element = { (e0), (e1) } \
+ }
+
+static struct mdss_mdp_format_params mdss_mdp_format_map[] = {
+ FMT_RGB_565(MDP_RGB_565, C1_B_Cb, C0_G_Y, C2_R_Cr),
+ FMT_RGB_565(MDP_BGR_565, C2_R_Cr, C0_G_Y, C1_B_Cb),
+ FMT_RGB_888(MDP_RGB_888, C2_R_Cr, C0_G_Y, C1_B_Cb),
+ FMT_RGB_888(MDP_BGR_888, C1_B_Cb, C0_G_Y, C2_R_Cr),
+
+ FMT_RGB_8888(MDP_XRGB_8888, 0, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
+ FMT_RGB_8888(MDP_ARGB_8888, 1, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
+ FMT_RGB_8888(MDP_RGBA_8888, 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
+ FMT_RGB_8888(MDP_RGBX_8888, 0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
+ FMT_RGB_8888(MDP_BGRA_8888, 1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
+
+ FMT_YUV_PSEUDO(MDP_Y_CRCB_H1V1, MDSS_MDP_CHROMA_RGB, C2_R_Cr, C1_B_Cb),
+ FMT_YUV_PSEUDO(MDP_Y_CBCR_H1V1, MDSS_MDP_CHROMA_RGB, C1_B_Cb, C2_R_Cr),
+ FMT_YUV_PSEUDO(MDP_Y_CRCB_H2V1, MDSS_MDP_CHROMA_H2V1, C2_R_Cr, C1_B_Cb),
+ FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V1, MDSS_MDP_CHROMA_H2V1, C1_B_Cb, C2_R_Cr),
+ FMT_YUV_PSEUDO(MDP_Y_CRCB_H1V2, MDSS_MDP_CHROMA_H1V2, C2_R_Cr, C1_B_Cb),
+ FMT_YUV_PSEUDO(MDP_Y_CBCR_H1V2, MDSS_MDP_CHROMA_H1V2, C1_B_Cb, C2_R_Cr),
+ FMT_YUV_PSEUDO(MDP_Y_CRCB_H2V2, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
+ FMT_YUV_PSEUDO(MDP_Y_CBCR_H2V2, MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
+
+ FMT_YUV_PLANR(MDP_Y_CR_CB_H2V2, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
+ FMT_YUV_PLANR(MDP_Y_CB_CR_H2V2, MDSS_MDP_CHROMA_420, C1_B_Cb, C2_R_Cr),
+ FMT_YUV_PLANR(MDP_Y_CR_CB_GH2V2, MDSS_MDP_CHROMA_420, C2_R_Cr, C1_B_Cb),
+
+ {
+ FMT_YUV_COMMON(MDP_YCBCR_H1V1),
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
- .a_bit = 0,
- .r_bit = 1, /* R, 5 bits */
- .b_bit = 1, /* B, 5 bits */
- .g_bit = 2, /* G, 6 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 2,
- .element2 = C2_R_Cr,
- .element1 = C0_G_Y,
- .element0 = C1_B_Cb,
- .bpp = 1, /* 2 bpp */
- },
- [MDP_BGR_565] = {
- .format = MDP_BGR_565,
- .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
- .a_bit = 0,
- .r_bit = 1, /* R, 5 bits */
- .b_bit = 1, /* B, 5 bits */
- .g_bit = 2, /* G, 6 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 2,
- .element2 = C1_B_Cb,
- .element1 = C0_G_Y,
- .element0 = C2_R_Cr,
- .bpp = 1, /* 2 bpp */
- },
- [MDP_RGB_888] = {
- .format = MDP_RGB_888,
- .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 2,
- .element2 = C1_B_Cb,
- .element1 = C0_G_Y,
- .element0 = C2_R_Cr,
- .bpp = 2, /* 3 bpp */
- },
- [MDP_XRGB_8888] = {
- .format = MDP_XRGB_8888,
- .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
- .a_bit = 3, /* alpha, 4 bits */
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
+ .chroma_sample = MDSS_MDP_CHROMA_RGB,
.unpack_count = 3,
- .element3 = C1_B_Cb,
- .element2 = C0_G_Y,
- .element1 = C2_R_Cr,
- .element0 = C3_ALPHA,
- .bpp = 3, /* 4 bpp */
+ .bpp = 3,
+ .element = { C2_R_Cr, C1_B_Cb, C0_G_Y },
},
- [MDP_ARGB_8888] = {
- .format = MDP_ARGB_8888,
+ {
+ FMT_YUV_COMMON(MDP_YCRCB_H1V1),
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
- .a_bit = 3, /* alpha, 4 bits */
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 1,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
+ .chroma_sample = MDSS_MDP_CHROMA_RGB,
.unpack_count = 3,
- .element3 = C1_B_Cb,
- .element2 = C0_G_Y,
- .element1 = C2_R_Cr,
- .element0 = C3_ALPHA,
- .bpp = 3, /* 4 bpp */
+ .bpp = 3,
+ .element = { C1_B_Cb, C2_R_Cr, C0_G_Y },
},
- [MDP_RGBA_8888] = {
- .format = MDP_RGBA_8888,
- .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
- .a_bit = 3, /* alpha, 4 bits */
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 1,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 3,
- .element3 = C3_ALPHA,
- .element2 = C1_B_Cb,
- .element1 = C0_G_Y,
- .element0 = C2_R_Cr,
- .bpp = 3, /* 4 bpp */
- },
- [MDP_RGBX_8888] = {
- .format = MDP_RGBX_8888,
- .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
- .a_bit = 3,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 3,
- .element3 = C3_ALPHA,
- .element2 = C1_B_Cb,
- .element1 = C0_G_Y,
- .element0 = C2_R_Cr,
- .bpp = 3, /* 4 bpp */
- },
- [MDP_BGRA_8888] = {
- .format = MDP_BGRA_8888,
- .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
- .a_bit = 3, /* alpha, 4 bits */
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 1,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 3,
- .element3 = C3_ALPHA,
- .element2 = C2_R_Cr,
- .element1 = C0_G_Y,
- .element0 = C1_B_Cb,
- .bpp = 3, /* 4 bpp */
- },
- [MDP_YCRYCB_H2V1] = {
- .format = MDP_YCRYCB_H2V1,
- .is_yuv = 1,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 1, /* 2 */
- .bpp = 1, /* 2 bpp */
+ {
+ FMT_YUV_COMMON(MDP_YCRYCB_H2V1),
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
.chroma_sample = MDSS_MDP_CHROMA_H2V1,
- .unpack_count = 3,
- .element3 = C0_G_Y,
- .element2 = C2_R_Cr,
- .element1 = C0_G_Y,
- .element0 = C1_B_Cb,
- },
- [MDP_Y_CRCB_H2V1] = {
- .format = MDP_Y_CRCB_H2V1,
- .is_yuv = 1,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 1, /* 2 */
- .bpp = 1, /* 2 bpp */
- .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
- .chroma_sample = MDSS_MDP_CHROMA_H2V1,
- .element1 = C1_B_Cb,
- .element0 = C2_R_Cr,
- },
- [MDP_Y_CBCR_H2V1] = {
- .format = MDP_Y_CBCR_H2V1,
- .is_yuv = 1,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 1, /* 2 */
- .bpp = 1, /* 2 bpp */
- .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
- .chroma_sample = MDSS_MDP_CHROMA_H2V1,
- .element1 = C2_R_Cr,
- .element0 = C1_B_Cb,
- },
- [MDP_Y_CRCB_H1V2] = {
- .format = MDP_Y_CRCB_H1V2,
- .is_yuv = 1,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 1, /* 2 */
- .bpp = 1, /* 2 bpp */
- .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
- .chroma_sample = MDSS_MDP_CHROMA_H1V2,
- .element1 = C1_B_Cb,
- .element0 = C2_R_Cr,
- },
- [MDP_Y_CBCR_H1V2] = {
- .format = MDP_Y_CBCR_H1V2,
- .is_yuv = 1,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 1, /* 2 */
- .bpp = 1, /* 2 bpp */
- .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
- .chroma_sample = MDSS_MDP_CHROMA_H1V2,
- .element1 = C2_R_Cr,
- .element0 = C1_B_Cb,
- },
- [MDP_Y_CRCB_H2V2] = {
- .format = MDP_Y_CRCB_H2V2,
- .is_yuv = 1,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 1, /* 2 */
- .bpp = 1, /* 2 bpp */
- .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
- .chroma_sample = MDSS_MDP_CHROMA_420,
- .element1 = C1_B_Cb,
- .element0 = C2_R_Cr,
- },
- [MDP_Y_CBCR_H2V2] = {
- .format = MDP_Y_CBCR_H2V2,
- .is_yuv = 1,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 1, /* 2 */
- .bpp = 1, /* 2 bpp */
- .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
- .chroma_sample = MDSS_MDP_CHROMA_420,
- .element1 = C2_R_Cr,
- .element0 = C1_B_Cb,
- },
- [MDP_Y_CR_CB_H2V2] = {
- .format = MDP_Y_CR_CB_H2V2,
- .is_yuv = 1,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 1, /* 2 */
- .bpp = 1, /* 2 bpp */
- .fetch_planes = MDSS_MDP_PLANE_PLANAR,
- .chroma_sample = MDSS_MDP_CHROMA_420,
- },
- [MDP_Y_CB_CR_H2V2] = {
- .format = MDP_Y_CB_CR_H2V2,
- .is_yuv = 1,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 1, /* 2 */
- .bpp = 1, /* 2 bpp */
- .fetch_planes = MDSS_MDP_PLANE_PLANAR,
- .chroma_sample = MDSS_MDP_CHROMA_420,
- },
- [MDP_Y_CR_CB_GH2V2] = {
- .format = MDP_Y_CR_CB_GH2V2,
- .is_yuv = 1,
- .a_bit = 0,
- .r_bit = 3, /* R, 8 bits */
- .b_bit = 3, /* B, 8 bits */
- .g_bit = 3, /* G, 8 bits */
- .alpha_enable = 0,
- .unpack_tight = 1,
- .unpack_align_msb = 0,
- .unpack_count = 1, /* 2 */
- .bpp = 1, /* 2 bpp */
- .fetch_planes = MDSS_MDP_PLANE_PLANAR,
- .chroma_sample = MDSS_MDP_CHROMA_420,
+ .unpack_count = 4,
+ .bpp = 2,
+ .element = { C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y },
},
};
#endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 2f0a1f5..bc64d2e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -304,7 +304,7 @@
itp.h_back_porch = pinfo->lcdc.h_back_porch;
itp.h_front_porch = pinfo->lcdc.h_front_porch;
itp.v_back_porch = pinfo->lcdc.v_back_porch;
- itp.v_front_porch = pinfo->lcdc.h_front_porch;
+ itp.v_front_porch = pinfo->lcdc.v_front_porch;
itp.hsync_pulse_width = pinfo->lcdc.h_pulse_width;
itp.vsync_pulse_width = pinfo->lcdc.v_pulse_width;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index af422b7..8b4434e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -145,20 +145,24 @@
dst_format = (chroma_samp << 23) |
(fmt->fetch_planes << 19) |
- (fmt->unpack_align_msb << 18) |
- (fmt->unpack_tight << 17) |
- (fmt->unpack_count << 12) |
- (fmt->bpp << 9) |
- (fmt->alpha_enable << 8) |
- (fmt->a_bit << 6) |
- (fmt->r_bit << 4) |
- (fmt->b_bit << 2) |
- (fmt->g_bit << 0);
+ (fmt->bits[C3_ALPHA] << 6) |
+ (fmt->bits[C2_R_Cr] << 4) |
+ (fmt->bits[C1_B_Cb] << 2) |
+ (fmt->bits[C0_G_Y] << 0);
- pattern = (fmt->element3 << 24) |
- (fmt->element2 << 15) |
- (fmt->element1 << 8) |
- (fmt->element0 << 0);
+ if (fmt->alpha_enable)
+ dst_format |= BIT(8); /* DSTC3_EN */
+
+ if (fmt->fetch_planes != MDSS_MDP_PLANE_PLANAR) {
+ pattern = (fmt->element[3] << 24) | (fmt->element[2] << 15) |
+ (fmt->element[1] << 8) | (fmt->element[0] << 0);
+ dst_format |= (fmt->unpack_align_msb << 18) |
+ (fmt->unpack_tight << 17) |
+ ((fmt->unpack_count - 1) << 12) |
+ ((fmt->bpp - 1) << 9);
+ } else {
+ pattern = 0;
+ }
ystride0 = (ctx->dst_planes.ystride[0]) |
(ctx->dst_planes.ystride[1] << 16);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 2e9a2dc..d4d889b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
+#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
@@ -48,7 +49,6 @@
struct mdss_mdp_format_params *fmt)
{
u32 xres, yres;
- u32 dst_w, dst_h;
xres = mfd->fbi->var.xres;
yres = mfd->fbi->var.yres;
@@ -61,32 +61,45 @@
if (req->src.width > MAX_IMG_WIDTH ||
req->src.height > MAX_IMG_HEIGHT ||
req->src_rect.w == 0 || req->src_rect.h == 0 ||
- req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
- req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H ||
CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
- CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height) ||
- CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
- CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres)) {
- pr_err("invalid image img_w=%d img_h=%d\n",
- req->src.width, req->src.height);
-
- pr_err("\tsrc_rect=%d,%d,%d,%d dst_rect=%d,%d,%d,%d\n",
+ CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height)) {
+ pr_err("invalid source image img wh=%dx%d rect=%d,%d,%d,%d\n",
+ req->src.width, req->src.height,
req->src_rect.x, req->src_rect.y,
- req->src_rect.w, req->src_rect.h,
- req->dst_rect.x, req->dst_rect.y,
+ req->src_rect.w, req->src_rect.h);
+ return -EOVERFLOW;
+ }
+
+ if (req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
+ req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H) {
+ pr_err("invalid destination resolution (%dx%d)",
req->dst_rect.w, req->dst_rect.h);
- return -EINVAL;
+ return -EOVERFLOW;
}
- if (req->flags & MDP_ROT_90) {
- dst_h = req->dst_rect.w;
- dst_w = req->dst_rect.h;
+ if (req->flags & MDSS_MDP_ROT_ONLY) {
+ /* dst res should match src res in rotation only mode*/
+ req->dst_rect.w = req->src_rect.w;
+ req->dst_rect.h = req->src_rect.h;
} else {
- dst_w = req->dst_rect.w;
- dst_h = req->dst_rect.h;
- }
+ u32 dst_w, dst_h;
- if (!(req->flags & MDSS_MDP_ROT_ONLY)) {
+ if ((CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
+ CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres))) {
+ pr_err("invalid destination rect=%d,%d,%d,%d\n",
+ req->dst_rect.x, req->dst_rect.y,
+ req->dst_rect.w, req->dst_rect.h);
+ return -EOVERFLOW;
+ }
+
+ if (req->flags & MDP_ROT_90) {
+ dst_h = req->dst_rect.w;
+ dst_w = req->dst_rect.h;
+ } else {
+ dst_w = req->dst_rect.w;
+ dst_h = req->dst_rect.h;
+ }
+
if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
pr_err("too much upscaling Width %d->%d\n",
req->src_rect.w, req->dst_rect.w);
@@ -110,6 +123,22 @@
req->src_rect.h, req->dst_rect.h);
return -EINVAL;
}
+
+ if ((fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
+ fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1) &&
+ ((req->src_rect.w * (MAX_UPSCALE_RATIO / 2)) < dst_w)) {
+ pr_err("too much YUV upscaling Width %d->%d\n",
+ req->src_rect.w, req->dst_rect.w);
+ return -EINVAL;
+ }
+
+ if ((fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
+ fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2) &&
+ (req->src_rect.h * (MAX_UPSCALE_RATIO / 2)) < dst_h) {
+ pr_err("too much YUV upscaling Height %d->%d\n",
+ req->src_rect.h, req->dst_rect.h);
+ return -EINVAL;
+ }
}
if (fmt->is_yuv) {
@@ -122,22 +151,6 @@
pr_err("invalid odd dst resolution\n");
return -EINVAL;
}
-
- if (((req->src_rect.w * (MAX_UPSCALE_RATIO / 2)) < dst_w) &&
- (fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
- fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
- pr_err("too much YUV upscaling Width %d->%d\n",
- req->src_rect.w, req->dst_rect.w);
- return -EINVAL;
- }
-
- if (((req->src_rect.h * (MAX_UPSCALE_RATIO / 2)) < dst_h) &&
- (fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
- fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
- pr_err("too much YUV upscaling Height %d->%d\n",
- req->src_rect.h, req->dst_rect.h);
- return -EINVAL;
- }
}
return 0;
@@ -494,24 +507,26 @@
MDSS_MDP_STAGE_BASE);
if (pipe == NULL) {
struct mdp_overlay req;
- int ret;
+ struct fb_info *fbi = mfd->fbi;
+ int ret, bpp;
memset(&req, 0, sizeof(req));
+ bpp = fbi->var.bits_per_pixel / 8;
req.id = MSMFB_NEW_REQUEST;
req.src.format = mfd->fb_imgType;
- req.src.height = mfd->fbi->var.yres;
- req.src.width = mfd->fbi->var.xres;
+ req.src.height = fbi->var.yres;
+ req.src.width = fbi->fix.line_length / bpp;
if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
if (req.src.width <= MAX_MIXER_WIDTH)
return -ENODEV;
req.flags |= MDSS_MDP_RIGHT_MIXER;
req.src_rect.x = MAX_MIXER_WIDTH;
- req.src_rect.w = req.src.width - MAX_MIXER_WIDTH;
+ req.src_rect.w = fbi->var.xres - MAX_MIXER_WIDTH;
} else {
req.src_rect.x = 0;
- req.src_rect.w = MIN(req.src.width, MAX_MIXER_WIDTH);
+ req.src_rect.w = MIN(fbi->var.xres, MAX_MIXER_WIDTH);
}
req.src_rect.y = 0;
@@ -600,15 +615,24 @@
mfd->kickoff_fnc(mfd->ctl);
}
-static int mdss_mdp_hw_cursor_update(struct fb_info *info,
+static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
struct fb_cursor *cursor)
{
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct mdss_mdp_mixer *mixer;
struct fb_image *img = &cursor->image;
- int calpha_en, transp_en, blendcfg, alpha;
+ u32 blendcfg;
int off, ret = 0;
+ if (!mfd->cursor_buf) {
+ mfd->cursor_buf = dma_alloc_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+ (dma_addr_t *) &mfd->cursor_buf_phys,
+ GFP_KERNEL);
+ if (!mfd->cursor_buf) {
+ pr_err("can't allocate cursor buffer\n");
+ return -ENOMEM;
+ }
+ }
+
mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
@@ -628,6 +652,7 @@
(img->dy << 16) | img->dx);
if (cursor->set & FB_CUR_SETIMAGE) {
+ int calpha_en, transp_en, alpha, size;
ret = copy_from_user(mfd->cursor_buf, img->data,
img->width * img->height * 4);
if (ret)
@@ -645,8 +670,9 @@
else
calpha_en = 0x2; /* argb */
- MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_SIZE,
- (img->height << 16) | img->width);
+ size = (img->height << 16) | img->width;
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_IMG_SIZE, size);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_SIZE, size);
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_STRIDE,
img->width * 4);
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BASE_ADDR,
@@ -682,10 +708,13 @@
}
if (!cursor->enable != !(blendcfg & 0x1)) {
- if (cursor->enable)
+ if (cursor->enable) {
+ pr_debug("enable hw cursor on mixer=%d\n", mixer->num);
blendcfg |= 0x1;
- else
+ } else {
+ pr_debug("disable hw cursor on mixer=%d\n", mixer->num);
blendcfg &= ~0x1;
+ }
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG,
blendcfg);
@@ -807,7 +836,6 @@
mfd->on_fnc = mdss_mdp_ctl_on;
mfd->off_fnc = mdss_mdp_ctl_off;
mfd->hw_refresh = true;
- mfd->lut_update = NULL;
mfd->do_histogram = NULL;
mfd->overlay_play_enable = true;
mfd->cursor_update = mdss_mdp_hw_cursor_update;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index d9a148e..c94068a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -363,6 +363,12 @@
}
chroma_sample = pipe->src_fmt->chroma_sample;
+ if (pipe->flags & MDP_SOURCE_ROTATED_90) {
+ if (chroma_sample == MDSS_MDP_CHROMA_H1V2)
+ chroma_sample = MDSS_MDP_CHROMA_H2V1;
+ else if (chroma_sample == MDSS_MDP_CHROMA_H2V1)
+ chroma_sample = MDSS_MDP_CHROMA_H1V2;
+ }
if ((pipe->src.h != pipe->dst.h) ||
(chroma_sample == MDSS_MDP_CHROMA_420) ||
@@ -391,7 +397,7 @@
else
scale_config |= /* G/Y, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
- (MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+ (MDSS_MDP_SCALE_FILTER_PCMN << 18);
if (pipe->src.h <= chr_dst_h)
scale_config |= /* CrCb */
@@ -449,7 +455,7 @@
else
scale_config |= /* G/Y, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
- (MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+ (MDSS_MDP_SCALE_FILTER_PCMN << 16);
if (pipe->src.w <= chr_dst_w)
scale_config |= /* CrCb */
@@ -523,7 +529,7 @@
static int mdss_mdp_format_setup(struct mdss_mdp_pipe *pipe)
{
struct mdss_mdp_format_params *fmt;
- u32 rot90, opmode, chroma_samp;
+ u32 opmode, chroma_samp, unpack, src_format;
fmt = pipe->src_fmt;
@@ -536,8 +542,6 @@
pr_debug("pnum=%d format=%d opmode=%x\n", pipe->num, fmt->format,
opmode);
- rot90 = !!(pipe->flags & MDP_ROT_90);
-
chroma_samp = fmt->chroma_sample;
if (pipe->flags & MDP_SOURCE_ROTATED_90) {
if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
@@ -546,26 +550,34 @@
chroma_samp = MDSS_MDP_CHROMA_H2V1;
}
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT,
- (chroma_samp << 23) |
- (fmt->fetch_planes << 19) |
- (fmt->unpack_align_msb << 18) |
- (fmt->unpack_tight << 17) |
- (fmt->unpack_count << 12) |
- (rot90 << 11) |
- (fmt->bpp << 9) |
- (fmt->alpha_enable << 8) |
- (fmt->a_bit << 6) |
- (fmt->r_bit << 4) |
- (fmt->b_bit << 2) |
- (fmt->g_bit << 0));
+ src_format = (chroma_samp << 23) |
+ (fmt->fetch_planes << 19) |
+ (fmt->bits[C3_ALPHA] << 6) |
+ (fmt->bits[C2_R_Cr] << 4) |
+ (fmt->bits[C1_B_Cb] << 2) |
+ (fmt->bits[C0_G_Y] << 0);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN,
- (fmt->element3 << 24) |
- (fmt->element2 << 16) |
- (fmt->element1 << 8) |
- (fmt->element0 << 0));
+ if (pipe->flags & MDP_ROT_90)
+ src_format |= BIT(11); /* ROT90 */
+ if (fmt->alpha_enable &&
+ fmt->fetch_planes != MDSS_MDP_PLANE_INTERLEAVED)
+ src_format |= BIT(8); /* SRCC3_EN */
+
+ if (fmt->fetch_planes != MDSS_MDP_PLANE_PLANAR) {
+ unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) |
+ (fmt->element[1] << 8) | (fmt->element[0] << 0);
+
+ src_format |= ((fmt->unpack_count - 1) << 12) |
+ (fmt->unpack_tight << 17) |
+ (fmt->unpack_align_msb << 18) |
+ ((fmt->bpp - 1) << 9);
+ } else {
+ unpack = 0;
+ }
+
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, src_format);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN, unpack);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
return 0;
@@ -595,17 +607,23 @@
static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
struct mdss_mdp_data *data)
{
- int ret;
+ int is_rot = pipe->mixer->rotator_mode;
+ int ret = 0;
pr_debug("pnum=%d\n", pipe->num);
- if (pipe->type != MDSS_MDP_PIPE_TYPE_DMA)
+ if (!is_rot)
data->bwc_enabled = pipe->bwc_mode;
ret = mdss_mdp_data_check(data, &pipe->src_planes);
if (ret)
return ret;
+ /* planar format expects YCbCr, swap chroma planes if YCrCb */
+ if (!is_rot && (pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_PLANAR) &&
+ (pipe->src_fmt->element[0] == C2_R_Cr))
+ swap(data->p[1].addr, data->p[2].addr);
+
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data->p[0].addr);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data->p[1].addr);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data->p[2].addr);
@@ -630,7 +648,8 @@
return -ENODEV;
}
- pr_debug("pnum=%x mixer=%d\n", pipe->num, pipe->mixer->num);
+ pr_debug("pnum=%x mixer=%d play_cnt=%u\n", pipe->num,
+ pipe->mixer->num, pipe->play_cnt);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index f6b4fce..7f61a14 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -164,14 +164,16 @@
struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format)
{
- struct mdss_mdp_format_params *fmt = NULL;
if (format < MDP_IMGTYPE_LIMIT) {
- fmt = &mdss_mdp_format_map[format];
- if (fmt->format != format)
- fmt = NULL;
+ struct mdss_mdp_format_params *fmt = NULL;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(mdss_mdp_format_map); i++) {
+ fmt = &mdss_mdp_format_map[i];
+ if (format == fmt->format)
+ return fmt;
+ }
}
-
- return fmt;
+ return NULL;
}
int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
@@ -193,7 +195,7 @@
memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
- u32 bpp = fmt->bpp + 1;
+ u32 bpp = fmt->bpp;
ps->num_planes = 1;
ps->plane_size[0] = w * h * bpp;
ps->ystride[0] = w * bpp;
@@ -206,16 +208,14 @@
vert = vmap[fmt->chroma_sample];
if (format == MDP_Y_CR_CB_GH2V2) {
- ps->plane_size[0] = ALIGN(w, 16) * h;
- ps->plane_size[1] = ALIGN(w / horiz, 16) * (h / vert);
ps->ystride[0] = ALIGN(w, 16);
ps->ystride[1] = ALIGN(w / horiz, 16);
} else {
- ps->plane_size[0] = w * h;
- ps->plane_size[1] = (w / horiz) * (h / vert);
ps->ystride[0] = w;
ps->ystride[1] = (w / horiz);
}
+ ps->plane_size[0] = ps->ystride[0] * h;
+ ps->plane_size[1] = ps->ystride[1] * (h / vert);
if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
ps->num_planes = 2;
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 3ec3a5d..5d23548 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -83,6 +83,18 @@
u32 yres_pad;
};
+
+/* DSI PHY configuration */
+struct mdss_dsi_phy_ctrl {
+ uint32_t regulator[8];
+ uint32_t timing[12];
+ uint32_t ctrl[4];
+ uint32_t strength[2];
+ char bistCtrl[6];
+ uint32_t pll[21];
+ char laneCfg[45];
+};
+
struct mipi_panel_info {
char mode; /* video/cmd */
char interleave_mode;
@@ -103,7 +115,7 @@
char t_clk_post; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
char t_clk_pre; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
char vc; /* virtual channel */
- struct mipi_dsi_phy_ctrl *dsi_phy_db;
+ struct mdss_dsi_phy_ctrl *dsi_phy_db;
/* video mode */
char pulse_mode_hsa_he;
char hfp_power_stop;
@@ -168,6 +180,7 @@
struct mdss_panel_info panel_info;
void (*set_backlight) (u32 bl_level);
unsigned char *dsi_base;
+ unsigned char *mmss_cc_base;
/* function entry chain */
int (*on) (struct mdss_panel_data *pdata);
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index c766ec7..9d9a366 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -12,6 +12,7 @@
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
@@ -26,8 +27,9 @@
static struct dsi_clk_desc dsi_pclk;
-static struct clk *dsi_byte_div_clk;
+static struct clk *dsi_byte_clk;
static struct clk *dsi_esc_clk;
+static struct clk *dsi_pixel_clk;
int mdss_dsi_clk_on;
@@ -35,16 +37,23 @@
{
struct device *dev = &pdev->dev;
- dsi_byte_div_clk = clk_get(dev, "byte_clk");
- if (IS_ERR(dsi_byte_div_clk)) {
- pr_err("can't find dsi_byte_div_clk\n");
- dsi_byte_div_clk = NULL;
+ dsi_byte_clk = clk_get(dev, "byte_clk");
+ if (IS_ERR(dsi_byte_clk)) {
+ pr_err("can't find dsi_byte_clk\n");
+ dsi_byte_clk = NULL;
+ goto mdss_dsi_clk_err;
+ }
+
+ dsi_pixel_clk = clk_get(dev, "pixel_clk");
+ if (IS_ERR(dsi_pixel_clk)) {
+ pr_err("can't find dsi_pixel_clk\n");
+ dsi_pixel_clk = NULL;
goto mdss_dsi_clk_err;
}
dsi_esc_clk = clk_get(dev, "core_clk");
if (IS_ERR(dsi_esc_clk)) {
- printk(KERN_ERR "can't find dsi_esc_clk\n");
+ pr_err("can't find dsi_esc_clk\n");
dsi_esc_clk = NULL;
goto mdss_dsi_clk_err;
}
@@ -58,10 +67,12 @@
void mdss_dsi_clk_deinit(struct device *dev)
{
- if (dsi_byte_div_clk)
- clk_put(dsi_byte_div_clk);
+ if (dsi_byte_clk)
+ clk_put(dsi_byte_clk);
if (dsi_esc_clk)
clk_put(dsi_esc_clk);
+ if (dsi_pixel_clk)
+ clk_put(dsi_pixel_clk);
}
#define PREF_DIV_RATIO 27
@@ -143,57 +154,145 @@
return 0;
}
-void cont_splash_clk_ctrl(int enable)
-{
- static int cont_splash_clks_enabled;
- if (enable && !cont_splash_clks_enabled) {
- clk_prepare_enable(dsi_byte_div_clk);
- clk_prepare_enable(dsi_esc_clk);
- cont_splash_clks_enabled = 1;
- } else if (!enable && cont_splash_clks_enabled) {
- clk_disable_unprepare(dsi_byte_div_clk);
- clk_disable_unprepare(dsi_esc_clk);
- cont_splash_clks_enabled = 0;
- }
-}
-
void mdss_dsi_prepare_clocks(void)
{
- clk_prepare(dsi_byte_div_clk);
+ clk_prepare(dsi_byte_clk);
clk_prepare(dsi_esc_clk);
+ clk_prepare(dsi_pixel_clk);
}
void mdss_dsi_unprepare_clocks(void)
{
clk_unprepare(dsi_esc_clk);
- clk_unprepare(dsi_byte_div_clk);
+ clk_unprepare(dsi_pixel_clk);
+ clk_unprepare(dsi_byte_clk);
}
-void mdss_dsi_clk_enable(void)
+void mdss_dsi_clk_enable(struct mdss_panel_data *pdata)
{
if (mdss_dsi_clk_on) {
pr_info("%s: mdss_dsi_clks already ON\n", __func__);
return;
}
- if (clk_set_rate(dsi_byte_div_clk, 1) < 0) /* divided by 1 */
- pr_err("%s: dsi_byte_div_clk - clk_set_rate failed\n",
- __func__);
- if (clk_set_rate(dsi_esc_clk, 2) < 0) /* divided by 2 */
+ if (clk_set_rate(dsi_esc_clk, 19200000) < 0)
pr_err("%s: dsi_esc_clk - clk_set_rate failed\n",
__func__);
- clk_enable(dsi_byte_div_clk);
+
+ if (clk_set_rate(dsi_byte_clk, 53000000) < 0)
+ pr_err("%s: dsi_byte_clk - clk_set_rate failed\n",
+ __func__);
+
+ if (clk_set_rate(dsi_pixel_clk, 70000000) < 0)
+ pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n",
+ __func__);
+
clk_enable(dsi_esc_clk);
+ clk_enable(dsi_byte_clk);
+ clk_enable(dsi_pixel_clk);
+
mdss_dsi_clk_on = 1;
}
-void mdss_dsi_clk_disable(void)
+void mdss_dsi_clk_disable(struct mdss_panel_data *pdata)
{
if (mdss_dsi_clk_on == 0) {
pr_info("%s: mdss_dsi_clks already OFF\n", __func__);
return;
}
+
+ clk_disable(dsi_pixel_clk);
+ clk_disable(dsi_byte_clk);
clk_disable(dsi_esc_clk);
- clk_disable(dsi_byte_div_clk);
+
mdss_dsi_clk_on = 0;
}
+
+void mdss_dsi_phy_sw_reset(struct mdss_panel_data *pdata)
+{
+ /* start phy sw reset */
+ MIPI_OUTP((pdata->dsi_base) + 0x12c, 0x0001);
+ wmb();
+ usleep(1);
+ /* end phy sw reset */
+ MIPI_OUTP((pdata->dsi_base) + 0x12c, 0x0000);
+ wmb();
+ usleep(1);
+}
+
+void mdss_dsi_phy_enable(struct mdss_panel_data *pdata, int on)
+{
+ if (on) {
+ MIPI_OUTP((pdata->dsi_base) + 0x0220, 0x006);
+ usleep(10);
+ MIPI_OUTP((pdata->dsi_base) + 0x0268, 0x001);
+ usleep(10);
+ MIPI_OUTP((pdata->dsi_base) + 0x0268, 0x000);
+ usleep(10);
+ MIPI_OUTP((pdata->dsi_base) + 0x0220, 0x007);
+ wmb();
+
+ /* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
+ MIPI_OUTP((pdata->dsi_base) + 0x0470, 0x07e);
+ MIPI_OUTP((pdata->dsi_base) + 0x0470, 0x06e);
+ MIPI_OUTP((pdata->dsi_base) + 0x0470, 0x06c);
+ MIPI_OUTP((pdata->dsi_base) + 0x0470, 0x064);
+ MIPI_OUTP((pdata->dsi_base) + 0x0470, 0x065);
+ MIPI_OUTP((pdata->dsi_base) + 0x0470, 0x075);
+ MIPI_OUTP((pdata->dsi_base) + 0x0470, 0x077);
+ MIPI_OUTP((pdata->dsi_base) + 0x0470, 0x07f);
+ wmb();
+
+ } else {
+ MIPI_OUTP((pdata->dsi_base) + 0x0220, 0x006);
+ usleep(10);
+ MIPI_OUTP((pdata->dsi_base) + 0x0470, 0x000);
+ wmb();
+ }
+}
+
+void mdss_dsi_phy_init(struct mdss_panel_data *pdata)
+{
+ struct mdss_dsi_phy_ctrl *pd;
+ int i, off, ln, offset;
+
+ pd = (pdata->panel_info.mipi).dsi_phy_db;
+
+ off = 0x0580; /* phy regulator ctrl settings */
+ for (i = 0; i < 8; i++) {
+ MIPI_OUTP((pdata->dsi_base) + off, pd->regulator[i]);
+ wmb();
+ off += 4;
+ }
+
+ off = 0x0440; /* phy timing ctrl 0 - 11 */
+ for (i = 0; i < 12; i++) {
+ MIPI_OUTP((pdata->dsi_base) + off, pd->timing[i]);
+ wmb();
+ off += 4;
+ }
+
+ /* Strength ctrl 0 - 1 */
+ MIPI_OUTP((pdata->dsi_base) + 0x0484, pd->strength[0]);
+ MIPI_OUTP((pdata->dsi_base) + 0x0488, pd->strength[1]);
+ wmb();
+
+ off = 0x04b4; /* phy BIST ctrl 0 - 5 */
+ for (i = 0; i < 6; i++) {
+ MIPI_OUTP((pdata->dsi_base) + off, pd->bistCtrl[i]);
+ wmb();
+ off += 4;
+ }
+
+ /* 4 lanes + clk lane configuration */
+ /* lane config n * (0 - 4) & DataPath setup */
+ for (ln = 0; ln < 5; ln++) {
+ off = 0x0300 + (ln * 0x40);
+ for (i = 0; i < 9; i++) {
+ offset = i + (ln * 9);
+ MIPI_OUTP((pdata->dsi_base) + off, pd->laneCfg[offset]);
+ wmb();
+ off += 4;
+ }
+ }
+}
diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c
index 646dd29..4347dc7 100644
--- a/drivers/video/msm/mhl/mhl_8334.c
+++ b/drivers/video/msm/mhl/mhl_8334.c
@@ -224,12 +224,6 @@
return 0;
}
-bool mhl_is_connected(void)
-{
- return true;
-}
-
-
/* USB_HANDSHAKING FUNCTIONS */
int mhl_device_discovery(const char *name, int *result)
@@ -547,6 +541,11 @@
pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
mhl_msm_state->mhl_data->irq);
+ if (!mhl_msm_state->mhl_data->mhl_enabled) {
+ pr_info("MHL Display not enabled\n");
+ return -ENODEV;
+ }
+
/* Init GPIO stuff here */
ret = mhl_sii_gpio_setup(1);
if (ret == -1) {
diff --git a/drivers/video/msm/mhl_api.h b/drivers/video/msm/mhl_api.h
index a4364ea..7fdbaa9 100644
--- a/drivers/video/msm/mhl_api.h
+++ b/drivers/video/msm/mhl_api.h
@@ -15,9 +15,9 @@
#define __MHL_API_H__
#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
-bool mhl_is_connected(void);
+bool mhl_is_enabled(void);
#else
-static bool mhl_is_connected(void)
+static bool mhl_is_enabled(void)
{
return false;
}
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index ebbf362..2f691cf 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -117,6 +117,9 @@
#define DSI_INTR_CMD_DMA_DONE_MASK BIT(1)
#define DSI_INTR_CMD_DMA_DONE BIT(0)
+#define DSI_MDP_TERM BIT(8)
+#define DSI_CMD_TERM BIT(0)
+
#define DSI_CMD_TRIGGER_NONE 0x0 /* mdp trigger */
#define DSI_CMD_TRIGGER_TE 0x02
#define DSI_CMD_TRIGGER_SW 0x04
@@ -185,8 +188,8 @@
#define DSI_HDR_DATA1(data) ((data) & 0x0ff)
#define DSI_HDR_WC(wc) ((wc) & 0x0ffff)
-#define DSI_BUF_SIZE 1024
-#define MIPI_DSI_MRPS 0x04 /* Maximum Return Packet Size */
+#define DSI_BUF_SIZE 64
+#define MIPI_DSI_MRPS 0x04 /* Maximum Return Packet Size */
#define MIPI_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align */
@@ -247,7 +250,6 @@
char *payload;
};
-
typedef void (*kickoff_act)(void *);
struct dsi_kickoff_action {
@@ -257,6 +259,30 @@
};
+#define CMD_REQ_MAX 4
+
+typedef void (*fxn)(u32 data);
+
+#define CMD_REQ_RX 0x0001
+#define CMD_REQ_COMMIT 0x0002
+#define CMD_REQ_NO_MAX_PKT_SIZE 0x0008
+
+struct dcs_cmd_req {
+ struct dsi_cmd_desc *cmds;
+ int cmds_cnt;
+ u32 flags;
+ int rlen; /* rx length */
+ fxn cb;
+};
+
+struct dcs_cmd_list {
+ int put;
+ int get;
+ int tot;
+ struct dcs_cmd_req list[CMD_REQ_MAX];
+};
+
+
char *mipi_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen);
char *mipi_dsi_buf_init(struct dsi_buf *dp);
void mipi_dsi_init(void);
@@ -284,7 +310,7 @@
void mipi_dsi_set_tear_on(struct msm_fb_data_type *mfd);
void mipi_dsi_set_tear_off(struct msm_fb_data_type *mfd);
void mipi_dsi_set_backlight(struct msm_fb_data_type *mfd, int level);
-void mipi_dsi_cmd_backlight_tx(int level);
+void mipi_dsi_cmd_backlight_tx(struct dsi_buf *dp);
void mipi_dsi_clk_enable(void);
void mipi_dsi_clk_disable(void);
void mipi_dsi_pre_kickoff_action(void);
@@ -315,6 +341,10 @@
void mipi_dsi_turn_off_clks(void);
void mipi_dsi_clk_cfg(int on);
+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);
+
#ifdef CONFIG_FB_MSM_MDP303
void update_lane_config(struct msm_panel_info *pinfo);
#endif
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 39e2d6d..39a071b 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -42,12 +42,13 @@
static struct completion dsi_dma_comp;
static struct completion dsi_mdp_comp;
static struct dsi_buf dsi_tx_buf;
-static int dsi_irq_enabled;
+static struct dsi_buf dsi_rx_buf;
static spinlock_t dsi_irq_lock;
static spinlock_t dsi_mdp_lock;
spinlock_t dsi_clk_lock;
static int dsi_ctrl_lock;
static int dsi_mdp_busy;
+static struct mutex cmd_mutex;
static struct list_head pre_kickoff_list;
static struct list_head post_kickoff_list;
@@ -59,6 +60,8 @@
STAT_DSI_MDP
};
+struct dcs_cmd_list cmdlist;
+
#ifdef CONFIG_FB_MSM_MDP40
void mipi_dsi_mdp_stat_inc(int which)
{
@@ -90,42 +93,52 @@
init_completion(&dsi_dma_comp);
init_completion(&dsi_mdp_comp);
mipi_dsi_buf_alloc(&dsi_tx_buf, DSI_BUF_SIZE);
+ mipi_dsi_buf_alloc(&dsi_rx_buf, DSI_BUF_SIZE);
spin_lock_init(&dsi_irq_lock);
spin_lock_init(&dsi_mdp_lock);
spin_lock_init(&dsi_clk_lock);
+ mutex_init(&cmd_mutex);
INIT_LIST_HEAD(&pre_kickoff_list);
INIT_LIST_HEAD(&post_kickoff_list);
}
-void mipi_dsi_enable_irq(void)
+
+static u32 dsi_irq_mask;
+
+void mipi_dsi_enable_irq(u32 term)
{
unsigned long flags;
spin_lock_irqsave(&dsi_irq_lock, flags);
- if (dsi_irq_enabled) {
- pr_debug("%s: IRQ aleady enabled\n", __func__);
+ if (dsi_irq_mask & term) {
spin_unlock_irqrestore(&dsi_irq_lock, flags);
return;
}
- dsi_irq_enabled = 1;
- enable_irq(dsi_irq);
+ if (dsi_irq_mask == 0) {
+ enable_irq(dsi_irq);
+ pr_debug("%s: IRQ Enable, mask=%x term=%x\n",
+ __func__, (int)dsi_irq_mask, (int)term);
+ }
+ dsi_irq_mask |= term;
spin_unlock_irqrestore(&dsi_irq_lock, flags);
}
-void mipi_dsi_disable_irq(void)
+void mipi_dsi_disable_irq(u32 term)
{
unsigned long flags;
spin_lock_irqsave(&dsi_irq_lock, flags);
- if (dsi_irq_enabled == 0) {
- pr_debug("%s: IRQ already disabled\n", __func__);
+ if (!(dsi_irq_mask & term)) {
spin_unlock_irqrestore(&dsi_irq_lock, flags);
return;
}
-
- dsi_irq_enabled = 0;
- disable_irq(dsi_irq);
+ dsi_irq_mask &= ~term;
+ if (dsi_irq_mask == 0) {
+ disable_irq(dsi_irq);
+ pr_debug("%s: IRQ Disable, mask=%x term=%x\n",
+ __func__, (int)dsi_irq_mask, (int)term);
+ }
spin_unlock_irqrestore(&dsi_irq_lock, flags);
}
@@ -133,17 +146,19 @@
* mipi_dsi_disale_irq_nosync() should be called
* from interrupt context
*/
- void mipi_dsi_disable_irq_nosync(void)
+void mipi_dsi_disable_irq_nosync(u32 term)
{
spin_lock(&dsi_irq_lock);
- if (dsi_irq_enabled == 0) {
- pr_debug("%s: IRQ cannot be disabled\n", __func__);
+ if (!(dsi_irq_mask & term)) {
spin_unlock(&dsi_irq_lock);
return;
}
-
- dsi_irq_enabled = 0;
- disable_irq_nosync(dsi_irq);
+ dsi_irq_mask &= ~term;
+ if (dsi_irq_mask == 0) {
+ disable_irq_nosync(dsi_irq);
+ pr_debug("%s: IRQ Disable, mask=%x term=%x\n",
+ __func__, (int)dsi_irq_mask, (int)term);
+ }
spin_unlock(&dsi_irq_lock);
}
@@ -1007,27 +1022,6 @@
wmb();
}
-int mipi_dsi_ctrl_lock(int mdp)
-{
- unsigned long flag;
- int lock = 0;
-
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- if (dsi_ctrl_lock == FALSE) {
- dsi_ctrl_lock = TRUE;
- lock = 1;
- if (lock && mdp) /* mdp pixel */
- mipi_dsi_enable_irq();
- }
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
- return lock;
-}
-
-int mipi_dsi_ctrl_lock_query()
-{
- return dsi_ctrl_lock;
-}
-
void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd)
{
unsigned long flag;
@@ -1060,7 +1054,7 @@
mipi_dsi_mdp_stat_inc(STAT_DSI_START);
spin_lock_irqsave(&dsi_mdp_lock, flag);
- mipi_dsi_enable_irq();
+ mipi_dsi_enable_irq(DSI_MDP_TERM);
dsi_mdp_busy = TRUE;
spin_unlock_irqrestore(&dsi_mdp_lock, flag);
}
@@ -1134,51 +1128,6 @@
return 4;
}
-static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */
-
-static struct dsi_cmd_desc backlight_cmd = {
- DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
-
-/*
- * mipi_dsi_cmd_backlight_tx:
- * thread context only
- */
-void mipi_dsi_cmd_backlight_tx(int level)
-{
- struct dsi_buf *tp;
- struct dsi_cmd_desc *cmd;
- unsigned long flag;
-
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = TRUE;
- led_pwm1[1] = (unsigned char)(level);
- tp = &dsi_tx_buf;
- cmd = &backlight_cmd;
- mipi_dsi_buf_init(&dsi_tx_buf);
-
- if (tp->dmap) {
- dma_unmap_single(&dsi_dev, tp->dmap, tp->len, DMA_TO_DEVICE);
- tp->dmap = 0;
- }
-
- mipi_dsi_enable_irq();
- mipi_dsi_cmd_dma_add(tp, cmd);
-
- tp->len += 3;
- tp->len &= ~0x03; /* multipled by 4 */
-
- tp->dmap = dma_map_single(&dsi_dev, tp->data, tp->len, DMA_TO_DEVICE);
- if (dma_mapping_error(&dsi_dev, tp->dmap))
- pr_err("%s: dmap mapp failed\n", __func__);
-
- MIPI_OUTP(MIPI_DSI_BASE + 0x044, tp->dmap);
- MIPI_OUTP(MIPI_DSI_BASE + 0x048, tp->len);
- wmb();
- MIPI_OUTP(MIPI_DSI_BASE + 0x08c, 0x01); /* trigger */
- wmb();
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-}
-
/*
* mipi_dsi_cmds_tx:
* thread context only
@@ -1209,7 +1158,7 @@
cm = cmds;
mipi_dsi_buf_init(tp);
for (i = 0; i < cnt; i++) {
- mipi_dsi_enable_irq();
+ mipi_dsi_enable_irq(DSI_CMD_TERM);
mipi_dsi_buf_init(tp);
mipi_dsi_cmd_dma_add(tp, cm);
mipi_dsi_cmd_dma_tx(tp);
@@ -1300,20 +1249,20 @@
/* packet size need to be set at every read */
pkt_size = len;
max_pktsize[0] = pkt_size;
- mipi_dsi_enable_irq();
+ mipi_dsi_enable_irq(DSI_CMD_TERM);
mipi_dsi_buf_init(tp);
mipi_dsi_cmd_dma_add(tp, pkt_size_cmd);
mipi_dsi_cmd_dma_tx(tp);
}
- mipi_dsi_enable_irq();
+ mipi_dsi_enable_irq(DSI_CMD_TERM);
mipi_dsi_buf_init(tp);
mipi_dsi_cmd_dma_add(tp, cmds);
/* transmit read comamnd to client */
mipi_dsi_cmd_dma_tx(tp);
- mipi_dsi_disable_irq();
+ mipi_dsi_disable_irq(DSI_CMD_TERM);
/*
* once cmd_dma_done interrupt received,
* return data from client is ready and stored
@@ -1372,6 +1321,126 @@
return rp->len;
}
+int mipi_dsi_cmds_rx_new(struct dsi_buf *tp, struct dsi_buf *rp,
+ struct dcs_cmd_req *req, int rlen)
+{
+ struct dsi_cmd_desc *cmds;
+ int cnt, len, diff, pkt_size;
+ char cmd;
+ unsigned long flag;
+
+ if (req->flags & CMD_REQ_NO_MAX_PKT_SIZE) {
+ /* Only support rlen = 4*n */
+ rlen += 3;
+ rlen &= ~0x03;
+ }
+
+ cmds = req->cmds;
+
+ len = rlen;
+ diff = 0;
+
+ if (len <= 2)
+ cnt = 4; /* short read */
+ else {
+ if (len > MIPI_DSI_LEN)
+ len = MIPI_DSI_LEN; /* 8 bytes at most */
+
+ len = (len + 3) & ~0x03; /* len 4 bytes align */
+ diff = len - rlen;
+ /*
+ * add extra 2 bytes to len to have overall
+ * packet size is multipe by 4. This also make
+ * sure 4 bytes dcs headerlocates within a
+ * 32 bits register after shift in.
+ * after all, len should be either 6 or 10.
+ */
+ len += 2;
+ cnt = len + 6; /* 4 bytes header + 2 bytes crc */
+ }
+
+ spin_lock_irqsave(&dsi_mdp_lock, flag);
+ dsi_mdp_busy = TRUE;
+ spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+ if (!(req->flags & CMD_REQ_NO_MAX_PKT_SIZE)) {
+
+
+ /* packet size need to be set at every read */
+ pkt_size = len;
+ max_pktsize[0] = pkt_size;
+ mipi_dsi_enable_irq(DSI_CMD_TERM);
+ mipi_dsi_buf_init(tp);
+ mipi_dsi_cmd_dma_add(tp, pkt_size_cmd);
+ mipi_dsi_cmd_dma_tx(tp);
+ }
+
+ mipi_dsi_enable_irq(DSI_CMD_TERM);
+ mipi_dsi_buf_init(tp);
+ mipi_dsi_cmd_dma_add(tp, cmds);
+
+ /* transmit read comamnd to client */
+ mipi_dsi_cmd_dma_tx(tp);
+
+ mipi_dsi_disable_irq(DSI_CMD_TERM);
+ /*
+ * once cmd_dma_done interrupt received,
+ * return data from client is ready and stored
+ * at RDBK_DATA register already
+ */
+ mipi_dsi_buf_init(rp);
+ if (req->flags & CMD_REQ_NO_MAX_PKT_SIZE) {
+ /*
+ * expect rlen = n * 4
+ * short alignement for start addr
+ */
+ rp->data += 2;
+ }
+
+ mipi_dsi_cmd_dma_rx(rp, cnt);
+
+ spin_lock_irqsave(&dsi_mdp_lock, flag);
+ dsi_mdp_busy = FALSE;
+ complete(&dsi_mdp_comp);
+ spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+
+ if (req->flags & CMD_REQ_NO_MAX_PKT_SIZE) {
+ /*
+ * remove extra 2 bytes from previous
+ * rx transaction at shift register
+ * which was inserted during copy
+ * shift registers to rx buffer
+ * rx payload start from long alignment addr
+ */
+ rp->data += 2;
+ }
+
+ cmd = rp->data[0];
+ switch (cmd) {
+ case DTYPE_ACK_ERR_RESP:
+ pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__);
+ break;
+ case DTYPE_GEN_READ1_RESP:
+ case DTYPE_DCS_READ1_RESP:
+ mipi_dsi_short_read1_resp(rp);
+ break;
+ case DTYPE_GEN_READ2_RESP:
+ case DTYPE_DCS_READ2_RESP:
+ mipi_dsi_short_read2_resp(rp);
+ break;
+ case DTYPE_GEN_LREAD_RESP:
+ case DTYPE_DCS_LREAD_RESP:
+ mipi_dsi_long_read_resp(rp);
+ rp->len -= 2; /* extra 2 bytes added */
+ rp->len -= diff; /* align bytes */
+ break;
+ default:
+ break;
+ }
+
+ return rp->len;
+}
+
int mipi_dsi_cmd_dma_tx(struct dsi_buf *tp)
{
@@ -1390,6 +1459,11 @@
pr_debug("\n");
#endif
+ if (tp->len == 0) {
+ pr_err("%s: Error, len=0\n", __func__);
+ return 0;
+ }
+
spin_lock_irqsave(&dsi_mdp_lock, flags);
tp->len += 3;
tp->len &= ~0x03; /* multipled by 4 */
@@ -1441,6 +1515,134 @@
return rlen;
}
+void mipi_dsi_cmd_mdp_busy(void)
+{
+ u32 status;
+ unsigned long flags;
+ int need_wait;
+
+ spin_lock_irqsave(&dsi_mdp_lock, flags);
+ status = MIPI_INP(MIPI_DSI_BASE + 0x0004);/* DSI_STATUS */
+ if (status & 0x04) { /* MDP BUSY */
+ INIT_COMPLETION(dsi_mdp_comp);
+ need_wait = 1;
+ pr_debug("%s: status=%x need_wait\n", __func__, (int)status);
+ mipi_dsi_enable_irq(DSI_MDP_TERM);
+ }
+ spin_unlock_irqrestore(&dsi_mdp_lock, flags);
+
+ if (need_wait)
+ wait_for_completion(&dsi_mdp_comp);
+}
+
+/*
+ * mipi_dsi_cmd_get: cmd_mutex acquired by caller
+ */
+struct dcs_cmd_req *mipi_dsi_cmdlist_get(void)
+{
+ struct dcs_cmd_req *req = NULL;
+
+ if (cmdlist.get != cmdlist.put) {
+ req = &cmdlist.list[cmdlist.get];
+ cmdlist.get++;
+ cmdlist.get %= CMD_REQ_MAX;
+ cmdlist.tot--;
+ pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+ cmdlist.tot, cmdlist.put, cmdlist.get);
+ }
+ return req;
+}
+void mipi_dsi_cmdlist_tx(struct dcs_cmd_req *req)
+{
+ struct dsi_buf *tp;
+ int ret;
+
+ mipi_dsi_buf_init(&dsi_tx_buf);
+ tp = &dsi_tx_buf;
+ ret = mipi_dsi_cmds_tx(tp, req->cmds, req->cmds_cnt);
+
+ if (req->cb)
+ req->cb(ret);
+
+}
+
+void mipi_dsi_cmdlist_rx(struct dcs_cmd_req *req)
+{
+ int len;
+ u32 *dp;
+ struct dsi_buf *tp;
+ struct dsi_buf *rp;
+
+ mipi_dsi_buf_init(&dsi_tx_buf);
+ mipi_dsi_buf_init(&dsi_rx_buf);
+
+ tp = &dsi_tx_buf;
+ rp = &dsi_rx_buf;
+
+ len = mipi_dsi_cmds_rx_new(tp, rp, req, req->rlen);
+ dp = (u32 *)rp->data;
+
+ if (req->cb)
+ req->cb(*dp);
+}
+
+void mipi_dsi_cmdlist_commit(int from_mdp)
+{
+ struct dcs_cmd_req *req;
+
+ mutex_lock(&cmd_mutex);
+ req = mipi_dsi_cmdlist_get();
+ if (req == NULL) {
+ mutex_unlock(&cmd_mutex);
+ return;
+ }
+
+ pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
+
+ if (!from_mdp) { /* from put */
+ /* make sure dsi_cmd_mdp is idle */
+ mipi_dsi_cmd_mdp_busy();
+ }
+
+ if (req->flags && CMD_REQ_RX)
+ mipi_dsi_cmdlist_rx(req);
+ else
+ mipi_dsi_cmdlist_tx(req);
+
+ mutex_unlock(&cmd_mutex);
+}
+
+int mipi_dsi_cmdlist_put(struct dcs_cmd_req *cmdreq)
+{
+ struct dcs_cmd_req *req;
+ int ret = 0;
+
+ mutex_lock(&cmd_mutex);
+ req = &cmdlist.list[cmdlist.put];
+ *req = *cmdreq;
+ cmdlist.put++;
+ cmdlist.put %= CMD_REQ_MAX;
+ cmdlist.tot++;
+ if (cmdlist.put == cmdlist.get) {
+ /* drop the oldest one */
+ pr_debug("%s: DROP, tot=%d put=%d get=%d\n", __func__,
+ cmdlist.tot, cmdlist.put, cmdlist.get);
+ cmdlist.get++;
+ cmdlist.get %= CMD_REQ_MAX;
+ cmdlist.tot--;
+ }
+ mutex_unlock(&cmd_mutex);
+
+ ret++;
+ pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+ cmdlist.tot, cmdlist.put, cmdlist.get);
+
+ if (req->flags & CMD_REQ_COMMIT)
+ mipi_dsi_cmdlist_commit(0);
+
+ return ret;
+}
+
void mipi_dsi_irq_set(uint32 mask, uint32 irq)
{
uint32 data;
@@ -1529,6 +1731,8 @@
isr = MIPI_INP(MIPI_DSI_BASE + 0x010c);/* DSI_INTR_CTRL */
MIPI_OUTP(MIPI_DSI_BASE + 0x010c, isr);
+ pr_debug("%s: isr=%x\n", __func__, (int)isr);
+
#ifdef CONFIG_FB_MSM_MDP40
mdp4_stat.intr_dsi++;
#endif
@@ -1548,7 +1752,7 @@
spin_lock(&dsi_mdp_lock);
complete(&dsi_dma_comp);
dsi_ctrl_lock = FALSE;
- mipi_dsi_disable_irq_nosync();
+ mipi_dsi_disable_irq_nosync(DSI_CMD_TERM);
spin_unlock(&dsi_mdp_lock);
}
@@ -1556,7 +1760,7 @@
mipi_dsi_mdp_stat_inc(STAT_DSI_MDP);
spin_lock(&dsi_mdp_lock);
dsi_ctrl_lock = FALSE;
- mipi_dsi_disable_irq_nosync();
+ mipi_dsi_disable_irq_nosync(DSI_MDP_TERM);
dsi_mdp_busy = FALSE;
complete(&dsi_mdp_comp);
spin_unlock(&dsi_mdp_lock);
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index 7dd41d2..b893cc7 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -393,18 +393,16 @@
mipi = &mfd->panel_info.mipi;
- if (mipi_dsi_ctrl_lock(0)) {
- if (mipi->mode == DSI_VIDEO_MODE) {
- mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_video_on_cmds,
+ if (mipi->mode == DSI_VIDEO_MODE) {
+ mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_video_on_cmds,
ARRAY_SIZE(novatek_video_on_cmds));
- } else {
- mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_cmd_on_cmds,
+ } else {
+ mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_cmd_on_cmds,
ARRAY_SIZE(novatek_cmd_on_cmds));
- /* clean up ack_err_status */
- mipi_dsi_cmd_bta_sw_trigger();
- mipi_novatek_manufacture_id(mfd);
- }
+ /* clean up ack_err_status */
+ mipi_dsi_cmd_bta_sw_trigger();
+ mipi_novatek_manufacture_id(mfd);
}
return 0;
@@ -421,35 +419,38 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- if (mipi_dsi_ctrl_lock(0)) {
- mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_display_off_cmds,
+ mipi_dsi_cmds_tx(&novatek_tx_buf, novatek_display_off_cmds,
ARRAY_SIZE(novatek_display_off_cmds));
- }
return 0;
}
DEFINE_LED_TRIGGER(bkl_led_trigger);
-#ifdef CONFIG_FB_MSM_MDP303
-void mdp4_backlight_put_level(int cndx, int level)
-{
- /* do nothing */
-}
-#endif
+static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */
+static struct dsi_cmd_desc backlight_cmd = {
+ DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
+
+struct dcs_cmd_req cmdreq;
static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd)
{
- struct mipi_panel_info *mipi;
if ((mipi_novatek_pdata->enable_wled_bl_ctrl)
&& (wled_trigger_initialized)) {
led_trigger_event(bkl_led_trigger, mfd->bl_level);
return;
}
- mipi = &mfd->panel_info.mipi;
- mdp4_backlight_put_level(0, mfd->bl_level);
+ led_pwm1[1] = (unsigned char)mfd->bl_level;
+
+ cmdreq.cmds = &backlight_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = 0;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mipi_dsi_cmdlist_put(&cmdreq);
}
static int mipi_dsi_3d_barrier_sysfs_register(struct device *dev);
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index efe6160..ae5acf4 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -184,8 +184,6 @@
u32 ov_start;
u32 mem_hid;
u32 mdp_rev;
- u32 use_ov0_blt, ov0_blt_state;
- u32 use_ov1_blt, ov1_blt_state;
u32 writeback_state;
bool writeback_active_cnt;
int cont_splash_done;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 0c6aa86..84f148f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -171,6 +171,7 @@
u32 sz_desc;
u32 sz_cpb;
u32 sz_context;
+ u32 sz_extnuserdata;
};
struct ddl_dec_buffers{
struct ddl_buf_addr desc;
@@ -186,6 +187,7 @@
struct ddl_buf_addr h264_vert_nb_mv;
struct ddl_buf_addr h264_nb_ip;
struct ddl_buf_addr context;
+ struct ddl_buf_addr extnuserdata;
};
struct ddl_enc_buffer_size{
u32 sz_cur_y;
@@ -228,7 +230,17 @@
[DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH];
u32 num_output_frames;
u32 out_frm_next_frmindex;
- u32 first_output_frame_tag;
+};
+struct ddl_mp2_datadumpenabletype {
+ u32 userdatadump_enable;
+ u32 pictempscalable_extdump_enable;
+ u32 picspat_extdump_enable;
+ u32 picdisp_extdump_enable;
+ u32 copyright_extdump_enable;
+ u32 quantmatrix_extdump_enable;
+ u32 seqscalable_extdump_enable;
+ u32 seqdisp_extdump_enable;
+ u32 seq_extdump_enable;
};
struct ddl_encoder_data{
struct ddl_codec_data_hdr hdr;
@@ -323,6 +335,9 @@
u32 dmx_disable;
int avg_dec_time;
int dec_time_sum;
+ struct ddl_mp2_datadumpenabletype mp2_datadump_enable;
+ u32 mp2_datadump_status;
+ u32 extn_user_data_enable;
};
union ddl_codec_data{
struct ddl_codec_data_hdr hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 949e5c0..95be1b6 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -533,6 +533,7 @@
ddl_pmem_free(&dec_bufs->stx_parser);
ddl_pmem_free(&dec_bufs->desc);
ddl_pmem_free(&dec_bufs->context);
+ ddl_pmem_free(&dec_bufs->extnuserdata);
memset(dec_bufs, 0, sizeof(struct ddl_dec_buffers));
}
@@ -601,6 +602,7 @@
u32 sz_sub_anchor_mv = 0, sz_overlap_xform = 0, sz_bit_plane3 = 0;
u32 sz_bit_plane2 = 0, sz_bit_plane1 = 0, sz_stx_parser = 0;
u32 sz_desc, sz_cpb, sz_context, sz_vert_nb_mv = 0, sz_nb_ip = 0;
+ u32 sz_extnuserdata = 0;
if (codec == VCD_CODEC_H264) {
sz_mv = ddl_get_yuv_buf_size(width,
@@ -630,7 +632,8 @@
sz_bit_plane3 = DDL_KILO_BYTE(2);
sz_bit_plane2 = DDL_KILO_BYTE(2);
sz_bit_plane1 = DDL_KILO_BYTE(2);
- }
+ } else if (codec == VCD_CODEC_MPEG2)
+ sz_extnuserdata = DDL_KILO_BYTE(2);
}
sz_desc = DDL_KILO_BYTE(128);
sz_cpb = VCD_DEC_CPB_SIZE;
@@ -657,6 +660,7 @@
buf_size->sz_desc = sz_desc;
buf_size->sz_cpb = sz_cpb;
buf_size->sz_context = sz_context;
+ buf_size->sz_extnuserdata = sz_extnuserdata;
}
}
@@ -774,6 +778,16 @@
}
}
}
+ if (buf_size.sz_extnuserdata > 0) {
+ dec_bufs->extnuserdata.mem_type = DDL_FW_MEM;
+ ptr = ddl_pmem_alloc(&dec_bufs->extnuserdata,
+ buf_size.sz_extnuserdata, DDL_KILO_BYTE(2));
+ if (!ptr)
+ goto fail_free_exit;
+ else
+ memset(dec_bufs->extnuserdata.align_virtual_addr,
+ 0, buf_size.sz_extnuserdata);
+ }
return status;
fail_free_exit:
status = VCD_ERR_ALLOC_FAIL;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index 8ec444f..c3d20cf 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -256,6 +256,10 @@
DDL_MSG_LOW("HEADER_DONE");
vidc_1080p_get_decode_seq_start_result(&seq_hdr_info);
parse_hdr_size_data(ddl, &seq_hdr_info);
+ decoder->mp2_datadump_status = 0;
+ vidc_sm_get_mp2datadump_status(&ddl->shared_mem
+ [ddl->command_channel],
+ &decoder->mp2_datadump_status);
if (res_trk_get_disable_fullhd() &&
(seq_hdr_info.img_size_x * seq_hdr_info.img_size_y >
1280 * 720)) {
@@ -1205,6 +1209,10 @@
vidc_sm_get_metadata_status(&ddl->shared_mem
[ddl->command_channel],
&decoder->meta_data_exists);
+ decoder->mp2_datadump_status = 0;
+ vidc_sm_get_mp2datadump_status(&ddl->shared_mem
+ [ddl->command_channel],
+ &decoder->mp2_datadump_status);
if (decoder->output_order == VCD_DEC_ORDER_DISPLAY) {
vidc_sm_get_frame_tags(&ddl->shared_mem
[ddl->command_channel],
@@ -1793,27 +1801,11 @@
vidc_sm_get_frame_tags(&ddl->shared_mem
[ddl->command_channel],
&output_frame->ip_frm_tag, &bottom_frame_tag);
-
- if (start_bfr_idx == 0) {
- encoder->batch_frame.first_output_frame_tag =
- output_frame->ip_frm_tag;
- DDL_MSG_LOW("%s: first_output_frame_tag[0x%x]",
- __func__, output_frame->ip_frm_tag);
- if (!output_frame->ip_frm_tag) {
- DDL_MSG_ERROR("%s: first_output_frame_tag "\
- "is zero", __func__);
- }
+ if (!output_frame->ip_frm_tag) {
+ DDL_MSG_ERROR("%s: zero frame tag rcvd, index = %d",
+ __func__, index);
+ output_frame->ip_frm_tag = (u32)ddl->client_data;
}
- if (output_frame->ip_frm_tag !=
- encoder->batch_frame.first_output_frame_tag) {
- DDL_MSG_ERROR("%s: output_frame->ip_frm_tag[0x%x] is "\
- "not equal to the first_output_frame_tag[0x%x]\n",
- __func__, output_frame->ip_frm_tag,
- encoder->batch_frame.first_output_frame_tag);
- output_frame->ip_frm_tag =
- encoder->batch_frame.first_output_frame_tag;
- }
-
ddl_get_encoded_frame(output_frame,
encoder->codec.codec,
encoder->enc_frame_info.enc_frame);
@@ -1896,27 +1888,11 @@
vidc_sm_get_frame_tags(&ddl->shared_mem
[ddl->command_channel],
&output_frame->ip_frm_tag, &bottom_frame_tag);
-
- if (start_bfr_idx == 0) {
- encoder->batch_frame.first_output_frame_tag =
- output_frame->ip_frm_tag;
- DDL_MSG_LOW("%s: first_output_frame_tag[0x%x]",
- __func__, output_frame->ip_frm_tag);
- if (!output_frame->ip_frm_tag) {
- DDL_MSG_ERROR("%s: first_output_frame_tag "\
- "is zero", __func__);
- }
+ if (!output_frame->ip_frm_tag) {
+ DDL_MSG_ERROR("%s: zero frame tag rcvd, index = %d",
+ __func__, index);
+ output_frame->ip_frm_tag = (u32)ddl->client_data;
}
- if (output_frame->ip_frm_tag !=
- encoder->batch_frame.first_output_frame_tag) {
- DDL_MSG_ERROR("%s: output_frame->ip_frm_tag[0x%x] is "\
- "not equal to the first_output_frame_tag[0x%x]\n",
- __func__, output_frame->ip_frm_tag,
- encoder->batch_frame.first_output_frame_tag);
- output_frame->ip_frm_tag =
- encoder->batch_frame.first_output_frame_tag;
- }
-
ddl_get_encoded_frame(output_frame,
encoder->codec.codec,
encoder->enc_frame_info.enc_frame);
@@ -1987,8 +1963,9 @@
&output_frame->ip_frm_tag,
&bottom_frame_tag);
if (!output_frame->ip_frm_tag) {
- DDL_MSG_ERROR("%s: output frame tag is zero",
- __func__);
+ DDL_MSG_ERROR("%s: zero frame tag rcvd, index = %d",
+ __func__, index);
+ output_frame->ip_frm_tag = (u32)ddl->client_data;
}
ddl_get_encoded_frame(
output_frame,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
index fade821..f70c47c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
@@ -52,6 +52,12 @@
case VCD_METADATA_QCOMFILLER:
skip_words = 21;
break;
+ case VCD_METADATA_USER_DATA:
+ skip_words = 27;
+ break;
+ case VCD_METADATA_EXT_DATA:
+ skip_words = 30;
+ break;
}
} else {
buffer = (u32 *) ddl->codec_data.encoder.meta_data_input.
@@ -123,6 +129,18 @@
hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] =
VCD_METADATA_PASSTHROUGH;
+ hdr_entry = ddl_metadata_hdr_entry(ddl,
+ VCD_METADATA_USER_DATA);
+ hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
+ hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
+ hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] =
+ VCD_METADATA_USER_DATA;
+ hdr_entry = ddl_metadata_hdr_entry(ddl,
+ VCD_METADATA_EXT_DATA);
+ hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
+ hdr_entry[DDL_METADATA_HDR_PORT_INDEX] = 1;
+ hdr_entry[DDL_METADATA_HDR_TYPE_INDEX] =
+ VCD_METADATA_EXT_DATA;
} else {
hdr_entry = ddl_metadata_hdr_entry(ddl, VCD_METADATA_ENC_SLICE);
hdr_entry[DDL_METADATA_HDR_VERSION_INDEX] = 0x00000101;
@@ -146,6 +164,9 @@
else if (codec == VCD_CODEC_VC1 ||
codec == VCD_CODEC_VC1_RCV)
flag |= VCD_METADATA_VC1;
+ else if (codec == VCD_CODEC_MPEG2)
+ flag |= (VCD_METADATA_USER_DATA |
+ VCD_METADATA_EXT_DATA);
} else
flag |= VCD_METADATA_ENC_SLICE;
return flag;
@@ -165,7 +186,6 @@
{
u32 flag = decoder->meta_data_enable_flag;
u32 suffix = 0, size = 0;
-
if (!flag) {
decoder->suffix = 0;
return;
@@ -210,6 +230,18 @@
DDL_METADATA_ALIGNSIZE(size);
suffix += (size);
}
+ if (flag & VCD_METADATA_USER_DATA) {
+ size = DDL_METADATA_HDR_SIZE;
+ size += DDL_METADATA_USER_PAYLOAD_SIZE;
+ DDL_METADATA_ALIGNSIZE(size);
+ suffix += (size);
+ }
+ if (flag & VCD_METADATA_EXT_DATA) {
+ size = DDL_METADATA_HDR_SIZE;
+ size += DDL_METADATA_EXT_PAYLOAD_SIZE;
+ DDL_METADATA_ALIGNSIZE(size);
+ suffix += (size);
+ }
size = DDL_METADATA_EXTRADATANONE_SIZE;
DDL_METADATA_ALIGNSIZE(size);
suffix += (size);
@@ -278,6 +310,10 @@
if (flag)
flag |= DDL_METADATA_MANDATORY;
if (*meta_data_enable_flag != flag) {
+ if (VCD_CODEC_MPEG2 == codec)
+ ddl_set_mp2_dump_default(
+ &ddl->codec_data.decoder,
+ flag);
*meta_data_enable_flag = flag;
if (ddl->decoding)
ddl_set_default_decoder_buffer_req(
@@ -357,6 +393,7 @@
u32 qp_enable = false, concealed_mb_enable = false;
u32 vc1_param_enable = false, sei_nal_enable = false;
u32 vui_enable = false, enc_slice_size_enable = false;
+ u32 mp2_data_dump_enable = false;
if (ddl->decoding)
flag = ddl->codec_data.decoder.meta_data_enable_flag;
@@ -380,10 +417,22 @@
}
DDL_MSG_LOW("metadata enable flag : %d", sei_nal_enable);
+ if (flag & VCD_METADATA_EXT_DATA || flag & VCD_METADATA_USER_DATA) {
+ mp2_data_dump_enable = true;
+ ddl->codec_data.decoder.extn_user_data_enable =
+ mp2_data_dump_enable;
+ vidc_sm_set_mp2datadump_enable(&ddl->shared_mem
+ [ddl->command_channel],
+ &ddl->codec_data.decoder.mp2_datadump_enable);
+ } else {
+ mp2_data_dump_enable = false;
+ ddl->codec_data.decoder.extn_user_data_enable =
+ mp2_data_dump_enable;
+ }
vidc_sm_set_metadata_enable(&ddl->shared_mem
[ddl->command_channel], extradata_enable, qp_enable,
concealed_mb_enable, vc1_param_enable, sei_nal_enable,
- vui_enable, enc_slice_size_enable);
+ vui_enable, enc_slice_size_enable, mp2_data_dump_enable);
}
u32 ddl_vidc_encode_set_metadata_output_buf(struct ddl_client_context *ddl)
@@ -487,6 +536,11 @@
output_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
return;
}
+ if (!decoder->mp2_datadump_status && decoder->codec.codec ==
+ VCD_CODEC_MPEG2 && !decoder->extn_user_data_enable) {
+ output_frame->flags &= ~(VCD_FRAME_FLAG_EXTRADATA);
+ return;
+ }
DDL_MSG_LOW("processing metadata for decoder");
DDL_MSG_LOW("data_len/metadata_offset : %d/%d",
output_frame->data_len, decoder->meta_data_offset);
@@ -507,3 +561,27 @@
*qfiller = (u32)(qfiller_size - DDL_METADATA_HDR_SIZE);
}
}
+
+void ddl_set_mp2_dump_default(struct ddl_decoder_data *decoder, u32 flag)
+{
+
+ if (flag & VCD_METADATA_EXT_DATA) {
+ decoder->mp2_datadump_enable.pictempscalable_extdump_enable =
+ true;
+ decoder->mp2_datadump_enable.picspat_extdump_enable = true;
+ decoder->mp2_datadump_enable.picdisp_extdump_enable = true;
+ decoder->mp2_datadump_enable.copyright_extdump_enable = true;
+ decoder->mp2_datadump_enable.quantmatrix_extdump_enable =
+ true;
+ decoder->mp2_datadump_enable.seqscalable_extdump_enable =
+ true;
+ decoder->mp2_datadump_enable.seqdisp_extdump_enable = true;
+ decoder->mp2_datadump_enable.seq_extdump_enable = true;
+ }
+ if (flag & VCD_METADATA_USER_DATA)
+ decoder->mp2_datadump_enable.userdatadump_enable =
+ DDL_METADATA_USER_DUMP_FULL_MODE;
+ else
+ decoder->mp2_datadump_enable.userdatadump_enable =
+ DDL_METADATA_USER_DUMP_DISABLE_MODE;
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
index c63b6a9..e03a9b7 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.h
@@ -14,7 +14,7 @@
#ifndef _VCD_DDL_METADATA_H_
#define _VCD_DDL_METADATA_H_
-#define DDL_MAX_DEC_METADATATYPE 8
+#define DDL_MAX_DEC_METADATATYPE 10
#define DDL_MAX_ENC_METADATATYPE 3
#define DDL_METADATA_EXTRAPAD_SIZE 256
#define DDL_METADATA_HDR_SIZE 20
@@ -27,6 +27,8 @@
#define DDL_METADATA_SEI_MAX 5
#define DDL_METADATA_VUI_PAYLOAD_SIZE 256
#define DDL_METADATA_PASSTHROUGH_PAYLOAD_SIZE 68
+#define DDL_METADATA_EXT_PAYLOAD_SIZE (640)
+#define DDL_METADATA_USER_PAYLOAD_SIZE (2048)
#define DDL_METADATA_CLIENT_INPUTBUFSIZE 256
#define DDL_METADATA_TOTAL_INPUTBUFSIZE \
(DDL_METADATA_CLIENT_INPUTBUFSIZE * VCD_MAX_NO_CLIENT)
@@ -46,6 +48,10 @@
#define DDL_METADATA_HDR_PORT_INDEX 1
#define DDL_METADATA_HDR_TYPE_INDEX 2
+#define DDL_METADATA_USER_DUMP_DISABLE_MODE 0
+#define DDL_METADATA_USER_DUMP_OFFSET_MODE 1
+#define DDL_METADATA_USER_DUMP_FULL_MODE 2
+
void ddl_set_default_meta_data_hdr(struct ddl_client_context *ddl);
u32 ddl_get_metadata_params(struct ddl_client_context *ddl,
struct vcd_property_hdr *property_hdr, void *property_value);
@@ -62,5 +68,6 @@
void ddl_vidc_decode_set_metadata_output(struct ddl_decoder_data *decoder);
void ddl_process_encoder_metadata(struct ddl_client_context *ddl);
void ddl_process_decoder_metadata(struct ddl_client_context *ddl);
+void ddl_set_mp2_dump_default(struct ddl_decoder_data *decoder, u32 flag);
#endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index d83cde8..416b497 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -187,6 +187,8 @@
#define VIDC_SM_METADATA_ENABLE_ADDR 0x0038
+#define VIDC_SM_METADATA_ENABLE_MP2_DATADUMP_BMSK 0x00000200
+#define VIDC_SM_METADATA_ENABLE_MP2_DATADUMP_SHFT 9
#define VIDC_SM_METADATA_ENABLE_EXTRADATA_BMSK 0x40
#define VIDC_SM_METADATA_ENABLE_EXTRADATA_SHFT 6
#define VIDC_SM_METADATA_ENABLE_ENC_SLICE_SIZE_BMSK 0x20
@@ -251,6 +253,51 @@
#define VIDC_SM_TIMEOUT_VALUE_BMSK 0xffffffff
#define VIDC_SM_TIMEOUT_VALUE_SHFT 0
+#define VIDC_SM_MP2_DATA_DUMP_CONTROL_ADDR 0x0194
+#define VIDC_SM_MP2_USERDATA_DUMP_ENABLE_BMSK 0x00000300
+#define VIDC_SM_MP2_USERDATA_DUMP_ENABLE_SHFT 8
+#define VIDC_SM_MP2_PICT_TEMP_DUMP_ENABLE_BMSK 0x00000080
+#define VIDC_SM_MP2_PICT_TEMP_DUMP_ENABLE_SHFT 7
+#define VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_ENABLE_BMSK 0x00000040
+#define VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_ENABLE_SHFT 6
+#define VIDC_SM_MP2_PICT_DISP_EXT_DUMP_ENABLE_BMSK 0x00000020
+#define VIDC_SM_MP2_PICT_DISP_EXT_DUMP_ENABLE_SHFT 5
+#define VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_ENABLE_BMSK 0x00000010
+#define VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_ENABLE_SHFT 4
+#define VIDC_SM_MP2_QMATRIX_EXT_DUMP_ENABLE_BMSK 0x00000008
+#define VIDC_SM_MP2_QMATRIX_EXT_DUMP_ENABLE_SHFT 3
+#define VIDC_SM_MP2_SCAL_EXT_DUMP_ENABLE_BMSK 0x00000004
+#define VIDC_SM_MP2_SCAL_EXT_DUMP_ENABLE_SHFT 2
+#define VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_ENABLE_BMSK 0x00000002
+#define VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_ENABLE_SHFT 1
+#define VIDC_SM_MP2_SEQ_EXT_DUMP_ENABLE_BMSK 0x00000001
+#define VIDC_SM_MP2_SEQ_EXT_DUMP_ENABLE_SHFT 0
+
+#define VIDC_SM_MP2_DATA_DUMP_STATUS_ADDR 0x0198
+#define VIDC_SM_MP2_USERDATA_DUMP_STATUS_BMSK 0x00000300
+#define VIDC_SM_MP2_USERDATA_DUMP_STATUS_SHFT 8
+#define VIDC_SM_MP2_PICT_TEMP_DUMP_STATUS_BMSK 0x00000080
+#define VIDC_SM_MP2_PICT_TEMP_DUMP_STATUS_SHFT 7
+#define VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_STATUS_BMSK 0x00000040
+#define VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_STATUS_SHFT 6
+#define VIDC_SM_MP2_PICT_DISP_EXT_DUMP_STATUS_BMSK 0x00000020
+#define VIDC_SM_MP2_PICT_DISP_EXT_DUMP_STATUS_SHFT 5
+#define VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_STATUS_BMSK 0x00000010
+#define VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_STATUS_SHFT 4
+#define VIDC_SM_MP2_QMATRIX_EXT_DUMP_STATUS_BMSK 0x00000008
+#define VIDC_SM_MP2_QMATRIX_EXT_DUMP_STATUS_SHFT 3
+#define VIDC_SM_MP2_SCAL_EXT_DUMP_STATUS_BMSK 0x00000004
+#define VIDC_SM_MP2_SCAL_EXT_DUMP_STATUS_SHFT 2
+#define VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_STATUS_BMSK 0x00000002
+#define VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_STATUS_SHFT 1
+#define VIDC_SM_MP2_SEQ_EXT_DUMP_STATUS_BMSK 0x00000001
+#define VIDC_SM_MP2_SEQ_EXT_DUMP_STATUS_SHFT 0
+
+#define VIDC_SM_MP2_DATA_DUMP_BUFFER_ADDR 0x01a4
+#define VIDC_SM_MP2_DATA_DUMP_BUFFER_SIZE_ADDR 0x01a8
+
+
+
#define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK 0x40
#define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT 6
@@ -579,11 +626,14 @@
void vidc_sm_set_metadata_enable(struct ddl_buf_addr *shared_mem,
u32 extradata_enable, u32 qp_enable, u32 concealed_mb_enable,
u32 vc1Param_enable, u32 sei_nal_enable, u32 vui_enable,
- u32 enc_slice_size_enable)
+ u32 enc_slice_size_enable, u32 mp2_data_dump_enable)
{
u32 metadata_enable;
- metadata_enable = VIDC_SETFIELD((extradata_enable) ? 1 : 0,
+ metadata_enable = VIDC_SETFIELD((mp2_data_dump_enable) ? 1 : 0,
+ VIDC_SM_METADATA_ENABLE_MP2_DATADUMP_SHFT,
+ VIDC_SM_METADATA_ENABLE_MP2_DATADUMP_BMSK) |
+ VIDC_SETFIELD((extradata_enable) ? 1 : 0,
VIDC_SM_METADATA_ENABLE_EXTRADATA_SHFT,
VIDC_SM_METADATA_ENABLE_EXTRADATA_BMSK) |
VIDC_SETFIELD((enc_slice_size_enable) ? 1 : 0,
@@ -1015,3 +1065,71 @@
timeout);
}
+void vidc_sm_set_mp2datadump_enable(struct ddl_buf_addr *shared_mem,
+ struct ddl_mp2_datadumpenabletype *ddl_mp2_datadump_enable)
+{
+ u32 mp2_datadump_enable = 0;
+
+ mp2_datadump_enable = VIDC_SETFIELD(
+ ddl_mp2_datadump_enable->userdatadump_enable,
+ VIDC_SM_MP2_USERDATA_DUMP_ENABLE_SHFT,
+ VIDC_SM_MP2_USERDATA_DUMP_ENABLE_BMSK) |
+ VIDC_SETFIELD(ddl_mp2_datadump_enable->
+ pictempscalable_extdump_enable ? 1 : 0,
+ VIDC_SM_MP2_PICT_TEMP_DUMP_ENABLE_SHFT,
+ VIDC_SM_MP2_PICT_TEMP_DUMP_ENABLE_BMSK) |
+ VIDC_SETFIELD(ddl_mp2_datadump_enable->
+ picspat_extdump_enable ? 1 : 0,
+ VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_ENABLE_SHFT,
+ VIDC_SM_MP2_PICT_SPAT_EXT_DUMP_ENABLE_BMSK) |
+ VIDC_SETFIELD(ddl_mp2_datadump_enable->
+ picdisp_extdump_enable ? 1 : 0,
+ VIDC_SM_MP2_PICT_DISP_EXT_DUMP_ENABLE_SHFT,
+ VIDC_SM_MP2_PICT_DISP_EXT_DUMP_ENABLE_BMSK) |
+ VIDC_SETFIELD(ddl_mp2_datadump_enable->
+ copyright_extdump_enable ? 1 : 0,
+ VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_ENABLE_SHFT,
+ VIDC_SM_MP2_COPYRIGHT_EXT_DUMP_ENABLE_BMSK) |
+ VIDC_SETFIELD(ddl_mp2_datadump_enable->
+ quantmatrix_extdump_enable ? 1 : 0,
+ VIDC_SM_MP2_QMATRIX_EXT_DUMP_ENABLE_SHFT,
+ VIDC_SM_MP2_QMATRIX_EXT_DUMP_ENABLE_BMSK) |
+ VIDC_SETFIELD(ddl_mp2_datadump_enable->
+ seqscalable_extdump_enable ? 1 : 0,
+ VIDC_SM_MP2_SCAL_EXT_DUMP_ENABLE_SHFT,
+ VIDC_SM_MP2_SCAL_EXT_DUMP_ENABLE_BMSK) |
+ VIDC_SETFIELD(ddl_mp2_datadump_enable->
+ seqdisp_extdump_enable ? 1 : 0,
+ VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_ENABLE_SHFT,
+ VIDC_SM_MP2_SEQ_DISP_EXT_DUMP_ENABLE_BMSK) |
+ VIDC_SETFIELD(ddl_mp2_datadump_enable->
+ seq_extdump_enable ? 1 : 0,
+ VIDC_SM_MP2_SEQ_EXT_DUMP_ENABLE_SHFT,
+ VIDC_SM_MP2_SEQ_EXT_DUMP_ENABLE_BMSK);
+ DDL_MEM_WRITE_32(shared_mem, VIDC_SM_MP2_DATA_DUMP_CONTROL_ADDR,
+ mp2_datadump_enable);
+
+}
+
+void vidc_sm_get_mp2datadump_status(struct ddl_buf_addr
+ *shared_mem, u32 *ext_userdata_present)
+{
+ u32 status;
+
+ status = DDL_MEM_READ_32(shared_mem,
+ VIDC_SM_MP2_DATA_DUMP_STATUS_ADDR);
+ *ext_userdata_present = (u32) VIDC_GETFIELD(status,
+ VIDC_SM_MP2_USERDATA_DUMP_STATUS_BMSK,
+ VIDC_SM_MP2_USERDATA_DUMP_STATUS_SHFT);
+}
+
+void vidc_sm_set_mp2datadumpbuffer(struct ddl_buf_addr *shared_mem,
+ u32 mp2datadumpaddr, u32 mp2datadumpsize)
+{
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_MP2_DATA_DUMP_BUFFER_ADDR,
+ mp2datadumpaddr);
+ DDL_MEM_WRITE_32(shared_mem,
+ VIDC_SM_MP2_DATA_DUMP_BUFFER_SIZE_ADDR,
+ mp2datadumpsize);
+}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 1a46c36..9cb1933 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -139,7 +139,7 @@
void vidc_sm_set_metadata_enable(struct ddl_buf_addr *shared_mem,
u32 extradata_enable, u32 qp_enable, u32 concealed_mb_enable,
u32 vc1Param_enable, u32 sei_nal_enable, u32 vui_enable,
- u32 enc_slice_size_enable);
+ u32 enc_slice_size_enable, u32 mp2_data_dump_enable);
void vidc_sm_get_metadata_status(struct ddl_buf_addr *shared_mem,
u32 *pb_metadata_present);
void vidc_sm_get_metadata_display_index(struct ddl_buf_addr *shared_mem,
@@ -193,4 +193,11 @@
u32 *output_buffer_size);
void vidc_sm_set_video_core_timeout_value(struct ddl_buf_addr *shared_mem,
u32 timeout);
+void vidc_sm_get_mp2datadump_status(struct ddl_buf_addr
+ *shared_mem, u32 *ext_userdata_present);
+void vidc_sm_set_mp2datadump_enable(struct ddl_buf_addr *shared_mem,
+ struct ddl_mp2_datadumpenabletype *ddl_mp2_datadump_enable);
+void vidc_sm_set_mp2datadumpbuffer(struct ddl_buf_addr *shared_mem,
+ u32 mp2datadumpaddr, u32 mp2datadumpsize);
+
#endif
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index 260cd72..90114f7 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -112,10 +112,10 @@
&iova,
&buffer_size,
UNCACHED, 0);
- if (ret) {
+ if (ret || !iova) {
DDL_MSG_ERROR(
- "%s():DDL ION ion map iommu failed\n",
- __func__);
+ "%s():DDL ION ion map iommu failed, ret = %d iova = 0x%lx\n",
+ __func__, ret, iova);
goto unmap_ion_alloc;
}
addr->alloced_phys_addr = (phys_addr_t) iova;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index d1f6e07..4072b02 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -867,7 +867,6 @@
DDL_MEMSET(encoder->batch_frame.slice_batch_in.align_virtual_addr, 0,
sizeof(struct vidc_1080p_enc_slice_batch_in_param));
encoder->batch_frame.out_frm_next_frmindex = 0;
- encoder->batch_frame.first_output_frame_tag = 0;
bitstream_size = encoder->batch_frame.output_frame[0].vcd_frm.alloc_len;
encoder->output_buf_req.sz = bitstream_size;
y_addr = DDL_OFFSET(ddl_context->dram_base_b.align_physical_addr,
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 291de5f..972160a 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -85,9 +85,10 @@
&iova,
&buffer_size,
UNCACHED, 0);
- if (ret) {
- DDL_MSG_ERROR("%s():DDL ION client iommu map failed\n",
- __func__);
+ if (ret || !iova) {
+ DDL_MSG_ERROR(
+ "%s():DDL ION client iommu map failed, ret = %d iova = 0x%lx\n",
+ __func__, ret, iova);
goto ion_unmap_bail_out;
}
addr->mapped_buffer = NULL;
diff --git a/drivers/video/msm/vidc/Kconfig b/drivers/video/msm/vidc/Kconfig
index 9ffcb15..7820e53 100644
--- a/drivers/video/msm/vidc/Kconfig
+++ b/drivers/video/msm/vidc/Kconfig
@@ -37,3 +37,7 @@
help
This option enables support for Video decoder.
+config MSM_VIDC_CONTENT_PROTECTION
+ bool "Enable Content Protection"
+ help
+ Enable content protection feature for Video.
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 927f19b..f68265a 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -936,9 +936,10 @@
SZ_4K, 0, (unsigned long *)&iova,
(unsigned long *)&buffer_size,
UNCACHED, 0);
- if (rc) {
- ERR("%s():get_ION_kernel physical addr fail\n",
- __func__);
+ if (rc || !iova) {
+ ERR(
+ "%s():get_ION_kernel physical addr fail, rc = %d iova = 0x%lx\n",
+ __func__, rc, iova);
goto ion_map_error;
}
vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 50cccbb..5ee0a3d 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1868,9 +1868,10 @@
(unsigned long *)&iova,
(unsigned long *)&buffer_size,
UNCACHED, 0);
- if (rc) {
- ERR("%s():ION map iommu addr fail\n",
- __func__);
+ if (rc || !iova) {
+ ERR(
+ "%s():ION map iommu addr fail, rc = %d, iova = 0x%lx\n",
+ __func__, rc, iova);
goto map_ion_error;
}
control->physical_addr = (u8 *) iova;
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index c884cf5..221c154 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -680,9 +680,10 @@
(unsigned long *) &buffer_size,
UNCACHED,
ION_IOMMU_UNMAP_DELAYED);
- if (ret) {
- ERR("%s():ION iommu map fail\n",
- __func__);
+ if (ret || !iova) {
+ ERR(
+ "%s():ION iommu map fail, ret = %d, iova = 0x%lx\n",
+ __func__, ret, iova);
goto ion_map_error;
}
phys_addr = iova;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 28ea453..b97a58e 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -121,8 +121,10 @@
(unsigned long *)&iova,
(unsigned long *)&buffer_size,
UNCACHED, 0);
- if (ret) {
- pr_err("%s() ION iommu map failed", __func__);
+ if (ret || !iova) {
+ pr_err(
+ "%s() ION iommu map failed, ret = %d, iova = 0x%lx",
+ __func__, ret, iova);
goto ion_map_bailout;
}
map_buffer->phy_addr = iova;
diff --git a/include/asm-generic/dma-coherent.h b/include/asm-generic/dma-coherent.h
index 85a3ffa..abfb268 100644
--- a/include/asm-generic/dma-coherent.h
+++ b/include/asm-generic/dma-coherent.h
@@ -3,13 +3,15 @@
#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT
/*
- * These two functions are only for dma allocator.
+ * These three functions are only for dma allocator.
* Don't use them in device drivers.
*/
int dma_alloc_from_coherent(struct device *dev, ssize_t size,
dma_addr_t *dma_handle, void **ret);
int dma_release_from_coherent(struct device *dev, int order, void *vaddr);
+int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, size_t size, int *ret);
/*
* Standard interface
*/
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 277fdf1..31a152d 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -427,6 +427,7 @@
header-y += msm_vidc_enc.h
header-y += msm_audio.h
header-y += msm_audio_aac.h
+header-y += msm_audio_ac3.h
header-y += msm_audio_acdb.h
header-y += android_pmem.h
header-y += msm_audio_wma.h
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index a829f06..04fcd88 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -15,7 +15,6 @@
#include <linux/device.h>
-
/* Peripheral id registers (0xFD0-0xFEC) */
#define CORESIGHT_PERIPHIDR4 (0xFD0)
#define CORESIGHT_PERIPHIDR5 (0xFD4)
@@ -31,7 +30,6 @@
#define CORESIGHT_COMPIDR2 (0xFF8)
#define CORESIGHT_COMPIDR3 (0xFFC)
-
/* DBGv7 with baseline CP14 registers implemented */
#define ARM_DEBUG_ARCH_V7B (0x3)
/* DBGv7 with all CP14 registers implemented */
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 7769950..c953613 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -112,7 +112,7 @@
#define EVENT_LAST_ID 0x08AD
#define MSG_SSID_0 0
-#define MSG_SSID_0_LAST 91
+#define MSG_SSID_0_LAST 93
#define MSG_SSID_1 500
#define MSG_SSID_1_LAST 506
#define MSG_SSID_2 1000
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index b54fcb4..5c3c728 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -69,7 +69,9 @@
bool i2c_pull_up;
bool digital_pwr_regulator;
int reset_gpio;
+ u32 reset_gpio_flags;
int irq_gpio;
+ u32 irq_gpio_flags;
int *key_codes;
u8(*read_chg) (void);
diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
index 7169870..f28053c 100644
--- a/include/linux/iopoll.h
+++ b/include/linux/iopoll.h
@@ -49,6 +49,28 @@
})
/**
+ * readl_poll_timeout_noirq - Periodically poll an address until a condition is met or a timeout occurs
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @max_reads: Maximum number of reads before giving up
+ * @time_between_us: Time to udelay() between successive reads
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout.
+ */
+#define readl_poll_timeout_noirq(addr, val, cond, max_reads, time_between_us) \
+({ \
+ int count; \
+ for (count = (max_reads); count > 0; count--) { \
+ (val) = readl(addr); \
+ if (cond) \
+ break; \
+ udelay(time_between_us); \
+ } \
+ (cond) ? 0 : -ETIMEDOUT; \
+})
+
+/**
* readl_poll - Periodically poll an address until a condition is met
* @addr: Address to poll
* @val: Variable to read the value into
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index f1e2527..771cb35 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -154,6 +154,14 @@
return desc->status_use_accessors & IRQ_NO_BALANCING_MASK;
}
+static inline int irq_is_per_cpu(unsigned int irq)
+{
+ struct irq_desc *desc;
+
+ desc = irq_to_desc(irq);
+ return desc->status_use_accessors & IRQ_PER_CPU;
+}
+
static inline void
irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class)
{
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index bbd032d..a73a284 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -116,7 +116,8 @@
* @r_sense: sense resistor value in (mOhms)
* @i_test: current at which the unusable charger cutoff is to be
* calculated or the peak system current (mA)
- * @v_failure: the voltage at which the battery is considered empty(mV)
+ * @v_cutoff: the loaded voltage at which the battery
+ * is considered empty(mV)
* @enable_fcc_learning: if set the driver will learn full charge
* capacity of the battery upon end of charge
*/
@@ -125,10 +126,14 @@
enum battery_type battery_type;
unsigned int r_sense;
unsigned int i_test;
- unsigned int v_failure;
+ unsigned int v_cutoff;
unsigned int max_voltage_uv;
unsigned int rconn_mohm;
int enable_fcc_learning;
+ int shutdown_soc_valid_limit;
+ int ignore_shutdown_soc;
+ int adjust_soc_low_threshold;
+ int chg_term_ua;
};
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index b00e050..6bd4cb2 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -281,6 +281,13 @@
*
*/
int pm8921_usb_ovp_disable(int disable);
+/**
+ * pm8921_is_batfet_closed - battery fet status
+ *
+ * Returns 1 if batfet is closed 0 if open. On configurations without
+ * batfet this will return 0.
+ */
+int pm8921_is_batfet_closed(void);
#else
static inline void pm8921_charger_vbus_draw(unsigned int mA)
{
@@ -353,6 +360,10 @@
{
return -ENXIO;
}
+static inline int pm8921_is_batfet_closed(void)
+{
+ return 1;
+}
#endif
#endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
index 9619527..0d5d058 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-slimslave.h
@@ -116,4 +116,6 @@
unsigned int *rx_ch,
unsigned int *tx_ch);
int wcd9xxx_get_slave_port(unsigned int ch_num);
+int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
+ unsigned int tot_ch, unsigned int rx_tx);
#endif /* __WCD9310_SLIMSLAVE_H_ */
diff --git a/include/linux/msm_audio.h b/include/linux/msm_audio.h
index f2a39e4..4eb8a65 100644
--- a/include/linux/msm_audio.h
+++ b/include/linux/msm_audio.h
@@ -222,6 +222,28 @@
#define SND_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_device_config *)
+enum cad_device_path_type {
+ CAD_DEVICE_PATH_RX, /*For Decoding session*/
+ CAD_DEVICE_PATH_TX, /* For Encoding session*/
+ CAD_DEVICE_PATH_RX_TX, /* For Voice call */
+ CAD_DEVICE_PATH_LB, /* For loopback (FM Analog)*/
+ CAD_DEVICE_PATH_MAX
+};
+
+struct cad_devices_type {
+ uint32_t rx_device;
+ uint32_t tx_device;
+ enum cad_device_path_type pathtype;
+};
+
+struct msm_cad_device_config {
+ struct cad_devices_type device;
+ uint32_t ear_mute;
+ uint32_t mic_mute;
+};
+
+#define CAD_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_cad_device_config *)
+
#define SND_METHOD_VOICE 0
struct msm_snd_volume_config {
@@ -232,6 +254,14 @@
#define SND_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_snd_volume_config *)
+struct msm_cad_volume_config {
+ struct cad_devices_type device;
+ uint32_t method;
+ uint32_t volume;
+};
+
+#define CAD_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_cad_volume_config *)
+
/* Returns the number of SND endpoints supported. */
#define SND_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned *)
@@ -254,6 +284,24 @@
#define SND_AVC_CTL _IOW(SND_IOCTL_MAGIC, 6, unsigned *)
#define SND_AGC_CTL _IOW(SND_IOCTL_MAGIC, 7, unsigned *)
+/*return the number of CAD endpoints supported. */
+
+#define CAD_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned *)
+
+struct msm_cad_endpoint {
+ int id; /* input and output */
+ char name[64]; /* output only */
+};
+
+/* Takes an index between 0 and one less than the number returned by
+ * SND_GET_NUM_ENDPOINTS, and returns the CAD index and name of a
+ * CAD endpoint. On input, the .id field contains the number of the
+ * endpoint, and on exit it contains the SND index, while .name contains
+ * the description of the endpoint.
+ */
+
+#define CAD_GET_ENDPOINT _IOWR(SND_IOCTL_MAGIC, 5, struct msm_cad_endpoint *)
+
struct msm_audio_pcm_config {
uint32_t pcm_feedback; /* 0 - disable > 0 - enable */
uint32_t buffer_count; /* Number of buffers to allocate */
diff --git a/include/linux/msm_audio_ac3.h b/include/linux/msm_audio_ac3.h
new file mode 100644
index 0000000..fc50c30
--- /dev/null
+++ b/include/linux/msm_audio_ac3.h
@@ -0,0 +1,41 @@
+#ifndef __MSM_AUDIO_AC3_H
+#define __MSM_AUDIO_AC3_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_SET_AC3_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned)
+#define AUDIO_GET_AC3_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned)
+
+#define AUDAC3_DEF_WORDSIZE 0
+#define AUDAC3_DEF_USER_DOWNMIX_FLAG 0x0
+#define AUDAC3_DEF_USER_KARAOKE_FLAG 0x0
+#define AUDAC3_DEF_ERROR_CONCEALMENT 0
+#define AUDAC3_DEF_MAX_REPEAT_COUNT 0
+
+struct msm_audio_ac3_config {
+ unsigned short numChans;
+ unsigned short wordSize;
+ unsigned short kCapableMode;
+ unsigned short compMode;
+ unsigned short outLfeOn;
+ unsigned short outputMode;
+ unsigned short stereoMode;
+ unsigned short dualMonoMode;
+ unsigned short fsCod;
+ unsigned short pcmScaleFac;
+ unsigned short dynRngScaleHi;
+ unsigned short dynRngScaleLow;
+ unsigned short user_downmix_flag;
+ unsigned short user_karaoke_flag;
+ unsigned short dm_address_high;
+ unsigned short dm_address_low;
+ unsigned short ko_address_high;
+ unsigned short ko_address_low;
+ unsigned short error_concealment;
+ unsigned short max_rep_count;
+ unsigned short channel_routing_mode[6];
+};
+
+#endif /* __MSM_AUDIO_AC3_H */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 2519a6e..4dd6907 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -105,6 +105,7 @@
MDP_YCRCB_H1V1, /* YCrCb interleave */
MDP_YCBCR_H1V1, /* YCbCr interleave */
MDP_BGR_565, /* BGR 565 planer */
+ MDP_BGR_888, /* BGR 888 */
MDP_IMGTYPE_LIMIT,
MDP_RGB_BORDERFILL, /* border fill pipe */
MDP_FB_FORMAT = MDP_IMGTYPE2_START, /* framebuffer format */
diff --git a/include/linux/msm_vidc_dec.h b/include/linux/msm_vidc_dec.h
index 3d8907a..3c99562 100644
--- a/include/linux/msm_vidc_dec.h
+++ b/include/linux/msm_vidc_dec.h
@@ -76,6 +76,9 @@
#define VDEC_EXTRADATA_VUI 0x020
#define VDEC_EXTRADATA_VC1 0x040
+#define VDEC_EXTRADATA_EXT_DATA 0x0800
+#define VDEC_EXTRADATA_USER_DATA 0x1000
+
#define VDEC_CMDBASE 0x800
#define VDEC_CMD_SET_INTF_VERSION (VDEC_CMDBASE)
diff --git a/include/linux/qpnp/clkdiv.h b/include/linux/qpnp/clkdiv.h
new file mode 100644
index 0000000..c75a922
--- /dev/null
+++ b/include/linux/qpnp/clkdiv.h
@@ -0,0 +1,35 @@
+/* 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 QPNP_CLKDIV_H
+#define QPNP_CLKDIV_H
+
+enum q_clkdiv_cfg {
+ Q_CLKDIV_NO_CLK = 0,
+ Q_CLKDIV_XO_DIV_1,
+ Q_CLKDIV_XO_DIV_2,
+ Q_CLKDIV_XO_DIV_4,
+ Q_CLKDIV_XO_DIV_8,
+ Q_CLKDIV_XO_DIV_16,
+ Q_CLKDIV_XO_DIV_32,
+ Q_CLKDIV_XO_DIV_64,
+ Q_CLKDIV_INVALID,
+};
+
+struct q_clkdiv;
+
+struct q_clkdiv *qpnp_clkdiv_get(struct device *dev, const char *name);
+int qpnp_clkdiv_enable(struct q_clkdiv *q_clkdiv);
+int qpnp_clkdiv_disable(struct q_clkdiv *q_clkdiv);
+int qpnp_clkdiv_config(struct q_clkdiv *q_clkdiv,
+ enum q_clkdiv_cfg cfg);
+#endif
diff --git a/include/linux/regulator/krait-regulator.h b/include/linux/regulator/krait-regulator.h
index 1f85952..eb1c3fd 100644
--- a/include/linux/regulator/krait-regulator.h
+++ b/include/linux/regulator/krait-regulator.h
@@ -23,5 +23,6 @@
* success and error on failure.
*/
int __init krait_power_init(void);
+void secondary_cpu_hs_init(void *base_ptr);
#endif
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 75b132b..a088b9c 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -479,6 +479,8 @@
* @m_ctrl: Mutex protecting controller data structures (ports, channels etc)
* @addrt: Logical address table
* @num_dev: Number of active slimbus slaves on this bus
+ * @devs: List of devices on this controller
+ * @wq: Workqueue per controller used to notify devices when they report present
* @txnt: Table of transactions having transaction ID
* @last_tid: size of the table txnt (can't grow beyond 256 since TID is 8-bits)
* @ports: Ports associated with this controller
@@ -525,6 +527,8 @@
struct mutex m_ctrl;
struct slim_addrt *addrt;
u8 num_dev;
+ struct list_head devs;
+ struct workqueue_struct *wq;
struct slim_msg_txn **txnt;
u8 last_tid;
struct slim_port *ports;
@@ -569,6 +573,7 @@
int (*suspend)(struct slim_device *sldev,
pm_message_t pmesg);
int (*resume)(struct slim_device *sldev);
+ int (*device_up)(struct slim_device *sldev);
struct device_driver driver;
const struct slim_device_id *id_table;
@@ -601,6 +606,11 @@
* @mark_define: List of channels pending definition/activation.
* @mark_suspend: List of channels pending suspend.
* @mark_removal: List of channels pending removal.
+ * @notified: Flag to indicate whether this device has been notified. The
+ * device may report present multiple times, but should be notified only
+ * first time it has reported present.
+ * @dev_list: List of devices on a controller
+ * @wd: Work structure associated with workqueue for presence notification
* @sldev_reconf: Mutex to protect the pending data-channel lists.
* @pending_msgsl: Message bandwidth reservation request by this client in
* slots that's pending reconfiguration.
@@ -619,6 +629,9 @@
struct list_head mark_define;
struct list_head mark_suspend;
struct list_head mark_removal;
+ bool notified;
+ struct list_head dev_list;
+ struct work_struct wd;
struct mutex sldev_reconf;
u32 pending_msgsl;
u32 cur_msgsl;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6a0259d..6fcafa8 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -282,8 +282,10 @@
struct winsize winsize; /* termios mutex */
unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
unsigned char low_latency:1, warned:1;
+ unsigned char update_room_in_ldisc:1;
unsigned char ctrl_status; /* ctrl_lock */
unsigned int receive_room; /* Bytes free for queue */
+ unsigned int rr_bug;
struct tty_struct *link;
struct fasync_struct *fasync;
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index e731f97..468a410 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -268,6 +268,7 @@
* @otg: USB OTG Transceiver structure.
* @pdata: otg device platform data.
* @irq: IRQ number assigned for HSUSB controller.
+ * @async_irq: IRQ number used by some controllers during low power state
* @clk: clock struct of alt_core_clk.
* @pclk: clock struct of iface_clk.
* @phy_reset_clk: clock struct of phy_clk.
@@ -276,7 +277,7 @@
* @inputs: OTG state machine inputs(Id, SessValid etc).
* @sm_work: OTG state machine work.
* @in_lpm: indicates low power mode (LPM) state.
- * @async_int: Async interrupt arrived.
+ * @async_int: IRQ line on which ASYNC interrupt arrived in LPM.
* @cur_power: The amount of mA available from downstream port.
* @chg_work: Charger detection work.
* @chg_state: The state of charger detection process.
@@ -298,6 +299,7 @@
struct usb_phy phy;
struct msm_otg_platform_data *pdata;
int irq;
+ int async_irq;
struct clk *clk;
struct clk *pclk;
struct clk *phy_reset_clk;
@@ -376,6 +378,7 @@
unsigned strobe;
unsigned data;
struct msm_bus_scale_pdata *bus_scale_table;
+ unsigned log2_irq_thresh;
};
struct msm_usb_host_platform_data {
@@ -394,6 +397,12 @@
bool core_clk_always_on_workaround;
};
+enum usb_pipe_mem_type {
+ SPS_PIPE_MEM = 0, /* Default, SPS dedicated pipe memory */
+ USB_PRIVATE_MEM, /* USB's private memory */
+ SYSTEM_MEM, /* System RAM, requires allocation */
+};
+
/**
* struct usb_bam_pipe_connect: pipe connection information
* between USB/HSIC BAM and another BAM. USB/HSIC BAM can be
@@ -402,6 +411,7 @@
* @src_pipe_index: src bam pipe index.
* @dst_phy_addr: dst bam physical address.
* @dst_pipe_index: dst bam pipe index.
+ * @mem_type: type of memory used for BAM FIFOs
* @data_fifo_base_offset: data fifo offset.
* @data_fifo_size: data fifo size.
* @desc_fifo_base_offset: descriptor fifo offset.
@@ -412,6 +422,7 @@
u32 src_pipe_index;
u32 dst_phy_addr;
u32 dst_pipe_index;
+ enum usb_pipe_mem_type mem_type;
u32 data_fifo_base_offset;
u32 data_fifo_size;
u32 desc_fifo_base_offset;
@@ -437,8 +448,10 @@
};
enum usb_bam {
- HSUSB_BAM = 0,
+ SSUSB_BAM = 0,
+ HSUSB_BAM,
HSIC_BAM,
+ MAX_BAMS,
};
#ifdef CONFIG_USB_DWC3_MSM
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 516f764..a040d49 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -29,6 +29,7 @@
#define USBCMD_RESET 2
#define USB_USBINTR (MSM_USB_BASE + 0x0148)
+#define USB_FRINDEX (MSM_USB_BASE + 0x014C)
#define PORTSC_PHCD (1 << 23) /* phy suspend mode */
#define PORTSC_PTS_MASK (3 << 30)
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index acd0fa3..484d08f 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -113,6 +113,9 @@
#define VCD_METADATA_PASSTHROUGH 0x080
#define VCD_METADATA_ENC_SLICE 0x100
+#define VCD_METADATA_EXT_DATA 0x0800
+#define VCD_METADATA_USER_DATA 0x1000
+
struct vcd_property_meta_data_enable {
u32 meta_data_enable_flag;
};
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index b27debc..f95230e 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -16,6 +16,7 @@
#ifdef MSM_CAMERA_BIONIC
#include <sys/types.h>
#endif
+#include <linux/videodev2.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#ifdef __KERNEL__
@@ -151,7 +152,7 @@
_IOW(MSM_CAM_IOCTL_MAGIC, 39, struct msm_camera_st_frame *)
#define MSM_CAM_IOCTL_V4L2_EVT_NOTIFY \
- _IOR(MSM_CAM_IOCTL_MAGIC, 40, struct v4l2_event *)
+ _IOW(MSM_CAM_IOCTL_MAGIC, 40, struct v4l2_event_and_payload)
#define MSM_CAM_IOCTL_SET_MEM_MAP_INFO \
_IOR(MSM_CAM_IOCTL_MAGIC, 41, struct msm_mem_map_info *)
@@ -216,6 +217,24 @@
#define MSM_CAM_IOCTL_STATS_UNREG_BUF \
_IOR(MSM_CAM_IOCTL_MAGIC, 61, struct msm_stats_flush_bufq *)
+#define MSM_CAM_IOCTL_CSIC_IO_CFG \
+ _IOWR(MSM_CAM_IOCTL_MAGIC, 62, struct csic_cfg_data *)
+
+#define MSM_CAM_IOCTL_CSID_IO_CFG \
+ _IOWR(MSM_CAM_IOCTL_MAGIC, 63, struct csid_cfg_data *)
+
+#define MSM_CAM_IOCTL_CSIPHY_IO_CFG \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 64, struct csiphy_cfg_data *)
+
+#define MSM_CAM_IOCTL_OEM \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 65, struct sensor_cfg_data *)
+
+struct v4l2_event_and_payload {
+ struct v4l2_event evt;
+ uint32_t payload_length;
+ uint32_t transaction_id;
+ void *payload;
+};
struct msm_stats_reqbuf {
int num_buf; /* how many buffers requested */
@@ -350,6 +369,27 @@
uint32_t inst_handle;
};
+struct msm_pp_crop {
+ uint32_t src_x;
+ uint32_t src_y;
+ uint32_t src_w;
+ uint32_t src_h;
+ uint32_t dst_x;
+ uint32_t dst_y;
+ uint32_t dst_w;
+ uint32_t dst_h;
+ uint8_t update_flag;
+};
+
+struct msm_mctl_pp_frame_cmd {
+ uint32_t cookie;
+ uint8_t vpe_output_action;
+ struct msm_pp_frame src_frame;
+ struct msm_pp_frame dest_frame;
+ struct msm_pp_crop crop;
+ int path;
+};
+
struct msm_cam_evt_divert_frame {
unsigned short image_mode;
unsigned short op_mode;
@@ -486,8 +526,8 @@
#define CMD_STATS_BG_BUF_RELEASE 56
#define CMD_STATS_BF_BUF_RELEASE 57
#define CMD_STATS_BHIST_BUF_RELEASE 58
-#define CMD_VFE_SOF_COUNT_UPDATE 59
-#define CMD_VFE_COUNT_SOF_ENABLE 60
+#define CMD_VFE_PIX_SOF_COUNT_UPDATE 59
+#define CMD_VFE_COUNT_PIX_SOF_ENABLE 60
#define CMD_AXI_CFG_PRIM BIT(8)
#define CMD_AXI_CFG_PRIM_ALL_CHNLS BIT(9)
@@ -499,6 +539,8 @@
#define CMD_AXI_START 0xE1
#define CMD_AXI_STOP 0xE2
#define CMD_AXI_RESET 0xE3
+#define CMD_AXI_ABORT 0xE4
+
#define AXI_CMD_PREVIEW BIT(0)
@@ -583,6 +625,7 @@
MSM_STATS_TYPE_BF, /* Bayer Focus */
MSM_STATS_TYPE_BHIST, /* Bayer Hist */
MSM_STATS_TYPE_AE_AW, /* legacy stats for vfe 2.x*/
+ MSM_STATS_TYPE_COMP, /* Composite stats */
MSM_STATS_TYPE_MAX /* MAX */
};
@@ -662,8 +705,11 @@
#define OUTPUT_TYPE_ST_D BIT(7)
#define OUTPUT_TYPE_R BIT(8)
#define OUTPUT_TYPE_R1 BIT(9)
-
-
+#define OUTPUT_TYPE_SAEC BIT(10)
+#define OUTPUT_TYPE_SAFC BIT(11)
+#define OUTPUT_TYPE_SAWB BIT(12)
+#define OUTPUT_TYPE_IHST BIT(13)
+#define OUTPUT_TYPE_CSTA BIT(14)
struct fd_roi_info {
void *info;
@@ -778,27 +824,39 @@
/* extendedmode for the thumb nail image in VIDIOC_S_PARM */
#define MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+4)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RAW \
+/* ISP_PIX_OUTPUT1: no pp, directly send output1 buf to user */
+#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT1 \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+5)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RDI \
+/* ISP_PIX_OUTPUT2: no pp, directly send output2 buf to user */
+#define MSM_V4L2_EXT_CAPTURE_MODE_ISP_PIX_OUTPUT2 \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+6)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RDI1 \
+/* raw image type */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RAW \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+7)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RDI2 \
+/* RDI dump */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+8)
-#define MSM_V4L2_EXT_CAPTURE_MODE_AEC \
+/* RDI dump 1 */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI1 \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+9)
-#define MSM_V4L2_EXT_CAPTURE_MODE_AWB \
+/* RDI dump 2 */
+#define MSM_V4L2_EXT_CAPTURE_MODE_RDI2 \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+10)
-#define MSM_V4L2_EXT_CAPTURE_MODE_AF \
+#define MSM_V4L2_EXT_CAPTURE_MODE_AEC \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+11)
-#define MSM_V4L2_EXT_CAPTURE_MODE_IHIST \
+#define MSM_V4L2_EXT_CAPTURE_MODE_AWB \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+12)
-#define MSM_V4L2_EXT_CAPTURE_MODE_CS \
+#define MSM_V4L2_EXT_CAPTURE_MODE_AF \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+13)
-#define MSM_V4L2_EXT_CAPTURE_MODE_RS \
+#define MSM_V4L2_EXT_CAPTURE_MODE_IHIST \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+14)
-#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+15)
+#define MSM_V4L2_EXT_CAPTURE_MODE_CS \
+ (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+15)
+#define MSM_V4L2_EXT_CAPTURE_MODE_RS \
+ (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+16)
+#define MSM_V4L2_EXT_CAPTURE_MODE_CSTA \
+ (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+17)
+#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+18)
#define MSM_V4L2_PID_MOTION_ISO V4L2_CID_PRIVATE_BASE
#define MSM_V4L2_PID_EFFECT (V4L2_CID_PRIVATE_BASE+1)
@@ -851,7 +909,8 @@
#define MSM_V4L2_CLOSE 11
#define MSM_V4L2_SET_CTRL_CMD 12
#define MSM_V4L2_EVT_SUB_MASK 13
-#define MSM_V4L2_MAX 14
+#define MSM_V4L2_PRIVATE_CMD 14
+#define MSM_V4L2_MAX 15
#define V4L2_CAMERA_EXIT 43
struct crop_info {
@@ -918,7 +977,15 @@
#define CFG_START_STREAM 44
#define CFG_STOP_STREAM 45
#define CFG_GET_CSI_PARAMS 46
-#define CFG_MAX 47
+#define CFG_POWER_UP 47
+#define CFG_POWER_DOWN 48
+#define CFG_WRITE_I2C_ARRAY 49
+#define CFG_READ_I2C_ARRAY 50
+#define CFG_PCLK_CHANGE 51
+#define CFG_CONFIG_VREG_ARRAY 52
+#define CFG_CONFIG_CLK_ARRAY 53
+#define CFG_GPIO_OP 54
+#define CFG_MAX 55
#define MOVE_NEAR 0
@@ -1233,6 +1300,33 @@
uint16_t num_info;
};
+struct msm_sensor_exp_gain_info_t {
+ uint16_t coarse_int_time_addr;
+ uint16_t global_gain_addr;
+ uint16_t vert_offset;
+};
+
+struct msm_sensor_output_reg_addr_t {
+ uint16_t x_output;
+ uint16_t y_output;
+ uint16_t line_length_pclk;
+ uint16_t frame_length_lines;
+};
+
+struct sensor_driver_params_type {
+ struct msm_camera_i2c_reg_setting *init_settings;
+ uint16_t init_settings_size;
+ struct msm_camera_i2c_reg_setting *mode_settings;
+ uint16_t mode_settings_size;
+ struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr;
+ struct msm_camera_i2c_reg_setting *start_settings;
+ struct msm_camera_i2c_reg_setting *stop_settings;
+ struct msm_camera_i2c_reg_setting *groupon_settings;
+ struct msm_camera_i2c_reg_setting *groupoff_settings;
+ struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info;
+ struct msm_sensor_output_info_t *output_info;
+};
+
struct mirror_flip {
int32_t x_mirror;
int32_t y_flip;
@@ -1255,11 +1349,81 @@
};
struct csi_lane_params_t {
- uint8_t csi_lane_assign;
+ uint16_t csi_lane_assign;
uint8_t csi_lane_mask;
uint8_t csi_if;
- uint8_t csid_core;
- uint32_t csid_version;
+ uint8_t csid_core[2];
+};
+
+struct msm_camera_csid_lut_params {
+ uint8_t num_cid;
+ struct msm_camera_csid_vc_cfg *vc_cfg;
+};
+
+struct msm_camera_csid_params {
+ uint8_t lane_cnt;
+ uint16_t lane_assign;
+ uint8_t phy_sel;
+ struct msm_camera_csid_lut_params lut_params;
+};
+
+struct msm_camera_csiphy_params {
+ uint8_t lane_cnt;
+ uint8_t settle_cnt;
+ uint16_t lane_mask;
+ uint8_t combo_mode;
+};
+
+struct msm_camera_csi2_params {
+ struct msm_camera_csid_params csid_params;
+ struct msm_camera_csiphy_params csiphy_params;
+};
+
+enum msm_camera_csi_data_format {
+ CSI_8BIT,
+ CSI_10BIT,
+ CSI_12BIT,
+};
+
+struct msm_camera_csi_params {
+ enum msm_camera_csi_data_format data_format;
+ uint8_t lane_cnt;
+ uint8_t lane_assign;
+ uint8_t settle_cnt;
+ uint8_t dpcm_scheme;
+};
+
+enum csic_cfg_type_t {
+ CSIC_INIT,
+ CSIC_CFG,
+};
+
+struct csic_cfg_data {
+ enum csic_cfg_type_t cfgtype;
+ struct msm_camera_csi_params *csic_params;
+};
+
+enum csid_cfg_type_t {
+ CSID_INIT,
+ CSID_CFG,
+};
+
+struct csid_cfg_data {
+ enum csid_cfg_type_t cfgtype;
+ union {
+ uint32_t csid_version;
+ struct msm_camera_csid_params *csid_params;
+ } cfg;
+};
+
+enum csiphy_cfg_type_t {
+ CSIPHY_INIT,
+ CSIPHY_CFG,
+};
+
+struct csiphy_cfg_data {
+ enum csiphy_cfg_type_t cfgtype;
+ struct msm_camera_csiphy_params *csiphy_params;
};
#define CSI_EMBED_DATA 0x12
@@ -1359,6 +1523,81 @@
} cfg;
};
+enum msm_camera_i2c_reg_addr_type {
+ MSM_CAMERA_I2C_BYTE_ADDR = 1,
+ MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+struct msm_camera_i2c_reg_array {
+ uint16_t reg_addr;
+ uint16_t reg_data;
+};
+
+enum msm_camera_i2c_data_type {
+ MSM_CAMERA_I2C_BYTE_DATA = 1,
+ MSM_CAMERA_I2C_WORD_DATA,
+ MSM_CAMERA_I2C_SET_BYTE_MASK,
+ MSM_CAMERA_I2C_UNSET_BYTE_MASK,
+ MSM_CAMERA_I2C_SET_WORD_MASK,
+ MSM_CAMERA_I2C_UNSET_WORD_MASK,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
+};
+
+struct msm_camera_i2c_reg_setting {
+ struct msm_camera_i2c_reg_array *reg_setting;
+ uint16_t size;
+ enum msm_camera_i2c_reg_addr_type addr_type;
+ enum msm_camera_i2c_data_type data_type;
+ uint16_t delay;
+};
+
+enum oem_setting_type {
+ I2C_READ = 1,
+ I2C_WRITE,
+ GPIO_OP,
+ EEPROM_READ,
+ VREG_SET,
+ CLK_SET,
+};
+
+struct sensor_oem_setting {
+ enum oem_setting_type type;
+ void *data;
+};
+
+enum camera_vreg_type {
+ REG_LDO,
+ REG_VS,
+ REG_GPIO,
+};
+
+struct camera_vreg_t {
+ const char *reg_name;
+ enum camera_vreg_type type;
+ int min_voltage;
+ int max_voltage;
+ int op_mode;
+ uint32_t delay;
+};
+
+struct msm_camera_vreg_setting {
+ struct camera_vreg_t *cam_vreg;
+ uint16_t num_vreg;
+ uint8_t enable;
+};
+
+struct msm_cam_clk_info {
+ const char *clk_name;
+ long clk_rate;
+ uint32_t delay;
+};
+
+struct msm_cam_clk_setting {
+ struct msm_cam_clk_info *clk_info;
+ uint16_t num_clk_info;
+ uint8_t enable;
+};
+
struct sensor_cfg_data {
int cfgtype;
int mode;
@@ -1395,12 +1634,30 @@
int ae_mode;
uint8_t wb_val;
int8_t exp_compensation;
+ uint32_t pclk;
struct cord aec_cord;
int is_autoflash;
struct mirror_flip mirror_flip;
+ void *setting;
} cfg;
};
+enum gpio_operation_type {
+ GPIO_REQUEST,
+ GPIO_FREE,
+ GPIO_SET_DIRECTION_OUTPUT,
+ GPIO_SET_DIRECTION_INPUT,
+ GPIO_GET_VALUE,
+ GPIO_SET_VALUE,
+};
+
+struct msm_cam_gpio_operation {
+ enum gpio_operation_type op_type;
+ unsigned address;
+ int value;
+ const char *tag;
+};
+
struct damping_params_t {
uint32_t damping_step;
uint32_t damping_delay;
@@ -1557,11 +1814,17 @@
struct pixel_t video_coord[128];
};
+struct msm_calib_raw {
+ uint8_t *data;
+ uint32_t size;
+};
+
struct msm_camera_eeprom_info_t {
struct msm_eeprom_support af;
struct msm_eeprom_support wb;
struct msm_eeprom_support lsc;
struct msm_eeprom_support dpc;
+ struct msm_eeprom_support raw;
};
struct msm_eeprom_cfg_data {
@@ -1734,6 +1997,9 @@
#define MSM_CAM_V4L2_IOCTL_PRIVATE_G_CTRL \
_IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl_t)
+#define MSM_CAM_V4L2_IOCTL_PRIVATE_GENERAL \
+ _IOW('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl_t)
+
#define VIDIOC_MSM_VPE_INIT \
_IO('V', BASE_VIDIOC_PRIVATE + 15)
@@ -1758,22 +2024,27 @@
#define VIDIOC_MSM_AXI_BUF_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 22, void *)
+#define VIDIOC_MSM_AXI_RDI_COUNT_UPDATE \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct rdi_count_msg)
+
#define VIDIOC_MSM_VFE_INIT \
- _IO('V', BASE_VIDIOC_PRIVATE + 22)
+ _IO('V', BASE_VIDIOC_PRIVATE + 24)
#define VIDIOC_MSM_VFE_RELEASE \
- _IO('V', BASE_VIDIOC_PRIVATE + 23)
+ _IO('V', BASE_VIDIOC_PRIVATE + 25)
struct msm_camera_v4l2_ioctl_t {
uint32_t id;
- void __user *ioctl_ptr;
uint32_t len;
+ uint32_t trans_code;
+ void __user *ioctl_ptr;
};
struct msm_camera_vfe_params_t {
uint32_t operation_mode;
uint32_t capture_count;
uint32_t skip_abort;
+ uint8_t stop_immediately;
uint16_t port_info;
uint32_t inst_handle;
uint16_t cmd_type;
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 9fa5932..faaa522 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -68,6 +68,9 @@
#define MSG_ID_RDI0_UPDATE_ACK 49
#define MSG_ID_RDI1_UPDATE_ACK 50
#define MSG_ID_RDI2_UPDATE_ACK 51
+#define MSG_ID_PIX0_UPDATE_ACK 52
+#define MSG_ID_PREV_STOP_ACK 53
+
/* ISP command IDs */
#define VFE_CMD_DUMMY_0 0
@@ -324,30 +327,10 @@
struct msm_vpe_clock_rate {
uint32_t rate;
};
-struct msm_pp_crop {
- uint32_t src_x;
- uint32_t src_y;
- uint32_t src_w;
- uint32_t src_h;
- uint32_t dst_x;
- uint32_t dst_y;
- uint32_t dst_w;
- uint32_t dst_h;
- uint8_t update_flag;
-};
+
#define MSM_MCTL_PP_VPE_FRAME_ACK (1<<0)
#define MSM_MCTL_PP_VPE_FRAME_TO_APP (1<<1)
-struct msm_mctl_pp_frame_cmd {
- uint32_t cookie;
- uint8_t vpe_output_action;
- uint32_t src_buf_handle;
- uint32_t dest_buf_handle;
- struct msm_pp_crop crop;
- int path;
- /* TBD: 3D related */
-};
-
#define VFE_OUTPUTS_MAIN_AND_PREVIEW BIT(0)
#define VFE_OUTPUTS_MAIN_AND_VIDEO BIT(1)
#define VFE_OUTPUTS_MAIN_AND_THUMB BIT(2)
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index baa6a28..2efe31c 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -44,6 +44,7 @@
int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec);
+int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc);
int msm_vidc_poll(void *instance, struct file *filp,
struct poll_table_struct *pt);
#endif
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index a15d1f1..2918b94 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -289,6 +289,7 @@
atomic_t queued_count;
struct list_head done_list;
spinlock_t done_lock;
+ struct mutex q_lock;
wait_queue_head_t done_wq;
void *alloc_ctx[VIDEO_MAX_PLANES];
diff --git a/include/media/videobuf2-msm-mem.h b/include/media/videobuf2-msm-mem.h
index 84e2bea..5285997 100644
--- a/include/media/videobuf2-msm-mem.h
+++ b/include/media/videobuf2-msm-mem.h
@@ -72,9 +72,10 @@
struct videobuf2_msm_offset *offset,
enum videobuf2_buffer_type,
uint32_t addr_offset, int path,
- struct ion_client *client);
+ struct ion_client *client,
+ int domain_num);
void videobuf2_pmem_contig_user_put(struct videobuf2_contig_pmem *mem,
- struct ion_client *client);
+ struct ion_client *client, int domain_num);
unsigned long videobuf2_to_pmem_contig(struct vb2_buffer *buf,
unsigned int plane_no);
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 3526e29..80f36e0 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -967,6 +967,26 @@
#define HCI_OP_LE_CREATE_CONN_CANCEL 0x200e
+#define HCI_OP_LE_READ_WHITE_LIST_SIZE 0x200F
+struct hci_rp_le_read_white_list_size {
+ __u8 status;
+ __u8 size;
+} __packed;
+
+#define HCI_OP_LE_CLEAR_WHITE_LIST 0x2010
+
+#define HCI_OP_LE_ADD_DEV_WHITE_LIST 0x2011
+struct hci_cp_le_add_dev_white_list {
+ __u8 addr_type;
+ bdaddr_t addr;
+} __packed;
+
+#define HCI_OP_LE_REMOVE_DEV_WHITE_LIST 0x2012
+struct hci_cp_le_remove_dev_white_list {
+ __u8 addr_type;
+ bdaddr_t addr;
+} __packed;
+
#define HCI_OP_LE_CONN_UPDATE 0x2013
struct hci_cp_le_conn_update {
__le16 handle;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 22428c1..e8c0bf3 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -191,6 +191,7 @@
unsigned int acl_pkts;
unsigned int sco_pkts;
unsigned int le_pkts;
+ unsigned int le_white_list_size;
unsigned int data_block_len;
@@ -602,6 +603,9 @@
bdaddr_t *dst, __u8 sec_level,
__u8 auth_type,
struct bt_le_params *le_params);
+void hci_le_add_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst);
+void hci_le_remove_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst);
+void hci_le_cancel_create_connect(struct hci_dev *hdev, bdaddr_t *dst);
int hci_conn_check_link_mode(struct hci_conn *conn);
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
int hci_conn_change_link_key(struct hci_conn *conn);
@@ -1035,7 +1039,7 @@
int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le);
int mgmt_le_conn_params(u16 index, bdaddr_t *bdaddr, u16 interval,
u16 latency, u16 timeout);
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
+int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason);
int mgmt_disconnect_failed(u16 index);
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 3048339..602fe59 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -60,6 +60,7 @@
__u8 hci_ver;
__u16 hci_rev;
__u8 name[MGMT_MAX_NAME_LENGTH];
+ __u8 le_white_list_size;
} __packed;
struct mgmt_mode {
@@ -246,6 +247,26 @@
bdaddr_t bdaddr;
} __packed;
+#define MGMT_OP_LE_READ_WHITE_LIST_SIZE 0xE000
+
+#define MGMT_OP_LE_CLEAR_WHITE_LIST 0xE001
+
+#define MGMT_OP_LE_ADD_DEV_WHITE_LIST 0xE002
+struct mgmt_cp_le_add_dev_white_list {
+ __u8 addr_type;
+ bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_OP_LE_REMOVE_DEV_WHITE_LIST 0xE003
+struct mgmt_cp_le_remove_dev_white_list {
+ __u8 addr_type;
+ bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_OP_LE_CREATE_CONN_WHITE_LIST 0xE004
+
+#define MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST 0xE005
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
@@ -290,6 +311,7 @@
#define MGMT_EV_DISCONNECTED 0x000C
struct mgmt_ev_disconnected {
bdaddr_t bdaddr;
+ __u8 reason;
} __packed;
#define MGMT_EV_CONNECT_FAILED 0x000D
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 979db58..90872c9 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -561,6 +561,7 @@
#define ADM_CMD_COPP_CLOSE 0x00010305
#define ADM_CMD_MULTI_CHANNEL_COPP_OPEN 0x00010310
+#define ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3 0x00010333
struct adm_multi_ch_copp_open_command {
struct apr_hdr hdr;
u16 flags;
@@ -573,7 +574,6 @@
u32 rate;
u8 dev_channel_mapping[8];
} __packed;
-
#define ADM_CMD_MEMORY_MAP 0x00010C30
struct adm_cmd_memory_map{
struct apr_hdr hdr;
@@ -618,6 +618,14 @@
#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72
#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY 0x00010F75
+#define LOWLATENCY_POPP_TOPOLOGY 0x00010C68
+#define LOWLATENCY_COPP_TOPOLOGY 0x00010312
+#define PCM_BITS_PER_SAMPLE 16
+
+#define ASM_OPEN_WRITE_PERF_MODE_BIT (1<<28)
+#define ASM_OPEN_READ_PERF_MODE_BIT (1<<29)
+#define ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT (1<<13)
+
/* SRS TRUMEDIA GUIDS */
/* topology */
#define SRS_TRUMEDIA_TOPOLOGY_ID 0x00010D90
@@ -741,6 +749,7 @@
} __attribute__ ((packed));
#define ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN 0x00010311
+#define ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3 0x00010334
#define ASM_STREAM_PRIORITY_NORMAL 0
@@ -969,6 +978,16 @@
u32 sample_rate;
};
+struct asm_amrwbplus_cfg {
+ u32 size_bytes;
+ u32 version;
+ u32 num_channels;
+ u32 amr_band_mode;
+ u32 amr_dtx_mode;
+ u32 amr_frame_fmt;
+ u32 amr_lsf_idx;
+};
+
struct asm_flac_cfg {
u16 stream_info_present;
u16 min_blk_size;
@@ -1102,6 +1121,7 @@
/* Stream level commands */
#define ASM_STREAM_CMD_OPEN_READ 0x00010BCB
+#define ASM_STREAM_CMD_OPEN_READ_V2_1 0x00010DB2
struct asm_stream_cmd_open_read {
struct apr_hdr hdr;
u32 uMode;
@@ -1110,6 +1130,16 @@
u32 format;
} __attribute__((packed));
+struct asm_stream_cmd_open_read_v2_1 {
+ struct apr_hdr hdr;
+ u32 uMode;
+ u32 src_endpoint;
+ u32 pre_proc_top;
+ u32 format;
+ u16 bits_per_sample;
+ u16 reserved;
+} __packed;
+
/* Supported formats */
#define LINEAR_PCM 0x00010BE5
#define DTMF 0x00010BE6
@@ -1158,6 +1188,7 @@
} __packed;
#define ASM_STREAM_CMD_OPEN_WRITE 0x00010BCA
+#define ASM_STREAM_CMD_OPEN_WRITE_V2_1 0x00010DB1
struct asm_stream_cmd_open_write {
struct apr_hdr hdr;
u32 uMode;
@@ -1352,7 +1383,7 @@
u32 uid;
} __attribute__((packed));
-#define ASM_DATA_CMD_READ_COMPRESSED 0x00010DBC
+#define ASM_DATA_CMD_READ_COMPRESSED 0x00010DBF
struct asm_stream_cmd_read_compressed {
struct apr_hdr hdr;
u32 buf_add;
@@ -1377,6 +1408,7 @@
struct asm_flac_cfg flac_cfg;
struct asm_vorbis_cfg vorbis_cfg;
struct asm_multi_channel_pcm_fmt_blk multi_ch_pcm_cfg;
+ struct asm_amrwbplus_cfg amrwbplus_cfg;
} __attribute__((packed)) write_cfg;
} __attribute__((packed));
@@ -1423,7 +1455,7 @@
u32 id;
} __attribute__((packed));
-#define ASM_DATA_EVENT_READ_COMPRESSED_DONE 0x00010DBD
+#define ASM_DATA_EVENT_READ_COMPRESSED_DONE 0x00010DC0
struct asm_data_event_read_compressed_done {
u32 status;
u32 buffer_add;
diff --git a/include/sound/q6adm.h b/include/sound/q6adm.h
index 8e15955..676c4cb 100644
--- a/include/sound/q6adm.h
+++ b/include/sound/q6adm.h
@@ -27,7 +27,7 @@
int adm_open(int port, int path, int rate, int mode, int topology);
int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
- int topology);
+ int topology, int perfmode);
int adm_memory_map_regions(uint32_t *buf_add, uint32_t mempool_id,
uint32_t *bufsz, uint32_t bufcnt);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index ea77974..323a228 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -160,6 +160,7 @@
uint32_t io_mode;
uint64_t time_stamp;
atomic_t cmd_response;
+ bool perf_mode;
};
void q6asm_audio_client_free(struct audio_client *ac);
@@ -182,6 +183,7 @@
struct audio_client *ac);
int q6asm_open_read(struct audio_client *ac, uint32_t format);
+int q6asm_open_read_v2_1(struct audio_client *ac, uint32_t format);
int q6asm_open_read_compressed(struct audio_client *ac,
uint32_t frames_per_buffer, uint32_t meta_data_mode);
@@ -286,6 +288,9 @@
int q6asm_media_format_block_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
+int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
+ struct asm_amrwbplus_cfg *cfg);
+
int q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index 9271f5d..5fa311a 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -48,6 +48,48 @@
TP_ARGS(frequency, cpu_id)
);
+TRACE_EVENT(cpu_frequency_switch_start,
+
+ TP_PROTO(unsigned int start_freq, unsigned int end_freq,
+ unsigned int cpu_id),
+
+ TP_ARGS(start_freq, end_freq, cpu_id),
+
+ TP_STRUCT__entry(
+ __field( u32, start_freq )
+ __field( u32, end_freq )
+ __field( u32, cpu_id )
+ ),
+
+ TP_fast_assign(
+ __entry->start_freq = start_freq;
+ __entry->end_freq = end_freq;
+ __entry->cpu_id = cpu_id;
+ ),
+
+ TP_printk("start=%lu end=%lu cpu_id=%lu",
+ (unsigned long)__entry->start_freq,
+ (unsigned long)__entry->end_freq,
+ (unsigned long)__entry->cpu_id)
+);
+
+TRACE_EVENT(cpu_frequency_switch_end,
+
+ TP_PROTO(unsigned int cpu_id),
+
+ TP_ARGS(cpu_id),
+
+ TP_STRUCT__entry(
+ __field( u32, cpu_id )
+ ),
+
+ TP_fast_assign(
+ __entry->cpu_id = cpu_id;
+ ),
+
+ TP_printk("cpu_id=%lu", (unsigned long)__entry->cpu_id)
+);
+
TRACE_EVENT(machine_suspend,
TP_PROTO(unsigned int state),
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 431dba8..006d5c9 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -2002,7 +2002,7 @@
static int __ftrace_function_set_filter(int filter, char *buf, int len,
struct function_filter_data *data)
{
- int i, re_cnt, ret;
+ int i, re_cnt, ret = 0;
int *reset;
char **re;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 08bf42d..f57fab7 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -50,7 +50,7 @@
bdaddr_t *dst, __u8 sec_level, __u8 auth_type,
struct bt_le_params *le_params)
{
- struct hci_conn *le;
+ struct hci_conn *le, *le_wlist_conn;
struct hci_cp_le_create_conn cp;
struct adv_entry *entry;
struct link_key *key;
@@ -59,8 +59,21 @@
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
if (le) {
- hci_conn_hold(le);
- return le;
+ le_wlist_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
+ BDADDR_ANY);
+ if (!le_wlist_conn) {
+ hci_conn_hold(le);
+ return le;
+ } else {
+ BT_DBG("remove wlist conn");
+ le->out = 1;
+ le->link_mode |= HCI_LM_MASTER;
+ le->sec_level = BT_SECURITY_LOW;
+ le->type = LE_LINK;
+ hci_proto_connect_cfm(le, 0);
+ hci_conn_del(le_wlist_conn);
+ return le;
+ }
}
key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
@@ -107,8 +120,13 @@
cp.conn_latency = cpu_to_le16(BT_LE_LATENCY_DEF);
le->conn_timeout = 5;
}
- bacpy(&cp.peer_addr, &le->dst);
- cp.peer_addr_type = le->dst_type;
+ if (!bacmp(&le->dst, BDADDR_ANY)) {
+ cp.filter_policy = 0x01;
+ le->conn_timeout = 0;
+ } else {
+ bacpy(&cp.peer_addr, &le->dst);
+ cp.peer_addr_type = le->dst_type;
+ }
hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
@@ -121,6 +139,73 @@
hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
}
+void hci_le_cancel_create_connect(struct hci_dev *hdev, bdaddr_t *dst)
+{
+ struct hci_conn *le;
+
+ BT_DBG("%p", hdev);
+
+ le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
+ if (le) {
+ BT_DBG("send hci connect cancel");
+ hci_le_connect_cancel(le);
+ hci_conn_del(le);
+ }
+}
+EXPORT_SYMBOL(hci_le_cancel_create_connect);
+
+void hci_le_add_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst)
+{
+ struct hci_cp_le_add_dev_white_list cp;
+ struct adv_entry *entry;
+ struct link_key *key;
+
+ BT_DBG("%p", hdev);
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.addr, dst);
+
+ key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
+ if (!key) {
+ entry = hci_find_adv_entry(hdev, dst);
+ if (entry)
+ cp.addr_type = entry->bdaddr_type;
+ else
+ cp.addr_type = 0x00;
+ } else {
+ cp.addr_type = key->addr_type;
+ }
+
+ hci_send_cmd(hdev, HCI_OP_LE_ADD_DEV_WHITE_LIST, sizeof(cp), &cp);
+}
+EXPORT_SYMBOL(hci_le_add_dev_white_list);
+
+void hci_le_remove_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst)
+{
+ struct hci_cp_le_remove_dev_white_list cp;
+ struct adv_entry *entry;
+ struct link_key *key;
+
+ BT_DBG("%p", hdev);
+
+ memset(&cp, 0, sizeof(cp));
+ bacpy(&cp.addr, dst);
+
+ key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
+ if (!key) {
+ entry = hci_find_adv_entry(hdev, dst);
+ if (entry)
+ cp.addr_type = entry->bdaddr_type;
+ else
+ cp.addr_type = 0x00;
+ } else {
+ cp.addr_type = key->addr_type;
+ }
+
+ hci_send_cmd(hdev, HCI_OP_LE_REMOVE_DEV_WHITE_LIST, sizeof(cp), &cp);
+}
+EXPORT_SYMBOL(hci_le_remove_dev_white_list);
+
void hci_acl_connect(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index bf854c3..0cd3c3f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -305,6 +305,12 @@
/* Read LE buffer size */
hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
+
+ /* Read LE clear white list */
+ hci_send_cmd(hdev, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
+
+ /* Read LE white list size */
+ hci_send_cmd(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
}
static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 6e8500b..e5f43ec 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -426,6 +426,16 @@
hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
}
+static void hci_cc_le_clear_white_list(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ __u8 status = *((__u8 *) skb->data);
+
+ BT_DBG("%s status 0x%x", hdev->name, status);
+
+ hci_req_complete(hdev, HCI_OP_LE_CLEAR_WHITE_LIST, status);
+}
+
static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_ssp_mode *rp = (void *) skb->data;
@@ -913,6 +923,23 @@
hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
}
+static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_rp_le_read_white_list_size *rp = (void *) skb->data;
+
+ BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+ if (rp->status)
+ return;
+
+ hdev->le_white_list_size = rp->size;
+
+ BT_DBG("%s le white list %d", hdev->name, hdev->le_white_list_size);
+
+ hci_req_complete(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, rp->status);
+}
+
static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
@@ -1767,7 +1794,7 @@
struct hci_ev_disconn_complete *ev = (void *) skb->data;
struct hci_conn *conn;
- BT_DBG("%s status %d", hdev->name, ev->status);
+ BT_DBG("%s status %d reason %d", hdev->name, ev->status, ev->reason);
if (ev->status) {
hci_dev_lock(hdev);
@@ -1785,7 +1812,7 @@
conn->state = BT_CLOSED;
if (conn->type == ACL_LINK || conn->type == LE_LINK)
- mgmt_disconnected(hdev->id, &conn->dst);
+ mgmt_disconnected(hdev->id, &conn->dst, ev->reason);
if (conn->type == LE_LINK)
del_timer(&conn->smp_timer);
@@ -2253,6 +2280,14 @@
hci_cc_le_read_buffer_size(hdev, skb);
break;
+ case HCI_OP_LE_READ_WHITE_LIST_SIZE:
+ hci_cc_le_read_white_list_size(hdev, skb);
+ break;
+
+ case HCI_OP_LE_CLEAR_WHITE_LIST:
+ hci_cc_le_clear_white_list(hdev, skb);
+ break;
+
case HCI_OP_READ_RSSI:
hci_cc_read_rssi(hdev, skb);
break;
@@ -3172,11 +3207,23 @@
{
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
struct hci_conn *conn;
+ u8 white_list;
BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev);
+ /* Ignore event for LE cancel create conn whitelist */
+ if (ev->status && !bacmp(&ev->bdaddr, BDADDR_ANY))
+ goto unlock;
+
+ if (hci_conn_hash_lookup_ba(hdev, LE_LINK, BDADDR_ANY))
+ white_list = 1;
+ else
+ white_list = 0;
+
+ BT_DBG("w_list %d", white_list);
+
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
if (!conn) {
conn = hci_le_conn_add(hdev, &ev->bdaddr, ev->bdaddr_type);
@@ -3208,7 +3255,8 @@
hci_conn_hold_device(conn);
hci_conn_add_sysfs(conn);
- hci_proto_connect_cfm(conn, ev->status);
+ if (!white_list)
+ hci_proto_connect_cfm(conn, ev->status);
unlock:
hci_dev_unlock(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 72234c1..d7deaaf 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -229,6 +229,8 @@
memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
+ rp.le_white_list_size = hdev->le_white_list_size;
+
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
@@ -1450,6 +1452,185 @@
return err;
}
+static int le_add_dev_white_list(struct sock *sk, u16 index,
+ unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_le_add_dev_white_list *cp;
+ int err = 0;
+
+ BT_DBG("");
+
+ cp = (void *) data;
+
+ if (len != sizeof(*cp))
+ return cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
+ EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
+ ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ if (!test_bit(HCI_UP, &hdev->flags)) {
+ err = cmd_status(sk, index, MGMT_OP_LE_ADD_DEV_WHITE_LIST,
+ ENETDOWN);
+ goto failed;
+ }
+
+ hci_le_add_dev_white_list(hdev, &cp->bdaddr);
+
+failed:
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int le_remove_dev_white_list(struct sock *sk, u16 index,
+ unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_le_remove_dev_white_list *cp;
+ int err = 0;
+
+ BT_DBG("");
+
+ cp = (void *) data;
+
+ if (len != sizeof(*cp))
+ return cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
+ EINVAL);
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
+ ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ if (!test_bit(HCI_UP, &hdev->flags)) {
+ err = cmd_status(sk, index, MGMT_OP_LE_REMOVE_DEV_WHITE_LIST,
+ ENETDOWN);
+ goto failed;
+ }
+
+ hci_le_remove_dev_white_list(hdev, &cp->bdaddr);
+
+failed:
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int le_create_conn_white_list(struct sock *sk, u16 index)
+{
+ struct hci_dev *hdev;
+ struct hci_conn *conn;
+ u8 sec_level, auth_type;
+ struct pending_cmd *cmd;
+ bdaddr_t bdaddr;
+ int err = 0;
+
+ BT_DBG("");
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_LE_CREATE_CONN_WHITE_LIST,
+ ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ if (!test_bit(HCI_UP, &hdev->flags)) {
+ err = cmd_status(sk, index, MGMT_OP_LE_CREATE_CONN_WHITE_LIST,
+ ENETDOWN);
+ goto failed;
+ }
+
+ cmd = mgmt_pending_add(sk, MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index,
+ NULL, 0);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto failed;
+ }
+
+ sec_level = BT_SECURITY_MEDIUM;
+ auth_type = HCI_AT_GENERAL_BONDING;
+ memset(&bdaddr, 0, sizeof(bdaddr));
+ conn = hci_le_connect(hdev, 0, BDADDR_ANY, sec_level, auth_type, NULL);
+ if (IS_ERR(conn)) {
+ err = PTR_ERR(conn);
+ mgmt_pending_remove(cmd);
+ }
+
+failed:
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int le_cancel_create_conn_white_list(struct sock *sk, u16 index)
+{
+ struct hci_dev *hdev;
+ int err = 0;
+
+ BT_DBG("");
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index,
+ MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST, ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ if (!test_bit(HCI_UP, &hdev->flags)) {
+ err = cmd_status(sk, index,
+ MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST, ENETDOWN);
+ goto failed;
+ }
+
+ hci_le_cancel_create_connect(hdev, BDADDR_ANY);
+
+failed:
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
+static int le_clear_white_list(struct sock *sk, u16 index)
+{
+ struct hci_dev *hdev;
+ int err;
+
+ BT_DBG("");
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index,
+ MGMT_OP_LE_CLEAR_WHITE_LIST, ENODEV);
+
+ hci_dev_lock_bh(hdev);
+
+ if (!test_bit(HCI_UP, &hdev->flags)) {
+ err = cmd_status(sk, index,
+ MGMT_OP_LE_CLEAR_WHITE_LIST, ENETDOWN);
+ goto failed;
+ }
+
+ err = hci_send_cmd(hdev, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
+
+failed:
+ hci_dev_unlock_bh(hdev);
+ hci_dev_put(hdev);
+
+ return err;
+}
+
static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
@@ -2466,7 +2647,23 @@
case MGMT_OP_ENCRYPT_LINK:
err = encrypt_link(sk, index, buf + sizeof(*hdr), len);
break;
-
+ case MGMT_OP_LE_ADD_DEV_WHITE_LIST:
+ err = le_add_dev_white_list(sk, index, buf + sizeof(*hdr),
+ len);
+ break;
+ case MGMT_OP_LE_REMOVE_DEV_WHITE_LIST:
+ err = le_remove_dev_white_list(sk, index, buf + sizeof(*hdr),
+ len);
+ break;
+ case MGMT_OP_LE_CLEAR_WHITE_LIST:
+ err = le_clear_white_list(sk, index);
+ break;
+ case MGMT_OP_LE_CREATE_CONN_WHITE_LIST:
+ err = le_create_conn_white_list(sk, index);
+ break;
+ case MGMT_OP_LE_CANCEL_CREATE_CONN_WHITE_LIST:
+ err = le_cancel_create_conn_white_list(sk, index);
+ break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, index, opcode, 0x01);
@@ -2626,10 +2823,25 @@
int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 le)
{
struct mgmt_ev_connected ev;
+ struct pending_cmd *cmd;
+ struct hci_dev *hdev;
+
+ BT_DBG("hci%u", index);
+
+ hdev = hci_dev_get(index);
+
+ if (!hdev)
+ return -ENODEV;
bacpy(&ev.bdaddr, bdaddr);
ev.le = le;
+ cmd = mgmt_pending_find(MGMT_OP_LE_CREATE_CONN_WHITE_LIST, index);
+ if (cmd) {
+ BT_ERR("mgmt_connected remove mgmt pending white_list");
+ mgmt_pending_remove(cmd);
+ }
+
return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
}
@@ -2663,21 +2875,22 @@
mgmt_pending_remove(cmd);
}
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
+int mgmt_disconnected(u16 index, bdaddr_t *bdaddr, u8 reason)
{
struct mgmt_ev_disconnected ev;
struct sock *sk = NULL;
int err;
- mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
-
bacpy(&ev.bdaddr, bdaddr);
+ ev.reason = reason;
err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
if (sk)
sock_put(sk);
+ mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
+
return err;
}
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 776e193..4c655c2 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1726,7 +1726,7 @@
$subjectline = $line;
$sublinenr = "#$linenr & ";
# Check for Subject line less than line limit
- if (length($1) > SHORTTEXT_LIMIT) {
+ if (length($1) > SHORTTEXT_LIMIT && !($1 =~ m/Revert\ \"/)) {
WARN("LONG_SUMMARY_LINE",
"summary line over " .
SHORTTEXT_LIMIT .
@@ -1738,7 +1738,7 @@
# headers so we are now in the shorttext.
$shorttext = IN_SHORTTEXT_BLANKLINE;
$shorttext_exspc = 4;
- if (length($1) > SHORTTEXT_LIMIT) {
+ if (length($1) > SHORTTEXT_LIMIT && !($1 =~ m/Revert\ \"/)) {
WARN("LONG_SUMMARY_LINE",
"summary line over " .
SHORTTEXT_LIMIT .
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index f4f55fa..67572c3 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -38,6 +38,8 @@
#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
+#define ADC_DMIC_SEL_ADC 0
+#define ADC_DMIC_SEL_DMIC 1
#define NUM_DECIMATORS 4
#define NUM_INTERPOLATORS 3
@@ -812,17 +814,106 @@
static const struct snd_kcontrol_new sb_tx1_mux =
SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
+static int wcd9304_put_dec_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+ {
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *w = wlist->widgets[0];
+ struct snd_soc_codec *codec = w->codec;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int dec_mux, decimator;
+ char *dec_name = NULL;
+ char *widget_name = NULL;
+ char *temp;
+ u16 tx_mux_ctl_reg;
+ u8 adc_dmic_sel = 0x0;
+ int ret = 0;
+
+ if (ucontrol->value.enumerated.item[0] > e->max - 1)
+ return -EINVAL;
+
+ dec_mux = ucontrol->value.enumerated.item[0];
+
+ widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+ if (!widget_name)
+ return -ENOMEM;
+ temp = widget_name;
+
+ dec_name = strsep(&widget_name, " ");
+ widget_name = temp;
+ if (!dec_name) {
+ pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
+ if (ret < 0) {
+ pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"\
+ "dec_mux = %u\n", __func__, w->name, dec_name, decimator,
+ dec_mux);
+
+
+ switch (decimator) {
+ case 1:
+ case 2:
+ if ((dec_mux == 1) || (dec_mux == 6))
+ adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+ else
+ adc_dmic_sel = ADC_DMIC_SEL_ADC;
+ break;
+ case 3:
+ if ((dec_mux == 1) || (dec_mux == 6) || (dec_mux == 7))
+ adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+ else
+ adc_dmic_sel = ADC_DMIC_SEL_ADC;
+ break;
+ case 4:
+ if ((dec_mux == 1) || (dec_mux == 5)
+ || (dec_mux == 6) || (dec_mux == 7))
+ adc_dmic_sel = ADC_DMIC_SEL_DMIC;
+ else
+ adc_dmic_sel = ADC_DMIC_SEL_ADC;
+ break;
+ default:
+ pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
+
+ ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+out:
+ kfree(widget_name);
+ return ret;
+}
+
+#define WCD9304_DEC_ENUM(xname, xenum) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_enum_double, \
+ .get = snd_soc_dapm_get_enum_double, \
+ .put = wcd9304_put_dec_enum, \
+ .private_value = (unsigned long)&xenum }
+
static const struct snd_kcontrol_new dec1_mux =
- SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+ WCD9304_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
static const struct snd_kcontrol_new dec2_mux =
- SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+ WCD9304_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
static const struct snd_kcontrol_new dec3_mux =
- SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+ WCD9304_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
static const struct snd_kcontrol_new dec4_mux =
- SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+ WCD9304_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
static const struct snd_kcontrol_new iir1_inp1_mux =
SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
@@ -970,7 +1061,7 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- u16 tx_dmic_ctl_reg, tx_mux_ctl_reg;
+ u16 tx_dmic_ctl_reg;
u8 dmic_clk_sel, dmic_clk_en;
unsigned int dmic;
int ret;
@@ -1000,15 +1091,12 @@
return -EINVAL;
}
- tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
pr_debug("%s %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x01);
-
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
dmic_clk_sel, dmic_clk_sel);
@@ -1020,8 +1108,6 @@
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
dmic_clk_en, 0);
-
- snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x00);
break;
}
return 0;
@@ -1573,10 +1659,22 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
+ snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+ 0x30, 0x20);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+ 0x0C, 0x08);
+ }
snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+ if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
+ snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+ 0x30, 0x10);
+ snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
+ 0x0C, 0x04);
+ }
break;
}
return 0;
@@ -2018,13 +2116,16 @@
{"HEADPHONE", NULL, "HPHL"},
{"HEADPHONE", NULL, "HPHR"},
+
{"HPHL DAC", NULL, "CP"},
{"HPHR DAC", NULL, "CP"},
{"HPHL", NULL, "HPHL DAC"},
- {"HPHL DAC", "NULL", "DAC4 MUX"},
+ {"HPHL DAC", "NULL", "RX2 CHAIN"},
+ {"RX2 CHAIN", NULL, "DAC4 MUX"},
{"HPHR", NULL, "HPHR DAC"},
- {"HPHR DAC", NULL, "RX3 MIX1"},
+ {"HPHR DAC", NULL, "RX3 CHAIN"},
+ {"RX3 CHAIN", NULL, "RX3 MIX1"},
{"DAC1 MUX", "RX1", "RX1 CHAIN"},
{"DAC2 MUX", "RX1", "RX1 CHAIN"},
@@ -2313,7 +2414,7 @@
snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
if (SITAR_IS_1P0(sitar_core->version))
snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1,
- 0xFF, 0x65);
+ 0xF3, 0x61);
usleep_range(1000, 1000);
} else {
pr_err("%s: Error, Invalid bandgap settings\n", __func__);
@@ -2459,19 +2560,6 @@
return 0;
}
-static void sitar_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
- if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
- (wcd9xxx->dev->parent != NULL)) {
- pm_runtime_mark_last_busy(wcd9xxx->dev->parent);
- pm_runtime_put(wcd9xxx->dev->parent);
- }
- pr_debug("%s(): substream = %s stream = %d\n" , __func__,
- substream->name, substream->stream);
-}
-
int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
@@ -2767,7 +2855,6 @@
static struct snd_soc_dai_ops sitar_dai_ops = {
.startup = sitar_startup,
- .shutdown = sitar_shutdown,
.hw_params = sitar_hw_params,
.set_sysclk = sitar_set_dai_sysclk,
.set_fmt = sitar_set_dai_fmt,
@@ -2872,6 +2959,15 @@
return ret;
}
+static void sitar_codec_pm_runtime_put(struct wcd9xxx *sitar)
+{
+ if (sitar->dev != NULL &&
+ sitar->dev->parent != NULL) {
+ pm_runtime_mark_last_busy(sitar->dev->parent);
+ pm_runtime_put(sitar->dev->parent);
+ }
+}
+
static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -2881,9 +2977,14 @@
u32 j = 0, ret = 0;
codec->control_data = dev_get_drvdata(codec->dev->parent);
sitar = codec->control_data;
+
/* Execute the callback only if interface type is slimbus */
- if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (event == SND_SOC_DAPM_POST_PMD && (sitar != NULL))
+ sitar_codec_pm_runtime_put(sitar);
return 0;
+ }
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
@@ -2922,6 +3023,8 @@
sitar_p->dai[j].ch_tot));
sitar_p->dai[j].ch_tot = 0;
ret = sitar_codec_enable_chmask(sitar_p, event, j);
+ if (sitar != NULL)
+ sitar_codec_pm_runtime_put(sitar);
}
}
return ret;
@@ -2940,8 +3043,12 @@
sitar = codec->control_data;
/* Execute the callback only if interface type is slimbus */
- if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ if (event == SND_SOC_DAPM_POST_PMD && (sitar != NULL))
+ sitar_codec_pm_runtime_put(sitar);
return 0;
+ }
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
@@ -2980,6 +3087,8 @@
sitar_p->dai[j].ch_tot));
sitar_p->dai[j].ch_tot = 0;
ret = sitar_codec_enable_chmask(sitar_p, event, j);
+ if (sitar != NULL)
+ sitar_codec_pm_runtime_put(sitar);
}
}
return ret;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 4758829..9881640 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -4472,8 +4472,8 @@
pr_err("%s: Slim close tx/rx wait timeout\n",
__func__);
ret = -EINVAL;
- }
- ret = 0;
+ } else
+ ret = 0;
break;
}
return ret;
@@ -4486,7 +4486,7 @@
struct snd_soc_codec *codec = w->codec;
struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
u32 j = 0;
- u32 ret = 0;
+ int ret = 0;
codec->control_data = dev_get_drvdata(codec->dev->parent);
tabla = codec->control_data;
@@ -4543,13 +4543,22 @@
ret = wcd9xxx_close_slim_sch_rx(tabla,
tabla_p->dai[j].ch_num,
tabla_p->dai[j].ch_tot);
- tabla_p->dai[j].rate = 0;
- memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
- tabla_p->dai[j].ch_tot));
- tabla_p->dai[j].ch_tot = 0;
ret = tabla_codec_enable_chmask(tabla_p,
SND_SOC_DAPM_POST_PMD,
j);
+ if (ret < 0) {
+ ret = wcd9xxx_disconnect_port(tabla,
+ tabla_p->dai[j].ch_num,
+ tabla_p->dai[j].ch_tot,
+ 1);
+ pr_info("%s: Disconnect RX port ret = %d\n",
+ __func__, ret);
+ }
+ tabla_p->dai[j].rate = 0;
+ memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
+ tabla_p->dai[j].ch_tot));
+ tabla_p->dai[j].ch_tot = 0;
+
if ((tabla != NULL) &&
(tabla->dev != NULL) &&
(tabla->dev->parent != NULL)) {
@@ -4569,7 +4578,7 @@
struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
/* index to the DAI ID, for now hardcoding */
u32 j = 0;
- u32 ret = 0;
+ int ret = 0;
codec->control_data = dev_get_drvdata(codec->dev->parent);
tabla = codec->control_data;
@@ -4626,13 +4635,21 @@
ret = wcd9xxx_close_slim_sch_tx(tabla,
tabla_p->dai[j].ch_num,
tabla_p->dai[j].ch_tot);
+ ret = tabla_codec_enable_chmask(tabla_p,
+ SND_SOC_DAPM_POST_PMD,
+ j);
+ if (ret < 0) {
+ ret = wcd9xxx_disconnect_port(tabla,
+ tabla_p->dai[j].ch_num,
+ tabla_p->dai[j].ch_tot, 0);
+ pr_info("%s: Disconnect TX port, ret = %d\n",
+ __func__, ret);
+ }
+
tabla_p->dai[j].rate = 0;
memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
tabla_p->dai[j].ch_tot));
tabla_p->dai[j].ch_tot = 0;
- ret = tabla_codec_enable_chmask(tabla_p,
- SND_SOC_DAPM_POST_PMD,
- j);
if ((tabla != NULL) &&
(tabla->dev != NULL) &&
(tabla->dev->parent != NULL)) {
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 43c678d..390c314 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -56,7 +56,7 @@
obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
-snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
+snd-soc-qdsp6-objs := msm-dai-q6.o msm-pcm-q6.o msm-multi-ch-pcm-q6.o msm-lowlatency-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o msm-compr-q6.o msm-dai-stub.o
obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
obj-$(CONFIG_SND_SOC_VOICE) += msm-pcm-voice.o msm-pcm-voip.o
snd-soc-qdsp6-objs += msm-pcm-lpa.o msm-pcm-afe.o
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index a596f03..4b86f2b 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -796,7 +796,7 @@
#undef S
#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
S(v_no_mic, 30);
- S(v_hs_max, 1550);
+ S(v_hs_max, 2400);
#undef S
#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
S(c[0], 62);
@@ -814,24 +814,24 @@
btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
btn_low[0] = -50;
- btn_high[0] = 10;
- btn_low[1] = 11;
- btn_high[1] = 38;
- btn_low[2] = 39;
- btn_high[2] = 64;
- btn_low[3] = 65;
- btn_high[3] = 91;
- btn_low[4] = 92;
- btn_high[4] = 115;
- btn_low[5] = 116;
- btn_high[5] = 141;
- btn_low[6] = 142;
- btn_high[6] = 163;
- btn_low[7] = 164;
- btn_high[7] = 250;
+ btn_high[0] = 20;
+ btn_low[1] = 21;
+ btn_high[1] = 62;
+ btn_low[2] = 62;
+ btn_high[2] = 104;
+ btn_low[3] = 105;
+ btn_high[3] = 143;
+ btn_low[4] = 144;
+ btn_high[4] = 181;
+ btn_low[5] = 182;
+ btn_high[5] = 218;
+ btn_low[6] = 219;
+ btn_high[6] = 254;
+ btn_low[7] = 255;
+ btn_high[7] = 330;
n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
- n_ready[0] = 48;
- n_ready[1] = 38;
+ n_ready[0] = 80;
+ n_ready[1] = 68;
n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
n_cic[0] = 60;
n_cic[1] = 47;
@@ -1280,6 +1280,28 @@
return 0;
}
+static int msm_slim_4_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+
+ rate->min = rate->max = 48000;
+ if (rec_mode == INCALL_REC_STEREO)
+ channels->min = channels->max = 2;
+ else
+ channels->min = channels->max = 1;
+
+ pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+ channels->min, channels->max);
+ return 0;
+}
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1678,6 +1700,37 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ {
+ .name = "VoLTE",
+ .stream_name = "VoLTE",
+ .cpu_dai_name = "VoLTE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOLTE,
+ },
+ {
+ .name = "MSM8960 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-lowlatency-pcm-dsp",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
@@ -1913,7 +1966,7 @@
.codec_dai_name = "msm-stub-tx",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .be_hw_params_fixup = msm_slim_4_tx_be_hw_params_fixup,
.ops = &msm_slimbus_4_be_ops,
},
{
@@ -1979,6 +2032,9 @@
return -ENODEV;
}
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(16);
+
mbhc_cfg.calibration = def_tabla_mbhc_cal();
if (!mbhc_cfg.calibration) {
pr_err("Calibration data allocation failed\n");
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index f5bbf56..3b880ed 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -627,7 +627,7 @@
#undef S
#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
S(v_no_mic, 30);
- S(v_hs_max, 1550);
+ S(v_hs_max, 2400);
#undef S
#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
S(c[0], 62);
@@ -645,24 +645,24 @@
btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
btn_low[0] = -50;
- btn_high[0] = 10;
- btn_low[1] = 11;
- btn_high[1] = 38;
- btn_low[2] = 39;
- btn_high[2] = 64;
- btn_low[3] = 65;
- btn_high[3] = 91;
- btn_low[4] = 92;
- btn_high[4] = 115;
- btn_low[5] = 116;
- btn_high[5] = 141;
- btn_low[6] = 142;
- btn_high[6] = 163;
- btn_low[7] = 164;
- btn_high[7] = 250;
+ btn_high[0] = 20;
+ btn_low[1] = 21;
+ btn_high[1] = 62;
+ btn_low[2] = 62;
+ btn_high[2] = 104;
+ btn_low[3] = 105;
+ btn_high[3] = 143;
+ btn_low[4] = 144;
+ btn_high[4] = 181;
+ btn_low[5] = 182;
+ btn_high[5] = 218;
+ btn_low[6] = 219;
+ btn_high[6] = 254;
+ btn_low[7] = 255;
+ btn_high[7] = 330;
n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
- n_ready[0] = 48;
- n_ready[1] = 38;
+ n_ready[0] = 80;
+ n_ready[1] = 68;
n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
n_cic[0] = 60;
n_cic[1] = 47;
@@ -1486,6 +1486,9 @@
return -ENODEV;
}
+ if (socinfo_get_pmic_model() == PMIC_MODEL_PM8917)
+ bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(16);
+
mbhc_cfg.calibration = def_tabla_mbhc_cal();
if (!mbhc_cfg.calibration) {
pr_err("Calibration data allocation failed\n");
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 35cbb5b..5df132b 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -84,10 +84,10 @@
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 1200 * 1024 * 2,
- .period_bytes_min = 4800,
+ .period_bytes_min = 2400,
.period_bytes_max = 1200 * 1024,
.periods_min = 2,
- .periods_max = 512,
+ .periods_max = 1024,
.fifo_size = 0,
};
@@ -292,6 +292,7 @@
struct asm_aac_cfg aac_cfg;
struct asm_wma_cfg wma_cfg;
struct asm_wmapro_cfg wma_pro_cfg;
+ struct asm_amrwbplus_cfg amrwb_cfg;
int ret;
pr_debug("compressed stream prepare\n");
@@ -389,6 +390,27 @@
return ret;
}
break;
+ case SND_AUDIOCODEC_AMRWB:
+ pr_debug("SND_AUDIOCODEC_AMRWB\n");
+ ret = q6asm_media_format_block(prtd->audio_client,
+ compr->codec);
+ if (ret < 0) {
+ pr_err("%s: CMD Format block failed\n", __func__);
+ return ret;
+ }
+ break;
+ case SND_AUDIOCODEC_AMRWBPLUS:
+ pr_debug("SND_AUDIOCODEC_AMRWBPLUS\n");
+ memset(&amrwb_cfg, 0x0, sizeof(struct asm_amrwbplus_cfg));
+ amrwb_cfg.size_bytes = sizeof(struct asm_amrwbplus_cfg);
+ pr_debug("calling q6asm_media_format_block_amrwbplus");
+ ret = q6asm_media_format_block_amrwbplus(prtd->audio_client,
+ &amrwb_cfg);
+ if (ret < 0) {
+ pr_err("%s: CMD Format block failed\n", __func__);
+ return ret;
+ }
+ break;
default:
return -EINVAL;
}
@@ -506,7 +528,7 @@
{
pr_debug("%s\n", __func__);
/* MP3 Block */
- compr->info.compr_cap.num_codecs = 1;
+ compr->info.compr_cap.num_codecs = 10;
compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -519,6 +541,8 @@
compr->info.compr_cap.codecs[5] = SND_AUDIOCODEC_DTS;
compr->info.compr_cap.codecs[6] = SND_AUDIOCODEC_DTS_LBR;
compr->info.compr_cap.codecs[7] = SND_AUDIOCODEC_DTS_PASS_THROUGH;
+ compr->info.compr_cap.codecs[8] = SND_AUDIOCODEC_AMRWB;
+ compr->info.compr_cap.codecs[9] = SND_AUDIOCODEC_AMRWBPLUS;
/* Add new codecs here */
}
@@ -555,7 +579,7 @@
kfree(prtd);
return -ENOMEM;
}
-
+ prtd->audio_client->perf_mode = false;
pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
@@ -768,7 +792,9 @@
}
msm_pcm_routing_reg_phy_stream(
soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream);
+ prtd->audio_client->perf_mode,
+ prtd->session_id,
+ substream->stream);
break;
}
@@ -904,10 +930,17 @@
pr_debug("SND_AUDIOCODEC_DTS\n");
compr->codec = FORMAT_DTS_LBR;
break;
- default:
- pr_debug("FORMAT_LINEAR_PCM\n");
- compr->codec = FORMAT_LINEAR_PCM;
+ case SND_AUDIOCODEC_AMRWB:
+ pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWB\n");
+ compr->codec = FORMAT_AMRWB;
break;
+ case SND_AUDIOCODEC_AMRWBPLUS:
+ pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWBPLUS\n");
+ compr->codec = FORMAT_AMR_WB_PLUS;
+ break;
+ default:
+ pr_err("msm_compr_ioctl failed..unknown codec\n");
+ return -EFAULT;
}
return 0;
case SNDRV_PCM_IOCTL1_RESET:
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 4cd4a2c..011ff29 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -203,6 +203,17 @@
.rate_min = 8000,
.rate_max = 48000,
},
+ .capture = {
+ .stream_name = "MultiMedia5 Capture",
+ .aif_name = "MM_UL5",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia5",
},
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
new file mode 100644
index 0000000..129f69f
--- /dev/null
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -0,0 +1,756 @@
+/* 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 <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/android_pmem.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#include "msm-pcm-q6.h"
+#include "msm-pcm-routing.h"
+
+static struct audio_locks the_locks;
+
+struct snd_msm {
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+};
+
+struct snd_msm_volume {
+ struct msm_audio *prtd;
+ unsigned volume;
+};
+
+#define PLAYBACK_NUM_PERIODS 4
+#define PLAYBACK_MAX_PERIOD_SIZE 1024
+#define PLAYBACK_MIN_PERIOD_SIZE 512
+#define CAPTURE_NUM_PERIODS 4
+#define CAPTURE_MIN_PERIOD_SIZE 128
+#define CAPTURE_MAX_PERIOD_SIZE 1024
+
+static struct snd_pcm_hardware msm_pcm_hardware_capture = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max = CAPTURE_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
+ .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+ .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE,
+ .periods_min = CAPTURE_NUM_PERIODS,
+ .periods_max = CAPTURE_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware_playback = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 6,
+ .buffer_bytes_max = PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE,
+ .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
+ .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE,
+ .periods_min = PLAYBACK_NUM_PERIODS,
+ .periods_max = PLAYBACK_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+ .count = ARRAY_SIZE(supported_sample_rates),
+ .list = supported_sample_rates,
+ .mask = 0,
+};
+
+static void event_handler(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv)
+{
+ struct msm_audio *prtd = priv;
+ struct snd_pcm_substream *substream = prtd->substream;
+ uint32_t *ptrmem = (uint32_t *)payload;
+ int i = 0;
+ uint32_t idx = 0;
+ uint32_t size = 0;
+
+ pr_debug("%s\n", __func__);
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE: {
+ pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+ pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+ prtd->pcm_irq_pos += prtd->pcm_count;
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ atomic_inc(&prtd->out_count);
+ wake_up(&the_locks.write_wait);
+ if (!atomic_read(&prtd->start))
+ break;
+ if (!prtd->mmap_flag)
+ break;
+ if (q6asm_is_cpu_buf_avail_nolock(IN,
+ prtd->audio_client,
+ &size, &idx)) {
+ pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+ __func__, prtd->pcm_count);
+ q6asm_write_nolock(prtd->audio_client,
+ prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+ }
+ break;
+ }
+ case ASM_DATA_CMDRSP_EOS:
+ pr_debug("ASM_DATA_CMDRSP_EOS\n");
+ prtd->cmd_ack = 1;
+ wake_up(&the_locks.eos_wait);
+ break;
+ case ASM_DATA_EVENT_READ_DONE: {
+ pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+ pr_debug("token = 0x%08x\n", token);
+ for (i = 0; i < 8; i++, ++ptrmem)
+ pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+ in_frame_info[token][0] = payload[2];
+ in_frame_info[token][1] = payload[3];
+ prtd->pcm_irq_pos += in_frame_info[token][0];
+ pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+ if (atomic_read(&prtd->in_count) <= prtd->periods)
+ atomic_inc(&prtd->in_count);
+ wake_up(&the_locks.read_wait);
+ if (prtd->mmap_flag
+ && q6asm_is_cpu_buf_avail_nolock(OUT,
+ prtd->audio_client,
+ &size, &idx))
+ q6asm_read_nolock(prtd->audio_client);
+ break;
+ }
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ case ASM_SESSION_CMD_RUN:
+ if (substream->stream
+ != SNDRV_PCM_STREAM_PLAYBACK) {
+ atomic_set(&prtd->start, 1);
+ break;
+ }
+ if (prtd->mmap_flag) {
+ pr_debug("%s:writing %d bytes buffer to dsp\n",
+ __func__, prtd->pcm_count);
+ q6asm_write_nolock(prtd->audio_client,
+ prtd->pcm_count,
+ 0, 0, NO_TIMESTAMP);
+ } else {
+ while (atomic_read(&prtd->out_needed)) {
+ pr_debug("%s:writing %d bytesto dsp\n",
+ __func__, prtd->pcm_count);
+ q6asm_write_nolock(prtd->audio_client,
+ prtd->pcm_count,
+ 0, 0, NO_TIMESTAMP);
+ atomic_dec(&prtd->out_needed);
+ wake_up(&the_locks.write_wait);
+ };
+ }
+ atomic_set(&prtd->start, 1);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+ break;
+ }
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ int ret;
+
+ pr_debug("%s\n", __func__);
+ prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_irq_pos = 0;
+ /* rate and channels are sent to audio driver */
+ prtd->samp_rate = runtime->rate;
+ prtd->channel_mode = runtime->channels;
+ if (prtd->enabled)
+ return 0;
+
+ ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
+ runtime->rate, runtime->channels);
+ if (ret < 0)
+ pr_info("%s: CMD Format block failed\n", __func__);
+
+ atomic_set(&prtd->out_count, runtime->periods);
+
+ prtd->enabled = 1;
+ prtd->cmd_ack = 0;
+
+ return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ int ret = 0;
+ int i = 0;
+ pr_debug("%s\n", __func__);
+ prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_irq_pos = 0;
+
+ /* rate and channels are sent to audio driver */
+ prtd->samp_rate = runtime->rate;
+ prtd->channel_mode = runtime->channels;
+
+ if (prtd->enabled)
+ return 0;
+
+ 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);
+ if (ret < 0)
+ pr_debug("%s: cmd cfg pcm was block failed", __func__);
+
+ for (i = 0; i < runtime->periods; i++)
+ q6asm_read(prtd->audio_client);
+ prtd->periods = runtime->periods;
+
+ prtd->enabled = 1;
+
+ return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ pr_debug("%s: Trigger start\n", __func__);
+ q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ atomic_set(&prtd->start, 0);
+ if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ break;
+ prtd->cmd_ack = 0;
+ q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+ q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ atomic_set(&prtd->start, 0);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_audio *prtd;
+ int ret = 0;
+ pr_debug("%s lowlatency\n", __func__);
+ prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+ if (prtd == NULL) {
+ pr_err("Failed to allocate memory for msm_audio\n");
+ return -ENOMEM;
+ }
+ prtd->substream = substream;
+ prtd->audio_client = q6asm_audio_client_alloc(
+ (app_cb)event_handler, prtd);
+ if (!prtd->audio_client) {
+ pr_err("%s: Could not allocate memory\n", __func__);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ prtd->audio_client->perf_mode = true;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw = msm_pcm_hardware_playback;
+ ret = q6asm_open_write(prtd->audio_client,
+ FORMAT_MULTI_CHANNEL_LINEAR_PCM);
+ if (ret < 0) {
+ pr_err("%s: pcm out open failed\n", __func__);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ }
+ /* Capture path */
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ runtime->hw = msm_pcm_hardware_capture;
+ ret = q6asm_open_read_v2_1(prtd->audio_client,
+ FORMAT_LINEAR_PCM);
+ if (ret < 0) {
+ pr_err("%s: pcm in open failed\n", __func__);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ }
+
+ pr_debug("%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->audio_client->perf_mode,
+ prtd->session_id, substream->stream);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prtd->cmd_ack = 1;
+
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_sample_rates);
+ if (ret < 0)
+ pr_err("snd_pcm_hw_constraint_list failed\n");
+ /* Ensure that buffer size is a multiple of period size */
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ pr_err("snd_pcm_hw_constraint_integer failed\n");
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ PLAYBACK_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
+ PLAYBACK_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
+ if (ret < 0) {
+ pr_err("constraint for buffer bytes min max ret = %d\n",
+ ret);
+ }
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ ret = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ CAPTURE_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
+ CAPTURE_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
+ if (ret < 0) {
+ pr_err("constraint for buffer bytes min max ret = %d\n",
+ ret);
+ }
+ }
+
+ prtd->dsp_cnt = 0;
+ runtime->private_data = prtd;
+ pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
+ pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
+ return 0;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ int fbytes = 0;
+ int xfer = 0;
+ char *bufptr = NULL;
+ void *data = NULL;
+ uint32_t idx = 0;
+ uint32_t size = 0;
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+
+ fbytes = frames_to_bytes(runtime, frames);
+ pr_debug("%s: prtd->out_count = %d\n",
+ __func__, atomic_read(&prtd->out_count));
+ ret = wait_event_timeout(the_locks.write_wait,
+ (atomic_read(&prtd->out_count)), 5 * HZ);
+ if (ret < 0) {
+ pr_err("%s: wait_event_timeout failed\n", __func__);
+ goto fail;
+ }
+
+ if (!atomic_read(&prtd->out_count)) {
+ pr_err("%s: pcm stopped out_count 0\n", __func__);
+ return 0;
+ }
+
+ data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+ bufptr = data;
+ if (bufptr) {
+ pr_debug("%s:fbytes =%d: xfer=%d size=%d\n",
+ __func__, fbytes, xfer, size);
+ xfer = fbytes;
+ if (copy_from_user(bufptr, buf, xfer)) {
+ ret = -EFAULT;
+ goto fail;
+ }
+ buf += xfer;
+ fbytes -= xfer;
+ pr_debug("%s:fbytes = %d: xfer=%d\n", __func__, fbytes, xfer);
+ if (atomic_read(&prtd->start)) {
+ pr_debug("%s:writing %d bytes of buffer to dsp\n",
+ __func__, xfer);
+ ret = q6asm_write(prtd->audio_client, xfer,
+ 0, 0, NO_TIMESTAMP);
+ if (ret < 0) {
+ ret = -EFAULT;
+ goto fail;
+ }
+ } else
+ atomic_inc(&prtd->out_needed);
+ atomic_dec(&prtd->out_count);
+ }
+fail:
+ return ret;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_audio *prtd = runtime->private_data;
+ int dir = 0;
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ dir = IN;
+ ret = wait_event_timeout(the_locks.eos_wait,
+ prtd->cmd_ack, 5 * HZ);
+ if (ret < 0)
+ pr_err("%s: CMD_EOS failed\n", __func__);
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
+
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+ return 0;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+ int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+ snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+ int fbytes = 0;
+ int xfer;
+ char *bufptr;
+ void *data = NULL;
+ static uint32_t idx;
+ static uint32_t size;
+ uint32_t offset = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = substream->runtime->private_data;
+
+
+ pr_debug("%s\n", __func__);
+ fbytes = frames_to_bytes(runtime, frames);
+
+ pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
+ pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
+ pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+
+ ret = wait_event_timeout(the_locks.read_wait,
+ (atomic_read(&prtd->in_count)), 5 * HZ);
+ if (ret < 0) {
+ pr_debug("%s: wait_event_timeout failed\n", __func__);
+ goto fail;
+ }
+ if (!atomic_read(&prtd->in_count)) {
+ pr_debug("%s: pcm stopped in_count 0\n", __func__);
+ return 0;
+ }
+ pr_debug("Checking if valid buffer is available...%08x\n",
+ (unsigned int) data);
+ data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
+ bufptr = data;
+ pr_debug("Size = %d\n", size);
+ pr_debug("fbytes = %d\n", fbytes);
+ pr_debug("idx = %d\n", idx);
+ if (bufptr) {
+ xfer = fbytes;
+ if (xfer > size)
+ xfer = size;
+ offset = in_frame_info[idx][1];
+ pr_debug("Offset value = %d\n", offset);
+ if (copy_to_user(buf, bufptr+offset, xfer)) {
+ pr_err("Failed to copy buf to user\n");
+ ret = -EFAULT;
+ goto fail;
+ }
+ fbytes -= xfer;
+ size -= xfer;
+ in_frame_info[idx][1] += xfer;
+ pr_debug("%s:fbytes = %d: size=%d: xfer=%d\n",
+ __func__, fbytes, size, xfer);
+ pr_debug(" Sending next buffer to dsp\n");
+ memset(&in_frame_info[idx], 0,
+ sizeof(uint32_t) * 2);
+ atomic_dec(&prtd->in_count);
+ ret = q6asm_read(prtd->audio_client);
+ if (ret < 0) {
+ pr_err("q6asm read failed\n");
+ ret = -EFAULT;
+ goto fail;
+ }
+ } else
+ pr_err("No valid buffer\n");
+
+ pr_debug("Returning from capture_copy... %d\n", ret);
+fail:
+ return ret;
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct msm_audio *prtd = runtime->private_data;
+ int dir = OUT;
+
+ pr_debug("%s\n", __func__);
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+
+ return 0;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+ snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+ return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_close(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_close(substream);
+ return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = msm_pcm_playback_prepare(substream);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ret = msm_pcm_capture_prepare(substream);
+ return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+
+ if (prtd->pcm_irq_pos >= prtd->pcm_size)
+ prtd->pcm_irq_pos = 0;
+
+ pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+ return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ int result = 0;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+
+ pr_debug("%s\n", __func__);
+ prtd->mmap_flag = 1;
+
+ if (runtime->dma_addr && runtime->dma_bytes) {
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ result = remap_pfn_range(vma, vma->vm_start,
+ runtime->dma_addr >> PAGE_SHIFT,
+ runtime->dma_bytes,
+ vma->vm_page_prot);
+ } else {
+ pr_err("Physical address or size of buf is NULL");
+ return -EINVAL;
+ }
+
+ return result;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct audio_buffer *buf;
+ int dir, ret;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+
+ /*
+ *TODO : Need to Add Async IO changes. All period
+ * size might not be supported.
+ */
+ ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+ prtd->audio_client,
+ (params_buffer_bytes(params) / params_periods(params)),
+ params_periods(params));
+
+ if (ret < 0) {
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
+ return -ENOMEM;
+ }
+ buf = prtd->audio_client->port[dir].buf;
+
+ pr_debug("%s:buf = %p\n", __func__, buf);
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+ dma_buf->area = buf[0].data;
+ dma_buf->addr = buf[0].phys;
+ dma_buf->bytes = params_buffer_bytes(params);
+ if (!dma_buf->area)
+ return -ENOMEM;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+ .open = msm_pcm_open,
+ .copy = msm_pcm_copy,
+ .hw_params = msm_pcm_hw_params,
+ .close = msm_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .prepare = msm_pcm_prepare,
+ .trigger = msm_pcm_trigger,
+ .pointer = msm_pcm_pointer,
+ .mmap = msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ int ret = 0;
+
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ return ret;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .ops = &msm_pcm_ops,
+ .pcm_new = msm_asoc_pcm_new,
+};
+
+static __devinit int msm_pcm_probe(struct platform_device *pdev)
+{
+ pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver msm_pcm_driver = {
+ .driver = {
+ .name = "msm-lowlatency-pcm-dsp",
+ .owner = THIS_MODULE,
+ },
+ .probe = msm_pcm_probe,
+ .remove = __devexit_p(msm_pcm_remove),
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ init_waitqueue_head(&the_locks.enable_wait);
+ init_waitqueue_head(&the_locks.eos_wait);
+ init_waitqueue_head(&the_locks.write_wait);
+ init_waitqueue_head(&the_locks.read_wait);
+
+ return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("Multi channel PCM module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index ef58dd1..a13d4da 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -337,6 +337,7 @@
kfree(prtd);
return -ENOMEM;
}
+ prtd->audio_client->perf_mode = false;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw = msm_pcm_hardware_playback;
ret = q6asm_open_write(prtd->audio_client,
@@ -364,8 +365,8 @@
prtd->session_id = prtd->audio_client->session;
msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
prtd->cmd_ack = 1;
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 269b49b..ff0fb3b 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -289,6 +289,7 @@
kfree(prtd);
return -ENOMEM;
}
+ prtd->audio_client->perf_mode = false;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
if (ret < 0) {
@@ -311,6 +312,7 @@
pr_debug("%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->audio_client->perf_mode,
prtd->session_id, substream->stream);
ret = snd_pcm_hw_constraint_list(runtime, 0,
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 942c3ea..74136dc 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -324,6 +324,7 @@
kfree(prtd);
return -ENOMEM;
}
+ prtd->audio_client->perf_mode = false;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw = msm_pcm_hardware_playback;
ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
@@ -338,6 +339,7 @@
prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
prtd->cmd_ack = 1;
@@ -443,7 +445,7 @@
prtd->audio_client);
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
- SNDRV_PCM_STREAM_PLAYBACK);
+ SNDRV_PCM_STREAM_PLAYBACK);
q6asm_audio_client_free(prtd->audio_client);
kfree(prtd);
return 0;
@@ -649,8 +651,9 @@
prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
- }
+ }
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 26dbb21..374357d 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -38,6 +38,7 @@
unsigned long port_sessions; /* track Tx BE ports -> Rx BE */
unsigned int sample_rate;
unsigned int channel;
+ bool perf_mode;
};
#define INVALID_SESSION -1
@@ -291,7 +292,8 @@
mutex_unlock(&routing_lock);
}
-void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id, int stream_type)
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
+ int stream_type)
{
int i, session_type, path_type, port_type;
struct route_payload payload;
@@ -321,6 +323,8 @@
if (eq_data[fedai_id].enable)
msm_send_eq_values(fedai_id);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+ msm_bedais[i].perf_mode = perf_mode;
if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
@@ -329,12 +333,22 @@
channels = msm_bedais[i].channel;
if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
+ ((channels == 1) || (channels == 2)) &&
+ msm_bedais[i].perf_mode) {
+ pr_debug("%s configure COPP to lowlatency mode",
+ __func__);
+ adm_multi_ch_copp_open(msm_bedais[i].port_id,
+ path_type,
+ msm_bedais[i].sample_rate,
+ msm_bedais[i].channel,
+ DEFAULT_COPP_TOPOLOGY, msm_bedais[i].perf_mode);
+ } else if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
(channels > 2))
adm_multi_ch_copp_open(msm_bedais[i].port_id,
path_type,
msm_bedais[i].sample_rate,
msm_bedais[i].channel,
- DEFAULT_COPP_TOPOLOGY);
+ DEFAULT_COPP_TOPOLOGY, msm_bedais[i].perf_mode);
else
adm_open(msm_bedais[i].port_id,
path_type,
@@ -440,18 +454,32 @@
channels = msm_bedais[reg].channel;
- if ((session_type == SESSION_TYPE_RX) && (channels > 2))
+ if ((session_type == SESSION_TYPE_RX) &&
+ ((channels == 1) || (channels == 2))
+ && msm_bedais[reg].perf_mode) {
adm_multi_ch_copp_open(msm_bedais[reg].port_id,
path_type,
msm_bedais[reg].sample_rate,
channels,
- DEFAULT_COPP_TOPOLOGY);
+ DEFAULT_COPP_TOPOLOGY,
+ msm_bedais[reg].perf_mode);
+ pr_debug("%s:configure COPP to lowlatency mode",
+ __func__);
+ } else if ((session_type == SESSION_TYPE_RX)
+ && (channels > 2))
+ adm_multi_ch_copp_open(msm_bedais[reg].port_id,
+ path_type,
+ msm_bedais[reg].sample_rate,
+ channels,
+ DEFAULT_COPP_TOPOLOGY,
+ msm_bedais[reg].perf_mode);
else
adm_open(msm_bedais[reg].port_id,
path_type,
msm_bedais[reg].sample_rate, channels,
DEFAULT_COPP_TOPOLOGY);
+
msm_pcm_routing_build_matrix(val,
fe_dai_map[val][session_type], path_type);
srs_port_id = msm_bedais[reg].port_id;
@@ -1375,6 +1403,12 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul5_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new mmul4_mixer_controls[] = {
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
@@ -2023,6 +2057,7 @@
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@@ -2122,6 +2157,8 @@
mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia4 Mixer", SND_SOC_NOPM, 0, 0,
mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2280,6 +2317,7 @@
{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
{"MultiMedia1 Mixer", "SLIM_4_TX", "SLIMBUS_4_TX"},
+ {"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -2320,6 +2358,7 @@
{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
{"MM_UL4", NULL, "MultiMedia4 Mixer"},
+ {"MM_UL5", NULL, "MultiMedia5 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2553,6 +2592,7 @@
bedai->active = 0;
bedai->sample_rate = 0;
bedai->channel = 0;
+ bedai->perf_mode = false;
mutex_unlock(&routing_lock);
return 0;
@@ -2565,6 +2605,7 @@
int i, path_type, session_type;
struct msm_pcm_routing_bdai_data *bedai;
u32 channels;
+ bool playback, capture;
if (be_id >= MSM_BACKEND_DAI_MAX) {
pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -2592,18 +2633,29 @@
* is started.
*/
bedai->active = 1;
+ playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ capture = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
+
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
if (fe_dai_map[i][session_type] != INVALID_SESSION) {
-
channels = bedai->channel;
- if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
- substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ if ((playback || capture)
+ && ((channels == 2) || (channels == 1)) &&
+ bedai->perf_mode) {
+ adm_multi_ch_copp_open(bedai->port_id,
+ path_type,
+ bedai->sample_rate,
+ channels,
+ DEFAULT_COPP_TOPOLOGY, bedai->perf_mode);
+ pr_debug("%s:configure COPP to lowlatency mode",
+ __func__);
+ } else if ((playback || capture)
&& (channels > 2))
adm_multi_ch_copp_open(bedai->port_id,
path_type,
bedai->sample_rate,
channels,
- DEFAULT_COPP_TOPOLOGY);
+ DEFAULT_COPP_TOPOLOGY, bedai->perf_mode);
else
adm_open(bedai->port_id,
path_type,
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 45dbf40..6b87475 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -111,8 +111,8 @@
* dspst_id: DSP audio stream ID
* stream_type: playback or capture
*/
-void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id,
- int stream_type);
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+ int dspst_id, int stream_type);
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
int stream_type, int enable);
diff --git a/sound/soc/msm/msm-pcm.h b/sound/soc/msm/msm-pcm.h
index 6e1325b..867116a 100644
--- a/sound/soc/msm/msm-pcm.h
+++ b/sound/soc/msm/msm-pcm.h
@@ -27,7 +27,7 @@
#include <mach/qdsp5/qdsp5audrecmsg.h>
#include <mach/qdsp5/qdsp5audpreproccmdi.h>
#include <mach/qdsp5/qdsp5audpreprocmsg.h>
-
+#include <mach/qdsp5/qdsp5audpp.h>
#include <../arch/arm/mach-msm/qdsp5/adsp.h>
#include <../arch/arm/mach-msm/qdsp5/audmgr.h>
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index e86db10..a577b6a 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -1015,6 +1015,53 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ {
+ .name = "VoLTE",
+ .stream_name = "VoLTE",
+ .cpu_dai_name = "VoLTE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOLTE,
+ },
+ {
+ .name = "SGLTE",
+ .stream_name = "SGLTE",
+ .cpu_dai_name = "SGLTE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_SGLTE,
+ },
+ {
+ .name = "MSM8960 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-lowlatency-pcm-dsp",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index b10a7ea..e98fe64 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -715,20 +715,20 @@
btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
btn_low[0] = -50;
- btn_high[0] = 20;
- btn_low[1] = 21;
- btn_high[1] = 62;
- btn_low[2] = 63;
- btn_high[2] = 104;
- btn_low[3] = 105;
- btn_high[3] = 143;
- btn_low[4] = 144;
- btn_high[4] = 181;
- btn_low[5] = 182;
- btn_high[5] = 218;
- btn_low[6] = 219;
- btn_high[6] = 254;
- btn_low[7] = 255;
+ btn_high[0] = 10;
+ btn_low[1] = 11;
+ btn_high[1] = 52;
+ btn_low[2] = 53;
+ btn_high[2] = 94;
+ btn_low[3] = 95;
+ btn_high[3] = 133;
+ btn_low[4] = 134;
+ btn_high[4] = 171;
+ btn_low[5] = 172;
+ btn_high[5] = 208;
+ btn_low[6] = 209;
+ btn_high[6] = 244;
+ btn_low[7] = 245;
btn_high[7] = 330;
n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
n_ready[0] = 80;
@@ -1348,6 +1348,21 @@
.codec_name = "snd-soc-dummy",
.be_id = MSM_FRONTEND_DAI_SGLTE,
},
+ {
+ .name = "MSM8960 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-lowlatency-pcm-dsp",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1739,13 +1754,21 @@
return ret;
}
- if (msm8960_configure_headset_mic_gpios()) {
- pr_err("%s Fail to configure headset mic gpios\n", __func__);
+ if (cpu_is_msm8960()) {
+ if (msm8960_configure_headset_mic_gpios()) {
+ pr_err("%s Fail to configure headset mic gpios\n",
+ __func__);
+ msm8960_headset_gpios_configured = 0;
+ } else
+ msm8960_headset_gpios_configured = 1;
+ } else {
msm8960_headset_gpios_configured = 0;
- } else
- msm8960_headset_gpios_configured = 1;
+ pr_debug("%s headset GPIO 23 and 35 not configured msm960ab",
+ __func__);
+ }
mutex_init(&cdc_mclk_mutex);
+
return ret;
}
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 3516022..545a5b9 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -823,6 +823,22 @@
.be_id = MSM_FRONTEND_DAI_VOIP,
},
{
+ .name = "Circuit-Switch Voice",
+ .stream_name = "CS-Voice",
+ .cpu_dai_name = "CS-VOICE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_CS_VOICE,
+ },
+ {
.name = "MSM8974 LPA",
.stream_name = "LPA",
.cpu_dai_name = "MultiMedia3",
@@ -837,6 +853,21 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
},
+ /* Hostless PCM purpose */
+ {
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
{
.name = "MSM8974 Compr",
.stream_name = "COMPR",
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 0327e4a..c6970f1 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -250,6 +250,18 @@
}
this_adm.apr = NULL;
}
+ pr_debug("Resetting calibration blocks");
+ for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+ /* Device calibration */
+ mem_addr_audproc[i].cal_size = 0;
+ mem_addr_audproc[i].cal_kvaddr = 0;
+ mem_addr_audproc[i].cal_paddr = 0;
+
+ /* Volume calibration */
+ mem_addr_audvol[i].cal_size = 0;
+ mem_addr_audvol[i].cal_kvaddr = 0;
+ mem_addr_audvol[i].cal_paddr = 0;
+ }
return 0;
}
@@ -294,7 +306,8 @@
switch (data->opcode) {
case ADM_CMDRSP_COPP_OPEN:
- case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN: {
+ case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN:
+ case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3: {
struct adm_copp_open_respond *open = data->payload;
if (open->copp_id == INVALID_COPP_ID) {
pr_err("%s: invalid coppid rxed %d\n",
@@ -707,7 +720,7 @@
int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
- int topology)
+ int topology, int perfmode)
{
struct adm_multi_ch_copp_open_command open;
int ret = 0;
@@ -745,7 +758,17 @@
open.hdr.pkt_size =
sizeof(struct adm_multi_ch_copp_open_command);
- open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN;
+
+ if (perfmode) {
+ pr_debug("%s Performance mode", __func__);
+ open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3;
+ open.flags = ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT;
+ open.reserved = PCM_BITS_PER_SAMPLE;
+ } else {
+ open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN;
+ open.reserved = 0;
+ }
+
memset(open.dev_channel_mapping, 0, 8);
if (channel_mode == 1) {
@@ -779,8 +802,6 @@
channel_mode);
return -EINVAL;
}
-
-
open.hdr.src_svc = APR_SVC_ADM;
open.hdr.src_domain = APR_DOMAIN_APPS;
open.hdr.src_port = port_id;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 06be186..1aac158 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -209,6 +209,7 @@
session[ac->session] = 0;
mutex_unlock(&session_lock);
ac->session = 0;
+ ac->perf_mode = false;
return;
}
@@ -412,6 +413,7 @@
ac->cb = cb;
ac->priv = priv;
ac->io_mode = SYNC_IO_MODE;
+ ac->perf_mode = false;
ac->apr = apr_register("ADSP", "ASM", \
(apr_fn)q6asm_callback,\
((ac->session) << 8 | 0x0001),\
@@ -844,6 +846,7 @@
if (data->opcode == APR_BASIC_RSP_RESULT) {
token = data->token;
+ pr_debug("%s payload[0]:%x", __func__, payload[0]);
switch (payload[0]) {
case ASM_STREAM_CMD_SET_PP_PARAMS:
if (rtac_make_asm_callback(ac->session, payload,
@@ -863,7 +866,9 @@
return -EINVAL;
}
case ASM_STREAM_CMD_OPEN_READ:
+ case ASM_STREAM_CMD_OPEN_READ_V2_1:
case ASM_STREAM_CMD_OPEN_WRITE:
+ case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
case ASM_STREAM_CMD_OPEN_READWRITE:
case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
@@ -871,8 +876,11 @@
case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
if (atomic_read(&ac->cmd_state) && wakeup_flag) {
atomic_set(&ac->cmd_state, 0);
- if (payload[1] == ADSP_EUNSUPPORTED)
+ if (payload[1] == ADSP_EUNSUPPORTED) {
+ pr_debug("paload[1]:%d unsupported",
+ payload[1]);
atomic_set(&ac->cmd_response, 1);
+ }
else
atomic_set(&ac->cmd_response, 0);
wake_up(&ac->cmd_wait);
@@ -1276,6 +1284,82 @@
return -EINVAL;
}
+int q6asm_open_read_v2_1(struct audio_client *ac,
+ uint32_t format)
+{
+ int rc = 0x00;
+ struct asm_stream_cmd_open_read_v2_1 open;
+#ifdef CONFIG_DEBUG_FS
+ in_cont_index = 0;
+#endif
+ if ((ac == NULL) || (ac->apr == NULL)) {
+ pr_err("%s: APR handle NULL\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s:session[%d]", __func__, ac->session);
+
+ q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V2_1;
+ open.src_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+ open.pre_proc_top = get_asm_topology();
+ if (open.pre_proc_top == 0)
+ open.pre_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+ switch (format) {
+ case FORMAT_LINEAR_PCM:
+ open.uMode = STREAM_PRIORITY_HIGH;
+ open.format = LINEAR_PCM;
+ break;
+ case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+ open.uMode = STREAM_PRIORITY_HIGH;
+ open.format = MULTI_CHANNEL_PCM;
+ break;
+ case FORMAT_MPEG4_AAC:
+ open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+ open.format = MPEG4_AAC;
+ break;
+ case FORMAT_V13K:
+ open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+ open.format = V13K_FS;
+ break;
+ case FORMAT_EVRC:
+ open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+ open.format = EVRC_FS;
+ break;
+ case FORMAT_AMRNB:
+ open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+ open.format = AMRNB_FS;
+ break;
+ case FORMAT_AMRWB:
+ open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+ open.format = AMRWB_FS;
+ break;
+ default:
+ pr_err("Invalid format[%d]\n", format);
+ goto fail_cmd;
+ }
+ open.uMode = ASM_OPEN_READ_PERF_MODE_BIT;
+ open.bits_per_sample = PCM_BITS_PER_SAMPLE;
+ open.reserved = 0;
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+ if (rc < 0) {
+ pr_err("open failed op[0x%x]rc[%d]\n", \
+ open.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+ rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
+
int q6asm_open_read_compressed(struct audio_client *ac,
uint32_t frames_per_buffer, uint32_t meta_data_mode)
{
@@ -1396,12 +1480,20 @@
q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
- open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE;
- open.uMode = STREAM_PRIORITY_HIGH;
- /* source endpoint : matrix */
- open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
- open.stream_handle = 0x00;
-
+ if (ac->perf_mode) {
+ pr_debug("%s In Performance/lowlatency mode", __func__);
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V2_1;
+ open.uMode = ASM_OPEN_WRITE_PERF_MODE_BIT;
+ /* source endpoint : matrix */
+ open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+ open.stream_handle = PCM_BITS_PER_SAMPLE;
+ } else {
+ open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE;
+ open.uMode = STREAM_PRIORITY_HIGH;
+ /* source endpoint : matrix */
+ open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+ open.stream_handle = 0x00;
+ }
open.post_proc_top = get_asm_topology();
if (open.post_proc_top == 0)
open.post_proc_top = DEFAULT_POPP_TOPOLOGY;
@@ -1434,6 +1526,14 @@
case FORMAT_DTS_LBR:
open.format = DTS_LBR;
break;
+ case FORMAT_AMRWB:
+ open.format = AMRWB_FS;
+ pr_debug("q6asm_open_write FORMAT_AMRWB");
+ break;
+ case FORMAT_AMR_WB_PLUS:
+ open.format = AMR_WB_PLUS;
+ pr_debug("q6asm_open_write FORMAT_AMR_WB_PLUS");
+ break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, format);
goto fail_cmd;
@@ -2280,7 +2380,56 @@
return -EINVAL;
}
+int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
+ struct asm_amrwbplus_cfg *cfg)
+{
+ struct asm_stream_media_format_update fmt;
+ int rc = 0;
+ pr_debug("q6asm_media_format_block_amrwbplus");
+ pr_debug("%s:session[%d]band-mode[%d]frame-fmt[%d]ch[%d]\n",
+ __func__,
+ ac->session,
+ cfg->amr_band_mode,
+ cfg->amr_frame_fmt,
+ cfg->num_channels);
+
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+ fmt.format = AMR_WB_PLUS;
+ fmt.cfg_size = cfg->size_bytes;
+
+ fmt.write_cfg.amrwbplus_cfg.size_bytes = cfg->size_bytes;
+ fmt.write_cfg.amrwbplus_cfg.version = cfg->version;
+ fmt.write_cfg.amrwbplus_cfg.num_channels = cfg->num_channels;
+ fmt.write_cfg.amrwbplus_cfg.amr_band_mode = cfg->amr_band_mode;
+ fmt.write_cfg.amrwbplus_cfg.amr_dtx_mode = cfg->amr_dtx_mode;
+ fmt.write_cfg.amrwbplus_cfg.amr_frame_fmt = cfg->amr_frame_fmt;
+ fmt.write_cfg.amrwbplus_cfg.amr_lsf_idx = cfg->amr_lsf_idx;
+
+ pr_debug("%s: num_channels=%x amr_band_mode=%d amr_frame_fmt=%d\n",
+ __func__,
+ cfg->num_channels,
+ cfg->amr_band_mode,
+ cfg->amr_frame_fmt);
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s:Comamnd media format update failed..\n", __func__);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
int q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg)
{
@@ -2352,6 +2501,9 @@
case FORMAT_AMRWB:
fmt.format = AMRWB_FS;
break;
+ case FORMAT_AMR_WB_PLUS:
+ fmt.format = AMR_WB_PLUS;
+ break;
case FORMAT_AMRNB:
fmt.format = AMRNB_FS;
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 206e881..f1e0f3a 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -466,6 +466,9 @@
static __devinit int msm_pcm_probe(struct platform_device *pdev)
{
+ if (pdev->dev.of_node)
+ dev_set_name(&pdev->dev, "%s", "msm-pcm-voice");
+
pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
return snd_soc_register_platform(&pdev->dev,
&msm_soc_platform);
@@ -477,10 +480,17 @@
return 0;
}
+static const struct of_device_id msm_voice_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-voice"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_voice_dt_match);
+
static struct platform_driver msm_pcm_driver = {
.driver = {
.name = "msm-pcm-voice",
.owner = THIS_MODULE,
+ .of_match_table = msm_voice_dt_match,
},
.probe = msm_pcm_probe,
.remove = __devexit_p(msm_pcm_remove),
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 756cb18..2e58e1b 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -586,25 +586,23 @@
sizeof(lb_cmd) - APR_HDR_SIZE);
lb_cmd.hdr.src_port = 0;
lb_cmd.hdr.dest_port = 0;
- lb_cmd.hdr.token = 0;
+ lb_cmd.hdr.token = index;
lb_cmd.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
lb_cmd.param.port_id = tx_port;
- lb_cmd.param.payload_size = (sizeof(lb_cmd) -
- sizeof(struct apr_hdr) -
- sizeof(struct afe_port_cmd_set_param_v2));
+ lb_cmd.param.payload_size = (sizeof(lb_cmd) - sizeof(struct apr_hdr) -
+ sizeof(struct afe_port_cmd_set_param_v2));
lb_cmd.param.payload_address_lsw = 0x00;
lb_cmd.param.payload_address_msw = 0x00;
lb_cmd.param.mem_map_handle = 0x00;
lb_cmd.pdata.module_id = AFE_MODULE_LOOPBACK;
lb_cmd.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
- lb_cmd.pdata.param_size = lb_cmd.param.payload_size -
- sizeof(struct afe_port_param_data_v2);
+ lb_cmd.pdata.param_size = lb_cmd.param.payload_size -
+ sizeof(struct afe_port_param_data_v2);
lb_cmd.dst_port_id = rx_port;
lb_cmd.routing_mode = LB_MODE_DEFAULT;
lb_cmd.enable = (enable ? 1 : 0);
- lb_cmd.loopback_cfg_minor_version =
- AFE_API_VERSION_LOOPBACK_CONFIG;
+ lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
@@ -613,9 +611,10 @@
ret = -EINVAL;
goto done;
}
+ pr_debug("%s: waiting for this_afe.wait[%d]\n", __func__, index);
ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
@@ -667,26 +666,24 @@
set_param.hdr.pkt_size = sizeof(set_param);
set_param.hdr.src_port = 0;
set_param.hdr.dest_port = 0;
- set_param.hdr.token = 0;
+ set_param.hdr.token = index;
set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
- set_param.param.port_id = port_id;
- set_param.param.payload_size =
- (sizeof(struct afe_loopback_gain_per_path_param) -
- sizeof(struct apr_hdr) -
- sizeof(struct afe_port_cmd_set_param_v2));
+ set_param.param.port_id = port_id;
+ set_param.param.payload_size =
+ (sizeof(struct afe_loopback_gain_per_path_param) -
+ sizeof(struct apr_hdr) - sizeof(struct afe_port_cmd_set_param_v2));
set_param.param.payload_address_lsw = 0;
set_param.param.payload_address_msw = 0;
set_param.param.mem_map_handle = 0;
- set_param.pdata.module_id = AFE_MODULE_LOOPBACK;
- set_param.pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
- set_param.pdata.param_size = (set_param.param.payload_size -
- sizeof(struct afe_port_param_data_v2));
+ set_param.pdata.module_id = AFE_MODULE_LOOPBACK;
+ set_param.pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
+ set_param.pdata.param_size =
+ (set_param.param.payload_size -
+ sizeof(struct afe_port_param_data_v2));
set_param.rx_port_id = port_id;
- set_param.gain = volume;
-
- set_param.hdr.token = index;
+ set_param.gain = volume;
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
@@ -698,8 +695,8 @@
}
ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
if (ret < 0) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index a3af263..392b9b0 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -136,7 +136,7 @@
kfree(temp);
return -EFAULT;
}
- if (!strict_strtol(temp, 10, &out_enable_flag)) {
+ if (!kstrtol(temp, 10, &out_enable_flag)) {
kfree(temp);
return count;
}
@@ -177,7 +177,7 @@
kfree(temp);
return -EFAULT;
}
- if (!strict_strtol(temp, 10, &in_enable_flag)) {
+ if (!kstrtol(temp, 10, &in_enable_flag)) {
kfree(temp);
return count;
}
@@ -347,7 +347,7 @@
int rc = 0;
pr_debug("%s: Session id %d\n", __func__, ac->session);
mutex_lock(&ac->cmd_lock);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[dir];
if (!port->buf) {
mutex_unlock(&ac->cmd_lock);
@@ -454,7 +454,7 @@
if (!ac || !ac->session)
return;
pr_debug("%s: Session id %d\n", __func__, ac->session);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
port = &ac->port[loopcnt];
if (!port->buf)
@@ -603,7 +603,7 @@
if (ac->session <= 0 || ac->session > 8)
goto fail;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
if (ac->port[dir].buf) {
pr_debug("%s: buffer already allocated\n", __func__);
return 0;
@@ -973,7 +973,7 @@
pr_debug("%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
__func__, payload[0], payload[1],
data->token);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
if (port->buf == NULL) {
pr_err("%s: Unexpected Write Done\n",
__func__);
@@ -1025,7 +1025,7 @@
payload[READDONE_IDX_SEQ_ID],
payload[READDONE_IDX_NUMFRAMES]);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
if (port->buf == NULL) {
pr_err("%s: Unexpected Write Done\n", __func__);
return -EINVAL;
@@ -1092,7 +1092,7 @@
if (!ac || ((dir != IN) && (dir != OUT)))
return NULL;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[dir];
mutex_lock(&port->lock);
@@ -1186,7 +1186,7 @@
if (!ac || (dir != OUT))
return ret;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[dir];
mutex_lock(&port->lock);
@@ -2825,7 +2825,7 @@
pr_err("APR handle NULL\n");
return -EINVAL;
}
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[OUT];
q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
@@ -2888,7 +2888,7 @@
pr_err("APR handle NULL\n");
return -EINVAL;
}
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[OUT];
q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
@@ -2969,12 +2969,10 @@
write.timestamp_lsw = param->lsw_ts;
liomode = (ASYNC_IO_MODE | NT_MODE);
- if (ac->io_mode == liomode) {
- pr_info("%s: subtracting 32 for header\n", __func__);
+ if (ac->io_mode == liomode)
lbuf_addr_lsw = (write.buf_addr_lsw - 32);
- } else{
+ else
lbuf_addr_lsw = write.buf_addr_lsw;
- }
pr_debug("%s: token[0x%x], buf_addr_lsw[0x%x], buf_size[0x%x], ts_msw[0x%x], ts_lsw[0x%x], lbuf_addr_lsw: 0x[%x]\n",
__func__,
@@ -3034,12 +3032,10 @@
read.buf_size = param->len;
read.seq_id = param->uid;
liomode = (NT_MODE | ASYNC_IO_MODE);
- if (ac->io_mode == liomode) {
- pr_info("%s: subtracting 32 for header\n", __func__);
+ if (ac->io_mode == liomode)
lbuf_addr_lsw = (read.buf_addr_lsw - 32);
- } else{
+ else
lbuf_addr_lsw = read.buf_addr_lsw;
- }
list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
buf_node = list_entry(ptr, struct asm_buffer_node, list);
@@ -3075,7 +3071,7 @@
return -EINVAL;
}
pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[IN];
q6asm_add_hdr(ac, &write.hdr, sizeof(write),
@@ -3143,7 +3139,7 @@
return -EINVAL;
}
pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
port = &ac->port[IN];
q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
@@ -3352,7 +3348,7 @@
int loopcnt = 0;
struct audio_port_data *port = NULL;
- if (ac->io_mode == SYNC_IO_MODE) {
+ if (ac->io_mode & SYNC_IO_MODE) {
mutex_lock(&ac->cmd_lock);
for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
port = &ac->port[loopcnt];
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 4e11dfe..f84b456 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -50,19 +50,6 @@
static int voice_send_set_device_cmd(struct voice_data *v);
static int voice_send_disable_vocproc_cmd(struct voice_data *v);
static int voice_send_vol_index_cmd(struct voice_data *v);
-static int voice_send_cvp_map_memory_cmd(struct voice_data *v);
-static int voice_send_cvp_unmap_memory_cmd(struct voice_data *v);
-static int voice_send_cvs_map_memory_cmd(struct voice_data *v);
-static int voice_send_cvs_unmap_memory_cmd(struct voice_data *v);
-static int voice_send_cvs_register_cal_cmd(struct voice_data *v);
-static int voice_send_cvs_deregister_cal_cmd(struct voice_data *v);
-static int voice_send_cvp_register_cal_cmd(struct voice_data *v);
-static int voice_send_cvp_deregister_cal_cmd(struct voice_data *v);
-static int voice_send_cvp_register_vol_cal_table_cmd(struct voice_data *v);
-static int voice_send_cvp_deregister_vol_cal_table_cmd(struct voice_data *v);
-static int voice_send_set_widevoice_enable_cmd(struct voice_data *v);
-static int voice_send_set_pp_enable_cmd(struct voice_data *v,
- uint32_t module_id, int enable);
static int voice_cvs_stop_playback(struct voice_data *v);
static int voice_cvs_start_playback(struct voice_data *v);
static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode);
@@ -223,7 +210,6 @@
goto err;
}
- rtac_set_voice_handle(RTAC_CVS, common.apr_q6_cvs);
}
if (common.apr_q6_cvp == NULL) {
@@ -238,7 +224,6 @@
goto err;
}
- rtac_set_voice_handle(RTAC_CVP, common.apr_q6_cvp);
}
mutex_unlock(&common.common_lock);
@@ -249,7 +234,6 @@
if (common.apr_q6_cvs != NULL) {
apr_deregister(common.apr_q6_cvs);
common.apr_q6_cvs = NULL;
- rtac_set_voice_handle(RTAC_CVS, NULL);
}
if (common.apr_q6_mvm != NULL) {
apr_deregister(common.apr_q6_mvm);
@@ -278,7 +262,8 @@
return -EINVAL;
}
pr_debug("%s: VoLTE command to MVM\n", __func__);
- if (is_volte_session(v->session_id)) {
+ if (is_volte_session(v->session_id) ||
+ is_voice_session(v->session_id)) {
mvm_handle = voice_get_mvm_handle(v);
mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
@@ -1211,765 +1196,6 @@
return -EINVAL;
}
-static int voice_send_cvs_register_cal_cmd(struct voice_data *v)
-{
- struct cvs_register_cal_data_cmd cvs_reg_cal_cmd;
- struct acdb_cal_block cal_block;
- int ret = 0;
- void *apr_cvs;
- u16 cvs_handle;
- uint32_t cal_paddr;
-
- /* get the cvs cal data */
- get_all_vocstrm_cal(&cal_block);
- if (cal_block.cal_size == 0)
- goto fail;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvs = common.apr_q6_cvs;
-
- if (!apr_cvs) {
- pr_err("%s: apr_cvs is NULL.\n", __func__);
- return -EINVAL;
- }
-
- if (is_voip_session(v->session_id)) {
- if (common.cvs_cal.buf) {
- cal_paddr = common.cvs_cal.phy;
-
- memcpy(common.cvs_cal.buf,
- (void *) cal_block.cal_kvaddr,
- cal_block.cal_size);
- } else {
- return -EINVAL;
- }
- } else {
- cal_paddr = cal_block.cal_paddr;
- }
-
- cvs_handle = voice_get_cvs_handle(v);
-
- /* fill in the header */
- cvs_reg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvs_reg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_reg_cal_cmd) - APR_HDR_SIZE);
- cvs_reg_cal_cmd.hdr.src_port = v->session_id;
- cvs_reg_cal_cmd.hdr.dest_port = cvs_handle;
- cvs_reg_cal_cmd.hdr.token = 0;
- cvs_reg_cal_cmd.hdr.opcode = VSS_ISTREAM_CMD_REGISTER_CALIBRATION_DATA;
-
- cvs_reg_cal_cmd.cvs_cal_data.phys_addr = cal_paddr;
- cvs_reg_cal_cmd.cvs_cal_data.mem_size = cal_block.cal_size;
-
- v->cvs_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_reg_cal_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvs cal,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-
-}
-
-static int voice_send_cvs_deregister_cal_cmd(struct voice_data *v)
-{
- struct cvs_deregister_cal_data_cmd cvs_dereg_cal_cmd;
- struct acdb_cal_block cal_block;
- int ret = 0;
- void *apr_cvs;
- u16 cvs_handle;
-
- get_all_vocstrm_cal(&cal_block);
- if (cal_block.cal_size == 0)
- return 0;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvs = common.apr_q6_cvs;
-
- if (!apr_cvs) {
- pr_err("%s: apr_cvs is NULL.\n", __func__);
- return -EINVAL;
- }
- cvs_handle = voice_get_cvs_handle(v);
-
- /* fill in the header */
- cvs_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvs_dereg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_dereg_cal_cmd) - APR_HDR_SIZE);
- cvs_dereg_cal_cmd.hdr.src_port = v->session_id;
- cvs_dereg_cal_cmd.hdr.dest_port = cvs_handle;
- cvs_dereg_cal_cmd.hdr.token = 0;
- cvs_dereg_cal_cmd.hdr.opcode =
- VSS_ISTREAM_CMD_DEREGISTER_CALIBRATION_DATA;
-
- v->cvs_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_dereg_cal_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvs cal,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-
-}
-
-static int voice_send_cvp_map_memory_cmd(struct voice_data *v)
-{
- struct vss_map_memory_cmd cvp_map_mem_cmd;
- struct acdb_cal_block cal_block;
- int ret = 0;
- void *apr_cvp;
- u16 cvp_handle;
- uint32_t cal_paddr;
-
- /* get all cvp cal data */
- get_all_cvp_cal(&cal_block);
- if (cal_block.cal_size == 0)
- goto fail;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvp = common.apr_q6_cvp;
-
- if (!apr_cvp) {
- pr_err("%s: apr_cvp is NULL.\n", __func__);
- return -EINVAL;
- }
-
- if (is_voip_session(v->session_id)) {
- if (common.cvp_cal.buf)
- cal_paddr = common.cvp_cal.phy;
- else
- return -EINVAL;
- } else {
- cal_paddr = cal_block.cal_paddr;
- }
- cvp_handle = voice_get_cvp_handle(v);
-
- /* fill in the header */
- cvp_map_mem_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvp_map_mem_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvp_map_mem_cmd) - APR_HDR_SIZE);
- cvp_map_mem_cmd.hdr.src_port = v->session_id;
- cvp_map_mem_cmd.hdr.dest_port = cvp_handle;
- cvp_map_mem_cmd.hdr.token = 0;
- cvp_map_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_MAP_MEMORY;
-
- pr_debug("%s, phy_addr:0x%x, mem_size:%d\n", __func__,
- cal_paddr, cal_block.cal_size);
- cvp_map_mem_cmd.vss_map_mem.phys_addr = cal_paddr;
- cvp_map_mem_cmd.vss_map_mem.mem_size = cal_block.cal_size;
- cvp_map_mem_cmd.vss_map_mem.mem_pool_id =
- VSS_ICOMMON_MAP_MEMORY_SHMEM8_4K_POOL;
-
- v->cvp_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_map_mem_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvp cal,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvp_wait,
- (v->cvp_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-
-}
-
-static int voice_send_cvp_unmap_memory_cmd(struct voice_data *v)
-{
- struct vss_unmap_memory_cmd cvp_unmap_mem_cmd;
- struct acdb_cal_block cal_block;
- int ret = 0;
- void *apr_cvp;
- u16 cvp_handle;
- uint32_t cal_paddr;
-
- get_all_cvp_cal(&cal_block);
- if (cal_block.cal_size == 0)
- return 0;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvp = common.apr_q6_cvp;
-
- if (!apr_cvp) {
- pr_err("%s: apr_cvp is NULL.\n", __func__);
- return -EINVAL;
- }
-
- if (is_voip_session(v->session_id))
- cal_paddr = common.cvp_cal.phy;
- else
- cal_paddr = cal_block.cal_paddr;
-
- cvp_handle = voice_get_cvp_handle(v);
-
- /* fill in the header */
- cvp_unmap_mem_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvp_unmap_mem_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvp_unmap_mem_cmd) - APR_HDR_SIZE);
- cvp_unmap_mem_cmd.hdr.src_port = v->session_id;
- cvp_unmap_mem_cmd.hdr.dest_port = cvp_handle;
- cvp_unmap_mem_cmd.hdr.token = 0;
- cvp_unmap_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_UNMAP_MEMORY;
-
- cvp_unmap_mem_cmd.vss_unmap_mem.phys_addr = cal_paddr;
-
- v->cvp_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_unmap_mem_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvp cal,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvp_wait,
- (v->cvp_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-
-}
-
-static int voice_send_cvs_map_memory_cmd(struct voice_data *v)
-{
- struct vss_map_memory_cmd cvs_map_mem_cmd;
- struct acdb_cal_block cal_block;
- int ret = 0;
- void *apr_cvs;
- u16 cvs_handle;
- uint32_t cal_paddr;
-
- /* get all cvs cal data */
- get_all_vocstrm_cal(&cal_block);
- if (cal_block.cal_size == 0)
- goto fail;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvs = common.apr_q6_cvs;
-
- if (!apr_cvs) {
- pr_err("%s: apr_cvs is NULL.\n", __func__);
- return -EINVAL;
- }
-
- if (is_voip_session(v->session_id)) {
- if (common.cvs_cal.buf)
- cal_paddr = common.cvs_cal.phy;
- else
- return -EINVAL;
- } else {
- cal_paddr = cal_block.cal_paddr;
- }
-
- cvs_handle = voice_get_cvs_handle(v);
-
- /* fill in the header */
- cvs_map_mem_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvs_map_mem_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_map_mem_cmd) - APR_HDR_SIZE);
- cvs_map_mem_cmd.hdr.src_port = v->session_id;
- cvs_map_mem_cmd.hdr.dest_port = cvs_handle;
- cvs_map_mem_cmd.hdr.token = 0;
- cvs_map_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_MAP_MEMORY;
-
- pr_debug("%s, phys_addr: 0x%x, mem_size: %d\n", __func__,
- cal_paddr, cal_block.cal_size);
- cvs_map_mem_cmd.vss_map_mem.phys_addr = cal_paddr;
- cvs_map_mem_cmd.vss_map_mem.mem_size = cal_block.cal_size;
- cvs_map_mem_cmd.vss_map_mem.mem_pool_id =
- VSS_ICOMMON_MAP_MEMORY_SHMEM8_4K_POOL;
-
- v->cvs_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_map_mem_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvs cal,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-
-}
-
-static int voice_send_cvs_unmap_memory_cmd(struct voice_data *v)
-{
- struct vss_unmap_memory_cmd cvs_unmap_mem_cmd;
- struct acdb_cal_block cal_block;
- int ret = 0;
- void *apr_cvs;
- u16 cvs_handle;
- uint32_t cal_paddr;
-
- get_all_vocstrm_cal(&cal_block);
- if (cal_block.cal_size == 0)
- return 0;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvs = common.apr_q6_cvs;
-
- if (!apr_cvs) {
- pr_err("%s: apr_cvs is NULL.\n", __func__);
- return -EINVAL;
- }
-
- if (is_voip_session(v->session_id))
- cal_paddr = common.cvs_cal.phy;
- else
- cal_paddr = cal_block.cal_paddr;
-
- cvs_handle = voice_get_cvs_handle(v);
-
- /* fill in the header */
- cvs_unmap_mem_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvs_unmap_mem_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_unmap_mem_cmd) - APR_HDR_SIZE);
- cvs_unmap_mem_cmd.hdr.src_port = v->session_id;
- cvs_unmap_mem_cmd.hdr.dest_port = cvs_handle;
- cvs_unmap_mem_cmd.hdr.token = 0;
- cvs_unmap_mem_cmd.hdr.opcode = VSS_ICOMMON_CMD_UNMAP_MEMORY;
-
- cvs_unmap_mem_cmd.vss_unmap_mem.phys_addr = cal_paddr;
-
- v->cvs_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_unmap_mem_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvs cal,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-
-}
-
-static int voice_send_cvp_register_cal_cmd(struct voice_data *v)
-{
- struct cvp_register_cal_data_cmd cvp_reg_cal_cmd;
- struct acdb_cal_block cal_block;
- int ret = 0;
- void *apr_cvp;
- u16 cvp_handle;
- uint32_t cal_paddr;
-
- /* get the cvp cal data */
- get_all_vocproc_cal(&cal_block);
- if (cal_block.cal_size == 0)
- goto fail;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvp = common.apr_q6_cvp;
-
- if (!apr_cvp) {
- pr_err("%s: apr_cvp is NULL.\n", __func__);
- return -EINVAL;
- }
-
- if (is_voip_session(v->session_id)) {
- if (common.cvp_cal.buf) {
- cal_paddr = common.cvp_cal.phy;
-
- memcpy(common.cvp_cal.buf,
- (void *)cal_block.cal_kvaddr,
- cal_block.cal_size);
- } else {
- return -EINVAL;
- }
- } else {
- cal_paddr = cal_block.cal_paddr;
- }
-
- cvp_handle = voice_get_cvp_handle(v);
-
- /* fill in the header */
- cvp_reg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvp_reg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvp_reg_cal_cmd) - APR_HDR_SIZE);
- cvp_reg_cal_cmd.hdr.src_port = v->session_id;
- cvp_reg_cal_cmd.hdr.dest_port = cvp_handle;
- cvp_reg_cal_cmd.hdr.token = 0;
- cvp_reg_cal_cmd.hdr.opcode = VSS_IVOCPROC_CMD_REGISTER_CALIBRATION_DATA;
-
- cvp_reg_cal_cmd.cvp_cal_data.phys_addr = cal_paddr;
- cvp_reg_cal_cmd.cvp_cal_data.mem_size = cal_block.cal_size;
-
- v->cvp_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_reg_cal_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvp cal,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvp_wait,
- (v->cvp_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-
-}
-
-static int voice_send_cvp_deregister_cal_cmd(struct voice_data *v)
-{
- struct cvp_deregister_cal_data_cmd cvp_dereg_cal_cmd;
- struct acdb_cal_block cal_block;
- int ret = 0;
- void *apr_cvp;
- u16 cvp_handle;
-
- get_all_vocproc_cal(&cal_block);
- if (cal_block.cal_size == 0)
- return 0;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvp = common.apr_q6_cvp;
-
- if (!apr_cvp) {
- pr_err("%s: apr_cvp is NULL.\n", __func__);
- return -EINVAL;
- }
- cvp_handle = voice_get_cvp_handle(v);
-
- /* fill in the header */
- cvp_dereg_cal_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvp_dereg_cal_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvp_dereg_cal_cmd) - APR_HDR_SIZE);
- cvp_dereg_cal_cmd.hdr.src_port = v->session_id;
- cvp_dereg_cal_cmd.hdr.dest_port = cvp_handle;
- cvp_dereg_cal_cmd.hdr.token = 0;
- cvp_dereg_cal_cmd.hdr.opcode =
- VSS_IVOCPROC_CMD_DEREGISTER_CALIBRATION_DATA;
-
- v->cvp_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_dereg_cal_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvp cal,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvp_wait,
- (v->cvp_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-
-}
-
-static int voice_send_cvp_register_vol_cal_table_cmd(struct voice_data *v)
-{
- struct cvp_register_vol_cal_table_cmd cvp_reg_cal_tbl_cmd;
- struct acdb_cal_block vol_block;
- struct acdb_cal_block voc_block;
- int ret = 0;
- void *apr_cvp;
- u16 cvp_handle;
- uint32_t cal_paddr;
-
- /* get the cvp vol cal data */
- get_all_vocvol_cal(&vol_block);
- get_all_vocproc_cal(&voc_block);
-
- if (vol_block.cal_size == 0)
- goto fail;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvp = common.apr_q6_cvp;
-
- if (!apr_cvp) {
- pr_err("%s: apr_cvp is NULL.\n", __func__);
- return -EINVAL;
- }
-
- if (is_voip_session(v->session_id)) {
- if (common.cvp_cal.buf) {
- cal_paddr = common.cvp_cal.phy + voc_block.cal_size;
-
- memcpy(common.cvp_cal.buf + voc_block.cal_size,
- (void *) vol_block.cal_kvaddr,
- vol_block.cal_size);
- } else {
- return -EINVAL;
- }
- } else {
- cal_paddr = vol_block.cal_paddr;
- }
-
- cvp_handle = voice_get_cvp_handle(v);
-
- /* fill in the header */
- cvp_reg_cal_tbl_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvp_reg_cal_tbl_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvp_reg_cal_tbl_cmd) - APR_HDR_SIZE);
- cvp_reg_cal_tbl_cmd.hdr.src_port = v->session_id;
- cvp_reg_cal_tbl_cmd.hdr.dest_port = cvp_handle;
- cvp_reg_cal_tbl_cmd.hdr.token = 0;
- cvp_reg_cal_tbl_cmd.hdr.opcode =
- VSS_IVOCPROC_CMD_REGISTER_VOLUME_CAL_TABLE;
-
- cvp_reg_cal_tbl_cmd.cvp_vol_cal_tbl.phys_addr = cal_paddr;
- cvp_reg_cal_tbl_cmd.cvp_vol_cal_tbl.mem_size = vol_block.cal_size;
-
- v->cvp_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_reg_cal_tbl_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvp cal table,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvp_wait,
- (v->cvp_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-
-}
-
-static int voice_send_cvp_deregister_vol_cal_table_cmd(struct voice_data *v)
-{
- struct cvp_deregister_vol_cal_table_cmd cvp_dereg_cal_tbl_cmd;
- struct acdb_cal_block cal_block;
- int ret = 0;
- void *apr_cvp;
- u16 cvp_handle;
-
- get_all_vocvol_cal(&cal_block);
- if (cal_block.cal_size == 0)
- return 0;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvp = common.apr_q6_cvp;
-
- if (!apr_cvp) {
- pr_err("%s: apr_cvp is NULL.\n", __func__);
- return -EINVAL;
- }
- cvp_handle = voice_get_cvp_handle(v);
-
- /* fill in the header */
- cvp_dereg_cal_tbl_cmd.hdr.hdr_field = APR_HDR_FIELD(
- APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- cvp_dereg_cal_tbl_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvp_dereg_cal_tbl_cmd) - APR_HDR_SIZE);
- cvp_dereg_cal_tbl_cmd.hdr.src_port = v->session_id;
- cvp_dereg_cal_tbl_cmd.hdr.dest_port = cvp_handle;
- cvp_dereg_cal_tbl_cmd.hdr.token = 0;
- cvp_dereg_cal_tbl_cmd.hdr.opcode =
- VSS_IVOCPROC_CMD_DEREGISTER_VOLUME_CAL_TABLE;
-
- v->cvp_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_dereg_cal_tbl_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvp cal table,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvp_wait,
- (v->cvp_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-
-}
-
-static int voice_send_set_widevoice_enable_cmd(struct voice_data *v)
-{
- struct mvm_set_widevoice_enable_cmd mvm_set_wv_cmd;
- int ret = 0;
- void *apr_mvm;
- u16 mvm_handle;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_mvm = common.apr_q6_mvm;
-
- if (!apr_mvm) {
- pr_err("%s: apr_mvm is NULL.\n", __func__);
- return -EINVAL;
- }
- mvm_handle = voice_get_mvm_handle(v);
-
- /* fill in the header */
- mvm_set_wv_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- mvm_set_wv_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(mvm_set_wv_cmd) - APR_HDR_SIZE);
- mvm_set_wv_cmd.hdr.src_port = v->session_id;
- mvm_set_wv_cmd.hdr.dest_port = mvm_handle;
- mvm_set_wv_cmd.hdr.token = 0;
- mvm_set_wv_cmd.hdr.opcode = VSS_IWIDEVOICE_CMD_SET_WIDEVOICE;
-
- mvm_set_wv_cmd.vss_set_wv.enable = v->wv_enable;
-
- v->mvm_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_wv_cmd);
- if (ret < 0) {
- pr_err("Fail: sending mvm set widevoice enable,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->mvm_wait,
- (v->mvm_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-}
-
-static int voice_send_set_pp_enable_cmd(struct voice_data *v,
- uint32_t module_id, int enable)
-{
- struct cvs_set_pp_enable_cmd cvs_set_pp_cmd;
- int ret = 0;
- void *apr_cvs;
- u16 cvs_handle;
-
- if (v == NULL) {
- pr_err("%s: v is NULL\n", __func__);
- return -EINVAL;
- }
- apr_cvs = common.apr_q6_cvs;
-
- if (!apr_cvs) {
- pr_err("%s: apr_cvs is NULL.\n", __func__);
- return -EINVAL;
- }
- cvs_handle = voice_get_cvs_handle(v);
-
- /* fill in the header */
- cvs_set_pp_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- cvs_set_pp_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_pp_cmd) - APR_HDR_SIZE);
- cvs_set_pp_cmd.hdr.src_port = v->session_id;
- cvs_set_pp_cmd.hdr.dest_port = cvs_handle;
- cvs_set_pp_cmd.hdr.token = 0;
- cvs_set_pp_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_UI_PROPERTY;
-
- cvs_set_pp_cmd.vss_set_pp.module_id = module_id;
- cvs_set_pp_cmd.vss_set_pp.param_id = VOICE_PARAM_MOD_ENABLE;
- cvs_set_pp_cmd.vss_set_pp.param_size = MOD_ENABLE_PARAM_LEN;
- cvs_set_pp_cmd.vss_set_pp.reserved = 0;
- cvs_set_pp_cmd.vss_set_pp.enable = enable;
- cvs_set_pp_cmd.vss_set_pp.reserved_field = 0;
- pr_debug("voice_send_set_pp_enable_cmd, module_id=%d, enable=%d\n",
- module_id, enable);
-
- v->cvs_state = CMD_STATUS_FAIL;
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_pp_cmd);
- if (ret < 0) {
- pr_err("Fail: sending cvs set slowtalk enable,\n");
- goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
- return 0;
-fail:
- return -EINVAL;
-}
static int voice_setup_vocproc(struct voice_data *v)
{
@@ -2040,17 +1266,6 @@
goto fail;
}
- /* send cvs cal */
- ret = voice_send_cvs_map_memory_cmd(v);
- if (!ret)
- voice_send_cvs_register_cal_cmd(v);
-
- /* send cvp and vol cal */
- ret = voice_send_cvp_map_memory_cmd(v);
- if (!ret) {
- voice_send_cvp_register_cal_cmd(v);
- voice_send_cvp_register_vol_cal_table_cmd(v);
- }
/* enable vocproc */
ret = voice_send_enable_vocproc_cmd(v);
@@ -2065,16 +1280,6 @@
/* send tty mode if tty device is used */
voice_send_tty_mode_cmd(v);
- /* enable widevoice if wv_enable is set */
- if (v->wv_enable)
- voice_send_set_widevoice_enable_cmd(v);
-
- /* enable slowtalk if st_enable is set */
- if (v->st_enable)
- voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_ST,
- v->st_enable);
- voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_FENS,
- v->fens_enable);
if (is_voip_session(v->session_id))
voice_send_netid_timing_cmd(v);
@@ -2087,10 +1292,6 @@
if (v->rec_info.rec_enable)
voice_cvs_start_record(v, v->rec_info.rec_mode);
- rtac_add_voice(voice_get_cvs_handle(v),
- voice_get_cvp_handle(v),
- v->dev_rx.port_id, v->dev_tx.port_id,
- v->session_id);
return 0;
@@ -2359,14 +1560,6 @@
goto fail;
}
- /* deregister cvp and vol cal */
- voice_send_cvp_deregister_vol_cal_table_cmd(v);
- voice_send_cvp_deregister_cal_cmd(v);
- voice_send_cvp_unmap_memory_cmd(v);
-
- /* deregister cvs cal */
- voice_send_cvs_deregister_cal_cmd(v);
- voice_send_cvs_unmap_memory_cmd(v);
/* destrop cvp session */
cvp_destroy_session_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -2395,7 +1588,6 @@
goto fail;
}
- rtac_remove_voice(voice_get_cvs_handle(v));
cvp_handle = 0;
voice_set_cvp_handle(v, cvp_handle);
@@ -2975,12 +2167,6 @@
mutex_lock(&v->lock);
if (v->voc_state == VOC_RUN) {
- if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
- v->dev_rx.port_id != RT_PROXY_PORT_001_RX)
- afe_sidetone(v->dev_tx.port_id, v->dev_rx.port_id,
- 0, 0);
-
- rtac_remove_voice(voice_get_cvs_handle(v));
/* send cmd to dsp to disable vocproc */
ret = voice_send_disable_vocproc_cmd(v);
if (ret < 0) {
@@ -2988,10 +2174,6 @@
goto fail;
}
- /* deregister cvp and vol cal */
- voice_send_cvp_deregister_vol_cal_table_cmd(v);
- voice_send_cvp_deregister_cal_cmd(v);
- voice_send_cvp_unmap_memory_cmd(v);
v->voc_state = VOC_CHANGE;
}
@@ -3004,7 +2186,6 @@
int voc_enable_cvp(uint16_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
- struct sidetone_cal sidetone_cal_data;
int ret = 0;
if (v == NULL) {
@@ -3021,53 +2202,9 @@
pr_err("%s: set device failed\n", __func__);
goto fail;
}
- /* send cvp and vol cal */
- ret = voice_send_cvp_map_memory_cmd(v);
- if (!ret) {
- voice_send_cvp_register_cal_cmd(v);
- voice_send_cvp_register_vol_cal_table_cmd(v);
- }
- ret = voice_send_enable_vocproc_cmd(v);
- if (ret < 0) {
- pr_err("%s: enable vocproc failed\n", __func__);
- goto fail;
-
- }
/* send tty mode if tty device is used */
voice_send_tty_mode_cmd(v);
- /* enable widevoice if wv_enable is set */
- if (v->wv_enable)
- voice_send_set_widevoice_enable_cmd(v);
-
- /* enable slowtalk */
- if (v->st_enable)
- voice_send_set_pp_enable_cmd(v,
- MODULE_ID_VOICE_MODULE_ST,
- v->st_enable);
- /* enable FENS */
- if (v->fens_enable)
- voice_send_set_pp_enable_cmd(v,
- MODULE_ID_VOICE_MODULE_FENS,
- v->fens_enable);
-
- get_sidetone_cal(&sidetone_cal_data);
- if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
- v->dev_rx.port_id != RT_PROXY_PORT_001_RX) {
- ret = afe_sidetone(v->dev_tx.port_id,
- v->dev_rx.port_id,
- sidetone_cal_data.enable,
- sidetone_cal_data.gain);
-
- if (ret < 0)
- pr_err("%s: AFE command sidetone failed\n",
- __func__);
- }
-
- rtac_add_voice(voice_get_cvs_handle(v),
- voice_get_cvp_handle(v),
- v->dev_rx.port_id, v->dev_tx.port_id,
- v->session_id);
v->voc_state = VOC_RUN;
}
@@ -3201,8 +2338,6 @@
mvm_handle = voice_get_mvm_handle(v);
- if (mvm_handle != 0)
- voice_send_set_widevoice_enable_cmd(v);
mutex_unlock(&v->lock);
@@ -3246,16 +2381,6 @@
else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
v->fens_enable = enable;
- if (v->voc_state == VOC_RUN) {
- if (module_id == MODULE_ID_VOICE_MODULE_ST)
- ret = voice_send_set_pp_enable_cmd(v,
- MODULE_ID_VOICE_MODULE_ST,
- enable);
- else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
- ret = voice_send_set_pp_enable_cmd(v,
- MODULE_ID_VOICE_MODULE_FENS,
- enable);
- }
mutex_unlock(&v->lock);
return ret;
@@ -3391,10 +2516,6 @@
mutex_lock(&v->lock);
if (v->voc_state == VOC_RUN) {
- if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
- v->dev_rx.port_id != RT_PROXY_PORT_001_RX)
- afe_sidetone(v->dev_tx.port_id, v->dev_rx.port_id,
- 0, 0);
ret = voice_destroy_vocproc(v);
if (ret < 0)
pr_err("%s: destroy voice failed\n", __func__);
@@ -3409,7 +2530,6 @@
int voc_start_voice_call(uint16_t session_id)
{
struct voice_data *v = voice_get_session(session_id);
- struct sidetone_cal sidetone_cal_data;
int ret = 0;
if (v == NULL) {
@@ -3447,16 +2567,6 @@
pr_err("start voice failed\n");
goto fail;
}
- get_sidetone_cal(&sidetone_cal_data);
- if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
- v->dev_rx.port_id != RT_PROXY_PORT_001_RX) {
- ret = afe_sidetone(v->dev_tx.port_id,
- v->dev_rx.port_id,
- sidetone_cal_data.enable,
- sidetone_cal_data.gain);
- if (ret < 0)
- pr_err("AFE command sidetone failed\n");
- }
v->voc_state = VOC_RUN;
}
@@ -3649,8 +2759,6 @@
wake_up(&v->cvs_wait);
break;
case VOICE_CMD_SET_PARAM:
- rtac_make_voice_callback(RTAC_CVS, ptr,
- data->payload_size);
break;
default:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
@@ -3712,9 +2820,6 @@
pr_debug("%s: dl_cb is NULL\n", __func__);
} else if (data->opcode == VSS_ISTREAM_EVT_SEND_DEC_BUFFER) {
pr_debug("Send dec buf resp\n");
- } else if (data->opcode == VOICE_EVT_GET_PARAM_ACK) {
- rtac_make_voice_callback(RTAC_CVS, data->payload,
- data->payload_size);
} else
pr_debug("Unknown opcode 0x%x\n", data->opcode);
@@ -3792,8 +2897,6 @@
wake_up(&v->cvp_wait);
break;
case VOICE_CMD_SET_PARAM:
- rtac_make_voice_callback(RTAC_CVP, ptr,
- data->payload_size);
break;
default:
pr_debug("%s: not match cmd = 0x%x\n",
@@ -3801,9 +2904,6 @@
break;
}
}
- } else if (data->opcode == VOICE_EVT_GET_PARAM_ACK) {
- rtac_make_voice_callback(RTAC_CVP, data->payload,
- data->payload_size);
}
return 0;
}
@@ -3812,73 +2912,9 @@
static int __init voice_init(void)
{
int rc = 0, i = 0;
- int len;
memset(&common, 0, sizeof(struct common_data));
- /* Allocate memory for VoIP calibration */
- common.client = msm_ion_client_create(UINT_MAX, "voip_client");
- if (IS_ERR_OR_NULL((void *)common.client)) {
- pr_err("%s: ION create client for Voip failed\n", __func__);
- goto cont;
- }
- common.cvp_cal.handle = ion_alloc(common.client, CVP_CAL_SIZE, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
- if (IS_ERR_OR_NULL((void *) common.cvp_cal.handle)) {
- pr_err("%s: ION memory allocation for CVP failed\n",
- __func__);
- ion_client_destroy(common.client);
- goto cont;
- }
-
- rc = ion_phys(common.client, common.cvp_cal.handle,
- (ion_phys_addr_t *)&common.cvp_cal.phy, (size_t *)&len);
- if (rc) {
- pr_err("%s: ION Get Physical for cvp failed, rc = %d\n",
- __func__, rc);
- ion_free(common.client, common.cvp_cal.handle);
- ion_client_destroy(common.client);
- goto cont;
- }
-
- common.cvp_cal.buf = ion_map_kernel(common.client,
- common.cvp_cal.handle, 0);
- if (IS_ERR_OR_NULL((void *) common.cvp_cal.buf)) {
- pr_err("%s: ION memory mapping for cvp failed\n", __func__);
- common.cvp_cal.buf = NULL;
- ion_free(common.client, common.cvp_cal.handle);
- ion_client_destroy(common.client);
- goto cont;
- }
- memset((void *)common.cvp_cal.buf, 0, CVP_CAL_SIZE);
-
- common.cvs_cal.handle = ion_alloc(common.client, CVS_CAL_SIZE, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
- if (IS_ERR_OR_NULL((void *) common.cvs_cal.handle)) {
- pr_err("%s: ION memory allocation for CVS failed\n",
- __func__);
- goto cont;
- }
-
- rc = ion_phys(common.client, common.cvs_cal.handle,
- (ion_phys_addr_t *)&common.cvs_cal.phy, (size_t *)&len);
- if (rc) {
- pr_err("%s: ION Get Physical for cvs failed, rc = %d\n",
- __func__, rc);
- ion_free(common.client, common.cvs_cal.handle);
- goto cont;
- }
-
- common.cvs_cal.buf = ion_map_kernel(common.client,
- common.cvs_cal.handle, 0);
- if (IS_ERR_OR_NULL((void *) common.cvs_cal.buf)) {
- pr_err("%s: ION memory mapping for cvs failed\n", __func__);
- common.cvs_cal.buf = NULL;
- ion_free(common.client, common.cvs_cal.handle);
- goto cont;
- }
- memset((void *)common.cvs_cal.buf, 0, CVS_CAL_SIZE);
-cont:
/* set default value */
common.default_mute_val = 1; /* default is mute */
common.default_vol_val = 0;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 1bedb15..d313349 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -119,6 +119,8 @@
#define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION 0x000110FE
/* Create a new full control MVM session. */
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2 0x000112BF
+
#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 4522d15..79016b5 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3231,6 +3231,7 @@
card->instantiated = 0;
mutex_init(&card->mutex);
mutex_init(&card->dpcm_mutex);
+ mutex_init(&card->dapm_power_mutex);
mutex_lock(&client_mutex);
list_add(&card->list, &card_list);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 729142f..5ac643416 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1290,7 +1290,7 @@
/* Do we need to apply any queued changes? */
if (sort[w->id] != cur_sort || w->reg != cur_reg ||
w->dapm != cur_dapm || w->subseq != cur_subseq) {
- if (!list_empty(&pending))
+ if (cur_dapm && !list_empty(&pending))
dapm_seq_run_coalesced(cur_dapm, &pending);
if (cur_dapm && cur_dapm->seq_notifier) {
@@ -1350,7 +1350,7 @@
"Failed to apply widget power: %d\n", ret);
}
- if (!list_empty(&pending))
+ if (cur_dapm && !list_empty(&pending))
dapm_seq_run_coalesced(cur_dapm, &pending);
if (cur_dapm && cur_dapm->seq_notifier) {
@@ -1567,6 +1567,8 @@
trace_snd_soc_dapm_start(card);
+ mutex_lock(&card->dapm_power_mutex);
+
list_for_each_entry(d, &card->dapm_list, list) {
if (d->n_widgets || d->codec == NULL) {
if (d->idle_bias_off)
@@ -1682,6 +1684,8 @@
"DAPM sequencing finished, waiting %dms\n", card->pop_time);
pop_wait(card->pop_time);
+ mutex_unlock(&card->dapm_power_mutex);
+
trace_snd_soc_dapm_done(card);
return 0;
@@ -3092,9 +3096,9 @@
if (stream == NULL)
return 0;
- //mutex_lock(&codec->mutex);
+ mutex_lock(&codec->mutex);
soc_dapm_stream_event(&codec->dapm, stream, event);
- //mutex_unlock(&codec->mutex);
+ mutex_unlock(&codec->mutex);
return 0;
}