Merge "mdss: hdmi: Enable general control packet transmission to support AVMUTE"
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
new file mode 100644
index 0000000..6508329
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -0,0 +1,78 @@
+* ARM CPUs binding description
+
+The device tree allows to describe the layout of CPUs in a system through
+the "cpus" node, which in turn contains a number of subnodes (ie "cpu")
+defining properties for every cpu.
+
+Bindings for CPU nodes follow the ePAPR standard, available from:
+
+http://devicetree.org
+
+For the ARM architecture every CPU node must contain the following properties:
+
+- device_type: must be "cpu"
+- reg: property matching the CPU MPIDR[23:0] register bits
+ reg[31:24] bits must be set to 0
+- compatible: should be one of:
+ "arm,arm1020"
+ "arm,arm1020e"
+ "arm,arm1022"
+ "arm,arm1026"
+ "arm,arm720"
+ "arm,arm740"
+ "arm,arm7tdmi"
+ "arm,arm920"
+ "arm,arm922"
+ "arm,arm925"
+ "arm,arm926"
+ "arm,arm940"
+ "arm,arm946"
+ "arm,arm9tdmi"
+ "arm,cortex-a5"
+ "arm,cortex-a7"
+ "arm,cortex-a8"
+ "arm,cortex-a9"
+ "arm,cortex-a15"
+ "arm,arm1136"
+ "arm,arm1156"
+ "arm,arm1176"
+ "arm,arm11mpcore"
+ "faraday,fa526"
+ "intel,sa110"
+ "intel,sa1100"
+ "marvell,feroceon"
+ "marvell,mohawk"
+ "marvell,xsc3"
+ "marvell,xscale"
+ "qcom,krait"
+
+Example:
+
+ cpus {
+ #size-cells = <0>;
+ #address-cells = <1>;
+
+ CPU0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x0>;
+ };
+
+ CPU1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x1>;
+ };
+
+ CPU2: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x100>;
+ };
+
+ CPU3: cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x101>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 203730f..439418d 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -13,8 +13,10 @@
Required properties:
- compatible: Must be "qcom,cpr-regulator"
- reg: Register addresses for RBCPR and efuse
-- reg-names: Register names. Must be "rbcpr" and "efuse_phys"
+- reg-names: Register names. Must be "rbcpr", "pvs_efuse"
+ and "cpr_efuse"
- regulator-name: A string used to describe the regulator
+- interrupts: Interrupt line from RBCPR to interrupt controller.
- regulator-min-microvolt: Minimum corner value as min constraint, which
should be 1 for SVS corner
- regulator-max-microvolt: Maximum corner value as max constraint, which
@@ -23,9 +25,6 @@
represent total number of PVS bins. It should
not exceed a maximum of 5 for total number of
32 bins.
-- qcom,efuse-bit-pos: A list of integers whose length must equal
- to qcom,num-efuse-bits and each integer indicates
- bit position in efuse memory from LSB to MSB
- qcom,pvs-bin-process: A list of integers whose length is equal to 2 to
the power of qcom,num-efuse-bits. The location or
0-based index of an element in the list corresponds
@@ -44,8 +43,25 @@
0 (SVS voltage): 1050000 uV
1 (NORMAL voltage): 1150000 uV
2 (TURBO voltage): 1275000 uV
- 3 (SUPER_TURBO voltage): 1275000 uV
- vdd-apc-supply: Regulator to supply VDD APC power
+- qcom,vdd-apc-step-up-limit: Limit of vdd-apc-supply steps for scaling up.
+- qcom,vdd-apc-step-down-limit: Limit of vdd-apc-supply steps for scaling down.
+- qcom,cpr-ref-clk: The reference clock in kHz.
+- qcom,cpr-timer-delay: The delay in microseconds for the timer interval.
+- qcom,cpr-timer-cons-up: Consecutive number of timer interval (qcom,cpr-timer-delay)
+ occurred before issuing UP interrupt.
+- qcom,cpr-timer-cons-down: Consecutive number of timer interval (qcom,cpr-timer-delay)
+ occurred before issuing DOWN interrupt.
+- qcom,cpr-irq-line: Internal interrupt route signal of RBCPR, one of 0, 1 or 2.
+- qcom,cpr-step-quotient: Number of CPR quotient (RO count) per vdd-apc-supply step
+ to issue error_steps.
+- qcom,cpr-up-threshold: The threshold for CPR to issue interrupt when
+ error_steps is greater than it when stepping up.
+- qcom,cpr-down-threshold: The threshold for CPR to issue interrupt when
+ error_steps is greater than it when stepping down.
+- qcom,cpr-idle-clocks: Idle clock cycles RO can be in.
+- qcom,cpr-gcnt-time: The time for gate count in microseconds.
+- qcom,cpr-apc-volt-step: The voltage in microvolt per CPR step, such as 5000uV.
Optional properties:
@@ -61,28 +77,42 @@
2 => equal to slow speed corner ceiling
3 => equal to qcom,vdd-mx-vmax
This is required when vdd-mx-supply is present.
+- qcom,cpr-enable: Present: CPR enabled by default.
+ Not Present: CPR disable by default.
Example:
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>,
- <0xfc4b80b0 8>;
- reg-names = "rbcpr", "efuse_phys";
+ reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
+ reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <4>;
+ regulator-max-microvolt = <3>;
qcom,num-efuse-bits = <5>;
- qcom,efuse-bit-pos = <6 7 8 9 10>;
- qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
- qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
vdd-apc-supply = <&pm8226_s2>;
vdd-mx-supply = <&pm8226_l3_ao>;
qcom,vdd-mx-vmax = <1350000>;
qcom,vdd-mx-vmin-method = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay = <5000>;
+ qcom,cpr-timer-cons-up = <1>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-irq-line = <0>;
+ qcom,cpr-step-quotient = <15>;
+ qcom,cpr-up-threshold = <1>;
+ qcom,cpr-down-threshold = <2>;
+ qcom,cpr-idle-clocks = <5>;
+ qcom,cpr-gcnt-time = <1>;
+ qcom,cpr-apc-volt-step = <5000>;
};
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 23498e5..6ef2b77 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -24,6 +24,8 @@
Optional properties
+- qcom,freq-control-mask: The cpu mask that will be used to determine if a
+ core can be used for freq control.
- qcom,core-limit-temp: Threshold temperature to start shutting down cores
in degC
- qcom,core-temp-hysterisis: Degrees C below which the cores will be brought
@@ -77,6 +79,7 @@
qcom,limit-temp = <60>;
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
+ qcom,freq-control-mask = <0xf>
qcom,core-limit-temp = <90>;
qcom,core-temp-hysterisis = <10>;
qcom,core-control-mask = <7>;
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
index 2b5e143..cfda474 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_tspp.txt
@@ -28,6 +28,13 @@
Note: it is assumed that the functionality value (e.g. 1 in 8974 case)
is applicable to all TSIF GPIOs.
+Optional properties:
+
+- vdd_cx-supply: Reference to the regulator that supplies the CX rail.
+ Some hardware platforms (e.g. 8974-v2) require the voltage of the rail
+ supplying power to the TSIF hardware block to be elevated before
+ enabling the TSIF clocks.
+
Example (for 8974 platform, avaialble at msm8974.dtsi):
tspp: msm_tspp@f99d8000 {
diff --git a/Documentation/devicetree/bindings/arm/msm/pm_snoc_client.txt b/Documentation/devicetree/bindings/arm/msm/pm_snoc_client.txt
new file mode 100644
index 0000000..4f7111f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/pm_snoc_client.txt
@@ -0,0 +1,35 @@
+* MSM PM SNOC client
+
+MSM PM SNOC client device is used to setup a bus request for 100 Mhz for the
+SNOC bus when the Apps cores are active. This bus request helps mitigate the
+exit latency from power collapse in cases where there aren't any active bus
+requests for SNOC.
+
+This device is dependent on the pm-8x60 device, which configures the low power
+mode of respective cores.
+
+The required properties of this device are:
+
+- compatible: qcom,pm-snoc-client
+- qcom,msm-bus,name: String representing the client-name
+- qcom,msm-bus,num-cases: Total number of usecases
+- qcom,msm-bus,active-only: Boolean context flag for requests in active or
+ dual (active & sleep) contex
+- qcom,msm-bus,num-paths: Total number of master-slave pairs
+- qcom,msm-bus,vectors-KBps: Arrays of unsigned integers representing:
+ master-id, slave-id, arbitrated bandwidth
+ in KBps, instantaneous bandwidth in KBps
+
+
+Example:
+ qcom,pm-snoc-client {
+ compatible = "qcom,pm-snoc-client";
+ qcom,msm-bus,name = "ocimem_snoc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors =
+ <22 512 0 0>,
+ <22 512 320000 3200000>;
+ };
+
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index a9528c5..7ed873f 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -56,9 +56,9 @@
- qcom,enable-gpio: Specifies the panel lcd/display enable gpio.
- qcom,rst-gpio: Specifies the panel reset gpio.
- qcom,te-gpio: Specifies the gpio used for TE.
-- qcom,dsi-lpg-channel : LPG channel for backlight.
-- qcom,dsi-pwm-period : PWM period in microseconds.
-- qcom,dsi-pwm-gpio : PWM gpio.
+- qcom,pwm-lpg-channel: LPG channel for backlight.
+- qcom,pwm-period: PWM period in microseconds.
+- qcom,pwm-pmic-gpio: PMIC gpio binding to backlight.
- qcom,mdss-pan-broadcast-mode: Boolean used to enable broadcast mode.
- qcom,cont-splash-enabled: Boolean used to enable continuous splash mode.
- qcom,fbc-enabled: Boolean used to enable frame buffer compression mode.
@@ -174,6 +174,19 @@
- qcom,off-cmds-dsi-state: A string that Specifies the ctrl state for sending ON commands.
Supported modes are "DSI_LP_MODE" and "DSI_HS_MODE".
+
+- qcom,panel-on-cmds: A byte stream formed by multiple dcs packets base on
+ qcom dsi controller protocol.
+ byte 0 : dcs data type
+ byte 1 : set to indicate this is an individual packet
+ (no chain).
+ byte 2 : virtual channel number
+ byte 3 : expect ack from client (dcs read command)
+ byte 4 : wait number of specified ms after dcs command
+ transmitted
+ byte 5, 6: 16 bits length in network byte order
+ byte 7 and beyond: number byte of payload
+
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -204,7 +217,7 @@
qcom,mdss-pan-dsi-mdp-tr = <0x04>;
qcom,mdss-pan-dsi-dma-tr = <0x04>;
qcom,mdss-pan-frame-rate = <60>;
- qcom,panel-on-cmds = [32 01 00 00 00 02 00 00];
+ qcom,panel-on-cmds = [32 01 00 00 00 00 02 00 00];
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
qcom,panel-off-cmds = [22 01 00 00 00 00 00];
qcom,off-cmds-dsi-state = "DSI LP MODE";
diff --git a/Documentation/devicetree/bindings/input/gen_vkeys.txt b/Documentation/devicetree/bindings/input/gen_vkeys.txt
index 76cacd8..2f8d65e 100644
--- a/Documentation/devicetree/bindings/input/gen_vkeys.txt
+++ b/Documentation/devicetree/bindings/input/gen_vkeys.txt
@@ -11,7 +11,10 @@
- qcom,panel-maxx : Maximum x-coordinate of touch panel
- qcom,panel-maxy : Maximum y-coordinate of touch panel
- qcom,key-codes : Array of key codes for virtual keys
- - qcom,y-offset : Offset of y-location for virtual keys
+
+Optional properties:
+ - qcom,y-offset : Offset of y-location for virtual keys, default 0
+
Example:
gen-vkeys {
compatible = "qcom,gen-vkeys";
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
index af5cbc6..c7c6415 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
@@ -13,10 +13,12 @@
- qcom,iommu-pmu-event-classes: List of event classes supported.
- qcom,needs-alt-core-clk : boolean to enable the secondary core clock for
access to the IOMMU configuration registers
+- Bus scaling properties: See msm_bus.txt
- List of sub nodes, one for each of the translation context banks supported.
Required properties for each sub-node:
+ - compatible : "qcom,msm-smmu-v0-ctx"
- reg : offset and length of the register set for the context bank.
- interrupts : should contain the context bank interrupt.
- qcom,iommu-ctx-mids : List of machine identifiers associated with this
@@ -42,6 +44,7 @@
0x11>;
qcom,iommu-ctx@fd000000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd000000 0x1000>;
interrupts = <0 250 0>;
qcom,iommu-ctx-mids = <0 3>;
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
index 2c47f74..ed45979 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
@@ -21,10 +21,12 @@
- qcom,iommu-pmu-ngroups: Number of Performance Monitor Unit (PMU) groups.
- qcom,iommu-pmu-ncounters: Number of PMU counters per group.
- qcom,iommu-pmu-event-classes: List of event classes supported.
+- Bus scaling properties: See msm_bus.txt
- List of sub nodes, one for each of the translation context banks supported.
Each sub node has the following required properties:
+ - compatible : "qcom,msm-smmu-v1-ctx"
- reg : offset and length of the register set for the context bank.
- interrupts : should contain the context bank interrupt.
- qcom,iommu-ctx-sids : List of stream identifiers associated with this
@@ -65,12 +67,14 @@
0x01>;
qcom,iommu-ctx@fda6c000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda6c000 0x1000>;
interrupts = <0 70 0>;
qcom,iommu-ctx-sids = <0 2>;
label = "ctx_0";
};
qcom,iommu-ctx@fda6d000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda6d000 0x1000>;
interrupts = <0 71 0>;
qcom,iommu-ctx-sids = <1>;
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 9a7fa90..1836867 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -51,6 +51,9 @@
- qcom,sensor-name : should contain unique sensor name to differentiate from
other sensor
- "s5k3l1yx"
+- qcom,vdd-cx-supply : should contain regulator from which cx voltage is
+ supplied
+- qcom,vdd-cx-name : should contain names of cx regulator
- cam_vdig-supply : should contain regulator from which digital voltage is
supplied
- cam_vana-supply : should contain regulator from which analog voltage is
@@ -91,6 +94,7 @@
- gpios : should contain phandle to gpio controller node and array of
#gpio-cells specifying specific gpio (controller specific)
- qcom,gpio-reset : should contain index to gpio used by sensors reset_n
+- qcom,gpio-standby : should contain index to gpio used by sensors standby_n
- 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)
@@ -190,6 +194,8 @@
qcom,led-flash-src = <&led_flash0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -201,11 +207,15 @@
qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
qcom,gpio-req-tbl-label = "CAMIF_MCLK",
- "CAM_RESET1";
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 4000>;
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index 4cbff52..a7a3f0c 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -15,6 +15,7 @@
- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain.
- qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
- qcom,gpio-err-fatal: GPIO used by the lpass to indicate error fatal to the apps.
+- qcom,gpio-err-ready: GPIO used by the lpass to indicate apps error service is ready.
- qcom,gpio-force-stop: GPIO used by the apps to force the lpass to shutdown.
- qcom,gpio-proxy-unvote: GPIO used by the lpass to indicate apps clock is ready.
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 4a312a8..ded8f77 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -30,7 +30,8 @@
- qcom,vdd_pll: Voltage to be set for the PLL's rail.
- reg-names: "cxrail_bhs_reg" - control register for modem power
domain.
-- qcom,is-loadable: Boolean- Present if the image needs to be loaded.
+- qcom,is-not-loadable: Boolean- Present if the image does not need to
+ be loaded.
- qcom,pil-self-auth: Boolean- True if authentication is required.
Example:
@@ -47,7 +48,7 @@
vdd_cx-supply = <&pm8841_s2>;
vdd_mx-supply = <&pm8841_s1>;
- qcom,is-loadable;
+ qcom,is-not-loadable;
qcom,firmware-name = "mba";
qcom,pil-self-auth;
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index 6d093f0..b350e24 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -47,7 +47,7 @@
SoC recalculations when the current SoC is below
qcom,low-soc-calculate-soc-threshold or when battery
voltage is below qcom,low-voltage-threshold.
-- qcom,soc-calculate-soc-ms : The time period between subsequent SoC
+- qcom,calculate-soc-ms : The time period between subsequent SoC
recalculations when the current SoC is above or equal
qcom,low-soc-calculate-soc-threshold.
- qcom,chg-term-ua : current in micro-amps when charging is considered done.
@@ -64,6 +64,9 @@
curve.
- qcom,hold-soc-est: if the voltage-based estimated SoC is above this percent,
the BMS will clamp SoC to be at least 1.
+- qcom,tm-temp-margin: if the pmic die temperature changes by more than this
+ value, recalibrate the ADCs. The unit of this property
+ is in millidegrees celsius.
Parent node optional properties:
- qcom,ignore-shutdown-soc: A boolean that controls whether BMS will
@@ -122,6 +125,7 @@
qcom,low-ocv-correction-limit-uv = <100>;
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
+ qcom,tm-temp-margin = <5000>;
qcom,bms-iadc@3800 {
reg = <0x3800 0x100>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index fced0d7..359ee6c 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -56,6 +56,13 @@
- qcom,warm-bat-mv: Warm temperature battery target voltage.
- qcom,cool-bat-mv: Cool temperature battery target voltage.
- qcom,tchg-mins: Maximum total software initialized charge time.
+- qcom,bpd-detection: Select a battery presence detection scheme by
+ specifying either "bpd_thm", "bpd_id" or
+ "bpd_thm_id". "bpd_thm" selects the temperature
+ pin, "bpd_id" uses the id pin for battery presence
+ detection, "bpd_thm_id" selects both.
+ If the property is not set the hw default will
+ be used.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index f2cfe34..daa68b3 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -15,6 +15,8 @@
- qcom,retain-mems: Presence denotes a hardware requirement to leave the
forced memory retention signals in the core's clock
branch control register asserted.
+ - qcom,retain-logic: Presence denotes a requirement to leave power to the
+ core's logic enabled.
Example:
gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index 6a02e86..a8195df 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -9,16 +9,27 @@
[First Level Nodes]
Required properties:
- compatible: Must be "qcom,krait-pdn"
-- reg: Specifies the physical address of the APCS GCC
- register base
-- reg-names: "apcs_gcc" -string to identify the area where
- the APCS GCC registers reside.
+- reg: This property contains a list of physical
+ addresses for Krait PDN features. The list
+ should contain the address of the APCS GCC
+ register base and the address of the phase
+ scaling factor eFuse.
+- reg-names: This property contains a list of strings naming
+ the registers listed in the reg property.
+ "apcs_gcc" is a string to identify the area
+ where the APCS GCC registers reside.
+ "phase-scaling-efuse" should be used to identify
+ the phase scaling factor eFuse address.
- qcom,pfm-threshold The power coeff threshold in abstract power units below which
pmic will be made to operate in PFM mode.
Optional properties:
- qcom,use-phase-switching indicates whether the driver should add/shed phases on the PMIC
ganged regulator as cpus are hotplugged.
+- qcom,use-phase-scaling-factor Boolean which indicates if the value stored in
+ the phase scaling eFuse should be used or not.
+ If this property is not specified, then worst
+ case scaling will be assumed.
[Second Level Nodes]
Required properties:
@@ -49,10 +60,12 @@
Example:
krait_pdn: krait-pdn@f9011000 {
- reg = <0xf9011000 0x1000>;
- reg-names = "apcs_gcc";
+ reg = <0xf9011000 0x1000>,
+ <0xfc4b80b0 8>;
+ reg-names = "apcs_gcc", "phase-scaling-efuse";
compatible = "qcom,krait-pdn";
qcom,use-phase-switching;
+ qcom,use-phase-scaling-factor;
qcom,pfm-threshold = <376975>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 9f6cb16..74ea2cd 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -465,6 +465,8 @@
- qcom,ext-ult-lo-amp-gpio: GPIO to enable external ultrasound lineout
amplifier.
+- qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
+
Example:
sound {
@@ -667,3 +669,32 @@
compatible = "qcom,msm-audio-ion;
qcom,smmu-enabled;
};
+
+* MSM8226 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,msm8226-audio-tapan"
+- qcom,model : The user-visible name of this sound card.
+- qcom,tapan-mclk-clk-freq : Tapan mclk Freq in Hz. currently only 9600000Hz
+ is supported.
+- qcom,prim-auxpcm-gpio-clk : GPIO on which Primary AUXPCM clk signal is coming.
+- qcom,prim-auxpcm-gpio-sync : GPIO on which Primary AUXPCM SYNC signal is coming.
+- qcom,prim-auxpcm-gpio-din : GPIO on which Primary AUXPCM DIN signal is coming.
+- qcom,prim-auxpcm-gpio-dout : GPIO on which Primary AUXPCM DOUT signal is coming.
+- qcom,prim-auxpcm-gpio-set : set of GPIO lines used for Primary AUXPCM port
+ Possible Values:
+ prim-gpio-prim : Primary AUXPCM shares GPIOs with Primary MI2S
+ prim-gpio-tert : Primary AUXPCM shares GPIOs with Tertiary MI2S
+
+Example:
+
+sound {
+ compatible = "qcom,msm8226-audio-tapan";
+ qcom,model = "msm8226-tapan-snd-card";
+ qcom,tapan-mclk-clk-freq = <9600000>;
+ qcom,prim-auxpcm-gpio-clk = <&msmgpio 63 0>;
+ qcom,prim-auxpcm-gpio-sync = <&msmgpio 64 0>;
+ qcom,prim-auxpcm-gpio-din = <&msmgpio 65 0>;
+ qcom,prim-auxpcm-gpio-dout = <&msmgpio 66 0>;
+ qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
+};
diff --git a/Documentation/workqueue.txt b/Documentation/workqueue.txt
index a0b577d..a6ab4b6 100644
--- a/Documentation/workqueue.txt
+++ b/Documentation/workqueue.txt
@@ -89,25 +89,28 @@
The cmwq design differentiates between the user-facing workqueues that
subsystems and drivers queue work items on and the backend mechanism
-which manages thread-pool and processes the queued work items.
+which manages thread-pools and processes the queued work items.
The backend is called gcwq. There is one gcwq for each possible CPU
-and one gcwq to serve work items queued on unbound workqueues.
+and one gcwq to serve work items queued on unbound workqueues. Each
+gcwq has two thread-pools - one for normal work items and the other
+for high priority ones.
Subsystems and drivers can create and queue work items through special
workqueue API functions as they see fit. They can influence some
aspects of the way the work items are executed by setting flags on the
workqueue they are putting the work item on. These flags include
-things like CPU locality, reentrancy, concurrency limits and more. To
-get a detailed overview refer to the API description of
+things like CPU locality, reentrancy, concurrency limits, priority and
+more. To get a detailed overview refer to the API description of
alloc_workqueue() below.
-When a work item is queued to a workqueue, the target gcwq is
-determined according to the queue parameters and workqueue attributes
-and appended on the shared worklist of the gcwq. For example, unless
-specifically overridden, a work item of a bound workqueue will be
-queued on the worklist of exactly that gcwq that is associated to the
-CPU the issuer is running on.
+When a work item is queued to a workqueue, the target gcwq and
+thread-pool is determined according to the queue parameters and
+workqueue attributes and appended on the shared worklist of the
+thread-pool. For example, unless specifically overridden, a work item
+of a bound workqueue will be queued on the worklist of either normal
+or highpri thread-pool of the gcwq that is associated to the CPU the
+issuer is running on.
For any worker pool implementation, managing the concurrency level
(how many execution contexts are active) is an important issue. cmwq
@@ -115,26 +118,26 @@
Minimal to save resources and sufficient in that the system is used at
its full capacity.
-Each gcwq bound to an actual CPU implements concurrency management by
-hooking into the scheduler. The gcwq is notified whenever an active
-worker wakes up or sleeps and keeps track of the number of the
-currently runnable workers. Generally, work items are not expected to
-hog a CPU and consume many cycles. That means maintaining just enough
-concurrency to prevent work processing from stalling should be
-optimal. As long as there are one or more runnable workers on the
-CPU, the gcwq doesn't start execution of a new work, but, when the
-last running worker goes to sleep, it immediately schedules a new
-worker so that the CPU doesn't sit idle while there are pending work
-items. This allows using a minimal number of workers without losing
-execution bandwidth.
+Each thread-pool bound to an actual CPU implements concurrency
+management by hooking into the scheduler. The thread-pool is notified
+whenever an active worker wakes up or sleeps and keeps track of the
+number of the currently runnable workers. Generally, work items are
+not expected to hog a CPU and consume many cycles. That means
+maintaining just enough concurrency to prevent work processing from
+stalling should be optimal. As long as there are one or more runnable
+workers on the CPU, the thread-pool doesn't start execution of a new
+work, but, when the last running worker goes to sleep, it immediately
+schedules a new worker so that the CPU doesn't sit idle while there
+are pending work items. This allows using a minimal number of workers
+without losing execution bandwidth.
Keeping idle workers around doesn't cost other than the memory space
for kthreads, so cmwq holds onto idle ones for a while before killing
them.
For an unbound wq, the above concurrency management doesn't apply and
-the gcwq for the pseudo unbound CPU tries to start executing all work
-items as soon as possible. The responsibility of regulating
+the thread-pools for the pseudo unbound CPU try to start executing all
+work items as soon as possible. The responsibility of regulating
concurrency level is on the users. There is also a flag to mark a
bound wq to ignore the concurrency management. Please refer to the
API section for details.
@@ -205,31 +208,22 @@
WQ_HIGHPRI
- Work items of a highpri wq are queued at the head of the
- worklist of the target gcwq and start execution regardless of
- the current concurrency level. In other words, highpri work
- items will always start execution as soon as execution
- resource is available.
+ Work items of a highpri wq are queued to the highpri
+ thread-pool of the target gcwq. Highpri thread-pools are
+ served by worker threads with elevated nice level.
- Ordering among highpri work items is preserved - a highpri
- work item queued after another highpri work item will start
- execution after the earlier highpri work item starts.
-
- Although highpri work items are not held back by other
- runnable work items, they still contribute to the concurrency
- level. Highpri work items in runnable state will prevent
- non-highpri work items from starting execution.
-
- This flag is meaningless for unbound wq.
+ Note that normal and highpri thread-pools don't interact with
+ each other. Each maintain its separate pool of workers and
+ implements concurrency management among its workers.
WQ_CPU_INTENSIVE
Work items of a CPU intensive wq do not contribute to the
concurrency level. In other words, runnable CPU intensive
- work items will not prevent other work items from starting
- execution. This is useful for bound work items which are
- expected to hog CPU cycles so that their execution is
- regulated by the system scheduler.
+ work items will not prevent other work items in the same
+ thread-pool from starting execution. This is useful for bound
+ work items which are expected to hog CPU cycles so that their
+ execution is regulated by the system scheduler.
Although CPU intensive work items don't contribute to the
concurrency level, start of their executions is still
@@ -239,14 +233,6 @@
This flag is meaningless for unbound wq.
- WQ_HIGHPRI | WQ_CPU_INTENSIVE
-
- This combination makes the wq avoid interaction with
- concurrency management completely and behave as a simple
- per-CPU execution context provider. Work items queued on a
- highpri CPU-intensive wq start execution as soon as resources
- are available and don't affect execution of other work items.
-
@max_active:
@max_active determines the maximum number of execution contexts per
@@ -328,20 +314,7 @@
35 w2 wakes up and finishes
Now, let's assume w1 and w2 are queued to a different wq q1 which has
-WQ_HIGHPRI set,
-
- TIME IN MSECS EVENT
- 0 w1 and w2 start and burn CPU
- 5 w1 sleeps
- 10 w2 sleeps
- 10 w0 starts and burns CPU
- 15 w0 sleeps
- 15 w1 wakes up and finishes
- 20 w2 wakes up and finishes
- 25 w0 wakes up and burns CPU
- 30 w0 finishes
-
-If q1 has WQ_CPU_INTENSIVE set,
+WQ_CPU_INTENSIVE set,
TIME IN MSECS EVENT
0 w0 starts and burns CPU
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index c56f06a..ea626c8 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -230,8 +230,31 @@
qcom,rfr-gpio = <&msmgpio 44 0x00>;
};
+&usb_otg {
+ status = "ok";
+ qcom,hsusb-otg-otg-control = <2>;
+ qcom,hsusb-otg-mode = <3>;
+ vbus_otg-supply = <&pm8941_mvs1>;
+ qcom,usb2-enable-hsphy2;
+ qcom,dp-manual-pullup;
+
+ #address-cells = <0>;
+ interrupt-parent = <&usb_otg>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 134 0
+ 1 &intc 0 140 0
+ 2 &spmi_bus 0x0 0x0 0x9 0x0>;
+ interrupt-names = "core_irq", "async_irq", "pmic_id_irq";
+};
+
&usb3 {
qcom,charging-disabled;
+ vbus_dwc3-supply = <0>;
+ dwc3@f9200000 {
+ host-only-mode;
+ };
};
&slim_msm {
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index 2543c40..224089e 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/include/ "skeleton.dtsi"
+/include/ "skeleton64.dtsi"
/ {
model = "Qualcomm APQ 8084";
@@ -24,7 +24,7 @@
&soc {
#address-cells = <1>;
#size-cells = <1>;
- ranges;
+ ranges = <0 0 0 0xffffffff>;
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
@@ -201,6 +201,11 @@
};
};
+
+ memory_hole: qcom,msm-mem-hole {
+ compatible = "qcom,msm-mem-hole";
+ qcom,memblock-remove = <0x0dc00000 0x2000000>; /* Address and Size of Hole */
+ };
};
/include/ "msm-pma8084.dtsi"
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index 10ca8a8..7bc748d 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -51,474 +51,474 @@
00 00 00 00 0a 00 00 01 97 /* lane2 config */
00 00 00 00 0f 00 00 01 97 /* lane3 config */
00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
- qcom,panel-on-cmds = [29 01 00 00 00 02 FF EE
- 29 01 00 00 00 02 26 08
- 29 01 00 00 00 02 26 00
- 29 01 00 00 10 02 FF 00
- 29 01 00 00 00 02 BA 03
- 29 01 00 00 00 02 C2 03
- 29 01 00 00 00 02 FF 01
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 00 4A
- 29 01 00 00 00 02 01 33
- 29 01 00 00 00 02 02 53
- 29 01 00 00 00 02 03 55
- 29 01 00 00 00 02 04 55
- 29 01 00 00 00 02 05 33
- 29 01 00 00 00 02 06 22
- 29 01 00 00 00 02 08 56
- 29 01 00 00 00 02 09 8F
- 29 01 00 00 00 02 36 73
- 29 01 00 00 00 02 0B 9F
- 29 01 00 00 00 02 0C 9F
- 29 01 00 00 00 02 0D 2F
- 29 01 00 00 00 02 0E 24
- 29 01 00 00 00 02 11 83
- 29 01 00 00 00 02 12 03
- 29 01 00 00 00 02 71 2C
- 29 01 00 00 00 02 6F 03
- 29 01 00 00 00 02 0F 0A
- 29 01 00 00 00 02 FF 05
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 01 00
- 29 01 00 00 00 02 02 8B
- 29 01 00 00 00 02 03 82
- 29 01 00 00 00 02 04 82
- 29 01 00 00 00 02 05 30
- 29 01 00 00 00 02 06 33
- 29 01 00 00 00 02 07 01
- 29 01 00 00 00 02 08 00
- 29 01 00 00 00 02 09 46
- 29 01 00 00 00 02 0A 46
- 29 01 00 00 00 02 0D 0B
- 29 01 00 00 00 02 0E 1D
- 29 01 00 00 00 02 0F 08
- 29 01 00 00 00 02 10 53
- 29 01 00 00 00 02 11 00
- 29 01 00 00 00 02 12 00
- 29 01 00 00 00 02 14 01
- 29 01 00 00 00 02 15 00
- 29 01 00 00 00 02 16 05
- 29 01 00 00 00 02 17 00
- 29 01 00 00 00 02 19 7F
- 29 01 00 00 00 02 1A FF
- 29 01 00 00 00 02 1B 0F
- 29 01 00 00 00 02 1C 00
- 29 01 00 00 00 02 1D 00
- 29 01 00 00 00 02 1E 00
- 29 01 00 00 00 02 1F 07
- 29 01 00 00 00 02 20 00
- 29 01 00 00 00 02 21 06
- 29 01 00 00 00 02 22 55
- 29 01 00 00 00 02 23 4D
- 29 01 00 00 00 02 2D 02
- 29 01 00 00 00 02 28 01
- 29 01 00 00 00 02 2F 02
- 29 01 00 00 00 02 83 01
- 29 01 00 00 00 02 9E 58
- 29 01 00 00 00 02 9F 6A
- 29 01 00 00 00 02 A0 01
- 29 01 00 00 00 02 A2 10
- 29 01 00 00 00 02 BB 0A
- 29 01 00 00 00 02 BC 0A
- 29 01 00 00 00 02 32 08
- 29 01 00 00 00 02 33 B8
- 29 01 00 00 00 02 36 01
- 29 01 00 00 00 02 37 00
- 29 01 00 00 00 02 43 00
- 29 01 00 00 00 02 4B 21
- 29 01 00 00 00 02 4C 03
- 29 01 00 00 00 02 50 21
- 29 01 00 00 00 02 51 03
- 29 01 00 00 00 02 58 21
- 29 01 00 00 00 02 59 03
- 29 01 00 00 00 02 5D 21
- 29 01 00 00 00 02 5E 03
- 29 01 00 00 00 02 6C 00
- 29 01 00 00 00 02 6D 00
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 FF 01
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 75 00
- 29 01 00 00 00 02 76 7D
- 29 01 00 00 00 02 77 00
- 29 01 00 00 00 02 78 8A
- 29 01 00 00 00 02 79 00
- 29 01 00 00 00 02 7A 9C
- 29 01 00 00 00 02 7B 00
- 29 01 00 00 00 02 7C B1
- 29 01 00 00 00 02 7D 00
- 29 01 00 00 00 02 7E BF
- 29 01 00 00 00 02 7F 00
- 29 01 00 00 00 02 80 CF
- 29 01 00 00 00 02 81 00
- 29 01 00 00 00 02 82 DD
- 29 01 00 00 00 02 83 00
- 29 01 00 00 00 02 84 E8
- 29 01 00 00 00 02 85 00
- 29 01 00 00 00 02 86 F2
- 29 01 00 00 00 02 87 01
- 29 01 00 00 00 02 88 1F
- 29 01 00 00 00 02 89 01
- 29 01 00 00 00 02 8A 41
- 29 01 00 00 00 02 8B 01
- 29 01 00 00 00 02 8C 78
- 29 01 00 00 00 02 8D 01
- 29 01 00 00 00 02 8E A5
- 29 01 00 00 00 02 8F 01
- 29 01 00 00 00 02 90 EE
- 29 01 00 00 00 02 91 02
- 29 01 00 00 00 02 92 29
- 29 01 00 00 00 02 93 02
- 29 01 00 00 00 02 94 2A
- 29 01 00 00 00 02 95 02
- 29 01 00 00 00 02 96 5D
- 29 01 00 00 00 02 97 02
- 29 01 00 00 00 02 98 93
- 29 01 00 00 00 02 99 02
- 29 01 00 00 00 02 9A B8
- 29 01 00 00 00 02 9B 02
- 29 01 00 00 00 02 9C E7
- 29 01 00 00 00 02 9D 03
- 29 01 00 00 00 02 9E 07
- 29 01 00 00 00 02 9F 03
- 29 01 00 00 00 02 A0 37
- 29 01 00 00 00 02 A2 03
- 29 01 00 00 00 02 A3 46
- 29 01 00 00 00 02 A4 03
- 29 01 00 00 00 02 A5 56
- 29 01 00 00 00 02 A6 03
- 29 01 00 00 00 02 A7 66
- 29 01 00 00 00 02 A9 03
- 29 01 00 00 00 02 AA 7A
- 29 01 00 00 00 02 AB 03
- 29 01 00 00 00 02 AC 93
- 29 01 00 00 00 02 AD 03
- 29 01 00 00 00 02 AE A3
- 29 01 00 00 00 02 AF 03
- 29 01 00 00 00 02 B0 B4
- 29 01 00 00 00 02 B1 03
- 29 01 00 00 00 02 B2 CB
- 29 01 00 00 00 02 B3 00
- 29 01 00 00 00 02 B4 7D
- 29 01 00 00 00 02 B5 00
- 29 01 00 00 00 02 B6 8A
- 29 01 00 00 00 02 B7 00
- 29 01 00 00 00 02 B8 9C
- 29 01 00 00 00 02 B9 00
- 29 01 00 00 00 02 BA B1
- 29 01 00 00 00 02 BB 00
- 29 01 00 00 00 02 BC BF
- 29 01 00 00 00 02 BD 00
- 29 01 00 00 00 02 BE CF
- 29 01 00 00 00 02 BF 00
- 29 01 00 00 00 02 C0 DD
- 29 01 00 00 00 02 C1 00
- 29 01 00 00 00 02 C2 E8
- 29 01 00 00 00 02 C3 00
- 29 01 00 00 00 02 C4 F2
- 29 01 00 00 00 02 C5 01
- 29 01 00 00 00 02 C6 1F
- 29 01 00 00 00 02 C7 01
- 29 01 00 00 00 02 C8 41
- 29 01 00 00 00 02 C9 01
- 29 01 00 00 00 02 CA 78
- 29 01 00 00 00 02 CB 01
- 29 01 00 00 00 02 CC A5
- 29 01 00 00 00 02 CD 01
- 29 01 00 00 00 02 CE EE
- 29 01 00 00 00 02 CF 02
- 29 01 00 00 00 02 D0 29
- 29 01 00 00 00 02 D1 02
- 29 01 00 00 00 02 D2 2A
- 29 01 00 00 00 02 D3 02
- 29 01 00 00 00 02 D4 5D
- 29 01 00 00 00 02 D5 02
- 29 01 00 00 00 02 D6 93
- 29 01 00 00 00 02 D7 02
- 29 01 00 00 00 02 D8 B8
- 29 01 00 00 00 02 D9 02
- 29 01 00 00 00 02 DA E7
- 29 01 00 00 00 02 DB 03
- 29 01 00 00 00 02 DC 07
- 29 01 00 00 00 02 DD 03
- 29 01 00 00 00 02 DE 37
- 29 01 00 00 00 02 DF 03
- 29 01 00 00 00 02 E0 46
- 29 01 00 00 00 02 E1 03
- 29 01 00 00 00 02 E2 56
- 29 01 00 00 00 02 E3 03
- 29 01 00 00 00 02 E4 66
- 29 01 00 00 00 02 E5 03
- 29 01 00 00 00 02 E6 7A
- 29 01 00 00 00 02 E7 03
- 29 01 00 00 00 02 E8 93
- 29 01 00 00 00 02 E9 03
- 29 01 00 00 00 02 EA A3
- 29 01 00 00 00 02 EB 03
- 29 01 00 00 00 02 EC B4
- 29 01 00 00 00 02 ED 03
- 29 01 00 00 00 02 EE CB
- 29 01 00 00 00 02 EF 00
- 29 01 00 00 00 02 F0 ED
- 29 01 00 00 00 02 F1 00
- 29 01 00 00 00 02 F2 F3
- 29 01 00 00 00 02 F3 00
- 29 01 00 00 00 02 F4 FE
- 29 01 00 00 00 02 F5 01
- 29 01 00 00 00 02 F6 09
- 29 01 00 00 00 02 F7 01
- 29 01 00 00 00 02 F8 13
- 29 01 00 00 00 02 F9 01
- 29 01 00 00 00 02 FA 1D
- 29 01 00 00 00 02 FF 02
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 00 01
- 29 01 00 00 00 02 01 26
- 29 01 00 00 00 02 02 01
- 29 01 00 00 00 02 03 2F
- 29 01 00 00 00 02 04 01
- 29 01 00 00 00 02 05 37
- 29 01 00 00 00 02 06 01
- 29 01 00 00 00 02 07 56
- 29 01 00 00 00 02 08 01
- 29 01 00 00 00 02 09 70
- 29 01 00 00 00 02 0A 01
- 29 01 00 00 00 02 0B 9D
- 29 01 00 00 00 02 0C 01
- 29 01 00 00 00 02 0D C2
- 29 01 00 00 00 02 0E 01
- 29 01 00 00 00 02 0F FF
- 29 01 00 00 00 02 10 02
- 29 01 00 00 00 02 11 31
- 29 01 00 00 00 02 12 02
- 29 01 00 00 00 02 13 32
- 29 01 00 00 00 02 14 02
- 29 01 00 00 00 02 15 60
- 29 01 00 00 00 02 16 02
- 29 01 00 00 00 02 17 94
- 29 01 00 00 00 02 18 02
- 29 01 00 00 00 02 19 B5
- 29 01 00 00 00 02 1A 02
- 29 01 00 00 00 02 1B E3
- 29 01 00 00 00 02 1C 03
- 29 01 00 00 00 02 1D 03
- 29 01 00 00 00 02 1E 03
- 29 01 00 00 00 02 1F 2D
- 29 01 00 00 00 02 20 03
- 29 01 00 00 00 02 21 3A
- 29 01 00 00 00 02 22 03
- 29 01 00 00 00 02 23 48
- 29 01 00 00 00 02 24 03
- 29 01 00 00 00 02 25 57
- 29 01 00 00 00 02 26 03
- 29 01 00 00 00 02 27 68
- 29 01 00 00 00 02 28 03
- 29 01 00 00 00 02 29 7B
- 29 01 00 00 00 02 2A 03
- 29 01 00 00 00 02 2B 90
- 29 01 00 00 00 02 2D 03
- 29 01 00 00 00 02 2F A0
- 29 01 00 00 00 02 30 03
- 29 01 00 00 00 02 31 CB
- 29 01 00 00 00 02 32 00
- 29 01 00 00 00 02 33 ED
- 29 01 00 00 00 02 34 00
- 29 01 00 00 00 02 35 F3
- 29 01 00 00 00 02 36 00
- 29 01 00 00 00 02 37 FE
- 29 01 00 00 00 02 38 01
- 29 01 00 00 00 02 39 09
- 29 01 00 00 00 02 3A 01
- 29 01 00 00 00 02 3B 13
- 29 01 00 00 00 02 3D 01
- 29 01 00 00 00 02 3F 1D
- 29 01 00 00 00 02 40 01
- 29 01 00 00 00 02 41 26
- 29 01 00 00 00 02 42 01
- 29 01 00 00 00 02 43 2F
- 29 01 00 00 00 02 44 01
- 29 01 00 00 00 02 45 37
- 29 01 00 00 00 02 46 01
- 29 01 00 00 00 02 47 56
- 29 01 00 00 00 02 48 01
- 29 01 00 00 00 02 49 70
- 29 01 00 00 00 02 4A 01
- 29 01 00 00 00 02 4B 9D
- 29 01 00 00 00 02 4C 01
- 29 01 00 00 00 02 4D C2
- 29 01 00 00 00 02 4E 01
- 29 01 00 00 00 02 4F FF
- 29 01 00 00 00 02 50 02
- 29 01 00 00 00 02 51 31
- 29 01 00 00 00 02 52 02
- 29 01 00 00 00 02 53 32
- 29 01 00 00 00 02 54 02
- 29 01 00 00 00 02 55 60
- 29 01 00 00 00 02 56 02
- 29 01 00 00 00 02 58 94
- 29 01 00 00 00 02 59 02
- 29 01 00 00 00 02 5A B5
- 29 01 00 00 00 02 5B 02
- 29 01 00 00 00 02 5C E3
- 29 01 00 00 00 02 5D 03
- 29 01 00 00 00 02 5E 03
- 29 01 00 00 00 02 5F 03
- 29 01 00 00 00 02 60 2D
- 29 01 00 00 00 02 61 03
- 29 01 00 00 00 02 62 3A
- 29 01 00 00 00 02 63 03
- 29 01 00 00 00 02 64 48
- 29 01 00 00 00 02 65 03
- 29 01 00 00 00 02 66 57
- 29 01 00 00 00 02 67 03
- 29 01 00 00 00 02 68 68
- 29 01 00 00 00 02 69 03
- 29 01 00 00 00 02 6A 7B
- 29 01 00 00 00 02 6B 03
- 29 01 00 00 00 02 6C 90
- 29 01 00 00 00 02 6D 03
- 29 01 00 00 00 02 6E A0
- 29 01 00 00 00 02 6F 03
- 29 01 00 00 00 02 70 CB
- 29 01 00 00 00 02 71 00
- 29 01 00 00 00 02 72 19
- 29 01 00 00 00 02 73 00
- 29 01 00 00 00 02 74 36
- 29 01 00 00 00 02 75 00
- 29 01 00 00 00 02 76 55
- 29 01 00 00 00 02 77 00
- 29 01 00 00 00 02 78 70
- 29 01 00 00 00 02 79 00
- 29 01 00 00 00 02 7A 83
- 29 01 00 00 00 02 7B 00
- 29 01 00 00 00 02 7C 99
- 29 01 00 00 00 02 7D 00
- 29 01 00 00 00 02 7E A8
- 29 01 00 00 00 02 7F 00
- 29 01 00 00 00 02 80 B7
- 29 01 00 00 00 02 81 00
- 29 01 00 00 00 02 82 C5
- 29 01 00 00 00 02 83 00
- 29 01 00 00 00 02 84 F7
- 29 01 00 00 00 02 85 01
- 29 01 00 00 00 02 86 1E
- 29 01 00 00 00 02 87 01
- 29 01 00 00 00 02 88 60
- 29 01 00 00 00 02 89 01
- 29 01 00 00 00 02 8A 95
- 29 01 00 00 00 02 8B 01
- 29 01 00 00 00 02 8C E1
- 29 01 00 00 00 02 8D 02
- 29 01 00 00 00 02 8E 20
- 29 01 00 00 00 02 8F 02
- 29 01 00 00 00 02 90 23
- 29 01 00 00 00 02 91 02
- 29 01 00 00 00 02 92 59
- 29 01 00 00 00 02 93 02
- 29 01 00 00 00 02 94 94
- 29 01 00 00 00 02 95 02
- 29 01 00 00 00 02 96 B4
- 29 01 00 00 00 02 97 02
- 29 01 00 00 00 02 98 E1
- 29 01 00 00 00 02 99 03
- 29 01 00 00 00 02 9A 01
- 29 01 00 00 00 02 9B 03
- 29 01 00 00 00 02 9C 28
- 29 01 00 00 00 02 9D 03
- 29 01 00 00 00 02 9E 30
- 29 01 00 00 00 02 9F 03
- 29 01 00 00 00 02 A0 37
- 29 01 00 00 00 02 A2 03
- 29 01 00 00 00 02 A3 3B
- 29 01 00 00 00 02 A4 03
- 29 01 00 00 00 02 A5 40
- 29 01 00 00 00 02 A6 03
- 29 01 00 00 00 02 A7 50
- 29 01 00 00 00 02 A9 03
- 29 01 00 00 00 02 AA 6D
- 29 01 00 00 00 02 AB 03
- 29 01 00 00 00 02 AC 80
- 29 01 00 00 00 02 AD 03
- 29 01 00 00 00 02 AE CB
- 29 01 00 00 00 02 AF 00
- 29 01 00 00 00 02 B0 19
- 29 01 00 00 00 02 B1 00
- 29 01 00 00 00 02 B2 36
- 29 01 00 00 00 02 B3 00
- 29 01 00 00 00 02 B4 55
- 29 01 00 00 00 02 B5 00
- 29 01 00 00 00 02 B6 70
- 29 01 00 00 00 02 B7 00
- 29 01 00 00 00 02 B8 83
- 29 01 00 00 00 02 B9 00
- 29 01 00 00 00 02 BA 99
- 29 01 00 00 00 02 BB 00
- 29 01 00 00 00 02 BC A8
- 29 01 00 00 00 02 BD 00
- 29 01 00 00 00 02 BE B7
- 29 01 00 00 00 02 BF 00
- 29 01 00 00 00 02 C0 C5
- 29 01 00 00 00 02 C1 00
- 29 01 00 00 00 02 C2 F7
- 29 01 00 00 00 02 C3 01
- 29 01 00 00 00 02 C4 1E
- 29 01 00 00 00 02 C5 01
- 29 01 00 00 00 02 C6 60
- 29 01 00 00 00 02 C7 01
- 29 01 00 00 00 02 C8 95
- 29 01 00 00 00 02 C9 01
- 29 01 00 00 00 02 CA E1
- 29 01 00 00 00 02 CB 02
- 29 01 00 00 00 02 CC 20
- 29 01 00 00 00 02 CD 02
- 29 01 00 00 00 02 CE 23
- 29 01 00 00 00 02 CF 02
- 29 01 00 00 00 02 D0 59
- 29 01 00 00 00 02 D1 02
- 29 01 00 00 00 02 D2 94
- 29 01 00 00 00 02 D3 02
- 29 01 00 00 00 02 D4 B4
- 29 01 00 00 00 02 D5 02
- 29 01 00 00 00 02 D6 E1
- 29 01 00 00 00 02 D7 03
- 29 01 00 00 00 02 D8 01
- 29 01 00 00 00 02 D9 03
- 29 01 00 00 00 02 DA 28
- 29 01 00 00 00 02 DB 03
- 29 01 00 00 00 02 DC 30
- 29 01 00 00 00 02 DD 03
- 29 01 00 00 00 02 DE 37
- 29 01 00 00 00 02 DF 03
- 29 01 00 00 00 02 E0 3B
- 29 01 00 00 00 02 E1 03
- 29 01 00 00 00 02 E2 40
- 29 01 00 00 00 02 E3 03
- 29 01 00 00 00 02 E4 50
- 29 01 00 00 00 02 E5 03
- 29 01 00 00 00 02 E6 6D
- 29 01 00 00 00 02 E7 03
- 29 01 00 00 00 02 E8 80
- 29 01 00 00 00 02 E9 03
- 29 01 00 00 00 02 EA CB
- 29 01 00 00 00 02 FF 01
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 FF 02
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 FF 04
- 29 01 00 00 00 02 FB 01
- 29 01 00 00 00 02 FF 00
- 29 01 00 00 64 02 11 00
- 29 01 00 00 00 02 FF EE
- 29 01 00 00 00 02 12 50
- 29 01 00 00 00 02 13 02
- 29 01 00 00 00 02 6A 60
- 29 01 00 00 00 02 FF 00
- 29 01 00 00 78 02 29 00];
+ qcom,panel-on-cmds = [29 01 00 00 00 00 02 FF EE
+ 29 01 00 00 00 00 02 26 08
+ 29 01 00 00 00 00 02 26 00
+ 29 01 00 00 10 00 02 FF 00
+ 29 01 00 00 00 00 02 BA 03
+ 29 01 00 00 00 00 02 C2 03
+ 29 01 00 00 00 00 02 FF 01
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 00 4A
+ 29 01 00 00 00 00 02 01 33
+ 29 01 00 00 00 00 02 02 53
+ 29 01 00 00 00 00 02 03 55
+ 29 01 00 00 00 00 02 04 55
+ 29 01 00 00 00 00 02 05 33
+ 29 01 00 00 00 00 02 06 22
+ 29 01 00 00 00 00 02 08 56
+ 29 01 00 00 00 00 02 09 8F
+ 29 01 00 00 00 00 02 36 73
+ 29 01 00 00 00 00 02 0B 9F
+ 29 01 00 00 00 00 02 0C 9F
+ 29 01 00 00 00 00 02 0D 2F
+ 29 01 00 00 00 00 02 0E 24
+ 29 01 00 00 00 00 02 11 83
+ 29 01 00 00 00 00 02 12 03
+ 29 01 00 00 00 00 02 71 2C
+ 29 01 00 00 00 00 02 6F 03
+ 29 01 00 00 00 00 02 0F 0A
+ 29 01 00 00 00 00 02 FF 05
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 01 00
+ 29 01 00 00 00 00 02 02 8B
+ 29 01 00 00 00 00 02 03 82
+ 29 01 00 00 00 00 02 04 82
+ 29 01 00 00 00 00 02 05 30
+ 29 01 00 00 00 00 02 06 33
+ 29 01 00 00 00 00 02 07 01
+ 29 01 00 00 00 00 02 08 00
+ 29 01 00 00 00 00 02 09 46
+ 29 01 00 00 00 00 02 0A 46
+ 29 01 00 00 00 00 02 0D 0B
+ 29 01 00 00 00 00 02 0E 1D
+ 29 01 00 00 00 00 02 0F 08
+ 29 01 00 00 00 00 02 10 53
+ 29 01 00 00 00 00 02 11 00
+ 29 01 00 00 00 00 02 12 00
+ 29 01 00 00 00 00 02 14 01
+ 29 01 00 00 00 00 02 15 00
+ 29 01 00 00 00 00 02 16 05
+ 29 01 00 00 00 00 02 17 00
+ 29 01 00 00 00 00 02 19 7F
+ 29 01 00 00 00 00 02 1A FF
+ 29 01 00 00 00 00 02 1B 0F
+ 29 01 00 00 00 00 02 1C 00
+ 29 01 00 00 00 00 02 1D 00
+ 29 01 00 00 00 00 02 1E 00
+ 29 01 00 00 00 00 02 1F 07
+ 29 01 00 00 00 00 02 20 00
+ 29 01 00 00 00 00 02 21 06
+ 29 01 00 00 00 00 02 22 55
+ 29 01 00 00 00 00 02 23 4D
+ 29 01 00 00 00 00 02 2D 02
+ 29 01 00 00 00 00 02 28 01
+ 29 01 00 00 00 00 02 2F 02
+ 29 01 00 00 00 00 02 83 01
+ 29 01 00 00 00 00 02 9E 58
+ 29 01 00 00 00 00 02 9F 6A
+ 29 01 00 00 00 00 02 A0 01
+ 29 01 00 00 00 00 02 A2 10
+ 29 01 00 00 00 00 02 BB 0A
+ 29 01 00 00 00 00 02 BC 0A
+ 29 01 00 00 00 00 02 32 08
+ 29 01 00 00 00 00 02 33 B8
+ 29 01 00 00 00 00 02 36 01
+ 29 01 00 00 00 00 02 37 00
+ 29 01 00 00 00 00 02 43 00
+ 29 01 00 00 00 00 02 4B 21
+ 29 01 00 00 00 00 02 4C 03
+ 29 01 00 00 00 00 02 50 21
+ 29 01 00 00 00 00 02 51 03
+ 29 01 00 00 00 00 02 58 21
+ 29 01 00 00 00 00 02 59 03
+ 29 01 00 00 00 00 02 5D 21
+ 29 01 00 00 00 00 02 5E 03
+ 29 01 00 00 00 00 02 6C 00
+ 29 01 00 00 00 00 02 6D 00
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 01
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 75 00
+ 29 01 00 00 00 00 02 76 7D
+ 29 01 00 00 00 00 02 77 00
+ 29 01 00 00 00 00 02 78 8A
+ 29 01 00 00 00 00 02 79 00
+ 29 01 00 00 00 00 02 7A 9C
+ 29 01 00 00 00 00 02 7B 00
+ 29 01 00 00 00 00 02 7C B1
+ 29 01 00 00 00 00 02 7D 00
+ 29 01 00 00 00 00 02 7E BF
+ 29 01 00 00 00 00 02 7F 00
+ 29 01 00 00 00 00 02 80 CF
+ 29 01 00 00 00 00 02 81 00
+ 29 01 00 00 00 00 02 82 DD
+ 29 01 00 00 00 00 02 83 00
+ 29 01 00 00 00 00 02 84 E8
+ 29 01 00 00 00 00 02 85 00
+ 29 01 00 00 00 00 02 86 F2
+ 29 01 00 00 00 00 02 87 01
+ 29 01 00 00 00 00 02 88 1F
+ 29 01 00 00 00 00 02 89 01
+ 29 01 00 00 00 00 02 8A 41
+ 29 01 00 00 00 00 02 8B 01
+ 29 01 00 00 00 00 02 8C 78
+ 29 01 00 00 00 00 02 8D 01
+ 29 01 00 00 00 00 02 8E A5
+ 29 01 00 00 00 00 02 8F 01
+ 29 01 00 00 00 00 02 90 EE
+ 29 01 00 00 00 00 02 91 02
+ 29 01 00 00 00 00 02 92 29
+ 29 01 00 00 00 00 02 93 02
+ 29 01 00 00 00 00 02 94 2A
+ 29 01 00 00 00 00 02 95 02
+ 29 01 00 00 00 00 02 96 5D
+ 29 01 00 00 00 00 02 97 02
+ 29 01 00 00 00 00 02 98 93
+ 29 01 00 00 00 00 02 99 02
+ 29 01 00 00 00 00 02 9A B8
+ 29 01 00 00 00 00 02 9B 02
+ 29 01 00 00 00 00 02 9C E7
+ 29 01 00 00 00 00 02 9D 03
+ 29 01 00 00 00 00 02 9E 07
+ 29 01 00 00 00 00 02 9F 03
+ 29 01 00 00 00 00 02 A0 37
+ 29 01 00 00 00 00 02 A2 03
+ 29 01 00 00 00 00 02 A3 46
+ 29 01 00 00 00 00 02 A4 03
+ 29 01 00 00 00 00 02 A5 56
+ 29 01 00 00 00 00 02 A6 03
+ 29 01 00 00 00 00 02 A7 66
+ 29 01 00 00 00 00 02 A9 03
+ 29 01 00 00 00 00 02 AA 7A
+ 29 01 00 00 00 00 02 AB 03
+ 29 01 00 00 00 00 02 AC 93
+ 29 01 00 00 00 00 02 AD 03
+ 29 01 00 00 00 00 02 AE A3
+ 29 01 00 00 00 00 02 AF 03
+ 29 01 00 00 00 00 02 B0 B4
+ 29 01 00 00 00 00 02 B1 03
+ 29 01 00 00 00 00 02 B2 CB
+ 29 01 00 00 00 00 02 B3 00
+ 29 01 00 00 00 00 02 B4 7D
+ 29 01 00 00 00 00 02 B5 00
+ 29 01 00 00 00 00 02 B6 8A
+ 29 01 00 00 00 00 02 B7 00
+ 29 01 00 00 00 00 02 B8 9C
+ 29 01 00 00 00 00 02 B9 00
+ 29 01 00 00 00 00 02 BA B1
+ 29 01 00 00 00 00 02 BB 00
+ 29 01 00 00 00 00 02 BC BF
+ 29 01 00 00 00 00 02 BD 00
+ 29 01 00 00 00 00 02 BE CF
+ 29 01 00 00 00 00 02 BF 00
+ 29 01 00 00 00 00 02 C0 DD
+ 29 01 00 00 00 00 02 C1 00
+ 29 01 00 00 00 00 02 C2 E8
+ 29 01 00 00 00 00 02 C3 00
+ 29 01 00 00 00 00 02 C4 F2
+ 29 01 00 00 00 00 02 C5 01
+ 29 01 00 00 00 00 02 C6 1F
+ 29 01 00 00 00 00 02 C7 01
+ 29 01 00 00 00 00 02 C8 41
+ 29 01 00 00 00 00 02 C9 01
+ 29 01 00 00 00 00 02 CA 78
+ 29 01 00 00 00 00 02 CB 01
+ 29 01 00 00 00 00 02 CC A5
+ 29 01 00 00 00 00 02 CD 01
+ 29 01 00 00 00 00 02 CE EE
+ 29 01 00 00 00 00 02 CF 02
+ 29 01 00 00 00 00 02 D0 29
+ 29 01 00 00 00 00 02 D1 02
+ 29 01 00 00 00 00 02 D2 2A
+ 29 01 00 00 00 00 02 D3 02
+ 29 01 00 00 00 00 02 D4 5D
+ 29 01 00 00 00 00 02 D5 02
+ 29 01 00 00 00 00 02 D6 93
+ 29 01 00 00 00 00 02 D7 02
+ 29 01 00 00 00 00 02 D8 B8
+ 29 01 00 00 00 00 02 D9 02
+ 29 01 00 00 00 00 02 DA E7
+ 29 01 00 00 00 00 02 DB 03
+ 29 01 00 00 00 00 02 DC 07
+ 29 01 00 00 00 00 02 DD 03
+ 29 01 00 00 00 00 02 DE 37
+ 29 01 00 00 00 00 02 DF 03
+ 29 01 00 00 00 00 02 E0 46
+ 29 01 00 00 00 00 02 E1 03
+ 29 01 00 00 00 00 02 E2 56
+ 29 01 00 00 00 00 02 E3 03
+ 29 01 00 00 00 00 02 E4 66
+ 29 01 00 00 00 00 02 E5 03
+ 29 01 00 00 00 00 02 E6 7A
+ 29 01 00 00 00 00 02 E7 03
+ 29 01 00 00 00 00 02 E8 93
+ 29 01 00 00 00 00 02 E9 03
+ 29 01 00 00 00 00 02 EA A3
+ 29 01 00 00 00 00 02 EB 03
+ 29 01 00 00 00 00 02 EC B4
+ 29 01 00 00 00 00 02 ED 03
+ 29 01 00 00 00 00 02 EE CB
+ 29 01 00 00 00 00 02 EF 00
+ 29 01 00 00 00 00 02 F0 ED
+ 29 01 00 00 00 00 02 F1 00
+ 29 01 00 00 00 00 02 F2 F3
+ 29 01 00 00 00 00 02 F3 00
+ 29 01 00 00 00 00 02 F4 FE
+ 29 01 00 00 00 00 02 F5 01
+ 29 01 00 00 00 00 02 F6 09
+ 29 01 00 00 00 00 02 F7 01
+ 29 01 00 00 00 00 02 F8 13
+ 29 01 00 00 00 00 02 F9 01
+ 29 01 00 00 00 00 02 FA 1D
+ 29 01 00 00 00 00 02 FF 02
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 00 01
+ 29 01 00 00 00 00 02 01 26
+ 29 01 00 00 00 00 02 02 01
+ 29 01 00 00 00 00 02 03 2F
+ 29 01 00 00 00 00 02 04 01
+ 29 01 00 00 00 00 02 05 37
+ 29 01 00 00 00 00 02 06 01
+ 29 01 00 00 00 00 02 07 56
+ 29 01 00 00 00 00 02 08 01
+ 29 01 00 00 00 00 02 09 70
+ 29 01 00 00 00 00 02 0A 01
+ 29 01 00 00 00 00 02 0B 9D
+ 29 01 00 00 00 00 02 0C 01
+ 29 01 00 00 00 00 02 0D C2
+ 29 01 00 00 00 00 02 0E 01
+ 29 01 00 00 00 00 02 0F FF
+ 29 01 00 00 00 00 02 10 02
+ 29 01 00 00 00 00 02 11 31
+ 29 01 00 00 00 00 02 12 02
+ 29 01 00 00 00 00 02 13 32
+ 29 01 00 00 00 00 02 14 02
+ 29 01 00 00 00 00 02 15 60
+ 29 01 00 00 00 00 02 16 02
+ 29 01 00 00 00 00 02 17 94
+ 29 01 00 00 00 00 02 18 02
+ 29 01 00 00 00 00 02 19 B5
+ 29 01 00 00 00 00 02 1A 02
+ 29 01 00 00 00 00 02 1B E3
+ 29 01 00 00 00 00 02 1C 03
+ 29 01 00 00 00 00 02 1D 03
+ 29 01 00 00 00 00 02 1E 03
+ 29 01 00 00 00 00 02 1F 2D
+ 29 01 00 00 00 00 02 20 03
+ 29 01 00 00 00 00 02 21 3A
+ 29 01 00 00 00 00 02 22 03
+ 29 01 00 00 00 00 02 23 48
+ 29 01 00 00 00 00 02 24 03
+ 29 01 00 00 00 00 02 25 57
+ 29 01 00 00 00 00 02 26 03
+ 29 01 00 00 00 00 02 27 68
+ 29 01 00 00 00 00 02 28 03
+ 29 01 00 00 00 00 02 29 7B
+ 29 01 00 00 00 00 02 2A 03
+ 29 01 00 00 00 00 02 2B 90
+ 29 01 00 00 00 00 02 2D 03
+ 29 01 00 00 00 00 02 2F A0
+ 29 01 00 00 00 00 02 30 03
+ 29 01 00 00 00 00 02 31 CB
+ 29 01 00 00 00 00 02 32 00
+ 29 01 00 00 00 00 02 33 ED
+ 29 01 00 00 00 00 02 34 00
+ 29 01 00 00 00 00 02 35 F3
+ 29 01 00 00 00 00 02 36 00
+ 29 01 00 00 00 00 02 37 FE
+ 29 01 00 00 00 00 02 38 01
+ 29 01 00 00 00 00 02 39 09
+ 29 01 00 00 00 00 02 3A 01
+ 29 01 00 00 00 00 02 3B 13
+ 29 01 00 00 00 00 02 3D 01
+ 29 01 00 00 00 00 02 3F 1D
+ 29 01 00 00 00 00 02 40 01
+ 29 01 00 00 00 00 02 41 26
+ 29 01 00 00 00 00 02 42 01
+ 29 01 00 00 00 00 02 43 2F
+ 29 01 00 00 00 00 02 44 01
+ 29 01 00 00 00 00 02 45 37
+ 29 01 00 00 00 00 02 46 01
+ 29 01 00 00 00 00 02 47 56
+ 29 01 00 00 00 00 02 48 01
+ 29 01 00 00 00 00 02 49 70
+ 29 01 00 00 00 00 02 4A 01
+ 29 01 00 00 00 00 02 4B 9D
+ 29 01 00 00 00 00 02 4C 01
+ 29 01 00 00 00 00 02 4D C2
+ 29 01 00 00 00 00 02 4E 01
+ 29 01 00 00 00 00 02 4F FF
+ 29 01 00 00 00 00 02 50 02
+ 29 01 00 00 00 00 02 51 31
+ 29 01 00 00 00 00 02 52 02
+ 29 01 00 00 00 00 02 53 32
+ 29 01 00 00 00 00 02 54 02
+ 29 01 00 00 00 00 02 55 60
+ 29 01 00 00 00 00 02 56 02
+ 29 01 00 00 00 00 02 58 94
+ 29 01 00 00 00 00 02 59 02
+ 29 01 00 00 00 00 02 5A B5
+ 29 01 00 00 00 00 02 5B 02
+ 29 01 00 00 00 00 02 5C E3
+ 29 01 00 00 00 00 02 5D 03
+ 29 01 00 00 00 00 02 5E 03
+ 29 01 00 00 00 00 02 5F 03
+ 29 01 00 00 00 00 02 60 2D
+ 29 01 00 00 00 00 02 61 03
+ 29 01 00 00 00 00 02 62 3A
+ 29 01 00 00 00 00 02 63 03
+ 29 01 00 00 00 00 02 64 48
+ 29 01 00 00 00 00 02 65 03
+ 29 01 00 00 00 00 02 66 57
+ 29 01 00 00 00 00 02 67 03
+ 29 01 00 00 00 00 02 68 68
+ 29 01 00 00 00 00 02 69 03
+ 29 01 00 00 00 00 02 6A 7B
+ 29 01 00 00 00 00 02 6B 03
+ 29 01 00 00 00 00 02 6C 90
+ 29 01 00 00 00 00 02 6D 03
+ 29 01 00 00 00 00 02 6E A0
+ 29 01 00 00 00 00 02 6F 03
+ 29 01 00 00 00 00 02 70 CB
+ 29 01 00 00 00 00 02 71 00
+ 29 01 00 00 00 00 02 72 19
+ 29 01 00 00 00 00 02 73 00
+ 29 01 00 00 00 00 02 74 36
+ 29 01 00 00 00 00 02 75 00
+ 29 01 00 00 00 00 02 76 55
+ 29 01 00 00 00 00 02 77 00
+ 29 01 00 00 00 00 02 78 70
+ 29 01 00 00 00 00 02 79 00
+ 29 01 00 00 00 00 02 7A 83
+ 29 01 00 00 00 00 02 7B 00
+ 29 01 00 00 00 00 02 7C 99
+ 29 01 00 00 00 00 02 7D 00
+ 29 01 00 00 00 00 02 7E A8
+ 29 01 00 00 00 00 02 7F 00
+ 29 01 00 00 00 00 02 80 B7
+ 29 01 00 00 00 00 02 81 00
+ 29 01 00 00 00 00 02 82 C5
+ 29 01 00 00 00 00 02 83 00
+ 29 01 00 00 00 00 02 84 F7
+ 29 01 00 00 00 00 02 85 01
+ 29 01 00 00 00 00 02 86 1E
+ 29 01 00 00 00 00 02 87 01
+ 29 01 00 00 00 00 02 88 60
+ 29 01 00 00 00 00 02 89 01
+ 29 01 00 00 00 00 02 8A 95
+ 29 01 00 00 00 00 02 8B 01
+ 29 01 00 00 00 00 02 8C E1
+ 29 01 00 00 00 00 02 8D 02
+ 29 01 00 00 00 00 02 8E 20
+ 29 01 00 00 00 00 02 8F 02
+ 29 01 00 00 00 00 02 90 23
+ 29 01 00 00 00 00 02 91 02
+ 29 01 00 00 00 00 02 92 59
+ 29 01 00 00 00 00 02 93 02
+ 29 01 00 00 00 00 02 94 94
+ 29 01 00 00 00 00 02 95 02
+ 29 01 00 00 00 00 02 96 B4
+ 29 01 00 00 00 00 02 97 02
+ 29 01 00 00 00 00 02 98 E1
+ 29 01 00 00 00 00 02 99 03
+ 29 01 00 00 00 00 02 9A 01
+ 29 01 00 00 00 00 02 9B 03
+ 29 01 00 00 00 00 02 9C 28
+ 29 01 00 00 00 00 02 9D 03
+ 29 01 00 00 00 00 02 9E 30
+ 29 01 00 00 00 00 02 9F 03
+ 29 01 00 00 00 00 02 A0 37
+ 29 01 00 00 00 00 02 A2 03
+ 29 01 00 00 00 00 02 A3 3B
+ 29 01 00 00 00 00 02 A4 03
+ 29 01 00 00 00 00 02 A5 40
+ 29 01 00 00 00 00 02 A6 03
+ 29 01 00 00 00 00 02 A7 50
+ 29 01 00 00 00 00 02 A9 03
+ 29 01 00 00 00 00 02 AA 6D
+ 29 01 00 00 00 00 02 AB 03
+ 29 01 00 00 00 00 02 AC 80
+ 29 01 00 00 00 00 02 AD 03
+ 29 01 00 00 00 00 02 AE CB
+ 29 01 00 00 00 00 02 AF 00
+ 29 01 00 00 00 00 02 B0 19
+ 29 01 00 00 00 00 02 B1 00
+ 29 01 00 00 00 00 02 B2 36
+ 29 01 00 00 00 00 02 B3 00
+ 29 01 00 00 00 00 02 B4 55
+ 29 01 00 00 00 00 02 B5 00
+ 29 01 00 00 00 00 02 B6 70
+ 29 01 00 00 00 00 02 B7 00
+ 29 01 00 00 00 00 02 B8 83
+ 29 01 00 00 00 00 02 B9 00
+ 29 01 00 00 00 00 02 BA 99
+ 29 01 00 00 00 00 02 BB 00
+ 29 01 00 00 00 00 02 BC A8
+ 29 01 00 00 00 00 02 BD 00
+ 29 01 00 00 00 00 02 BE B7
+ 29 01 00 00 00 00 02 BF 00
+ 29 01 00 00 00 00 02 C0 C5
+ 29 01 00 00 00 00 02 C1 00
+ 29 01 00 00 00 00 02 C2 F7
+ 29 01 00 00 00 00 02 C3 01
+ 29 01 00 00 00 00 02 C4 1E
+ 29 01 00 00 00 00 02 C5 01
+ 29 01 00 00 00 00 02 C6 60
+ 29 01 00 00 00 00 02 C7 01
+ 29 01 00 00 00 00 02 C8 95
+ 29 01 00 00 00 00 02 C9 01
+ 29 01 00 00 00 00 02 CA E1
+ 29 01 00 00 00 00 02 CB 02
+ 29 01 00 00 00 00 02 CC 20
+ 29 01 00 00 00 00 02 CD 02
+ 29 01 00 00 00 00 02 CE 23
+ 29 01 00 00 00 00 02 CF 02
+ 29 01 00 00 00 00 02 D0 59
+ 29 01 00 00 00 00 02 D1 02
+ 29 01 00 00 00 00 02 D2 94
+ 29 01 00 00 00 00 02 D3 02
+ 29 01 00 00 00 00 02 D4 B4
+ 29 01 00 00 00 00 02 D5 02
+ 29 01 00 00 00 00 02 D6 E1
+ 29 01 00 00 00 00 02 D7 03
+ 29 01 00 00 00 00 02 D8 01
+ 29 01 00 00 00 00 02 D9 03
+ 29 01 00 00 00 00 02 DA 28
+ 29 01 00 00 00 00 02 DB 03
+ 29 01 00 00 00 00 02 DC 30
+ 29 01 00 00 00 00 02 DD 03
+ 29 01 00 00 00 00 02 DE 37
+ 29 01 00 00 00 00 02 DF 03
+ 29 01 00 00 00 00 02 E0 3B
+ 29 01 00 00 00 00 02 E1 03
+ 29 01 00 00 00 00 02 E2 40
+ 29 01 00 00 00 00 02 E3 03
+ 29 01 00 00 00 00 02 E4 50
+ 29 01 00 00 00 00 02 E5 03
+ 29 01 00 00 00 00 02 E6 6D
+ 29 01 00 00 00 00 02 E7 03
+ 29 01 00 00 00 00 02 E8 80
+ 29 01 00 00 00 00 02 E9 03
+ 29 01 00 00 00 00 02 EA CB
+ 29 01 00 00 00 00 02 FF 01
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 02
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 04
+ 29 01 00 00 00 00 02 FB 01
+ 29 01 00 00 00 00 02 FF 00
+ 29 01 00 00 64 00 02 11 00
+ 29 01 00 00 00 00 02 FF EE
+ 29 01 00 00 00 00 02 12 50
+ 29 01 00 00 00 00 02 13 02
+ 29 01 00 00 00 00 02 6A 60
+ 29 01 00 00 00 00 02 FF 00
+ 29 01 00 00 78 00 02 29 00];
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
- 05 01 00 00 78 02 10 00];
+ qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
qcom,off-cmds-dsi-state = "DSI_HS_MODE";
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
index a27a88a..478541f 100644
--- a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
@@ -50,11 +50,11 @@
00 c2 45 00 00 00 00 01 75 /* lane3 config */
00 02 45 00 00 00 00 01 97]; /* Clk ln config */
- qcom,panel-on-cmds = [05 01 00 00 78 02 11 00
- 05 01 00 00 78 02 29 00];
+ qcom,panel-on-cmds = [05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00];
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
- 05 01 00 00 78 02 10 00];
+ qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
qcom,off-cmds-dsi-state = "DSI_LP_MODE";
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
index d182bac..45d396c 100644
--- a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -52,16 +52,16 @@
00 00 00 00 0a 00 00 01 97 /* lane2 config */
00 00 00 00 0f 00 00 01 97 /* lane3 config */
00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
- qcom,panel-on-cmds = [05 01 00 00 32 02 01 00 /* sw reset */
- 05 01 00 00 0a 02 11 00 /* exit sleep */
- 15 01 00 00 0a 02 53 2c /* backlight on */
- 15 01 00 00 0a 02 51 ff /* brightness max */
- 05 01 00 00 0a 02 29 00 /* display on */
- 15 01 00 00 0a 02 ae 03 /* set num of lanes */
- 15 01 00 00 0a 02 3a 77 /* rgb_888 */];
+ qcom,panel-on-cmds = [05 01 00 00 32 00 02 01 00 /* sw reset */
+ 05 01 00 00 0a 00 02 11 00 /* exit sleep */
+ 15 01 00 00 0a 00 02 53 2c /* backlight on */
+ 15 01 00 00 0a 00 02 51 ff /* brightness max */
+ 05 01 00 00 0a 00 02 29 00 /* display on */
+ 15 01 00 00 0a 00 02 ae 03 /* set num of lanes */
+ 15 01 00 00 0a 00 02 3a 77 /* rgb_888 */];
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 0a 02 28 00 /* display off */
- 05 01 00 00 78 02 10 00 /* enter sleep */];
+ qcom,panel-off-cmds = [05 01 00 00 0a 00 02 28 00 /* display off */
+ 05 01 00 00 78 00 02 10 00 /* enter sleep */];
qcom,off-cmds-dsi-state = "DSI_HS_MODE";
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
index 3b39dea..271e373 100644
--- a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
@@ -38,9 +38,9 @@
qcom,mdss-pan-dsi-mdp-tr = <0x04>;
qcom,mdss-pan-dsi-dma-tr = <0x04>;
qcom,mdss-pan-dsi-frame-rate = <60>;
- qcom,panel-on-cmds = [32 01 00 00 00 02 00 00];
+ qcom,panel-on-cmds = [32 01 00 00 00 00 02 00 00];
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [22 01 00 00 00 02 00 00];
+ qcom,panel-off-cmds = [22 01 00 00 00 00 02 00 00];
qcom,off-cmds-dsi-state = "DSI_LP_MODE";
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 82b57cd..5c37cf8 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -54,71 +54,71 @@
00 00 00 00 0f 00 00 01 97 /* lane3 config */
00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
- qcom,panel-on-cmds = [23 01 00 00 0a 02 b0 00
- 23 01 00 00 0a 02 b2 00
- 23 01 00 00 0a 02 b3 0c
- 23 01 00 00 0a 02 b4 02
- 29 01 00 00 00 06
+ qcom,panel-on-cmds = [23 01 00 00 0a 00 02 b0 00
+ 23 01 00 00 0a 00 02 b2 00
+ 23 01 00 00 0a 00 02 b3 0c
+ 23 01 00 00 0a 00 02 b4 02
+ 29 01 00 00 00 00 06
c0 40 02 7f c8 08
- 29 01 00 00 00 10
+ 29 01 00 00 00 00 10
c1 00 a8 00 00 00
00 00 9d 08 27 00
00 00 00 00
- 29 01 00 00 00 06
+ 29 01 00 00 00 00 06
c2 00 00 09 00 00
- 23 01 00 00 0a 02 c3 04
- 29 01 00 00 00 04
+ 23 01 00 00 0a 00 02 c3 04
+ 29 01 00 00 00 00 04
c4 4d 83 00
- 29 01 00 00 00 0b
+ 29 01 00 00 00 00 0b
c6 12 00 08 71 00
00 00 80 00 04
- 23 01 00 00 0a 02 c7 22
- 29 01 00 00 00 05
+ 23 01 00 00 0a 00 02 c7 22
+ 29 01 00 00 00 00 05
c8 4c 0c 0c 0c
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
c9 00 40 00 16 32
2e 3a 43 3e 3c 45
79 3f
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
ca 00 46 1a 23 21
1c 25 31 2d 49 5f
7f 3f
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
cb 00 4c 20 3a 42
40 47 4b 42 3e 46
7e 3f
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
cc 00 41 19 21 1d
14 18 1f 1d 25 3f
73 3f
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
cd 23 79 5a 5f 57
4c 51 51 45 3f 4b
7f 3f
- 29 01 00 00 00 0e
+ 29 01 00 00 00 00 0e
ce 00 40 14 20 1a
0e 0e 13 08 00 05
46 1c
- 29 01 00 00 00 04
+ 29 01 00 00 00 00 04
d0 6a 64 01
- 29 01 00 00 00 03 d1 77 d4
- 23 01 00 00 0a 02 d3 33
- 29 01 00 00 00 03 d5 0f 0f
- 29 01 00 00 00 07
+ 29 01 00 00 00 00 03 d1 77 d4
+ 23 01 00 00 0a 00 02 d3 33
+ 29 01 00 00 00 00 03 d5 0f 0f
+ 29 01 00 00 00 00 07
d8 34 64 23 25 62
32
- 29 01 00 00 00 0c
+ 29 01 00 00 00 00 0c
de 10 7b 11 0a 00
00 00 00 00 00 00
- 29 01 00 00 00 09
+ 29 01 00 00 00 00 09
fd 04 55 53 00 70
ff 10 73
- 23 01 00 00 0a 02 e2 00
- 05 01 00 00 78 02 11 00
- 05 01 00 00 32 02 29 00];
+ 23 01 00 00 0a 00 02 e2 00
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 32 00 02 29 00];
qcom,on-cmds-dsi-state = "DSI_LP_MODE";
- qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
- 05 01 00 00 78 02 10 00];
+ qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
qcom,off-cmds-dsi-state = "DSI_HS_MODE";
};
};
diff --git a/arch/arm/boot/dts/mpq8092-ion.dtsi b/arch/arm/boot/dts/mpq8092-ion.dtsi
index ee3fbc4..f9f5985 100644
--- a/arch/arm/boot/dts/mpq8092-ion.dtsi
+++ b/arch/arm/boot/dts/mpq8092-ion.dtsi
@@ -20,58 +20,14 @@
reg = <30>;
};
- qcom,ion-heap@8 { /* CP_MM HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <8>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x7800000>;
- };
-
- qcom,ion-heap@29 { /* FIRMWARE HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <29>;
- qcom,heap-align = <0x20000>;
- qcom,heap-adjacent = <8>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0xA00000>;
- };
-
- qcom,ion-heap@12 { /* MFC HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <12>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x2000>;
- };
-
- qcom,ion-heap@24 { /* SF HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <24>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x2800000>;
+ qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
+ reg = <21>;
};
qcom,ion-heap@25 { /* IOMMU HEAP */
reg = <25>;
};
- qcom,ion-heap@27 { /* QSECOM HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <27>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x600000>;
- };
-
- qcom,ion-heap@28 { /* AUDIO HEAP */
- compatible = "qcom,msm-ion-reserve";
- reg = <28>;
- qcom,heap-align = <0x1000>;
- qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x2B4000>;
- };
};
};
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index ce97d4d..676ef3b 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -16,7 +16,7 @@
/ {
model = "Qualcomm MPQ8092 Simulator";
- compatible = "qcom,mpq8092-sim", "qcom,mpq8092";
+ compatible = "qcom,mpq8092-sim", "qcom,mpq8092", "qcom,sim";
qcom,msm-id = <126 16 0>;
};
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
index d4c5061..78234e8 100644
--- a/arch/arm/boot/dts/msm-gdsc.dtsi
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -11,8 +11,6 @@
* GNU General Public License for more details.
*/
-/include/ "skeleton.dtsi"
-
&soc {
gdsc_venus: qcom,gdsc@fd8c1024 {
compatible = "qcom,gdsc";
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index b0257d0..65075e5 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -27,9 +27,17 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "lpass_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <11 512 0 0>,
+ <11 512 0 1000>;
status = "disabled";
lpass_q6_fw: qcom,iommu-ctx@fd000000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd000000 0x1000>;
interrupts = <0 250 0>;
qcom,iommu-ctx-mids = <0 15>;
@@ -37,6 +45,7 @@
};
lpass_audio_shared: qcom,iommu-ctx@fd001000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd001000 0x1000>;
interrupts = <0 250 0>;
qcom,iommu-ctx-mids = <1>;
@@ -44,6 +53,7 @@
};
lpass_video_shared: qcom,iommu-ctx@fd002000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd002000 0x1000>;
interrupts = <0 250 0>;
qcom,iommu-ctx-mids = <2>;
@@ -51,6 +61,7 @@
};
lpass_q6_spare: qcom,iommu-ctx@fd003000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd003000 0x1000>;
interrupts = <0 250 0>;
qcom,iommu-ctx-mids = <3 4 5 6 7 8 9 10 11 12 13 14>;
@@ -74,9 +85,18 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "copss_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <88 512 0 0>,
+ <88 512 0 1000>;
+
status = "disabled";
qcom,iommu-ctx@fd010000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd010000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <0>;
@@ -84,6 +104,7 @@
};
qcom,iommu-ctx@fd011000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd011000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <1>;
@@ -91,6 +112,7 @@
};
qcom,iommu-ctx@fd012000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd012000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <2>;
@@ -98,6 +120,7 @@
};
qcom,iommu-ctx@fd013000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd013000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <3>;
@@ -105,6 +128,7 @@
};
qcom,iommu-ctx@fd014000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd014000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <4>;
@@ -112,6 +136,7 @@
};
qcom,iommu-ctx@fd015000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd015000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <5>;
@@ -119,6 +144,7 @@
};
qcom,iommu-ctx@fd016000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd016000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <6>;
@@ -126,6 +152,7 @@
};
qcom,iommu-ctx@fd017000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd017000 0x1000>;
interrupts = <0 254 0>;
qcom,iommu-ctx-mids = <7>;
@@ -149,9 +176,17 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "mdpe_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <92 512 0 0>,
+ <92 512 0 1000>;
status = "disabled";
qcom,iommu-ctx@fd860000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd860000 0x1000>;
interrupts = <0 247 0>;
qcom,iommu-ctx-mids = <0 1 3>;
@@ -159,6 +194,7 @@
};
qcom,iommu-ctx@fd861000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd861000 0x1000>;
interrupts = <0 247 0>;
qcom,iommu-ctx-mids = <2>;
@@ -182,9 +218,17 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "mdps_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <22 512 0 0>,
+ <22 512 0 1000>;
status = "disabled";
qcom,iommu-ctx@fd870000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd870000 0x1000>;
interrupts = <0 47 0>;
qcom,iommu-ctx-mids = <0>;
@@ -192,6 +236,7 @@
};
qcom,iommu-ctx@fd871000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd871000 0x1000>;
interrupts = <0 47 0>;
qcom,iommu-ctx-mids = <1>;
@@ -216,9 +261,17 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "gfx_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 512 0 0>,
+ <26 512 0 1000>;
status = "disabled";
qcom,iommu-ctx@fd880000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd880000 0x1000>;
interrupts = <0 241 0>;
qcom,iommu-ctx-mids = <0 1 2 3 4 5 6 7 8 9 10 11 12 13
@@ -227,6 +280,7 @@
};
qcom,iommu-ctx@fd881000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd881000 0x1000>;
interrupts = <0 241 0>;
qcom,iommu-ctx-mids = <16 17 18 19 20 21 22 23 24 25
@@ -235,6 +289,7 @@
};
qcom,iommu-ctx@fd882000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd882000 0x1000>;
interrupts = <0 241 0>;
qcom,iommu-ctx-mids = <>;
@@ -258,9 +313,17 @@
0x10
0x12
0x80>;
+ qcom,msm-bus,name = "vfe_ebi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <29 512 0 0>,
+ <29 512 0 1000>;
status = "disabled";
qcom,iommu-ctx@fd890000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd890000 0x1000>;
interrupts = <0 65 0>;
qcom,iommu-ctx-mids = <0>;
@@ -268,6 +331,7 @@
};
qcom,iommu-ctx@fd891000 {
+ compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd891000 0x1000>;
interrupts = <0 65 0>;
qcom,iommu-ctx-mids = <1>;
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index f495850..ab46861 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -77,6 +77,7 @@
0x0>;
qcom,iommu-ctx@fda6c000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda6c000 0x1000>;
interrupts = <0 70 0>;
qcom,iommu-ctx-sids = <0>;
@@ -84,6 +85,7 @@
};
qcom,iommu-ctx@fda6d000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda6d000 0x1000>;
interrupts = <0 70 0>;
qcom,iommu-ctx-sids = <1>;
@@ -91,6 +93,7 @@
};
qcom,iommu-ctx@fda6e000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda6e000 0x1000>;
interrupts = <0 70 0>;
qcom,iommu-ctx-sids = <2>;
@@ -170,6 +173,7 @@
0x0>;
qcom,iommu-ctx@fd930000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd930000 0x1000>;
interrupts = <0 47 0>;
qcom,iommu-ctx-sids = <0>;
@@ -177,6 +181,7 @@
};
qcom,iommu-ctx@fd931000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd931000 0x1000>;
interrupts = <0 47 0>;
qcom,iommu-ctx-sids = <1>;
@@ -185,6 +190,7 @@
};
qcom,iommu-ctx@fd932000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd932000 0x1000>;
interrupts = <0 47 0>;
qcom,iommu-ctx-sids = <>;
@@ -279,6 +285,7 @@
0x0>;
venus_ns: qcom,iommu-ctx@fdc8c000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8c000 0x1000>;
interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0 1 2 3 4 5>;
@@ -286,6 +293,7 @@
};
venus_cp: qcom,iommu-ctx@fdc8d000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8d000 0x1000>;
interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84 0x85>;
@@ -294,6 +302,7 @@
};
venus_fw: qcom,iommu-ctx@fdc8e000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8e000 0x1000>;
interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0xc0 0xc6>;
@@ -363,6 +372,7 @@
0x0>;
qcom,iommu-ctx@fdb18000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdb18000 0x1000>;
interrupts = <0 241 0>;
qcom,iommu-ctx-sids = <0>;
@@ -370,6 +380,7 @@
};
qcom,iommu-ctx@fdb19000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdb19000 0x1000>;
interrupts = <0 241 0>;
qcom,iommu-ctx-sids = <1>;
@@ -449,6 +460,7 @@
0x0>;
qcom,iommu-ctx@fda4c000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda4c000 0x1000>;
interrupts = <0 65 0>;
qcom,iommu-ctx-sids = <0>;
@@ -456,6 +468,7 @@
};
qcom,iommu-ctx@fda4d000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda4d000 0x1000>;
interrupts = <0 65 0>;
qcom,iommu-ctx-sids = <1>;
@@ -463,6 +476,7 @@
};
qcom,iommu-ctx@fda4e000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfda4e000 0x1000>;
interrupts = <0 65 0>;
qcom,iommu-ctx-sids = <2>;
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index bce9806..e1f0e61 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -265,6 +265,58 @@
};
};
+ pm8110_bms: qcom,bms {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-bms";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ qcom,r-sense-uohm = <10000>;
+ qcom,v-cutoff-uv = <3400000>;
+ qcom,max-voltage-uv = <4200000>;
+ qcom,r-conn-mohm = <0>;
+ qcom,shutdown-soc-valid-limit = <20>;
+ qcom,adjust-soc-low-threshold = <15>;
+ qcom,ocv-voltage-high-threshold-uv = <3750000>;
+ qcom,ocv-voltage-low-threshold-uv = <3650000>;
+ qcom,low-soc-calculate-soc-threshold = <15>;
+ qcom,low-soc-calculate-soc-ms = <5000>;
+ qcom,calculate-soc-ms = <20000>;
+ qcom,chg-term-ua = <100000>;
+ qcom,batt-type = <0>;
+ qcom,low-voltage-threshold = <3420000>;
+ qcom,tm-temp-margin = <5000>;
+ qcom,low-ocv-correction-limit-uv = <100>;
+ qcom,high-ocv-correction-limit-uv = <50>;
+ qcom,hold-soc-est = <3>;
+
+ qcom,bms-iadc@3800 {
+ reg = <0x3800 0x100>;
+ };
+
+ qcom,bms-bms@4000 {
+ reg = <0x4000 0x100>;
+ interrupts = <0x0 0x40 0x0>,
+ <0x0 0x40 0x1>,
+ <0x0 0x40 0x2>,
+ <0x0 0x40 0x3>,
+ <0x0 0x40 0x4>,
+ <0x0 0x40 0x5>,
+ <0x0 0x40 0x6>,
+ <0x0 0x40 0x7>;
+
+ interrupt-names = "vsense_for_r",
+ "vsense_avg",
+ "sw_cc_thr",
+ "ocv_thr",
+ "charge_begin",
+ "good_ocv",
+ "ocv_for_r",
+ "cc_thr";
+ };
+ };
+
qcom,pm8110_rtc {
spmi-dev-container;
compatible = "qcom,qpnp-rtc";
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 41920d5..d6d919b 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -61,7 +61,7 @@
qcom,vinmin-mv = <4200>;
qcom,vbatdet-delta-mv = <150>;
qcom,ibatmax-ma = <1500>;
- qcom,ibatterm-ma = <200>;
+ qcom,ibatterm-ma = <100>;
qcom,ibatsafe-ma = <1500>;
qcom,thermal-mitigation = <1500 700 600 325>;
qcom,tchg-mins = <150>;
@@ -173,6 +173,7 @@
qcom,calculate-soc-ms = <20000>;
qcom,chg-term-ua = <100000>;
qcom,batt-type = <0>;
+ qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
@@ -204,6 +205,12 @@
};
};
+ qcom,leds@a100 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa100 0x100>;
+ label = "mpp";
+ };
+
pm8226_gpios: gpios {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
@@ -381,6 +388,21 @@
};
};
+ pm8226_adc_tm: vadc@3400 {
+ compatible = "qcom,qpnp-adc-tm";
+ reg = <0x3400 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x34 0x0>,
+ <0x0 0x34 0x3>,
+ <0x0 0x34 0x4>;
+ interrupt-names = "eoc-int-en-set",
+ "high-thr-en-set",
+ "low-thr-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+ };
+
qcom,pm8226_rtc {
spmi-dev-container;
compatible = "qcom,qpnp-rtc";
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index eadd5d3..34ea33d 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -116,6 +116,7 @@
qcom,chg-term-ua = <100000>;
qcom,batt-type = <0>;
qcom,low-voltage-threshold = <3420000>;
+ qcom,tm-temp-margin = <5000>;
qcom,low-ocv-correction-limit-uv = <100>;
qcom,high-ocv-correction-limit-uv = <50>;
qcom,hold-soc-est = <3>;
@@ -173,8 +174,9 @@
qcom,vddmax-mv = <4200>;
qcom,vddsafe-mv = <4200>;
- qcom,vinmin-mv = <4200>;
+ qcom,vinmin-mv = <4300>;
qcom,ibatmax-ma = <1500>;
+ qcom,ibatterm-ma = <100>;
qcom,ibatsafe-ma = <1500>;
qcom,thermal-mitigation = <1500 700 600 325>;
qcom,cool-bat-decidegc = <100>;
@@ -183,7 +185,7 @@
qcom,warm-bat-decidegc = <450>;
qcom,warm-bat-mv = <4100>;
qcom,ibatmax-cool-ma = <350>;
- qcom,vbatdet-delta-mv = <350>;
+ qcom,vbatdet-delta-mv = <100>;
qcom,tchg-mins = <150>;
qcom,chgr@1000 {
@@ -584,10 +586,10 @@
};
chan@3 {
- label = "spare1";
+ label = "spare1_div3";
reg = <3>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <6>;
+ qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
@@ -595,10 +597,10 @@
};
chan@4 {
- label = "spare2";
+ label = "usb_id_mv";
reg = <4>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <6>;
+ qcom,pre-div-channel-scaling = <1>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
@@ -872,7 +874,7 @@
reg = <0xb5>;
qcom,decimation = <0>;
qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "absolute";
+ qcom,calibration-type = "ratiometric";
qcom,scale-function = <2>;
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <3>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index 07f16b9..41d6b7e 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -73,7 +73,7 @@
reg = <0x6d>;
qcom,slave-id = <0x20 0x0 0x9724>;
qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <0>;
+ qcom,csid-sd-index = <1>;
qcom,mount-angle = <0>;
qcom,sensor-name = "ov9724";
cam_vdig-supply = <&pm8226_l5>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index f06033e..53860ac 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -73,8 +73,8 @@
reg = <0x6d>;
qcom,slave-id = <0x20 0x0 0x9724>;
qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <0>;
- qcom,mount-angle = <90>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <270>;
qcom,sensor-name = "ov9724";
cam_vdig-supply = <&pm8226_l5>;
cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 47f4049..3935dbb 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -73,8 +73,8 @@
reg = <0x6d>;
qcom,slave-id = <0x20 0x0 0x9724>;
qcom,csiphy-sd-index = <1>;
- qcom,csid-sd-index = <0>;
- qcom,mount-angle = <90>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <270>;
qcom,sensor-name = "ov9724";
cam_vdig-supply = <&pm8226_l5>;
cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera.dtsi b/arch/arm/boot/dts/msm8226-camera.dtsi
index 0dae162..ec0092d 100644
--- a/arch/arm/boot/dts/msm8226-camera.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera.dtsi
@@ -21,8 +21,9 @@
qcom,csiphy@fda0ac00 {
cell-index = <0>;
compatible = "qcom,csiphy";
- reg = <0xfda0ac00 0x200>;
- reg-names = "csiphy";
+ reg = <0xfda0ac00 0x200>,
+ <0xfda00030 0x4>;
+ reg-names = "csiphy", "csiphy_clk_mux";
interrupts = <0 78 0>;
interrupt-names = "csiphy";
};
@@ -30,8 +31,9 @@
qcom,csiphy@fda0b000 {
cell-index = <1>;
compatible = "qcom,csiphy";
- reg = <0xfda0b000 0x200>;
- reg-names = "csiphy";
+ reg = <0xfda0b000 0x200>,
+ <0xfda00038 0x4>;
+ reg-names = "csiphy", "csiphy_clk_mux";
interrupts = <0 79 0>;
interrupt-names = "csiphy";
};
@@ -61,8 +63,9 @@
qcom,ispif@fda0a000 {
cell-index = <0>;
compatible = "qcom,ispif";
- reg = <0xfda0a000 0x500>;
- reg-names = "ispif";
+ reg = <0xfda0a000 0x500>,
+ <0xfda00020 0x10>;
+ reg-names = "ispif", "csi_clk_mux";
interrupts = <0 55 0>;
interrupt-names = "ispif";
};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index f887740..b96a9e1 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -18,7 +18,10 @@
/ {
model = "Qualcomm MSM 8226 CDP";
compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
- qcom,msm-id = <145 1 0>;
+ qcom,msm-id = <145 1 0>,
+ <158 1 0>,
+ <159 1 0>,
+ <198 1 0>;
};
&soc {
@@ -116,6 +119,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,headset-jack-type-NO;
};
};
@@ -239,6 +243,24 @@
};
&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = <2>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+ };
+
qcom,pm8226@1 {
qcom,leds@d800 {
status = "okay";
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index e4a42fa..e11c963 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -34,6 +34,11 @@
coresight-id = <1>;
coresight-name = "coresight-tpiu";
coresight-nr-inports = <1>;
+
+ vdd-supply = <&pm8226_l18>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
};
replicator: replicator@fc31c000 {
@@ -355,4 +360,18 @@
coresight-name = "coresight-cti-cpu3";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@fd828018 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xfd828018 0x80>,
+ <0xf9011080 0x80>,
+ <0xfd4ab160 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+ coresight-id = <29>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ qcom,hwevent-clks = "core_mmss_clk";
+ };
};
diff --git a/arch/arm/boot/dts/msm8226-fluid.dts b/arch/arm/boot/dts/msm8226-fluid.dts
index 7b11200..c58b43b 100644
--- a/arch/arm/boot/dts/msm8226-fluid.dts
+++ b/arch/arm/boot/dts/msm8226-fluid.dts
@@ -16,7 +16,10 @@
/ {
model = "Qualcomm MSM 8226 FLUID";
compatible = "qcom,msm8226-fluid", "qcom,msm8226", "qcom,fluid";
- qcom,msm-id = <145 3 0>;
+ qcom,msm-id = <145 3 0>,
+ <158 3 0>,
+ <159 3 0>,
+ <198 3 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 3dd517b..65b71e9 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -18,7 +18,10 @@
/ {
model = "Qualcomm MSM 8226 MTP";
compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
- qcom,msm-id = <145 8 0>;
+ qcom,msm-id = <145 8 0>,
+ <158 8 0>,
+ <159 8 0>,
+ <198 8 0>;
};
&soc {
@@ -228,6 +231,24 @@
};
&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = <2>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+ };
+
qcom,pm8226@1 {
qcom,leds@d300 {
status = "okay";
@@ -365,3 +386,10 @@
&pm8226_chg {
qcom,charging-disabled;
};
+
+&slim_msm {
+ tapan_codec {
+ qcom,cdc-micbias1-ext-cap;
+ qcom,cdc-micbias2-ext-cap;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index 721bcbb..aba5c4a 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -18,7 +18,10 @@
/ {
model = "Qualcomm MSM 8226 QRD";
compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
- qcom,msm-id = <145 11 0>;
+ qcom,msm-id = <145 11 0>,
+ <158 11 0>,
+ <159 11 0>,
+ <198 11 0>;
};
&soc {
@@ -231,6 +234,24 @@
};
&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = <2>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+ };
+
qcom,pm8226@1 {
qcom,leds@d300 {
status = "okay";
@@ -265,6 +286,18 @@
};
};
+&pm8226_bms {
+ status = "okay";
+ qcom,batt-type = <4>;
+ qcom,max-voltage-uv = <4350000>;
+};
+
+&pm8226_chg {
+ status = "okay";
+ qcom,chg-vddmax-mv = <4350>;
+ qcom,chg-vddsafe-mv = <4350>;
+};
+
&pm8226_gpios {
gpio@c000 { /* GPIO 1 */
/* XO_PMIC_CDC_MCLK enable for tapan codec */
@@ -331,3 +364,10 @@
mpp@a700 { /* MPP 8 */
};
};
+
+&slim_msm {
+ tapan_codec {
+ qcom,cdc-micbias1-ext-cap;
+ };
+
+};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 7fa9081..6aeaf49 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -30,23 +30,37 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>,
- <0xfc4b80b0 8>;
- reg-names = "rbcpr", "efuse_phys";
+ reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
+ reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <4>;
+ regulator-max-microvolt = <3>;
qcom,num-efuse-bits = <5>;
- qcom,efuse-bit-pos = <6 7 8 9 10>;
- qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
- qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1155000 1160000 1275000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
vdd-apc-supply = <&pm8226_s2>;
+
vdd-mx-supply = <&pm8226_l3_ao>;
qcom,vdd-mx-vmax = <1350000>;
qcom,vdd-mx-vmin-method = <1>;
+
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay = <5000>;
+ qcom,cpr-timer-cons-up = <1>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-irq-line = <0>;
+ qcom,cpr-step-quotient = <15>;
+ qcom,cpr-up-threshold = <1>;
+ qcom,cpr-down-threshold = <2>;
+ qcom,cpr-idle-clocks = <5>;
+ qcom,cpr-gcnt-time = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-apc-volt-step = <5000>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 3cca8b0..2405646 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -17,7 +17,10 @@
/ {
model = "Qualcomm MSM 8226 Simulator";
compatible = "qcom,msm8226-sim", "qcom,msm8226", "qcom,sim";
- qcom,msm-id = <145 16 0>;
+ qcom,msm-id = <145 16 0>,
+ <158 16 0>,
+ <159 16 0>,
+ <198 16 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 3cd9cb5..17cda51 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -282,7 +282,7 @@
interrupt-names = "cdc-int";
};
- slim@fe12f000 {
+ slim_msm: slim@fe12f000 {
cell-index = <1>;
compatible = "qcom,slim-ngd";
reg = <0xfe12f000 0x35000>,
@@ -350,6 +350,11 @@
compatible = "qcom,msm8226-audio-tapan";
qcom,model = "msm8226-tapan-snd-card";
qcom,tapan-mclk-clk-freq = <9600000>;
+ qcom,prim-auxpcm-gpio-clk = <&msmgpio 63 0>;
+ qcom,prim-auxpcm-gpio-sync = <&msmgpio 64 0>;
+ qcom,prim-auxpcm-gpio-din = <&msmgpio 65 0>;
+ qcom,prim-auxpcm-gpio-dout = <&msmgpio 66 0>;
+ qcom,prim-auxpcm-gpio-set = "prim-gpio-prim";
};
qcom,msm-pcm {
@@ -502,6 +507,28 @@
compatible = "qcom,msm-pcm-hostless";
};
+ qcom,msm-auxpcm {
+ compatible = "qcom,msm-auxpcm-resource";
+ qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+
+ qcom,msm-prim-auxpcm-rx {
+ qcom,msm-auxpcm-dev-id = <4106>;
+ compatible = "qcom,msm-auxpcm-dev";
+ };
+
+ qcom,msm-prim-auxpcm-tx {
+ qcom,msm-auxpcm-dev-id = <4107>;
+ compatible = "qcom,msm-auxpcm-dev";
+ };
+ };
+
qcom,wcnss-wlan@fb000000 {
compatible = "qcom,wcnss_wlan";
reg = <0xfb000000 0x280000>,
@@ -784,6 +811,7 @@
/* GPIO inputs from lpass */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
/* GPIO output to lpass */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
@@ -841,6 +869,7 @@
qcom,limit-temp = <60>;
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
+ qcom,freq-control-mask = <0xf>;
};
spi_0: spi@f9923000 { /* BLSP1 QUP1 */
@@ -1112,6 +1141,71 @@
};
};
+&pm8226_adc_tm {
+ /* Channel Node */
+ chan@30 {
+ label = "batt_therm";
+ reg = <0x30>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <1>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x48>;
+ };
+
+ chan@8 {
+ label = "die_temp";
+ reg = <8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x68>;
+ };
+
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <3>;
+ qcom,btm-channel-number = <0x70>;
+ };
+
+ chan@14 {
+ label = "pa_therm0";
+ reg = <0x14>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
+ };
+
+ chan@17 {
+ label = "pa_therm1";
+ reg = <0x17>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x80>;
+ qcom,thermal-node;
+ };
+};
+
&pm8226_chg {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index 2e7ba25..7ed914e 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -29,11 +29,13 @@
qcom,masterp = <2>;
qcom,tier = <2>;
qcom,hw-sel = "NoC";
- qcom,perm-mode = "Bypass";
- qcom,mode = "Bypass";
+ qcom,perm-mode = "Fixed";
+ qcom,mode = "Fixed";
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <8>;
+ qcom,prio1 = <2>;
+ qcom,prio0 = <2>;
};
mas-vfe {
@@ -47,6 +49,8 @@
qcom,ws = <10000>;
qcom,qport = <2>;
qcom,mas-hw-id = <11>;
+ qcom,prio1 = <2>;
+ qcom,prio0 = <2>;
};
mas-mdpe {
@@ -55,11 +59,13 @@
qcom,masterp = <4>;
qcom,tier = <2>;
qcom,hw-sel = "NoC";
- qcom,perm-mode = "Bypass";
- qcom,mode = "Bypass";
+ qcom,perm-mode = "Fixed";
+ qcom,mode = "Fixed";
qcom,ws = <10000>;
qcom,qport = <7>;
qcom,mas-hw-id = <11>;
+ qcom,prio1 = <2>;
+ qcom,prio0 = <2>;
};
fab-bimc {
@@ -67,7 +73,7 @@
label = "fab-bimc";
qcom,gateway;
qcom,slavep = <16>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <16>;
};
@@ -77,7 +83,7 @@
label = "slv-camera-cfg";
qcom,slavep = <0>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <3>;
};
@@ -87,7 +93,7 @@
label = "slv-display-cfg";
qcom,slavep = <1>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <4>;
};
@@ -97,7 +103,7 @@
label = "slv-cpr-cfg";
qcom,slavep = <3>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <6>;
};
@@ -107,7 +113,7 @@
label = "slv-cpr-xpu-cfg";
qcom,slavep = <4>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <7>;
};
@@ -117,7 +123,7 @@
label = "slv-misc-cfg";
qcom,slavep = <6>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <8>;
};
@@ -127,7 +133,7 @@
label = "slv-misc-xpu-cfg";
qcom,slavep = <7>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <9>;
};
@@ -137,7 +143,7 @@
label = "slv-gfx3d-cfg";
qcom,slavep = <9>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <11>;
};
@@ -147,7 +153,7 @@
label = "slv-mmss-clk-cfg";
qcom,slavep = <11>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <12>;
};
@@ -157,7 +163,7 @@
label = "slv-mmss-clk-xpu-cfg";
qcom,slavep = <12>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <13>;
};
@@ -167,7 +173,7 @@
label = "slv-mnoc-mpu-cfg";
qcom,slavep = <13>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <14>;
};
@@ -177,7 +183,7 @@
label = "slv-onoc-mpu-cfg";
qcom,slavep = <14>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <15>;
};
@@ -187,7 +193,7 @@
label = "slv-service-mnoc";
qcom,slavep = <18>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <17>;
};
@@ -197,7 +203,7 @@
label = "slv-dsi-cfg";
qcom,slavep = <19>;
qcom,tier = <2>;
- qcom,buswidth = <16>;
+ qcom,buswidth = <8>;
qcom,hw-sel = "NoC";
qcom,slv-hw-id = <19>;
};
@@ -272,8 +278,8 @@
qcom,mas-hw-id = <29>;
qcom,slv-hw-id = <28>;
qcom,mode = "Fixed";
- qcom,prio-rd = <2>;
- qcom,prio-wr = <2>;
+ qcom,prio0 = <2>;
+ qcom,prio1 = <2>;
};
fab-ovnoc {
@@ -291,6 +297,9 @@
qcom,masterp = <5>;
qcom,tier = <2>;
qcom,mas-hw-id = <23>;
+ qcom,hw-sel = "NoC";
+ qcom,prio0 = <1>;
+ qcom,prio1 = <1>;
};
mas-mss {
@@ -899,6 +908,7 @@
qcom,mas-hw-id = <0>;
qcom,prio-rd = <1>;
qcom,prio-wr = <1>;
+ qcom,prio-lvl = <1>;
};
mas-mss-proc {
@@ -943,8 +953,8 @@
qcom,qport = <4>;
qcom,mas-hw-id = <25>;
qcom,mode = "Fixed";
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
+ qcom,prio0 = <1>;
+ qcom,prio1 = <1>;
};
mas-gfx3d {
@@ -952,13 +962,11 @@
label = "mas-gfx3d";
qcom,masterp = <5>;
qcom,tier = <2>;
- qcom,hw-sel = "NoC";
- qcom,perm-mode = "Bypass";
- qcom,mode = "Bypass";
+ qcom,hw-sel = "BIMC";
+ qcom,perm-mode = "Fixed";
+ qcom,mode = "Fixed";
qcom,ws = <10000>;
qcom,qport = <5>;
- qcom,prio-rd = <1>;
- qcom,prio-wr = <1>;
qcom,mas-hw-id = <6>;
};
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 1bf7c2b..d3fc917 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -88,6 +88,49 @@
};
};
};
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "atmel_mxt_ts";
+ qcom,disp-maxx = <480>;
+ qcom,disp-maxy = <800>;
+ qcom,panel-maxx = <508>;
+ qcom,panel-maxy = <880>;
+ qcom,key-codes = <158 102 139>;
+ qcom,y-offset = <35>;
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&msmgpio 73 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&msmgpio 74 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&msmgpio 72 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
};
&i2c_cdc {
@@ -165,38 +208,6 @@
};
};
};
-
- gpio_keys {
- compatible = "gpio-keys";
- input-name = "gpio-keys";
-
- camera_snapshot {
- label = "camera_snapshot";
- gpios = <&msmgpio 73 0x1>;
- linux,input-type = <1>;
- linux,code = <0x2fe>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- camera_focus {
- label = "camera_focus";
- gpios = <&msmgpio 74 0x1>;
- linux,input-type = <1>;
- linux,code = <0x210>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_up {
- label = "volume_up";
- gpios = <&msmgpio 72 0x1>;
- linux,input-type = <1>;
- linux,code = <115>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
- };
};
&spmi_bus {
@@ -207,17 +218,6 @@
qcom,vib-vtg-level-mV = <3100>;
};
};
-
- gen-vkeys {
- compatible = "qcom,gen-vkeys";
- label = "atmel_mxt_ts";
- qcom,disp-maxx = <480>;
- qcom,disp-maxy = <800>;
- qcom,panel-maxx = <508>;
- qcom,panel-maxy = <880>;
- qcom,key-codes = <158 102 139>;
- qcom,y-offset = <35>;
- };
};
&sdhc_1 {
@@ -327,3 +327,52 @@
mpp@a300 { /* MPP 4 */
};
};
+
+/* CoreSight */
+&tpiu {
+ qcom,seta-gpios = <&msmgpio 4 0>,
+ <&msmgpio 5 0>,
+ <&msmgpio 6 0>,
+ <&msmgpio 7 0>,
+ <&msmgpio 22 0>,
+ <&msmgpio 23 0>,
+ <&msmgpio 24 0>,
+ <&msmgpio 25 0>,
+ <&msmgpio 26 0>,
+ <&msmgpio 27 0>,
+ <&msmgpio 28 0>,
+ <&msmgpio 29 0>,
+ <&msmgpio 30 0>,
+ <&msmgpio 31 0>,
+ <&msmgpio 94 0>,
+ <&msmgpio 95 0>,
+ <&msmgpio 96 0>,
+ <&msmgpio 97 0>;
+ qcom,seta-gpios-func = <9 9 8 11 2 2 2 2 2 2 3 2 3 3 4 4 4 4>;
+ qcom,seta-gpios-drv = <7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7>;
+ qcom,seta-gpios-pull = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+ qcom,seta-gpios-dir = <2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2>;
+
+ qcom,setb-gpios = <&msmgpio 8 0>,
+ <&msmgpio 10 0>,
+ <&msmgpio 11 0>,
+ <&msmgpio 13 0>,
+ <&msmgpio 14 0>,
+ <&msmgpio 15 0>,
+ <&msmgpio 16 0>,
+ <&msmgpio 17 0>,
+ <&msmgpio 18 0>,
+ <&msmgpio 19 0>,
+ <&msmgpio 20 0>,
+ <&msmgpio 21 0>,
+ <&msmgpio 42 0>,
+ <&msmgpio 80 0>,
+ <&msmgpio 81 0>,
+ <&msmgpio 82 0>,
+ <&msmgpio 83 0>,
+ <&msmgpio 84 0>;
+ qcom,setb-gpios-func = <10 8 8 6 9 9 9 9 9 9 9 9 5 7 7 8 8 8>;
+ qcom,setb-gpios-drv = <7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7>;
+ qcom,setb-gpios-pull = <0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
+ qcom,setb-gpios-dir = <2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2>;
+};
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 4945693..516522e 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -34,6 +34,11 @@
coresight-id = <1>;
coresight-name = "coresight-tpiu";
coresight-nr-inports = <1>;
+
+ vdd-supply = <&pm8110_l18>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 400000>;
};
replicator: replicator@fc324000 {
@@ -335,4 +340,18 @@
coresight-name = "coresight-cti-cpu3";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@fd820018 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xfd820018 0x80>,
+ <0xf9011080 0x80>,
+ <0xfd4ab160 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+ coresight-id = <27>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ qcom,hwevent-clks = "core_mmss_clk";
+ };
};
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 3fbc820..e1fe66a 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -88,6 +88,49 @@
};
};
};
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "atmel_mxt_ts";
+ qcom,disp-maxx = <480>;
+ qcom,disp-maxy = <800>;
+ qcom,panel-maxx = <508>;
+ qcom,panel-maxy = <880>;
+ qcom,key-codes = <158 102 139>;
+ qcom,y-offset = <35>;
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&msmgpio 73 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&msmgpio 74 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&msmgpio 72 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
};
&i2c_cdc {
@@ -165,38 +208,6 @@
};
};
};
-
- gpio_keys {
- compatible = "gpio-keys";
- input-name = "gpio-keys";
-
- camera_snapshot {
- label = "camera_snapshot";
- gpios = <&msmgpio 73 0x1>;
- linux,input-type = <1>;
- linux,code = <0x2fe>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- camera_focus {
- label = "camera_focus";
- gpios = <&msmgpio 74 0x1>;
- linux,input-type = <1>;
- linux,code = <0x210>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_up {
- label = "volume_up";
- gpios = <&msmgpio 72 0x1>;
- linux,input-type = <1>;
- linux,code = <115>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
- };
};
&spmi_bus {
@@ -207,17 +218,6 @@
qcom,vib-vtg-level-mV = <3100>;
};
};
-
- gen-vkeys {
- compatible = "qcom,gen-vkeys";
- label = "atmel_mxt_ts";
- qcom,disp-maxx = <480>;
- qcom,disp-maxy = <800>;
- qcom,panel-maxx = <508>;
- qcom,panel-maxy = <880>;
- qcom,key-codes = <158 102 139>;
- qcom,y-offset = <35>;
- };
};
&sdhc_1 {
@@ -330,3 +330,7 @@
mpp@a300 { /* MPP 4 */
};
};
+
+&pm8110_bms {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 3df428a..a90f053 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -30,23 +30,37 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>,
- <0xfc4b80b0 8>;
- reg-names = "rbcpr", "efuse_phys";
+ reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
+ reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <4>;
+ regulator-max-microvolt = <3>;
qcom,num-efuse-bits = <5>;
- qcom,efuse-bit-pos = <6 7 8 9 10>;
- qcom,pvs-bin-process = <0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
+ qcom,pvs-bin-process = <0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2
2 2 2 2 3 3 3 3 3 3 3 3 0 0 0 0>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000 1350000>;
- qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
+ qcom,pvs-corner-ceiling-slow = <1150000 1150000 1275000>;
+ qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
+ qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
vdd-apc-supply = <&pm8110_s2>;
+
vdd-mx-supply = <&pm8110_l3_ao>;
qcom,vdd-mx-vmax = <1350000>;
qcom,vdd-mx-vmin-method = <1>;
+
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay = <5000>;
+ qcom,cpr-timer-cons-up = <1>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-irq-line = <0>;
+ qcom,cpr-step-quotient = <15>;
+ qcom,cpr-up-threshold = <1>;
+ qcom,cpr-down-threshold = <2>;
+ qcom,cpr-idle-clocks = <5>;
+ qcom,cpr-gcnt-time = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-apc-volt-step = <5000>;
};
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 6a2855d..6347902 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -144,6 +144,11 @@
qcom,adsp-state = <0>;
};
+ qcom,msm-audio-ion {
+ compatible = "qcom,msm-audio-ion";
+ qcom,smmu-enabled;
+ };
+
qcom,msm-imem@fe805000 {
compatible = "qcom,msm-imem";
reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
@@ -706,6 +711,7 @@
/* GPIO inputs from lpass */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
/* GPIO output to lpass */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
@@ -725,11 +731,12 @@
qcom,msm-thermal {
compatible = "qcom,msm-thermal";
- qcom,sensor-id = <0>;
+ qcom,sensor-id = <5>;
qcom,poll-ms = <250>;
qcom,limit-temp = <60>;
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
+ qcom,freq-control-mask = <0xf>;
};
qcom,ipc-spinlock@fd484000 {
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index b574a31..4a9820d 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -36,6 +36,8 @@
qcom,actuator-src = <&actuator0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -77,6 +79,8 @@
qcom,mount-angle = <90>;
qcom,sensor-name = "imx135";
qcom,actuator-src = <&actuator1>;
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -89,11 +93,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
@@ -114,6 +122,8 @@
qcom,csid-sd-index = <2>;
qcom,mount-angle = <90>;
qcom,sensor-name = "ov2720";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -149,6 +159,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 748d5f7..f61b83a 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -37,6 +37,8 @@
qcom,led-flash-src = <&led_flash0>;
qcom,mount-angle = <270>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -78,6 +80,8 @@
qcom,mount-angle = <270>;
qcom,sensor-name = "imx135";
qcom,actuator-src = <&actuator1>;
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -90,11 +94,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
@@ -115,6 +123,8 @@
qcom,csid-sd-index = <2>;
qcom,mount-angle = <90>;
qcom,sensor-name = "ov2720";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -150,6 +160,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index 5a97a11..e0b572e 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -36,6 +36,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs2>;
@@ -73,6 +75,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "imx135";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
qcom,actuator-src = <&actuator1>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
@@ -86,11 +90,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
@@ -111,6 +119,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <180>;
qcom,sensor-name = "ov2720";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs2>;
@@ -145,6 +155,8 @@
qcom,csiphy-sd-index = <1>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
qcom,sensor-name = "mt9m114";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 53f6e9e..6ad6213 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -37,6 +37,8 @@
qcom,led-flash-src = <&led_flash0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -77,6 +79,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "imx135";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
qcom,actuator-src = <&actuator1>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
@@ -90,11 +94,15 @@
qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 15 0>,
- <&msmgpio 90 0>;
+ <&msmgpio 90 0>,
+ <&msmgpio 89 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-req-tbl-num = <0 1>;
- qcom,gpio-req-tbl-flags = <1 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
qcom,gpio-set-tbl-num = <1 1>;
qcom,gpio-set-tbl-flags = <0 2>;
qcom,gpio-set-tbl-delay = <1000 30000>;
@@ -116,6 +124,8 @@
qcom,csid-sd-index = <2>;
qcom,mount-angle = <90>;
qcom,sensor-name = "ov2720";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
@@ -151,6 +161,8 @@
qcom,csid-sd-index = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "mt9m114";
+ qcom,vdd-cx-supply = <&pm8841_s2>;
+ qcom,vdd-cx-name = "qcom,vdd-cx";
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
cam_vio-supply = <&pm8941_lvs3>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 5fa7c08..3e65b8a 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -247,7 +247,7 @@
<85 512 40000 160000>,
<85 512 40000 320000>,
<85 512 40000 480000>,
- <85 512 40000 640000>;
+ <85 512 40000 800000>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index ee8152d..63f6d59 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -53,7 +53,7 @@
reg = <28>;
qcom,heap-align = <0x1000>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x314000>;
+ qcom,memory-reservation-size = <0x614000>;
};
};
};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index e63b53b..c2dae28 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -294,9 +294,19 @@
enable-active-high;
};
+ ath_chip_pwd_l: ath_chip_reset {
+ compatible = "regulator-fixed";
+ regulator-name = "ath_chip_pwd_l";
+ gpio = <&pm8941_gpios 33 0>;
+ enable-active-high;
+ };
+
bt_ar3002 {
compatible = "qca,ar3002";
qca,bt-reset-gpio = <&pm8941_gpios 34 0>;
+ qca,bt-chip-pwd-supply = <&ath_chip_pwd_l>;
+ qca,bt-vdd-io-supply = <&pm8941_s3>;
+ qca,bt-vdd-pa-supply = <&pm8941_l19>;
};
bt_ar3002_sleep {
@@ -717,8 +727,10 @@
&slim_msm {
taiko_codec {
+ qcom,cdc-micbias1-ext-cap;
qcom,cdc-micbias2-ext-cap;
qcom,cdc-micbias3-ext-cap;
+ qcom,cdc-micbias4-ext-cap;
/*
* Liquid has external spkrdrv supply. Give a dummy supply to
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 2cd3d24..35f3993 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -460,8 +460,9 @@
&soc {
krait_pdn: krait-pdn@f9011000 {
- reg = <0xf9011000 0x1000>;
- reg-names = "apcs_gcc";
+ reg = <0xf9011000 0x1000>,
+ <0xfc4b80b0 8>;
+ reg-names = "apcs_gcc", "phase-scaling-efuse";
compatible = "qcom,krait-pdn";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8974-v1-cdp.dts b/arch/arm/boot/dts/msm8974-v1-cdp.dts
index cb58026..c3fd98d 100644
--- a/arch/arm/boot/dts/msm8974-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-cdp.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974 CDP";
compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
- qcom,msm-id = <126 1 0>;
+ qcom,msm-id = <126 1 0>,
+ <185 1 0>,
+ <186 1 0>;
};
&ehci {
diff --git a/arch/arm/boot/dts/msm8974-v1-fluid.dts b/arch/arm/boot/dts/msm8974-v1-fluid.dts
index 8ab24df..2b96ecb 100644
--- a/arch/arm/boot/dts/msm8974-v1-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-fluid.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974 FLUID";
compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
- qcom,msm-id = <126 3 0>;
+ qcom,msm-id = <126 3 0>,
+ <185 3 0>,
+ <186 3 0>;
};
diff --git a/arch/arm/boot/dts/msm8974-v1-liquid.dts b/arch/arm/boot/dts/msm8974-v1-liquid.dts
index ccbd82f..29d6150 100644
--- a/arch/arm/boot/dts/msm8974-v1-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-v1-liquid.dts
@@ -18,5 +18,7 @@
/ {
model = "Qualcomm MSM 8974 LIQUID";
compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
- qcom,msm-id = <126 9 0>;
+ qcom,msm-id = <126 9 0>,
+ <185 9 0>,
+ <186 9 0>;
};
diff --git a/arch/arm/boot/dts/msm8974-v1-mtp.dts b/arch/arm/boot/dts/msm8974-v1-mtp.dts
index 09ea84b..8cbcca0 100644
--- a/arch/arm/boot/dts/msm8974-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v1-mtp.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974 MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
- qcom,msm-id = <126 8 0>;
+ qcom,msm-id = <126 8 0>,
+ <185 8 0>,
+ <186 8 0>;
};
&pm8941_chg {
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 1a88749..cebc99a 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -340,7 +340,8 @@
qcom,ipc-bit-offset = <1>;
qcom,gic-parent = <&intc>;
- qcom,gic-map = <47 165>, /* usb30_hs_phy_irq */
+ qcom,gic-map = <2 216>, /* tsens_upper_lower_int */
+ <47 165>, /* usb30_hs_phy_irq */
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
diff --git a/arch/arm/boot/dts/msm8974-v1-rumi.dts b/arch/arm/boot/dts/msm8974-v1-rumi.dts
index caf89ee..85aab17 100644
--- a/arch/arm/boot/dts/msm8974-v1-rumi.dts
+++ b/arch/arm/boot/dts/msm8974-v1-rumi.dts
@@ -18,5 +18,7 @@
/ {
model = "Qualcomm MSM 8974 RUMI";
compatible = "qcom,msm8974-rumi", "qcom,msm8974", "qcom,rumi";
- qcom,msm-id = <126 15 0>;
+ qcom,msm-id = <126 15 0>,
+ <185 15 0>,
+ <186 15 0>;
};
diff --git a/arch/arm/boot/dts/msm8974-v1-sim.dts b/arch/arm/boot/dts/msm8974-v1-sim.dts
index c4b29c2..fc9858d 100644
--- a/arch/arm/boot/dts/msm8974-v1-sim.dts
+++ b/arch/arm/boot/dts/msm8974-v1-sim.dts
@@ -18,5 +18,7 @@
/ {
model = "Qualcomm MSM 8974 Simulator";
compatible = "qcom,msm8974-sim", "qcom,msm8974", "qcom,sim";
- qcom,msm-id = <126 16 0>;
+ qcom,msm-id = <126 16 0>,
+ <185 16 0>,
+ <186 16 0>;
};
diff --git a/arch/arm/boot/dts/msm8974-v2-cdp.dts b/arch/arm/boot/dts/msm8974-v2-cdp.dts
index 4fa1f2a..85d478b 100644
--- a/arch/arm/boot/dts/msm8974-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-cdp.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974v2 CDP";
compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
- qcom,msm-id = <126 1 0x20000>;
+ qcom,msm-id = <126 1 0x20000>,
+ <185 1 0x20000>,
+ <186 1 0x20000>;
};
&usb3 {
diff --git a/arch/arm/boot/dts/msm8974-v2-fluid.dts b/arch/arm/boot/dts/msm8974-v2-fluid.dts
index c5779b1..d83d130 100644
--- a/arch/arm/boot/dts/msm8974-v2-fluid.dts
+++ b/arch/arm/boot/dts/msm8974-v2-fluid.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974v2 FLUID";
compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
- qcom,msm-id = <126 3 0x20000>;
+ qcom,msm-id = <126 3 0x20000>,
+ <185 3 0x20000>,
+ <186 3 0x20000>;
};
&usb3 {
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index c974884..b5652d1 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -76,6 +76,7 @@
};
venus_sec_pixel: qcom,iommu-ctx@fdc8f000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8f000 0x1000>;
interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0x85>;
@@ -84,6 +85,7 @@
};
venus_sec_non_pixel: qcom,iommu-ctx@fdc90000 {
+ compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc90000 0x1000>;
interrupts = <0 42 0>;
qcom,iommu-ctx-sids = <0x87 0xA0>;
diff --git a/arch/arm/boot/dts/msm8974-v2-liquid.dts b/arch/arm/boot/dts/msm8974-v2-liquid.dts
index 7132f43..53983dc 100644
--- a/arch/arm/boot/dts/msm8974-v2-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-v2-liquid.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974v2 LIQUID";
compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
- qcom,msm-id = <126 9 0x20000>;
+ qcom,msm-id = <126 9 0x20000>,
+ <185 9 0x20000>,
+ <186 9 0x20000>;
};
&usb3 {
diff --git a/arch/arm/boot/dts/msm8974-v2-mtp.dts b/arch/arm/boot/dts/msm8974-v2-mtp.dts
index d38e663..1735515 100644
--- a/arch/arm/boot/dts/msm8974-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-v2-mtp.dts
@@ -18,7 +18,9 @@
/ {
model = "Qualcomm MSM 8974v2 MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
- qcom,msm-id = <126 8 0x20000>;
+ qcom,msm-id = <126 8 0x20000>,
+ <185 8 0x20000>,
+ <186 8 0x20000>;
};
&usb3 {
@@ -32,3 +34,7 @@
qcom,misc-ref = <&pm8941_misc>;
};
+
+&pm8941_chg {
+ qcom,bpd-detection = "bpd_id";
+};
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index f8492c0..d3a0bc8 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -190,9 +190,9 @@
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <1>;
- qcom,ss-power = <784>;
- qcom,energy-overhead = <190000>;
- qcom,time-overhead = <100>;
+ qcom,ss-power = <715>;
+ qcom,energy-overhead = <17700>;
+ qcom,time-overhead = <2>;
};
qcom,lpm-level@1 {
@@ -206,10 +206,10 @@
qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
- qcom,latency-us = <75>;
- qcom,ss-power = <735>;
- qcom,energy-overhead = <77341>;
- qcom,time-overhead = <105>;
+ qcom,latency-us = <35>;
+ qcom,ss-power = <542>;
+ qcom,energy-overhead = <34920>;
+ qcom,time-overhead = <40>;
};
@@ -224,10 +224,10 @@
qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
- qcom,latency-us = <95>;
- qcom,ss-power = <725>;
- qcom,energy-overhead = <99500>;
- qcom,time-overhead = <130>;
+ qcom,latency-us = <300>;
+ qcom,ss-power = <476>;
+ qcom,energy-overhead = <225300>;
+ qcom,time-overhead = <350>;
};
qcom,lpm-level@3 {
@@ -241,10 +241,10 @@
qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
- qcom,latency-us = <2000>;
- qcom,ss-power = <138>;
- qcom,energy-overhead = <1208400>;
- qcom,time-overhead = <3200>;
+ qcom,latency-us = <2817>;
+ qcom,ss-power = <163>;
+ qcom,energy-overhead = <1577736>;
+ qcom,time-overhead = <5067>;
};
qcom,lpm-level@4 {
@@ -258,44 +258,29 @@
qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,irqs-detectable;
qcom,gpio-detectable;
- qcom,latency-us = <3000>;
- qcom,ss-power = <110>;
- qcom,energy-overhead = <1250300>;
- qcom,time-overhead = <3500>;
+ qcom,latency-us = <3922>;
+ qcom,ss-power = <83>;
+ qcom,energy-overhead = <2274420>;
+ qcom,time-overhead = <6605>;
};
qcom,lpm-level@5 {
reg = <0x5>;
qcom,mode = "pc";
qcom,xo = "xo_off";
- qcom,l2 = "l2_cache_gdhs";
- qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <3000>;
- qcom,ss-power = <68>;
- qcom,energy-overhead = <1350200>;
- qcom,time-overhead = <4000>;
- };
-
- qcom,lpm-level@6 {
- reg = <0x6>;
- qcom,mode = "pc";
- qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
qcom,vdd-mem-upper-bound = <1050000>; /* SUPER TURBO */
qcom,vdd-mem-lower-bound = <950000>; /* NORMAL */
qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
- qcom,latency-us = <10300>;
- qcom,ss-power = <63>;
- qcom,energy-overhead = <2128000>;
- qcom,time-overhead = <18200>;
+ qcom,latency-us = <4922>;
+ qcom,ss-power = <68>;
+ qcom,energy-overhead = <2568180>;
+ qcom,time-overhead = <8812>;
};
- qcom,lpm-level@7 {
- reg = <0x7>;
+ qcom,lpm-level@6 {
+ reg = <0x6>;
qcom,mode= "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
@@ -303,14 +288,14 @@
qcom,vdd-mem-lower-bound = <950000>; /* SVS SOC */
qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
- qcom,latency-us = <18000>;
- qcom,ss-power = <10>;
- qcom,energy-overhead = <3202600>;
- qcom,time-overhead = <27000>;
+ qcom,latency-us = <5890>;
+ qcom,ss-power = <60>;
+ qcom,energy-overhead = <2675900>;
+ qcom,time-overhead = <10140>;
};
- qcom,lpm-level@8 {
- reg = <0x8>;
+ qcom,lpm-level@7 {
+ reg = <0x7>;
qcom,mode= "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
@@ -318,10 +303,10 @@
qcom,vdd-mem-lower-bound = <675000>; /* RETENTION */
qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
- qcom,latency-us = <20000>;
- qcom,ss-power = <2>;
- qcom,energy-overhead = <4252000>;
- qcom,time-overhead = <32000>;
+ qcom,latency-us = <8500>;
+ qcom,ss-power = <18>;
+ qcom,energy-overhead = <3286600>;
+ qcom,time-overhead = <15760>;
};
};
@@ -340,7 +325,8 @@
qcom,ipc-bit-offset = <1>;
qcom,gic-parent = <&intc>;
- qcom,gic-map = <47 165>, /* usb30_hs_phy_irq */
+ qcom,gic-map = <2 216>, /* tsens_upper_lower_int */
+ <47 165>, /* usb30_hs_phy_irq */
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
@@ -427,6 +413,17 @@
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
+ qcom,pm-snoc-client {
+ compatible = "qcom,pm-snoc-client";
+ qcom,msm-bus,name = "ocimem_snoc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <54 585 0 0>,
+ <54 585 0 800000>;
+ };
+
qcom,cpu-sleep-status@f9088008{
compatible = "qcom,cpu-sleep-status";
reg = <0xf9088008 0x100>;
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 75dce17..b37a509 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -131,3 +131,7 @@
&krait_pdn {
qcom,use-phase-switching;
};
+
+&tspp {
+ vdd_cx-supply = <&pm8841_s2_corner>;
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 71bbdc5..e2dd3fd 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -869,6 +869,7 @@
/* GPIO inputs from lpass */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
/* GPIO output to lpass */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
@@ -1127,7 +1128,6 @@
vdd_mx-supply = <&pm8841_s1>;
vdd_pll-supply = <&pm8941_l12>;
qcom,vdd_pll = <1800000>;
- qcom,is-loadable;
qcom,firmware-name = "mba";
qcom,pil-self-auth;
@@ -1419,6 +1419,7 @@
qcom,limit-temp = <60>;
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
+ qcom,freq-control-mask = <0xf>;
qcom,core-limit-temp = <80>;
qcom,core-temp-hysteresis = <10>;
qcom,core-control-mask = <0xe>;
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 8520b19..9b18b72 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -243,4 +243,15 @@
coresight-name = "coresight-cti-cpu";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@f9011038 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xf9011038 0x8>,
+ <0xfd4ab160 0x80>;
+ reg-names = "apcs-mux", "ppss-mux";
+
+ coresight-id = <20>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 6c45f80..1d10f8c 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -201,7 +201,8 @@
qcom,ipc-bit-offset = <1>;
qcom,gic-parent = <&intc>;
- qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
+ qcom,gic-map = <2 216>, /* tsens_upper_lower_int */
+ <47 172>, /* usb2_hsic_async_wakeup_irq */
<41 180>, /* usb_async_wakeup_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 5abfab8..6e258b5 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -763,6 +763,7 @@
qcom,mss {
compatible = "qcom,pil-q6v5-mss";
interrupts = <0 24 1>;
+ qcom,is-not-loadable;
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
diff --git a/arch/arm/boot/dts/msmsamarium-ion.dtsi b/arch/arm/boot/dts/msmsamarium-ion.dtsi
new file mode 100644
index 0000000..ea954b8
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-ion.dtsi
@@ -0,0 +1,31 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ion-heap@30 { /* SYSTEM HEAP */
+ reg = <30>;
+ };
+
+ qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
+ reg = <21>;
+ };
+
+ qcom,ion-heap@25 { /* IOMMU HEAP */
+ reg = <25>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msmsamarium-sim.dts b/arch/arm/boot/dts/msmsamarium-sim.dts
new file mode 100644
index 0000000..2774f7f
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-sim.dts
@@ -0,0 +1,25 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msmsamarium.dtsi"
+
+/ {
+ model = "Qualcomm MSM SAMARIUM SIM";
+ compatible = "qcom,msmsamarium-sim", "qcom,msmsamarium", "qcom,sim";
+ qcom,msm-id = <195 0 0>;
+};
+
+&uartblsp0dm2{
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
new file mode 100644
index 0000000..9d9ff87
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -0,0 +1,66 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Qualcomm MSM SAMARIUM";
+ compatible = "qcom,msmsamarium";
+ interrupt-parent = <&intc>;
+ soc: soc { };
+};
+
+/include/ "msmsamarium-ion.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ intc: interrupt-controller@f9000000 {
+ compatible = "qcom,msm-qgic2";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0xf9000000 0x1000>,
+ <0xf9002000 0x1000>;
+ };
+
+ msmgpio: gpio@fd510000 {
+ compatible = "qcom,msm-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0xfd510000 0x4000>;
+ ngpio = <145>;
+ interrupts = <0 208 0>;
+ qcom,direct-connect-irqs = <8>;
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 2 0 1 3 0>;
+ clock-frequency = <19200000>;
+ };
+
+ uartblsp0dm2: serial@f991f000 {
+ compatible = "qcom,msm-lsuart-v14";
+ reg = <0xf991f000 0x1000>;
+ interrupts = <0 109 0>;
+ status = "disabled";
+ };
+
+ qcom,msm-imem@fe805000 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe805000 0x1000>; /* Address and size of IMEM */
+ };
+};
diff --git a/arch/arm/boot/dts/skeleton64.dtsi b/arch/arm/boot/dts/skeleton64.dtsi
new file mode 100644
index 0000000..5bf6a82
--- /dev/null
+++ b/arch/arm/boot/dts/skeleton64.dtsi
@@ -0,0 +1,18 @@
+/*
+ * Skeleton device tree; the bare minimum needed to boot; just include and
+ * add a compatible value. The bootloader will typically populate the memory
+ * node.
+ */
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ chosen { };
+ aliases { };
+ memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ device_type = "memory";
+ reg = <0 0 0 0>;
+ };
+};
diff --git a/arch/arm/configs/mpq8092_defconfig b/arch/arm/configs/mpq8092_defconfig
new file mode 100644
index 0000000..c06161d
--- /dev/null
+++ b/arch/arm/configs/mpq8092_defconfig
@@ -0,0 +1,382 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_IOSCHED_TEST=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MPQ8092=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+CONFIG_MSM_MPM_OF=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_SECURITY=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_RUN_QUEUE_STATS=y
+CONFIG_MSM_SPM_V2=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_CACHE_ERP=y
+CONFIG_MSM_L1_ERR_PANIC=y
+CONFIG_MSM_L1_RECOV_ERR_PANIC=y
+CONFIG_MSM_L1_ERR_LOG=y
+CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
+CONFIG_MSM_L2_ERP_PORT_PANIC=y
+CONFIG_MSM_L2_ERP_1BIT_PANIC=y
+CONFIG_MSM_L2_ERP_2BIT_PANIC=y
+CONFIG_MSM_CACHE_DUMP=y
+CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_USE_OF=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_CFG80211=y
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_USB_HSIC_SMSC_HUB=y
+CONFIG_TI_DRV2667=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_KS8851=m
+# CONFIG_MSM_RMNET is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_USB_USBNET=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_SMB350_CHARGER=y
+CONFIG_BATTERY_BQ28400=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_BATTERY_BCL=y
+CONFIG_SENSORS_EPM_ADC=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_USB=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_STORAGE_ENE_UB6250=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_SWITCH=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_QPNP_CLKDIV=y
+CONFIG_MSM_IOMMU=y
+CONFIG_IOMMU_PGTABLES_L2=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_PSTORE=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index aea092e..ba36df1 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -370,6 +370,7 @@
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_SHIRQ=y
+CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
new file mode 100644
index 0000000..07a15d9
--- /dev/null
+++ b/arch/arm/configs/msm8226_defconfig
@@ -0,0 +1,383 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8226=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_VENUS=y
+CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_OCMEM_POWER_DISABLE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_USE_OF=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_QPNP_BMS=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_WCD9306_CODEC=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_MSM_CAMERA is not set
+CONFIG_OV8825=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_ISPIF=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_OV9724=y
+CONFIG_MSMB_JPEG=y
+CONFIG_SWITCH=y
+CONFIG_MSM_WFD=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8226=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_MSM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SPS=y
+CONFIG_USB_BAM=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_MSM_IOMMU=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_TMC=y
+CONFIG_CORESIGHT_TPIU=y
+CONFIG_CORESIGHT_FUNNEL=y
+CONFIG_CORESIGHT_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_ETM=y
+CONFIG_CORESIGHT_EVENT=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_QPNP_VIBRATOR=y
+CONFIG_QSEECOM=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=m
\ No newline at end of file
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index e45024e..ef56fec 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -217,6 +217,8 @@
CONFIG_INPUT_EVBUG=m
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_GEN_VKEYS=y
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
@@ -332,14 +334,6 @@
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_MSM_IOMMU=y
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_TMC=y
-CONFIG_CORESIGHT_TPIU=y
-CONFIG_CORESIGHT_FUNNEL=y
-CONFIG_CORESIGHT_REPLICATOR=y
-CONFIG_CORESIGHT_STM=y
-CONFIG_CORESIGHT_ETM=y
-CONFIG_CORESIGHT_EVENT=m
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index bff59db..e4497e1 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -216,6 +216,7 @@
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_GEN_VKEYS=y
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
@@ -336,6 +337,7 @@
CONFIG_CORESIGHT_FUNNEL=y
CONFIG_CORESIGHT_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_ETM=y
CONFIG_CORESIGHT_EVENT=m
CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index dda9bd3..5885c6e 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -428,6 +428,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index f90e5f3..6c18a97 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -510,6 +510,7 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 8ebe7d4..72032dc 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -459,6 +459,7 @@
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_TIMER_STATS=y
+CONFIG_SCHEDSTATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
@@ -475,3 +476,4 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index fd8a639..091cdd9 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -37,6 +37,7 @@
CONFIG_DEFAULT_ROW=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM8974=y
+CONFIG_ARCH_MSMSAMARIUM=y
CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
# CONFIG_MSM_STACKED_MEMORY is not set
CONFIG_CPU_HAS_L2_PMU=y
@@ -455,6 +456,7 @@
CONFIG_CORESIGHT_FUNNEL=y
CONFIG_CORESIGHT_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_ETM=y
CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
CONFIG_CORESIGHT_EVENT=m
@@ -506,3 +508,4 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 662d555..f434199 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -258,6 +258,7 @@
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_G_ANDROID=y
CONFIG_MMC=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 7e92748..2a1215d 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -258,6 +258,7 @@
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_CI13XXX_MSM=y
CONFIG_USB_G_ANDROID=y
CONFIG_MMC=y
@@ -285,6 +286,7 @@
CONFIG_CORESIGHT_FUNNEL=y
CONFIG_CORESIGHT_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_ETM=y
CONFIG_CORESIGHT_EVENT=m
CONFIG_EXT3_FS=y
@@ -318,8 +320,8 @@
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_DEV_QCRYPTO=m
-CONFIG_CRYPTO_DEV_QCE=m
-CONFIG_CRYPTO_DEV_QCEDEV=m
+#CONFIG_CRYPTO_DEV_QCRYPTO is not set
+#CONFIG_CRYPTO_DEV_QCE is not set
+#CONFIG_CRYPTO_DEV_QCEDEV is not set
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index 2a46914..07a09b5 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -196,7 +196,7 @@
struct membank {
phys_addr_t start;
- unsigned long size;
+ phys_addr_t size;
unsigned int highmem;
};
@@ -218,7 +218,7 @@
#define bank_phys_end(bank) ((bank)->start + (bank)->size)
#define bank_phys_size(bank) (bank)->size
-extern int arm_add_memory(phys_addr_t start, unsigned long size);
+extern int arm_add_memory(phys_addr_t start, phys_addr_t size);
extern void early_print(const char *str, ...);
extern void dump_machine_table(void);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 4aabf0e..28b114f 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -510,7 +510,7 @@
/* can't use cpu_relax() here as it may require MMU setup */;
}
-int __init arm_add_memory(phys_addr_t start, unsigned long size)
+int __init arm_add_memory(phys_addr_t start, phys_addr_t size)
{
struct membank *bank = &meminfo.bank[meminfo.nr_banks];
@@ -540,7 +540,7 @@
}
#endif
- bank->size = size & PAGE_MASK;
+ bank->size = size & ~(phys_addr_t)(PAGE_SIZE - 1);
/*
* Check whether this memory region has non-zero size or
@@ -560,7 +560,7 @@
static int __init early_mem(char *p)
{
static int usermem __initdata = 0;
- unsigned long size;
+ phys_addr_t size;
phys_addr_t start;
char *endp;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 0eecffd..108a68f 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -145,7 +145,7 @@
select CPU_V7
select GPIO_MSM_V2
select MSM_GPIOMUX
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_DIRECT_SCLK_ACCESS
select REGULATOR
select MSM_RPM_REGULATOR
@@ -187,7 +187,7 @@
select CPU_V7
select GPIO_MSM_V2
select MSM_GPIOMUX
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_DIRECT_SCLK_ACCESS
select REGULATOR
select MSM_RPM_REGULATOR
@@ -223,7 +223,7 @@
select GPIO_MSM_V2
select ARM_GIC
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_GPIOMUX
select MSM_REMOTE_SPINLOCK_SFPB
select MSM_PIL
@@ -257,7 +257,7 @@
select GPIO_MSM_V3
select ARM_GIC
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
select MSM_MULTIMEDIA_USE_ION
@@ -292,7 +292,7 @@
select GPIO_MSM_V3
select ARM_GIC
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
select MSM_NATIVE_RESTART
@@ -304,6 +304,8 @@
select ARM_HAS_SG_CHAIN
select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
select ARCH_WANT_KMAP_ATOMIC_FLUSH
+ select MEMORY_HOLE_CARVEOUT
+ select DONT_MAP_HOLE_AFTER_MEMBANK0
config ARCH_MPQ8092
bool "MPQ8092"
@@ -317,6 +319,25 @@
select SPARSE_IRQ
select MSM_NOPM
+config ARCH_FSM9900
+ bool "FSM9900"
+ select ARCH_MSM_KRAITMP
+ select GPIO_MSM_V3
+ select ARM_GIC
+ select CPU_V7
+ select MSM_SCM
+ select MSM_GPIOMUX
+ select MULTI_IRQ_HANDLER
+ select MSM_PIL
+ select MSM_NATIVE_RESTART
+ select MSM_RESTART_V2
+ select MAY_HAVE_SPARSE_IRQ
+ select SPARSE_IRQ
+ select REGULATOR
+ select ARM_HAS_SG_CHAIN
+ select MSM_RUN_QUEUE_STATS
+ select MSM_NOPM
+
config ARCH_FSM9XXX
bool "FSM9XXX"
select ARCH_MSM_SCORPION
@@ -378,7 +399,6 @@
select MSM_RESTART_V2
select MSM_SPM_V2
select MSM_PM8X60 if PM
- select MSM_SCM if SMP
select MULTI_IRQ_HANDLER
select GPIO_MSM_V3
select MAY_HAVE_SPARSE_IRQ
@@ -414,7 +434,7 @@
select GIC_SECURE
select ARCH_MSM_CORTEXMP
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
@@ -456,7 +476,7 @@
select GIC_SECURE
select ARCH_MSM_CORTEXMP
select CPU_V7
- select MSM_SCM if SMP
+ select MSM_SCM
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
@@ -491,6 +511,26 @@
select MSM_RPM_LOG
select MSM_RPM_STATS_LOG
select ARCH_WANT_KMAP_ATOMIC_FLUSH
+
+config ARCH_MSMSAMARIUM
+ bool "MSMSAMARIUM"
+ select ARCH_MSM_KRAITMP
+ select GPIO_MSM_V3
+ select ARM_GIC
+ select CPU_V7
+ select MSM_SCM
+ select MSM_GPIOMUX
+ select MULTI_IRQ_HANDLER
+ 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 ARM_HAS_SG_CHAIN
+ select MSM_RUN_QUEUE_STATS
+ select ARCH_WANT_KMAP_ATOMIC_FLUSH
endmenu
choice
@@ -1093,7 +1133,9 @@
default "0x00000000" if ARCH_MPQ8092
default "0x00000000" if ARCH_MSM8226
default "0x00000000" if ARCH_MSM8610
+ default "0x00000000" if ARCH_MSMSAMARIUM
default "0x10000000" if ARCH_FSM9XXX
+ default "0x00000000" if ARCH_FSM9900
default "0x00200000" if ARCH_MSM9625
default "0x00000000" if ARCH_MSMKRYPTON
default "0x00200000" if !MSM_STACKED_MEMORY
@@ -1257,6 +1299,22 @@
help
Say Y here if you want the debug print routines to direct
their output to the serial port on MSM9625 devices.
+
+ config DEBUG_FSM9900_UART
+ bool "Kernel low-level debugging messages via FSM9900 UART"
+ depends on ARCH_FSM9900
+ select MSM_HAS_DEBUG_UART_HS_V14
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port on FSM9900 devices.
+
+ config DEBUG_MSMSAMARIUM_UART
+ bool "Kernel low-level debugging messages via MSM SAMARIUM UART"
+ depends on ARCH_MSMSAMARIUM
+ select MSM_HAS_DEBUG_UART_HS_V14
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port on MSM SAMARIUM devices.
endchoice
choice
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 8efc000..4f4bfbc 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -75,7 +75,7 @@
$(obj)/smd_rpc_sym.c: $(src)/smd_rpc_sym $(src)/mkrpcsym.pl
$(call if_changed,mkrpcsym)
-obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o
+obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o smem.o
obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o smp2p_gpio.o
obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_gpio_test.o smp2p_spinlock_test.o
obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
@@ -121,6 +121,8 @@
ifndef CONFIG_ARCH_MSM8610
ifndef CONFIG_ARCH_APQ8084
ifndef CONFIG_ARCH_MSMKRYPTON
+ifndef CONFIG_ARCH_FSM9900
+ifndef CONFIG_ARCH_MSMSAMARIUM
obj-y += nand_partitions.o
endif
endif
@@ -132,6 +134,8 @@
endif
endif
endif
+endif
+endif
obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -230,6 +234,7 @@
obj-$(CONFIG_ARCH_FSM9XXX) += clock-fsm9xxx.o clock-local.o acpuclock-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += dfe-fsm9xxx.o rfic-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += restart-fsm9xxx.o xo-fsm9xxx.o
+obj-$(CONFIG_ARCH_FSM9900) += board-fsm9900.o board-fsm9900-gpiomux.o
obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog.o
obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog_asm.o
@@ -288,7 +293,7 @@
obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
obj-$(CONFIG_QPNP_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
-obj-$(CONFIG_QPNP_BMS) += bms-batterydata-oem.o
+obj-$(CONFIG_QPNP_BMS) += bms-batterydata-oem.o bms-batterydata-qrd-4v35-2000mah.o
obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_MACH_APQ8064_LIQUID) += board-8064-all.o board-8064-regulator.o
@@ -297,6 +302,7 @@
obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o board-9615-display.o
obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
obj-$(CONFIG_ARCH_APQ8084) += board-8084.o board-8084-gpiomux.o
+obj-$(CONFIG_ARCH_APQ8084) += clock-8084.o
obj-$(CONFIG_ARCH_MSM8974) += board-8974.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 clock-mdss-8974.o
@@ -306,6 +312,7 @@
obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
+obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += clock-local2.o clock-pll.o clock-9625.o clock-rpm.o clock-voter.o acpuclock-9625.o acpuclock-cortex.o
obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o acpuclock-8930ab.o
@@ -372,10 +379,12 @@
obj-$(CONFIG_ARCH_MSM8974) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_MSMSAMARIUM) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MPQ8092) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_ARCH_APQ8084) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_FSM9900) += gpiomux-v2.o gpiomux.o
obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_mpdecision.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 2827e65..b40c70a 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -93,6 +93,11 @@
params_phys-$(CONFIG_ARCH_FSM9XXX) := 0x10000100
initrd_phys-$(CONFIG_ARCH_FSM9XXX) := 0x12000000
+# FSM9900
+ zreladdr-$(CONFIG_ARCH_FSM9900) := 0x00008000
+ dtb-$(CONFIG_ARCH_FSM9900) := fsm9900-rumi.dtb
+ dtb-$(CONFIG_ARCH_FSM9900) := fsm9900-sim.dtb
+
# MPQ8092
zreladdr-$(CONFIG_ARCH_MPQ8092) := 0x00008000
@@ -100,3 +105,7 @@
zreladdr-$(CONFIG_ARCH_MSM8610) := 0x00008000
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-rumi.dtb
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-sim.dtb
+
+# MSMSAMARIUM
+ zreladdr-$(CONFIG_ARCH_MSMSAMARIUM) := 0x00008000
+ dtb-$(CONFIG_ARCH_MSMSAMARIUM) += msmsamarium-sim.dtb
diff --git a/arch/arm/mach-msm/bms-batterydata-qrd-4v35-2000mah.c b/arch/arm/mach-msm/bms-batterydata-qrd-4v35-2000mah.c
new file mode 100644
index 0000000..8adf8ca
--- /dev/null
+++ b/arch/arm/mach-msm/bms-batterydata-qrd-4v35-2000mah.c
@@ -0,0 +1,117 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
+
+static struct single_row_lut fcc_temp = {
+ .x = {-20, 0, 25, 40, 60},
+ .y = {2096, 2124, 2121, 2118, 2103},
+ .cols = 5
+};
+
+static struct single_row_lut fcc_sf = {
+ .x = {0},
+ .y = {100},
+ .cols = 1
+};
+
+static struct sf_lut rbatt_sf = {
+ .rows = 30,
+ .cols = 5,
+ .row_entries = {-20, 0, 25, 40, 60},
+ .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60,
+ 55, 50, 45, 40, 35, 30, 25, 20, 16, 13,
+ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
+ .sf = {
+ {2422, 324, 100, 79, 72},
+ {2417, 325, 100, 79, 71},
+ {2344, 327, 100, 80, 72},
+ {2416, 336, 102, 81, 73},
+ {2072, 354, 107, 82, 73},
+ {1961, 372, 113, 84, 75},
+ {1929, 341, 118, 87, 77},
+ {1929, 321, 130, 93, 80},
+ {2041, 306, 140, 104, 85},
+ {2202, 292, 119, 96, 83},
+ {2374, 290, 98, 80, 73},
+ {2550, 292, 98, 79, 72},
+ {2727, 294, 99, 81, 73},
+ {2904, 303, 100, 82, 75},
+ {3091, 323, 100, 81, 73},
+ {3278, 348, 100, 80, 73},
+ {3470, 376, 99, 79, 72},
+ {3627, 386, 100, 79, 72},
+ {3672, 398, 100, 80, 71},
+ {3812, 424, 100, 80, 73},
+ {3895, 443, 101, 80, 73},
+ {3985, 465, 102, 82, 75},
+ {4094, 497, 105, 83, 76},
+ {4211, 533, 109, 85, 79},
+ {4335, 579, 113, 87, 80},
+ {4505, 612, 113, 85, 76},
+ {4693, 643, 113, 86, 77},
+ {4930, 712, 120, 90, 81},
+ {5283, 835, 145, 111, 107},
+ {10293, 15765, 5566, 6904, 2547},
+ }
+};
+
+static struct pc_temp_ocv_lut pc_temp_ocv = {
+ .rows = 31,
+ .cols = 5,
+ .temp = {-20, 0, 25, 40, 60},
+ .percent = {100, 95, 90, 85, 80, 75, 70, 65, 60,
+ 55, 50, 45, 40, 35, 30, 25, 20, 16, 13,
+ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
+ .ocv = {
+ {4340, 4340, 4335, 4330, 4323},
+ {4217, 4260, 4265, 4263, 4258},
+ {4135, 4203, 4207, 4205, 4201},
+ {4084, 4150, 4152, 4150, 4146},
+ {3992, 4101, 4101, 4097, 4093},
+ {3934, 4049, 4051, 4046, 4044},
+ {3889, 3974, 3995, 3998, 3999},
+ {3852, 3926, 3958, 3961, 3959},
+ {3832, 3892, 3921, 3923, 3921},
+ {3819, 3859, 3874, 3877, 3877},
+ {3807, 3831, 3838, 3838, 3838},
+ {3796, 3809, 3815, 3815, 3814},
+ {3784, 3792, 3797, 3797, 3796},
+ {3770, 3780, 3783, 3782, 3781},
+ {3754, 3770, 3772, 3769, 3764},
+ {3737, 3758, 3763, 3754, 3742},
+ {3717, 3737, 3744, 3735, 3720},
+ {3700, 3713, 3718, 3710, 3696},
+ {3687, 3701, 3692, 3683, 3671},
+ {3674, 3695, 3689, 3681, 3669},
+ {3667, 3692, 3688, 3680, 3669},
+ {3659, 3690, 3687, 3680, 3668},
+ {3649, 3687, 3685, 3678, 3667},
+ {3636, 3683, 3683, 3676, 3664},
+ {3618, 3674, 3679, 3671, 3658},
+ {3596, 3652, 3663, 3652, 3632},
+ {3566, 3611, 3620, 3606, 3584},
+ {3522, 3547, 3555, 3540, 3517},
+ {3460, 3449, 3461, 3446, 3424},
+ {3356, 3282, 3312, 3299, 3273},
+ {3000, 3000, 3000, 3000, 3000}
+ }
+};
+
+
+struct bms_battery_data QRD_4v35_2000mAh_data = {
+ .fcc = 2000,
+ .fcc_temp_lut = &fcc_temp,
+ .fcc_sf_lut = &fcc_sf,
+ .pc_temp_ocv_lut = &pc_temp_ocv,
+ .rbatt_sf_lut = &rbatt_sf,
+ .default_rbatt_mohm = 172
+};
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index c20ba92..500c302 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -74,27 +74,6 @@
of_scan_flat_dt(dt_scan_for_memory_hole, apq8084_reserve_table);
}
-static struct clk_lookup msm_clocks_dummy[] = {
- CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
- CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
- CLK_DUMMY("core_clk", SDC1_CLK, "msm_sdcc.1", OFF),
- CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
- CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
- CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
- CLK_DUMMY("xo", NULL, "f9200000.qcom,ssusb", OFF),
- CLK_DUMMY("core_clk", NULL, "f9200000.qcom,ssusb", OFF),
- CLK_DUMMY("iface_clk", NULL, "f9200000.qcom,ssusb", OFF),
- CLK_DUMMY("sleep_clk", NULL, "f9200000.qcom,ssusb", OFF),
- CLK_DUMMY("sleep_a_clk", NULL, "f9200000.qcom,ssusb", OFF),
- CLK_DUMMY("utmi_clk", NULL, "f9200000.qcom,ssusb", OFF),
- CLK_DUMMY("ref_clk", NULL, "f9200000.qcom,ssusb", OFF),
-};
-
-static struct clock_init_data msm_dummy_clock_init_data __initdata = {
- .table = msm_clocks_dummy,
- .size = ARRAY_SIZE(msm_clocks_dummy),
-};
-
/*
* Used to satisfy dependencies for devices that need to be
* run early or in a particular order. Most likely your device doesn't fall
@@ -104,7 +83,7 @@
void __init apq8084_add_drivers(void)
{
msm_smd_init();
- msm_clock_init(&msm_dummy_clock_init_data);
+ msm_clock_init(&msm8084_clock_init_data);
}
static void __init apq8084_map_io(void)
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index 3da3e2d..cd95bf3 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -29,6 +29,7 @@
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <mach/clk-provider.h>
#include "board-dt.h"
#include "clock.h"
@@ -37,6 +38,11 @@
static struct clk_lookup msm_clocks_dummy[] = {
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+ CLK_DUMMY("core_clk", SDC1_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
+
};
struct clock_init_data mpq8092_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 819ca56..ad4a516 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -397,6 +397,49 @@
};
+static struct gpiomux_setting auxpcm_act_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting auxpcm_sus_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm_auxpcm_configs[] __initdata = {
+ {
+ .gpio = 63,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &auxpcm_act_cfg,
+ },
+ },
+ {
+ .gpio = 64,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &auxpcm_act_cfg,
+ },
+ },
+ {
+ .gpio = 65,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &auxpcm_act_cfg,
+ },
+ },
+ {
+ .gpio = 66,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &auxpcm_act_cfg,
+ },
+ },
+};
+
void __init msm8226_init_gpiomux(void)
{
int rc;
@@ -423,4 +466,6 @@
msm_gpiomux_install_nowrite(msm_lcd_configs,
ARRAY_SIZE(msm_lcd_configs));
msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
+ msm_gpiomux_install(msm_auxpcm_configs,
+ ARRAY_SIZE(msm_auxpcm_configs));
}
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 5d96389..cb88cdc 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1308,6 +1308,7 @@
.gpios = tsif_gpios,
.tsif_pclk = "tsif_pclk",
.tsif_ref_clk = "tsif_ref_clk",
+ .tsif_vreg_present = 0,
};
static struct platform_device msm_device_tspp = {
diff --git a/arch/arm/mach-msm/board-fsm9900-gpiomux.c b/arch/arm/mach-msm/board-fsm9900-gpiomux.c
new file mode 100644
index 0000000..dede706
--- /dev/null
+++ b/arch/arm/mach-msm/board-fsm9900-gpiomux.c
@@ -0,0 +1,29 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+
+void __init fsm9900_init_gpiomux(void)
+{
+ int rc;
+
+ rc = msm_gpiomux_init_dt();
+ if (rc) {
+ pr_err("%s failed %d\n", __func__, rc);
+ return;
+ }
+}
diff --git a/arch/arm/mach-msm/board-fsm9900.c b/arch/arm/mach-msm/board-fsm9900.c
new file mode 100644
index 0000000..7177355
--- /dev/null
+++ b/arch/arm/mach-msm/board-fsm9900.c
@@ -0,0 +1,102 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/memory.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_smd.h>
+#include <mach/restart.h>
+#include <mach/socinfo.h>
+#include <mach/clk-provider.h>
+#include "board-dt.h"
+#include "clock.h"
+#include "devices.h"
+#include "platsmp.h"
+
+void __init fsm9900_reserve(void)
+{
+}
+
+static void __init fsm9900_early_memory(void)
+{
+}
+
+static struct clk_lookup msm_clocks_dummy[] = {
+ CLK_DUMMY("core_clk", BLSP2_UART_CLK, "f9960000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP2_UART_CLK, "f9960000.serial", OFF),
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+};
+
+static struct clock_init_data msm_dummy_clock_init_data __initdata = {
+ .table = msm_clocks_dummy,
+ .size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init fsm9900_add_drivers(void)
+{
+ msm_smd_init();
+ msm_clock_init(&msm_dummy_clock_init_data);
+}
+
+static void __init fsm9900_map_io(void)
+{
+ msm_map_fsm9900_io();
+}
+
+void __init fsm9900_init(void)
+{
+ if (socinfo_init() < 0)
+ pr_err("%s: socinfo_init() failed\n", __func__);
+
+ fsm9900_init_gpiomux();
+ board_dt_populate(NULL);
+ fsm9900_add_drivers();
+}
+
+void __init fsm9900_init_very_early(void)
+{
+ fsm9900_early_memory();
+}
+
+static const char *fsm9900_dt_match[] __initconst = {
+ "qcom,fsm9900",
+ NULL
+};
+
+DT_MACHINE_START(FSM9900_DT, "Qualcomm FSM 9900 (Flattened Device Tree)")
+ .map_io = fsm9900_map_io,
+ .init_irq = msm_dt_init_irq,
+ .init_machine = fsm9900_init,
+ .handle_irq = gic_handle_irq,
+ .timer = &msm_dt_timer,
+ .dt_compat = fsm9900_dt_match,
+ .reserve = fsm9900_reserve,
+ .init_very_early = fsm9900_init_very_early,
+ .restart = msm_restart,
+ .smp = &msm8974_smp_ops,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-samarium-gpiomux.c b/arch/arm/mach-msm/board-samarium-gpiomux.c
new file mode 100644
index 0000000..645cb6f
--- /dev/null
+++ b/arch/arm/mach-msm/board-samarium-gpiomux.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+
+static struct gpiomux_setting gpio_uart_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_16MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_HIGH,
+};
+
+static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+ {
+ .gpio = 4, /* BLSP2 UART TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_uart_config,
+ },
+ },
+ {
+ .gpio = 5, /* BLSP2 UART RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_uart_config,
+ },
+ },
+};
+
+void __init msmsamarium_init_gpiomux(void)
+{
+ int rc;
+
+ rc = msm_gpiomux_init_dt();
+ if (rc) {
+ pr_err("%s failed %d\n", __func__, rc);
+ return;
+ }
+
+ msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+}
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
new file mode 100644
index 0000000..00d63a3
--- /dev/null
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -0,0 +1,90 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/memory.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_memtypes.h>
+#include <mach/restart.h>
+#include <mach/socinfo.h>
+#include <mach/clk-provider.h>
+#include "board-dt.h"
+#include "clock.h"
+#include "devices.h"
+#include "platsmp.h"
+
+static struct clk_lookup msm_clocks_dummy[] = {
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+};
+
+static struct clock_init_data msm_dummy_clock_init_data __initdata = {
+ .table = msm_clocks_dummy,
+ .size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+static struct of_dev_auxdata msmsamarium_auxdata_lookup[] __initdata = {
+ {},
+};
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msmsamarium_add_drivers(void)
+{
+ msm_clock_init(&msm_dummy_clock_init_data);
+}
+
+static void __init msmsamarium_map_io(void)
+{
+ msm_map_msmsamarium_io();
+}
+
+void __init msmsamarium_init(void)
+{
+ struct of_dev_auxdata *adata = msmsamarium_auxdata_lookup;
+
+ if (socinfo_init() < 0)
+ pr_err("%s: socinfo_init() failed\n", __func__);
+
+ msmsamarium_init_gpiomux();
+ board_dt_populate(adata);
+ msmsamarium_add_drivers();
+}
+
+static const char *msmsamarium_dt_match[] __initconst = {
+ "qcom,msmsamarium",
+ NULL
+};
+
+DT_MACHINE_START(MSMSAMARIUM_DT, "Qualcomm MSM Samarium(Flattened Device Tree)")
+ .map_io = msmsamarium_map_io,
+ .init_irq = msm_dt_init_irq,
+ .init_machine = msmsamarium_init,
+ .handle_irq = gic_handle_irq,
+ .timer = &msm_dt_timer,
+ .dt_compat = msmsamarium_dt_match,
+ .restart = msm_restart,
+ .smp = &msm8974_smp_ops,
+MACHINE_END
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
new file mode 100644
index 0000000..424b694
--- /dev/null
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -0,0 +1,351 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/regulator/consumer.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.h"
+
+/*
+ * TODO: Drivers need to fill in the clock names and device names for the clocks
+ * they need to control.
+ */
+static struct clk_lookup msm_clocks_8084[] = {
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("core_clk", SDC1_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
+ CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("iface_clk", SDC2_P_CLK, "msm_sdcc.2", OFF),
+ CLK_DUMMY("xo", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("core_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("iface_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("sleep_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("sleep_a_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("utmi_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("ref_clk", NULL, "f9200000.qcom,ssusb", OFF),
+ CLK_DUMMY("", ufs_axi_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb30_master_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb30_sec_master_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_ahb_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_asic0_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_pmalive_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_rx_clk_src.c, "", OFF),
+ CLK_DUMMY("", sata_rx_oob_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdcc1_apps_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdcc2_apps_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdcc3_apps_clk_src.c, "", OFF),
+ CLK_DUMMY("", sdcc4_apps_clk_src.c, "", OFF),
+ CLK_DUMMY("", tsif_ref_clk_src.c, "", OFF),
+ CLK_DUMMY("", ufs_rx_cfg_postdiv_clk_src.c, "", OFF),
+ CLK_DUMMY("", ufs_tx_cfg_postdiv_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb30_mock_utmi_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb30_sec_mock_utmi_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hs_system_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_io_cal_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_mock_utmi_clk_src.c, "", OFF),
+ CLK_DUMMY("", usb_hsic_system_clk_src.c, "", OFF),
+ CLK_DUMMY("", gcc_bam_dma_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_bam_dma_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup1_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup1_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup2_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup2_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup3_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup3_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup4_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup4_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup5_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup5_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup6_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_qup6_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart1_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart2_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart3_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart4_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart5_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp1_uart6_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup1_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup1_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup2_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup2_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup3_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup3_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup4_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup4_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup5_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup5_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup6_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_qup6_spi_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart1_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart2_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart3_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart4_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart5_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_blsp2_uart6_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_boot_rom_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce1_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce1_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce2_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce2_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce3_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce3_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ce3_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_copss_smmu_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_copss_smmu_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_dcd_xo_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_bimc_gfx_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_xo_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_xo_div4_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gp1_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gp2_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_gp3_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_lpass_mport_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_lpass_q6_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_lpass_sway_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_mmss_bimc_gfx_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_mmss_vpu_maple_sys_noc_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ocmem_noc_cfg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_msg_ram_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pdm2_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pdm_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_pdm_xo4_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_periph_noc_usb_hsic_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_prng_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_asic0_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_cfg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_pmalive_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_rx_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sata_rx_oob_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc1_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc1_cdccal_ff_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc1_cdccal_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc2_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc2_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc3_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc3_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc3_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc4_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc4_apps_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sdcc4_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_spss_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sys_noc_ufs_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sys_noc_usb3_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_sys_noc_usb3_sec_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_tsif_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_tsif_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_tsif_ref_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_axi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_rx_cfg_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_rx_symbol_0_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_rx_symbol_1_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_tx_cfg_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_tx_symbol_0_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_ufs_tx_symbol_1_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb2a_phy_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb2b_phy_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_master_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_mock_utmi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_sec_master_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_sec_mock_utmi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb30_sec_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hs_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hs_inactivity_timers_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hs_system_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_io_cal_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_io_cal_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_mock_utmi_clk.c, "", OFF),
+ CLK_DUMMY("", gcc_usb_hsic_system_clk.c, "", OFF),
+
+ CLK_DUMMY("", axi_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll0_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll1_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll2_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll3_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", mmpll4_pll_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi0_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi1_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi2_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi3_clk_src.c, "", OFF),
+ CLK_DUMMY("", vcodec0_clk_src.c, "", OFF),
+ CLK_DUMMY("", vfe0_clk_src.c, "", OFF),
+ CLK_DUMMY("", vfe1_clk_src.c, "", OFF),
+ CLK_DUMMY("", edppixel_clk_src.c, "", OFF),
+ CLK_DUMMY("", extpclk_clk_src.c, "", OFF),
+ CLK_DUMMY("", mdp_clk_src.c, "", OFF),
+ CLK_DUMMY("", pclk0_clk_src.c, "", OFF),
+ CLK_DUMMY("", pclk1_clk_src.c, "", OFF),
+ CLK_DUMMY("", ocmemnoc_clk_src.c, "", OFF),
+ CLK_DUMMY("", gfx3d_clk_src.c, "", OFF),
+ CLK_DUMMY("", vp_clk_src.c, "", OFF),
+ CLK_DUMMY("", cci_clk_src.c, "", OFF),
+ CLK_DUMMY("", gp0_clk_src.c, "", OFF),
+ CLK_DUMMY("", gp1_clk_src.c, "", OFF),
+ CLK_DUMMY("", jpeg0_clk_src.c, "", OFF),
+ CLK_DUMMY("", jpeg1_clk_src.c, "", OFF),
+ CLK_DUMMY("", jpeg2_clk_src.c, "", OFF),
+ CLK_DUMMY("", mclk0_clk_src.c, "", OFF),
+ CLK_DUMMY("", mclk1_clk_src.c, "", OFF),
+ CLK_DUMMY("", mclk2_clk_src.c, "", OFF),
+ CLK_DUMMY("", mclk3_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi0phytimer_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi1phytimer_clk_src.c, "", OFF),
+ CLK_DUMMY("", csi2phytimer_clk_src.c, "", OFF),
+ CLK_DUMMY("", cpp_clk_src.c, "", OFF),
+ CLK_DUMMY("", byte0_clk_src.c, "", OFF),
+ CLK_DUMMY("", byte1_clk_src.c, "", OFF),
+ CLK_DUMMY("", edpaux_clk_src.c, "", OFF),
+ CLK_DUMMY("", edplink_clk_src.c, "", OFF),
+ CLK_DUMMY("", esc0_clk_src.c, "", OFF),
+ CLK_DUMMY("", esc1_clk_src.c, "", OFF),
+ CLK_DUMMY("", hdmi_clk_src.c, "", OFF),
+ CLK_DUMMY("", vsync_clk_src.c, "", OFF),
+ CLK_DUMMY("", rbbmtimer_clk_src.c, "", OFF),
+ CLK_DUMMY("", maple_clk_src.c, "", OFF),
+ CLK_DUMMY("", vdp_clk_src.c, "", OFF),
+ CLK_DUMMY("", vpu_bus_clk_src.c, "", OFF),
+ CLK_DUMMY("", dsi0_phy_pll_out_byteclk.c, "", OFF),
+ CLK_DUMMY("", dsi0_phy_pll_out_dsiclk.c, "", OFF),
+ CLK_DUMMY("", dsi1_phy_pll_out_byteclk.c, "", OFF),
+ CLK_DUMMY("", dsi1_phy_pll_out_dsiclk.c, "", OFF),
+ CLK_DUMMY("", edpphy_cc_link_clk.c, "", OFF),
+ CLK_DUMMY("", edpphy_cc_vco_div_clk.c, "", OFF),
+ CLK_DUMMY("", hdmi_phy_pll_out.c, "", OFF),
+ CLK_DUMMY("", csiphy_bist_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_edppixel_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_extpclk_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_pclk0_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_pclk1_clk.c, "", OFF),
+ CLK_DUMMY("", avsync_vp_clk.c, "", OFF),
+ CLK_DUMMY("", camss_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_cci_cci_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_cci_cci_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi0_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi0phy_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi0pix_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi0rdi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi1phy_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi1pix_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi1rdi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi2_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi2_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi2phy_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi2pix_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi2rdi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi3_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi3_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi3phy_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi3pix_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi3rdi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi_vfe0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_csi_vfe1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_gp0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_gp1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_ispif_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg2_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_jpeg_jpeg_axi_clk.c, "", OFF),
+ CLK_DUMMY("", camss_mclk0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_mclk1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_mclk2_clk.c, "", OFF),
+ CLK_DUMMY("", camss_mclk3_clk.c, "", OFF),
+ CLK_DUMMY("", camss_micro_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_phy0_csi0phytimer_clk.c, "", OFF),
+ CLK_DUMMY("", camss_phy1_csi1phytimer_clk.c, "", OFF),
+ CLK_DUMMY("", camss_phy2_csi2phytimer_clk.c, "", OFF),
+ CLK_DUMMY("", camss_top_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_cpp_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_cpp_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_vfe0_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_vfe1_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_vfe_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", camss_vfe_vfe_axi_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_axi_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_byte0_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_byte1_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_edpaux_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_edplink_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_edppixel_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_esc0_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_esc1_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_extpclk_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_hdmi_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_hdmi_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_mdp_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_mdp_lut_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_pclk0_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_pclk1_clk.c, "", OFF),
+ CLK_DUMMY("", mdss_vsync_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_misc_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_mmssnoc_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_mmssnoc_axi_clk.c, "", OFF),
+ CLK_DUMMY("", mmss_s0_axi_clk.c, "", OFF),
+ CLK_DUMMY("", ocmemcx_ocmemnoc_clk.c, "", OFF),
+ CLK_DUMMY("", oxili_ocmemgx_clk.c, "", OFF),
+ CLK_DUMMY("", oxili_gfx3d_clk.c, "", OFF),
+ CLK_DUMMY("", oxili_rbbmtimer_clk.c, "", OFF),
+ CLK_DUMMY("", oxilicx_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_axi_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_core0_vcodec_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_core1_vcodec_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_ocmemnoc_clk.c, "", OFF),
+ CLK_DUMMY("", venus0_vcodec0_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_ahb_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_axi_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_bus_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_cxo_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_maple_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_sleep_clk.c, "", OFF),
+ CLK_DUMMY("", vpu_vdp_clk.c, "", OFF),
+};
+
+struct clock_init_data msm8084_clock_init_data __initdata = {
+ .table = msm_clocks_8084,
+ .size = ARRAY_SIZE(msm_clocks_8084),
+};
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 6212a4d..f3de05a 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -169,11 +169,11 @@
VDD_DIG_NUM
};
-static int *vdd_corner[] = {
- [VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
- [VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
- [VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_LOW */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_HIGH */
};
static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
@@ -2753,11 +2753,11 @@
VDD_SR2_PLL_NUM
};
-static int *vdd_sr2_levels[] = {
- [VDD_SR2_PLL_OFF] = VDD_UV(0, RPM_REGULATOR_CORNER_NONE),
- [VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
- [VDD_SR2_PLL_TUR] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_sr2_levels[] = {
+ 0, RPM_REGULATOR_CORNER_NONE, /* VDD_SR2_PLL_OFF */
+ 1800000, RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_SR2_PLL_SVS */
+ 1800000, RPM_REGULATOR_CORNER_NORMAL, /* VDD_SR2_PLL_NOM */
+ 1800000, RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_SR2_PLL_TUR */
};
static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
@@ -3123,6 +3123,7 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fd828018.hwevent"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -3156,6 +3157,9 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fd828018.hwevent"),
+
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fd828018.hwevent"),
/* HSUSB-OTG Clocks */
CLK_LOOKUP("xo", cxo_otg_clk.c, "f9a55000.usb"),
@@ -3323,31 +3327,40 @@
"fda0b000.qcom,csiphy"),
/* CSID clocks */
- CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
- "fda08000.qcom,csid"),
CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
- "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_clk", camss_csi0_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08000.qcom,csid"),
- CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08000.qcom,csid"),
+ "fda08000.qcom,csid"),
+ CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+ "fda08000.qcom,csid"),
+ 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("camss_top_ahb_clk", camss_top_ahb_clk.c,
- "fda08400.qcom,csid"),
+
CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
- "fda08400.qcom,csid"),
- CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi1_ahb_clk", camss_csi1_ahb_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi1_src_clk", csi1_clk_src.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi1_phy_clk", camss_csi1phy_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi1_pix_clk", camss_csi1pix_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c, "fda08400.qcom,csid"),
- CLK_LOOKUP("csi1_rdi_clk", camss_csi1rdi_clk.c, "fda08400.qcom,csid"),
+ "fda08400.qcom,csid"),
+ CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+ "fda08400.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"),
/* ISPIF clocks */
CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index aa9368d..340f1ef 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -434,11 +434,11 @@
VDD_DIG_NUM
};
-static int *vdd_corner[] = {
- [VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
- [VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
- [VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_LOW */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_HIGH */
};
static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
@@ -533,11 +533,11 @@
VDD_SR2_PLL_NUM
};
-static int *vdd_sr2_levels[] = {
- [VDD_SR2_PLL_OFF] = VDD_UV(0, RPM_REGULATOR_CORNER_NONE),
- [VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
- [VDD_SR2_PLL_TUR] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_sr2_levels[] = {
+ 0, RPM_REGULATOR_CORNER_NONE, /* VDD_SR2_PLL_OFF */
+ 1800000, RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_SR2_PLL_SVS */
+ 1800000, RPM_REGULATOR_CORNER_NORMAL, /* VDD_SR2_PLL_NOM */
+ 1800000, RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_SR2_PLL_TUR */
};
static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
@@ -2819,6 +2819,7 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc34d000.jtagmm"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc34e000.jtagmm"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc34f000.jtagmm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fd820018.hwevent"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc326000.tmc"),
@@ -2852,8 +2853,9 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34d000.jtagmm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34e000.jtagmm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34f000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fd820018.hwevent"),
-
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fd820018.hwevent"),
CLK_LOOKUP("core_clk_src", blsp1_qup1_spi_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", blsp1_qup2_spi_apps_clk_src.c, ""),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index ec94f00..4a16b42 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -638,11 +638,11 @@
VDD_DIG_NUM
};
-static int *vdd_corner[] = {
- [VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
- [VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
- [VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_LOW */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_HIGH */
};
static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 313e04c..3277d75 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -280,11 +280,11 @@
VDD_DIG_NUM
};
-static int *vdd_corner[] = {
- [VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
- [VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
- [VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
- [VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_LOW */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_HIGH */
};
static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
@@ -1924,6 +1924,7 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc333000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "f9011038.hwevent"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -1945,7 +1946,7 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc333000.cti"),
-
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "f9011038.hwevent"),
};
#define PLL_AUX_OUTPUT_BIT 1
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index bf95615..17a6801 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -409,9 +409,9 @@
static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
{
if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
- c->rate = 53000000;
- dsi_pll_rate = 53000000;
- pll_byte_clk_rate = 53000000;
+ c->rate = 52954560;
+ dsi_pll_rate = 52954560;
+ pll_byte_clk_rate = 52954560;
pll_pclk_rate = 105000000;
dsipll_refcount++;
return HANDOFF_ENABLED_CLK;
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index d2be1f9..8d99ad1 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,10 +19,10 @@
#include <mach/scm-io.h>
#include <mach/msm_iomap.h>
+#include <mach/msm_smem.h>
#include "clock.h"
#include "clock-pll.h"
-#include "smd_private.h"
#ifdef CONFIG_MSM_SECURE_IO
#undef readl_relaxed
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 08817c0..608018c 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -62,27 +62,31 @@
{
int level, rc = 0, i;
struct regulator **r = vdd_class->regulator;
- int **vdd_uv = vdd_class->vdd_uv;
- int **vdd_ua = vdd_class->vdd_ua;
- int max_level = vdd_class->num_levels - 1;
+ int *uv = vdd_class->vdd_uv;
+ int *ua = vdd_class->vdd_ua;
+ int n_reg = vdd_class->num_regulators;
+ int max_lvl = vdd_class->num_levels - 1;
+ int lvl_base;
- for (level = max_level; level > 0; level--)
+ for (level = max_lvl; level > 0; level--)
if (vdd_class->level_votes[level])
break;
if (level == vdd_class->cur_level)
return 0;
+ max_lvl = max_lvl * n_reg;
+ lvl_base = level * n_reg;
for (i = 0; i < vdd_class->num_regulators; i++) {
- rc = regulator_set_voltage(r[i], vdd_uv[level][i],
- vdd_uv[max_level][i]);
+ rc = regulator_set_voltage(r[i], uv[lvl_base + i],
+ uv[max_lvl + i]);
if (rc)
goto set_voltage_fail;
- if (!vdd_ua)
+ if (!ua)
continue;
- rc = regulator_set_optimum_mode(r[i], vdd_ua[level][i]);
+ rc = regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
if (rc < 0)
goto set_mode_fail;
}
@@ -95,18 +99,17 @@
return 0;
set_mode_fail:
- regulator_set_voltage(r[i], vdd_uv[vdd_class->cur_level][i],
- vdd_uv[max_level][i]);
+ regulator_set_voltage(r[i], uv[vdd_class->cur_level * n_reg + i],
+ uv[max_lvl + i]);
set_voltage_fail:
+ lvl_base = vdd_class->cur_level * n_reg;
for (i--; i >= 0; i--) {
- regulator_set_voltage(r[i], vdd_uv[vdd_class->cur_level][i],
- vdd_uv[max_level][i]);
+ regulator_set_voltage(r[i], uv[lvl_base + i], uv[max_lvl + i]);
- if (!vdd_ua)
+ if (!ua)
continue;
- regulator_set_optimum_mode(r[i],
- vdd_ua[vdd_class->cur_level][i]);
+ regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
}
return rc;
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 9ca1965..674ef77 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -53,6 +53,7 @@
extern struct clock_init_data msm8610_rumi_clock_init_data;
extern struct clock_init_data msm8226_clock_init_data;
extern struct clock_init_data msm8226_rumi_clock_init_data;
+extern struct clock_init_data msm8084_clock_init_data;
int msm_clock_init(struct clock_init_data *data);
int find_vdd_level(struct clk *clk, unsigned long rate);
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 08923e4..e51a1f5 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -24,26 +24,139 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/interrupt.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/cpr-regulator.h>
+/* Register Offsets for RB-CPR and Bit Definitions */
+
+/* RBCPR Gate Count and Target Registers */
+#define REG_RBCPR_GCNT_TARGET(n) (0x60 + 4 * n)
+
+#define RBCPR_GCNT_TARGET_GCNT_BITS 10
+#define RBCPR_GCNT_TARGET_GCNT_SHIFT 12
+#define RBCPR_GCNT_TARGET_GCNT_MASK ((1<<RBCPR_GCNT_TARGET_GCNT_BITS)-1)
+
+/* RBCPR Timer Control */
+#define REG_RBCPR_TIMER_INTERVAL 0x44
+#define REG_RBIF_TIMER_ADJUST 0x4C
+
+#define RBIF_TIMER_ADJ_CONS_UP_BITS 4
+#define RBIF_TIMER_ADJ_CONS_UP_MASK ((1<<RBIF_TIMER_ADJ_CONS_UP_BITS)-1)
+#define RBIF_TIMER_ADJ_CONS_DOWN_BITS 4
+#define RBIF_TIMER_ADJ_CONS_DOWN_MASK ((1<<RBIF_TIMER_ADJ_CONS_DOWN_BITS)-1)
+#define RBIF_TIMER_ADJ_CONS_DOWN_SHIFT 4
+
+/* RBCPR Config Register */
+#define REG_RBIF_LIMIT 0x48
+#define REG_RBCPR_STEP_QUOT 0x80
+#define REG_RBIF_SW_VLEVEL 0x94
+
+#define RBIF_LIMIT_CEILING_BITS 6
+#define RBIF_LIMIT_CEILING_MASK ((1<<RBIF_LIMIT_CEILING_BITS)-1)
+#define RBIF_LIMIT_CEILING_SHIFT 6
+#define RBIF_LIMIT_FLOOR_BITS 6
+#define RBIF_LIMIT_FLOOR_MASK ((1<<RBIF_LIMIT_FLOOR_BITS)-1)
+
+#define RBIF_LIMIT_CEILING_DEFAULT RBIF_LIMIT_CEILING_MASK
+#define RBIF_LIMIT_FLOOR_DEFAULT 0
+#define RBIF_SW_VLEVEL_DEFAULT 0x20
+
+#define RBCPR_STEP_QUOT_STEPQUOT_BITS 8
+#define RBCPR_STEP_QUOT_STEPQUOT_MASK ((1<<RBCPR_STEP_QUOT_STEPQUOT_BITS)-1)
+#define RBCPR_STEP_QUOT_IDLE_CLK_BITS 4
+#define RBCPR_STEP_QUOT_IDLE_CLK_MASK ((1<<RBCPR_STEP_QUOT_IDLE_CLK_BITS)-1)
+#define RBCPR_STEP_QUOT_IDLE_CLK_SHIFT 8
+
+/* RBCPR Control Register */
+#define REG_RBCPR_CTL 0x90
+
+#define RBCPR_CTL_LOOP_EN BIT(0)
+#define RBCPR_CTL_TIMER_EN BIT(3)
+#define RBCPR_CTL_SW_AUTO_CONT_ACK_EN BIT(5)
+#define RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN BIT(6)
+#define RBCPR_CTL_COUNT_MODE BIT(10)
+#define RBCPR_CTL_UP_THRESHOLD_BITS 4
+#define RBCPR_CTL_UP_THRESHOLD_MASK ((1<<RBCPR_CTL_UP_THRESHOLD_BITS)-1)
+#define RBCPR_CTL_UP_THRESHOLD_SHIFT 24
+#define RBCPR_CTL_DN_THRESHOLD_BITS 4
+#define RBCPR_CTL_DN_THRESHOLD_MASK ((1<<RBCPR_CTL_DN_THRESHOLD_BITS)-1)
+#define RBCPR_CTL_DN_THRESHOLD_SHIFT 28
+
+/* RBCPR Ack/Nack Response */
+#define REG_RBIF_CONT_ACK_CMD 0x98
+#define REG_RBIF_CONT_NACK_CMD 0x9C
+
+/* RBCPR Result status Register */
+#define REG_RBCPR_RESULT_0 0xA0
+
+#define RBCPR_RESULT0_ERROR_STEPS_SHIFT 2
+#define RBCPR_RESULT0_ERROR_STEPS_BITS 4
+#define RBCPR_RESULT0_ERROR_STEPS_MASK ((1<<RBCPR_RESULT0_ERROR_STEPS_BITS)-1)
+
+/* RBCPR Interrupt Control Register */
+#define REG_RBIF_IRQ_EN(n) (0x100 + 4 * n)
+#define REG_RBIF_IRQ_CLEAR 0x110
+#define REG_RBIF_IRQ_STATUS 0x114
+
+#define CPR_INT_DONE BIT(0)
+#define CPR_INT_MIN BIT(1)
+#define CPR_INT_DOWN BIT(2)
+#define CPR_INT_MID BIT(3)
+#define CPR_INT_UP BIT(4)
+#define CPR_INT_MAX BIT(5)
+#define CPR_INT_CLAMP BIT(6)
+#define CPR_INT_ALL (CPR_INT_DONE | CPR_INT_MIN | CPR_INT_DOWN | \
+ CPR_INT_MID | CPR_INT_UP | CPR_INT_MAX | CPR_INT_CLAMP)
+#define CPR_INT_DEFAULT (CPR_INT_UP | CPR_INT_DOWN)
+
+#define CPR_NUM_RING_OSC 8
+#define CPR_NUM_SAVE_REGS 10
+
+/* CPR eFuse parameters */
+#define CPR_FUSE_TARGET_QUOT_BITS 12
+#define CPR_FUSE_TARGET_QUOT_BITS_MASK ((1<<CPR_FUSE_TARGET_QUOT_BITS)-1)
+#define CPR_FUSE_RO_SEL_BITS 3
+#define CPR_FUSE_RO_SEL_BITS_MASK ((1<<CPR_FUSE_RO_SEL_BITS)-1)
+
+#define CPR_FUSE_TARGET_QUOT_TURBO_SHIFT 0
+#define CPR_FUSE_TARGET_QUOT_NOMINAL_SHIFT 12
+#define CPR_FUSE_TARGET_QUOT_SVS_SHIFT 24
+
+#define CPR_FUSE_DISABLE_CPR_SHIFT 36
+#define CPR_FUSE_LOCAL_APPROACH_SHIFT 37
+#define CPR_FUSE_REDUNDANT_SHIFT 57
+
+/* PVS eFuse parameters */
+#define PVS_FUSE_REDUNDANT_SHIFT 24
+#define PVS_FUSE_REDUNDANT_BITS 3
+#define PVS_FUSE_REDUNDANT_MASK ((1<<PVS_FUSE_REDUNDANT_BITS)-1)
+
+#define PVS_FUSE_BINS_SHIFT 6
+#define PVS_FUSE_BINS_REDUNDANT_SHIFT 27
+
+enum voltage_change_dir {
+ NO_CHANGE,
+ DOWN,
+ UP,
+};
+
struct cpr_regulator {
struct regulator_desc rdesc;
struct regulator_dev *rdev;
- bool enabled;
+ bool vreg_enabled;
int corner;
+ int ceiling_max;
/* Process voltage parameters */
- phys_addr_t efuse_phys;
+ phys_addr_t pvs_efuse;
u32 num_efuse_bits;
- u32 efuse_bit_pos[CPR_PVS_EFUSE_BITS_MAX];
u32 pvs_bin_process[CPR_PVS_EFUSE_BINS_MAX];
- u32 pvs_corner_ceiling[NUM_APC_PVS][CPR_CORNER_MAX];
+ u32 pvs_corner_v[NUM_APC_PVS][CPR_CORNER_MAX];
/* Process voltage variables */
u32 pvs_bin;
- u32 pvs_process;
- u32 *corner_ceiling;
+ u32 process;
/* APC voltage regulator */
struct regulator *vdd_apc;
@@ -53,13 +166,499 @@
int vdd_mx_vmax;
int vdd_mx_vmin_method;
int vdd_mx_vmin;
+
+ /* CPR parameters */
+ phys_addr_t cpr_fuse_addr;
+ u64 cpr_fuse_bits;
+ u64 cpr_fuse_bits_2;
+ bool cpr_fuse_disable;
+ bool cpr_fuse_local;
+ bool cpr_fuse_redundancy;
+ int cpr_fuse_target_quot[CPR_CORNER_MAX];
+ int cpr_fuse_ro_sel[CPR_CORNER_MAX];
+ int gcnt;
+
+ unsigned int cpr_irq;
+ void __iomem *rbcpr_base;
+ struct mutex cpr_mutex;
+
+ int ceiling_volt[CPR_CORNER_MAX];
+ int floor_volt[CPR_CORNER_MAX];
+ int last_volt[CPR_CORNER_MAX];
+ int step_volt;
+
+ int save_ctl[CPR_CORNER_MAX];
+ int save_irq[CPR_CORNER_MAX];
+
+ u32 save_regs[CPR_NUM_SAVE_REGS];
+ u32 save_reg_val[CPR_NUM_SAVE_REGS];
+
+ /* Config parameters */
+ bool enable;
+ u32 ref_clk_khz;
+ u32 timer_delay_us;
+ u32 timer_cons_up;
+ u32 timer_cons_down;
+ u32 irq_line;
+ u32 step_quotient;
+ u32 up_threshold;
+ u32 down_threshold;
+ u32 idle_clocks;
+ u32 gcnt_time_us;
+ u32 vdd_apc_step_up_limit;
+ u32 vdd_apc_step_down_limit;
};
+static int cpr_debug_enable;
+static int cpr_enable;
+static struct cpr_regulator *the_cpr;
+
+module_param_named(debug_enable, cpr_debug_enable, int, S_IRUGO | S_IWUSR);
+#define cpr_debug(message, ...) \
+ do { \
+ if (cpr_debug_enable) \
+ pr_info(message, ##__VA_ARGS__); \
+ } while (0)
+
+static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
+{
+ if (cpr_vreg->cpr_fuse_disable || !cpr_enable)
+ return false;
+ else
+ return true;
+}
+
+static void cpr_write(struct cpr_regulator *cpr_vreg, u32 offset, u32 value)
+{
+ writel_relaxed(value, cpr_vreg->rbcpr_base + offset);
+}
+
+static u32 cpr_read(struct cpr_regulator *cpr_vreg, u32 offset)
+{
+ return readl_relaxed(cpr_vreg->rbcpr_base + offset);
+}
+
+static void cpr_masked_write(struct cpr_regulator *cpr_vreg, u32 offset,
+ u32 mask, u32 value)
+{
+ u32 reg_val;
+
+ reg_val = readl_relaxed(cpr_vreg->rbcpr_base + offset);
+ reg_val &= ~mask;
+ reg_val |= value & mask;
+ writel_relaxed(reg_val, cpr_vreg->rbcpr_base + offset);
+}
+
+static void cpr_irq_clr(struct cpr_regulator *cpr_vreg)
+{
+ cpr_write(cpr_vreg, REG_RBIF_IRQ_CLEAR, CPR_INT_ALL);
+}
+
+static void cpr_irq_clr_nack(struct cpr_regulator *cpr_vreg)
+{
+ cpr_irq_clr(cpr_vreg);
+ cpr_write(cpr_vreg, REG_RBIF_CONT_NACK_CMD, 1);
+}
+
+static void cpr_irq_clr_ack(struct cpr_regulator *cpr_vreg)
+{
+ cpr_irq_clr(cpr_vreg);
+ cpr_write(cpr_vreg, REG_RBIF_CONT_ACK_CMD, 1);
+}
+
+static void cpr_irq_set(struct cpr_regulator *cpr_vreg, u32 int_bits)
+{
+ cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), int_bits);
+}
+
+static void cpr_ctl_modify(struct cpr_regulator *cpr_vreg, u32 mask, u32 value)
+{
+ cpr_masked_write(cpr_vreg, REG_RBCPR_CTL, mask, value);
+}
+
+static void cpr_ctl_enable(struct cpr_regulator *cpr_vreg)
+{
+ u32 val;
+
+ if (cpr_is_allowed(cpr_vreg))
+ val = RBCPR_CTL_LOOP_EN;
+ else
+ val = 0;
+ cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, val);
+}
+
+static void cpr_ctl_disable(struct cpr_regulator *cpr_vreg)
+{
+ cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0);
+}
+
+static void cpr_regs_save(struct cpr_regulator *cpr_vreg)
+{
+ int i, offset;
+
+ for (i = 0; i < CPR_NUM_SAVE_REGS; i++) {
+ offset = cpr_vreg->save_regs[i];
+ cpr_vreg->save_reg_val[i] = cpr_read(cpr_vreg, offset);
+ }
+}
+
+static void cpr_regs_restore(struct cpr_regulator *cpr_vreg)
+{
+ int i, offset;
+ u32 val;
+
+ for (i = 0; i < CPR_NUM_SAVE_REGS; i++) {
+ offset = cpr_vreg->save_regs[i];
+ val = cpr_vreg->save_reg_val[i];
+ cpr_write(cpr_vreg, offset, val);
+ }
+}
+
+static void cpr_corner_save(struct cpr_regulator *cpr_vreg, int corner)
+{
+ cpr_vreg->save_ctl[corner] = cpr_read(cpr_vreg, REG_RBCPR_CTL);
+ cpr_vreg->save_irq[corner] =
+ cpr_read(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line));
+}
+
+static void cpr_corner_restore(struct cpr_regulator *cpr_vreg, int corner)
+{
+ u32 gcnt, ctl, irq, ro_sel;
+
+ ro_sel = cpr_vreg->cpr_fuse_ro_sel[corner];
+ gcnt = cpr_vreg->gcnt | cpr_vreg->cpr_fuse_target_quot[corner];
+ cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(ro_sel), gcnt);
+ ctl = cpr_vreg->save_ctl[corner];
+ cpr_write(cpr_vreg, REG_RBCPR_CTL, ctl);
+ irq = cpr_vreg->save_irq[corner];
+ cpr_irq_set(cpr_vreg, irq);
+ cpr_debug("gcnt = 0x%08x, ctl = 0x%08x, irq = 0x%08x\n",
+ gcnt, ctl, irq);
+}
+
+static void cpr_corner_switch(struct cpr_regulator *cpr_vreg, int corner)
+{
+ if (cpr_vreg->corner == corner)
+ return;
+
+ cpr_corner_restore(cpr_vreg, corner);
+}
+
+/* Module parameter ops */
+static int cpr_enable_param_set(const char *val, const struct kernel_param *kp)
+{
+ int rc;
+ int old_cpr_enable;
+
+ if (!the_cpr) {
+ pr_err("the_cpr = NULL\n");
+ return -ENXIO;
+ }
+
+ mutex_lock(&the_cpr->cpr_mutex);
+
+ old_cpr_enable = cpr_enable;
+ rc = param_set_int(val, kp);
+ if (rc) {
+ pr_err("param_set_int: rc = %d\n", rc);
+ goto _exit;
+ }
+
+ cpr_debug("%d -> %d [corner=%d]\n",
+ old_cpr_enable, cpr_enable, the_cpr->corner);
+
+ if (the_cpr->cpr_fuse_disable) {
+ /* Already disabled */
+ pr_info("CPR disabled by fuse\n");
+ goto _exit;
+ }
+
+ if ((old_cpr_enable != cpr_enable) && the_cpr->corner) {
+ if (cpr_enable) {
+ cpr_ctl_disable(the_cpr);
+ cpr_irq_clr(the_cpr);
+ cpr_corner_restore(the_cpr, the_cpr->corner);
+ cpr_ctl_enable(the_cpr);
+ } else {
+ cpr_ctl_disable(the_cpr);
+ cpr_irq_set(the_cpr, 0);
+ }
+ }
+
+_exit:
+ mutex_unlock(&the_cpr->cpr_mutex);
+ return 0;
+}
+
+static struct kernel_param_ops cpr_enable_ops = {
+ .set = cpr_enable_param_set,
+ .get = param_get_int,
+};
+
+module_param_cb(cpr_enable, &cpr_enable_ops, &cpr_enable, S_IRUGO | S_IWUSR);
+
+static int cpr_apc_set(struct cpr_regulator *cpr_vreg, u32 new_volt)
+{
+ int max_volt, rc;
+
+ max_volt = cpr_vreg->ceiling_max;
+ rc = regulator_set_voltage(cpr_vreg->vdd_apc, new_volt, max_volt);
+ if (rc)
+ pr_err("set: vdd_apc = %d uV: rc=%d\n", new_volt, rc);
+ return rc;
+}
+
+static int cpr_mx_get(struct cpr_regulator *cpr_vreg, int corner, int apc_volt)
+{
+ int vdd_mx;
+
+ switch (cpr_vreg->vdd_mx_vmin_method) {
+ case VDD_MX_VMIN_APC:
+ vdd_mx = apc_volt;
+ break;
+ case VDD_MX_VMIN_APC_CORNER_CEILING:
+ vdd_mx = cpr_vreg->ceiling_volt[corner];
+ break;
+ case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
+ vdd_mx = cpr_vreg->pvs_corner_v[APC_PVS_SLOW]
+ [CPR_CORNER_TURBO];
+ break;
+ case VDD_MX_VMIN_MX_VMAX:
+ vdd_mx = cpr_vreg->vdd_mx_vmax;
+ break;
+ default:
+ vdd_mx = 0;
+ break;
+ }
+
+ return vdd_mx;
+}
+
+static int cpr_mx_set(struct cpr_regulator *cpr_vreg, int corner,
+ int vdd_mx_vmin)
+{
+ int rc;
+
+ rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
+ cpr_vreg->vdd_mx_vmax);
+ cpr_debug("[corner:%d] %d uV\n", corner, vdd_mx_vmin);
+ if (!rc)
+ cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
+ else
+ pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
+ corner, vdd_mx_vmin, rc);
+ return rc;
+}
+
+static int cpr_scale_voltage(struct cpr_regulator *cpr_vreg, int corner,
+ int new_apc_volt, enum voltage_change_dir dir)
+{
+ int rc = 0, vdd_mx_vmin = 0;
+
+ /* No MX scaling if no vdd_mx */
+ if (cpr_vreg->vdd_mx == NULL)
+ dir = NO_CHANGE;
+
+ if (dir != NO_CHANGE) {
+ /* Determine the vdd_mx voltage */
+ vdd_mx_vmin = cpr_mx_get(cpr_vreg, corner, new_apc_volt);
+ }
+
+ if (vdd_mx_vmin && dir == UP) {
+ if (vdd_mx_vmin != cpr_vreg->vdd_mx_vmin)
+ rc = cpr_mx_set(cpr_vreg, corner, vdd_mx_vmin);
+ }
+
+ if (!rc)
+ rc = cpr_apc_set(cpr_vreg, new_apc_volt);
+
+ if (!rc && vdd_mx_vmin && dir == DOWN) {
+ if (vdd_mx_vmin != cpr_vreg->vdd_mx_vmin)
+ rc = cpr_mx_set(cpr_vreg, corner, vdd_mx_vmin);
+ }
+
+ return rc;
+}
+
+static void cpr_scale(struct cpr_regulator *cpr_vreg,
+ enum voltage_change_dir dir)
+{
+ u32 reg_val, error_steps, reg_mask;
+ int last_volt, new_volt, corner;
+
+ corner = cpr_vreg->corner;
+
+ reg_val = cpr_read(cpr_vreg, REG_RBCPR_RESULT_0);
+
+ error_steps = (reg_val >> RBCPR_RESULT0_ERROR_STEPS_SHIFT)
+ & RBCPR_RESULT0_ERROR_STEPS_MASK;
+ last_volt = cpr_vreg->last_volt[corner];
+
+ cpr_debug("last_volt[corner:%d] = %d uV\n", corner, last_volt);
+
+ if (dir == UP) {
+ cpr_debug("Up: cpr status = 0x%08x (error_steps=%d)\n",
+ reg_val, error_steps);
+
+ if (last_volt >= cpr_vreg->ceiling_volt[corner]) {
+ cpr_debug("[corn:%d] @ ceiling: %d >= %d: NACK\n",
+ corner, last_volt,
+ cpr_vreg->ceiling_volt[corner]);
+ cpr_irq_clr_nack(cpr_vreg);
+
+ /* Maximize the UP threshold */
+ reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
+ RBCPR_CTL_UP_THRESHOLD_SHIFT;
+ reg_val = reg_mask;
+ cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+ return;
+ }
+
+ if (error_steps > cpr_vreg->vdd_apc_step_up_limit) {
+ cpr_debug("%d is over up-limit(%d): Clamp\n",
+ error_steps,
+ cpr_vreg->vdd_apc_step_up_limit);
+ error_steps = cpr_vreg->vdd_apc_step_up_limit;
+ }
+
+ /* Calculate new voltage */
+ new_volt = last_volt + (error_steps * cpr_vreg->step_volt);
+ if (new_volt > cpr_vreg->ceiling_volt[corner]) {
+ cpr_debug("new_volt(%d) >= ceiling_volt(%d): Clamp\n",
+ new_volt, cpr_vreg->ceiling_volt[corner]);
+ new_volt = cpr_vreg->ceiling_volt[corner];
+ }
+
+ if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
+ cpr_irq_clr_nack(cpr_vreg);
+ return;
+ }
+ cpr_vreg->last_volt[corner] = new_volt;
+
+ /* Restore default threshold for DOWN */
+ reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
+ RBCPR_CTL_DN_THRESHOLD_SHIFT;
+ reg_val = cpr_vreg->down_threshold <<
+ RBCPR_CTL_DN_THRESHOLD_SHIFT;
+ /* and disable auto nack down */
+ reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+
+ cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+
+ /* Re-enable default interrupts */
+ cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
+
+ /* Ack */
+ cpr_irq_clr_ack(cpr_vreg);
+
+ cpr_debug("UP: -> new_volt = %d uV\n", new_volt);
+ } else if (dir == DOWN) {
+ cpr_debug("Down: cpr status = 0x%08x (error_steps=%d)\n",
+ reg_val, error_steps);
+
+ if (last_volt <= cpr_vreg->floor_volt[corner]) {
+ cpr_debug("[corn:%d] @ floor: %d <= %d: NACK\n",
+ corner, last_volt,
+ cpr_vreg->floor_volt[corner]);
+ cpr_irq_clr_nack(cpr_vreg);
+
+ /* Maximize the DOWN threshold */
+ reg_mask = RBCPR_CTL_DN_THRESHOLD_MASK <<
+ RBCPR_CTL_DN_THRESHOLD_SHIFT;
+ reg_val = reg_mask;
+
+ /* Enable auto nack down */
+ reg_mask |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+ reg_val |= RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+
+ cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+
+ /* Disable DOWN interrupt */
+ cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT & ~CPR_INT_DOWN);
+
+ return;
+ }
+
+ if (error_steps > cpr_vreg->vdd_apc_step_down_limit) {
+ cpr_debug("%d is over down-limit(%d): Clamp\n",
+ error_steps,
+ cpr_vreg->vdd_apc_step_down_limit);
+ error_steps = cpr_vreg->vdd_apc_step_down_limit;
+ }
+
+ /* Calculte new voltage */
+ new_volt = last_volt - (error_steps * cpr_vreg->step_volt);
+ if (new_volt < cpr_vreg->floor_volt[corner]) {
+ cpr_debug("new_volt(%d) < floor_volt(%d): Clamp\n",
+ new_volt, cpr_vreg->floor_volt[corner]);
+ new_volt = cpr_vreg->floor_volt[corner];
+ }
+
+ if (cpr_scale_voltage(cpr_vreg, corner, new_volt, dir)) {
+ cpr_irq_clr_nack(cpr_vreg);
+ return;
+ }
+ cpr_vreg->last_volt[corner] = new_volt;
+
+ /* Restore default threshold for UP */
+ reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK <<
+ RBCPR_CTL_UP_THRESHOLD_SHIFT;
+ reg_val = cpr_vreg->up_threshold <<
+ RBCPR_CTL_UP_THRESHOLD_SHIFT;
+ cpr_ctl_modify(cpr_vreg, reg_mask, reg_val);
+
+ /* Ack */
+ cpr_irq_clr_ack(cpr_vreg);
+
+ cpr_debug("DOWN: -> new_volt = %d uV\n", new_volt);
+ }
+}
+
+static irqreturn_t cpr_irq_handler(int irq, void *dev)
+{
+ struct cpr_regulator *cpr_vreg = dev;
+ u32 reg_val;
+
+ mutex_lock(&cpr_vreg->cpr_mutex);
+
+ reg_val = cpr_read(cpr_vreg, REG_RBIF_IRQ_STATUS);
+ cpr_debug("IRQ_STATUS = 0x%02X\n", reg_val);
+
+ if (!cpr_is_allowed(cpr_vreg)) {
+ reg_val = cpr_read(cpr_vreg, REG_RBCPR_CTL);
+ pr_err("Interrupt broken? RBCPR_CTL = 0x%02X\n", reg_val);
+ goto _exit;
+ }
+
+ /* Following sequence of handling is as per each IRQ's priority */
+ if (reg_val & CPR_INT_UP) {
+ cpr_scale(cpr_vreg, UP);
+ } else if (reg_val & CPR_INT_DOWN) {
+ cpr_scale(cpr_vreg, DOWN);
+ } else if (reg_val & CPR_INT_MIN) {
+ cpr_irq_clr_nack(cpr_vreg);
+ } else if (reg_val & CPR_INT_MAX) {
+ cpr_irq_clr_nack(cpr_vreg);
+ } else if (reg_val & CPR_INT_MID) {
+ /* RBCPR_CTL_SW_AUTO_CONT_ACK_EN is enabled */
+ cpr_debug("IRQ occured for Mid Flag\n");
+ } else {
+ pr_err("IRQ occured for unknown flag (0x%08x)\n", reg_val);
+ }
+
+ /* Save register values for the corner */
+ cpr_corner_save(cpr_vreg, cpr_vreg->corner);
+
+_exit:
+ mutex_unlock(&cpr_vreg->cpr_mutex);
+ return IRQ_HANDLED;
+}
+
static int cpr_regulator_is_enabled(struct regulator_dev *rdev)
{
struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
- return cpr_vreg->enabled;
+ return cpr_vreg->vreg_enabled;
}
static int cpr_regulator_enable(struct regulator_dev *rdev)
@@ -78,7 +677,7 @@
rc = regulator_enable(cpr_vreg->vdd_apc);
if (!rc)
- cpr_vreg->enabled = true;
+ cpr_vreg->vreg_enabled = true;
else
pr_err("regulator_enable: vdd_apc: rc=%d\n", rc);
@@ -98,7 +697,7 @@
if (rc)
pr_err("regulator_disable: vdd_mx: rc=%d\n", rc);
else
- cpr_vreg->enabled = false;
+ cpr_vreg->vreg_enabled = false;
} else {
pr_err("regulator_disable: vdd_apc: rc=%d\n", rc);
}
@@ -107,90 +706,44 @@
}
static int cpr_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int corner, int corner_max, unsigned *selector)
{
struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev);
int rc;
- int vdd_apc_min, vdd_apc_max, vdd_mx_vmin = 0;
- int change_dir = 0;
+ int new_volt;
+ enum voltage_change_dir change_dir = NO_CHANGE;
- if (cpr_vreg->vdd_mx) {
- if (min_uV > cpr_vreg->corner)
- change_dir = 1;
- else if (min_uV < cpr_vreg->corner)
- change_dir = -1;
- }
+ mutex_lock(&cpr_vreg->cpr_mutex);
- vdd_apc_min = cpr_vreg->corner_ceiling[min_uV];
- vdd_apc_max = cpr_vreg->corner_ceiling[CPR_CORNER_SUPER_TURBO];
-
- if (change_dir) {
- /* Determine the vdd_mx voltage */
- switch (cpr_vreg->vdd_mx_vmin_method) {
- case VDD_MX_VMIN_APC:
- vdd_mx_vmin = vdd_apc_min;
- break;
- case VDD_MX_VMIN_APC_CORNER_CEILING:
- vdd_mx_vmin = vdd_apc_min;
- break;
- case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
- vdd_mx_vmin = cpr_vreg->pvs_corner_ceiling
- [APC_PVS_SLOW][min_uV];
- break;
- case VDD_MX_VMIN_MX_VMAX:
- default:
- vdd_mx_vmin = cpr_vreg->vdd_mx_vmax;
- break;
- }
- }
-
- if (change_dir > 0) {
- if (vdd_mx_vmin < cpr_vreg->vdd_mx_vmin) {
- /* Check and report the value in case */
- pr_err("Up: but new %d < old %d uV\n", vdd_mx_vmin,
- cpr_vreg->vdd_mx_vmin);
- }
-
- rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
- cpr_vreg->vdd_mx_vmax);
- if (!rc) {
- cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
- } else {
- pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
- min_uV, vdd_mx_vmin, rc);
- return rc;
- }
- }
-
- rc = regulator_set_voltage(cpr_vreg->vdd_apc,
- vdd_apc_min, vdd_apc_max);
- if (!rc) {
- cpr_vreg->corner = min_uV;
+ if (cpr_is_allowed(cpr_vreg)) {
+ cpr_ctl_disable(cpr_vreg);
+ new_volt = cpr_vreg->last_volt[corner];
} else {
- pr_err("set: vdd_apc [%d] = %d uV: rc=%d\n",
- min_uV, vdd_apc_min, rc);
- return rc;
+ new_volt = cpr_vreg->pvs_corner_v[cpr_vreg->process][corner];
}
- if (change_dir < 0) {
- if (vdd_mx_vmin > cpr_vreg->vdd_mx_vmin) {
- /* Check and report the value in case */
- pr_err("Down: but new %d >= old %d uV\n", vdd_mx_vmin,
- cpr_vreg->vdd_mx_vmin);
- }
+ cpr_debug("[corner:%d] = %d uV\n", corner, new_volt);
- rc = regulator_set_voltage(cpr_vreg->vdd_mx, vdd_mx_vmin,
- cpr_vreg->vdd_mx_vmax);
- if (!rc) {
- cpr_vreg->vdd_mx_vmin = vdd_mx_vmin;
- } else {
- pr_err("set: vdd_mx [%d] = %d uV: rc=%d\n",
- min_uV, vdd_mx_vmin, rc);
- return rc;
- }
+ if (corner > cpr_vreg->corner)
+ change_dir = UP;
+ else if (corner < cpr_vreg->corner)
+ change_dir = DOWN;
+
+ rc = cpr_scale_voltage(cpr_vreg, corner, new_volt, change_dir);
+ if (rc)
+ goto _exit;
+
+ if (cpr_is_allowed(cpr_vreg)) {
+ cpr_irq_clr(cpr_vreg);
+ cpr_corner_switch(cpr_vreg, corner);
+ cpr_ctl_enable(cpr_vreg);
}
- pr_debug("set [corner:%d] = %d uV: rc=%d\n", min_uV, vdd_apc_min, rc);
+ cpr_vreg->corner = corner;
+
+_exit:
+ mutex_unlock(&cpr_vreg->cpr_mutex);
+
return rc;
}
@@ -209,56 +762,202 @@
.get_voltage = cpr_regulator_get_voltage,
};
-static int __init cpr_regulator_pvs_init(struct cpr_regulator *cpr_vreg)
+#ifdef CONFIG_PM
+static int cpr_suspend(struct cpr_regulator *cpr_vreg)
+{
+ cpr_debug("suspend\n");
+
+ cpr_ctl_disable(cpr_vreg);
+ disable_irq(cpr_vreg->cpr_irq);
+
+ cpr_irq_clr(cpr_vreg);
+ cpr_regs_save(cpr_vreg);
+
+ return 0;
+}
+
+static int cpr_resume(struct cpr_regulator *cpr_vreg)
+
+{
+ cpr_debug("resume\n");
+
+ cpr_regs_restore(cpr_vreg);
+ cpr_irq_clr(cpr_vreg);
+
+ enable_irq(cpr_vreg->cpr_irq);
+ cpr_ctl_enable(cpr_vreg);
+
+ return 0;
+}
+
+static int cpr_regulator_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct cpr_regulator *cpr_vreg = platform_get_drvdata(pdev);
+
+ if (cpr_is_allowed(cpr_vreg))
+ return cpr_suspend(cpr_vreg);
+ else
+ return 0;
+}
+
+static int cpr_regulator_resume(struct platform_device *pdev)
+{
+ struct cpr_regulator *cpr_vreg = platform_get_drvdata(pdev);
+
+ if (cpr_is_allowed(cpr_vreg))
+ return cpr_resume(cpr_vreg);
+ else
+ return 0;
+}
+#else
+#define cpr_regulator_suspend NULL
+#define cpr_regulator_resume NULL
+#endif
+
+static void cpr_config(struct cpr_regulator *cpr_vreg)
+{
+ int i;
+ u32 val, gcnt;
+
+ /* Disable interrupt and CPR */
+ cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), 0);
+ cpr_write(cpr_vreg, REG_RBCPR_CTL, 0);
+
+ /* Program the default HW Ceiling, Floor and vlevel */
+ val = ((RBIF_LIMIT_CEILING_DEFAULT & RBIF_LIMIT_CEILING_MASK)
+ << RBIF_LIMIT_CEILING_SHIFT)
+ | (RBIF_LIMIT_FLOOR_DEFAULT & RBIF_LIMIT_FLOOR_MASK);
+ cpr_write(cpr_vreg, REG_RBIF_LIMIT, val);
+ cpr_write(cpr_vreg, REG_RBIF_SW_VLEVEL, RBIF_SW_VLEVEL_DEFAULT);
+
+ /* Clear the target quotient value and gate count of all ROs */
+ for (i = 0; i < CPR_NUM_RING_OSC; i++)
+ cpr_write(cpr_vreg, REG_RBCPR_GCNT_TARGET(i), 0);
+
+ /* Init and save gcnt */
+ gcnt = (cpr_vreg->ref_clk_khz * cpr_vreg->gcnt_time_us) / 1000;
+ gcnt = (gcnt & RBCPR_GCNT_TARGET_GCNT_MASK) <<
+ RBCPR_GCNT_TARGET_GCNT_SHIFT;
+ cpr_vreg->gcnt = gcnt;
+
+ /* Program the step quotient and idle clocks */
+ val = ((cpr_vreg->idle_clocks & RBCPR_STEP_QUOT_IDLE_CLK_MASK)
+ << RBCPR_STEP_QUOT_IDLE_CLK_SHIFT) |
+ (cpr_vreg->step_quotient & RBCPR_STEP_QUOT_STEPQUOT_MASK);
+ cpr_write(cpr_vreg, REG_RBCPR_STEP_QUOT, val);
+
+ /* Program the delay count for the timer */
+ val = (cpr_vreg->ref_clk_khz * cpr_vreg->timer_delay_us) / 1000;
+ cpr_write(cpr_vreg, REG_RBCPR_TIMER_INTERVAL, val);
+ pr_info("Timer count: 0x%0x (for %d us)\n", val,
+ cpr_vreg->timer_delay_us);
+
+ /* Program Consecutive Up & Down */
+ val = ((cpr_vreg->timer_cons_down & RBIF_TIMER_ADJ_CONS_DOWN_MASK)
+ << RBIF_TIMER_ADJ_CONS_DOWN_SHIFT) |
+ (cpr_vreg->timer_cons_up & RBIF_TIMER_ADJ_CONS_UP_MASK);
+ cpr_write(cpr_vreg, REG_RBIF_TIMER_ADJUST, val);
+
+ /* Program the control register */
+ cpr_vreg->up_threshold &= RBCPR_CTL_UP_THRESHOLD_MASK;
+ cpr_vreg->down_threshold &= RBCPR_CTL_DN_THRESHOLD_MASK;
+ val = (cpr_vreg->up_threshold << RBCPR_CTL_UP_THRESHOLD_SHIFT)
+ | (cpr_vreg->down_threshold << RBCPR_CTL_DN_THRESHOLD_SHIFT);
+ val |= RBCPR_CTL_TIMER_EN | RBCPR_CTL_COUNT_MODE;
+ val |= RBCPR_CTL_SW_AUTO_CONT_ACK_EN;
+ cpr_write(cpr_vreg, REG_RBCPR_CTL, val);
+
+ /* Registers to save & restore for suspend */
+ cpr_vreg->save_regs[0] = REG_RBCPR_TIMER_INTERVAL;
+ cpr_vreg->save_regs[1] = REG_RBCPR_STEP_QUOT;
+ cpr_vreg->save_regs[2] = REG_RBIF_TIMER_ADJUST;
+ cpr_vreg->save_regs[3] = REG_RBIF_LIMIT;
+ cpr_vreg->save_regs[4] = REG_RBIF_SW_VLEVEL;
+ cpr_vreg->save_regs[5] = REG_RBIF_IRQ_EN(cpr_vreg->irq_line);
+ cpr_vreg->save_regs[6] = REG_RBCPR_CTL;
+ cpr_vreg->save_regs[7] = REG_RBCPR_GCNT_TARGET
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS]);
+ cpr_vreg->save_regs[8] = REG_RBCPR_GCNT_TARGET
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL]);
+ cpr_vreg->save_regs[9] = REG_RBCPR_GCNT_TARGET
+ (cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO]);
+
+ cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
+
+ cpr_corner_save(cpr_vreg, CPR_CORNER_SVS);
+ cpr_corner_save(cpr_vreg, CPR_CORNER_NORMAL);
+ cpr_corner_save(cpr_vreg, CPR_CORNER_TURBO);
+}
+
+static int __init cpr_pvs_init(struct cpr_regulator *cpr_vreg)
{
void __iomem *efuse_base;
- u32 efuse_bits;
- int i, bit_pos;
- u32 vmax;
+ u32 efuse_bits, redundant, shift, mask;
+ int i, process;
- efuse_base = ioremap(cpr_vreg->efuse_phys, 4);
+ efuse_base = ioremap(cpr_vreg->pvs_efuse, 4);
if (!efuse_base) {
- pr_err("Unable to map efuse_phys 0x%x\n",
- cpr_vreg->efuse_phys);
+ pr_err("Unable to map pvs_efuse 0x%08x\n",
+ cpr_vreg->pvs_efuse);
return -EINVAL;
}
efuse_bits = readl_relaxed(efuse_base);
/* Construct PVS process # from the efuse bits */
- for (i = 0; i < cpr_vreg->num_efuse_bits; i++) {
- bit_pos = cpr_vreg->efuse_bit_pos[i];
- cpr_vreg->pvs_bin |= (efuse_bits & BIT(bit_pos)) ? BIT(i) : 0;
- }
+ redundant = (efuse_bits >> PVS_FUSE_REDUNDANT_SHIFT)
+ & PVS_FUSE_REDUNDANT_MASK;
+ if (redundant == 2)
+ shift = PVS_FUSE_BINS_REDUNDANT_SHIFT;
+ else
+ shift = PVS_FUSE_BINS_SHIFT;
+ mask = (1 << cpr_vreg->num_efuse_bits) - 1;
+ cpr_vreg->pvs_bin = (efuse_bits >> shift) & mask;
- cpr_vreg->pvs_process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
- if (cpr_vreg->pvs_process >= NUM_APC_PVS)
- cpr_vreg->pvs_process = APC_PVS_NO;
-
- /* Use ceiling voltage of Turbo@Slow for all corners of APC_PVS_NO
- but use SuperTurbo@Slow for its SuperTurbo */
- vmax = cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW][CPR_CORNER_TURBO];
- for (i = CPR_CORNER_SVS; i <= CPR_CORNER_TURBO; i++)
- cpr_vreg->pvs_corner_ceiling[APC_PVS_NO][i] = vmax;
- cpr_vreg->pvs_corner_ceiling[APC_PVS_NO][CPR_CORNER_SUPER_TURBO]
- = cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW]
- [CPR_CORNER_SUPER_TURBO];
-
- cpr_vreg->corner_ceiling =
- cpr_vreg->pvs_corner_ceiling[cpr_vreg->pvs_process];
+ /* Set ceiling max and use it for APC_PVS_NO */
+ cpr_vreg->ceiling_max =
+ cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_TURBO];
iounmap(efuse_base);
- pr_info("PVS Info: efuse_phys=0x%08X, n_bits=%d\n",
- cpr_vreg->efuse_phys, cpr_vreg->num_efuse_bits);
- pr_info("PVS Info: efuse=0x%08X, bin=%d, process=%d\n",
- efuse_bits, cpr_vreg->pvs_bin, cpr_vreg->pvs_process);
+ process = cpr_vreg->pvs_bin_process[cpr_vreg->pvs_bin];
+ pr_info("[0x%08X] = 0x%08X, n_bits=%d, bin=%d (%d) [redundant=%d]\n",
+ cpr_vreg->pvs_efuse, efuse_bits, cpr_vreg->num_efuse_bits,
+ cpr_vreg->pvs_bin, process, redundant);
+ for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++) {
+ pr_info("[%d] [%d %d %d] uV\n", i,
+ cpr_vreg->pvs_corner_v[i][CPR_CORNER_SVS],
+ cpr_vreg->pvs_corner_v[i][CPR_CORNER_NORMAL],
+ cpr_vreg->pvs_corner_v[i][CPR_CORNER_TURBO]);
+ }
+
+ if (process == APC_PVS_NO || process >= NUM_APC_PVS) {
+ pr_err("Bin=%d (%d) is out of spec. Assume SLOW.\n",
+ cpr_vreg->pvs_bin, process);
+ process = APC_PVS_SLOW;
+ }
+
+ cpr_vreg->process = process;
return 0;
}
-static int __init cpr_regulator_apc_init(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
+#define CPR_PROP_READ_U32(of_node, cpr_property, cpr_config, rc) \
+do { \
+ if (!rc) { \
+ rc = of_property_read_u32(of_node, \
+ "qcom," cpr_property, \
+ cpr_config); \
+ if (rc) { \
+ pr_err("Missing " #cpr_property \
+ ": rc = %d\n", rc); \
+ } \
+ } \
+} while (0)
+
+static int __init cpr_apc_init(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
int rc;
@@ -308,9 +1007,9 @@
return 0;
}
-static void cpr_regulator_apc_exit(struct cpr_regulator *cpr_vreg)
+static void cpr_apc_exit(struct cpr_regulator *cpr_vreg)
{
- if (cpr_vreg->enabled) {
+ if (cpr_vreg->vreg_enabled) {
regulator_disable(cpr_vreg->vdd_apc);
if (cpr_vreg->vdd_mx)
@@ -318,8 +1017,231 @@
}
}
-static int __init cpr_regulator_parse_dt(struct platform_device *pdev,
- struct cpr_regulator *cpr_vreg)
+static int __init cpr_init_cpr_efuse(struct cpr_regulator *cpr_vreg)
+{
+ void __iomem *efuse_base;
+ u32 ro_sel, val;
+ u64 fuse_bits;
+ int ro_sel_shift[CPR_CORNER_MAX];
+
+ efuse_base = ioremap(cpr_vreg->cpr_fuse_addr, 16);
+ if (!efuse_base) {
+ pr_err("Unable to map cpr_fuse_addr 0x%08x\n",
+ cpr_vreg->cpr_fuse_addr);
+ return -EINVAL;
+ }
+
+ cpr_vreg->cpr_fuse_bits = readll_relaxed(efuse_base);
+ cpr_vreg->cpr_fuse_bits_2 = readll_relaxed(efuse_base + 8);
+
+ iounmap(efuse_base);
+
+ /* Read the control bits of eFuse */
+ cpr_vreg->cpr_fuse_disable = (cpr_vreg->cpr_fuse_bits >>
+ CPR_FUSE_DISABLE_CPR_SHIFT) & 0x01;
+ cpr_vreg->cpr_fuse_local = (cpr_vreg->cpr_fuse_bits >>
+ CPR_FUSE_LOCAL_APPROACH_SHIFT) & 0x01;
+ cpr_vreg->cpr_fuse_redundancy = (cpr_vreg->cpr_fuse_bits >>
+ CPR_FUSE_REDUNDANT_SHIFT) & 0x01;
+
+ pr_info("[0x%08X] = 0x%llx\n", cpr_vreg->cpr_fuse_addr,
+ cpr_vreg->cpr_fuse_bits);
+ pr_info("disable = %d, local = %d, redundancy = %d\n",
+ cpr_vreg->cpr_fuse_disable,
+ cpr_vreg->cpr_fuse_local,
+ cpr_vreg->cpr_fuse_redundancy);
+ pr_info("[0x%08X] = 0x%llx\n", cpr_vreg->cpr_fuse_addr + 8,
+ cpr_vreg->cpr_fuse_bits_2);
+
+ if (cpr_vreg->cpr_fuse_redundancy == 0) {
+ fuse_bits = cpr_vreg->cpr_fuse_bits;
+ ro_sel_shift[CPR_CORNER_SVS] = 54;
+ ro_sel_shift[CPR_CORNER_NORMAL] = 38;
+ ro_sel_shift[CPR_CORNER_TURBO] = 41;
+ } else {
+ fuse_bits = cpr_vreg->cpr_fuse_bits_2;
+ ro_sel_shift[CPR_CORNER_SVS] = 46;
+ ro_sel_shift[CPR_CORNER_NORMAL] = 36;
+ ro_sel_shift[CPR_CORNER_TURBO] = 39;
+ }
+
+ /* SVS */
+ ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_SVS])
+ & CPR_FUSE_RO_SEL_BITS_MASK;
+ val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_SVS_SHIFT)
+ & CPR_FUSE_TARGET_QUOT_BITS_MASK;
+ cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_SVS] = val;
+ cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_SVS] = ro_sel;
+ pr_info("SVS: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+
+ /* Nominal */
+ ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_NORMAL])
+ & CPR_FUSE_RO_SEL_BITS_MASK;
+ val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_NOMINAL_SHIFT)
+ & CPR_FUSE_TARGET_QUOT_BITS_MASK;
+ cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_NORMAL] = val;
+ cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_NORMAL] = ro_sel;
+ pr_info("Nominal: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+
+ /* Turbo */
+ ro_sel = (fuse_bits >> ro_sel_shift[CPR_CORNER_TURBO])
+ & CPR_FUSE_RO_SEL_BITS_MASK;
+ val = (fuse_bits >> CPR_FUSE_TARGET_QUOT_TURBO_SHIFT)
+ & CPR_FUSE_TARGET_QUOT_BITS_MASK;
+ cpr_vreg->cpr_fuse_target_quot[CPR_CORNER_TURBO] = val;
+ cpr_vreg->cpr_fuse_ro_sel[CPR_CORNER_TURBO] = ro_sel;
+ pr_info("Turbo: ro_sel = %d, target quot = 0x%04x\n", ro_sel, val);
+
+ if (!cpr_vreg->cpr_fuse_bits) {
+ cpr_vreg->cpr_fuse_disable = 1;
+ pr_err("cpr_fuse_bits = 0: set cpr_fuse_disable = 1\n");
+ }
+
+ return 0;
+}
+
+static int __init cpr_init_cpr_voltages(struct cpr_regulator *cpr_vreg)
+{
+ int i;
+
+ /* Construct CPR voltage limits */
+ for (i = CPR_CORNER_SVS; i < CPR_CORNER_MAX; i++) {
+ cpr_vreg->floor_volt[i] =
+ cpr_vreg->pvs_corner_v[APC_PVS_FAST][i];
+ cpr_vreg->ceiling_volt[i] =
+ cpr_vreg->pvs_corner_v[APC_PVS_SLOW][i];
+ cpr_vreg->last_volt[i] =
+ cpr_vreg->pvs_corner_v[cpr_vreg->process][i];
+ }
+
+ return 0;
+}
+
+static int __init cpr_init_cpr_parameters(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
+{
+ struct device_node *of_node = pdev->dev.of_node;
+ int rc = 0;
+
+ CPR_PROP_READ_U32(of_node, "cpr-ref-clk",
+ &cpr_vreg->ref_clk_khz, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-timer-delay",
+ &cpr_vreg->timer_delay_us, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-timer-cons-up",
+ &cpr_vreg->timer_cons_up, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-timer-cons-down",
+ &cpr_vreg->timer_cons_down, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-irq-line",
+ &cpr_vreg->irq_line, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-step-quotient",
+ &cpr_vreg->step_quotient, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-up-threshold",
+ &cpr_vreg->up_threshold, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-down-threshold",
+ &cpr_vreg->down_threshold, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-idle-clocks",
+ &cpr_vreg->idle_clocks, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-gcnt-time",
+ &cpr_vreg->gcnt_time_us, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "vdd-apc-step-up-limit",
+ &cpr_vreg->vdd_apc_step_up_limit, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "vdd-apc-step-down-limit",
+ &cpr_vreg->vdd_apc_step_down_limit, rc);
+ if (rc)
+ return rc;
+ CPR_PROP_READ_U32(of_node, "cpr-apc-volt-step",
+ &cpr_vreg->step_volt, rc);
+ if (rc)
+ return rc;
+
+ /* Init module parameter with the DT value */
+ cpr_vreg->enable = of_property_read_bool(of_node, "qcom,cpr-enable");
+ cpr_enable = (int) cpr_vreg->enable;
+ pr_info("CPR is %s by default.\n",
+ cpr_vreg->enable ? "enabled" : "disabled");
+
+ return rc;
+}
+
+static int __init cpr_init_cpr(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
+{
+ struct resource *res;
+ int rc = 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "cpr_efuse");
+ if (!res || !res->start) {
+ pr_err("cpr_efuse missing: res=%p\n", res);
+ return -EINVAL;
+ }
+ cpr_vreg->cpr_fuse_addr = res->start;
+
+ rc = cpr_init_cpr_efuse(cpr_vreg);
+ if (rc)
+ return rc;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rbcpr");
+ if (!res || !res->start) {
+ pr_err("missing rbcpr address: res=%p\n", res);
+ return -EINVAL;
+ }
+ cpr_vreg->rbcpr_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+
+ /* Init all voltage set points of APC regulator for CPR */
+ cpr_init_cpr_voltages(cpr_vreg);
+
+ /* Init CPR configuration parameters */
+ rc = cpr_init_cpr_parameters(pdev, cpr_vreg);
+ if (rc)
+ return rc;
+
+ /* Get and Init interrupt */
+ cpr_vreg->cpr_irq = platform_get_irq(pdev, 0);
+ if (!cpr_vreg->cpr_irq) {
+ pr_err("missing CPR IRQ\n");
+ return -EINVAL;
+ }
+
+ /* Configure CPR HW but keep it disabled */
+ cpr_config(cpr_vreg);
+
+ rc = request_threaded_irq(cpr_vreg->cpr_irq, NULL, cpr_irq_handler,
+ IRQF_TRIGGER_RISING, "cpr", cpr_vreg);
+ if (rc) {
+ pr_err("CPR: request irq failed for IRQ %d\n",
+ cpr_vreg->cpr_irq);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int __init cpr_pvs_parse_dt(struct platform_device *pdev,
+ struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
struct resource *res;
@@ -327,13 +1249,12 @@
size_t pvs_bins;
/* Parse process voltage parameters */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "efuse_phys");
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pvs_efuse");
if (!res || !res->start) {
- pr_err("efuse_phys missing: res=%p\n", res);
+ pr_err("pvs_efuse missing: res=%p\n", res);
return -EINVAL;
}
- cpr_vreg->efuse_phys = res->start;
+ cpr_vreg->pvs_efuse = res->start;
rc = of_property_read_u32(of_node, "qcom,num-efuse-bits",
&cpr_vreg->num_efuse_bits);
@@ -349,14 +1270,6 @@
return -EINVAL;
}
- rc = of_property_read_u32_array(of_node, "qcom,efuse-bit-pos",
- cpr_vreg->efuse_bit_pos,
- cpr_vreg->num_efuse_bits);
- if (rc < 0) {
- pr_err("efuse-bit-pos missing: rc=%d\n", rc);
- return rc;
- }
-
pvs_bins = 1 << cpr_vreg->num_efuse_bits;
rc = of_property_read_u32_array(of_node, "qcom,pvs-bin-process",
cpr_vreg->pvs_bin_process,
@@ -368,7 +1281,7 @@
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-slow",
- &cpr_vreg->pvs_corner_ceiling[APC_PVS_SLOW][CPR_CORNER_SVS],
+ &cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_CORNER_SVS],
CPR_CORNER_MAX - CPR_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-slow missing: rc=%d\n", rc);
@@ -377,7 +1290,7 @@
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-nom",
- &cpr_vreg->pvs_corner_ceiling[APC_PVS_NOM][CPR_CORNER_SVS],
+ &cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_CORNER_SVS],
CPR_CORNER_MAX - CPR_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-norm missing: rc=%d\n", rc);
@@ -386,7 +1299,7 @@
rc = of_property_read_u32_array(of_node,
"qcom,pvs-corner-ceiling-fast",
- &cpr_vreg->pvs_corner_ceiling[APC_PVS_FAST][CPR_CORNER_SVS],
+ &cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_CORNER_SVS],
CPR_CORNER_MAX - CPR_CORNER_SVS);
if (rc < 0) {
pr_err("pvs-corner-ceiling-fast missing: rc=%d\n", rc);
@@ -426,25 +1339,33 @@
return -ENOMEM;
}
- rc = cpr_regulator_parse_dt(pdev, cpr_vreg);
+ rc = cpr_pvs_parse_dt(pdev, cpr_vreg);
if (rc) {
pr_err("Wrong DT parameter specified: rc=%d\n", rc);
return rc;
}
- rc = cpr_regulator_pvs_init(cpr_vreg);
+ rc = cpr_pvs_init(cpr_vreg);
if (rc) {
pr_err("Initialize PVS wrong: rc=%d\n", rc);
return rc;
}
- rc = cpr_regulator_apc_init(pdev, cpr_vreg);
+ rc = cpr_apc_init(pdev, cpr_vreg);
if (rc) {
if (rc != -EPROBE_DEFER)
pr_err("Initialize APC wrong: rc=%d\n", rc);
return rc;
}
+ rc = cpr_init_cpr(pdev, cpr_vreg);
+ if (rc) {
+ pr_err("Initialize CPR failed: rc=%d\n", rc);
+ return rc;
+ }
+
+ mutex_init(&cpr_vreg->cpr_mutex);
+
rdesc = &cpr_vreg->rdesc;
rdesc->owner = THIS_MODULE;
rdesc->type = REGULATOR_VOLTAGE;
@@ -457,17 +1378,12 @@
rc = PTR_ERR(cpr_vreg->rdev);
pr_err("regulator_register failed: rc=%d\n", rc);
- cpr_regulator_apc_exit(cpr_vreg);
+ cpr_apc_exit(cpr_vreg);
return rc;
}
platform_set_drvdata(pdev, cpr_vreg);
-
- pr_info("PVS [%d %d %d %d] uV\n",
- cpr_vreg->corner_ceiling[CPR_CORNER_SVS],
- cpr_vreg->corner_ceiling[CPR_CORNER_NORMAL],
- cpr_vreg->corner_ceiling[CPR_CORNER_TURBO],
- cpr_vreg->corner_ceiling[CPR_CORNER_SUPER_TURBO]);
+ the_cpr = cpr_vreg;
return 0;
}
@@ -478,7 +1394,13 @@
cpr_vreg = platform_get_drvdata(pdev);
if (cpr_vreg) {
- cpr_regulator_apc_exit(cpr_vreg);
+ /* Disable CPR */
+ if (cpr_is_allowed(cpr_vreg)) {
+ cpr_ctl_disable(cpr_vreg);
+ cpr_irq_set(cpr_vreg, 0);
+ }
+
+ cpr_apc_exit(cpr_vreg);
regulator_unregister(cpr_vreg->rdev);
}
@@ -498,6 +1420,8 @@
},
.probe = cpr_regulator_probe,
.remove = __devexit_p(cpr_regulator_remove),
+ .suspend = cpr_regulator_suspend,
+ .resume = cpr_regulator_resume,
};
/**
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index d5084e4..2e70c83 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -402,7 +402,8 @@
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
}
- msm_cpufreq_wq = create_workqueue("msm-cpufreq");
+ msm_cpufreq_wq = alloc_workqueue("msm-cpufreq",
+ WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
register_hotcpu_notifier(&msm_cpufreq_cpu_notifier);
return cpufreq_register_driver(&msm_cpufreq_driver);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 2f44566..14fe79d 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -904,6 +904,7 @@
.gpios = tspp_gpios,
.tsif_pclk = "iface_clk",
.tsif_ref_clk = "ref_clk",
+ .tsif_vreg_present = 0,
};
struct platform_device msm_8064_device_tspp = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index bf89321..483d8b3 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1270,6 +1270,7 @@
LPASS_SCSS_GP_HIGH_IRQ,
SPS_MTI_31,
A2_BAM_IRQ,
+ USB1_HS_BAM_IRQ,
};
struct msm_mpm_device_data msm9615_mpm_dev_data __initdata = {
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 30a034e..1701262 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -48,6 +48,7 @@
struct clk **clocks;
int clock_count;
bool toggle_mems;
+ bool retain_logic;
};
static int gdsc_is_enabled(struct regulator_dev *rdev)
@@ -96,16 +97,20 @@
{
struct gdsc *sc = rdev_get_drvdata(rdev);
uint32_t regval;
- int i, ret;
+ int i, ret = 0;
- regval = readl_relaxed(sc->gdscr);
- regval |= SW_COLLAPSE_MASK;
- writel_relaxed(regval, sc->gdscr);
+ if (!sc->retain_logic) {
+ regval = readl_relaxed(sc->gdscr);
+ regval |= SW_COLLAPSE_MASK;
+ writel_relaxed(regval, sc->gdscr);
- ret = readl_tight_poll_timeout(sc->gdscr, regval,
- !(regval & PWR_ON_MASK), TIMEOUT_US);
- if (ret)
- dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
+ ret = readl_tight_poll_timeout(sc->gdscr, regval,
+ !(regval & PWR_ON_MASK),
+ TIMEOUT_US);
+ if (ret)
+ dev_err(&rdev->dev, "%s disable timed out\n",
+ sc->rdesc.name);
+ }
if (sc->toggle_mems) {
for (i = 0; i < sc->clock_count; i++) {
@@ -214,6 +219,8 @@
}
}
sc->toggle_mems = !retain_mems;
+ sc->retain_logic = of_property_read_bool(pdev->dev.of_node,
+ "qcom,retain-logic");
sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
pdev->dev.of_node);
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 22f74c8..d3ef0be 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -599,9 +599,12 @@
void msm_map_apq8064_io(void);
void msm_map_msm7x30_io(void);
void msm_map_fsm9xxx_io(void);
+void msm_map_fsm9900_io(void);
+void fsm9900_init_gpiomux(void);
void msm_map_8974_io(void);
void msm_map_8084_io(void);
void msm_map_msmkrypton_io(void);
+void msm_map_msmsamarium_io(void);
void msm_map_msm8625_io(void);
void msm_map_msm9625_io(void);
void msm_init_irq(void);
@@ -613,6 +616,7 @@
void apq8084_init_gpiomux(void);
void msm9625_init_gpiomux(void);
void msmkrypton_init_gpiomux(void);
+void msmsamarium_init_gpiomux(void);
void msm_map_mpq8092_io(void);
void mpq8092_init_gpiomux(void);
void msm_map_msm8226_io(void);
diff --git a/arch/arm/mach-msm/include/mach/camera2.h b/arch/arm/mach-msm/include/mach/camera2.h
index 248c9b0..3e7e5fd 100644
--- a/arch/arm/mach-msm/include/mach/camera2.h
+++ b/arch/arm/mach-msm/include/mach/camera2.h
@@ -79,6 +79,7 @@
struct msm_camera_i2c_conf *i2c_conf;
struct msm_sensor_info_t *sensor_info;
struct msm_sensor_init_params *sensor_init_params;
+ const char *misc_regulator;
};
enum msm_camera_i2c_cmd_type {
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 0dd4957..27c6df4 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -61,8 +61,8 @@
struct regulator **regulator;
int num_regulators;
int (*set_vdd)(struct clk_vdd_class *v_class, int level);
- int **vdd_uv;
- int **vdd_ua;
+ int *vdd_uv;
+ int *vdd_ua;
int *level_votes;
int num_levels;
unsigned long cur_level;
@@ -93,9 +93,6 @@
.lock = __MUTEX_INITIALIZER(_name.lock) \
}
-#define VDD_UV(...) ((int []){__VA_ARGS__})
-#define VDD_UA(...) ((int []){__VA_ARGS__})
-
enum handoff {
HANDOFF_ENABLED_CLK,
HANDOFF_DISABLED_CLK,
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 23d204a..decf9bb 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -98,6 +98,7 @@
* @halt_enabled: Set to 1 if IOMMU halt is supported in the IOMMU, 0 otherwise.
* @asid: List of ASID and their usage count (index is ASID value).
* @ctx_attach_count: Count of how many context are attached.
+ * @bus_client : Bus client needed to vote for bus bandwidth.
*
* A msm_iommu_drvdata holds the global driver data about a single piece
* of an IOMMU hardware instance.
@@ -121,12 +122,14 @@
int halt_enabled;
int *asid;
unsigned int ctx_attach_count;
+ unsigned int bus_client;
};
/**
* struct iommu_access_ops - Callbacks for accessing IOMMU
* @iommu_power_on: Turn on power to unit
* @iommu_power_off: Turn off power to unit
+ * @iommu_bus_vote: Vote for bus bandwidth
* @iommu_clk_on: Turn on clks to unit
* @iommu_clk_off: Turn off clks to unit
* @iommu_lock_initialize: Initialize the remote lock
@@ -136,6 +139,8 @@
struct iommu_access_ops {
int (*iommu_power_on)(struct msm_iommu_drvdata *);
void (*iommu_power_off)(struct msm_iommu_drvdata *);
+ int (*iommu_bus_vote)(struct msm_iommu_drvdata *drvdata,
+ unsigned int vote);
int (*iommu_clk_on)(struct msm_iommu_drvdata *);
void (*iommu_clk_off)(struct msm_iommu_drvdata *);
void * (*iommu_lock_initialize)(void);
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-fsm9900.h b/arch/arm/mach-msm/include/mach/msm_iomap-fsm9900.h
new file mode 100644
index 0000000..02b8917
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-fsm9900.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * 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 __ASM_ARCH_MSM_IOMAP_FSM9900_H
+#define __ASM_ARCH_MSM_IOMAP_FSM9900_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define FSM9900_SHARED_RAM_PHYS 0x98000000
+
+#define FSM9900_QGIC_DIST_PHYS 0xF9000000
+#define FSM9900_QGIC_DIST_SIZE SZ_4K
+
+#define FSM9900_TLMM_PHYS 0xFD510000
+#define FSM9900_TLMM_SIZE SZ_16K
+
+#ifdef CONFIG_DEBUG_FSM9900_UART
+#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS 0xF9960000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-samarium.h b/arch/arm/mach-msm/include/mach/msm_iomap-samarium.h
new file mode 100644
index 0000000..7a6b626
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-samarium.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * 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 __ASM_ARCH_MSM_IOMAP_SAMARIUM_H
+#define __ASM_ARCH_MSM_IOMAP_SAMARIUM_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSMSAMARIUM_SHARED_RAM_PHYS 0x0FA00000
+
+#define MSMSAMARIUM_QGIC_DIST_PHYS 0xF9000000
+#define MSMSAMARIUM_QGIC_DIST_SIZE SZ_4K
+
+#define MSMSAMARIUM_TLMM_PHYS 0xFD510000
+#define MSMSAMARIUM_TLMM_SIZE SZ_16K
+
+#define MSMSAMARIUM_MPM2_PSHOLD_PHYS 0xFC4AB000
+#define MSMSAMARIUM_MPM2_PSHOLD_SIZE SZ_4K
+
+#ifdef CONFIG_DEBUG_MSMSAMARIUM_UART
+#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS 0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 8f48e94..676df66 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -136,6 +136,8 @@
#include "msm_iomap-8226.h"
#include "msm_iomap-8610.h"
#include "msm_iomap-krypton.h"
+#include "msm_iomap-fsm9900.h"
+#include "msm_iomap-samarium.h"
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index d155c6f..2cc7b10 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -19,7 +19,9 @@
#define __ASM_ARCH_MSM_SMD_H
#include <linux/io.h>
-#include <mach/msm_smsm.h>
+#include <linux/notifier.h>
+
+#include <mach/msm_smem.h>
typedef struct smd_channel smd_channel_t;
@@ -40,13 +42,13 @@
* SMD, the entry will only exist in this enum.
*/
enum {
- SMD_APPS = SMSM_APPS,
- SMD_MODEM = SMSM_MODEM,
- SMD_Q6 = SMSM_Q6,
- SMD_WCNSS = SMSM_WCNSS,
- SMD_DSPS = SMSM_DSPS,
- SMD_MODEM_Q6_FW,
- SMD_RPM,
+ SMD_APPS = SMEM_APPS,
+ SMD_MODEM = SMEM_MODEM,
+ SMD_Q6 = SMEM_Q6,
+ SMD_DSPS = SMEM_DSPS,
+ SMD_WCNSS = SMEM_WCNSS,
+ SMD_MODEM_Q6_FW = SMEM_MODEM_Q6_FW,
+ SMD_RPM = SMEM_RPM,
NUM_SMD_SUBSYSTEMS,
};
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
new file mode 100644
index 0000000..57f22cc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -0,0 +1,180 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_SMEM_H_
+#define _ARCH_ARM_MACH_MSM_SMEM_H_
+
+#include <linux/types.h>
+
+enum {
+ SMEM_APPS,
+ SMEM_MODEM,
+ SMEM_Q6,
+ SMEM_DSPS,
+ SMEM_WCNSS,
+ SMEM_MODEM_Q6_FW,
+ SMEM_RPM,
+ NUM_SMEM_SUBSYSTEMS,
+};
+
+#define SMEM_NUM_SMD_STREAM_CHANNELS 64
+#define SMEM_NUM_SMD_BLOCK_CHANNELS 64
+
+enum {
+ /* fixed items */
+ SMEM_PROC_COMM = 0,
+ SMEM_HEAP_INFO,
+ SMEM_ALLOCATION_TABLE,
+ SMEM_VERSION_INFO,
+ SMEM_HW_RESET_DETECT,
+ SMEM_AARM_WARM_BOOT,
+ SMEM_DIAG_ERR_MESSAGE,
+ SMEM_SPINLOCK_ARRAY,
+ SMEM_MEMORY_BARRIER_LOCATION,
+ SMEM_FIXED_ITEM_LAST = SMEM_MEMORY_BARRIER_LOCATION,
+
+ /* dynamic items */
+ SMEM_AARM_PARTITION_TABLE,
+ SMEM_AARM_BAD_BLOCK_TABLE,
+ SMEM_RESERVE_BAD_BLOCKS,
+ SMEM_WM_UUID,
+ SMEM_CHANNEL_ALLOC_TBL,
+ SMEM_SMD_BASE_ID,
+ SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS,
+ SMEM_SMEM_LOG_EVENTS,
+ SMEM_SMEM_STATIC_LOG_IDX,
+ SMEM_SMEM_STATIC_LOG_EVENTS,
+ SMEM_SMEM_SLOW_CLOCK_SYNC,
+ SMEM_SMEM_SLOW_CLOCK_VALUE,
+ SMEM_BIO_LED_BUF,
+ SMEM_SMSM_SHARED_STATE,
+ SMEM_SMSM_INT_INFO,
+ SMEM_SMSM_SLEEP_DELAY,
+ SMEM_SMSM_LIMIT_SLEEP,
+ SMEM_SLEEP_POWER_COLLAPSE_DISABLED,
+ SMEM_KEYPAD_KEYS_PRESSED,
+ SMEM_KEYPAD_STATE_UPDATED,
+ SMEM_KEYPAD_STATE_IDX,
+ SMEM_GPIO_INT,
+ SMEM_MDDI_LCD_IDX,
+ SMEM_MDDI_HOST_DRIVER_STATE,
+ SMEM_MDDI_LCD_DISP_STATE,
+ SMEM_LCD_CUR_PANEL,
+ SMEM_MARM_BOOT_SEGMENT_INFO,
+ SMEM_AARM_BOOT_SEGMENT_INFO,
+ SMEM_SLEEP_STATIC,
+ SMEM_SCORPION_FREQUENCY,
+ SMEM_SMD_PROFILES,
+ SMEM_TSSC_BUSY,
+ SMEM_HS_SUSPEND_FILTER_INFO,
+ SMEM_BATT_INFO,
+ SMEM_APPS_BOOT_MODE,
+ SMEM_VERSION_FIRST,
+ SMEM_VERSION_SMD = SMEM_VERSION_FIRST,
+ SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24,
+ SMEM_OSS_RRCASN1_BUF1,
+ SMEM_OSS_RRCASN1_BUF2,
+ SMEM_ID_VENDOR0,
+ SMEM_ID_VENDOR1,
+ SMEM_ID_VENDOR2,
+ SMEM_HW_SW_BUILD_ID,
+ SMEM_SMD_BLOCK_PORT_BASE_ID,
+ SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID +
+ SMEM_NUM_SMD_BLOCK_CHANNELS,
+ SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP +
+ SMEM_NUM_SMD_BLOCK_CHANNELS,
+ SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP +
+ SMEM_NUM_SMD_BLOCK_CHANNELS,
+ SMEM_SCLK_CONVERSION,
+ SMEM_SMD_SMSM_INTR_MUX,
+ SMEM_SMSM_CPU_INTR_MASK,
+ SMEM_APPS_DEM_SLAVE_DATA,
+ SMEM_QDSP6_DEM_SLAVE_DATA,
+ SMEM_CLKREGIM_BSP,
+ SMEM_CLKREGIM_SOURCES,
+ SMEM_SMD_FIFO_BASE_ID,
+ SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID +
+ SMEM_NUM_SMD_STREAM_CHANNELS,
+ SMEM_POWER_ON_STATUS_INFO,
+ SMEM_DAL_AREA,
+ SMEM_SMEM_LOG_POWER_IDX,
+ SMEM_SMEM_LOG_POWER_WRAP,
+ SMEM_SMEM_LOG_POWER_EVENTS,
+ SMEM_ERR_CRASH_LOG,
+ SMEM_ERR_F3_TRACE_LOG,
+ SMEM_SMD_BRIDGE_ALLOC_TABLE,
+ SMEM_SMDLITE_TABLE,
+ SMEM_SD_IMG_UPGRADE_STATUS,
+ SMEM_SEFS_INFO,
+ SMEM_RESET_LOG,
+ SMEM_RESET_LOG_SYMBOLS,
+ SMEM_MODEM_SW_BUILD_ID,
+ SMEM_SMEM_LOG_MPROC_WRAP,
+ SMEM_BOOT_INFO_FOR_APPS,
+ SMEM_SMSM_SIZE_INFO,
+ SMEM_SMD_LOOPBACK_REGISTER,
+ SMEM_SSR_REASON_MSS0,
+ SMEM_SSR_REASON_WCNSS0,
+ SMEM_SSR_REASON_LPASS0,
+ SMEM_SSR_REASON_DSPS0,
+ SMEM_SSR_REASON_VCODEC0,
+ SMEM_SMP2P_APPS_BASE = 427,
+ SMEM_SMP2P_MODEM_BASE = SMEM_SMP2P_APPS_BASE + 8, /* 435 */
+ SMEM_SMP2P_AUDIO_BASE = SMEM_SMP2P_MODEM_BASE + 8, /* 443 */
+ SMEM_SMP2P_WIRLESS_BASE = SMEM_SMP2P_AUDIO_BASE + 8, /* 451 */
+ SMEM_SMP2P_POWER_BASE = SMEM_SMP2P_WIRLESS_BASE + 8, /* 459 */
+ SMEM_FLASH_DEVICE_INFO = SMEM_SMP2P_POWER_BASE + 8, /* 467 */
+ SMEM_BAM_PIPE_MEMORY, /* 468 */
+ SMEM_IMAGE_VERSION_TABLE, /* 469 */
+ SMEM_LC_DEBUGGER, /* 470 */
+ SMEM_NUM_ITEMS,
+};
+
+#ifdef CONFIG_MSM_SMD
+void *smem_alloc(unsigned id, unsigned size);
+void *smem_alloc2(unsigned id, unsigned size_in);
+void *smem_get_entry(unsigned id, unsigned *size);
+void *smem_find(unsigned id, unsigned size);
+/**
+ * smem_virt_to_phys() - Convert SMEM address to physical address.
+ *
+ * @smem_address: Virtual address returned by smem_alloc()/smem_alloc2()
+ * @returns: Physical address (or NULL if there is a failure)
+ *
+ * This function should only be used if an SMEM item needs to be handed
+ * off to a DMA engine.
+ */
+phys_addr_t smem_virt_to_phys(void *smem_address);
+
+#else
+static inline void *smem_alloc(unsigned id, unsigned size)
+{
+ return NULL;
+}
+static inline void *smem_alloc2(unsigned id, unsigned size_in)
+{
+ return NULL;
+}
+static inline void *smem_get_entry(unsigned id, unsigned *size)
+{
+ return NULL;
+}
+static inline void *smem_find(unsigned id, unsigned size)
+{
+ return NULL;
+}
+static inline phys_addr_t smem_virt_to_phys(void *smem_address)
+{
+ return (phys_addr_t) NULL;
+}
+#endif /* CONFIG_MSM_SMD */
+#endif /* _ARCH_ARM_MACH_MSM_SMEM_H_ */
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 81a6399..733f5a9 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -14,6 +14,9 @@
#define _ARCH_ARM_MACH_MSM_SMSM_H_
#include <linux/notifier.h>
+
+#include <mach/msm_smem.h>
+
#if defined(CONFIG_MSM_N_WAY_SMSM)
enum {
SMSM_APPS_STATE,
@@ -37,11 +40,11 @@
#endif
enum {
- SMSM_APPS,
- SMSM_MODEM,
- SMSM_Q6,
- SMSM_WCNSS,
- SMSM_DSPS,
+ SMSM_APPS = SMEM_APPS,
+ SMSM_MODEM = SMEM_MODEM,
+ SMSM_Q6 = SMEM_Q6,
+ SMSM_DSPS = SMEM_DSPS,
+ SMSM_WCNSS = SMEM_WCNSS,
};
extern uint32_t SMSM_NUM_HOSTS;
@@ -97,119 +100,6 @@
#define SMSM_SUBSYS2AP_STATUS 0x00008000
-#define SMEM_NUM_SMD_STREAM_CHANNELS 64
-#define SMEM_NUM_SMD_BLOCK_CHANNELS 64
-
-enum {
- /* fixed items */
- SMEM_PROC_COMM = 0,
- SMEM_HEAP_INFO,
- SMEM_ALLOCATION_TABLE,
- SMEM_VERSION_INFO,
- SMEM_HW_RESET_DETECT,
- SMEM_AARM_WARM_BOOT,
- SMEM_DIAG_ERR_MESSAGE,
- SMEM_SPINLOCK_ARRAY,
- SMEM_MEMORY_BARRIER_LOCATION,
- SMEM_FIXED_ITEM_LAST = SMEM_MEMORY_BARRIER_LOCATION,
-
- /* dynamic items */
- SMEM_AARM_PARTITION_TABLE,
- SMEM_AARM_BAD_BLOCK_TABLE,
- SMEM_RESERVE_BAD_BLOCKS,
- SMEM_WM_UUID,
- SMEM_CHANNEL_ALLOC_TBL,
- SMEM_SMD_BASE_ID,
- SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS,
- SMEM_SMEM_LOG_EVENTS,
- SMEM_SMEM_STATIC_LOG_IDX,
- SMEM_SMEM_STATIC_LOG_EVENTS,
- SMEM_SMEM_SLOW_CLOCK_SYNC,
- SMEM_SMEM_SLOW_CLOCK_VALUE,
- SMEM_BIO_LED_BUF,
- SMEM_SMSM_SHARED_STATE,
- SMEM_SMSM_INT_INFO,
- SMEM_SMSM_SLEEP_DELAY,
- SMEM_SMSM_LIMIT_SLEEP,
- SMEM_SLEEP_POWER_COLLAPSE_DISABLED,
- SMEM_KEYPAD_KEYS_PRESSED,
- SMEM_KEYPAD_STATE_UPDATED,
- SMEM_KEYPAD_STATE_IDX,
- SMEM_GPIO_INT,
- SMEM_MDDI_LCD_IDX,
- SMEM_MDDI_HOST_DRIVER_STATE,
- SMEM_MDDI_LCD_DISP_STATE,
- SMEM_LCD_CUR_PANEL,
- SMEM_MARM_BOOT_SEGMENT_INFO,
- SMEM_AARM_BOOT_SEGMENT_INFO,
- SMEM_SLEEP_STATIC,
- SMEM_SCORPION_FREQUENCY,
- SMEM_SMD_PROFILES,
- SMEM_TSSC_BUSY,
- SMEM_HS_SUSPEND_FILTER_INFO,
- SMEM_BATT_INFO,
- SMEM_APPS_BOOT_MODE,
- SMEM_VERSION_FIRST,
- SMEM_VERSION_SMD = SMEM_VERSION_FIRST,
- SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24,
- SMEM_OSS_RRCASN1_BUF1,
- SMEM_OSS_RRCASN1_BUF2,
- SMEM_ID_VENDOR0,
- SMEM_ID_VENDOR1,
- SMEM_ID_VENDOR2,
- SMEM_HW_SW_BUILD_ID,
- SMEM_SMD_BLOCK_PORT_BASE_ID,
- SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID +
- SMEM_NUM_SMD_BLOCK_CHANNELS,
- SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP +
- SMEM_NUM_SMD_BLOCK_CHANNELS,
- SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP +
- SMEM_NUM_SMD_BLOCK_CHANNELS,
- SMEM_SCLK_CONVERSION,
- SMEM_SMD_SMSM_INTR_MUX,
- SMEM_SMSM_CPU_INTR_MASK,
- SMEM_APPS_DEM_SLAVE_DATA,
- SMEM_QDSP6_DEM_SLAVE_DATA,
- SMEM_CLKREGIM_BSP,
- SMEM_CLKREGIM_SOURCES,
- SMEM_SMD_FIFO_BASE_ID,
- SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID +
- SMEM_NUM_SMD_STREAM_CHANNELS,
- SMEM_POWER_ON_STATUS_INFO,
- SMEM_DAL_AREA,
- SMEM_SMEM_LOG_POWER_IDX,
- SMEM_SMEM_LOG_POWER_WRAP,
- SMEM_SMEM_LOG_POWER_EVENTS,
- SMEM_ERR_CRASH_LOG,
- SMEM_ERR_F3_TRACE_LOG,
- SMEM_SMD_BRIDGE_ALLOC_TABLE,
- SMEM_SMDLITE_TABLE,
- SMEM_SD_IMG_UPGRADE_STATUS,
- SMEM_SEFS_INFO,
- SMEM_RESET_LOG,
- SMEM_RESET_LOG_SYMBOLS,
- SMEM_MODEM_SW_BUILD_ID,
- SMEM_SMEM_LOG_MPROC_WRAP,
- SMEM_BOOT_INFO_FOR_APPS,
- SMEM_SMSM_SIZE_INFO,
- SMEM_SMD_LOOPBACK_REGISTER,
- SMEM_SSR_REASON_MSS0,
- SMEM_SSR_REASON_WCNSS0,
- SMEM_SSR_REASON_LPASS0,
- SMEM_SSR_REASON_DSPS0,
- SMEM_SSR_REASON_VCODEC0,
- SMEM_SMP2P_APPS_BASE = 427,
- SMEM_SMP2P_MODEM_BASE = SMEM_SMP2P_APPS_BASE + 8, /* 435 */
- SMEM_SMP2P_AUDIO_BASE = SMEM_SMP2P_MODEM_BASE + 8, /* 443 */
- SMEM_SMP2P_WIRLESS_BASE = SMEM_SMP2P_AUDIO_BASE + 8, /* 451 */
- SMEM_SMP2P_POWER_BASE = SMEM_SMP2P_WIRLESS_BASE + 8, /* 459 */
- SMEM_FLASH_DEVICE_INFO = SMEM_SMP2P_POWER_BASE + 8, /* 467 */
- SMEM_BAM_PIPE_MEMORY, /* 468 */
- SMEM_IMAGE_VERSION_TABLE, /* 469 */
- SMEM_LC_DEBUGGER, /* 470 */
- SMEM_NUM_ITEMS,
-};
-
enum {
SMEM_APPS_Q6_SMSM = 3,
SMEM_Q6_APPS_SMSM = 5,
@@ -217,9 +107,6 @@
};
#ifdef CONFIG_MSM_SMD
-void *smem_alloc(unsigned id, unsigned size);
-void *smem_alloc2(unsigned id, unsigned size_in);
-void *smem_get_entry(unsigned id, unsigned *size);
int smsm_change_state(uint32_t smsm_entry,
uint32_t clear_mask, uint32_t set_mask);
@@ -254,36 +141,8 @@
int smsm_check_for_modem_crash(void);
-void *smem_find(unsigned id, unsigned size);
-void *smem_get_entry(unsigned id, unsigned *size);
-
-/**
- * smem_virt_to_phys() - Convert SMEM address to physical address.
- *
- * @smem_address: Virtual address returned by smem_alloc()/smem_alloc2()
- * @returns: Physical address (or NULL if there is a failure)
- *
- * This function should only be used if an SMEM item needs to be handed
- * off to a DMA engine.
- */
-phys_addr_t smem_virt_to_phys(void *smem_address);
#else
-static inline void *smem_alloc(unsigned id, unsigned size)
-{
- return NULL;
-}
-
-static inline void *smem_alloc2(unsigned id, unsigned size_in)
-{
- return NULL;
-}
-
-static inline void *smem_get_entry(unsigned id, unsigned *size)
-{
- return NULL;
-}
-
static inline int smsm_change_state(uint32_t smsm_entry,
uint32_t clear_mask, uint32_t set_mask)
{
@@ -347,13 +206,5 @@
{
return -ENODEV;
}
-static inline void *smem_find(unsigned id, unsigned size)
-{
- return NULL;
-}
-static inline phys_addr_t smem_virt_to_phys(void *smem_address)
-{
- return NULL;
-}
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_tspp.h b/arch/arm/mach-msm/include/mach/msm_tspp.h
index 696d4ef..ddc99f3 100644
--- a/arch/arm/mach-msm/include/mach/msm_tspp.h
+++ b/arch/arm/mach-msm/include/mach/msm_tspp.h
@@ -20,6 +20,7 @@
const struct msm_gpio *gpios;
const char *tsif_pclk;
const char *tsif_ref_clk;
+ int tsif_vreg_present;
};
struct tspp_data_descriptor {
diff --git a/arch/arm/mach-msm/include/mach/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index e889242..3a997be 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -67,9 +67,9 @@
};
enum qseecom_pipe_type {
- QSEOS_PIPE_ENC = 0,
- QSEOS_PIPE_ENC_XTS,
- QSEOS_PIPE_AUTH,
+ QSEOS_PIPE_ENC = 0x1,
+ QSEOS_PIPE_ENC_XTS = 0x2,
+ QSEOS_PIPE_AUTH = 0x4,
QSEOS_PIPE_ENUM_FILL = 0x7FFFFFFF
};
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 64531f0..99bff66 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -53,6 +53,10 @@
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,apq8084")
#define early_machine_is_msmkrypton() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmkrypton")
+#define early_machine_is_fsm9900() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,fsm9900")
+#define early_machine_is_msmsamarium() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmsamarium")
#else
#define of_board_is_sim() 0
#define of_board_is_rumi() 0
@@ -70,6 +74,8 @@
#define early_machine_is_mpq8092() 0
#define early_machine_is_apq8084() 0
#define early_machine_is_msmkrypton() 0
+#define early_machine_is_fsm9900() 0
+#define early_machine_is_msmsamarium() 0
#endif
#define PLATFORM_SUBTYPE_MDM 1
@@ -110,6 +116,8 @@
MSM_CPU_8625Q,
MSM_CPU_8084,
MSM_CPU_KRYPTON,
+ FSM_CPU_9900,
+ MSM_CPU_SAMARIUM,
};
enum pmic_model {
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 893db0b..35b1f76 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -41,7 +41,8 @@
* @powerup: Start a subsystem
* @crash_shutdown: Shutdown a subsystem when the system crashes (can't sleep)
* @ramdump: Collect a ramdump of the subsystem
- * @is_loadable: Indicate if subsystem firmware is loadable via pil framework
+ * @is_not_loadable: Indicate if subsystem firmware is not loadable via pil
+ * framework
*/
struct subsys_desc {
const char *name;
@@ -57,7 +58,7 @@
void (*crash_shutdown)(const struct subsys_desc *desc);
int (*ramdump)(int, const struct subsys_desc *desc);
unsigned int err_ready_irq;
- int is_loadable;
+ int is_not_loadable;
};
#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index da7c039..5ecc63b 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -101,6 +101,7 @@
* @desc_mem_buf: descriptor fifo buffer.
* @event: event for wakeup.
* @enabled: true if pipe is enabled.
+* @ipa_clnt_hdl : pipe handle to ipa api.
* @priv: private data to return upon activity_notify
* or inactivity_notify callbacks.
* @activity_notify: callback to invoke on activity on one of the in pipes.
@@ -125,6 +126,7 @@
struct sps_mem_buffer desc_mem_buf;
struct usb_bam_event_info event;
bool enabled;
+ int ipa_clnt_hdl;
void *priv;
int (*activity_notify)(void *priv);
int (*inactivity_notify)(void *priv);
@@ -195,6 +197,14 @@
struct usb_bam_connect_ipa_params *ipa_params);
/**
+ * Wait for Consumer granted from Resource Manager.
+ *
+ * @ipa_params - in/out parameters
+ *
+ */
+void usb_bam_wait_for_cons_granted(
+ struct usb_bam_connect_ipa_params *ipa_params);
+/**
* Register a wakeup callback from peer BAM.
*
* @idx - Connection index.
@@ -221,6 +231,39 @@
int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param);
/**
+ * Register callbacks for start/stop of transfers.
+ *
+ * @start - the callback function that will be called in USB
+ * driver to start transfers
+ * @stop - the callback function that will be called in USB
+ * driver to stop transfers
+ *
+ * @param - context that the caller can supply
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int usb_bam_register_start_stop_cbs(
+ void (*start)(void *, enum usb_bam_pipe_dir),
+ void (*stop)(void *, enum usb_bam_pipe_dir),
+ void *param);
+
+/**
+ * Start usb suspend sequence
+ *
+ * @ipa_params - in/out parameters
+ *
+ */
+void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params);
+
+/**
+ * Start usb resume sequence
+ *
+ * @ipa_params - in/out parameters
+ *
+ */
+void usb_bam_resume(struct usb_bam_connect_ipa_params *ipa_params);
+/**
* Disconnect USB-to-Periperal SPS connection.
*
* @idx - Connection index.
@@ -315,6 +358,12 @@
return -ENODEV;
}
+static inline void usb_bam_wait_for_cons_granted(
+ struct usb_bam_connect_ipa_params *ipa_params)
+{
+ return;
+}
+
static inline int usb_bam_register_wake_cb(u8 idx,
int (*callback)(void *), void* param)
{
@@ -327,6 +376,20 @@
return -ENODEV;
}
+static inline int usb_bam_register_start_stop_cbs(
+ void (*start)(void *, enum usb_bam_pipe_dir),
+ void (*stop)(void *, enum usb_bam_pipe_dir),
+ void *param)
+{
+ return -ENODEV;
+}
+
+static inline void usb_bam_suspend(
+ struct usb_bam_connect_ipa_params *ipa_params){}
+
+static inline void usb_bam_resume(
+ struct usb_bam_connect_ipa_params *ipa_params) {}
+
static inline int usb_bam_disconnect_pipe(u8 idx)
{
return -ENODEV;
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 1c4a317..73e960f 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -406,6 +406,28 @@
}
#endif /* CONFIG_ARCH_FSM9XXX */
+#ifdef CONFIG_ARCH_FSM9900
+static struct map_desc fsm9900_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(QGIC_DIST, FSM9900),
+ MSM_CHIP_DEVICE(TLMM, FSM9900),
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+#ifdef CONFIG_DEBUG_FSM9900_UART
+ MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_fsm9900_io(void)
+{
+ msm_shared_ram_phys = FSM9900_SHARED_RAM_PHYS;
+ msm_map_io(fsm9900_io_desc, ARRAY_SIZE(fsm9900_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
+}
+#endif /* CONFIG_ARCH_FSM9900 */
+
#ifdef CONFIG_ARCH_MSM9615
static struct map_desc msm9615_io_desc[] __initdata = {
MSM_CHIP_DEVICE(QGIC_DIST, MSM9615),
@@ -592,3 +614,26 @@
of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
}
#endif /* CONFIG_ARCH_MSM8610 */
+
+#ifdef CONFIG_ARCH_MSMSAMARIUM
+static struct map_desc msmsamarium_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(QGIC_DIST, MSMSAMARIUM),
+ MSM_CHIP_DEVICE(TLMM, MSMSAMARIUM),
+ MSM_CHIP_DEVICE(MPM2_PSHOLD, MSMSAMARIUM),
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+#if defined(CONFIG_DEBUG_MSMSAMARIUM_UART) || defined(CONFIG_DEBUG_MSM8974_UART)
+ MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_msmsamarium_io(void)
+{
+ msm_shared_ram_phys = MSMSAMARIUM_SHARED_RAM_PHYS;
+ msm_map_io(msmsamarium_io_desc, ARRAY_SIZE(msmsamarium_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
+}
+#endif /* CONFIG_ARCH_MSMSAMARIUM */
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index f4ac37e..12f5a8e 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -570,12 +570,14 @@
goto out;
}
ctx = msm_iommu_get_ctx(name);
- if (!ctx) {
- pr_err("Unable to find context %s\n", name);
- ret_val = -EINVAL;
+ if (IS_ERR(ctx)) {
+ ret_val = PTR_ERR(ctx);
goto out;
}
- iommu_group_add_device(group, ctx);
+
+ ret_val = iommu_group_add_device(group, ctx);
+ if (ret_val)
+ goto out;
}
out:
return ret_val;
@@ -590,7 +592,7 @@
struct msm_iova_layout l;
struct msm_iova_partition *part = 0;
struct iommu_domain *domain = 0;
- unsigned int *addr_array;
+ unsigned int *addr_array = 0;
unsigned int array_size;
int domain_no;
int secure_domain;
@@ -661,11 +663,46 @@
iommu_group_set_iommudata(group, domain, NULL);
free_mem:
+ kfree(addr_array);
kfree(part);
out:
return ret_val;
}
+static int __msm_group_get_domain(struct device *dev, void *data)
+{
+ struct msm_iommu_data_entry *list_entry;
+ struct list_head *dev_list = data;
+ int ret_val = 0;
+
+ list_entry = kmalloc(sizeof(*list_entry), GFP_KERNEL);
+ if (list_entry) {
+ list_entry->data = dev;
+ list_add(&list_entry->list, dev_list);
+ } else {
+ ret_val = -ENOMEM;
+ }
+
+ return ret_val;
+}
+
+static void __msm_iommu_group_remove_device(struct iommu_group *grp)
+{
+ struct msm_iommu_data_entry *tmp;
+ struct msm_iommu_data_entry *list_entry;
+ struct list_head dev_list;
+
+ INIT_LIST_HEAD(&dev_list);
+ iommu_group_for_each_dev(grp, &dev_list, __msm_group_get_domain);
+
+ list_for_each_entry_safe(list_entry, tmp, &dev_list, list) {
+ iommu_group_remove_device(list_entry->data);
+ list_del(&list_entry->list);
+ kfree(list_entry);
+ }
+}
+
+
static int iommu_domain_parse_dt(const struct device_node *dt_node)
{
struct device_node *node;
@@ -674,13 +711,30 @@
int ret_val = 0;
struct iommu_group *group = 0;
const char *name;
+ struct msm_iommu_data_entry *grp_list_entry;
+ struct msm_iommu_data_entry *tmp;
+ struct list_head iommu_group_list;
+ INIT_LIST_HEAD(&iommu_group_list);
for_each_child_of_node(dt_node, node) {
group = iommu_group_alloc();
if (IS_ERR(group)) {
ret_val = PTR_ERR(group);
- goto out;
+ group = 0;
+ goto free_group;
}
+
+ /* This is only needed to clean up memory if something fails */
+ grp_list_entry = kmalloc(sizeof(*grp_list_entry),
+ GFP_KERNEL);
+ if (grp_list_entry) {
+ grp_list_entry->data = group;
+ list_add(&grp_list_entry->list, &iommu_group_list);
+ } else {
+ ret_val = -ENOMEM;
+ goto free_group;
+ }
+
if (of_property_read_string(node, "label", &name)) {
ret_val = -EINVAL;
goto free_group;
@@ -696,7 +750,6 @@
ret_val = find_and_add_contexts(group, node, num_contexts);
if (ret_val) {
- ret_val = -EINVAL;
goto free_group;
}
ret_val = create_and_add_domain(group, node, name);
@@ -704,9 +757,33 @@
ret_val = -EINVAL;
goto free_group;
}
+
+ /* Remove reference to the group that is taken when the group
+ * is allocated. This will ensure that when all the devices in
+ * the group are removed the group will be released.
+ */
+ iommu_group_put(group);
}
+
+ list_for_each_entry_safe(grp_list_entry, tmp, &iommu_group_list, list) {
+ list_del(&grp_list_entry->list);
+ kfree(grp_list_entry);
+ }
+ goto out;
+
free_group:
- /* No iommu_group_free() function */
+ list_for_each_entry_safe(grp_list_entry, tmp, &iommu_group_list, list) {
+ struct iommu_domain *d;
+
+ d = iommu_group_get_iommudata(grp_list_entry->data);
+ if (d)
+ msm_unregister_domain(d);
+
+ __msm_iommu_group_remove_device(grp_list_entry->data);
+ list_del(&grp_list_entry->list);
+ kfree(grp_list_entry);
+ }
+ iommu_group_put(group);
out:
return ret_val;
}
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index a328b2b..c620419 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -2253,12 +2253,11 @@
return ret;
}
- /* Achieve Flow control */
rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
dst_port_id);
if (!rport_ptr) {
- pr_err("%s: Could not create remote port\n", __func__);
- return -ENOMEM;
+ pr_err("%s: Remote port not found\n", __func__);
+ return -ENODEV;
}
if (src->check_send_permissions) {
@@ -2963,9 +2962,14 @@
D("open event for '%s'\n", xprt->name);
xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
GFP_ATOMIC);
- xprt_work->xprt = xprt;
- INIT_WORK(&xprt_work->work, xprt_open_worker);
- queue_work(msm_ipc_router_workqueue, &xprt_work->work);
+ if (xprt_work) {
+ xprt_work->xprt = xprt;
+ INIT_WORK(&xprt_work->work, xprt_open_worker);
+ queue_work(msm_ipc_router_workqueue, &xprt_work->work);
+ } else {
+ pr_err("%s: malloc failure - Couldn't notify OPEN event",
+ __func__);
+ }
break;
case IPC_ROUTER_XPRT_EVENT_CLOSE:
@@ -2973,9 +2977,14 @@
atomic_inc(&pending_close_count);
xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
GFP_ATOMIC);
- xprt_work->xprt = xprt;
- INIT_WORK(&xprt_work->work, xprt_close_worker);
- queue_work(msm_ipc_router_workqueue, &xprt_work->work);
+ if (xprt_work) {
+ xprt_work->xprt = xprt;
+ INIT_WORK(&xprt_work->work, xprt_close_worker);
+ queue_work(msm_ipc_router_workqueue, &xprt_work->work);
+ } else {
+ pr_err("%s: malloc failure - Couldn't notify CLOSE event",
+ __func__);
+ }
break;
}
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 9014f37..7c1b8d6 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -92,6 +92,16 @@
#define MDD_CONFIG_CTL 0x00000000
#define MDD_MODE 0x00000010
+#define PHASE_SCALING_REF 4
+
+/* bit definitions for phase scaling eFuses */
+#define PHASE_SCALING_EFUSE_VERSION_POS 26
+#define PHASE_SCALING_EFUSE_VERSION_MASK KRAIT_MASK(27, 26)
+#define PHASE_SCALING_EFUSE_VERSION_SET 1
+
+#define PHASE_SCALING_EFUSE_VALUE_POS 16
+#define PHASE_SCALING_EFUSE_VALUE_MASK KRAIT_MASK(18, 16)
+
/* bit definitions for APC_PWR_GATE_CTL */
#define BHS_CNT_BIT_POS 24
#define BHS_CNT_MASK KRAIT_MASK(31, 24)
@@ -149,6 +159,10 @@
* @manage_phases: begin phase control
* @pfm_threshold: the sum of coefficients below which PFM can be
* enabled
+ * @efuse_phase_scaling_factor: Phase scaling factor read out of an eFuse. When
+ * calculating the appropriate phase count to use,
+ * coeff2 is multiplied by this factor and then
+ * divided by PHASE_SCALING_REF.
*/
struct pmic_gang_vreg {
const char *name;
@@ -163,6 +177,7 @@
void __iomem *apcs_gcc_base;
bool manage_phases;
int pfm_threshold;
+ int efuse_phase_scaling_factor;
};
static struct pmic_gang_vreg *the_gang;
@@ -202,6 +217,12 @@
static u32 version;
+static int use_efuse_phase_scaling_factor;
+module_param_named(
+ use_phase_scaling_efuse, use_efuse_phase_scaling_factor, int,
+ S_IRUSR | S_IWUSR
+);
+
static int is_between(int left, int right, int value)
{
if (left >= right && left >= value && value >= right)
@@ -304,7 +325,7 @@
}
#define COEFF2_UV_THRESHOLD 850000
-static int get_coeff2(int krait_uV)
+static int get_coeff2(int krait_uV, int phase_scaling_factor)
{
int coeff2 = 0;
int krait_mV = krait_uV / 1000;
@@ -314,6 +335,8 @@
else
coeff2 = (892564 * krait_mV) / 1000 - 449543;
+ coeff2 = coeff2 * phase_scaling_factor / PHASE_SCALING_REF;
+
return coeff2;
}
@@ -330,6 +353,10 @@
int coeff_total = 0;
struct krait_power_vreg *kvreg;
struct pmic_gang_vreg *pvreg = from->pvreg;
+ int phase_scaling_factor = PHASE_SCALING_REF;
+
+ if (use_efuse_phase_scaling_factor)
+ phase_scaling_factor = pvreg->efuse_phase_scaling_factor;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
if (!kvreg->online)
@@ -340,12 +367,14 @@
get_coeff1(kvreg->uV - kvreg->ldo_delta_uV,
kvreg->uV, kvreg->load);
kvreg->coeff2 =
- get_coeff2(kvreg->uV - kvreg->ldo_delta_uV);
+ get_coeff2(kvreg->uV - kvreg->ldo_delta_uV,
+ phase_scaling_factor);
} else {
kvreg->coeff1 =
get_coeff1(pvreg->pmic_vmax_uV,
kvreg->uV, kvreg->load);
- kvreg->coeff2 = get_coeff2(pvreg->pmic_vmax_uV);
+ kvreg->coeff2 = get_coeff2(pvreg->pmic_vmax_uV,
+ phase_scaling_factor);
}
coeff_total += kvreg->coeff1 + kvreg->coeff2;
}
@@ -1226,6 +1255,65 @@
.resume = boot_cpu_mdd_on,
};
+static int __devinit krait_pdn_phase_scaling_init(struct pmic_gang_vreg *pvreg,
+ struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *efuse;
+ u32 efuse_data, efuse_version;
+ bool scaling_factor_valid, use_efuse;
+
+ use_efuse = of_property_read_bool(pdev->dev.of_node,
+ "qcom,use-phase-scaling-factor");
+ /*
+ * Allow usage of the eFuse phase scaling factor if it is enabled in
+ * either device tree or by module parameter.
+ */
+ use_efuse_phase_scaling_factor = use_efuse_phase_scaling_factor
+ || use_efuse;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "phase-scaling-efuse");
+ if (!res || !res->start) {
+ pr_err("phase scaling eFuse address is missing\n");
+ return -EINVAL;
+ }
+
+ efuse = ioremap(res->start, 8);
+ if (!efuse) {
+ pr_err("could not map phase scaling eFuse address\n");
+ return -EINVAL;
+ }
+
+ efuse_data = readl_relaxed(efuse);
+ efuse_version = readl_relaxed(efuse + 4);
+
+ iounmap(efuse);
+
+ scaling_factor_valid
+ = ((efuse_version & PHASE_SCALING_EFUSE_VERSION_MASK) >>
+ PHASE_SCALING_EFUSE_VERSION_POS)
+ == PHASE_SCALING_EFUSE_VERSION_SET;
+
+ if (scaling_factor_valid)
+ pvreg->efuse_phase_scaling_factor
+ = ((efuse_data & PHASE_SCALING_EFUSE_VALUE_MASK)
+ >> PHASE_SCALING_EFUSE_VALUE_POS) + 1;
+ else
+ pvreg->efuse_phase_scaling_factor = PHASE_SCALING_REF;
+
+ pr_info("eFuse phase scaling factor = %d/%d%s\n",
+ pvreg->efuse_phase_scaling_factor, PHASE_SCALING_REF,
+ scaling_factor_valid ? "" : " (eFuse not blown)");
+ pr_info("initial phase scaling factor = %d/%d%s\n",
+ use_efuse_phase_scaling_factor
+ ? pvreg->efuse_phase_scaling_factor : PHASE_SCALING_REF,
+ PHASE_SCALING_REF,
+ use_efuse_phase_scaling_factor ? "" : " (ignoring eFuse)");
+
+ return 0;
+}
+
static int __devinit krait_pdn_probe(struct platform_device *pdev)
{
int rc;
@@ -1269,6 +1357,10 @@
if (pvreg->apcs_gcc_base == NULL)
return -ENOMEM;
+ rc = krait_pdn_phase_scaling_init(pvreg, pdev);
+ if (rc)
+ return rc;
+
pvreg->name = "pmic_gang";
pvreg->pmic_vmax_uV = PMIC_VOLTAGE_MIN;
pvreg->pmic_phase_count = -EINVAL;
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index f0e5ebd..624a27c 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -429,7 +429,7 @@
trace_lpm_resources(rs->sleep_value, rs->name);
}
-static void msm_lpm_set_l2_mode(int sleep_mode, int notify_rpm)
+static void msm_lpm_set_l2_mode(int sleep_mode)
{
int lpm, rc;
@@ -453,7 +453,7 @@
break;
}
- rc = msm_spm_l2_set_low_power_mode(lpm, notify_rpm);
+ rc = msm_spm_l2_set_low_power_mode(lpm, true);
if (rc < 0)
pr_err("%s: Failed to set L2 low power mode %d",
@@ -474,7 +474,7 @@
{
struct msm_lpm_resource *rs = &msm_lpm_l2;
- msm_lpm_set_l2_mode(rs->sleep_value, notify_rpm);
+ msm_lpm_set_l2_mode(rs->sleep_value);
}
int msm_lpm_get_l2_cache_value(struct device_node *node,
@@ -786,7 +786,7 @@
msm_mpm_exit_sleep(from_idle);
if (msm_lpm_l2.valid)
- msm_lpm_set_l2_mode(msm_lpm_l2.rs_data.default_value, false);
+ msm_lpm_set_l2_mode(msm_lpm_l2.rs_data.default_value);
}
static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
index 781cd69..97195e3 100644
--- a/arch/arm/mach-msm/memory_topology.c
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
#include <linux/memory.h>
#include <mach/msm_memtypes.h>
#include <mach/socinfo.h>
+#include <mach/msm_smem.h>
#include "smd_private.h"
#if defined(CONFIG_ARCH_MSM8960)
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 5002a7d..eddf017 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -247,6 +247,11 @@
struct msm_bus_fabric_device *gwfab =
msm_bus_get_fabric_device(fabnodeinfo->
info->node_info->priv_id);
+ if (!gwfab) {
+ MSM_BUS_ERR("Err: No gateway found\n");
+ return -ENXIO;
+ }
+
if (!gwfab->visited) {
MSM_BUS_DBG("VISITED ID: %d\n",
gwfab->id);
@@ -320,6 +325,12 @@
struct msm_bus_fabric_device *fabdev = msm_bus_get_fabric_device
(GET_FABID(curr));
+ if (!fabdev) {
+ MSM_BUS_ERR("Bus device for bus ID: %d not found!\n",
+ GET_FABID(curr));
+ return -ENXIO;
+ }
+
MSM_BUS_DBG("args: %d %d %d %llu %llu %llu %llu %u\n",
curr, GET_NODE(pnode), GET_INDEX(pnode), req_clk, req_bw,
curr_clk, curr_bw, ctx);
@@ -525,6 +536,11 @@
goto err;
}
srcfab = msm_bus_get_fabric_device(GET_FABID(src));
+ if (!srcfab) {
+ MSM_BUS_ERR("Fabric not found\n");
+ goto err;
+ }
+
srcfab->visited = true;
pnode[i] = getpath(src, dest);
bus_for_each_dev(&msm_bus_type, NULL, NULL, clearvisitedflag);
@@ -661,6 +677,12 @@
struct msm_bus_fabric_device *fabdev;
int index, next_pnode;
fabdev = msm_bus_get_fabric_device(GET_FABID(curr));
+ if (!fabdev) {
+ MSM_BUS_ERR("Fabric not found for: %d\n",
+ (GET_FABID(curr)));
+ return -ENXIO;
+ }
+
index = GET_INDEX(pnode);
info = fabdev->algo->find_node(fabdev, curr);
if (!info) {
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index cd6693e..d531aaa 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1460,7 +1460,7 @@
* boundary in future
*/
wmb();
- set_qos_mode(binfo->base, mas_index, 0, 1, 1);
+ set_qos_mode(binfo->base, mas_index, 1, 1, 1);
break;
case BIMC_QOS_MODE_BYPASS:
@@ -1769,8 +1769,13 @@
}
}
+ if (fab_pdata->virt) {
+ MSM_BUS_DBG("Don't get memory regions for virtual fabric\n");
+ goto skip_mem;
+ }
+
bimc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!bimc_mem && !fab_pdata->virt) {
+ if (!bimc_mem) {
MSM_BUS_ERR("Cannot get BIMC Base address\n");
kfree(binfo);
return NULL;
@@ -1792,6 +1797,7 @@
return NULL;
}
+skip_mem:
fab_pdata->hw_data = (void *)binfo;
return (void *)binfo;
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_config.c b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
index c6fa250..858b15e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_config.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -39,7 +39,7 @@
MSM_BUS_DBG("master_port: %d iid: %d fabid%d\n",
master_port, priv_id, GET_FABID(priv_id));
fabdev = msm_bus_get_fabric_device(GET_FABID(priv_id));
- if (IS_ERR(fabdev)) {
+ if (IS_ERR_OR_NULL(fabdev)) {
MSM_BUS_ERR("Fabric device not found for mport: %d\n",
master_port);
return -ENODEV;
@@ -65,7 +65,7 @@
MSM_BUS_DBG("master_port: %d iid: %d fabid: %d\n",
master_port, priv_id, GET_FABID(priv_id));
fabdev = msm_bus_get_fabric_device(GET_FABID(priv_id));
- if (IS_ERR(fabdev)) {
+ if (IS_ERR_OR_NULL(fabdev)) {
MSM_BUS_ERR("Fabric device not found for mport: %d\n",
master_port);
return -ENODEV;
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 2c7ceab..62da5ac 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -364,7 +364,7 @@
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
void *sel_cdata;
- int i;
+ long rounded_rate;
sel_cdata = fabric->cdata[ctx];
@@ -379,8 +379,17 @@
}
/* Enable clocks before accessing QoS registers */
- for (i = 0; i < NUM_CTX; i++)
- clk_prepare_enable(fabric->info.nodeclk[i].clk);
+ if (fabric->info.nodeclk[DUAL_CTX].clk)
+ if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
+ rounded_rate = clk_round_rate(fabric->
+ info.nodeclk[DUAL_CTX].clk, 1);
+ if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
+ rounded_rate))
+ MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
+ fabric->fabdev.id, rounded_rate);
+
+ clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+ }
if (info->iface_clk.clk)
clk_prepare_enable(info->iface_clk.clk);
@@ -392,8 +401,9 @@
master_tiers, add_bw);
/* Disable clocks after accessing QoS registers */
- for (i = 0; i < NUM_CTX; i++)
- clk_disable_unprepare(fabric->info.nodeclk[i].clk);
+ if (fabric->info.nodeclk[DUAL_CTX].clk &&
+ fabric->info.nodeclk[DUAL_CTX].rate == 0)
+ clk_disable_unprepare(fabric->info.nodeclk[DUAL_CTX].clk);
if (info->iface_clk.clk) {
MSM_BUS_DBG("Commented: Will disable clock for info: %d\n",
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_of.c b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
index af3537c..4e25637 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_of.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_of.c
@@ -103,6 +103,11 @@
}
vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
+ if (vec_arr == NULL) {
+ pr_err("Error: Vector array not found\n");
+ goto err;
+ }
+
if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) {
pr_err("Error: Length-error on getting vectors\n");
goto err;
@@ -432,7 +437,7 @@
struct msm_bus_fabric_registration
*msm_bus_of_get_fab_data(struct platform_device *pdev)
{
- struct device_node *of_node = pdev->dev.of_node;
+ struct device_node *of_node;
struct msm_bus_fabric_registration *pdata;
bool mem_err = false;
int ret = 0;
@@ -443,6 +448,7 @@
return NULL;
}
+ of_node = pdev->dev.of_node;
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct msm_bus_fabric_registration), GFP_KERNEL);
if (!pdata) {
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 9e0be63..1a919fc 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1026,6 +1026,9 @@
uint32_t ret1;
uint32_t ret2;
+ if (!msm_dcvs_enabled)
+ return ret;
+
offset = get_core_offset(type, type_core_num);
if (offset < 0)
return ret;
@@ -1277,6 +1280,9 @@
struct kobject *module_kobj = NULL;
int ret = 0;
+ if (!msm_dcvs_enabled)
+ return ret;
+
module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
if (!module_kobj) {
pr_err("%s: cannot find kobject for module %s\n",
@@ -1343,6 +1349,7 @@
ret = msm_dcvs_scm_init(SZ_32K);
if (ret) {
__err("Unable to initialize DCVS err=%d\n", ret);
+ msm_dcvs_enabled = 0;
goto done;
}
diff --git a/arch/arm/mach-msm/msm_smem_iface.h b/arch/arm/mach-msm/msm_smem_iface.h
index bc3e73b..c9c56d9 100644
--- a/arch/arm/mach-msm/msm_smem_iface.h
+++ b/arch/arm/mach-msm/msm_smem_iface.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
#define __ARCH_ARM_MACH_MSM_SMEM_IFACE_H
#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#define MAX_KEY_EVENTS 10
#define MAX_SEC_KEY_PAYLOAD 32
diff --git a/arch/arm/mach-msm/nand_partitions.c b/arch/arm/mach-msm/nand_partitions.c
index ea5fb9c..ad2a10e 100644
--- a/arch/arm/mach-msm/nand_partitions.c
+++ b/arch/arm/mach-msm/nand_partitions.c
@@ -4,7 +4,7 @@
* bootloader.
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2009,2011 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2009,2011,2013 The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -34,7 +34,7 @@
#include <mach/board.h>
#ifdef CONFIG_MSM_SMD
-#include "smd_private.h"
+#include <mach/msm_smem.h>
#endif
/* configuration tags specific to msm */
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index df5ea35..73b58ab 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -22,6 +22,7 @@
#include <mach/subsystem_restart.h>
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 65f86bc..840c90f 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -30,6 +30,7 @@
#include <mach/msm_bus.h>
#include <mach/subsystem_restart.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index b186a4d..098cbd5 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -30,6 +30,7 @@
#include <mach/subsystem_restart.h>
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -329,12 +330,13 @@
drv->crash = true;
+ disable_irq_nosync(drv->irq);
+
if (drv->restart_inprogress) {
pr_err("Ignoring wcnss bite irq, restart in progress\n");
return IRQ_HANDLED;
}
- disable_irq_nosync(drv->irq);
drv->restart_inprogress = true;
restart_wcnss(drv);
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
index f05bcdb..7acb599 100644
--- a/arch/arm/mach-msm/pil-q6v4-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.c
@@ -25,6 +25,7 @@
#include <mach/subsystem_restart.h>
#include <mach/subsystem_notif.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "smd_private.h"
#include "sysmon.h"
diff --git a/arch/arm/mach-msm/pil-q6v4-mss.c b/arch/arm/mach-msm/pil-q6v4-mss.c
index 1821ab1..c4b6038 100644
--- a/arch/arm/mach-msm/pil-q6v4-mss.c
+++ b/arch/arm/mach-msm/pil-q6v4-mss.c
@@ -23,6 +23,7 @@
#include <mach/subsystem_restart.h>
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "smd_private.h"
#include "peripheral-loader.h"
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 04c1be3..19b5671 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -29,6 +29,7 @@
#include <mach/subsystem_notif.h>
#include <mach/scm.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "pil-q6v5.h"
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index d657b05..5ef6638 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -31,6 +31,7 @@
#include <mach/clk.h>
#include <mach/msm_smsm.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "pil-q6v5.h"
@@ -506,7 +507,7 @@
{
struct mba_data *drv = subsys_to_drv(subsys);
- if (!subsys->is_loadable)
+ if (subsys->is_not_loadable)
return 0;
pil_shutdown(&drv->desc);
pil_shutdown(&drv->q6->desc);
@@ -518,7 +519,7 @@
struct mba_data *drv = subsys_to_drv(subsys);
int ret;
- if (!subsys->is_loadable)
+ if (subsys->is_not_loadable)
return 0;
/*
* At this time, the modem is shutdown. Therefore this function cannot
@@ -605,7 +606,7 @@
int ret;
struct mba_data *drv = subsys_to_drv(desc);
- if (!desc->is_loadable)
+ if (desc->is_not_loadable)
return 0;
ret = pil_boot(&drv->q6->desc);
@@ -628,7 +629,7 @@
{
struct mba_data *drv = subsys_to_drv(desc);
- if (!desc->is_loadable)
+ if (desc->is_not_loadable)
return;
pil_shutdown(&drv->desc);
@@ -836,17 +837,18 @@
static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
{
struct mba_data *drv;
- int ret, err_fatal_gpio, is_loadable;
+ int ret, err_fatal_gpio, is_not_loadable;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
platform_set_drvdata(pdev, drv);
- is_loadable = of_property_read_bool(pdev->dev.of_node,
- "qcom,is-loadable");
- if (is_loadable) {
- drv->subsys_desc.is_loadable = 1;
+ is_not_loadable = of_property_read_bool(pdev->dev.of_node,
+ "qcom,is-not-loadable");
+ if (is_not_loadable) {
+ drv->subsys_desc.is_not_loadable = 1;
+ } else {
ret = pil_mss_loadable_init(drv, pdev);
if (ret)
return ret;
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index d72b848..7fd76ab 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -24,6 +24,7 @@
#include <mach/subsystem_restart.h>
#include <mach/ramdump.h>
+#include <mach/msm_smem.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -312,6 +313,7 @@
}
pr_err("riva: smsm state changed to smsm reset\n");
+ wcnss_riva_dump_pmic_regs();
smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
&smem_reset_size);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 4fca346..5e44a4e 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -36,6 +36,7 @@
#include <mach/scm.h>
#include <mach/socinfo.h>
#include <mach/msm-krait-l2-accessors.h>
+#include <mach/msm_bus.h>
#include <asm/cacheflush.h>
#include <asm/hardware/gic.h>
#include <asm/pgtable.h>
@@ -671,7 +672,7 @@
u64 modified_time_ns = modified_time_us * NSEC_PER_USEC;
ktime_t modified_ktime = ns_to_ktime(modified_time_ns);
pm_hrtimer.function = pm_hrtimer_cb;
- hrtimer_start(&pm_hrtimer, modified_ktime, HRTIMER_MODE_ABS);
+ hrtimer_start(&pm_hrtimer, modified_ktime, HRTIMER_MODE_REL);
}
/******************************************************************************
@@ -854,8 +855,10 @@
time = ktime_to_ns(ktime_get());
if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+ int64_t ns = msm_pm_timer_enter_idle();
notify_rpm = true;
- sleep_delay = (uint32_t)msm_pm_timer_enter_idle();
+ do_div(ns, NSEC_PER_SEC / SCLK_HZ);
+ sleep_delay = (uint32_t)ns;
if (sleep_delay == 0) /* 0 would mean infinite time */
sleep_delay = 1;
@@ -1110,6 +1113,36 @@
.enter = msm_pm_enter,
.valid = suspend_valid_only_mem,
};
+
+static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ static struct msm_bus_scale_pdata *msm_pm_bus_pdata;
+ static uint32_t msm_pm_bus_client;
+
+ msm_pm_bus_pdata = msm_bus_cl_get_pdata(pdev);
+
+ if (msm_pm_bus_pdata) {
+ msm_pm_bus_client =
+ msm_bus_scale_register_client(msm_pm_bus_pdata);
+
+ if (!msm_pm_bus_client) {
+ pr_err("%s: Failed to register SNOC client",
+ __func__);
+ rc = -ENXIO;
+ goto snoc_cl_probe_done;
+ }
+
+ rc = msm_bus_scale_client_update_request(msm_pm_bus_client, 1);
+
+ if (rc)
+ pr_err("%s: Error setting bus rate", __func__);
+ }
+
+snoc_cl_probe_done:
+ return rc;
+}
+
static int __devinit msm_cpu_status_probe(struct platform_device *pdev)
{
struct msm_pm_sleep_status_data *pdata;
@@ -1198,6 +1231,21 @@
},
};
+static struct of_device_id msm_snoc_clnt_match_tbl[] = {
+ {.compatible = "qcom,pm-snoc-client"},
+ {},
+};
+
+static struct platform_driver msm_cpu_pm_snoc_client_driver = {
+ .probe = msm_pm_snoc_client_probe,
+ .driver = {
+ .name = "pm_snoc_client",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_snoc_clnt_match_tbl,
+ },
+};
+
+
static int __init msm_pm_setup_saved_state(void)
{
pgd_t *pc_pgd;
@@ -1248,24 +1296,19 @@
static void setup_broadcast_timer(void *arg)
{
- unsigned long reason = (unsigned long)arg;
int cpu = smp_processor_id();
- reason = reason ?
- CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
-
- clockevents_notify(reason, &cpu);
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
}
static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
unsigned long action, void *hcpu)
{
- int hotcpu = (unsigned long)hcpu;
+ int cpu = (unsigned long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
- smp_call_function_single(hotcpu, setup_broadcast_timer,
- (void *)true, 1);
+ smp_call_function_single(cpu, setup_broadcast_timer, NULL, 1);
break;
}
@@ -1288,14 +1331,11 @@
msm_pm_mode_sysfs_add();
msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
suspend_set_ops(&msm_pm_ops);
- hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
msm_cpuidle_init();
if (msm_pm_pc_reset_timer) {
- get_cpu();
- smp_call_function_many(cpu_online_mask, setup_broadcast_timer,
- (void *)true, 1);
- put_cpu();
+ on_each_cpu(setup_broadcast_timer, NULL, 1);
register_cpu_notifier(&setup_broadcast_notifier);
}
@@ -1546,6 +1586,14 @@
return rc;
}
+ rc = platform_driver_register(&msm_cpu_pm_snoc_client_driver);
+
+ if (rc) {
+ pr_err("%s(): failed to register driver %s\n", __func__,
+ msm_cpu_pm_snoc_client_driver.driver.name);
+ return rc;
+ }
+
return platform_driver_register(&msm_pm_8x60_driver);
}
device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index a2da8b0..9f97a59 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -3,7 +3,7 @@
* MSM Power Management Routines
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2013 The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -44,9 +44,10 @@
#endif
#include <mach/socinfo.h>
#include <mach/proc_comm.h>
+#include <mach/msm_smem.h>
+#include <mach/msm_smsm.h>
#include <asm/smp_scu.h>
-#include "smd_private.h"
#include "smd_rpcrouter.h"
#include "acpuclock.h"
#include "clock.h"
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index ea22c12..b5ccc31 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -786,7 +786,7 @@
goto done;
}
- if (size <= 0) {
+ if ((size <= 0) || (size > sizeof(data))) {
pr_err("%s: Invalid size sent to driver: %d\n",
__func__, size);
result = -EFAULT;
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index c9bc3d7..5303009 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -22,10 +22,15 @@
#include <linux/of_device.h>
#include <linux/msm_audio_ion.h>
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
+
struct msm_audio_ion_private {
bool smmu_enabled;
- /*u32 group_id;*/
- /*u32 domain_id;*/
+ bool audioheap_enabled;
+ struct iommu_group *group;
+ u32 domain_id;
+ struct iommu_domain *domain;
};
static struct msm_audio_ion_private msm_audio_ion_data = {0,};
@@ -49,10 +54,22 @@
goto err;
}
- *handle = ion_alloc(*client, bufsz, SZ_4K, (0x1<<ION_AUDIO_HEAP_ID), 0);
+ *handle = ion_alloc(*client, bufsz, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL((void *) (*handle))) {
- pr_err("%s: ION memory allocation for AUDIO failed\n",
- __func__);
+ pr_debug("system heap is used");
+ msm_audio_ion_data.audioheap_enabled = 0;
+ *handle = ion_alloc(*client, bufsz, SZ_4K,
+ ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
+
+ } else {
+ pr_debug("audio heap is used");
+ msm_audio_ion_data.audioheap_enabled = 1;
+ }
+
+ if (IS_ERR_OR_NULL((void *) (*handle))) {
+ pr_err("%s: ION memory allocation for AUDIO failed rc=%d, smmu_enabled=%d\n",
+ __func__, rc, msm_audio_ion_data.smmu_enabled);
goto err_ion_client;
}
@@ -63,15 +80,17 @@
goto err_ion_handle;
}
- /*Need to add condition SMMU enable or not */
*vaddr = ion_map_kernel(*client, *handle);
if (IS_ERR_OR_NULL((void *)*vaddr)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
goto err_ion_handle;
}
+ pr_debug("%s: mapped address = %p, size=%d\n", __func__, *vaddr, bufsz);
- if (bufsz != 0)
+ if (bufsz != 0) {
+ pr_debug("%s: memset to 0 %p %d\n", __func__, *vaddr, bufsz);
memset((void *)*vaddr, 0, bufsz);
+ }
return 0;
@@ -81,7 +100,6 @@
msm_audio_ion_client_destroy(*client);
err:
return -EINVAL;
-
}
int msm_audio_ion_import(const char *name, struct ion_client **client,
@@ -125,13 +143,6 @@
goto err_ion_handle;
}
- /*Need to add condition SMMU enable or not */
- *vaddr = ion_map_kernel(*client, *handle);
- if (IS_ERR_OR_NULL((void *)*vaddr)) {
- pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
- goto err_ion_handle;
- }
-
if (bufsz != 0)
memset((void *)*vaddr, 0, bufsz);
@@ -142,12 +153,20 @@
msm_audio_ion_client_destroy(*client);
err:
return -EINVAL;
-
}
int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle)
{
- /* add condition for SMMU enabled */
+ if (msm_audio_ion_data.smmu_enabled) {
+ /* Need to populate book kept infomation */
+ pr_debug("client=%p, domain=%p, domain_id=%d, group=%p",
+ client, msm_audio_ion_data.domain,
+ msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
+
+ ion_unmap_iommu(client, handle,
+ msm_audio_ion_data.domain_id, 0);
+ }
+
ion_unmap_kernel(client, handle);
ion_free(client, handle);
@@ -155,6 +174,91 @@
return 0;
}
+int msm_audio_ion_mmap(struct audio_buffer *ab,
+ struct vm_area_struct *vma)
+{
+ struct sg_table *table;
+ unsigned long addr = vma->vm_start;
+ unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
+ struct scatterlist *sg;
+ unsigned int i;
+ struct page *page;
+ int ret;
+
+ pr_debug("%s\n", __func__);
+
+ table = ion_sg_table(ab->client, ab->handle);
+
+ if (IS_ERR(table)) {
+ pr_err("%s: Unable to get sg_table from ion: %ld\n",
+ __func__, PTR_ERR(table));
+ return PTR_ERR(table);
+ } else if (!table) {
+ pr_err("%s: sg_list is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ /* uncached */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ /* We need to check if a page is associated with this sg list because:
+ * If the allocation came from a carveout we currently don't have
+ * pages associated with carved out memory. This might change in the
+ * future and we can remove this check and the else statement.
+ */
+ page = sg_page(table->sgl);
+ if (page) {
+ pr_debug("%s: page is NOT null\n", __func__);
+ for_each_sg(table->sgl, sg, table->nents, i) {
+ unsigned long remainder = vma->vm_end - addr;
+ unsigned long len = sg_dma_len(sg);
+
+ page = sg_page(sg);
+
+ if (offset >= sg_dma_len(sg)) {
+ offset -= sg_dma_len(sg);
+ continue;
+ } else if (offset) {
+ page += offset / PAGE_SIZE;
+ len = sg_dma_len(sg) - offset;
+ offset = 0;
+ }
+ len = min(len, remainder);
+ pr_debug("vma=%p, addr=%x len=%ld vm_start=%x vm_end=%x vm_page_prot=%ld\n",
+ vma, (unsigned int)addr, len,
+ (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end,
+ (unsigned long int)vma->vm_page_prot);
+ remap_pfn_range(vma, addr, page_to_pfn(page), len,
+ vma->vm_page_prot);
+ addr += len;
+ if (addr >= vma->vm_end)
+ return 0;
+ }
+ } else {
+ ion_phys_addr_t phys_addr;
+ size_t phys_len;
+ pr_debug("%s: page is NULL\n", __func__);
+
+ ret = ion_phys(ab->client, ab->handle, &phys_addr, &phys_len);
+ if (ret) {
+ pr_err("%s: Unable to get phys address from ION buffer: %d\n"
+ , __func__ , ret);
+ return ret;
+ }
+ pr_debug("phys=%x len=%d\n", (unsigned int)phys_addr, phys_len);
+ pr_debug("vma=%p, vm_start=%x vm_end=%x vm_pgoff=%ld vm_page_prot=%ld\n",
+ vma, (unsigned int)vma->vm_start,
+ (unsigned int)vma->vm_end, vma->vm_pgoff,
+ (unsigned long int)vma->vm_page_prot);
+ ret = remap_pfn_range(vma, vma->vm_start,
+ __phys_to_pfn(phys_addr) + vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+ }
+ return 0;
+}
+
bool msm_audio_ion_is_smmu_available(void)
{
@@ -165,18 +269,17 @@
struct ion_client *msm_audio_ion_client_create(unsigned int heap_mask,
const char *name)
{
- pr_debug("%s: smmu_enabled = %d\n", __func__,
- msm_audio_ion_data.smmu_enabled);
-
-
- return msm_ion_client_create(heap_mask, name);
+ struct ion_client *pclient = NULL;
+ /*IOMMU group and domain are moved to probe()*/
+ pclient = msm_ion_client_create(heap_mask, name);
+ return pclient;
}
void msm_audio_ion_client_destroy(struct ion_client *client)
{
- pr_debug("%s: smmu_enabled = %d\n", __func__,
- msm_audio_ion_data.smmu_enabled);
+ pr_debug("%s: client = %p smmu_enabled = %d\n", __func__,
+ client, msm_audio_ion_data.smmu_enabled);
ion_client_destroy(client);
}
@@ -192,9 +295,9 @@
bufsz should be 0 and fd shouldn't be 0 as of now
*/
*handle = ion_import_dma_buf(client, fd);
- pr_err("%s: DMA Buf name=%s, fd=%d handle=%p\n", __func__,
+ pr_debug("%s: DMA Buf name=%s, fd=%d handle=%p\n", __func__,
name, fd, *handle);
- if (IS_ERR_OR_NULL((void *) (*handle))) {
+ if (IS_ERR_OR_NULL((void *)(*handle))) {
pr_err("%s: ion import dma buffer failed\n",
__func__);
goto err_ion_handle;
@@ -245,6 +348,41 @@
return 0;
}
+int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op)
+{
+ unsigned long ionflag = 0;
+ int rc = 0;
+ int msm_cache_ops = 0;
+
+ if (!abuff) {
+ pr_err("Invalid params: %p, %p\n", __func__, abuff);
+ return -EINVAL;
+ }
+ rc = ion_handle_get_flags(abuff->client, abuff->handle,
+ &ionflag);
+ if (rc) {
+ pr_err("ion_handle_get_flags failed: %d\n", rc);
+ goto cache_op_failed;
+ }
+
+ /* has to be CACHED */
+ if (ION_IS_CACHED(ionflag)) {
+ /* ION_IOC_INV_CACHES or ION_IOC_CLEAN_CACHES */
+ msm_cache_ops = cache_op;
+ rc = msm_ion_do_cache_op(abuff->client,
+ abuff->handle,
+ (unsigned long *) abuff->data,
+ (unsigned long)abuff->size,
+ msm_cache_ops);
+ if (rc) {
+ pr_err("cache operation failed %d\n", rc);
+ goto cache_op_failed;
+ }
+ }
+cache_op_failed:
+ return rc;
+}
+
static int msm_audio_ion_get_phys(struct ion_client *client,
struct ion_handle *handle,
@@ -255,18 +393,25 @@
msm_audio_ion_data.smmu_enabled);
if (msm_audio_ion_data.smmu_enabled) {
- /* SMMU enabled case ion_map_iommu()*/
+ rc = ion_map_iommu(client, handle, msm_audio_ion_data.domain_id,
+ 0 /*partition_num*/, SZ_4K /*align*/, 0/*iova_length*/,
+ addr, (unsigned long *)len,
+ 0, 0);
+ if (rc) {
+ pr_err("%s: ION map iommu failed %d\n", __func__, rc);
+ return rc;
+ }
+ pr_debug("client=%p, domain=%p, domain_id=%d, group=%p",
+ client, msm_audio_ion_data.domain,
+ msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
} else {
/* SMMU is disabled*/
rc = ion_phys(client, handle, addr, len);
}
- pr_debug("%s: addr= 0x%p, len= %d\n", __func__, addr, *len);
+ pr_debug("phys=%x, len=%d, rc=%d\n", (unsigned int)*addr, *len, rc);
return rc;
}
-
-
-
static int msm_audio_ion_probe(struct platform_device *pdev)
{
int rc = 0;
@@ -283,13 +428,53 @@
msm_audio_ion_dt);
msm_audio_ion_data.smmu_enabled = smmu_enabled;
+ if (smmu_enabled) {
+ msm_audio_ion_data.group = iommu_group_find("lpass_audio");
+ if (!msm_audio_ion_data.group) {
+ pr_debug("Failed to find group lpass_audio deferred\n");
+ goto fail_group;
+ }
+ msm_audio_ion_data.domain =
+ iommu_group_get_iommudata(msm_audio_ion_data.group);
+ if (IS_ERR_OR_NULL(msm_audio_ion_data.domain)) {
+ pr_err("Failed to get domain data for group %p",
+ msm_audio_ion_data.group);
+ goto fail_group;
+ }
+ msm_audio_ion_data.domain_id =
+ msm_find_domain_no(msm_audio_ion_data.domain);
+ if (msm_audio_ion_data.domain_id < 0) {
+ pr_err("Failed to get domain index for domain %p",
+ msm_audio_ion_data.domain);
+ goto fail_group;
+ }
+ pr_debug("domain=%p, domain_id=%d, group=%p",
+ msm_audio_ion_data.domain,
+ msm_audio_ion_data.domain_id, msm_audio_ion_data.group);
+
+ /* iommu_attach_group() will make AXI clock ON. For future PL
+ this will require to be called in once per session */
+ rc = iommu_attach_group(msm_audio_ion_data.domain,
+ msm_audio_ion_data.group);
+ if (rc) {
+ pr_err("%s:ION attach group failed %d\n", __func__, rc);
+ return rc;
+ }
+
+ }
+
pr_debug("%s: SMMU-Enabled = %d\n", __func__, smmu_enabled);
return rc;
+
+fail_group:
+ return -EPROBE_DEFER;
}
static int msm_audio_ion_remove(struct platform_device *pdev)
{
- pr_debug("%s: msm audio ion is unloaded\n", __func__);
+ pr_debug("%s: msm audio ion is unloaded, domain=%p, group=%p\n",
+ __func__, msm_audio_ion_data.domain, msm_audio_ion_data.group);
+ iommu_detach_group(msm_audio_ion_data.domain, msm_audio_ion_data.group);
return 0;
}
diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c
index 62e3e05..a9ebd7c 100644
--- a/arch/arm/mach-msm/remote_spinlock.c
+++ b/arch/arm/mach-msm/remote_spinlock.c
@@ -25,6 +25,7 @@
#include <mach/msm_iomap.h>
#include <mach/remote_spinlock.h>
#include <mach/dal.h>
+#include <mach/msm_smem.h>
#include "smd_private.h"
diff --git a/arch/arm/mach-msm/rmt_storage_client.c b/arch/arm/mach-msm/rmt_storage_client.c
index a4562e9..550624c 100644
--- a/arch/arm/mach-msm/rmt_storage_client.c
+++ b/arch/arm/mach-msm/rmt_storage_client.c
@@ -35,7 +35,7 @@
#ifdef CONFIG_MSM_SDIO_SMEM
#include <mach/sdio_smem.h>
#endif
-#include "smd_private.h"
+#include <mach/msm_smem.h>
enum {
RMT_STORAGE_EVNT_OPEN = 0,
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 6ed80f6..1eb66f4 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -1349,7 +1349,8 @@
smd_disable_read_intr(msm_rpm_data.ch_info);
if (!standalone) {
- msm_rpm_smd_wq = create_singlethread_workqueue("rpm-smd");
+ msm_rpm_smd_wq = alloc_workqueue("rpm-smd",
+ WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
if (!msm_rpm_smd_wq)
return -EINVAL;
queue_work(msm_rpm_smd_wq, &msm_rpm_data.work);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 3590e6b..a177593 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -47,11 +47,13 @@
#include <mach/msm_ipc_logging.h>
#include <mach/ramdump.h>
#include <mach/board.h>
+#include <mach/msm_smem.h>
#include <asm/cacheflush.h>
#include "smd_private.h"
#include "modem_notifier.h"
+#include "smem_private.h"
#if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
@@ -175,16 +177,6 @@
},
};
-struct smem_area {
- phys_addr_t phys_addr;
- resource_size_t size;
- void __iomem *virt_addr;
-};
-static uint32_t num_smem_areas;
-static struct smem_area *smem_areas;
-static struct ramdump_segment *smem_ramdump_segments;
-static void *smem_ramdump_dev;
-static void *smem_phys_to_virt(phys_addr_t base, unsigned offset);
static void *smd_dev;
struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
@@ -380,9 +372,6 @@
#define SMD_LOOPBACK_CID 100
-#define SMEM_SPINLOCK_SMEM_ALLOC "S:3"
-static remote_spinlock_t remote_spinlock;
-
static LIST_HEAD(smd_ch_list_loopback);
static void smd_fake_irq_handler(unsigned long arg);
static void smsm_cb_snapshot(uint32_t use_wakelock);
@@ -392,7 +381,6 @@
static DECLARE_WORK(smsm_cb_work, notify_smsm_cb_clients_worker);
static DEFINE_MUTEX(smsm_lock);
static struct smsm_state_info *smsm_states;
-static int spinlocks_initialized;
/**
* Variables to indicate smd module initialization.
@@ -2408,222 +2396,6 @@
}
EXPORT_SYMBOL(smd_is_pkt_avail);
-
-/* -------------------------------------------------------------------------- */
-
-/**
- * smem_phys_to_virt() - Convert a physical base and offset to virtual address
- *
- * @base: physical base address to check
- * @offset: offset from the base to get the final address
- * @returns: virtual SMEM address; NULL for failure
- *
- * Takes a physical address and an offset and checks if the resulting physical
- * address would fit into one of the smem regions. If so, returns the
- * corresponding virtual address. Otherwise returns NULL.
- */
-static void *smem_phys_to_virt(phys_addr_t base, unsigned offset)
-{
- int i;
- phys_addr_t phys_addr;
- resource_size_t size;
-
- if (OVERFLOW_ADD_UNSIGNED(phys_addr_t, base, offset))
- return NULL;
-
- if (!smem_areas) {
- /*
- * Early boot - no area configuration yet, so default
- * to using the main memory region.
- *
- * To remove the MSM_SHARED_RAM_BASE and the static
- * mapping of SMEM in the future, add dump_stack()
- * to identify the early callers of smem_get_entry()
- * (which calls this function) and replace those calls
- * with a new function that knows how to lookup the
- * SMEM base address before SMEM has been probed.
- */
- phys_addr = msm_shared_ram_phys;
- size = MSM_SHARED_RAM_SIZE;
-
- if (base >= phys_addr && base + offset < phys_addr + size) {
- if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
- (uintptr_t)MSM_SHARED_RAM_BASE, offset)) {
- pr_err("%s: overflow %p %x\n", __func__,
- MSM_SHARED_RAM_BASE, offset);
- return NULL;
- }
-
- return MSM_SHARED_RAM_BASE + offset;
- } else {
- return NULL;
- }
- }
- for (i = 0; i < num_smem_areas; ++i) {
- phys_addr = smem_areas[i].phys_addr;
- size = smem_areas[i].size;
-
- if (base < phys_addr || base + offset >= phys_addr + size)
- continue;
-
- if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
- (uintptr_t)smem_areas[i].virt_addr, offset)) {
- pr_err("%s: overflow %p %x\n", __func__,
- smem_areas[i].virt_addr, offset);
- return NULL;
- }
-
- return smem_areas[i].virt_addr + offset;
- }
-
- return NULL;
-}
-
-/**
- * smem_virt_to_phys() - Convert SMEM address to physical address.
- *
- * @smem_address: Address of SMEM item (returned by smem_alloc(), etc)
- * @returns: Physical address (or NULL if there is a failure)
- *
- * This function should only be used if an SMEM item needs to be handed
- * off to a DMA engine.
- */
-phys_addr_t smem_virt_to_phys(void *smem_address)
-{
- phys_addr_t phys_addr = 0;
- int i;
- void *vend;
-
- if (!smem_areas)
- return phys_addr;
-
- for (i = 0; i < num_smem_areas; ++i) {
- vend = (void *)(smem_areas[i].virt_addr + smem_areas[i].size);
-
- if (smem_address >= smem_areas[i].virt_addr &&
- smem_address < vend) {
- phys_addr = smem_address - smem_areas[i].virt_addr;
- phys_addr += smem_areas[i].phys_addr;
- break;
- }
- }
-
- return phys_addr;
-}
-EXPORT_SYMBOL(smem_virt_to_phys);
-
-/* smem_alloc returns the pointer to smem item if it is already allocated.
- * Otherwise, it returns NULL.
- */
-void *smem_alloc(unsigned id, unsigned size)
-{
- return smem_find(id, size);
-}
-EXPORT_SYMBOL(smem_alloc);
-
-/* smem_alloc2 returns the pointer to smem item. If it is not allocated,
- * it allocates it and then returns the pointer to it.
- */
-void *smem_alloc2(unsigned id, unsigned size_in)
-{
- struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
- struct smem_heap_entry *toc = shared->heap_toc;
- unsigned long flags;
- void *ret = NULL;
-
- if (!shared->heap_info.initialized) {
- pr_err("%s: smem heap info not initialized\n", __func__);
- return NULL;
- }
-
- if (id >= SMEM_NUM_ITEMS)
- return NULL;
-
- size_in = ALIGN(size_in, 8);
- remote_spin_lock_irqsave(&remote_spinlock, flags);
- if (toc[id].allocated) {
- SMD_DBG("%s: %u already allocated\n", __func__, id);
- if (size_in != toc[id].size)
- pr_err("%s: wrong size %u (expected %u)\n",
- __func__, toc[id].size, size_in);
- else
- ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
- } else if (id > SMEM_FIXED_ITEM_LAST) {
- SMD_DBG("%s: allocating %u\n", __func__, id);
- if (shared->heap_info.heap_remaining >= size_in) {
- toc[id].offset = shared->heap_info.free_offset;
- toc[id].size = size_in;
- wmb();
- toc[id].allocated = 1;
-
- shared->heap_info.free_offset += size_in;
- shared->heap_info.heap_remaining -= size_in;
- ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
- } else
- pr_err("%s: not enough memory %u (required %u)\n",
- __func__, shared->heap_info.heap_remaining,
- size_in);
- }
- wmb();
- remote_spin_unlock_irqrestore(&remote_spinlock, flags);
- return ret;
-}
-EXPORT_SYMBOL(smem_alloc2);
-
-void *smem_get_entry(unsigned id, unsigned *size)
-{
- struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
- struct smem_heap_entry *toc = shared->heap_toc;
- int use_spinlocks = spinlocks_initialized;
- void *ret = 0;
- unsigned long flags = 0;
-
- if (id >= SMEM_NUM_ITEMS)
- return ret;
-
- if (use_spinlocks)
- remote_spin_lock_irqsave(&remote_spinlock, flags);
- /* toc is in device memory and cannot be speculatively accessed */
- if (toc[id].allocated) {
- phys_addr_t phys_base;
-
- *size = toc[id].size;
- barrier();
-
- phys_base = toc[id].reserved & BASE_ADDR_MASK;
- if (!phys_base)
- phys_base = (phys_addr_t)msm_shared_ram_phys;
- ret = smem_phys_to_virt(phys_base, toc[id].offset);
- } else {
- *size = 0;
- }
- if (use_spinlocks)
- remote_spin_unlock_irqrestore(&remote_spinlock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(smem_get_entry);
-
-void *smem_find(unsigned id, unsigned size_in)
-{
- unsigned size;
- void *ptr;
-
- ptr = smem_get_entry(id, &size);
- if (!ptr)
- return 0;
-
- size_in = ALIGN(size_in, 8);
- if (size_in != size) {
- pr_err("smem_find(%d, %d): wrong size %d\n",
- id, size_in, size);
- return 0;
- }
-
- return ptr;
-}
-EXPORT_SYMBOL(smem_find);
-
static int smsm_cb_init(void)
{
struct smsm_state_info *state_info;
@@ -3313,17 +3085,6 @@
}
EXPORT_SYMBOL(smsm_state_cb_deregister);
-/**
- * smem_get_remote_spinlock - Remote spinlock pointer for unit testing.
- *
- * @returns: pointer to SMEM remote spinlock
- */
-remote_spinlock_t *smem_get_remote_spinlock(void)
-{
- return &remote_spinlock;
-}
-EXPORT_SYMBOL(smem_get_remote_spinlock);
-
int smd_module_init_notifier_register(struct notifier_block *nb)
{
int ret;
@@ -4126,23 +3887,6 @@
remote_spin_release(&remote_spinlock, notifier->processor);
remote_spin_release_all(notifier->processor);
- if (smem_ramdump_dev) {
- int ret;
-
- SMD_INFO("%s: saving ramdump\n", __func__);
- /*
- * XPU protection does not currently allow the
- * auxiliary memory regions to be dumped. If this
- * changes, then num_smem_areas + 1 should be passed
- * into do_elf_ramdump() to dump all regions.
- */
- ret = do_elf_ramdump(smem_ramdump_dev,
- smem_ramdump_segments, 1);
- if (ret < 0)
- pr_err("%s: unable to dump smem %d\n", __func__,
- ret);
- }
-
smd_channel_reset(notifier->processor);
}
@@ -4155,13 +3899,6 @@
void *handle;
struct restart_notifier_block *nb;
- smem_ramdump_dev = create_ramdump_device("smem-smd", smd_dev);
- if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
- pr_err("%s: Unable to create smem ramdump device.\n",
- __func__);
- smem_ramdump_dev = NULL;
- }
-
for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
nb = &restart_notifiers[i];
handle = subsys_notif_register_notifier(nb->name, &nb->nb);
@@ -4202,12 +3939,11 @@
}
registered = true;
- rc = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
+ rc = init_smem_remote_spinlock();
if (rc) {
pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
return rc;
}
- spinlocks_initialized = 1;
rc = platform_driver_register(&msm_smd_driver);
if (rc) {
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index 4dcf72f..b66e258 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -21,8 +21,10 @@
#include <linux/jiffies.h>
#include <mach/msm_iomap.h>
+#include <mach/msm_smem.h>
#include "smd_private.h"
+#include "smem_private.h"
#if defined(CONFIG_DEBUG_FS)
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 4a6a509..4fe9592 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -34,37 +34,6 @@
#define VERSION_MODEM 9
#define VERSION_DSPS 10
-#define SMD_HEAP_SIZE 512
-
-struct smem_heap_info {
- unsigned initialized;
- unsigned free_offset;
- unsigned heap_remaining;
- unsigned reserved;
-};
-
-struct smem_heap_entry {
- unsigned allocated;
- unsigned offset;
- unsigned size;
- unsigned reserved; /* bits 1:0 reserved, bits 31:2 aux smem base addr */
-};
-#define BASE_ADDR_MASK 0xfffffffc
-
-struct smem_proc_comm {
- unsigned command;
- unsigned status;
- unsigned data1;
- unsigned data2;
-};
-
-struct smem_shared {
- struct smem_proc_comm proc_comm[4];
- unsigned version[32];
- struct smem_heap_info heap_info;
- struct smem_heap_entry heap_toc[SMD_HEAP_SIZE];
-};
-
#if defined(CONFIG_MSM_SMD_PKG4)
struct smsm_interrupt_info {
uint32_t aArm_en_mask;
@@ -313,7 +282,4 @@
uint32_t smsm_interrupt_id;
};
extern struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
-
-/* used for unit testing spinlocks */
-remote_spinlock_t *smem_get_remote_spinlock(void);
#endif
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
new file mode 100644
index 0000000..2204609
--- /dev/null
+++ b/arch/arm/mach-msm/smem.c
@@ -0,0 +1,403 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/printk.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_smem.h>
+#include <mach/ramdump.h>
+#include <mach/subsystem_notif.h>
+
+#include "smem_private.h"
+
+/**
+ * OVERFLOW_ADD_UNSIGNED() - check for unsigned overflow
+ *
+ * @type: type to check for overflow
+ * @a: left value to use
+ * @b: right value to use
+ * @returns: true if a + b will result in overflow; false otherwise
+ */
+#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
+ (((type)~0 - (a)) < (b) ? true : false)
+
+enum {
+ MSM_SMEM_DEBUG = 1U << 0,
+ MSM_SMEM_INFO = 1U << 1,
+};
+
+static int msm_smem_debug_mask;
+module_param_named(debug_mask, msm_smem_debug_mask,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SMEM_DBG(x...) do { \
+ if (msm_smem_debug_mask & MSM_SMEM_DEBUG) \
+ pr_debug(x); \
+ } while (0)
+
+remote_spinlock_t remote_spinlock;
+int spinlocks_initialized;
+uint32_t num_smem_areas;
+struct smem_area *smem_areas;
+struct ramdump_segment *smem_ramdump_segments;
+
+static void *smem_ramdump_dev;
+static DEFINE_MUTEX(spinlock_init_lock);
+
+struct restart_notifier_block {
+ unsigned processor;
+ char *name;
+ struct notifier_block nb;
+};
+
+static int restart_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data);
+
+static struct restart_notifier_block restart_notifiers[] = {
+ {SMEM_MODEM, "modem", .nb.notifier_call = restart_notifier_cb},
+ {SMEM_Q6, "lpass", .nb.notifier_call = restart_notifier_cb},
+ {SMEM_WCNSS, "wcnss", .nb.notifier_call = restart_notifier_cb},
+ {SMEM_DSPS, "dsps", .nb.notifier_call = restart_notifier_cb},
+ {SMEM_MODEM, "gss", .nb.notifier_call = restart_notifier_cb},
+ {SMEM_Q6, "adsp", .nb.notifier_call = restart_notifier_cb},
+};
+
+/**
+ * smem_phys_to_virt() - Convert a physical base and offset to virtual address
+ *
+ * @base: physical base address to check
+ * @offset: offset from the base to get the final address
+ * @returns: virtual SMEM address; NULL for failure
+ *
+ * Takes a physical address and an offset and checks if the resulting physical
+ * address would fit into one of the smem regions. If so, returns the
+ * corresponding virtual address. Otherwise returns NULL.
+ */
+static void *smem_phys_to_virt(phys_addr_t base, unsigned offset)
+{
+ int i;
+ phys_addr_t phys_addr;
+ resource_size_t size;
+
+ if (OVERFLOW_ADD_UNSIGNED(phys_addr_t, base, offset))
+ return NULL;
+
+ if (!smem_areas) {
+ /*
+ * Early boot - no area configuration yet, so default
+ * to using the main memory region.
+ *
+ * To remove the MSM_SHARED_RAM_BASE and the static
+ * mapping of SMEM in the future, add dump_stack()
+ * to identify the early callers of smem_get_entry()
+ * (which calls this function) and replace those calls
+ * with a new function that knows how to lookup the
+ * SMEM base address before SMEM has been probed.
+ */
+ phys_addr = msm_shared_ram_phys;
+ size = MSM_SHARED_RAM_SIZE;
+
+ if (base >= phys_addr && base + offset < phys_addr + size) {
+ if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+ (uintptr_t)MSM_SHARED_RAM_BASE, offset)) {
+ pr_err("%s: overflow %p %x\n", __func__,
+ MSM_SHARED_RAM_BASE, offset);
+ return NULL;
+ }
+
+ return MSM_SHARED_RAM_BASE + offset;
+ } else {
+ return NULL;
+ }
+ }
+ for (i = 0; i < num_smem_areas; ++i) {
+ phys_addr = smem_areas[i].phys_addr;
+ size = smem_areas[i].size;
+
+ if (base < phys_addr || base + offset >= phys_addr + size)
+ continue;
+
+ if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+ (uintptr_t)smem_areas[i].virt_addr, offset)) {
+ pr_err("%s: overflow %p %x\n", __func__,
+ smem_areas[i].virt_addr, offset);
+ return NULL;
+ }
+
+ return smem_areas[i].virt_addr + offset;
+ }
+
+ return NULL;
+}
+
+/**
+ * smem_virt_to_phys() - Convert SMEM address to physical address.
+ *
+ * @smem_address: Address of SMEM item (returned by smem_alloc(), etc)
+ * @returns: Physical address (or NULL if there is a failure)
+ *
+ * This function should only be used if an SMEM item needs to be handed
+ * off to a DMA engine.
+ */
+phys_addr_t smem_virt_to_phys(void *smem_address)
+{
+ phys_addr_t phys_addr = 0;
+ int i;
+ void *vend;
+
+ if (!smem_areas)
+ return phys_addr;
+
+ for (i = 0; i < num_smem_areas; ++i) {
+ vend = (void *)(smem_areas[i].virt_addr + smem_areas[i].size);
+
+ if (smem_address >= smem_areas[i].virt_addr &&
+ smem_address < vend) {
+ phys_addr = smem_address - smem_areas[i].virt_addr;
+ phys_addr += smem_areas[i].phys_addr;
+ break;
+ }
+ }
+
+ return phys_addr;
+}
+EXPORT_SYMBOL(smem_virt_to_phys);
+
+/* smem_alloc returns the pointer to smem item if it is already allocated.
+ * Otherwise, it returns NULL.
+ */
+void *smem_alloc(unsigned id, unsigned size)
+{
+ return smem_find(id, size);
+}
+EXPORT_SYMBOL(smem_alloc);
+
+void *smem_find(unsigned id, unsigned size_in)
+{
+ unsigned size;
+ void *ptr;
+
+ ptr = smem_get_entry(id, &size);
+ if (!ptr)
+ return 0;
+
+ size_in = ALIGN(size_in, 8);
+ if (size_in != size) {
+ pr_err("smem_find(%d, %d): wrong size %d\n",
+ id, size_in, size);
+ return 0;
+ }
+
+ return ptr;
+}
+EXPORT_SYMBOL(smem_find);
+
+/* smem_alloc2 returns the pointer to smem item. If it is not allocated,
+ * it allocates it and then returns the pointer to it.
+ */
+void *smem_alloc2(unsigned id, unsigned size_in)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ struct smem_heap_entry *toc = shared->heap_toc;
+ unsigned long flags;
+ void *ret = NULL;
+ int rc;
+
+ if (!shared->heap_info.initialized) {
+ pr_err("%s: smem heap info not initialized\n", __func__);
+ return NULL;
+ }
+
+ if (id >= SMEM_NUM_ITEMS)
+ return NULL;
+
+ if (unlikely(!spinlocks_initialized)) {
+ rc = init_smem_remote_spinlock();
+ if (unlikely(rc)) {
+ pr_err("%s: remote spinlock init failed %d\n",
+ __func__, rc);
+ return NULL;
+ }
+ }
+
+ size_in = ALIGN(size_in, 8);
+ remote_spin_lock_irqsave(&remote_spinlock, flags);
+ if (toc[id].allocated) {
+ SMEM_DBG("%s: %u already allocated\n", __func__, id);
+ if (size_in != toc[id].size)
+ pr_err("%s: wrong size %u (expected %u)\n",
+ __func__, toc[id].size, size_in);
+ else
+ ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
+ } else if (id > SMEM_FIXED_ITEM_LAST) {
+ SMEM_DBG("%s: allocating %u\n", __func__, id);
+ if (shared->heap_info.heap_remaining >= size_in) {
+ toc[id].offset = shared->heap_info.free_offset;
+ toc[id].size = size_in;
+ wmb();
+ toc[id].allocated = 1;
+
+ shared->heap_info.free_offset += size_in;
+ shared->heap_info.heap_remaining -= size_in;
+ ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
+ } else
+ pr_err("%s: not enough memory %u (required %u)\n",
+ __func__, shared->heap_info.heap_remaining,
+ size_in);
+ }
+ wmb();
+ remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(smem_alloc2);
+
+void *smem_get_entry(unsigned id, unsigned *size)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ struct smem_heap_entry *toc = shared->heap_toc;
+ int use_spinlocks = spinlocks_initialized;
+ void *ret = 0;
+ unsigned long flags = 0;
+
+ if (id >= SMEM_NUM_ITEMS)
+ return ret;
+
+ if (use_spinlocks)
+ remote_spin_lock_irqsave(&remote_spinlock, flags);
+ /* toc is in device memory and cannot be speculatively accessed */
+ if (toc[id].allocated) {
+ phys_addr_t phys_base;
+
+ *size = toc[id].size;
+ barrier();
+
+ phys_base = toc[id].reserved & BASE_ADDR_MASK;
+ if (!phys_base)
+ phys_base = (phys_addr_t)msm_shared_ram_phys;
+ ret = smem_phys_to_virt(phys_base, toc[id].offset);
+ } else {
+ *size = 0;
+ }
+ if (use_spinlocks)
+ remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(smem_get_entry);
+
+
+/**
+ * smem_get_remote_spinlock - Remote spinlock pointer for unit testing.
+ *
+ * @returns: pointer to SMEM remote spinlock
+ */
+remote_spinlock_t *smem_get_remote_spinlock(void)
+{
+ return &remote_spinlock;
+}
+EXPORT_SYMBOL(smem_get_remote_spinlock);
+
+/**
+ * init_smem_remote_spinlock - Reentrant remote spinlock initialization
+ *
+ * @returns: sucess or error code for failure
+ */
+int init_smem_remote_spinlock(void)
+{
+ int rc = 0;
+
+ /*
+ * Optimistic locking. Init only needs to be done once by the first
+ * caller. After that, serializing inits between different callers
+ * is unnecessary. The second check after the lock ensures init
+ * wasn't previously completed by someone else before the lock could
+ * be grabbed.
+ */
+ if (!spinlocks_initialized) {
+ mutex_lock(&spinlock_init_lock);
+ if (!spinlocks_initialized) {
+ rc = remote_spin_lock_init(&remote_spinlock,
+ SMEM_SPINLOCK_SMEM_ALLOC);
+ if (!rc)
+ spinlocks_initialized = 1;
+ }
+ mutex_unlock(&spinlock_init_lock);
+ }
+ return rc;
+}
+
+static int restart_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data)
+{
+ if (code == SUBSYS_AFTER_SHUTDOWN) {
+ struct restart_notifier_block *notifier;
+
+ notifier = container_of(this,
+ struct restart_notifier_block, nb);
+ SMEM_DBG("%s: ssrestart for processor %d ('%s')\n",
+ __func__, notifier->processor,
+ notifier->name);
+
+ remote_spin_release(&remote_spinlock, notifier->processor);
+ remote_spin_release_all(notifier->processor);
+
+ if (smem_ramdump_dev) {
+ int ret;
+
+ SMEM_DBG("%s: saving ramdump\n", __func__);
+ /*
+ * XPU protection does not currently allow the
+ * auxiliary memory regions to be dumped. If this
+ * changes, then num_smem_areas + 1 should be passed
+ * into do_elf_ramdump() to dump all regions.
+ */
+ ret = do_elf_ramdump(smem_ramdump_dev,
+ smem_ramdump_segments, 1);
+ if (ret < 0)
+ pr_err("%s: unable to dump smem %d\n", __func__,
+ ret);
+ }
+ }
+
+ return NOTIFY_DONE;
+}
+
+static __init int modem_restart_late_init(void)
+{
+ int i;
+ void *handle;
+ struct restart_notifier_block *nb;
+
+ smem_ramdump_dev = create_ramdump_device("smem", NULL);
+ if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
+ pr_err("%s: Unable to create smem ramdump device.\n",
+ __func__);
+ smem_ramdump_dev = NULL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
+ nb = &restart_notifiers[i];
+ handle = subsys_notif_register_notifier(nb->name, &nb->nb);
+ SMEM_DBG("%s: registering notif for '%s', handle=%p\n",
+ __func__, nb->name, handle);
+ }
+
+ return 0;
+}
+late_initcall(modem_restart_late_init);
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 361df33..87f141d2 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -32,6 +32,7 @@
#include <mach/msm_iomap.h>
#include <mach/smem_log.h>
+#include <mach/msm_smem.h>
#include <asm/arch_timer.h>
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
new file mode 100644
index 0000000..b631e7c
--- /dev/null
+++ b/arch/arm/mach-msm/smem_private.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_
+#define _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_
+
+#include <linux/remote_spinlock.h>
+
+#include <mach/ramdump.h>
+
+#define SMEM_SPINLOCK_SMEM_ALLOC "S:3"
+extern remote_spinlock_t remote_spinlock;
+extern int spinlocks_initialized; /* only modify in init_smem_remote_spinlock */
+
+#define SMD_HEAP_SIZE 512
+
+struct smem_heap_info {
+ unsigned initialized;
+ unsigned free_offset;
+ unsigned heap_remaining;
+ unsigned reserved;
+};
+
+struct smem_heap_entry {
+ unsigned allocated;
+ unsigned offset;
+ unsigned size;
+ unsigned reserved; /* bits 1:0 reserved, bits 31:2 aux smem base addr */
+};
+#define BASE_ADDR_MASK 0xfffffffc
+
+struct smem_proc_comm {
+ unsigned command;
+ unsigned status;
+ unsigned data1;
+ unsigned data2;
+};
+
+struct smem_shared {
+ struct smem_proc_comm proc_comm[4];
+ unsigned version[32];
+ struct smem_heap_info heap_info;
+ struct smem_heap_entry heap_toc[SMD_HEAP_SIZE];
+};
+
+struct smem_area {
+ phys_addr_t phys_addr;
+ resource_size_t size;
+ void __iomem *virt_addr;
+};
+
+extern uint32_t num_smem_areas;
+extern struct smem_area *smem_areas;
+
+extern struct ramdump_segment *smem_ramdump_segments;
+
+/* used for unit testing spinlocks */
+remote_spinlock_t *smem_get_remote_spinlock(void);
+
+/*
+ * used to ensure the remote spinlock is only inited once since local
+ * spinlock init code appears non-reentrant
+ */
+int init_smem_remote_spinlock(void);
+#endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index 7bdcce9..ee262b0 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -19,7 +19,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#include <mach/msm_ipc_logging.h>
#include "smp2p_private_api.h"
#include "smp2p_private.h"
diff --git a/arch/arm/mach-msm/smp2p_loopback.c b/arch/arm/mach-msm/smp2p_loopback.c
index d95c93f..5df3d70 100644
--- a/arch/arm/mach-msm/smp2p_loopback.c
+++ b/arch/arm/mach-msm/smp2p_loopback.c
@@ -21,7 +21,7 @@
#include <linux/termios.h>
#include <linux/module.h>
#include <linux/remote_spinlock.h>
-#include "smd_private.h"
+#include "smem_private.h"
#include "smp2p_private.h"
/**
diff --git a/arch/arm/mach-msm/smp2p_spinlock_test.c b/arch/arm/mach-msm/smp2p_spinlock_test.c
index 09d7c0d..c14bac0 100644
--- a/arch/arm/mach-msm/smp2p_spinlock_test.c
+++ b/arch/arm/mach-msm/smp2p_spinlock_test.c
@@ -17,8 +17,8 @@
#include <linux/delay.h>
#include <linux/completion.h>
#include <linux/remote_spinlock.h>
-#include <mach/msm_smsm.h>
-#include "smd_private.h"
+#include <mach/msm_smem.h>
+#include "smem_private.h"
#include "smp2p_private.h"
#include "smp2p_test_common.h"
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index d316496..928f5cb 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -27,8 +27,8 @@
#include <asm/mach-types.h>
#include <mach/socinfo.h>
+#include <mach/msm_smem.h>
-#include "smd_private.h"
#include "boot_stats.h"
#define BUILD_ID_LENGTH 32
@@ -324,6 +324,9 @@
/* 8226 IDs */
[145] = MSM_CPU_8226,
+ [158] = MSM_CPU_8226,
+ [159] = MSM_CPU_8226,
+ [198] = MSM_CPU_8226,
/* 8092 IDs */
[146] = MSM_CPU_8092,
@@ -361,6 +364,12 @@
/* krypton IDs */
[187] = MSM_CPU_KRYPTON,
+ /* FSM9900 ID */
+ [188] = FSM_CPU_9900,
+
+ /* Samarium IDs */
+ [195] = MSM_CPU_SAMARIUM,
+
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
considered as unknown CPU. */
@@ -868,6 +877,10 @@
dummy_socinfo.id = 187;
strlcpy(dummy_socinfo.build_id, "msmkrypton - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_msmsamarium()) {
+ dummy_socinfo.id = 195;
+ strlcpy(dummy_socinfo.build_id, "msmsamarium - ",
+ sizeof(dummy_socinfo.build_id));
}
strlcat(dummy_socinfo.build_id, "Dummy socinfo",
sizeof(dummy_socinfo.build_id));
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 8e94b3a..fc05fce 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -392,7 +392,7 @@
};
struct mode_of of_l2_modes[] = {
- {"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 0},
+ {"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 1},
{"qcom,saw2-spm-cmd-gdhs", MSM_SPM_L2_MODE_GDHS, 1},
{"qcom,saw2-spm-cmd-pc", MSM_SPM_L2_MODE_POWER_COLLAPSE, 1},
};
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 9479d46c..b956649 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -41,6 +41,9 @@
#include "smd_private.h"
+static int enable_debug;
+module_param(enable_debug, int, S_IRUGO | S_IWUSR);
+
/**
* enum p_subsys_state - state of a subsystem (private)
* @SUBSYS_NORMAL: subsystem is operating normally
@@ -419,7 +422,7 @@
{
int ret;
- if (!subsys->desc->err_ready_irq)
+ if (!subsys->desc->err_ready_irq || enable_debug == 1)
return 0;
ret = wait_for_completion_timeout(&subsys->err_ready,
@@ -495,7 +498,7 @@
if (ret)
return ret;
- if (!subsys->desc->is_loadable)
+ if (subsys->desc->is_not_loadable)
return 0;
ret = wait_for_err_ready(subsys);
@@ -938,6 +941,10 @@
struct subsys_device *subsys_dev = subsys;
pr_info("Error ready interrupt occured for %s\n",
subsys_dev->desc->name);
+
+ if (subsys_dev->desc->is_not_loadable)
+ return IRQ_HANDLED;
+
complete(&subsys_dev->err_ready);
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 06a4c29..1ea0f2d 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -36,7 +36,8 @@
#include <mach/socinfo.h>
#if defined(CONFIG_MSM_SMD)
-#include "smd_private.h"
+#include <mach/msm_smem.h>
+#include <mach/msm_smsm.h>
#endif
#include "timer.h"
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 51578e0..e98fff2 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -26,10 +26,13 @@
#include <linux/msm_ion.h>
#include <mach/msm_smd.h>
#include <mach/ion.h>
+#include <mach/iommu_domains.h>
#include <linux/scatterlist.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/iommu.h>
#ifndef ION_ADSPRPC_HEAP_ID
#define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
@@ -53,6 +56,8 @@
} while (0)
+#define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0)
+
static inline uint32_t buf_page_start(void *buf)
{
uint32_t start = (uint32_t) buf & PAGE_MASK;
@@ -84,8 +89,9 @@
{
struct vm_area_struct *vma;
uint32_t start = buf_page_start(addr);
+ uint32_t end = buf_page_start((void *)((uint32_t)addr + sz - 1));
uint32_t len = nr_pages << PAGE_SHIFT;
- unsigned long pfn;
+ unsigned long pfn, pfnend;
int n = -1, err = 0;
VERIFY(err, 0 != access_ok(access ? VERIFY_WRITE : VERIFY_READ,
@@ -102,6 +108,12 @@
VERIFY(err, 0 == follow_pfn(vma, start, &pfn));
if (err)
goto bail;
+ VERIFY(err, 0 == follow_pfn(vma, end, &pfnend));
+ if (err)
+ goto bail;
+ VERIFY(err, (pfn + nr_pages - 1) == pfnend);
+ if (err)
+ goto bail;
VERIFY(err, nr_elems > 0);
if (err)
goto bail;
@@ -124,6 +136,13 @@
int last;
};
+struct fastrpc_smmu {
+ struct iommu_group *group;
+ struct iommu_domain *domain;
+ int domain_id;
+ bool enabled;
+};
+
struct fastrpc_apps {
smd_channel_t *chan;
struct smq_context_list clst;
@@ -132,6 +151,7 @@
struct cdev cdev;
struct class *class;
struct device *dev;
+ struct fastrpc_smmu smmu;
dev_t dev_no;
spinlock_t wrlock;
spinlock_t hlock;
@@ -172,7 +192,12 @@
{
struct fastrpc_apps *me = &gfa;
- if (buf->handle) {
+ if (!IS_ERR_OR_NULL(buf->handle)) {
+ if (me->smmu.enabled && buf->phys) {
+ ion_unmap_iommu(me->iclient, buf->handle,
+ me->smmu.domain_id, 0);
+ buf->phys = 0;
+ }
if (buf->virt) {
ion_unmap_kernel(me->iclient, buf->handle);
buf->virt = 0;
@@ -185,7 +210,7 @@
static void free_map(struct fastrpc_mmap *map)
{
struct fastrpc_apps *me = &gfa;
- if (map->handle) {
+ if (!IS_ERR_OR_NULL(map->handle)) {
if (map->virt) {
ion_unmap_kernel(me->iclient, map->handle);
map->virt = 0;
@@ -197,26 +222,39 @@
static int alloc_mem(struct fastrpc_buf *buf)
{
+ struct fastrpc_apps *me = &gfa;
struct ion_client *clnt = gfa.iclient;
struct sg_table *sg;
int err = 0;
+ unsigned int heap;
+ unsigned long len;
buf->handle = 0;
buf->virt = 0;
- buf->handle = ion_alloc(clnt, buf->size, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID), 0);
+ heap = me->smmu.enabled ? ION_HEAP(ION_IOMMU_HEAP_ID) :
+ ION_HEAP(ION_ADSP_HEAP_ID) | ION_HEAP(ION_AUDIO_HEAP_ID);
+ buf->handle = ion_alloc(clnt, buf->size, SZ_4K, heap, 0);
VERIFY(err, 0 == IS_ERR_OR_NULL(buf->handle));
if (err)
goto bail;
VERIFY(err, 0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
if (err)
goto bail;
- VERIFY(err, 0 != (sg = ion_sg_table(clnt, buf->handle)));
- if (err)
- goto bail;
- VERIFY(err, 1 == sg->nents);
- if (err)
- goto bail;
- buf->phys = sg_dma_address(sg->sgl);
+ if (me->smmu.enabled) {
+ len = buf->size;
+ VERIFY(err, 0 == ion_map_iommu(clnt, buf->handle,
+ me->smmu.domain_id, 0, SZ_4K, 0,
+ &buf->phys, &len, 0, 0));
+ if (err)
+ goto bail;
+ } else {
+ VERIFY(err, 0 != (sg = ion_sg_table(clnt, buf->handle)));
+ if (err)
+ goto bail;
+ VERIFY(err, 1 == sg->nents);
+ if (err)
+ goto bail;
+ buf->phys = sg_dma_address(sg->sgl);
+ }
bail:
if (err && !IS_ERR_OR_NULL(buf->handle))
free_mem(buf);
@@ -481,6 +519,28 @@
return err;
}
+static void inv_args_pre(uint32_t sc, remote_arg_t *rpra)
+{
+ int i, inbufs, outbufs;
+ uint32_t end;
+
+ inbufs = REMOTE_SCALARS_INBUFS(sc);
+ outbufs = REMOTE_SCALARS_OUTBUFS(sc);
+ for (i = inbufs; i < inbufs + outbufs; ++i) {
+ if (!rpra[i].buf.len)
+ continue;
+ if (buf_page_start(rpra) == buf_page_start(rpra[i].buf.pv))
+ continue;
+ if (!IS_CACHE_ALIGNED((uint32_t)rpra[i].buf.pv))
+ dmac_flush_range(rpra[i].buf.pv,
+ (char *)rpra[i].buf.pv + 1);
+ end = (uint32_t)rpra[i].buf.pv + rpra[i].buf.len;
+ if (!IS_CACHE_ALIGNED(end))
+ dmac_flush_range((char *)end,
+ (char *)end + 1);
+ }
+}
+
static void inv_args(uint32_t sc, remote_arg_t *rpra, int used)
{
int i, inbufs, outbufs;
@@ -572,6 +632,8 @@
{
int err = 0;
struct fastrpc_apps *me = &gfa;
+ struct device_node *node;
+ bool enabled = 0;
if (me->chan == 0) {
int i;
@@ -588,6 +650,22 @@
VERIFY(err, 0 == IS_ERR_OR_NULL(me->iclient));
if (err)
goto ion_bail;
+ node = of_find_compatible_node(NULL, NULL,
+ "qcom,msm-audio-ion");
+ if (node)
+ enabled = of_property_read_bool(node,
+ "qcom,smmu-enabled");
+ if (enabled)
+ me->smmu.group = iommu_group_find("lpass_audio");
+ if (me->smmu.group)
+ me->smmu.domain = iommu_group_get_iommudata(
+ me->smmu.group);
+ if (!IS_ERR_OR_NULL(me->smmu.domain)) {
+ me->smmu.domain_id = msm_find_domain_no(
+ me->smmu.domain);
+ if (me->smmu.domain_id >= 0)
+ me->smmu.enabled = enabled;
+ }
VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
SMD_APPS_QDSP, &me->chan,
me, smd_event_handler));
@@ -704,6 +782,12 @@
sc = invoke->sc;
obuf.handle = 0;
+ if (me->smmu.enabled) {
+ VERIFY(err, 0 == iommu_attach_group(me->smmu.domain,
+ me->smmu.group));
+ if (err)
+ return err;
+ }
if (REMOTE_SCALARS_LENGTH(sc)) {
VERIFY(err, 0 == get_dev(me, &dev));
if (err)
@@ -720,6 +804,7 @@
}
context_list_alloc_ctx(&me->clst, &ctx);
+ inv_args_pre(sc, rpra);
VERIFY(err, 0 == fastrpc_invoke_send(me, kernel, invoke->handle, sc,
ctx, &obuf));
if (err)
@@ -743,6 +828,8 @@
}
context_free(ctx);
+ if (me->smmu.enabled)
+ iommu_detach_group(me->smmu.domain, me->smmu.group);
for (i = 0, b = abufs; i < nbufs; ++i, ++b)
free_mem(b);
@@ -1093,6 +1180,7 @@
struct fastrpc_apps *me = &gfa;
int err = 0;
+ memset(me, 0, sizeof(*me));
VERIFY(err, 0 == fastrpc_init());
if (err)
goto fastrpc_bail;
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 684f11d..292a0be 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -219,6 +219,7 @@
int num_clients;
int polling_reg_flag;
struct diag_write_device *buf_tbl;
+ unsigned int buf_tbl_size;
int use_device_tree;
/* DCI related variables */
struct dci_pkt_req_tracking_tbl *req_tracking_tbl;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 7022a6f..96e8b11 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1167,7 +1167,7 @@
/* place holder for number of data field */
ret += 4;
- for (i = 0; i < driver->poolsize_write_struct; i++) {
+ for (i = 0; i < driver->buf_tbl_size; i++) {
if (driver->buf_tbl[i].length > 0) {
#ifdef DIAG_DEBUG
pr_debug("diag: WRITING the buf address "
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 151e304..f76d41a 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -48,7 +48,8 @@
int diag_debug_buf_idx;
unsigned char diag_debug_buf[1024];
-static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
+/* Number of entries in table of buffers */
+static unsigned int buf_tbl_size = 10;
struct diag_master_table entry;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
@@ -467,7 +468,7 @@
if (driver->logging_mode == MEMORY_DEVICE_MODE) {
int hsic_updated = 0;
if (data_type == APPS_DATA) {
- for (i = 0; i < driver->poolsize_write_struct; i++)
+ for (i = 0; i < driver->buf_tbl_size; i++)
if (driver->buf_tbl[i].length == 0) {
driver->buf_tbl[i].buf = buf;
driver->buf_tbl[i].length =
@@ -1768,6 +1769,12 @@
driver->read_len_legacy = 0;
driver->use_device_tree = has_device_tree();
driver->real_time_mode = 1;
+ /*
+ * The number of entries in table of buffers
+ * should not be any smaller than hdlc poolsize.
+ */
+ driver->buf_tbl_size = (buf_tbl_size < driver->poolsize_hdlc) ?
+ driver->poolsize_hdlc : buf_tbl_size;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
@@ -1802,7 +1809,7 @@
goto err;
kmemleak_not_leak(driver->client_map);
if (driver->buf_tbl == NULL)
- driver->buf_tbl = kzalloc(buf_tbl_size *
+ driver->buf_tbl = kzalloc(driver->buf_tbl_size *
sizeof(struct diag_write_device), GFP_KERNEL);
if (driver->buf_tbl == NULL)
goto err;
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index c3ff7dc..2776c58 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -69,7 +69,7 @@
type = *(uint32_t *)(buf);
data_len = *(uint32_t *)(buf + 4);
if (type < DIAG_CTRL_MSG_REG ||
- type > DIAG_CTRL_MSG_F3_MASK_V2) {
+ type > DIAG_CTRL_MSG_LAST) {
pr_alert("diag: In %s, Invalid Msg type %d proc %d",
__func__, type, smd_info->peripheral);
break;
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 9c2c691..f58ab24 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -29,6 +29,12 @@
#define DIAG_CTRL_MSG_EVENT_MASK_V2 10
/* Send Diag F3 mask */
#define DIAG_CTRL_MSG_F3_MASK_V2 11
+#define DIAG_CTRL_MSG_NUM_PRESETS 12
+#define DIAG_CTRL_MSG_SET_PRESET_ID 13
+#define DIAG_CTRL_MSG_LOG_MASK_WITH_PRESET_ID 14
+#define DIAG_CTRL_MSG_EVENT_MASK_WITH_PRESET_ID 15
+#define DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID 16
+#define DIAG_CTRL_MSG_LAST DIAG_CTRL_MSG_F3_MASK_WITH_PRESET_ID
/* Denotes that we support sending/receiving the feature mask */
#define F_DIAG_INT_FEATURE_MASK 0x01
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 0e2e2d9..2b14f86 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -2,7 +2,6 @@
# Makefile for CoreSight drivers.
#
obj-$(CONFIG_CORESIGHT) += coresight.o
-obj-$(CONFIG_OF) += of_coresight.o
obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
obj-$(CONFIG_CORESIGHT_TMC) += coresight-tmc.o
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index 7ea71d3..53df0f9 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -218,6 +218,24 @@
return 0;
}
+static int tpiu_reg_set_optimum_mode(struct regulator *reg,
+ unsigned int reg_hpm)
+{
+ if (regulator_count_voltages(reg) <= 0)
+ return 0;
+
+ return regulator_set_optimum_mode(reg, reg_hpm);
+}
+
+static int tpiu_reg_set_voltage(struct regulator *reg, unsigned int reg_low,
+ unsigned int reg_high)
+{
+ if (regulator_count_voltages(reg) <= 0)
+ return 0;
+
+ return regulator_set_voltage(reg, reg_low, reg_high);
+}
+
static int __tpiu_enable_to_sdc(struct tpiu_drvdata *drvdata)
{
int ret;
@@ -225,11 +243,11 @@
if (!drvdata->reg)
return -EINVAL;
- ret = regulator_set_optimum_mode(drvdata->reg, drvdata->reg_hpm);
+ ret = tpiu_reg_set_optimum_mode(drvdata->reg, drvdata->reg_hpm);
if (ret < 0)
return ret;
- ret = regulator_set_voltage(drvdata->reg, drvdata->reg_low,
- drvdata->reg_high);
+ ret = tpiu_reg_set_voltage(drvdata->reg, drvdata->reg_low,
+ drvdata->reg_high);
if (ret)
goto err0;
ret = regulator_enable(drvdata->reg);
@@ -248,9 +266,9 @@
return 0;
err1:
- regulator_set_voltage(drvdata->reg, 0, drvdata->reg_high);
+ tpiu_reg_set_voltage(drvdata->reg, 0, drvdata->reg_high);
err0:
- regulator_set_optimum_mode(drvdata->reg, 0);
+ tpiu_reg_set_optimum_mode(drvdata->reg, 0);
return ret;
}
@@ -325,8 +343,8 @@
msm_tlmm_misc_reg_write(TLMM_ETM_MODE_REG, 0);
regulator_disable(drvdata->reg);
- regulator_set_optimum_mode(drvdata->reg, 0);
- regulator_set_voltage(drvdata->reg, 0, drvdata->reg_high);
+ tpiu_reg_set_optimum_mode(drvdata->reg, 0);
+ tpiu_reg_set_voltage(drvdata->reg, 0, drvdata->reg_high);
}
static void tpiu_disable(struct coresight_device *csdev)
@@ -530,8 +548,7 @@
prop = of_get_property(node, "qcom,vdd-voltage-level", &len);
if (!prop || (len != (2 * sizeof(__be32)))) {
- of_node_put(reg_node);
- return -EINVAL;
+ dev_err(dev, "sdc voltage levels not specified\n");
} else {
drvdata->reg_low = be32_to_cpup(&prop[0]);
drvdata->reg_high = be32_to_cpup(&prop[1]);
@@ -539,8 +556,7 @@
prop = of_get_property(node, "qcom,vdd-current-level", &len);
if (!prop || (len != (2 * sizeof(__be32)))) {
- of_node_put(reg_node);
- return -EINVAL;
+ dev_err(dev, "sdc current levels not specified\n");
} else {
drvdata->reg_lpm = be32_to_cpup(&prop[0]);
drvdata->reg_hpm = be32_to_cpup(&prop[1]);
@@ -615,6 +631,8 @@
for (i = 0; i < drvdata->seta_gpiocnt; i++)
drvdata->seta_cfgs[i].dir = seta_cfgs[i];
+
+ devm_kfree(dev, seta_cfgs);
} else {
dev_err(dev, "seta gpios not specified\n");
}
@@ -681,6 +699,8 @@
for (i = 0; i < drvdata->setb_gpiocnt; i++)
drvdata->setb_cfgs[i].dir = setb_cfgs[i];
+
+ devm_kfree(dev, setb_cfgs);
} else {
dev_err(dev, "setb gpios not specified\n");
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index bf022ac..7b01432 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -4,6 +4,7 @@
* Copyright (C) 2001 Russell King
* (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
* Jun Nakajima <jun.nakajima@intel.com>
+ * (c) 2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -124,6 +125,14 @@
static DEFINE_PER_CPU(struct dbs_work_struct, dbs_refresh_work);
+struct dbs_sync_work_struct {
+ struct work_struct work;
+ unsigned int src_cpu;
+ unsigned int targ_cpu;
+};
+
+static DEFINE_PER_CPU(struct dbs_sync_work_struct, dbs_sync_work);
+
static struct dbs_tuners {
unsigned int sampling_rate;
unsigned int up_threshold;
@@ -878,9 +887,10 @@
freq_next = dbs_tuners_ins.sync_freq;
if (max_load_freq >
- (dbs_tuners_ins.up_threshold_multi_core -
+ ((dbs_tuners_ins.up_threshold_multi_core -
dbs_tuners_ins.down_differential_multi_core) *
- policy->cur)
+ policy->cur) &&
+ freq_next < dbs_tuners_ins.optimal_freq)
freq_next = dbs_tuners_ins.optimal_freq;
}
@@ -1019,6 +1029,92 @@
return;
}
+static int dbs_migration_notify(struct notifier_block *nb,
+ unsigned long target_cpu, void *arg)
+{
+ struct dbs_sync_work_struct *sync_work =
+ &per_cpu(dbs_sync_work, target_cpu);
+ sync_work->src_cpu = (unsigned int)arg;
+
+ queue_work_on(target_cpu, input_wq,
+ &per_cpu(dbs_sync_work, target_cpu).work);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block dbs_migration_nb = {
+ .notifier_call = dbs_migration_notify,
+};
+
+void dbs_synchronize(struct work_struct *work)
+{
+ struct cpufreq_policy *policy;
+ struct cpu_dbs_info_s *this_dbs_info, *src_dbs_info;
+ struct dbs_sync_work_struct *dbs_work;
+ unsigned int cpu, src_cpu;
+ unsigned int src_freq, src_max_load;
+ int delay;
+
+ dbs_work = container_of(work, struct dbs_sync_work_struct, work);
+ cpu = dbs_work->targ_cpu;
+ src_cpu = dbs_work->src_cpu;
+
+ get_online_cpus();
+
+ /* Getting source cpu info */
+ src_dbs_info = &per_cpu(od_cpu_dbs_info, src_cpu);
+ if (src_dbs_info != NULL && src_dbs_info->cur_policy != NULL) {
+ src_freq = src_dbs_info->cur_policy->cur;
+ src_max_load = src_dbs_info->max_load;
+ } else {
+ src_freq = dbs_tuners_ins.sync_freq;
+ src_max_load = 0;
+ }
+
+ if (lock_policy_rwsem_write(cpu) < 0)
+ goto bail_acq_sema_failed;
+
+ this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
+ policy = this_dbs_info->cur_policy;
+ if (!policy) {
+ /* CPU not using ondemand governor */
+ goto bail_incorrect_governor;
+ }
+
+ delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+
+ if (policy->cur < src_freq) {
+
+ /* Cancelling the next ondemand sample */
+ cancel_delayed_work_sync(&this_dbs_info->work);
+
+ /*
+ * Arch specific cpufreq driver may fail.
+ * Don't update governor frequency upon failure.
+ */
+ if (__cpufreq_driver_target(policy, src_freq,
+ CPUFREQ_RELATION_L) >= 0) {
+ policy->cur = src_freq;
+ if (src_max_load > this_dbs_info->max_load) {
+ this_dbs_info->max_load = src_max_load;
+ this_dbs_info->prev_load = src_max_load;
+ }
+ }
+
+ /* Rescheduling the next ondemand sample */
+ mutex_lock(&this_dbs_info->timer_mutex);
+ schedule_delayed_work_on(cpu, &this_dbs_info->work,
+ delay);
+ mutex_unlock(&this_dbs_info->timer_mutex);
+ }
+bail_incorrect_governor:
+ unlock_policy_rwsem_write(cpu);
+
+bail_acq_sema_failed:
+ put_online_cpus();
+ return;
+}
+
static void dbs_input_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
@@ -1147,6 +1243,9 @@
if (dbs_tuners_ins.sync_freq == 0)
dbs_tuners_ins.sync_freq = policy->min;
+
+ atomic_notifier_chain_register(&migration_notifier_head,
+ &dbs_migration_nb);
}
if (!cpu)
rc = input_register_handler(&dbs_input_handler);
@@ -1170,9 +1269,14 @@
this_dbs_info->cur_policy = NULL;
if (!cpu)
input_unregister_handler(&dbs_input_handler);
- if (!dbs_enable)
+ if (!dbs_enable) {
sysfs_remove_group(cpufreq_global_kobject,
&dbs_attr_group);
+ atomic_notifier_chain_unregister(
+ &migration_notifier_head,
+ &dbs_migration_nb);
+ }
+
mutex_unlock(&dbs_mutex);
break;
@@ -1231,10 +1335,17 @@
&per_cpu(od_cpu_dbs_info, i);
struct dbs_work_struct *dbs_work =
&per_cpu(dbs_refresh_work, i);
+ struct dbs_sync_work_struct *dbs_sync =
+ &per_cpu(dbs_sync_work, i);
mutex_init(&this_dbs_info->timer_mutex);
INIT_WORK(&dbs_work->work, dbs_refresh_callback);
dbs_work->cpu = i;
+
+ INIT_WORK(&dbs_sync->work, dbs_synchronize);
+ dbs_sync->src_cpu = 0;
+ dbs_sync->targ_cpu = i;
+
}
return cpufreq_register_governor(&cpufreq_gov_ondemand);
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 5249917..1dcd3bc 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -412,6 +412,9 @@
/* write seg size */
*((uint32_t *)(pce_dev->ce_dm.buffer.seg_size)) = sreq->size;
+ /* clear status */
+ *((uint32_t *)(pce_dev->ce_dm.buffer.status)) = 0;
+
_ce_setup_hash_cmdrptrlist(pce_dev, sreq);
return 0;
@@ -685,6 +688,9 @@
*((uint32_t *)(buffer->seg_size)) = totallen_in;
+ /* clear status */
+ *((uint32_t *)(pce_dev->ce_dm.buffer.status)) = 0;
+
_ce_setup_cipher_cmdrptrlist(pce_dev, creq);
return 0;
};
@@ -708,13 +714,19 @@
/* check MAC */
if (pce_dev->mode == QCE_MODE_CCM) {
- uint32_t result;
+ int32_t result = 0;
result =
(uint32_t)(*((uint32_t *)pce_dev->ce_dm.buffer.status));
result &= (1 << CRYPTO_MAC_FAILED);
result |= (pce_dev->ce_dm.chan_ce_in_status |
pce_dev->ce_dm.chan_ce_out_status);
+ if (pce_dev->ce_dm.chan_ce_in_status |
+ pce_dev->ce_dm.chan_ce_out_status)
+ result = -ENXIO;
+ else if (result & (1 << CRYPTO_MAC_FAILED))
+ result = -EBADMSG;
+
pce_dev->qce_cb(areq, pce_dev->ce_dm.buffer.auth_result, NULL,
result);
}
@@ -1617,16 +1629,16 @@
pscmd++;
- /* SET SEG SIZE REGISTER and OCB COMMAND LIST */
- pce_dev->ce_dm.cmdlist.set_seg_size_ocb = pscmd;
- pscmd->cmd = CMD_LC | CMD_MODE_SINGLE | CMD_OCB;
+ /* SET SEG SIZE REGISTER LIST */
+ pce_dev->ce_dm.cmdlist.set_seg_size = pscmd;
+ pscmd->cmd = CMD_LC | CMD_MODE_SINGLE;
pscmd->dst = (unsigned) (CRYPTO_SEG_SIZE_REG + pce_dev->phy_iobase);
pscmd->len = CRYPTO_REG_SIZE;
pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.seg_size);
pscmd++;
- /* OCU COMMAND LIST */
+ /* Get status and OCU COMMAND LIST */
pce_dev->ce_dm.cmdlist.get_status_ocu = pscmd;
pscmd->cmd = CMD_LC | CMD_MODE_SINGLE | CMD_OCU;
pscmd->src = (unsigned) (CRYPTO_STATUS_REG + pce_dev->phy_iobase);
@@ -1634,7 +1646,7 @@
pscmd->dst = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status);
pscmd++;
- /* CLEAR STATUS COMMAND LIST */
+ /* CLEAR STATUS and OCU COMMAND LIST */
pce_dev->ce_dm.cmdlist.clear_status = pscmd;
pscmd->cmd = CMD_LC | CMD_MODE_SINGLE | CMD_OCU;
pscmd->dst = (unsigned) (CRYPTO_STATUS_REG + pce_dev->phy_iobase);
@@ -1642,6 +1654,14 @@
pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status);
pscmd++;
+ /* CLEAR STATUS and OCB COMMAND LIST */
+ pce_dev->ce_dm.cmdlist.clear_status_ocb = pscmd;
+ pscmd->cmd = CMD_LC | CMD_MODE_SINGLE | CMD_OCB;
+ pscmd->dst = (unsigned) (CRYPTO_STATUS_REG + pce_dev->phy_iobase);
+ pscmd->len = CRYPTO_REG_SIZE;
+ pscmd->src = GET_PHYS_ADDR(pce_dev->ce_dm.buffer.status);
+ pscmd++;
+
/* SET GO_PROC REGISTERS COMMAND LIST */
pce_dev->ce_dm.cmdlist.set_go_proc = pscmd;
pscmd->cmd = CMD_LC | CMD_MODE_SINGLE;
@@ -1715,7 +1735,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_128_cbc_ctr = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_aes_128_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_aes_iv);
@@ -1727,7 +1748,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_256_cbc_ctr = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_aes_256_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_aes_iv);
@@ -1739,7 +1761,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_128_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_aes_128_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
@@ -1750,7 +1773,8 @@
cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_256_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_aes_256_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
@@ -1761,7 +1785,8 @@
cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_128_xts = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_aes_128_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_aes_128_xts_key);
@@ -1775,7 +1800,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_aes_256_xts = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_aes_256_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_aes_256_xts_key);
@@ -1789,7 +1815,8 @@
cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_des_cbc = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_iv);
@@ -1800,7 +1827,8 @@
cmd_ptr_vaddr = (uint32_t *)ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_des_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
@@ -1810,7 +1838,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_3des_cbc = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_3des_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_des_iv);
@@ -1821,7 +1850,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->cipher_3des_ecb = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_cipher_3des_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_cfg);
@@ -1861,7 +1891,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->auth_sha1 = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_auth_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_auth_iv_20);
@@ -1879,7 +1910,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->auth_sha256 = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_auth_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_auth_iv_32);
@@ -1897,7 +1929,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->auth_sha1_hmac = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_auth_key_512);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_auth_cfg);
@@ -1916,7 +1949,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->auth_sha256_hmac = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_auth_key_512);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_auth_cfg);
@@ -1935,7 +1969,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->auth_aes_128_cmac = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_iv);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_key);
@@ -1953,7 +1988,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->auth_aes_256_cmac = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_cipher_cfg);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_iv);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_key);
@@ -1988,7 +2024,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->aead_aes_128_ccm = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_iv);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_byte_count);
@@ -2005,7 +2042,8 @@
cmd_ptr_vaddr = (uint32_t *) ALIGN(((unsigned int) cmd_ptr_vaddr), 16);
cmdptrlist->aead_aes_256_ccm = QCE_SET_CMD_PTR(cmd_ptr_vaddr);
- *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->clear_status_ocb);
+ *cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->set_seg_size);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_iv);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_key);
*cmd_ptr_vaddr++ = QCE_SET_CMD_PTR(cmdlist->reset_auth_byte_count);
diff --git a/drivers/crypto/msm/qce40.h b/drivers/crypto/msm/qce40.h
index 0d19106..179250c 100644
--- a/drivers/crypto/msm/qce40.h
+++ b/drivers/crypto/msm/qce40.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -118,6 +118,7 @@
struct ce_cmdlists {
dmov_s *get_hw_version;
dmov_s *clear_status;
+ dmov_s *clear_status_ocb;
dmov_s *get_status_ocu;
dmov_s *set_cipher_cfg;
@@ -162,7 +163,7 @@
dmov_s *reset_auth_cfg;
dmov_s *reset_auth_byte_count;
- dmov_s *set_seg_size_ocb;
+ dmov_s *set_seg_size;
dmov_s *get_status_wait;
dmov_s *set_go_proc;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 58fa5c9..2b70d3f 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -717,6 +717,9 @@
bool sha1 = false;
uint32_t auth_cfg = 0;
+ /* clear status */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_STATUS_REG);
+
writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
CRYPTO_CONFIG_REG));
/*
@@ -896,6 +899,9 @@
uint32_t ivsize = creq->ivsize;
int i;
+ /* clear status */
+ writel_relaxed(0, pce_dev->iobase + CRYPTO_STATUS_REG);
+
writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
CRYPTO_CONFIG_REG));
/*
@@ -1213,6 +1219,7 @@
{
struct aead_request *areq;
unsigned char mac[SHA256_DIGEST_SIZE];
+ uint32_t status;
areq = (struct aead_request *) pce_dev->areq;
if (areq->src != areq->dst) {
@@ -1227,16 +1234,55 @@
/* check MAC */
memcpy(mac, (char *)(&pce_dev->ce_sps.result->auth_iv[0]),
SHA256_DIGEST_SIZE);
+
+ /* read status before unlock */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
if (_qce_unlock_other_pipes(pce_dev))
return -EINVAL;
if (pce_dev->mode == QCE_MODE_CCM) {
- uint32_t result_status;
+ int32_t result_status;
+
+ /*
+ * Don't use result dump status. The operation may not
+ * be complete.
+ * Instead, use the status we just read of device.
+ * In case, we need to use result_status from result
+ * dump the result_status needs to be byte swapped,
+ * since we set the device to little endian.
+ */
+
result_status = pce_dev->ce_sps.result->status;
- result_status &= (1 << CRYPTO_MAC_FAILED);
- result_status |= (pce_dev->ce_sps.consumer_status |
- pce_dev->ce_sps.producer_status);
+ pce_dev->ce_sps.result->status = 0;
+
+ if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+ | (1 << CRYPTO_HSD_ERR))) {
+
+ pr_err("aead operation error. Status %x\n",
+ status);
+ result_status = -ENXIO;
+ } else if (pce_dev->ce_sps.consumer_status |
+ pce_dev->ce_sps.producer_status) {
+ pr_err("aead sps operation error. sps status %x %x\n",
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+ } else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+ pr_err("aead operation not done? Status %x, sps status %x %x\n",
+ status,
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+
+ } else if (status & (1 << CRYPTO_MAC_FAILED)) {
+ result_status = -EBADMSG;
+ } else {
+ result_status = 0;
+ }
+
pce_dev->qce_cb(areq, mac, NULL, result_status);
+
} else {
uint32_t ivsize = 0;
struct crypto_aead *aead;
@@ -1260,6 +1306,8 @@
struct ahash_request *areq;
unsigned char digest[SHA256_DIGEST_SIZE];
uint32_t bytecount32[2];
+ int32_t result_status = pce_dev->ce_sps.result->status;
+ uint32_t status;
areq = (struct ahash_request *) pce_dev->areq;
qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
@@ -1269,10 +1317,39 @@
_byte_stream_to_net_words(bytecount32,
(unsigned char *)pce_dev->ce_sps.result->auth_byte_count,
2 * CRYPTO_REG_SIZE);
+
+ /* read status before unlock */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
if (_qce_unlock_other_pipes(pce_dev))
return -EINVAL;
+
+ /*
+ * Don't use result dump status. The operation may not be complete.
+ * Instead, use the status we just read of device.
+ * In case, we need to use result_status from result
+ * dump the result_status needs to be byte swapped,
+ * since we set the device to little endian.
+ */
+
+ if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+ | (1 << CRYPTO_HSD_ERR))) {
+
+ pr_err("sha operation error. Status %x\n", status);
+ result_status = -ENXIO;
+ } else if (pce_dev->ce_sps.consumer_status) {
+ pr_err("sha sps operation error. sps status %x\n",
+ pce_dev->ce_sps.consumer_status);
+ result_status = -ENXIO;
+ } else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+ pr_err("sha operation not done? Status %x, sps status %x\n",
+ status, pce_dev->ce_sps.consumer_status);
+ result_status = -ENXIO;
+ } else {
+ result_status = 0;
+ }
pce_dev->qce_cb(areq, digest, (char *)bytecount32,
- pce_dev->ce_sps.consumer_status);
+ result_status);
return 0;
};
@@ -1280,6 +1357,8 @@
{
struct ablkcipher_request *areq;
unsigned char iv[NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE];
+ uint32_t status;
+ int32_t result_status;
areq = (struct ablkcipher_request *) pce_dev->areq;
@@ -1290,13 +1369,46 @@
qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
DMA_TO_DEVICE);
+
+ /* read status before unlock */
+ status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
if (_qce_unlock_other_pipes(pce_dev))
return -EINVAL;
+ /*
+ * Don't use result dump status. The operation may not be complete.
+ * Instead, use the status we just read of device.
+ * In case, we need to use result_status from result
+ * dump the result_status needs to be byte swapped,
+ * since we set the device to little endian.
+ */
+ if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+ | (1 << CRYPTO_HSD_ERR))) {
+ pr_err("ablk_cipher operation error. Status %x\n",
+ status);
+ result_status = -ENXIO;
+ } else if (pce_dev->ce_sps.consumer_status |
+ pce_dev->ce_sps.producer_status) {
+ pr_err("ablk_cipher sps operation error. sps status %x %x\n",
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+ } else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+ pr_err("ablk_cipher operation not done? Status %x, sps status %x %x\n",
+ status,
+ pce_dev->ce_sps.consumer_status,
+ pce_dev->ce_sps.producer_status);
+ result_status = -ENXIO;
+
+ } else {
+ result_status = 0;
+ }
+
if (pce_dev->mode == QCE_MODE_ECB) {
pce_dev->qce_cb(areq, NULL, NULL,
pce_dev->ce_sps.consumer_status |
- pce_dev->ce_sps.producer_status);
+ result_status);
} else {
if (pce_dev->ce_sps.minor_version == 0) {
if (pce_dev->mode == QCE_MODE_CBC) {
@@ -1342,9 +1454,7 @@
(char *)(pce_dev->ce_sps.result->encr_cntr_iv),
sizeof(iv));
}
- pce_dev->qce_cb(areq, NULL, iv,
- pce_dev->ce_sps.consumer_status |
- pce_dev->ce_sps.producer_status);
+ pce_dev->qce_cb(areq, NULL, iv, result_status);
}
return 0;
};
@@ -1993,6 +2103,9 @@
break;
}
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
@@ -2037,13 +2150,9 @@
if (mode == QCE_MODE_XTS) {
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, &pcl_info->auth_seg_size);
} else {
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, &pcl_info->auth_seg_size);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
0, &pcl_info->auth_seg_size);
}
@@ -2130,6 +2239,9 @@
break;
}
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
@@ -2156,13 +2268,7 @@
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR1_IV1_REG, 0,
NULL);
}
- /* Add dummy to align size to burst-size multiple */
- if (!mode_cbc) {
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
- 0, &pcl_info->auth_seg_size);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, &pcl_info->auth_seg_size);
- }
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_le, NULL);
@@ -2206,10 +2312,13 @@
auth_cfg = pdev->reg.auth_cfg_sha1;
iv_reg = 5;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_SHA256:
@@ -2218,13 +2327,16 @@
auth_cfg = pdev->reg.auth_cfg_sha256;
iv_reg = 8;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_SHA1_HMAC:
cmdlistptr->auth_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2233,10 +2345,13 @@
auth_cfg = pdev->reg.auth_cfg_hmac_sha1;
key_reg = 16;
iv_reg = 5;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_AEAD_SHA1_HMAC:
cmdlistptr->aead_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2245,13 +2360,16 @@
auth_cfg = pdev->reg.auth_cfg_aead_sha1_hmac;
key_reg = 16;
iv_reg = 5;
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+ 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_SHA256_HMAC:
cmdlistptr->auth_sha256_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2261,13 +2379,15 @@
key_reg = 16;
iv_reg = 8;
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0,
+ NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
case QCE_HASH_AES_CMAC:
if (key_128 == true) {
@@ -2285,13 +2405,16 @@
auth_cfg = pdev->reg.auth_cfg_cmac_256;
key_reg = 8;
}
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0,
+ NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
/* 1 dummy write */
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
0, NULL);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
- 0, NULL);
break;
default:
pr_err("Unknown algorithms %d received, exiting now\n", alg);
@@ -2395,10 +2518,13 @@
key_reg = 8;
}
+
+ /* clear status register */
+ qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
- qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG, 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, 0, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_START_REG, 0,
NULL);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index d1cb933..a4bb2f1 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -56,6 +56,7 @@
u32 aead_ccm_aes_dec;
u32 aead_op_success;
u32 aead_op_fail;
+ u32 aead_bad_msg;
u32 ablk_cipher_aes_enc;
u32 ablk_cipher_aes_dec;
u32 ablk_cipher_des_enc;
@@ -684,6 +685,9 @@
" AEAD operation fail : %d\n",
pstat->aead_op_fail);
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD bad message : %d\n",
+ pstat->aead_bad_msg);
+ len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" SHA1 digest : %d\n",
pstat->sha1_digest);
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
@@ -1036,12 +1040,6 @@
kzfree(rctx->assoc);
areq->assoc = rctx->assoc_sg;
areq->assoclen = rctx->assoclen;
- if (ret) {
- if (ret == 0x2000000)
- ret = -EBADMSG;
- else
- ret = -ENXIO;
- }
} else {
if (ret == 0) {
if (rctx->dir == QCE_ENCRYPT) {
@@ -1070,11 +1068,15 @@
memcpy(ctx->iv, iv, crypto_aead_ivsize(aead));
}
- if (ret)
+ if (ret == (-EBADMSG))
+ pstat->aead_bad_msg++;
+ else if (ret)
pstat->aead_op_fail++;
else
pstat->aead_op_success++;
+ cp->res = ret;
+
if (cp->platform_support.ce_shared)
schedule_work(&cp->unlock_ce_ws);
tasklet_schedule(&cp->done_tasklet);
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 1be2702..e93e25c 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -297,6 +297,7 @@
#define CRYPTO_DOUT_SIZE_AVAIL_MASK (0x1F << CRYPTO_DOUT_SIZE_AVAIL)
#define CRYPTO_DIN_SIZE_AVAIL 21 /* bit 21-25 */
#define CRYPTO_DIN_SIZE_AVAIL_MASK (0x1F << CRYPTO_DIN_SIZE_AVAIL)
+#define CRYPTO_HSD_ERR 20
#define CRYPTO_ACCESS_VIOL 19
#define CRYPTO_PIPE_ACTIVE_ERR 18
#define CRYPTO_CFG_CHNG_ERR 17
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
index f28ebb4..058a3f9 100644
--- a/drivers/gpio/gpio-msm-v1.c
+++ b/drivers/gpio/gpio-msm-v1.c
@@ -1,7 +1,7 @@
/* linux/arch/arm/mach-msm/gpio.c
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -24,7 +24,7 @@
#include <asm/mach/irq.h>
#include <mach/gpiomux.h>
#include <mach/msm_iomap.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#include <mach/proc_comm.h>
diff --git a/drivers/gpu/ion/ion_cma_heap.c b/drivers/gpu/ion/ion_cma_heap.c
index 193f4d4..e7f7836 100644
--- a/drivers/gpu/ion/ion_cma_heap.c
+++ b/drivers/gpu/ion/ion_cma_heap.c
@@ -115,6 +115,7 @@
dev_dbg(dev, "Release buffer %p\n", buffer);
/* release memory */
dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
+ sg_free_table(info->table);
/* release sg table */
kfree(info->table);
kfree(info);
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index e1b3eea..b3960b2 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -154,6 +154,7 @@
dev_dbg(dev, "Release buffer %p\n", buffer);
/* release memory */
dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
+ sg_free_table(info->table);
/* release sg table */
kfree(info->table);
kfree(info);
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index bc9bddd..b1c1c5d 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -42,6 +42,7 @@
*/
struct ion_iommu_priv_data {
struct page **pages;
+ unsigned int pages_uses_vmalloc;
int nrpages;
unsigned long size;
};
@@ -118,6 +119,7 @@
unsigned int npages_to_vmap, total_pages, num_large_pages = 0;
unsigned long size_remaining = PAGE_ALIGN(size);
unsigned int max_order = ION_IS_CACHED(flags) ? 0 : orders[0];
+ unsigned int page_tbl_size;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@@ -139,8 +141,24 @@
data->size = PFN_ALIGN(size);
data->nrpages = data->size >> PAGE_SHIFT;
- data->pages = kzalloc(sizeof(struct page *)*data->nrpages,
- GFP_KERNEL);
+ data->pages_uses_vmalloc = 0;
+ page_tbl_size = sizeof(struct page *) * data->nrpages;
+
+ if (page_tbl_size > SZ_8K) {
+ /*
+ * Do fallback to ensure we have a balance between
+ * performance and availability.
+ */
+ data->pages = kmalloc(page_tbl_size,
+ __GFP_COMP | __GFP_NORETRY |
+ __GFP_NO_KSWAPD | __GFP_NOWARN);
+ if (!data->pages) {
+ data->pages = vmalloc(page_tbl_size);
+ data->pages_uses_vmalloc = 1;
+ }
+ } else {
+ data->pages = kmalloc(page_tbl_size, GFP_KERNEL);
+ }
if (!data->pages) {
ret = -ENOMEM;
goto err_free_data;
@@ -222,7 +240,10 @@
kfree(buffer->sg_table);
buffer->sg_table = 0;
err1:
- kfree(data->pages);
+ if (data->pages_uses_vmalloc)
+ vfree(data->pages);
+ else
+ kfree(data->pages);
err_free_data:
kfree(data);
@@ -253,7 +274,10 @@
sg_free_table(table);
kfree(table);
table = 0;
- kfree(data->pages);
+ if (data->pages_uses_vmalloc)
+ vfree(data->pages);
+ else
+ kfree(data->pages);
kfree(data);
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index d95c12b..a4f60f9 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -101,13 +101,6 @@
.iomemname = KGSL_3D0_REG_MEMORY,
.shadermemname = KGSL_3D0_SHADER_MEMORY,
.ftbl = &adreno_functable,
-#ifdef CONFIG_HAS_EARLYSUSPEND
- .display_off = {
- .level = EARLY_SUSPEND_LEVEL_STOP_DRAWING,
- .suspend = kgsl_early_suspend_driver,
- .resume = kgsl_late_resume_driver,
- },
-#endif
},
.gmem_base = 0,
.gmem_size = SZ_256K,
@@ -813,7 +806,8 @@
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
if (!adreno_dev->drawctxt_active ||
- KGSL_STATE_ACTIVE != device->state) {
+ KGSL_STATE_ACTIVE != device->state ||
+ !device->active_cnt) {
kgsl_mmu_device_setstate(&device->mmu, flags);
return;
}
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 967e4ab..144c3d6 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -822,7 +822,8 @@
int remain, void *priv)
{
struct kgsl_snapshot_replay_mem_list *header = snapshot;
- struct kgsl_process_private *private;
+ struct kgsl_process_private *private = NULL;
+ struct kgsl_process_private *tmp_private;
unsigned int ptbase;
struct rb_node *node;
struct kgsl_mem_entry *entry = NULL;
@@ -831,10 +832,12 @@
ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
mutex_lock(&kgsl_driver.process_mutex);
- list_for_each_entry(private, &kgsl_driver.process_list, list) {
- if (kgsl_mmu_pt_equal(&device->mmu, private->pagetable,
- ptbase))
+ list_for_each_entry(tmp_private, &kgsl_driver.process_list, list) {
+ if (kgsl_mmu_pt_equal(&device->mmu, tmp_private->pagetable,
+ ptbase)) {
+ private = tmp_private;
break;
+ }
}
mutex_unlock(&kgsl_driver.process_mutex);
if (!private) {
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2b674ab..992f88d 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -625,20 +625,6 @@
};
EXPORT_SYMBOL(kgsl_pm_ops);
-void kgsl_early_suspend_driver(struct early_suspend *h)
-{
- struct kgsl_device *device = container_of(h,
- struct kgsl_device, display_off);
- KGSL_PWR_WARN(device, "early suspend start\n");
- mutex_lock(&device->mutex);
- device->pwrctrl.restore_slumber = true;
- kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
- kgsl_pwrctrl_sleep(device);
- mutex_unlock(&device->mutex);
- KGSL_PWR_WARN(device, "early suspend end\n");
-}
-EXPORT_SYMBOL(kgsl_early_suspend_driver);
-
int kgsl_suspend_driver(struct platform_device *pdev,
pm_message_t state)
{
@@ -654,101 +640,44 @@
}
EXPORT_SYMBOL(kgsl_resume_driver);
-void kgsl_late_resume_driver(struct early_suspend *h)
+/**
+ * kgsl_destroy_process_private() - Cleanup function to free process private
+ * @kref: - Pointer to object being destroyed's kref struct
+ * Free struct object and all other resources attached to it.
+ * Since the function can be used when not all resources inside process
+ * private have been allocated, there is a check to (before each resource
+ * cleanup) see if the struct member being cleaned is in fact allocated or not.
+ * If the value is not NULL, resource is freed.
+ */
+static void kgsl_destroy_process_private(struct kref *kref)
{
- struct kgsl_device *device = container_of(h,
- struct kgsl_device, display_off);
- KGSL_PWR_WARN(device, "late resume start\n");
- mutex_lock(&device->mutex);
- device->pwrctrl.restore_slumber = false;
- if (device->pwrscale.policy == NULL)
- kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
- if (kgsl_pwrctrl_wake(device) != 0)
- return;
- /*
- * We don't have a way to go directly from
- * a deeper sleep state to NAP, which is
- * the desired state here.
- */
- kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
- kgsl_pwrctrl_sleep(device);
- mutex_unlock(&device->mutex);
- KGSL_PWR_WARN(device, "late resume end\n");
-}
-EXPORT_SYMBOL(kgsl_late_resume_driver);
-/* file operations */
-static struct kgsl_process_private *
-kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
-{
- struct kgsl_process_private *private;
-
- mutex_lock(&kgsl_driver.process_mutex);
- list_for_each_entry(private, &kgsl_driver.process_list, list) {
- if (private->pid == task_tgid_nr(current)) {
- private->refcnt++;
- goto out;
- }
- }
-
- /* no existing process private found for this dev_priv, create one */
- private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
- if (private == NULL) {
- KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n",
- sizeof(struct kgsl_process_private));
- goto out;
- }
-
- spin_lock_init(&private->mem_lock);
- private->refcnt = 1;
- private->pid = task_tgid_nr(current);
- private->mem_rb = RB_ROOT;
-
- idr_init(&private->mem_idr);
-
- if (kgsl_mmu_enabled())
- {
- unsigned long pt_name;
- struct kgsl_mmu *mmu = &cur_dev_priv->device->mmu;
-
- pt_name = task_tgid_nr(current);
- private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
- if (private->pagetable == NULL) {
- kfree(private);
- private = NULL;
- goto out;
- }
- }
-
- list_add(&private->list, &kgsl_driver.process_list);
-
- kgsl_process_init_sysfs(private);
- kgsl_process_init_debugfs(private);
-
-out:
- mutex_unlock(&kgsl_driver.process_mutex);
- return private;
-}
-
-static void
-kgsl_put_process_private(struct kgsl_device *device,
- struct kgsl_process_private *private)
-{
struct kgsl_mem_entry *entry = NULL;
int next = 0;
- if (!private)
+
+ struct kgsl_process_private *private = container_of(kref,
+ struct kgsl_process_private, refcount);
+
+ /*
+ * Remove this process from global process list
+ * We do not acquire a lock first as it is expected that
+ * kgsl_destroy_process_private() is only going to be called
+ * through kref_put() which is only called after acquiring
+ * the lock.
+ */
+ if (!private) {
+ KGSL_CORE_ERR("Cannot destroy null process private\n");
+ mutex_unlock(&kgsl_driver.process_mutex);
return;
-
- mutex_lock(&kgsl_driver.process_mutex);
-
- if (--private->refcnt)
- goto unlock;
-
- kgsl_process_uninit_sysfs(private);
- debugfs_remove_recursive(private->debug_root);
-
+ }
list_del(&private->list);
+ mutex_unlock(&kgsl_driver.process_mutex);
+
+ if (private->kobj.parent)
+ kgsl_process_uninit_sysfs(private);
+ if (private->debug_root)
+ debugfs_remove_recursive(private->debug_root);
while (1) {
rcu_read_lock();
@@ -766,9 +695,110 @@
}
kgsl_mmu_putpagetable(private->pagetable);
idr_destroy(&private->mem_idr);
+
kfree(private);
-unlock:
+ return;
+}
+
+static void
+kgsl_put_process_private(struct kgsl_device *device,
+ struct kgsl_process_private *private)
+{
+ mutex_lock(&kgsl_driver.process_mutex);
+
+ /*
+ * kref_put() returns 1 when the refcnt has reached 0 and the destroy
+ * function is called. Mutex is released in the destroy function if
+ * its called, so only release mutex if kref_put() return 0
+ */
+ if (!kref_put(&private->refcount, kgsl_destroy_process_private))
+ mutex_unlock(&kgsl_driver.process_mutex);
+ return;
+}
+
+/**
+ * find_process_private() - Helper function to search for process private
+ * @cur_dev_priv: Pointer to device private structure which contains pointers
+ * to device and process_private structs.
+ * Returns: Pointer to the found/newly created private struct
+ */
+static struct kgsl_process_private *
+kgsl_find_process_private(struct kgsl_device_private *cur_dev_priv)
+{
+ struct kgsl_process_private *private;
+
+ /* Search in the process list */
+ mutex_lock(&kgsl_driver.process_mutex);
+ list_for_each_entry(private, &kgsl_driver.process_list, list) {
+ if (private->pid == task_tgid_nr(current)) {
+ kref_get(&private->refcount);
+ goto done;
+ }
+ }
+
+ /* no existing process private found for this dev_priv, create one */
+ private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
+ if (private == NULL) {
+ KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n",
+ sizeof(struct kgsl_process_private));
+ goto done;
+ }
+
+ kref_init(&private->refcount);
+
+ private->pid = task_tgid_nr(current);
+ spin_lock_init(&private->mem_lock);
+ mutex_init(&private->process_private_mutex);
+ /* Add the newly created process struct obj to the process list */
+ list_add(&private->list, &kgsl_driver.process_list);
+done:
mutex_unlock(&kgsl_driver.process_mutex);
+ return private;
+}
+
+/**
+ * kgsl_get_process_private() - Used to find the process private structure
+ * @cur_dev_priv: Current device pointer
+ * Finds or creates a new porcess private structire and initializes its members
+ * Returns: Pointer to the private process struct obj found/created or
+ * NULL if pagetable creation for this process private obj failed.
+ */
+static struct kgsl_process_private *
+kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
+{
+ struct kgsl_process_private *private;
+
+ private = kgsl_find_process_private(cur_dev_priv);
+
+ mutex_lock(&private->process_private_mutex);
+
+ if (!private->mem_rb.rb_node) {
+ private->mem_rb = RB_ROOT;
+ idr_init(&private->mem_idr);
+ }
+
+ if ((!private->pagetable) && kgsl_mmu_enabled()) {
+ unsigned long pt_name;
+ struct kgsl_mmu *mmu = &cur_dev_priv->device->mmu;
+
+ pt_name = task_tgid_nr(current);
+ private->pagetable = kgsl_mmu_getpagetable(mmu, pt_name);
+ if (private->pagetable == NULL) {
+ mutex_unlock(&private->process_private_mutex);
+ kgsl_put_process_private(cur_dev_priv->device,
+ private);
+ return NULL;
+ }
+ }
+
+ if (!private->kobj.parent)
+ kgsl_process_init_sysfs(private);
+ if (!private->debug_root)
+ kgsl_process_init_debugfs(private);
+
+ mutex_unlock(&private->process_private_mutex);
+
+ return private;
}
static int kgsl_release(struct inode *inodep, struct file *filep)
@@ -879,7 +909,12 @@
result = device->ftbl->start(device);
if (result)
goto err_freedevpriv;
-
+ /*
+ * Make sure the gates are open, so they don't block until
+ * we start suspend or FT.
+ */
+ complete_all(&device->ft_gate);
+ complete_all(&device->hwaccess_gate);
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
kgsl_active_count_put(device);
}
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index debba18..c7cbaf8 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -46,7 +46,11 @@
#define KGSL_PAGETABLE_ENTRY_SIZE 4
/* Pagetable Virtual Address base */
+#ifndef CONFIG_MSM_KGSL_CFF_DUMP
#define KGSL_PAGETABLE_BASE 0x10000000
+#else
+#define KGSL_PAGETABLE_BASE 0xE0000000
+#endif
/* Extra accounting entries needed in the pagetable */
#define KGSL_PT_EXTRA_ENTRIES 16
@@ -222,11 +226,8 @@
extern const struct dev_pm_ops kgsl_pm_ops;
-struct early_suspend;
int kgsl_suspend_driver(struct platform_device *pdev, pm_message_t state);
int kgsl_resume_driver(struct platform_device *pdev);
-void kgsl_early_suspend_driver(struct early_suspend *h);
-void kgsl_late_resume_driver(struct early_suspend *h);
void kgsl_trace_regwrite(struct kgsl_device *device, unsigned int offset,
unsigned int value);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index ac82820..3ee9e4e 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -15,7 +15,6 @@
#include <linux/idr.h>
#include <linux/pm_qos.h>
-#include <linux/earlysuspend.h>
#include "kgsl.h"
#include "kgsl_mmu.h"
@@ -190,12 +189,12 @@
struct completion ft_gate;
struct dentry *d_debugfs;
struct idr context_idr;
- struct early_suspend display_off;
void *snapshot; /* Pointer to the snapshot memory region */
int snapshot_maxsize; /* Max size of the snapshot region */
int snapshot_size; /* Current size of the snapshot region */
u32 snapshot_timestamp; /* Timestamp of the last valid snapshot */
+ u32 snapshot_faultcount; /* Total number of faults since boot */
int snapshot_frozen; /* 1 if the snapshot output is frozen until
it gets read by the user. This avoids
losing the output on multiple hangs */
@@ -280,6 +279,12 @@
unsigned int refcnt;
pid_t pid;
spinlock_t mem_lock;
+
+ /* General refcount for process private struct obj */
+ struct kref refcount;
+ /* Mutex to synchronize access to each process_private struct obj */
+ struct mutex process_private_mutex;
+
struct rb_root mem_rb;
struct idr mem_idr;
struct kgsl_pagetable *pagetable;
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index d872783..a1fc5a2 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -143,6 +143,15 @@
cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
id = context->id;
+ /*
+ * Increment the refcount to avoid freeing the context while
+ * cancelling its events
+ */
+ kgsl_context_get(context);
+
+ /* Remove ourselves from the master pending list */
+ list_del_init(&context->events_list);
+
list_for_each_entry_safe(event, event_tmp, &context->events, list) {
/*
* "cancel" the events by calling their callback.
@@ -165,9 +174,7 @@
kgsl_active_count_put(device);
}
-
- /* Remove ourselves from the master pending list */
- list_del_init(&context->events_list);
+ kgsl_context_put(context);
}
/**
@@ -261,7 +268,8 @@
* timestamp on the event has passed - return that up a layer
*/
- return device->ftbl->next_event(device, event);
+ if (device->ftbl->next_event)
+ return device->ftbl->next_event(device, event);
}
return 0;
@@ -313,12 +321,18 @@
events_list) {
/*
+ * Increment the refcount to make sure that the list_del_init
+ * is called with a valid context's list
+ */
+ kgsl_context_get(context);
+ /*
* If kgsl_timestamp_expired_context returns 0 then it no longer
* has any pending events and can be removed from the list
*/
if (kgsl_process_context_events(device, context) == 0)
list_del_init(&context->events_list);
+ kgsl_context_put(context);
}
mutex_unlock(&device->mutex);
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 3057723..513fb90 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1345,13 +1345,27 @@
* we're better off with extra room.
*/
if (mmu->pt_per_process) {
+#ifndef CONFIG_MSM_KGSL_CFF_DUMP
mmu->pt_base = PAGE_OFFSET;
mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE
- kgsl_mmu_get_base_addr(mmu) - SZ_1M;
mmu->use_cpu_map = true;
+#else
+ mmu->pt_base = KGSL_PAGETABLE_BASE;
+ mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE +
+ KGSL_IOMMU_GLOBAL_MEM_SIZE -
+ KGSL_PAGETABLE_BASE;
+ mmu->use_cpu_map = false;
+#endif
} else {
mmu->pt_base = KGSL_PAGETABLE_BASE;
+#ifndef CONFIG_MSM_KGSL_CFF_DUMP
mmu->pt_size = SZ_2G;
+#else
+ mmu->pt_size = KGSL_IOMMU_GLOBAL_MEM_BASE +
+ KGSL_IOMMU_GLOBAL_MEM_SIZE -
+ KGSL_PAGETABLE_BASE;
+#endif
mmu->use_cpu_map = false;
}
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index ef5b0f4..02cde94 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -410,7 +410,7 @@
*/
static inline int kgsl_mmu_use_cpu_map(struct kgsl_mmu *mmu)
{
- return mmu->pt_per_process;
+ return mmu->use_cpu_map;
}
/*
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index b124257..52340cc 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1021,7 +1021,6 @@
pwr->pm_qos_latency = 501;
pm_runtime_enable(device->parentdev);
- register_early_suspend(&device->display_off);
return result;
clk_err:
@@ -1041,7 +1040,6 @@
KGSL_PWR_INFO(device, "close device %d\n", device->id);
pm_runtime_disable(device->parentdev);
- unregister_early_suspend(&device->display_off);
clk_put(pwr->ebi1_clk);
@@ -1151,8 +1149,7 @@
KGSL_PWR_INFO(device, "idle timer expired device %d\n", device->id);
if (device->requested_state != KGSL_STATE_SUSPEND) {
- if (device->pwrctrl.restore_slumber ||
- device->pwrctrl.strtstp_sleepwake)
+ if (device->pwrctrl.strtstp_sleepwake)
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
else
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
@@ -1448,20 +1445,17 @@
BUG_ON(!mutex_is_locked(&device->mutex));
if (device->active_cnt == 0) {
- if (device->requested_state == KGSL_STATE_SUSPEND ||
- device->state == KGSL_STATE_SUSPEND) {
- mutex_unlock(&device->mutex);
- wait_for_completion(&device->hwaccess_gate);
- mutex_lock(&device->mutex);
- } else if (device->state == KGSL_STATE_DUMP_AND_FT) {
- mutex_unlock(&device->mutex);
- wait_for_completion(&device->ft_gate);
- mutex_lock(&device->mutex);
- }
+ mutex_unlock(&device->mutex);
+ wait_for_completion(&device->hwaccess_gate);
+ wait_for_completion(&device->ft_gate);
+ mutex_lock(&device->mutex);
+
ret = kgsl_pwrctrl_wake(device);
}
if (ret == 0)
device->active_cnt++;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
return ret;
}
EXPORT_SYMBOL(kgsl_active_count_get);
@@ -1490,6 +1484,8 @@
}
device->active_cnt++;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
return 0;
}
EXPORT_SYMBOL(kgsl_active_count_get_light);
@@ -1512,6 +1508,8 @@
kgsl_pwrscale_idle(device);
if (device->active_cnt > 1) {
device->active_cnt--;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
return;
}
@@ -1528,6 +1526,8 @@
}
device->active_cnt--;
+ trace_kgsl_active_count(device,
+ (unsigned long) __builtin_return_address(0));
if (device->active_cnt == 0)
complete(&device->suspend_gate);
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index b3e8702..2b986c8 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -58,7 +58,6 @@
* @nap_allowed - true if the device supports naps
* @idle_needed - true if the device needs a idle before clock change
* @irq_name - resource name for the IRQ
- * @restore_slumber - Flag to indicate that we are in a suspend/restore sequence
* @clk_stats - structure of clock statistics
* @pm_qos_req_dma - the power management quality of service structure
* @pm_qos_latency - allowed CPU latency in microseconds
@@ -86,7 +85,6 @@
unsigned int idle_needed;
const char *irq_name;
s64 time;
- unsigned int restore_slumber;
struct kgsl_clk_stats clk_stats;
struct pm_qos_request pm_qos_req_dma;
unsigned int pm_qos_latency;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index b9bc432..4071b37 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -598,7 +598,7 @@
gfp_mask |= __GFP_COMP | __GFP_NORETRY |
__GFP_NO_KSWAPD | __GFP_NOWARN;
else
- gfp_mask |= GFP_KERNEL | __GFP_NORETRY;
+ gfp_mask |= GFP_KERNEL;
page = alloc_pages(gfp_mask, get_order(page_size));
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index f09c623..6fcd912 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -536,6 +536,10 @@
void *snapshot;
struct timespec boot;
+ /* increment the hang count (on hang) for good book keeping */
+ if (hang)
+ device->snapshot_faultcount++;
+
/*
* The first hang is always the one we are interested in. To
* avoid a subsequent hang blowing away the first, the snapshot
@@ -674,6 +678,22 @@
return itr.write;
}
+/* Show the total number of hangs since device boot */
+static ssize_t faultcount_show(struct kgsl_device *device, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", device->snapshot_faultcount);
+}
+
+/* Reset the total number of hangs since device boot */
+static ssize_t faultcount_store(struct kgsl_device *device, const char *buf,
+ size_t count)
+{
+ if (device && count > 0)
+ device->snapshot_faultcount = 0;
+
+ return count;
+}
+
/* Show the timestamp of the last collected snapshot */
static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
{
@@ -709,6 +729,7 @@
SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
+SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store);
static void snapshot_sysfs_release(struct kobject *kobj)
{
@@ -774,6 +795,7 @@
device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
device->snapshot_timestamp = 0;
+ device->snapshot_faultcount = 0;
INIT_LIST_HEAD(&device->snapshot_obj_list);
@@ -791,6 +813,10 @@
goto done;
ret = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
+ if (ret)
+ goto done;
+
+ ret = sysfs_create_file(&device->snapshot_kobj, &attr_faultcount.attr);
done:
return ret;
@@ -817,5 +843,6 @@
device->snapshot = NULL;
device->snapshot_maxsize = 0;
device->snapshot_timestamp = 0;
+ device->snapshot_faultcount = 0;
}
EXPORT_SYMBOL(kgsl_device_snapshot_close);
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 5f7ee3c..08677ef 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -739,6 +739,30 @@
__entry->id, __entry->ts, __entry->age)
);
+TRACE_EVENT(kgsl_active_count,
+
+ TP_PROTO(struct kgsl_device *device, unsigned long ip),
+
+ TP_ARGS(device, ip),
+
+ TP_STRUCT__entry(
+ __string(device_name, device->name)
+ __field(unsigned int, count)
+ __field(unsigned long, ip)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device_name, device->name);
+ __entry->count = device->active_cnt;
+ __entry->ip = ip;
+ ),
+
+ TP_printk(
+ "d_name=%s active_cnt=%x func=%pf",
+ __get_str(device_name), __entry->count, (void *) __entry->ip
+ )
+);
+
#endif /* _KGSL_TRACE_H */
/* This part must be outside protection */
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 275291f..f6ab3c2 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -95,6 +95,7 @@
#define QPNP_IADC_LSB_OFFSET 0xF3
#define QPNP_IADC_NOMINAL_RSENSE 0xF4
#define QPNP_IADC_ATE_GAIN_CALIB_OFFSET 0xF5
+#define QPNP_INT_TEST_VAL 0xE1
#define QPNP_IADC_ADC_CH_SEL_CTL 0x48
#define QPNP_IADC_ADC_CHX_SEL_SHIFT 3
@@ -126,16 +127,24 @@
#define QPNP_RSENSE_MSB_SIGN_CHECK 0x80
#define QPNP_ADC_COMPLETION_TIMEOUT HZ
+struct qpnp_iadc_comp {
+ bool ext_rsense;
+ u8 id;
+ u8 sys_gain;
+ u8 revision;
+};
+
struct qpnp_iadc_drv {
struct qpnp_adc_drv *adc;
int32_t rsense;
bool external_rsense;
struct device *iadc_hwmon;
bool iadc_initialized;
- int64_t die_temp_calib_offset;
+ int64_t die_temp;
struct delayed_work iadc_work;
struct mutex iadc_vadc_lock;
bool iadc_mode_sel;
+ struct qpnp_iadc_comp iadc_comp;
struct sensor_device_attribute sens_attr[0];
};
@@ -293,6 +302,104 @@
return 0;
}
+static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_comp comp,
+ int64_t die_temp)
+{
+ int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0, old;
+
+ old = *result;
+ *result = *result * 1000000;
+
+ if (comp.revision == QPNP_IADC_VER_3_1) {
+ /* revision 3.1 */
+ if (comp.sys_gain > 127)
+ sys_gain_coeff = -QPNP_COEFF_6 * (comp.sys_gain - 128);
+ else
+ sys_gain_coeff = QPNP_COEFF_6 * comp.sys_gain;
+ } else if (comp.revision != QPNP_IADC_VER_3_0) {
+ /* unsupported revision, do not compensate */
+ *result = old;
+ return 0;
+ }
+
+ if (!comp.ext_rsense) {
+ /* internal rsense */
+ switch (comp.id) {
+ case COMP_ID_TSMC:
+ temp_var = ((QPNP_COEFF_2 * die_temp) -
+ QPNP_COEFF_3_TYPEB);
+ break;
+ case COMP_ID_GF:
+ default:
+ temp_var = ((QPNP_COEFF_2 * die_temp) -
+ QPNP_COEFF_3_TYPEA);
+ break;
+ }
+ temp_var = div64_s64(temp_var, QPNP_COEFF_4);
+ if (comp.revision == QPNP_IADC_VER_3_0)
+ temp_var = QPNP_COEFF_1 * (1000000 - temp_var);
+ else if (comp.revision == QPNP_IADC_VER_3_1)
+ temp_var = 1000000 * (1000000 - temp_var);
+ *result = div64_s64(*result * 1000000, temp_var);
+ }
+
+ sign_coeff = *result < 0 ? QPNP_COEFF_7 : QPNP_COEFF_5;
+ if (comp.ext_rsense) {
+ /* external rsense and current charging */
+ temp_var = div64_s64((-sign_coeff * die_temp) + QPNP_COEFF_8,
+ QPNP_COEFF_4);
+ temp_var = 1000000000 - temp_var;
+ if (comp.revision == QPNP_IADC_VER_3_1) {
+ sys_gain_coeff = (1000000 +
+ div64_s64(sys_gain_coeff, QPNP_COEFF_4));
+ temp_var = div64_s64(temp_var * sys_gain_coeff,
+ 1000000000);
+ }
+ *result = div64_s64(*result, temp_var);
+ }
+ pr_debug("%lld compensated into %lld\n", old, *result);
+
+ return 0;
+}
+
+int32_t qpnp_iadc_comp_result(int64_t *result)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+
+ return qpnp_iadc_comp(result, iadc->iadc_comp, iadc->die_temp);
+}
+EXPORT_SYMBOL(qpnp_iadc_comp_result);
+
+static int32_t qpnp_iadc_comp_info(void)
+{
+ struct qpnp_iadc_drv *iadc = qpnp_iadc;
+ int rc = 0;
+
+ rc = qpnp_iadc_read_reg(QPNP_INT_TEST_VAL, &iadc->iadc_comp.id);
+ if (rc < 0) {
+ pr_err("qpnp adc comp id failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_iadc_read_reg(QPNP_IADC_REVISION2, &iadc->iadc_comp.revision);
+ if (rc < 0) {
+ pr_err("qpnp adc revision read failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_iadc_read_reg(QPNP_IADC_ATE_GAIN_CALIB_OFFSET,
+ &iadc->iadc_comp.sys_gain);
+ if (rc < 0)
+ pr_err("full scale read failed with %d\n", rc);
+
+ pr_debug("fab id = %u, revision = %u, sys gain = %u, external_rsense = %d\n",
+ iadc->iadc_comp.id,
+ iadc->iadc_comp.revision,
+ iadc->iadc_comp.sys_gain,
+ iadc->iadc_comp.ext_rsense);
+ return rc;
+}
+
static int32_t qpnp_iadc_configure(enum qpnp_iadc_channels channel,
uint16_t *raw_code, uint32_t mode_sel)
{
@@ -583,12 +690,12 @@
return rc;
die_temp_offset = result_pmic_therm.physical -
- iadc->die_temp_calib_offset;
+ iadc->die_temp;
if (die_temp_offset < 0)
die_temp_offset = -die_temp_offset;
if (die_temp_offset > QPNP_IADC_DIE_TEMP_CALIB_OFFSET) {
- iadc->die_temp_calib_offset =
+ iadc->die_temp =
result_pmic_therm.physical;
rc = qpnp_iadc_calibrate_for_trim();
if (rc)
@@ -640,12 +747,17 @@
(iadc->adc->calib.gain_raw - iadc->adc->calib.offset_raw);
result_current = result->result_uv;
result_current *= QPNP_IADC_NANO_VOLTS_FACTOR;
+ /* Intentional fall through. Process the result w/o comp */
do_div(result_current, rsense_u_ohms);
if (sign) {
result->result_uv = -result->result_uv;
result_current = -result_current;
}
+ rc = qpnp_iadc_comp_result(&result_current);
+ if (rc < 0)
+ pr_err("Error during compensating the IADC\n");
+ rc = 0;
result->result_ua = (int32_t) result_current;
fail:
@@ -868,6 +980,11 @@
mutex_init(&iadc->iadc_vadc_lock);
INIT_DELAYED_WORK(&iadc->iadc_work, qpnp_iadc_work);
+ rc = qpnp_iadc_comp_info();
+ if (rc) {
+ dev_err(&spmi->dev, "abstracting IADC comp info failed!\n");
+ goto fail;
+ }
iadc->iadc_initialized = true;
rc = qpnp_iadc_calibrate_for_trim();
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index edb1d66..4306b1d 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -83,6 +83,15 @@
#define QPNP_VADC_M1_LOW_THR_MSB 0x6a
#define QPNP_VADC_M1_HIGH_THR_LSB 0x6b
#define QPNP_VADC_M1_HIGH_THR_MSB 0x6c
+#define QPNP_VADC_ACCESS 0xd0
+#define QPNP_VADC_ACCESS_DATA 0xa5
+#define QPNP_VADC_PERH_RESET_CTL3 0xda
+#define QPNP_FOLLOW_OTST2_RB BIT(3)
+#define QPNP_FOLLOW_WARM_RB BIT(2)
+#define QPNP_FOLLOW_SHUTDOWN1_RB BIT(1)
+#define QPNP_FOLLOW_SHUTDOWN2_RB BIT(0)
+
+#define QPNP_INT_TEST_VAL 0xE1
#define QPNP_VADC_DATA0 0x60
#define QPNP_VADC_DATA1 0x61
@@ -100,7 +109,8 @@
bool vadc_initialized;
int max_channels_available;
bool vadc_iadc_sync_lock;
- struct sensor_device_attribute sens_attr[0];
+ u8 id;
+ struct sensor_device_attribute sens_attr[0];
};
struct qpnp_vadc_drv *qpnp_vadc;
@@ -148,6 +158,40 @@
return 0;
}
+static int32_t qpnp_vadc_warm_rst_configure(void)
+{
+ int rc = 0;
+ u8 data = 0;
+
+ rc = qpnp_vadc_write_reg(QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
+ if (rc < 0) {
+ pr_err("VADC write access failed\n");
+ return rc;
+ }
+
+ rc = qpnp_vadc_read_reg(QPNP_VADC_PERH_RESET_CTL3, &data);
+ if (rc < 0) {
+ pr_err("VADC perh reset ctl3 read failed\n");
+ return rc;
+ }
+
+ rc = qpnp_vadc_write_reg(QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
+ if (rc < 0) {
+ pr_err("VADC write access failed\n");
+ return rc;
+ }
+
+ data |= QPNP_FOLLOW_WARM_RB;
+
+ rc = qpnp_vadc_write_reg(QPNP_VADC_PERH_RESET_CTL3, data);
+ if (rc < 0) {
+ pr_err("VADC perh reset ctl3 write failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
static int32_t qpnp_vadc_enable(bool state)
{
int rc = 0;
@@ -432,6 +476,62 @@
return 0;
}
+static int32_t qpnp_vbat_sns_comp(int64_t *result, u8 id, int64_t die_temp)
+{
+ int64_t temp_var = 0;
+ int64_t old = *result;
+
+ if (die_temp < 25000)
+ return 0;
+
+ switch (id) {
+ case COMP_ID_TSMC:
+ temp_var = (((die_temp *
+ (-QPNP_VBAT_SNS_COEFF_1_TYPEB))
+ + QPNP_VBAT_SNS_COEFF_2_TYPEB));
+ break;
+ default:
+ case COMP_ID_GF:
+ temp_var = (((die_temp *
+ (-QPNP_VBAT_SNS_COEFF_1_TYPEA))
+ + QPNP_VBAT_SNS_COEFF_2_TYPEA));
+ break;
+ }
+
+ temp_var = div64_s64(temp_var, QPNP_VBAT_SNS_COEFF_3);
+
+ temp_var = 1000000 + temp_var;
+
+ *result = *result * temp_var;
+
+ *result = div64_s64(*result, 1000000);
+ pr_debug("%lld compensated into %lld\n", old, *result);
+
+ return 0;
+}
+
+int32_t qpnp_vbat_sns_comp_result(int64_t *result)
+{
+ struct qpnp_vadc_drv *vadc = qpnp_vadc;
+ struct qpnp_vadc_result die_temp_result;
+ int rc = 0;
+
+ rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ DIE_TEMP, &die_temp_result);
+ if (rc < 0) {
+ pr_err("Error reading die_temp\n");
+ return rc;
+ }
+
+ rc = qpnp_vbat_sns_comp(result, vadc->id,
+ die_temp_result.physical);
+ if (rc < 0)
+ pr_err("Error with vbat compensation\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_vbat_sns_comp_result);
+
static void qpnp_vadc_625mv_channel_sel(uint32_t *ref_channel_sel)
{
struct qpnp_vadc_drv *vadc = qpnp_vadc;
@@ -790,7 +890,34 @@
int32_t qpnp_vadc_read(enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result)
{
- return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ struct qpnp_vadc_drv *vadc = qpnp_vadc;
+ enum qpnp_vadc_channels;
+ struct qpnp_vadc_result die_temp_result;
+ int rc = 0;
+
+ if (channel == VBAT_SNS) {
+ rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ channel, result);
+ if (rc < 0) {
+ pr_err("Error reading vbatt\n");
+ return rc;
+ }
+
+ rc = qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
+ DIE_TEMP, &die_temp_result);
+ if (rc < 0) {
+ pr_err("Error reading die_temp\n");
+ return rc;
+ }
+
+ rc = qpnp_vbat_sns_comp(&result->physical, vadc->id,
+ die_temp_result.physical);
+ if (rc < 0)
+ pr_err("Error with vbat compensation\n");
+
+ return 0;
+ } else
+ return qpnp_vadc_conv_seq_request(ADC_SEQ_NONE,
channel, result);
}
EXPORT_SYMBOL(qpnp_vadc_read);
@@ -970,6 +1097,7 @@
struct device_node *node = spmi->dev.of_node;
struct device_node *child;
int rc, count_adc_channel_list = 0;
+ u8 fab_id = 0;
if (!node)
return -EINVAL;
@@ -1033,6 +1161,19 @@
vadc->vadc_hwmon = hwmon_device_register(&vadc->adc->spmi->dev);
vadc->vadc_init_calib = false;
vadc->max_channels_available = count_adc_channel_list;
+ rc = qpnp_vadc_read_reg(QPNP_INT_TEST_VAL, &fab_id);
+ if (rc < 0) {
+ pr_err("qpnp adc comp id failed with %d\n", rc);
+ return rc;
+ }
+ vadc->id = fab_id;
+
+ rc = qpnp_vadc_warm_rst_configure();
+ if (rc < 0) {
+ pr_err("Setting perp reset on warm reset failed %d\n", rc);
+ return rc;
+ }
+
vadc->vadc_initialized = true;
vadc->vadc_iadc_sync_lock = false;
diff --git a/drivers/input/touchscreen/gen_vkeys.c b/drivers/input/touchscreen/gen_vkeys.c
index 21e4829..efddf61 100644
--- a/drivers/input/touchscreen/gen_vkeys.c
+++ b/drivers/input/touchscreen/gen_vkeys.c
@@ -24,6 +24,8 @@
#define HEIGHT_SCALE_NUM 8
#define HEIGHT_SCALE_DENOM 10
+#define VKEY_Y_OFFSET_DEFAULT 0
+
/* numerator and denomenator for border equations */
#define BORDER_ADJUST_NUM 3
#define BORDER_ADJUST_DENOM 4
@@ -59,7 +61,7 @@
{
struct device_node *np = dev->of_node;
struct property *prop;
- int rc;
+ int rc, val;
rc = of_property_read_string(np, "label", &pdata->name);
if (rc) {
@@ -106,10 +108,13 @@
}
}
- rc = of_property_read_u32(np, "qcom,y-offset", &pdata->y_offset);
- if (rc) {
+ pdata->y_offset = VKEY_Y_OFFSET_DEFAULT;
+ rc = of_property_read_u32(np, "qcom,y-offset", &val);
+ if (!rc)
+ pdata->y_offset = val;
+ else if (rc != -EINVAL) {
dev_err(dev, "Failed to read y position offset\n");
- return -EINVAL;
+ return rc;
}
return 0;
}
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index ed53c41..ba94178 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -2567,7 +2567,7 @@
if (rmi4_data->board->i2c_pull_up) {
retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
- RMI4_I2C_LOAD_UA);
+ RMI4_I2C_LPM_LOAD_UA);
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
"Regulator vcc_i2c set_opt failed rc=%d\n",
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index b92ec7f..10fa5b1 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -31,7 +31,8 @@
#include <mach/iommu_hw-v0.h>
#include <mach/msm_iommu_priv.h>
#include <mach/iommu.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
+#include <mach/msm_bus.h>
#define MRC(reg, processor, op1, crn, crm, op2) \
__asm__ __volatile__ ( \
@@ -135,6 +136,20 @@
return msm_iommu_remote_lock.lock;
}
+static int apply_bus_vote(struct msm_iommu_drvdata *drvdata, unsigned int vote)
+{
+ int ret = 0;
+
+ if (drvdata->bus_client) {
+ ret = msm_bus_scale_client_update_request(drvdata->bus_client,
+ vote);
+ if (ret)
+ pr_err("%s: Failed to vote for bus: %d\n", __func__,
+ vote);
+ }
+ return ret;
+}
+
static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
{
int ret;
@@ -202,6 +217,7 @@
struct iommu_access_ops iommu_access_ops_v0 = {
.iommu_power_on = __enable_regulators,
.iommu_power_off = __disable_regulators,
+ .iommu_bus_vote = apply_bus_vote,
.iommu_clk_on = __enable_clocks,
.iommu_clk_off = __disable_clocks,
.iommu_lock_initialize = _iommu_lock_initialize,
@@ -506,6 +522,11 @@
goto unlock;
}
+ ret = apply_bus_vote(iommu_drvdata, 1);
+
+ if (ret)
+ goto unlock;
+
ret = __enable_clocks(iommu_drvdata);
if (ret)
goto unlock;
@@ -572,6 +593,9 @@
msm_iommu_remote_spin_unlock();
__disable_clocks(iommu_drvdata);
+
+ apply_bus_vote(iommu_drvdata, 0);
+
list_del_init(&ctx_drvdata->attached_elm);
ctx_drvdata->attached_domain = NULL;
unlock:
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 8e68beb..f90bf6c 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -32,6 +32,7 @@
#include <mach/iommu.h>
#include <mach/msm_iommu_priv.h>
#include <mach/iommu_perfmon.h>
+#include <mach/msm_bus.h>
#include "msm_iommu_pagetable.h"
/* bitmap of the page sizes currently supported */
@@ -62,6 +63,20 @@
regulator_disable(drvdata->gdsc);
}
+static int apply_bus_vote(struct msm_iommu_drvdata *drvdata, unsigned int vote)
+{
+ int ret = 0;
+
+ if (drvdata->bus_client) {
+ ret = msm_bus_scale_client_update_request(drvdata->bus_client,
+ vote);
+ if (ret)
+ pr_err("%s: Failed to vote for bus: %d\n", __func__,
+ vote);
+ }
+ return ret;
+}
+
static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
{
int ret;
@@ -116,6 +131,7 @@
struct iommu_access_ops iommu_access_ops_v1 = {
.iommu_power_on = __enable_regulators,
.iommu_power_off = __disable_regulators,
+ .iommu_bus_vote = apply_bus_vote,
.iommu_clk_on = __enable_clocks,
.iommu_clk_off = __disable_clocks,
.iommu_lock_acquire = _iommu_lock_acquire,
@@ -513,6 +529,10 @@
if (ret)
goto fail;
+ ret = apply_bus_vote(iommu_drvdata, 1);
+ if (ret)
+ goto fail;
+
ret = __enable_clocks(iommu_drvdata);
if (ret) {
__disable_regulators(iommu_drvdata);
@@ -602,6 +622,8 @@
__disable_clocks(iommu_drvdata);
+ apply_bus_vote(iommu_drvdata, 0);
+
__disable_regulators(iommu_drvdata);
list_del_init(&ctx_drvdata->attached_elm);
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 059216e..4ee65d8 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -30,10 +30,13 @@
#include <mach/iommu_perfmon.h>
#include <mach/iommu_hw-v0.h>
#include <mach/iommu.h>
+#include <mach/msm_bus.h>
static DEFINE_MUTEX(iommu_list_lock);
static LIST_HEAD(iommu_list);
+static struct of_device_id msm_iommu_v0_ctx_match_table[];
+
void msm_iommu_add_drv(struct msm_iommu_drvdata *drv)
{
mutex_lock(&iommu_list_lock);
@@ -77,10 +80,13 @@
}
mutex_unlock(&iommu_list_lock);
- if (!dev || !dev_get_drvdata(dev))
- pr_err("Could not find context <%s>\n", ctx_name);
put_device(dev);
+ if (!dev || !dev_get_drvdata(dev)) {
+ pr_debug("Could not find context <%s>\n", ctx_name);
+ dev = ERR_PTR(-EPROBE_DEFER);
+ }
+
return dev;
}
EXPORT_SYMBOL(msm_iommu_get_ctx);
@@ -128,74 +134,24 @@
mb();
}
-static int msm_iommu_parse_dt(struct platform_device *pdev,
- struct msm_iommu_drvdata *drvdata,
- int *needs_alt_core_clk)
-{
-#ifdef CONFIG_OF_DEVICE
- struct device_node *child;
- struct resource *r;
- u32 glb_offset = 0;
- int ret;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- pr_err("%s: Missing property reg\n", __func__);
- return -EINVAL;
- }
- drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
- if (!drvdata->base) {
- pr_err("%s: Unable to ioremap %pr\n", __func__, r);
- return -ENOMEM;
- }
- drvdata->glb_base = drvdata->base;
-
- if (!of_property_read_u32(pdev->dev.of_node, "qcom,glb-offset",
- &glb_offset)) {
- drvdata->glb_base += glb_offset;
- } else {
- pr_err("%s: Missing property qcom,glb-offset\n", __func__);
- return -EINVAL;
- }
-
- for_each_child_of_node(pdev->dev.of_node, child) {
- drvdata->ncb++;
- if (!of_platform_device_create(child, NULL, &pdev->dev))
- pr_err("Failed to create %s device\n", child->name);
- }
-
- ret = of_property_read_string(pdev->dev.of_node, "label",
- &drvdata->name);
- if (ret) {
- pr_err("%s: Missing property label\n", __func__);
- return -EINVAL;
- }
-
- *needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
- "qcom,needs-alt-core-clk");
-
- drvdata->sec_id = -1;
- drvdata->ttbr_split = 0;
-#endif
- return 0;
-}
-
static int __get_clocks(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata,
int needs_alt_core_clk)
{
int ret = 0;
- drvdata->pclk = clk_get(&pdev->dev, "iface_clk");
+ drvdata->pclk = devm_clk_get(&pdev->dev, "iface_clk");
if (IS_ERR(drvdata->pclk)) {
ret = PTR_ERR(drvdata->pclk);
drvdata->pclk = NULL;
- pr_err("Unable to get %s clock for %s IOMMU device\n",
- dev_name(&pdev->dev), drvdata->name);
+ if (ret != -EPROBE_DEFER) {
+ pr_err("Unable to get %s clock for %s IOMMU device\n",
+ dev_name(&pdev->dev), drvdata->name);
+ }
goto fail;
}
- drvdata->clk = clk_get(&pdev->dev, "core_clk");
+ drvdata->clk = devm_clk_get(&pdev->dev, "core_clk");
if (!IS_ERR(drvdata->clk)) {
if (clk_get_rate(drvdata->clk) == 0) {
@@ -208,8 +164,10 @@
if (needs_alt_core_clk) {
drvdata->aclk = devm_clk_get(&pdev->dev, "alt_core_clk");
- if (IS_ERR(drvdata->aclk))
- return PTR_ERR(drvdata->aclk);
+ if (IS_ERR(drvdata->aclk)) {
+ ret = PTR_ERR(drvdata->aclk);
+ goto fail;
+ }
}
if (drvdata->aclk && clk_get_rate(drvdata->aclk) == 0) {
@@ -222,15 +180,127 @@
return ret;
}
-static void __put_clocks(struct msm_iommu_drvdata *drvdata)
+#ifdef CONFIG_OF_DEVICE
+
+static int __get_bus_vote_client(struct platform_device *pdev,
+ struct msm_iommu_drvdata *drvdata)
{
- if (drvdata->aclk)
- clk_put(drvdata->aclk);
- if (drvdata->clk)
- clk_put(drvdata->clk);
- clk_put(drvdata->pclk);
+ int ret = 0;
+ struct msm_bus_scale_pdata *bs_table;
+ const char *dummy;
+
+ /* Check whether bus scaling has been specified for this node */
+ ret = of_property_read_string(pdev->dev.of_node, "qcom,msm-bus,name",
+ &dummy);
+ if (ret)
+ return 0;
+
+ bs_table = msm_bus_cl_get_pdata(pdev);
+
+ if (bs_table) {
+ drvdata->bus_client = msm_bus_scale_register_client(bs_table);
+ if (IS_ERR(&drvdata->bus_client)) {
+ pr_err("%s(): Bus client register failed.\n", __func__);
+ ret = -EINVAL;
+ }
+ }
+ return ret;
}
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+ msm_bus_scale_unregister_client(drvdata->bus_client);
+ drvdata->bus_client = 0;
+}
+
+static int msm_iommu_parse_dt(struct platform_device *pdev,
+ struct msm_iommu_drvdata *drvdata)
+{
+ struct device_node *child;
+ struct resource *r;
+ u32 glb_offset = 0;
+ int ret = 0;
+ int needs_alt_core_clk;
+
+ ret = __get_bus_vote_client(pdev, drvdata);
+
+ if (ret)
+ goto fail;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ pr_err("%s: Missing property reg\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+ drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+ if (!drvdata->base) {
+ pr_err("%s: Unable to ioremap %pr\n", __func__, r);
+ ret = -ENOMEM;
+ goto fail;
+ }
+ drvdata->glb_base = drvdata->base;
+
+ if (!of_property_read_u32(pdev->dev.of_node, "qcom,glb-offset",
+ &glb_offset)) {
+ drvdata->glb_base += glb_offset;
+ } else {
+ pr_err("%s: Missing property qcom,glb-offset\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ for_each_child_of_node(pdev->dev.of_node, child)
+ drvdata->ncb++;
+
+ ret = of_property_read_string(pdev->dev.of_node, "label",
+ &drvdata->name);
+ if (ret) {
+ pr_err("%s: Missing property label\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
+ "qcom,needs-alt-core-clk");
+
+ ret = __get_clocks(pdev, drvdata, needs_alt_core_clk);
+
+ if (ret)
+ goto fail;
+
+ drvdata->sec_id = -1;
+ drvdata->ttbr_split = 0;
+
+ ret = of_platform_populate(pdev->dev.of_node,
+ msm_iommu_v0_ctx_match_table,
+ NULL, &pdev->dev);
+ if (ret) {
+ pr_err("Failed to create iommu context device\n");
+ goto fail;
+ }
+
+ return ret;
+
+fail:
+ __put_bus_vote_client(drvdata);
+ return ret;
+}
+
+#else
+static int msm_iommu_parse_dt(struct platform_device *pdev,
+ struct msm_iommu_drvdata *drvdata)
+{
+ return 0;
+}
+
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+
+}
+
+#endif
+
/*
* Do a basic check of the IOMMU by performing an ATS operation
* on context bank 0.
@@ -322,23 +392,27 @@
struct msm_iommu_drvdata *drvdata;
struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
int ret;
- int needs_alt_core_clk = 0;
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata) {
ret = -ENOMEM;
- goto fail;
+ goto fail_mem;
}
if (pdev->dev.of_node) {
- ret = msm_iommu_parse_dt(pdev, drvdata, &needs_alt_core_clk);
+ ret = msm_iommu_parse_dt(pdev, drvdata);
if (ret)
goto fail;
} else if (pdev->dev.platform_data) {
struct resource *r, *r2;
resource_size_t len;
+ ret = __get_clocks(pdev, drvdata, 0);
+
+ if (ret)
+ goto fail;
+
r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"physbase");
@@ -349,7 +423,8 @@
len = resource_size(r);
- r2 = request_mem_region(r->start, len, r->name);
+ r2 = devm_request_mem_region(&pdev->dev, r->start,
+ len, r->name);
if (!r2) {
pr_err("Could not request memory region: %pr\n", r);
ret = -EBUSY;
@@ -379,11 +454,6 @@
drvdata->dev = &pdev->dev;
- ret = __get_clocks(pdev, drvdata, needs_alt_core_clk);
-
- if (ret)
- goto fail;
-
iommu_access_ops_v0.iommu_clk_on(drvdata);
msm_iommu_reset(drvdata->base, drvdata->glb_base, drvdata->ncb);
@@ -392,14 +462,14 @@
if (ret)
goto fail_clk;
+ iommu_access_ops_v0.iommu_clk_off(drvdata);
+
pr_info("device %s mapped at %p, with %d ctx banks\n",
drvdata->name, drvdata->base, drvdata->ncb);
msm_iommu_add_drv(drvdata);
platform_set_drvdata(pdev, drvdata);
- iommu_access_ops_v0.iommu_clk_off(drvdata);
-
pmon_info = msm_iommu_pm_alloc(&pdev->dev);
if (pmon_info != NULL) {
ret = msm_iommu_pmon_parse_dt(pdev, pmon_info);
@@ -428,8 +498,9 @@
fail_clk:
iommu_access_ops_v0.iommu_clk_off(drvdata);
- __put_clocks(drvdata);
fail:
+ __put_bus_vote_client(drvdata);
+fail_mem:
return ret;
}
@@ -437,12 +508,13 @@
{
struct msm_iommu_drvdata *drv = NULL;
+ msm_iommu_pm_iommu_unregister(&pdev->dev);
+ msm_iommu_pm_free(&pdev->dev);
+
drv = platform_get_drvdata(pdev);
if (drv) {
+ __put_bus_vote_client(drv);
msm_iommu_remove_drv(drv);
- if (drv->clk)
- clk_put(drv->clk);
- clk_put(drv->pclk);
platform_set_drvdata(pdev, NULL);
}
return 0;
@@ -458,26 +530,28 @@
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
- ret = request_threaded_irq(irq, NULL,
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
msm_iommu_fault_handler,
IRQF_ONESHOT | IRQF_SHARED,
"msm_iommu_nonsecure_irq", ctx_drvdata);
if (ret) {
pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
- return ret;
+ goto out;
}
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
pr_err("Could not find reg property for context bank\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
if (ret) {
pr_err("of_address_to_resource failed\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
/* Calculate the context bank number using the base addresses. CB0
@@ -488,29 +562,34 @@
if (of_property_read_string(pdev->dev.of_node, "label",
&ctx_drvdata->name)) {
pr_err("Could not find label property\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-mids",
&nmid_array_size)) {
pr_err("Could not find iommu-ctx-mids property\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (nmid_array_size >= sizeof(ctx_drvdata->sids)) {
pr_err("Too many mids defined - array size: %u, mids size: %u\n",
nmid_array_size, sizeof(ctx_drvdata->sids));
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
nmid = nmid_array_size / sizeof(*ctx_drvdata->sids);
if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-mids",
ctx_drvdata->sids, nmid)) {
pr_err("Could not find iommu-ctx-mids property\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ctx_drvdata->nsid = nmid;
- return 0;
+out:
+ return ret;
}
static void __program_m2v_tables(struct msm_iommu_drvdata *drvdata,
@@ -560,7 +639,7 @@
drvdata = dev_get_drvdata(pdev->dev.parent);
if (!drvdata) {
- ret = -ENODEV;
+ ret = -EPROBE_DEFER;
goto fail;
}
@@ -578,8 +657,10 @@
if (pdev->dev.of_node) {
ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
- if (ret)
+ if (ret) {
+ platform_set_drvdata(pdev, NULL);
goto fail;
+ }
} else if (pdev->dev.platform_data) {
struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
@@ -601,7 +682,8 @@
goto fail;
}
- ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ msm_iommu_fault_handler,
IRQF_ONESHOT | IRQF_SHARED,
"msm_iommu_nonsecure_irq", ctx_drvdata);
@@ -647,15 +729,15 @@
.remove = __devexit_p(msm_iommu_remove),
};
-static struct of_device_id msm_iommu_ctx_match_table[] = {
- { .name = "qcom,iommu-ctx", },
+static struct of_device_id msm_iommu_v0_ctx_match_table[] = {
+ { .compatible = "qcom,msm-smmu-v0-ctx", },
{}
};
static struct platform_driver msm_iommu_ctx_driver = {
.driver = {
.name = "msm_iommu_ctx",
- .of_match_table = msm_iommu_ctx_match_table,
+ .of_match_table = msm_iommu_v0_ctx_match_table,
},
.probe = msm_iommu_ctx_probe,
.remove = __devexit_p(msm_iommu_ctx_remove),
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index 418a086..c0e05f4 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -28,6 +28,9 @@
#include <mach/iommu_hw-v1.h>
#include <mach/iommu.h>
#include <mach/iommu_perfmon.h>
+#include <mach/msm_bus.h>
+
+static struct of_device_id msm_iommu_v1_ctx_match_table[];
static int msm_iommu_parse_bfb_settings(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata)
@@ -84,6 +87,36 @@
return 0;
}
+static int __get_bus_vote_client(struct platform_device *pdev,
+ struct msm_iommu_drvdata *drvdata)
+{
+ int ret = 0;
+ struct msm_bus_scale_pdata *bs_table;
+ const char *dummy;
+
+ /* Check whether bus scaling has been specified for this node */
+ ret = of_property_read_string(pdev->dev.of_node, "qcom,msm-bus,name",
+ &dummy);
+ if (ret)
+ return 0;
+
+ bs_table = msm_bus_cl_get_pdata(pdev);
+
+ if (bs_table) {
+ drvdata->bus_client = msm_bus_scale_register_client(bs_table);
+ if (IS_ERR(&drvdata->bus_client)) {
+ pr_err("%s(): Bus client register failed.\n", __func__);
+ ret = -EINVAL;
+ }
+ }
+ return ret;
+}
+
+static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
+{
+ msm_bus_scale_unregister_client(drvdata->bus_client);
+}
+
static int msm_iommu_parse_dt(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata)
{
@@ -92,17 +125,18 @@
struct resource *r;
drvdata->dev = &pdev->dev;
- msm_iommu_add_drv(drvdata);
+
+ ret = __get_bus_vote_client(pdev, drvdata);
+
+ if (ret)
+ goto fail;
ret = msm_iommu_parse_bfb_settings(pdev, drvdata);
if (ret)
goto fail;
- for_each_child_of_node(pdev->dev.of_node, child) {
+ for_each_child_of_node(pdev->dev.of_node, child)
drvdata->ncb++;
- if (!of_platform_device_create(child, NULL, &pdev->dev))
- pr_err("Failed to create %s device\n", child->name);
- }
drvdata->asid = devm_kzalloc(&pdev->dev, drvdata->ncb * sizeof(int),
GFP_KERNEL);
@@ -137,8 +171,15 @@
drvdata->halt_enabled = of_property_read_bool(pdev->dev.of_node,
"qcom,iommu-enable-halt");
- return 0;
+ ret = of_platform_populate(pdev->dev.of_node,
+ msm_iommu_v1_ctx_match_table,
+ NULL, &pdev->dev);
+ if (ret)
+ pr_err("Failed to create iommu context device\n");
+
+ msm_iommu_add_drv(drvdata);
fail:
+ __put_bus_vote_client(drvdata);
return ret;
}
@@ -224,7 +265,7 @@
drvdata->gdsc = devm_regulator_get(&pdev->dev, "vdd");
if (IS_ERR(drvdata->gdsc))
- return -EINVAL;
+ return PTR_ERR(drvdata->gdsc);
drvdata->alt_gdsc = devm_regulator_get(&pdev->dev, "qcom,alt-vdd");
if (IS_ERR(drvdata->alt_gdsc))
@@ -301,10 +342,8 @@
drv = platform_get_drvdata(pdev);
if (drv) {
+ __put_bus_vote_client(drv);
msm_iommu_remove_drv(drv);
- if (drv->clk)
- clk_put(drv->clk);
- clk_put(drv->pclk);
platform_set_drvdata(pdev, NULL);
}
return 0;
@@ -314,7 +353,7 @@
struct msm_iommu_ctx_drvdata *ctx_drvdata)
{
struct resource *r, rp;
- int irq, ret;
+ int irq = 0, ret = 0;
u32 nsid;
ctx_drvdata->secure_context = of_property_read_bool(pdev->dev.of_node,
@@ -323,25 +362,27 @@
if (!ctx_drvdata->secure_context) {
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
- ret = request_threaded_irq(irq, NULL,
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
msm_iommu_fault_handler_v2,
IRQF_ONESHOT | IRQF_SHARED,
"msm_iommu_nonsecure_irq", pdev);
if (ret) {
pr_err("Request IRQ %d failed with ret=%d\n",
irq, ret);
- return ret;
+ goto out;
}
}
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r)
- return -EINVAL;
+ if (!r) {
+ ret = -EINVAL;
+ goto out;
+ }
ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
if (ret)
- return -EINVAL;
+ goto out;
/* Calculate the context bank number using the base addresses. The
* first 8 pages belong to the global address space which is followed
@@ -354,21 +395,26 @@
&ctx_drvdata->name))
ctx_drvdata->name = dev_name(&pdev->dev);
- if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid))
- return -EINVAL;
-
- if (nsid >= sizeof(ctx_drvdata->sids))
- return -EINVAL;
+ if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (nsid >= sizeof(ctx_drvdata->sids)) {
+ ret = -EINVAL;
+ goto out;
+ }
if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-sids",
ctx_drvdata->sids,
nsid / sizeof(*ctx_drvdata->sids))) {
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ctx_drvdata->nsid = nsid;
ctx_drvdata->asid = -1;
- return 0;
+out:
+ return ret;
}
static int __devinit msm_iommu_ctx_probe(struct platform_device *pdev)
@@ -386,12 +432,14 @@
ctx_drvdata->pdev = pdev;
INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
- platform_set_drvdata(pdev, ctx_drvdata);
ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
- if (!ret)
+ if (!ret) {
+ platform_set_drvdata(pdev, ctx_drvdata);
+
dev_info(&pdev->dev, "context %s using bank %d\n",
ctx_drvdata->name, ctx_drvdata->num);
+ }
return ret;
}
@@ -416,15 +464,15 @@
.remove = __devexit_p(msm_iommu_remove),
};
-static struct of_device_id msm_iommu_ctx_match_table[] = {
- { .name = "qcom,iommu-ctx", },
+static struct of_device_id msm_iommu_v1_ctx_match_table[] = {
+ { .compatible = "qcom,msm-smmu-v1-ctx", },
{}
};
static struct platform_driver msm_iommu_ctx_driver = {
.driver = {
.name = "msm_iommu_ctx_v1",
- .of_match_table = msm_iommu_ctx_match_table,
+ .of_match_table = msm_iommu_v1_ctx_match_table,
},
.probe = msm_iommu_ctx_probe,
.remove = __devexit_p(msm_iommu_ctx_remove),
diff --git a/drivers/iommu/msm_iommu_perfmon.c b/drivers/iommu/msm_iommu_perfmon.c
index a11d794..958c6ca 100644
--- a/drivers/iommu/msm_iommu_perfmon.c
+++ b/drivers/iommu/msm_iommu_perfmon.c
@@ -257,6 +257,7 @@
dev_get_drvdata(iommu->iommu_dev);
iommu->ops->iommu_power_on(iommu_drvdata);
+ iommu->ops->iommu_bus_vote(iommu_drvdata, 1);
iommu->ops->iommu_clk_on(iommu_drvdata);
/* Reset counters in HW */
@@ -311,6 +312,7 @@
iommu->ops->iommu_lock_release();
iommu->ops->iommu_clk_off(iommu_drvdata);
+ iommu->ops->iommu_bus_vote(iommu_drvdata, 0);
iommu->ops->iommu_power_off(iommu_drvdata);
pr_info("%s: TLB performance monitoring turned OFF\n",
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index fcade49..2c2b339 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -75,7 +75,8 @@
DMX_FIFO_ERROR, /* Receiver FIFO overrun */
DMX_MISSED_ERROR, /* Receiver missed packet */
DMX_OK_DECODER_BUF, /* Received OK, new ES data in decoder buffer */
- DMX_OK_IDX /* Received OK, new index event */
+ DMX_OK_IDX, /* Received OK, new index event */
+ DMX_OK_SCRAMBLING_STATUS, /* Received OK, new scrambling status */
} ;
@@ -135,6 +136,7 @@
} marker;
struct dmx_index_event_info idx_event;
+ struct dmx_scrambling_status_event_info scrambling_bits;
};
};
@@ -250,6 +252,7 @@
int (*ts_insertion_terminate)(struct dmx_ts_feed *feed);
int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed,
char *data, size_t size);
+ int (*get_scrambling_bits)(struct dmx_ts_feed *feed, u8 *value);
};
/*--------------------------------------------------------------------------*/
@@ -300,6 +303,7 @@
struct dmx_secure_mode *sec_mode);
int (*oob_command) (struct dmx_section_feed *feed,
struct dmx_oob_command *cmd);
+ int (*get_scrambling_bits)(struct dmx_section_feed *feed, u8 *value);
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 2a750a6..6734da8 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1796,6 +1796,35 @@
return 0;
}
+static int dvb_dmxdev_get_scrambling_bits(struct dmxdev_filter *filter,
+ struct dmx_scrambling_bits *scrambling_bits)
+{
+ struct dmxdev_feed *feed;
+
+ if (!scrambling_bits ||
+ (filter->state != DMXDEV_STATE_GO))
+ return -EINVAL;
+
+ if (filter->type == DMXDEV_TYPE_SEC) {
+ if (filter->feed.sec.feed->get_scrambling_bits)
+ return filter->feed.sec.feed->get_scrambling_bits(
+ filter->feed.sec.feed,
+ &scrambling_bits->value);
+ return -EINVAL;
+ }
+
+ list_for_each_entry(feed, &filter->feed.ts, next) {
+ if (feed->pid == scrambling_bits->pid) {
+ if (feed->ts->get_scrambling_bits)
+ return feed->ts->get_scrambling_bits(feed->ts,
+ &scrambling_bits->value);
+ return -EINVAL;
+ }
+ }
+
+ return -EINVAL;
+}
+
static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker)
{
struct ts_insertion_buffer *ts_buffer =
@@ -2519,6 +2548,13 @@
dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
spin_unlock(&dmxdevfilter->dev->lock);
wake_up_all(&dmxdevfilter->buffer.queue);
+ } else if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) {
+ event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE;
+ event.params.scrambling_status =
+ dmx_data_ready->scrambling_bits;
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&dmxdevfilter->buffer.queue);
} else {
spin_unlock(&dmxdevfilter->dev->lock);
}
@@ -2635,6 +2671,16 @@
return 0;
}
+ if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) {
+ event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE;
+ event.params.scrambling_status =
+ dmx_data_ready->scrambling_bits;
+ dvb_dmxdev_add_event(events, &event);
+ spin_unlock(&dmxdevfilter->dev->lock);
+ wake_up_all(&buffer->queue);
+ return 0;
+ }
+
if (dmx_data_ready->status == DMX_OK_DECODER_BUF) {
event.type = DMX_EVENT_NEW_ES_DATA;
event.params.es_data.buf_handle = dmx_data_ready->buf.handle;
@@ -3938,6 +3984,15 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_GET_SCRAMBLING_BITS:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_get_scrambling_bits(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
@@ -4193,6 +4248,7 @@
struct dmxdev_filter *filter;
int active_count = 0;
struct dmx_buffer_status buffer_status;
+ struct dmx_scrambling_bits scrambling_bits;
const char *pes_feeds[] = {"DEC", "PES", "DVR", "REC"};
if (!dmxdev)
@@ -4209,23 +4265,32 @@
seq_printf(s, "type: SEC, ");
seq_printf(s, "PID %04d ",
filter->params.sec.pid);
+ scrambling_bits.pid = filter->params.sec.pid;
} else {
seq_printf(s, "type: %s, ",
pes_feeds[filter->params.pes.output]);
seq_printf(s, "PID: %04d ",
filter->params.pes.pid);
+ scrambling_bits.pid = filter->params.pes.pid;
}
+ dvb_dmxdev_get_scrambling_bits(filter,
+ &scrambling_bits);
+
if (0 == dvb_dmxdev_get_buffer_status(
filter, &buffer_status)) {
seq_printf(s, "size: %08d, ",
buffer_status.size);
seq_printf(s, "fullness: %08d, ",
buffer_status.fullness);
- seq_printf(s, "error: %d\n",
+ seq_printf(s, "error: %d, ",
buffer_status.error);
+ seq_printf(s, "scramble: %d\n",
+ scrambling_bits.value);
+
} else {
- seq_printf(s, "\n");
+ seq_printf(s, "scramble: %d\n",
+ scrambling_bits.value);
}
}
}
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 939d591..b8c3c44 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -164,6 +164,11 @@
return ((buf[1] & 0x1f) << 8) + buf[2];
}
+static inline u16 ts_scrambling_ctrl(const u8 *buf)
+{
+ return (buf[3] >> 6) & 0x3;
+}
+
static inline u8 payload(const u8 *tsp)
{
if (!(tsp[3] & 0x10)) // no payload?
@@ -437,6 +442,27 @@
}
EXPORT_SYMBOL(dvb_dmx_video_pattern_search);
+static int dvb_dmx_check_pes_end(struct dvb_demux_feed *feed)
+{
+ struct dmx_data_ready data;
+
+ if (!feed->pusi_seen)
+ return 0;
+
+ data.status = DMX_OK_PES_END;
+ data.data_length = 0;
+ data.pes_end.start_gap = 0;
+ data.pes_end.actual_length = feed->peslen;
+ data.pes_end.disc_indicator_set = 0;
+ data.pes_end.pes_length_mismatch = 0;
+ data.pes_end.stc = 0;
+ data.pes_end.tei_counter = feed->pes_tei_counter;
+ data.pes_end.cont_err_counter = feed->pes_cont_err_counter;
+ data.pes_end.ts_packets_num = feed->pes_ts_packets_num;
+
+ return feed->data_ready_cb.ts(&feed->feed.ts, &data);
+}
+
static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
const u8 *buf)
{
@@ -444,7 +470,6 @@
int p;
int ccok;
u8 cc;
- struct dmx_data_ready data;
if (count == 0)
return -1;
@@ -462,24 +487,7 @@
/* PUSI ? */
if (buf[1] & 0x40) {
- if (feed->pusi_seen) {
- /* We had seen PUSI before, this means
- * that previous PES can be closed now.
- */
- data.status = DMX_OK_PES_END;
- data.data_length = 0;
- data.pes_end.start_gap = 0;
- data.pes_end.actual_length = feed->peslen;
- data.pes_end.disc_indicator_set = 0;
- data.pes_end.pes_length_mismatch = 0;
- data.pes_end.stc = 0;
- data.pes_end.tei_counter = feed->pes_tei_counter;
- data.pes_end.cont_err_counter =
- feed->pes_cont_err_counter;
- data.pes_end.ts_packets_num = feed->pes_ts_packets_num;
- feed->data_ready_cb.ts(&feed->feed.ts, &data);
- }
-
+ dvb_dmx_check_pes_end(feed);
feed->pusi_seen = 1;
feed->peslen = 0;
feed->pes_tei_counter = 0;
@@ -1284,6 +1292,32 @@
static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
const u8 *buf, const u8 timestamp[TIMESTAMP_LEN])
{
+ u16 pid = ts_pid(buf);
+ u8 scrambling_bits = ts_scrambling_ctrl(buf);
+ struct dmx_data_ready dmx_data_ready;
+
+ /*
+ * Notify on scrambling status change only when we move
+ * from clear (0) to non-clear and vise-versa
+ */
+ if ((scrambling_bits && !feed->scrambling_bits) ||
+ (!scrambling_bits && feed->scrambling_bits)) {
+ dmx_data_ready.status = DMX_OK_SCRAMBLING_STATUS;
+ dmx_data_ready.data_length = 0;
+ dmx_data_ready.scrambling_bits.pid = pid;
+ dmx_data_ready.scrambling_bits.old_value =
+ feed->scrambling_bits;
+ dmx_data_ready.scrambling_bits.new_value = scrambling_bits;
+
+ if (feed->type == DMX_TYPE_SEC)
+ feed->data_ready_cb.sec(&feed->filter->filter,
+ &dmx_data_ready);
+ else
+ feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready);
+ }
+
+ feed->scrambling_bits = scrambling_bits;
+
switch (feed->type) {
case DMX_TYPE_TS:
if (!feed->feed.ts.is_filtering)
@@ -1543,9 +1577,11 @@
if (pktsize == 192) {
if (leadingbytes)
- memcpy(timestamp, &buf[p], TIMESTAMP_LEN);
+ memcpy(timestamp, &demux->tsbuf[p],
+ TIMESTAMP_LEN);
else
- memcpy(timestamp, &buf[188], TIMESTAMP_LEN);
+ memcpy(timestamp, &demux->tsbuf[188],
+ TIMESTAMP_LEN);
} else {
memset(timestamp, 0, TIMESTAMP_LEN);
}
@@ -2044,6 +2080,7 @@
}
feed->first_cc = 1;
+ feed->scrambling_bits = 0;
if ((feed->ts_type & TS_PACKET) &&
!(feed->ts_type & TS_PAYLOAD_ONLY)) {
@@ -2250,7 +2287,9 @@
struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
struct dmx_data_ready data;
struct dvb_demux *dvbdmx = feed->demux;
- int ret;
+ int ret = 0;
+ int secure_non_rec = feed->secure_mode.is_secured &&
+ !dvb_dmx_is_rec_feed(feed);
mutex_lock(&dvbdmx->mutex);
@@ -2259,13 +2298,14 @@
return -EINVAL;
}
- /* Decoder feeds are handled by plug-in */
- if (feed->ts_type & TS_DECODER) {
+ /* Decoder & non-recording secure feeds are handled by plug-in */
+ if ((feed->ts_type & TS_DECODER) || secure_non_rec) {
if (feed->demux->oob_command)
ret = feed->demux->oob_command(feed, cmd);
- else
- ret = 0;
+ }
+ if (!(feed->ts_type & (TS_PAYLOAD_ONLY | TS_PACKET)) ||
+ secure_non_rec) {
mutex_unlock(&dvbdmx->mutex);
return ret;
}
@@ -2274,44 +2314,9 @@
switch (cmd->type) {
case DMX_OOB_CMD_EOS:
- if (feed->ts_type & TS_PAYLOAD_ONLY) {
- if (feed->secure_mode.is_secured) {
- /* Secure feeds are handled by plug-in */
- if (feed->demux->oob_command)
- ret = feed->demux->oob_command(feed,
- cmd);
- else
- ret = 0;
- break;
- }
+ if (feed->ts_type & TS_PAYLOAD_ONLY)
+ dvb_dmx_check_pes_end(feed);
- /* Close last PES on non-secure feeds */
- if (feed->pusi_seen) {
- data.status = DMX_OK_PES_END;
- data.pes_end.start_gap = 0;
- data.pes_end.actual_length =
- feed->peslen;
- data.pes_end.disc_indicator_set = 0;
- data.pes_end.pes_length_mismatch = 0;
- data.pes_end.stc = 0;
- data.pes_end.tei_counter =
- feed->pes_tei_counter;
- data.pes_end.cont_err_counter =
- feed->pes_cont_err_counter;
- data.pes_end.ts_packets_num =
- feed->pes_ts_packets_num;
-
- feed->peslen = 0;
- feed->pes_tei_counter = 0;
- feed->pes_ts_packets_num = 0;
- feed->pes_cont_err_counter = 0;
-
- ret = feed->data_ready_cb.ts(&feed->feed.ts,
- &data);
- if (ret)
- break;
- }
- }
data.status = DMX_OK_EOS;
ret = feed->data_ready_cb.ts(&feed->feed.ts, &data);
break;
@@ -2331,6 +2336,25 @@
return ret;
}
+static int dvbdmx_ts_get_scrambling_bits(struct dmx_ts_feed *ts_feed,
+ u8 *value)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+ struct dvb_demux *demux = feed->demux;
+
+ spin_lock(&demux->lock);
+
+ if (!ts_feed->is_filtering) {
+ spin_unlock(&demux->lock);
+ return -EINVAL;
+ }
+
+ *value = feed->scrambling_bits;
+ spin_unlock(&demux->lock);
+
+ return 0;
+}
+
static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed,
char *data, size_t size)
{
@@ -2420,6 +2444,7 @@
(*ts_feed)->notify_data_read = NULL;
(*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode;
(*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd;
+ (*ts_feed)->get_scrambling_bits = dvbdmx_ts_get_scrambling_bits;
(*ts_feed)->ts_insertion_init = NULL;
(*ts_feed)->ts_insertion_terminate = NULL;
(*ts_feed)->ts_insertion_insert_buffer =
@@ -2586,6 +2611,7 @@
dvbdmxfeed->feed.sec.secbufp = 0;
dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->first_cc = 1;
+ dvbdmxfeed->scrambling_bits = 0;
if (!dvbdmx->start_feed) {
mutex_unlock(&dvbdmx->mutex);
@@ -2752,6 +2778,25 @@
return ret;
}
+static int dvbdmx_section_get_scrambling_bits(
+ struct dmx_section_feed *section_feed, u8 *value)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed;
+ struct dvb_demux *demux = feed->demux;
+
+ spin_lock(&demux->lock);
+
+ if (!section_feed->is_filtering) {
+ spin_unlock(&demux->lock);
+ return -EINVAL;
+ }
+
+ *value = feed->scrambling_bits;
+ spin_unlock(&demux->lock);
+
+ return 0;
+}
+
static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
struct dmx_section_feed **feed,
dmx_section_cb callback)
@@ -2792,6 +2837,7 @@
(*feed)->notify_data_read = NULL;
(*feed)->set_secure_mode = dmx_section_set_secure_mode;
(*feed)->oob_command = dvbdmx_section_feed_oob_cmd;
+ (*feed)->get_scrambling_bits = dvbdmx_section_get_scrambling_bits;
mutex_unlock(&dvbdmx->mutex);
return 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 879aad2..9fb1a12 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -187,6 +187,8 @@
int first_cc;
int pusi_seen; /* prevents feeding of garbage from previous section */
+ u8 scrambling_bits;
+
struct dvb_demux_rec_info *rec_info;
u64 prev_tsp_num;
u64 prev_stc;
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index d9552e2..52864ae 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -153,3 +153,8 @@
This module serves as the common driver
for the JPEG 1.0 encoder and decoder.
+config MSM_GEMINI
+ tristate "Qualcomm MSM Gemini JPEG engine support"
+ depends on MSMB_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960)
+ ---help---
+ Enables support for the Gemini JPEG encoder engine for 8x60.
diff --git a/drivers/media/platform/msm/camera_v2/Makefile b/drivers/media/platform/msm/camera_v2/Makefile
index a1c5ea5..02eb3dd 100644
--- a/drivers/media/platform/msm/camera_v2/Makefile
+++ b/drivers/media/platform/msm/camera_v2/Makefile
@@ -16,3 +16,4 @@
obj-$(CONFIG_MSMB_JPEG) += jpeg_10/
obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr/
obj-$(CONFIG_MSMB_CAMERA) += pproc/
+obj-$(CONFIG_MSMB_CAMERA) += gemini/
diff --git a/drivers/media/platform/msm/camera_v2/gemini/Makefile b/drivers/media/platform/msm/camera_v2/gemini/Makefile
new file mode 100644
index 0000000..74d7294
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/Makefile
@@ -0,0 +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/platform/msm/camera_v2/sensor/io
+
+obj-$(CONFIG_MSM_GEMINI) += msm_gemini_dev.o msm_gemini_sync.o msm_gemini_core.o msm_gemini_hw.o msm_gemini_platform.o
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_common.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_common.h
new file mode 100644
index 0000000..eefad6d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_common.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_GEMINI_COMMON_H
+#define MSM_GEMINI_COMMON_H
+
+#define MSM_GEMINI_DEBUG
+#ifdef MSM_GEMINI_DEBUG
+#define GMN_DBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define GMN_DBG(fmt, args...) do { } while (0)
+#endif
+
+#define GMN_PR_ERR pr_err
+
+enum GEMINI_MODE {
+ GEMINI_MODE_DISABLE,
+ GEMINI_MODE_OFFLINE,
+ GEMINI_MODE_REALTIME,
+ GEMINI_MODE_REALTIME_ROTATION
+};
+
+enum GEMINI_ROTATION {
+ GEMINI_ROTATION_0,
+ GEMINI_ROTATION_90,
+ GEMINI_ROTATION_180,
+ GEMINI_ROTATION_270
+};
+
+#endif /* MSM_GEMINI_COMMON_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.c
new file mode 100644
index 0000000..88fa9e7
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.c
@@ -0,0 +1,250 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include "msm_gemini_hw.h"
+#include "msm_gemini_core.h"
+#include "msm_gemini_platform.h"
+#include "msm_gemini_common.h"
+
+static struct msm_gemini_hw_pingpong fe_pingpong_buf;
+static struct msm_gemini_hw_pingpong we_pingpong_buf;
+static int we_pingpong_index;
+static int reset_done_ack;
+static spinlock_t reset_lock;
+static wait_queue_head_t reset_wait;
+
+int msm_gemini_core_reset(uint8_t op_mode, void *base, int size)
+{
+ unsigned long flags;
+ int rc = 0;
+ int tm = 500;
+ memset(&fe_pingpong_buf, 0, sizeof(fe_pingpong_buf));
+ fe_pingpong_buf.is_fe = 1;
+ we_pingpong_index = 0;
+ memset(&we_pingpong_buf, 0, sizeof(we_pingpong_buf));
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 0;
+ msm_gemini_hw_reset(base, size);
+ spin_unlock_irqrestore(&reset_lock, flags);
+ rc = wait_event_interruptible_timeout(
+ reset_wait,
+ reset_done_ack,
+ msecs_to_jiffies(tm));
+
+ if (!reset_done_ack) {
+ GMN_DBG("%s: reset ACK failed %d", __func__, rc);
+ return -EBUSY;
+ }
+
+ GMN_DBG("%s: reset_done_ack rc %d", __func__, rc);
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 0;
+ spin_unlock_irqrestore(&reset_lock, flags);
+
+ if (op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
+ /* Nothing needed for fe buffer cfg, config we only */
+ msm_gemini_hw_we_buffer_cfg(1);
+ } else {
+ /* Nothing needed for fe buffer cfg, config we only */
+ msm_gemini_hw_we_buffer_cfg(0);
+ }
+
+ /* @todo wait for reset done irq */
+
+ return 0;
+}
+
+void msm_gemini_core_release(int release_buf)
+{
+ int i = 0;
+ for (i = 0; i < 2; i++) {
+ if (we_pingpong_buf.buf_status[i] && release_buf)
+ msm_gemini_platform_p2v(we_pingpong_buf.buf[i].file,
+ &we_pingpong_buf.buf[i].handle);
+ we_pingpong_buf.buf_status[i] = 0;
+ }
+}
+
+void msm_gemini_core_init(void)
+{
+ init_waitqueue_head(&reset_wait);
+ spin_lock_init(&reset_lock);
+}
+
+int msm_gemini_core_fe_start(void)
+{
+ msm_gemini_hw_fe_start();
+ return 0;
+}
+
+/* fetch engine */
+int msm_gemini_core_fe_buf_update(struct msm_gemini_core_buf *buf)
+{
+ GMN_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__,
+ (int) buf->y_buffer_addr, buf->y_len,
+ (int) buf->cbcr_buffer_addr, buf->cbcr_len);
+ return msm_gemini_hw_pingpong_update(&fe_pingpong_buf, buf);
+}
+
+void *msm_gemini_core_fe_pingpong_irq(int gemini_irq_status, void *context)
+{
+ return msm_gemini_hw_pingpong_irq(&fe_pingpong_buf);
+}
+
+/* write engine */
+int msm_gemini_core_we_buf_update(struct msm_gemini_core_buf *buf)
+{
+ int rc;
+ GMN_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__,
+ (int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr,
+ buf->y_len);
+ we_pingpong_buf.buf_status[we_pingpong_index] = 0;
+ we_pingpong_index = (we_pingpong_index + 1)%2;
+ rc = msm_gemini_hw_pingpong_update(&we_pingpong_buf, buf);
+ return 0;
+}
+
+int msm_gemini_core_we_buf_reset(struct msm_gemini_hw_buf *buf)
+{
+ int i;
+ for (i = 0; i < 2; i++) {
+ if (we_pingpong_buf.buf[i].y_buffer_addr
+ == buf->y_buffer_addr)
+ we_pingpong_buf.buf_status[i] = 0;
+ }
+ return 0;
+}
+
+void *msm_gemini_core_we_pingpong_irq(int gemini_irq_status, void *context)
+{
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+ return msm_gemini_hw_pingpong_irq(&we_pingpong_buf);
+}
+
+void *msm_gemini_core_framedone_irq(int gemini_irq_status, void *context)
+{
+ struct msm_gemini_hw_buf *buf_p;
+
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+ buf_p = msm_gemini_hw_pingpong_active_buffer(&we_pingpong_buf);
+ if (buf_p) {
+ buf_p->framedone_len = msm_gemini_hw_encode_output_size();
+ GMN_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
+ buf_p->framedone_len);
+ }
+
+ return buf_p;
+}
+
+void *msm_gemini_core_reset_ack_irq(int gemini_irq_status, void *context)
+{
+ /* @todo return the status back to msm_gemini_core_reset */
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+ return NULL;
+}
+
+void *msm_gemini_core_err_irq(int gemini_irq_status, void *context)
+{
+ GMN_PR_ERR("%s:%d]\n", __func__, gemini_irq_status);
+ return NULL;
+}
+
+static int (*msm_gemini_irq_handler) (int, void *, void *);
+
+irqreturn_t msm_gemini_core_irq(int irq_num, void *context)
+{
+ void *data = NULL;
+ unsigned long flags;
+ int gemini_irq_status;
+
+ GMN_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
+
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 1;
+ spin_unlock_irqrestore(&reset_lock, flags);
+ gemini_irq_status = msm_gemini_hw_irq_get_status();
+
+ GMN_DBG("%s:%d] gemini_irq_status = %0x\n", __func__, __LINE__,
+ gemini_irq_status);
+
+ /* For reset and framedone IRQs, clear all bits */
+ if (gemini_irq_status & 0x400) {
+ wake_up(&reset_wait);
+ msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+ JPEG_IRQ_CLEAR_ALL);
+ } else if (gemini_irq_status & 0x1) {
+ msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+ JPEG_IRQ_CLEAR_ALL);
+ } else {
+ msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+ gemini_irq_status);
+ }
+
+ if (msm_gemini_hw_irq_is_frame_done(gemini_irq_status)) {
+ data = msm_gemini_core_framedone_irq(gemini_irq_status,
+ context);
+ if (msm_gemini_irq_handler)
+ msm_gemini_irq_handler(
+ MSM_GEMINI_HW_MASK_COMP_FRAMEDONE,
+ context, data);
+ }
+
+ if (msm_gemini_hw_irq_is_fe_pingpong(gemini_irq_status)) {
+ data = msm_gemini_core_fe_pingpong_irq(gemini_irq_status,
+ context);
+ if (msm_gemini_irq_handler)
+ msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_FE,
+ context, data);
+ }
+
+ if (msm_gemini_hw_irq_is_we_pingpong(gemini_irq_status) &&
+ !msm_gemini_hw_irq_is_frame_done(gemini_irq_status)) {
+ data = msm_gemini_core_we_pingpong_irq(gemini_irq_status,
+ context);
+ if (msm_gemini_irq_handler)
+ msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_WE,
+ context, data);
+ }
+
+ if (msm_gemini_hw_irq_is_reset_ack(gemini_irq_status)) {
+ data = msm_gemini_core_reset_ack_irq(gemini_irq_status,
+ context);
+ if (msm_gemini_irq_handler)
+ msm_gemini_irq_handler(
+ MSM_GEMINI_HW_MASK_COMP_RESET_ACK,
+ context, data);
+ }
+
+ /* Unexpected/unintended HW interrupt */
+ if (msm_gemini_hw_irq_is_err(gemini_irq_status)) {
+ data = msm_gemini_core_err_irq(gemini_irq_status, context);
+ if (msm_gemini_irq_handler)
+ msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_ERR,
+ context, data);
+ }
+
+ return IRQ_HANDLED;
+}
+
+void msm_gemini_core_irq_install(int (*irq_handler) (int, void *, void *))
+{
+ msm_gemini_irq_handler = irq_handler;
+}
+
+void msm_gemini_core_irq_remove(void)
+{
+ msm_gemini_irq_handler = NULL;
+}
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.h
new file mode 100644
index 0000000..3aac25a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_GEMINI_CORE_H
+#define MSM_GEMINI_CORE_H
+
+#include <linux/interrupt.h>
+#include "msm_gemini_hw.h"
+
+#define msm_gemini_core_buf msm_gemini_hw_buf
+
+irqreturn_t msm_gemini_core_irq(int irq_num, void *context);
+
+void msm_gemini_core_irq_install(int (*irq_handler) (int, void *, void *));
+void msm_gemini_core_irq_remove(void);
+
+int msm_gemini_core_fe_buf_update(struct msm_gemini_core_buf *buf);
+int msm_gemini_core_we_buf_update(struct msm_gemini_core_buf *buf);
+int msm_gemini_core_we_buf_reset(struct msm_gemini_hw_buf *buf);
+
+int msm_gemini_core_reset(uint8_t op_mode, void *base, int size);
+int msm_gemini_core_fe_start(void);
+
+void msm_gemini_core_release(int);
+void msm_gemini_core_init(void);
+#endif /* MSM_GEMINI_CORE_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_dev.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_dev.c
new file mode 100644
index 0000000..13c1e11
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_dev.c
@@ -0,0 +1,265 @@
+/* Copyright (c) 2010-2011,2013 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <media/msm_gemini.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/board.h>
+#include "../msm.h"
+#include "msm_gemini_sync.h"
+#include "msm_gemini_common.h"
+
+#define MSM_GEMINI_NAME "gemini"
+#define MSM_GEMINI_DRV_NAME "msm_gemini"
+
+static int msm_gemini_open(struct inode *inode, struct file *filp)
+{
+ int rc;
+
+ struct msm_gemini_device *pgmn_dev = container_of(inode->i_cdev,
+ struct msm_gemini_device, cdev);
+ filp->private_data = pgmn_dev;
+
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+ rc = __msm_gemini_open(pgmn_dev);
+
+ GMN_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+ filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+
+ return rc;
+}
+
+static int msm_gemini_release(struct inode *inode, struct file *filp)
+{
+ int rc;
+
+ struct msm_gemini_device *pgmn_dev = filp->private_data;
+
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+ rc = __msm_gemini_release(pgmn_dev);
+
+ GMN_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+ filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+ return rc;
+}
+
+static long msm_gemini_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc;
+ struct msm_gemini_device *pgmn_dev = filp->private_data;
+
+ GMN_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__,
+ __LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg);
+
+ rc = __msm_gemini_ioctl(pgmn_dev, cmd, arg);
+
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+ return rc;
+}
+
+static const struct file_operations msm_gemini_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_gemini_open,
+ .release = msm_gemini_release,
+ .unlocked_ioctl = msm_gemini_ioctl,
+};
+
+static struct class *msm_gemini_class;
+static dev_t msm_gemini_devno;
+static struct msm_gemini_device *msm_gemini_device_p;
+
+int msm_gemini_subdev_init(struct v4l2_subdev *gemini_sd)
+{
+ int rc;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *)gemini_sd->host_priv;
+
+ GMN_DBG("%s:%d: gemini_sd=0x%x pgmn_dev=0x%x\n",
+ __func__, __LINE__, (uint32_t)gemini_sd, (uint32_t)pgmn_dev);
+ rc = __msm_gemini_open(pgmn_dev);
+ GMN_DBG("%s:%d: rc=%d\n",
+ __func__, __LINE__, rc);
+ return rc;
+}
+
+static long msm_gemini_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ long rc;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *)sd->host_priv;
+
+ GMN_DBG("%s: cmd=%d\n", __func__, cmd);
+
+ GMN_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev);
+
+ GMN_DBG("%s: Calling __msm_gemini_ioctl\n", __func__);
+
+ rc = __msm_gemini_ioctl(pgmn_dev, cmd, (unsigned long)arg);
+ GMN_DBG("%s: X\n", __func__);
+ return rc;
+}
+
+void msm_gemini_subdev_release(struct v4l2_subdev *gemini_sd)
+{
+ int rc;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *)gemini_sd->host_priv;
+ GMN_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev);
+ rc = __msm_gemini_release(pgmn_dev);
+ GMN_DBG("%s:rc=%d", __func__, rc);
+}
+
+static const struct v4l2_subdev_core_ops msm_gemini_subdev_core_ops = {
+ .ioctl = msm_gemini_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_gemini_subdev_ops = {
+ .core = &msm_gemini_subdev_core_ops,
+};
+
+static int msm_gemini_init(struct platform_device *pdev)
+{
+ int rc = -1;
+ struct device *dev;
+
+ GMN_DBG("%s:\n", __func__);
+ msm_gemini_device_p = __msm_gemini_init(pdev);
+ if (msm_gemini_device_p == NULL) {
+ GMN_PR_ERR("%s: initialization failed\n", __func__);
+ goto fail;
+ }
+
+ v4l2_subdev_init(&msm_gemini_device_p->subdev, &msm_gemini_subdev_ops);
+ v4l2_set_subdev_hostdata(&msm_gemini_device_p->subdev,
+ msm_gemini_device_p);
+ GMN_DBG("%s: msm_gemini_device_p 0x%x", __func__,
+ (uint32_t)msm_gemini_device_p);
+ GMN_DBG("%s:gemini: platform_set_drvdata\n", __func__);
+ platform_set_drvdata(pdev, &msm_gemini_device_p->subdev);
+
+ rc = alloc_chrdev_region(&msm_gemini_devno, 0, 1, MSM_GEMINI_NAME);
+ if (rc < 0) {
+ GMN_PR_ERR("%s: failed to allocate chrdev\n", __func__);
+ goto fail_1;
+ }
+
+ if (!msm_gemini_class) {
+ msm_gemini_class = class_create(THIS_MODULE, MSM_GEMINI_NAME);
+ if (IS_ERR(msm_gemini_class)) {
+ rc = PTR_ERR(msm_gemini_class);
+ GMN_PR_ERR("%s: create device class failed\n",
+ __func__);
+ goto fail_2;
+ }
+ }
+
+ dev = device_create(msm_gemini_class, NULL,
+ MKDEV(MAJOR(msm_gemini_devno), MINOR(msm_gemini_devno)), NULL,
+ "%s%d", MSM_GEMINI_NAME, 0);
+
+ if (IS_ERR(dev)) {
+ GMN_PR_ERR("%s: error creating device\n", __func__);
+ rc = -ENODEV;
+ goto fail_3;
+ }
+
+ cdev_init(&msm_gemini_device_p->cdev, &msm_gemini_fops);
+ msm_gemini_device_p->cdev.owner = THIS_MODULE;
+ msm_gemini_device_p->cdev.ops =
+ (const struct file_operations *) &msm_gemini_fops;
+ rc = cdev_add(&msm_gemini_device_p->cdev, msm_gemini_devno, 1);
+ if (rc < 0) {
+ GMN_PR_ERR("%s: error adding cdev\n", __func__);
+ rc = -ENODEV;
+ goto fail_4;
+ }
+
+ GMN_DBG("%s %s: success\n", __func__, MSM_GEMINI_NAME);
+
+ return rc;
+
+fail_4:
+ device_destroy(msm_gemini_class, msm_gemini_devno);
+
+fail_3:
+ class_destroy(msm_gemini_class);
+
+fail_2:
+ unregister_chrdev_region(msm_gemini_devno, 1);
+
+fail_1:
+ __msm_gemini_exit(msm_gemini_device_p);
+
+fail:
+ return rc;
+}
+
+static void msm_gemini_exit(void)
+{
+ cdev_del(&msm_gemini_device_p->cdev);
+ device_destroy(msm_gemini_class, msm_gemini_devno);
+ class_destroy(msm_gemini_class);
+ unregister_chrdev_region(msm_gemini_devno, 1);
+
+ __msm_gemini_exit(msm_gemini_device_p);
+}
+
+static int __msm_gemini_probe(struct platform_device *pdev)
+{
+ return msm_gemini_init(pdev);
+}
+
+static int __msm_gemini_remove(struct platform_device *pdev)
+{
+ msm_gemini_exit();
+ return 0;
+}
+
+static struct platform_driver msm_gemini_driver = {
+ .probe = __msm_gemini_probe,
+ .remove = __msm_gemini_remove,
+ .driver = {
+ .name = MSM_GEMINI_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_gemini_driver_init(void)
+{
+ int rc;
+ rc = platform_driver_register(&msm_gemini_driver);
+ return rc;
+}
+
+static void __exit msm_gemini_driver_exit(void)
+{
+ platform_driver_unregister(&msm_gemini_driver);
+}
+
+MODULE_DESCRIPTION("MSM Gemini JPEG driver");
+MODULE_VERSION("msm gemini 0.1");
+
+module_init(msm_gemini_driver_init);
+module_exit(msm_gemini_driver_exit);
+
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
new file mode 100644
index 0000000..96470fd
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
@@ -0,0 +1,520 @@
+/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include "msm_gemini_hw.h"
+#include "msm_gemini_common.h"
+
+
+static void *gemini_region_base;
+static uint32_t gemini_region_size;
+
+int msm_gemini_hw_pingpong_update(struct msm_gemini_hw_pingpong *pingpong_hw,
+ struct msm_gemini_hw_buf *buf)
+{
+ int buf_free_index = -1;
+
+ if (!pingpong_hw->buf_status[0])
+ buf_free_index = 0;
+ else if (!pingpong_hw->buf_status[1])
+ buf_free_index = 1;
+ else {
+ GMN_PR_ERR("%s:%d: pingpong buffer busy\n", __func__, __LINE__);
+ return -EBUSY;
+ }
+
+ pingpong_hw->buf[buf_free_index] = *buf;
+ pingpong_hw->buf_status[buf_free_index] = 1;
+
+ if (pingpong_hw->is_fe)
+ msm_gemini_hw_fe_buffer_update(
+ &pingpong_hw->buf[buf_free_index], buf_free_index);
+ else
+ msm_gemini_hw_we_buffer_update(
+ &pingpong_hw->buf[buf_free_index], buf_free_index);
+ return 0;
+}
+
+void *msm_gemini_hw_pingpong_irq(struct msm_gemini_hw_pingpong *pingpong_hw)
+{
+ struct msm_gemini_hw_buf *buf_p = NULL;
+
+ if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) {
+ buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+ pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0;
+ }
+
+ pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index;
+
+ return (void *) buf_p;
+}
+
+void *msm_gemini_hw_pingpong_active_buffer(
+ struct msm_gemini_hw_pingpong *pingpong_hw)
+{
+ struct msm_gemini_hw_buf *buf_p = NULL;
+
+ if (pingpong_hw->buf_status[pingpong_hw->buf_active_index])
+ buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+
+ return (void *) buf_p;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_irq_get_status[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_READ, 1, HWIO_JPEG_IRQ_STATUS_ADDR,
+ HWIO_JPEG_IRQ_STATUS_RMSK, {0} },
+};
+
+int msm_gemini_hw_irq_get_status(void)
+{
+ uint32_t n_irq_status = 0;
+ n_irq_status = msm_gemini_hw_read(&hw_cmd_irq_get_status[0]);
+ return n_irq_status;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_encode_output_size[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_READ, 1,
+ HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_ADDR,
+ HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_RMSK, {0} },
+};
+
+long msm_gemini_hw_encode_output_size(void)
+{
+ long encode_output_size;
+
+ encode_output_size = msm_gemini_hw_read(&hw_cmd_encode_output_size[0]);
+
+ return encode_output_size;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_irq_clear[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_CLEAR_ADDR,
+ HWIO_JPEG_IRQ_CLEAR_RMSK, {JPEG_IRQ_CLEAR_ALL} },
+};
+
+void msm_gemini_hw_irq_clear(uint32_t mask, uint32_t data)
+{
+ GMN_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
+ hw_cmd_irq_clear[0].mask = mask;
+ hw_cmd_irq_clear[0].data = data;
+ msm_gemini_hw_write(&hw_cmd_irq_clear[0]);
+}
+
+struct msm_gemini_hw_cmd hw_cmd_fe_ping_update[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_BUFFER_CFG_ADDR,
+ HWIO_JPEG_FE_BUFFER_CFG_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_Y_PING_ADDR_ADDR,
+ HWIO_JPEG_FE_Y_PING_ADDR_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CBCR_PING_ADDR_ADDR,
+ HWIO_JPEG_FE_CBCR_PING_ADDR_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+ HWIO_JPEG_FE_CMD_RMSK, {JPEG_FE_CMD_BUFFERRELOAD} },
+};
+
+struct msm_gemini_hw_cmd hw_cmd_fe_pong_update[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_BUFFER_CFG_ADDR,
+ HWIO_JPEG_FE_BUFFER_CFG_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_Y_PONG_ADDR_ADDR,
+ HWIO_JPEG_FE_Y_PONG_ADDR_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CBCR_PONG_ADDR_ADDR,
+ HWIO_JPEG_FE_CBCR_PONG_ADDR_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+ HWIO_JPEG_FE_CMD_RMSK, {JPEG_FE_CMD_BUFFERRELOAD} },
+};
+
+void msm_gemini_hw_fe_buffer_update(struct msm_gemini_hw_buf *p_input,
+ uint8_t pingpong_index)
+{
+ uint32_t n_reg_val = 0;
+
+ struct msm_gemini_hw_cmd *hw_cmd_p;
+
+ if (pingpong_index == 0) {
+ hw_cmd_p = &hw_cmd_fe_ping_update[0];
+ n_reg_val = ((((p_input->num_of_mcu_rows - 1) <<
+ HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT) &
+ HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK) |
+ (((p_input->num_of_mcu_rows - 1) <<
+ HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT) &
+ HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK));
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = ((p_input->y_buffer_addr <<
+ HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_SHFT) &
+ HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = ((p_input->cbcr_buffer_addr<<
+ HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_SHFT) &
+ HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ msm_gemini_hw_write(hw_cmd_p);
+ } else if (pingpong_index == 1) {
+ hw_cmd_p = &hw_cmd_fe_pong_update[0];
+ n_reg_val = ((((p_input->num_of_mcu_rows - 1) <<
+ HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT) &
+ HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK) |
+ (((p_input->num_of_mcu_rows - 1) <<
+ HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT) &
+ HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK));
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = ((p_input->y_buffer_addr <<
+ HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_SHFT) &
+ HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = ((p_input->cbcr_buffer_addr<<
+ HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_SHFT) &
+ HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ msm_gemini_hw_write(hw_cmd_p);
+ } else {
+ /* shall not get to here */
+ }
+
+ return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_fe_start[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+ HWIO_JPEG_FE_CMD_RMSK, {JPEG_OFFLINE_CMD_START} },
+};
+
+void msm_gemini_hw_fe_start(void)
+{
+ msm_gemini_hw_write(&hw_cmd_fe_start[0]);
+
+ return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_we_buffer_cfg[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_THRESHOLD_ADDR,
+ HWIO_JPEG_WE_Y_THRESHOLD_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_UB_CFG_ADDR,
+ HWIO_JPEG_WE_Y_UB_CFG_RMSK, {JPEG_WE_YUB_ENCODE} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_CBCR_THRESHOLD_ADDR,
+ HWIO_JPEG_WE_CBCR_THRESHOLD_RMSK, {0} },
+};
+
+/*
+ * first dimension is WE_ASSERT_STALL_TH and WE_DEASSERT_STALL_TH
+ * second dimension is for offline and real-time settings
+ */
+static const uint32_t GEMINI_WE_Y_THRESHOLD[2][2] = {
+ { 0x00000190, 0x000001ff },
+ { 0x0000016a, 0x000001ff }
+};
+
+/*
+ * first dimension is WE_ASSERT_STALL_TH and WE_DEASSERT_STALL_TH
+ * second dimension is for offline and real-time settings
+ */
+static const uint32_t GEMINI_WE_CBCR_THRESHOLD[2][2] = {
+ { 0x00000190, 0x000001ff },
+ { 0x0000016a, 0x000001ff }
+};
+
+void msm_gemini_hw_we_buffer_cfg(uint8_t is_realtime)
+{
+ uint32_t n_reg_val = 0;
+
+ struct msm_gemini_hw_cmd *hw_cmd_p = &hw_cmd_we_buffer_cfg[0];
+
+ n_reg_val = (((GEMINI_WE_Y_THRESHOLD[1][is_realtime] <<
+ HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT) &
+ HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK) |
+ ((GEMINI_WE_Y_THRESHOLD[0][is_realtime] <<
+ HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_SHFT) &
+ HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_BMSK));
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ /* @todo maybe not for realtime? */
+ n_reg_val = (((GEMINI_WE_CBCR_THRESHOLD[1][is_realtime] <<
+ HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT) &
+ HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK) |
+ ((GEMINI_WE_CBCR_THRESHOLD[0][is_realtime] <<
+ HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_SHFT) &
+ HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_BMSK));
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p);
+
+ return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_we_ping_update[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PING_BUFFER_CFG_ADDR,
+ HWIO_JPEG_WE_Y_PING_BUFFER_CFG_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PING_ADDR_ADDR,
+ HWIO_JPEG_WE_Y_PING_ADDR_RMSK, {0} },
+};
+
+struct msm_gemini_hw_cmd hw_cmd_we_pong_update[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_ADDR,
+ HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_RMSK, {0} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PONG_ADDR_ADDR,
+ HWIO_JPEG_WE_Y_PONG_ADDR_RMSK, {0} },
+};
+
+void msm_gemini_hw_we_buffer_update(struct msm_gemini_hw_buf *p_input,
+ uint8_t pingpong_index)
+{
+ uint32_t n_reg_val = 0;
+
+ struct msm_gemini_hw_cmd *hw_cmd_p;
+
+ GMN_DBG("%s:%d] pingpong index %d", __func__, __LINE__,
+ pingpong_index);
+ if (pingpong_index == 0) {
+ hw_cmd_p = &hw_cmd_we_ping_update[0];
+
+ n_reg_val = ((p_input->y_len <<
+ HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT) &
+ HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = p_input->y_buffer_addr;
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+ } else if (pingpong_index == 1) {
+ hw_cmd_p = &hw_cmd_we_pong_update[0];
+
+ n_reg_val = ((p_input->y_len <<
+ HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT) &
+ HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK);
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+
+ n_reg_val = p_input->y_buffer_addr;
+ hw_cmd_p->data = n_reg_val;
+ msm_gemini_hw_write(hw_cmd_p++);
+ } else {
+ /* shall not get to here */
+ }
+
+ return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_reset[] = {
+ /* type, repeat n times, offset, mask, data or pdata */
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_MASK_ADDR,
+ HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_DISABLE_ALL} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_CLEAR_ADDR,
+ HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_CLEAR_ALL} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_MASK_ADDR,
+ HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+ {MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_RESET_CMD_ADDR,
+ HWIO_JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} },
+};
+
+void msm_gemini_hw_init(void *base, int size)
+{
+ gemini_region_base = base;
+ gemini_region_size = size;
+}
+
+void msm_gemini_hw_reset(void *base, int size)
+{
+ struct msm_gemini_hw_cmd *hw_cmd_p;
+
+ hw_cmd_p = &hw_cmd_reset[0];
+
+ msm_gemini_hw_write(hw_cmd_p++);
+ msm_gemini_hw_write(hw_cmd_p++);
+ msm_gemini_hw_write(hw_cmd_p++);
+ msm_gemini_hw_write(hw_cmd_p);
+}
+
+uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p)
+{
+ uint32_t *paddr;
+ uint32_t data;
+
+ paddr = gemini_region_base + hw_cmd_p->offset;
+
+ data = readl_relaxed(paddr);
+ data &= hw_cmd_p->mask;
+
+ GMN_DBG("%s:%d] type-%d n-%d offset-0x%4x mask-0x%8x data-0x%8x\n",
+ __func__, __LINE__, hw_cmd_p->type, hw_cmd_p->n,
+ hw_cmd_p->offset, hw_cmd_p->mask, data);
+ return data;
+}
+
+void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p)
+{
+ uint32_t *paddr;
+ uint32_t old_data, new_data;
+
+ /* type, repeat n times, offset, mask, data or pdata */
+ GMN_DBG("%s:%d] type-%d n-%d offset-0x%4x mask-0x%8x data-0x%8x\n",
+ __func__, __LINE__, hw_cmd_p->type, hw_cmd_p->n,
+ hw_cmd_p->offset, hw_cmd_p->mask, hw_cmd_p->data);
+
+ paddr = gemini_region_base + hw_cmd_p->offset;
+
+ if (hw_cmd_p->mask == 0xffffffff) {
+ old_data = 0;
+ } else {
+ old_data = readl_relaxed(paddr);
+ old_data &= ~hw_cmd_p->mask;
+ }
+
+ new_data = hw_cmd_p->data & hw_cmd_p->mask;
+ new_data |= old_data;
+ writel_relaxed(new_data, paddr);
+}
+
+int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us)
+{
+ int tm = hw_cmd_p->n;
+ uint32_t data;
+ uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
+
+ data = msm_gemini_hw_read(hw_cmd_p);
+ if (data != wait_data) {
+ while (tm) {
+ udelay(m_us);
+ data = msm_gemini_hw_read(hw_cmd_p);
+ if (data == wait_data)
+ break;
+ tm--;
+ }
+ }
+ hw_cmd_p->data = data;
+ return tm;
+}
+
+void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us)
+{
+ int tm = hw_cmd_p->n;
+ while (tm) {
+ udelay(m_us);
+ tm--;
+ }
+}
+
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+{
+ int is_copy_to_user = -1;
+ uint32_t data;
+
+ while (m_cmds--) {
+ if (hw_cmd_p->offset > gemini_region_size) {
+ GMN_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
+ __LINE__, hw_cmd_p->offset, gemini_region_size);
+ return -EFAULT;
+ }
+
+ switch (hw_cmd_p->type) {
+ case MSM_GEMINI_HW_CMD_TYPE_READ:
+ hw_cmd_p->data = msm_gemini_hw_read(hw_cmd_p);
+ is_copy_to_user = 1;
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_WRITE:
+ msm_gemini_hw_write(hw_cmd_p);
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_WRITE_OR:
+ data = msm_gemini_hw_read(hw_cmd_p);
+ hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
+ data;
+ msm_gemini_hw_write(hw_cmd_p);
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_UWAIT:
+ msm_gemini_hw_wait(hw_cmd_p, 1);
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_MWAIT:
+ msm_gemini_hw_wait(hw_cmd_p, 1000);
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_UDELAY:
+ /* Userspace driver provided delay duration */
+ msm_gemini_hw_delay(hw_cmd_p, 1);
+ break;
+
+ case MSM_GEMINI_HW_CMD_TYPE_MDELAY:
+ /* Userspace driver provided delay duration */
+ msm_gemini_hw_delay(hw_cmd_p, 1000);
+ break;
+
+ default:
+ GMN_PR_ERR("wrong hw command type\n");
+ break;
+ }
+
+ hw_cmd_p++;
+ }
+ return is_copy_to_user;
+}
+
+#ifdef MSM_GMN_DBG_DUMP
+void msm_gemini_io_dump(int size)
+{
+ char line_str[128], *p_str;
+ void __iomem *addr = gemini_region_base;
+ int i;
+ u32 *p = (u32 *) addr;
+ u32 data;
+ pr_info("%s: %p %d reg_size %d\n", __func__, addr, size,
+ gemini_region_size);
+ line_str[0] = '\0';
+ p_str = line_str;
+ for (i = 0; i < size/4; i++) {
+ if (i % 4 == 0) {
+ snprintf(p_str, 12, "%08x: ", (u32) p);
+ p_str += 10;
+ }
+ data = readl_relaxed(p++);
+ snprintf(p_str, 12, "%08x ", data);
+ p_str += 9;
+ if ((i + 1) % 4 == 0) {
+ pr_info("%s\n", line_str);
+ line_str[0] = '\0';
+ p_str = line_str;
+ }
+ }
+ if (line_str[0] != '\0')
+ pr_info("%s\n", line_str);
+}
+#else
+void msm_gemini_io_dump(int size)
+{
+
+}
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
new file mode 100644
index 0000000..84eed72
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
@@ -0,0 +1,104 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_GEMINI_HW_H
+#define MSM_GEMINI_HW_H
+
+#include <linux/msm_ion.h>
+#include <media/msm_gemini.h>
+#include <mach/iommu_domains.h>
+#include "msm_gemini_hw_reg.h"
+
+struct msm_gemini_hw_buf {
+ struct msm_gemini_buf vbuf;
+ struct file *file;
+ uint32_t framedone_len;
+ uint32_t y_buffer_addr;
+ uint32_t y_len;
+ uint32_t cbcr_buffer_addr;
+ uint32_t cbcr_len;
+ uint32_t num_of_mcu_rows;
+ struct ion_handle *handle;
+};
+
+struct msm_gemini_hw_pingpong {
+ uint8_t is_fe; /* 1: fe; 0: we */
+ struct msm_gemini_hw_buf buf[2];
+ int buf_status[2];
+ int buf_active_index;
+};
+
+int msm_gemini_hw_pingpong_update(struct msm_gemini_hw_pingpong *pingpong_hw,
+ struct msm_gemini_hw_buf *buf);
+void *msm_gemini_hw_pingpong_irq(struct msm_gemini_hw_pingpong *pingpong_hw);
+void *msm_gemini_hw_pingpong_active_buffer(struct msm_gemini_hw_pingpong
+ *pingpong_hw);
+
+void msm_gemini_hw_irq_clear(uint32_t, uint32_t);
+int msm_gemini_hw_irq_get_status(void);
+long msm_gemini_hw_encode_output_size(void);
+#define MSM_GEMINI_HW_MASK_COMP_FRAMEDONE \
+ MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_MASK
+#define MSM_GEMINI_HW_MASK_COMP_FE \
+ MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_MASK
+#define MSM_GEMINI_HW_MASK_COMP_WE \
+ (MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK)
+#define MSM_GEMINI_HW_MASK_COMP_RESET_ACK \
+ MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_MASK
+#define MSM_GEMINI_HW_MASK_COMP_ERR \
+ (MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_MASK | \
+ MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_MASK)
+
+#define msm_gemini_hw_irq_is_frame_done(gemini_irq_status) \
+ (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_FRAMEDONE)
+#define msm_gemini_hw_irq_is_fe_pingpong(gemini_irq_status) \
+ (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_FE)
+#define msm_gemini_hw_irq_is_we_pingpong(gemini_irq_status) \
+ (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_WE)
+#define msm_gemini_hw_irq_is_reset_ack(gemini_irq_status) \
+ (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_RESET_ACK)
+#define msm_gemini_hw_irq_is_err(gemini_irq_status) \
+ (gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_ERR)
+
+void msm_gemini_hw_fe_buffer_update(struct msm_gemini_hw_buf *p_input,
+ uint8_t pingpong_index);
+void msm_gemini_hw_we_buffer_update(struct msm_gemini_hw_buf *p_input,
+ uint8_t pingpong_index);
+
+void msm_gemini_hw_we_buffer_cfg(uint8_t is_realtime);
+
+void msm_gemini_hw_fe_start(void);
+void msm_gemini_hw_clk_cfg(void);
+
+void msm_gemini_hw_reset(void *base, int size);
+void msm_gemini_hw_irq_cfg(void);
+void msm_gemini_hw_init(void *base, int size);
+
+uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p);
+void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
+int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
+void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+void msm_gemini_io_dump(int size);
+
+#define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP 128MHz */
+#define MSM_GEMINI_PIPELINE_CLK_140MHZ 140 /* 9MP 140MHz */
+#define MSM_GEMINI_PIPELINE_CLK_200MHZ 153 /* 12MP 153MHz */
+
+#endif /* MSM_GEMINI_HW_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw_reg.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw_reg.h
new file mode 100644
index 0000000..4f05650
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw_reg.h
@@ -0,0 +1,176 @@
+/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_GEMINI_HW_REG_H
+#define MSM_GEMINI_HW_REG_H
+
+#define GEMINI_REG_BASE 0
+
+#define MSM_GEMINI_HW_IRQ_MASK_ADDR 0x00000014
+#define MSM_GEMINI_HW_IRQ_MASK_RMSK 0xffffffff
+#define MSM_GEMINI_HW_IRQ_MASK_SHFT 0
+#define MSM_GEMINI_HW_IRQ_DISABLE 0
+#define MSM_GEMINI_HW_IRQ_ENABLE 0xffffffff
+
+#define MSM_GEMINI_HW_IRQ_CLEAR_ADDR 0x00000018
+#define MSM_GEMINI_HW_IRQ_CLEAR_RMSK 0xffffffff
+#define MSM_GEMINI_HW_IRQ_CLEAR_SHFT 0
+#define MSM_GEMINI_HW_IRQ_CLEAR 0xffffffff
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001
+#define MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000002
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK 0x00000040
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_SHIFT 0x00000006
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK 0x00000080
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_SHIFT 0x00000007
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK 0x00000100
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_SHIFT 0x00000008
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK 0x00000200
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_SHIFT 0x00000009
+
+#define MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_MASK 0x00000400
+#define MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
+
+#define MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800
+#define MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b
+
+#define MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_MASK 0x00001000
+#define MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_SHIFT 0x0000000c
+
+#define JPEG_BUS_CMD_HALT_REQ 0x00000001
+
+#define JPEG_REALTIME_CMD_STOP_FB 0x00000000
+#define JPEG_REALTIME_CMD_STOP_IM 0x00000003
+#define JPEG_REALTIME_CMD_START 0x00000001
+
+#define JPEG_OFFLINE_CMD_START 0x00000003
+
+#define JPEG_DMI_CFG_DISABLE 0x00000000
+#define JPEG_DMI_ADDR_START 0x00000000
+
+#define JPEG_FE_CMD_BUFFERRELOAD 0x00000001
+
+#define JPEG_WE_YUB_ENCODE 0x01ff0000
+
+#define JPEG_RESET_DEFAULT 0x0004ffff /* cfff? */
+
+#define JPEG_IRQ_DISABLE_ALL 0x00000000
+#define JPEG_IRQ_CLEAR_ALL 0xffffffff
+#define JPEG_IRQ_ALLSOURCES_ENABLE 0xffffffff
+
+#define HWIO_JPEG_FE_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x00000080)
+#define HWIO_JPEG_FE_BUFFER_CFG_RMSK 0x1fff1fff
+
+#define HWIO_JPEG_FE_Y_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x00000084)
+#define HWIO_JPEG_FE_Y_PING_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_Y_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x00000088)
+#define HWIO_JPEG_FE_Y_PONG_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x0000008c)
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x00000090)
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CMD_ADDR (GEMINI_REG_BASE + 0x00000094)
+#define HWIO_JPEG_FE_CMD_RMSK 0x3
+
+#define HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK 0x1fff0000
+#define HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT 0x10
+#define HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK 0x1fff
+#define HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT 0
+
+#define HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_WE_Y_THRESHOLD_ADDR (GEMINI_REG_BASE + 0x000000c0)
+#define HWIO_JPEG_WE_Y_THRESHOLD_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_ADDR (GEMINI_REG_BASE + 0x000000c4)
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_Y_UB_CFG_ADDR (GEMINI_REG_BASE + 0x000000e8)
+#define HWIO_JPEG_WE_Y_UB_CFG_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK 0x1ff0000
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT 0x10
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_BMSK 0x1ff
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_SHFT 0
+
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK 0x1ff0000
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT 0x10
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_BMSK 0x1ff
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_SHFT 0
+
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x000000c8)
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_RMSK 0x7fffff
+
+#define HWIO_JPEG_WE_Y_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x000000d8)
+#define HWIO_JPEG_WE_Y_PING_ADDR_RMSK 0xfffffff8
+
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x000000cc)
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_RMSK 0x7fffff
+
+#define HWIO_JPEG_WE_Y_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x000000dc)
+#define HWIO_JPEG_WE_Y_PONG_ADDR_RMSK 0xfffffff8
+
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK 0x7fffff
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT 0
+
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK 0x7fffff
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT 0
+
+#define HWIO_JPEG_IRQ_MASK_ADDR (GEMINI_REG_BASE + 0x00000014)
+#define HWIO_JPEG_IRQ_MASK_RMSK 0xffffffff
+
+#define HWIO_JPEG_IRQ_CLEAR_ADDR (GEMINI_REG_BASE + 0x00000018)
+#define HWIO_JPEG_IRQ_CLEAR_RMSK 0xffffffff
+
+#define HWIO_JPEG_RESET_CMD_ADDR (GEMINI_REG_BASE + 0x00000004)
+#define HWIO_JPEG_RESET_CMD_RMSK 0xe004ffff
+
+#define HWIO_JPEG_IRQ_STATUS_ADDR (GEMINI_REG_BASE + 0x0000001c)
+#define HWIO_JPEG_IRQ_STATUS_RMSK 0xffffffff
+
+#define HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_ADDR (GEMINI_REG_BASE + 0x00000034)
+#define HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_RMSK 0xffffffff
+
+#endif /* MSM_GEMINI_HW_REG_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.c
new file mode 100644
index 0000000..f442068
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.c
@@ -0,0 +1,283 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/pm_qos.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <mach/clk.h>
+#include <mach/camera2.h>
+#include <mach/iommu_domains.h>
+#include "msm_gemini_platform.h"
+#include "msm_gemini_sync.h"
+#include "msm_gemini_common.h"
+#include "msm_gemini_hw.h"
+#include "msm_camera_io_util.h"
+
+/* AXI rate in KHz */
+#define MSM_SYSTEM_BUS_RATE 160000
+struct ion_client *gemini_client;
+
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+void msm_gemini_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle)
+{
+ ion_unmap_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL);
+ ion_free(gemini_client, *ionhandle);
+ *ionhandle = NULL;
+}
+#else
+void msm_gemini_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle)
+{
+
+}
+#endif
+
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p,
+ struct ion_handle **ionhandle)
+{
+ unsigned long paddr;
+ unsigned long size;
+ int rc;
+
+ *ionhandle = ion_import_dma_buf(gemini_client, fd);
+ if (IS_ERR_OR_NULL(*ionhandle))
+ return 0;
+
+ rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL,
+ SZ_4K, 0, &paddr, (unsigned long *)&size, 0, 0);
+ if (rc < 0) {
+ GMN_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
+ rc);
+ goto error1;
+ }
+ /* validate user input */
+ if (len > size) {
+ GMN_PR_ERR("%s: invalid offset + len\n", __func__);
+ goto error1;
+ }
+
+ return paddr;
+error1:
+ ion_free(gemini_client, *ionhandle);
+
+ return 0;
+}
+#else
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p,
+ struct ion_handle **ionhandle)
+{
+ return 0;
+}
+#endif
+
+static struct msm_cam_clk_info gemini_8x_clk_info[] = {
+ {"core_clk", 228571000, 0},
+ {"iface_clk", -1, 0},
+};
+
+static struct msm_cam_clk_info gemini_7x_clk_info[] = {
+ {"core_clk", 153600000, 0},
+ {"iface_clk", -1, 0},
+};
+
+static struct msm_cam_clk_info gemini_imem_clk_info[] = {
+ {"mem_clk", -1, 0},
+};
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_client *msm_gemini_ion_client_create(unsigned int heap_mask,
+ const char *name)
+{
+ return msm_ion_client_create(heap_mask, name);
+}
+#else
+static struct ion_client *msm_gemini_ion_client_create(unsigned int heap_mask,
+ const char *name)
+{
+ return NULL;
+}
+#endif
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+void msm_gemini_ion_client_destroy(struct ion_client *client)
+{
+ ion_client_destroy(client);
+}
+#else
+void msm_gemini_ion_client_destroy(struct ion_client *client)
+{
+
+}
+#endif
+
+int msm_gemini_platform_init(struct platform_device *pdev,
+ struct resource **mem,
+ void **base,
+ int *irq,
+ irqreturn_t (*handler) (int, void *),
+ void *context)
+{
+ int rc = -1;
+ int gemini_irq;
+ struct resource *gemini_mem, *gemini_io, *gemini_irq_res;
+ void *gemini_base;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *) context;
+
+ gemini_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!gemini_mem) {
+ GMN_PR_ERR("%s: no mem resource!\n", __func__);
+ return -ENODEV;
+ }
+
+ gemini_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!gemini_irq_res) {
+ GMN_PR_ERR("no irq resource!\n");
+ return -ENODEV;
+ }
+ gemini_irq = gemini_irq_res->start;
+
+ gemini_io = request_mem_region(gemini_mem->start,
+ resource_size(gemini_mem), pdev->name);
+ if (!gemini_io) {
+ GMN_PR_ERR("%s: region already claimed\n", __func__);
+ return -EBUSY;
+ }
+
+ gemini_base = ioremap(gemini_mem->start, resource_size(gemini_mem));
+ if (!gemini_base) {
+ rc = -ENOMEM;
+ GMN_PR_ERR("%s: ioremap failed\n", __func__);
+ goto fail1;
+ }
+ pgmn_dev->hw_version = GEMINI_8X60;
+ rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 1);
+ if (rc < 0) {
+ pgmn_dev->hw_version = GEMINI_7X;
+ rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev,
+ gemini_7x_clk_info, pgmn_dev->gemini_clk,
+ ARRAY_SIZE(gemini_7x_clk_info), 1);
+ if (rc < 0) {
+ GMN_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+ goto fail2;
+ }
+ } else {
+ rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev,
+ gemini_imem_clk_info, &pgmn_dev->gemini_clk[2],
+ ARRAY_SIZE(gemini_imem_clk_info), 1);
+ if (!rc)
+ pgmn_dev->hw_version = GEMINI_8960;
+ }
+
+ if (pgmn_dev->hw_version != GEMINI_7X) {
+ if (pgmn_dev->gemini_fs == NULL) {
+ pgmn_dev->gemini_fs =
+ regulator_get(&pgmn_dev->pdev->dev, "vdd");
+ if (IS_ERR(pgmn_dev->gemini_fs)) {
+ GMN_PR_ERR("%s: regulator_get failed %ld\n",
+ __func__, PTR_ERR(pgmn_dev->gemini_fs));
+ pgmn_dev->gemini_fs = NULL;
+ goto gemini_fs_failed;
+ } else if (regulator_enable(pgmn_dev->gemini_fs)) {
+ GMN_PR_ERR("%s: regulator_enable failed\n",
+ __func__);
+ regulator_put(pgmn_dev->gemini_fs);
+ pgmn_dev->gemini_fs = NULL;
+ goto gemini_fs_failed;
+ }
+ }
+ }
+
+ msm_gemini_hw_init(gemini_base, resource_size(gemini_mem));
+ rc = request_irq(gemini_irq, handler, IRQF_TRIGGER_RISING, "gemini",
+ context);
+ if (rc) {
+ GMN_PR_ERR("%s: request_irq failed, %d\n", __func__,
+ gemini_irq);
+ goto fail3;
+ }
+
+ *mem = gemini_mem;
+ *base = gemini_base;
+ *irq = gemini_irq;
+
+ gemini_client = msm_gemini_ion_client_create(-1, "camera/gemini");
+
+ GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+
+ return rc;
+
+fail3:
+ if (pgmn_dev->hw_version != GEMINI_7X) {
+ regulator_disable(pgmn_dev->gemini_fs);
+ regulator_put(pgmn_dev->gemini_fs);
+ pgmn_dev->gemini_fs = NULL;
+ }
+gemini_fs_failed:
+ if (pgmn_dev->hw_version == GEMINI_8960)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_imem_clk_info,
+ &pgmn_dev->gemini_clk[2], ARRAY_SIZE(gemini_imem_clk_info), 0);
+ if (pgmn_dev->hw_version != GEMINI_7X)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 0);
+ else
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_7x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_7x_clk_info), 0);
+fail2:
+ iounmap(gemini_base);
+fail1:
+ release_mem_region(gemini_mem->start, resource_size(gemini_mem));
+ GMN_DBG("%s:%d] fail\n", __func__, __LINE__);
+ return rc;
+}
+
+int msm_gemini_platform_release(struct resource *mem, void *base, int irq,
+ void *context)
+{
+ int result = 0;
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *) context;
+
+ free_irq(irq, context);
+
+ if (pgmn_dev->hw_version != GEMINI_7X) {
+ regulator_disable(pgmn_dev->gemini_fs);
+ regulator_put(pgmn_dev->gemini_fs);
+ pgmn_dev->gemini_fs = NULL;
+ }
+
+ if (pgmn_dev->hw_version == GEMINI_8960)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_imem_clk_info,
+ &pgmn_dev->gemini_clk[2], ARRAY_SIZE(gemini_imem_clk_info), 0);
+ if (pgmn_dev->hw_version != GEMINI_7X)
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 0);
+ else
+ msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_7x_clk_info,
+ pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_7x_clk_info), 0);
+
+ iounmap(base);
+ release_mem_region(mem->start, resource_size(mem));
+
+ msm_gemini_ion_client_destroy(gemini_client);
+
+ GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+ return result;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.h
new file mode 100644
index 0000000..a071df9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_GEMINI_PLATFORM_H
+#define MSM_GEMINI_PLATFORM_H
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+void msm_gemini_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle);
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file,
+ struct ion_handle **ionhandle);
+
+int msm_gemini_platform_clk_enable(void);
+int msm_gemini_platform_clk_disable(void);
+
+int msm_gemini_platform_init(struct platform_device *pdev,
+ struct resource **mem,
+ void **base,
+ int *irq,
+ irqreturn_t (*handler) (int, void *),
+ void *context);
+int msm_gemini_platform_release(struct resource *mem, void *base, int irq,
+ void *context);
+
+#endif /* MSM_GEMINI_PLATFORM_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
new file mode 100644
index 0000000..8f84a2c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
@@ -0,0 +1,1081 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <media/msm_gemini.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include "msm_gemini_sync.h"
+#include "msm_gemini_core.h"
+#include "msm_gemini_platform.h"
+#include "msm_gemini_common.h"
+
+static int release_buf;
+
+/* size is based on 4k page size */
+static const int g_max_out_size = 0x7ff000;
+
+/*************** queue helper ****************/
+static inline void msm_gemini_q_init(char const *name, struct msm_gemini_q *q_p)
+{
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+ q_p->name = name;
+ spin_lock_init(&q_p->lck);
+ INIT_LIST_HEAD(&q_p->q);
+ init_waitqueue_head(&q_p->wait);
+ q_p->unblck = 0;
+}
+
+static inline void *msm_gemini_q_out(struct msm_gemini_q *q_p)
+{
+ unsigned long flags;
+ struct msm_gemini_q_entry *q_entry_p = NULL;
+ void *data = NULL;
+
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ spin_lock_irqsave(&q_p->lck, flags);
+ if (!list_empty(&q_p->q)) {
+ q_entry_p = list_first_entry(&q_p->q, struct msm_gemini_q_entry,
+ list);
+ list_del_init(&q_entry_p->list);
+ }
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ if (q_entry_p) {
+ data = q_entry_p->data;
+ kfree(q_entry_p);
+ } else {
+ GMN_DBG("%s:%d] %s no entry\n", __func__, __LINE__,
+ q_p->name);
+ }
+
+ return data;
+}
+
+static inline int msm_gemini_q_in(struct msm_gemini_q *q_p, void *data)
+{
+ unsigned long flags;
+
+ struct msm_gemini_q_entry *q_entry_p;
+
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+ q_entry_p = kmalloc(sizeof(struct msm_gemini_q_entry), GFP_ATOMIC);
+ if (!q_entry_p) {
+ GMN_PR_ERR("%s: no mem\n", __func__);
+ return -ENOMEM;
+ }
+ q_entry_p->data = data;
+
+ spin_lock_irqsave(&q_p->lck, flags);
+ list_add_tail(&q_entry_p->list, &q_p->q);
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ return 0;
+}
+
+static inline int msm_gemini_q_in_buf(struct msm_gemini_q *q_p,
+ struct msm_gemini_core_buf *buf)
+{
+ struct msm_gemini_core_buf *buf_p;
+
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+ buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ GMN_PR_ERR("%s: no mem\n", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(buf_p, buf, sizeof(struct msm_gemini_core_buf));
+
+ msm_gemini_q_in(q_p, buf_p);
+ return 0;
+}
+
+static inline int msm_gemini_q_wait(struct msm_gemini_q *q_p)
+{
+ int tm = MAX_SCHEDULE_TIMEOUT;
+ int rc;
+
+ GMN_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name);
+ rc = wait_event_interruptible_timeout(q_p->wait,
+ (!list_empty_careful(&q_p->q) || q_p->unblck),
+ msecs_to_jiffies(tm));
+ GMN_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name);
+ if (list_empty_careful(&q_p->q)) {
+ if (rc == 0) {
+ rc = -ETIMEDOUT;
+ GMN_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__,
+ q_p->name);
+ } else if (q_p->unblck) {
+ GMN_DBG("%s:%d] %s unblock is true\n", __func__,
+ __LINE__, q_p->name);
+ q_p->unblck = 0;
+ rc = -ECANCELED;
+ } else if (rc < 0) {
+ GMN_PR_ERR("%s:%d] %s rc %d\n", __func__, __LINE__,
+ q_p->name, rc);
+ }
+ }
+ return rc;
+}
+
+static inline int msm_gemini_q_wakeup(struct msm_gemini_q *q_p)
+{
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+static inline int msm_gemini_q_unblock(struct msm_gemini_q *q_p)
+{
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ q_p->unblck = 1;
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+static inline void msm_gemini_outbuf_q_cleanup(struct msm_gemini_q *q_p)
+{
+ struct msm_gemini_core_buf *buf_p;
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ do {
+ buf_p = msm_gemini_q_out(q_p);
+ if (buf_p) {
+ msm_gemini_platform_p2v(buf_p->file,
+ &buf_p->handle);
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ kfree(buf_p);
+ }
+ } while (buf_p);
+ q_p->unblck = 0;
+}
+
+static inline void msm_gemini_q_cleanup(struct msm_gemini_q *q_p)
+{
+ void *data;
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ do {
+ data = msm_gemini_q_out(q_p);
+ if (data) {
+ GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ kfree(data);
+ }
+ } while (data);
+ q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+
+int msm_gemini_framedone_irq(struct msm_gemini_device *pgmn_dev,
+ struct msm_gemini_core_buf *buf_in)
+{
+ int rc = 0;
+
+ GMN_DBG("%s:%d] buf_in %p", __func__, __LINE__, buf_in);
+
+ if (buf_in) {
+ buf_in->vbuf.framedone_len = buf_in->framedone_len;
+ buf_in->vbuf.type = MSM_GEMINI_EVT_FRAMEDONE;
+ GMN_DBG("%s:%d] 0x%08x %d framedone_len %d\n",
+ __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len,
+ buf_in->vbuf.framedone_len);
+ rc = msm_gemini_q_in_buf(&pgmn_dev->evt_q, buf_in);
+ } else {
+ GMN_DBG("%s:%d] no output return buffer\n",
+ __func__, __LINE__);
+ rc = -1;
+ }
+
+ if (buf_in)
+ rc = msm_gemini_q_wakeup(&pgmn_dev->evt_q);
+
+ return rc;
+}
+
+int msm_gemini_evt_get(struct msm_gemini_device *pgmn_dev,
+ void __user *to)
+{
+ struct msm_gemini_core_buf *buf_p;
+ struct msm_gemini_ctrl_cmd ctrl_cmd;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ msm_gemini_q_wait(&pgmn_dev->evt_q);
+ buf_p = msm_gemini_q_out(&pgmn_dev->evt_q);
+
+ if (!buf_p) {
+ GMN_DBG("%s:%d] no buffer\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ memset(&ctrl_cmd, 0, sizeof(struct msm_gemini_ctrl_cmd));
+ ctrl_cmd.type = buf_p->vbuf.type;
+ kfree(buf_p);
+
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) ctrl_cmd.value, ctrl_cmd.len);
+
+ if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) {
+ GMN_PR_ERR("%s:%d]\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_gemini_evt_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_gemini_q_unblock(&pgmn_dev->evt_q);
+ return 0;
+}
+
+void msm_gemini_reset_ack_irq(struct msm_gemini_device *pgmn_dev)
+{
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+}
+
+void msm_gemini_err_irq(struct msm_gemini_device *pgmn_dev,
+ int event)
+{
+ int rc = 0;
+ struct msm_gemini_core_buf buf;
+
+ GMN_DBG("%s:%d] error: %d\n", __func__, __LINE__, event);
+
+ buf.vbuf.type = MSM_GEMINI_EVT_ERR;
+ rc = msm_gemini_q_in_buf(&pgmn_dev->evt_q, &buf);
+ if (!rc)
+ rc = msm_gemini_q_wakeup(&pgmn_dev->evt_q);
+
+ if (!rc)
+ GMN_PR_ERR("%s:%d] err err\n", __func__, __LINE__);
+
+ return;
+}
+
+/*************** output queue ****************/
+
+int msm_gemini_get_out_buffer(struct msm_gemini_device *pgmn_dev,
+ struct msm_gemini_hw_buf *p_outbuf)
+{
+ int buf_size = 0;
+ int bytes_remaining = 0;
+ if (pgmn_dev->out_offset >= pgmn_dev->out_buf.y_len) {
+ GMN_PR_ERR("%s:%d] no more buffers", __func__, __LINE__);
+ return -EINVAL;
+ }
+ bytes_remaining = pgmn_dev->out_buf.y_len - pgmn_dev->out_offset;
+ buf_size = min(bytes_remaining, pgmn_dev->max_out_size);
+
+ pgmn_dev->out_frag_cnt++;
+ GMN_DBG("%s:%d] buf_size[%d] %d", __func__, __LINE__,
+ pgmn_dev->out_frag_cnt, buf_size);
+ p_outbuf->y_len = buf_size;
+ p_outbuf->y_buffer_addr = pgmn_dev->out_buf.y_buffer_addr +
+ pgmn_dev->out_offset;
+ pgmn_dev->out_offset += buf_size;
+ return 0;
+}
+
+int msm_gemini_outmode_single_we_pingpong_irq(
+ struct msm_gemini_device *pgmn_dev,
+ struct msm_gemini_core_buf *buf_in)
+{
+ int rc = 0;
+ struct msm_gemini_core_buf out_buf;
+ int frame_done = buf_in &&
+ buf_in->vbuf.type == MSM_GEMINI_EVT_FRAMEDONE;
+ GMN_DBG("%s:%d] framedone %d", __func__, __LINE__, frame_done);
+ if (!pgmn_dev->out_buf_set) {
+ GMN_PR_ERR("%s:%d] output buffer not set",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ if (frame_done) {
+ /* send the buffer back */
+ pgmn_dev->out_buf.vbuf.framedone_len = buf_in->framedone_len;
+ pgmn_dev->out_buf.vbuf.type = MSM_GEMINI_EVT_FRAMEDONE;
+ rc = msm_gemini_q_in_buf(&pgmn_dev->output_rtn_q,
+ &pgmn_dev->out_buf);
+ if (rc) {
+ GMN_PR_ERR("%s:%d] cannot queue the output buffer",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ rc = msm_gemini_q_wakeup(&pgmn_dev->output_rtn_q);
+ /*
+ * reset the output buffer since the ownership is
+ * transferred to the rtn queue
+ */
+ if (!rc)
+ pgmn_dev->out_buf_set = 0;
+ } else {
+ /* configure ping/pong */
+ rc = msm_gemini_get_out_buffer(pgmn_dev, &out_buf);
+ if (rc)
+ msm_gemini_core_we_buf_reset(&out_buf);
+ else
+ msm_gemini_core_we_buf_update(&out_buf);
+ }
+ return rc;
+}
+
+int msm_gemini_we_pingpong_irq(struct msm_gemini_device *pgmn_dev,
+ struct msm_gemini_core_buf *buf_in)
+{
+ int rc = 0;
+ struct msm_gemini_core_buf *buf_out;
+
+ GMN_DBG("%s:%d] Enter mode %d", __func__, __LINE__,
+ pgmn_dev->out_mode);
+
+ if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_SINGLE)
+ return msm_gemini_outmode_single_we_pingpong_irq(pgmn_dev,
+ buf_in);
+
+ if (buf_in) {
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len);
+ rc = msm_gemini_q_in_buf(&pgmn_dev->output_rtn_q, buf_in);
+ } else {
+ GMN_DBG("%s:%d] no output return buffer\n", __func__,
+ __LINE__);
+ rc = -1;
+ return rc;
+ }
+
+ buf_out = msm_gemini_q_out(&pgmn_dev->output_buf_q);
+
+ if (buf_out) {
+ rc = msm_gemini_core_we_buf_update(buf_out);
+ kfree(buf_out);
+ } else {
+ msm_gemini_core_we_buf_reset(buf_in);
+ GMN_DBG("%s:%d] no output buffer\n", __func__, __LINE__);
+ rc = -2;
+ }
+
+ if (buf_in)
+ rc = msm_gemini_q_wakeup(&pgmn_dev->output_rtn_q);
+
+ return rc;
+}
+
+int msm_gemini_output_get(struct msm_gemini_device *pgmn_dev, void __user *to)
+{
+ struct msm_gemini_core_buf *buf_p;
+ struct msm_gemini_buf buf_cmd;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ msm_gemini_q_wait(&pgmn_dev->output_rtn_q);
+ buf_p = msm_gemini_q_out(&pgmn_dev->output_rtn_q);
+
+ if (!buf_p) {
+ GMN_DBG("%s:%d] no output buffer return\n",
+ __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ buf_cmd = buf_p->vbuf;
+ msm_gemini_platform_p2v(buf_p->file, &buf_p->handle);
+ kfree(buf_p);
+
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_cmd.vaddr, buf_cmd.y_len);
+
+ if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+ GMN_PR_ERR("%s:%d]", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_gemini_output_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_gemini_q_unblock(&pgmn_dev->output_rtn_q);
+ return 0;
+}
+
+int msm_gemini_set_output_buf(struct msm_gemini_device *pgmn_dev,
+ void __user *arg)
+{
+ struct msm_gemini_buf buf_cmd;
+
+ if (pgmn_dev->out_buf_set) {
+ GMN_PR_ERR("%s:%d] outbuffer buffer already provided",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ GMN_DBG("%s:%d] output addr 0x%08x len %d", __func__, __LINE__,
+ (int) buf_cmd.vaddr,
+ buf_cmd.y_len);
+
+ pgmn_dev->out_buf.y_buffer_addr = msm_gemini_platform_v2p(
+ buf_cmd.fd,
+ buf_cmd.y_len,
+ &pgmn_dev->out_buf.file,
+ &pgmn_dev->out_buf.handle);
+ if (!pgmn_dev->out_buf.y_buffer_addr) {
+ GMN_PR_ERR("%s:%d] cannot map the output address",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ pgmn_dev->out_buf.y_len = buf_cmd.y_len;
+ pgmn_dev->out_buf.vbuf = buf_cmd;
+ pgmn_dev->out_buf_set = 1;
+
+ return 0;
+}
+
+int msm_gemini_output_buf_enqueue(struct msm_gemini_device *pgmn_dev,
+ void __user *arg)
+{
+ struct msm_gemini_buf buf_cmd;
+ struct msm_gemini_core_buf *buf_p;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, (int) buf_cmd.vaddr,
+ buf_cmd.y_len);
+
+ buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
+ buf_cmd.y_len, &buf_p->file, &buf_p->handle);
+ if (!buf_p->y_buffer_addr) {
+ GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ kfree(buf_p);
+ return -ENOMEM;
+ }
+ buf_p->y_len = buf_cmd.y_len;
+ buf_p->vbuf = buf_cmd;
+
+ msm_gemini_q_in(&pgmn_dev->output_buf_q, buf_p);
+ return 0;
+}
+
+/*************** input queue ****************/
+
+int msm_gemini_fe_pingpong_irq(struct msm_gemini_device *pgmn_dev,
+ struct msm_gemini_core_buf *buf_in)
+{
+ struct msm_gemini_core_buf *buf_out;
+ int rc = 0;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (buf_in) {
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_in->y_buffer_addr, buf_in->y_len);
+ rc = msm_gemini_q_in_buf(&pgmn_dev->input_rtn_q, buf_in);
+ } else {
+ GMN_DBG("%s:%d] no input return buffer\n", __func__,
+ __LINE__);
+ rc = -1;
+ }
+
+ buf_out = msm_gemini_q_out(&pgmn_dev->input_buf_q);
+
+ if (buf_out) {
+ rc = msm_gemini_core_fe_buf_update(buf_out);
+ kfree(buf_out);
+ msm_gemini_core_fe_start();
+ } else {
+ GMN_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+ rc = -2;
+ }
+
+ if (buf_in)
+ rc = msm_gemini_q_wakeup(&pgmn_dev->input_rtn_q);
+
+ return rc;
+}
+
+int msm_gemini_input_get(struct msm_gemini_device *pgmn_dev, void __user *to)
+{
+ struct msm_gemini_core_buf *buf_p;
+ struct msm_gemini_buf buf_cmd;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_gemini_q_wait(&pgmn_dev->input_rtn_q);
+ buf_p = msm_gemini_q_out(&pgmn_dev->input_rtn_q);
+
+ if (!buf_p) {
+ GMN_DBG("%s:%d] no input buffer return\n",
+ __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ buf_cmd = buf_p->vbuf;
+ if (pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ENCODE ||
+ pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ROTATION) {
+ msm_gemini_platform_p2v(buf_p->file, &buf_p->handle);
+ }
+ kfree(buf_p);
+
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_cmd.vaddr, buf_cmd.y_len);
+
+ if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+ GMN_PR_ERR("%s:%d]\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_gemini_input_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_gemini_q_unblock(&pgmn_dev->input_rtn_q);
+ return 0;
+}
+
+int msm_gemini_input_buf_enqueue(struct msm_gemini_device *pgmn_dev,
+ void __user *arg)
+{
+ struct msm_gemini_core_buf *buf_p;
+ struct msm_gemini_buf buf_cmd;
+ int rc = 0;
+ struct msm_bus_scale_pdata *p_bus_scale_data = NULL;
+
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+ (int) buf_cmd.vaddr, buf_cmd.y_len);
+
+ if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
+ rc = msm_iommu_map_contig_buffer(
+ (unsigned long)buf_cmd.y_off, CAMERA_DOMAIN, GEN_POOL,
+ ((buf_cmd.y_len + buf_cmd.cbcr_len + 4095) & (~4095)),
+ SZ_4K, IOMMU_WRITE | IOMMU_READ,
+ (unsigned long *)&buf_p->y_buffer_addr);
+ if (rc < 0) {
+ GMN_PR_ERR("%s iommu mapping failed with error %d\n",
+ __func__, rc);
+ kfree(buf_p);
+ return rc;
+ }
+ } else {
+ buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
+ buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
+ &buf_p->handle) + buf_cmd.offset + buf_cmd.y_off;
+ }
+ buf_p->y_len = buf_cmd.y_len;
+
+ buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len +
+ buf_cmd.cbcr_off;
+ buf_p->cbcr_len = buf_cmd.cbcr_len;
+ buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+ GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
+ buf_p->y_buffer_addr, buf_p->y_len, buf_p->cbcr_buffer_addr,
+ buf_p->cbcr_len);
+
+ if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
+ GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ kfree(buf_p);
+ return -EINVAL;
+ }
+ buf_p->vbuf = buf_cmd;
+ buf_p->vbuf.type = MSM_GEMINI_EVT_RESET;
+
+ /* Set bus vectors */
+ p_bus_scale_data = (struct msm_bus_scale_pdata *)
+ pgmn_dev->pdev->dev.platform_data;
+ if (pgmn_dev->bus_perf_client &&
+ (MSM_GMN_OUTMODE_SINGLE == pgmn_dev->out_mode)) {
+ int rc;
+ struct msm_bus_paths *path = &(p_bus_scale_data->usecase[1]);
+ GMN_DBG("%s:%d] Update bus bandwidth", __func__, __LINE__);
+ if (pgmn_dev->op_mode & MSM_GEMINI_MODE_OFFLINE_ENCODE) {
+ path->vectors[0].ab = (buf_p->y_len + buf_p->cbcr_len) *
+ 15 * 2;
+ path->vectors[0].ib = path->vectors[0].ab;
+ path->vectors[1].ab = 0;
+ path->vectors[1].ib = 0;
+ }
+ rc = msm_bus_scale_client_update_request(
+ pgmn_dev->bus_perf_client, 1);
+ if (rc < 0) {
+ GMN_PR_ERR("%s:%d] update_request fails %d",
+ __func__, __LINE__, rc);
+ }
+ }
+
+ msm_gemini_q_in(&pgmn_dev->input_buf_q, buf_p);
+
+ return 0;
+}
+
+int msm_gemini_irq(int event, void *context, void *data)
+{
+ struct msm_gemini_device *pgmn_dev =
+ (struct msm_gemini_device *) context;
+
+ switch (event) {
+ case MSM_GEMINI_HW_MASK_COMP_FRAMEDONE:
+ msm_gemini_framedone_irq(pgmn_dev, data);
+ msm_gemini_we_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_GEMINI_HW_MASK_COMP_FE:
+ msm_gemini_fe_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_GEMINI_HW_MASK_COMP_WE:
+ msm_gemini_we_pingpong_irq(pgmn_dev, data);
+ break;
+
+ case MSM_GEMINI_HW_MASK_COMP_RESET_ACK:
+ msm_gemini_reset_ack_irq(pgmn_dev);
+ break;
+
+ case MSM_GEMINI_HW_MASK_COMP_ERR:
+ default:
+ msm_gemini_err_irq(pgmn_dev, event);
+ break;
+ }
+
+ return 0;
+}
+
+int __msm_gemini_open(struct msm_gemini_device *pgmn_dev)
+{
+ int rc;
+ struct msm_bus_scale_pdata *p_bus_scale_data =
+ (struct msm_bus_scale_pdata *)pgmn_dev->pdev->dev.
+ platform_data;
+
+ mutex_lock(&pgmn_dev->lock);
+ if (pgmn_dev->open_count) {
+ /* only open once */
+ GMN_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+ mutex_unlock(&pgmn_dev->lock);
+ return -EBUSY;
+ }
+ pgmn_dev->open_count++;
+ mutex_unlock(&pgmn_dev->lock);
+
+ msm_gemini_core_irq_install(msm_gemini_irq);
+
+
+ rc = msm_gemini_platform_init(pgmn_dev->pdev,
+ &pgmn_dev->mem, &pgmn_dev->base,
+ &pgmn_dev->irq, msm_gemini_core_irq, pgmn_dev);
+ if (rc) {
+ GMN_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+ __LINE__, rc);
+ return rc;
+ }
+
+ GMN_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n",
+ __func__, __LINE__,
+ pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq);
+
+ msm_gemini_q_cleanup(&pgmn_dev->evt_q);
+ msm_gemini_q_cleanup(&pgmn_dev->output_rtn_q);
+ msm_gemini_outbuf_q_cleanup(&pgmn_dev->output_buf_q);
+ msm_gemini_q_cleanup(&pgmn_dev->input_rtn_q);
+ msm_gemini_q_cleanup(&pgmn_dev->input_buf_q);
+ msm_gemini_core_init();
+ pgmn_dev->out_mode = MSM_GMN_OUTMODE_FRAGMENTED;
+ pgmn_dev->out_buf_set = 0;
+ pgmn_dev->out_offset = 0;
+ pgmn_dev->max_out_size = g_max_out_size;
+ pgmn_dev->out_frag_cnt = 0;
+ pgmn_dev->bus_perf_client = 0;
+
+ if (p_bus_scale_data) {
+ GMN_DBG("%s:%d] register bus client", __func__, __LINE__);
+ pgmn_dev->bus_perf_client =
+ msm_bus_scale_register_client(p_bus_scale_data);
+ if (!pgmn_dev->bus_perf_client) {
+ GMN_PR_ERR("%s:%d] bus client register failed",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ }
+ GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+ return rc;
+}
+
+int __msm_gemini_release(struct msm_gemini_device *pgmn_dev)
+{
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ mutex_lock(&pgmn_dev->lock);
+ if (!pgmn_dev->open_count) {
+ GMN_PR_ERR("%s: not opened\n", __func__);
+ mutex_unlock(&pgmn_dev->lock);
+ return -EINVAL;
+ }
+ pgmn_dev->open_count--;
+ mutex_unlock(&pgmn_dev->lock);
+
+ if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_FRAGMENTED) {
+ msm_gemini_core_release(release_buf);
+ } else if (pgmn_dev->out_buf_set) {
+ msm_gemini_platform_p2v(pgmn_dev->out_buf.file,
+ &pgmn_dev->out_buf.handle);
+ }
+ msm_gemini_q_cleanup(&pgmn_dev->evt_q);
+ msm_gemini_q_cleanup(&pgmn_dev->output_rtn_q);
+ msm_gemini_outbuf_q_cleanup(&pgmn_dev->output_buf_q);
+ msm_gemini_q_cleanup(&pgmn_dev->input_rtn_q);
+ msm_gemini_outbuf_q_cleanup(&pgmn_dev->input_buf_q);
+
+ if (pgmn_dev->bus_perf_client) {
+ msm_bus_scale_unregister_client(pgmn_dev->bus_perf_client);
+ pgmn_dev->bus_perf_client = 0;
+ }
+
+ if (pgmn_dev->open_count)
+ GMN_PR_ERR("%s: multiple opens\n", __func__);
+
+ msm_gemini_platform_release(pgmn_dev->mem, pgmn_dev->base,
+ pgmn_dev->irq, pgmn_dev);
+
+ return 0;
+}
+
+int msm_gemini_ioctl_hw_cmd(struct msm_gemini_device *pgmn_dev,
+ void * __user arg)
+{
+ struct msm_gemini_hw_cmd hw_cmd;
+ int is_copy_to_user;
+
+ if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_gemini_hw_cmd))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ is_copy_to_user = msm_gemini_hw_exec_cmds(&hw_cmd, 1);
+ GMN_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x, pdata %x\n",
+ __func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
+ hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata);
+
+ if (is_copy_to_user >= 0) {
+ if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int msm_gemini_ioctl_hw_cmds(struct msm_gemini_device *pgmn_dev,
+ void * __user arg)
+{
+ int is_copy_to_user;
+ int len;
+ uint32_t m;
+ struct msm_gemini_hw_cmds *hw_cmds_p;
+ struct msm_gemini_hw_cmd *hw_cmd_p;
+
+ if (copy_from_user(&m, arg, sizeof(m))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ len = sizeof(struct msm_gemini_hw_cmds) +
+ sizeof(struct msm_gemini_hw_cmd) * (m - 1);
+ hw_cmds_p = kmalloc(len, GFP_KERNEL);
+ if (!hw_cmds_p) {
+ GMN_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(hw_cmds_p, arg, len)) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+
+ hw_cmd_p = (struct msm_gemini_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+ is_copy_to_user = msm_gemini_hw_exec_cmds(hw_cmd_p, m);
+
+ if (is_copy_to_user >= 0) {
+ if (copy_to_user(arg, hw_cmds_p, len)) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+ }
+ kfree(hw_cmds_p);
+ return 0;
+}
+
+static int msm_gemini_start(struct msm_gemini_device *pgmn_dev,
+ void * __user arg)
+{
+ struct msm_gemini_core_buf *buf_out;
+ struct msm_gemini_core_buf *buf_out_free[2] = {NULL, NULL};
+ int i, rc;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+ release_buf = 1;
+ for (i = 0; i < 2; i++) {
+ buf_out = msm_gemini_q_out(&pgmn_dev->input_buf_q);
+
+ if (buf_out) {
+ msm_gemini_core_fe_buf_update(buf_out);
+ kfree(buf_out);
+ } else {
+ GMN_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+ break;
+ }
+ }
+
+ if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_FRAGMENTED) {
+ for (i = 0; i < 2; i++) {
+ buf_out_free[i] =
+ msm_gemini_q_out(&pgmn_dev->output_buf_q);
+
+ if (buf_out_free[i]) {
+ msm_gemini_core_we_buf_update(buf_out_free[i]);
+ } else if (i == 1) {
+ /* set the pong to same address as ping */
+ buf_out_free[0]->y_len >>= 1;
+ buf_out_free[0]->y_buffer_addr +=
+ buf_out_free[0]->y_len;
+ msm_gemini_core_we_buf_update(buf_out_free[0]);
+ /*
+ * since ping and pong are same buf
+ * release only once
+ */
+ release_buf = 0;
+ } else {
+ GMN_DBG("%s:%d] no output buffer\n",
+ __func__, __LINE__);
+ break;
+ }
+ }
+ for (i = 0; i < 2; i++)
+ kfree(buf_out_free[i]);
+ } else {
+ struct msm_gemini_core_buf out_buf;
+ /*
+ * Since the same buffer is fragmented, p2v need not be
+ * called for all the buffers
+ */
+ release_buf = 0;
+ if (!pgmn_dev->out_buf_set) {
+ GMN_PR_ERR("%s:%d] output buffer not set",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ /* configure ping */
+ rc = msm_gemini_get_out_buffer(pgmn_dev, &out_buf);
+ if (rc) {
+ GMN_PR_ERR("%s:%d] no output buffer for ping",
+ __func__, __LINE__);
+ return rc;
+ }
+ msm_gemini_core_we_buf_update(&out_buf);
+ /* configure pong */
+ rc = msm_gemini_get_out_buffer(pgmn_dev, &out_buf);
+ if (rc) {
+ GMN_DBG("%s:%d] no output buffer for pong",
+ __func__, __LINE__);
+ /* fall through to configure same buffer */
+ }
+ msm_gemini_core_we_buf_update(&out_buf);
+ msm_gemini_io_dump(0x150);
+ }
+
+ rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, arg);
+ GMN_DBG("%s:%d]\n", __func__, __LINE__);
+ return rc;
+}
+
+static int msm_gemini_ioctl_reset(struct msm_gemini_device *pgmn_dev,
+ void * __user arg)
+{
+ int rc;
+ struct msm_gemini_ctrl_cmd ctrl_cmd;
+
+ GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ pgmn_dev->op_mode = ctrl_cmd.type;
+
+ rc = msm_gemini_core_reset(pgmn_dev->op_mode, pgmn_dev->base,
+ resource_size(pgmn_dev->mem));
+ return rc;
+}
+
+static int msm_gemini_ioctl_set_outmode(struct msm_gemini_device *pgmn_dev,
+ void * __user arg)
+{
+ int rc = 0;
+ enum msm_gmn_out_mode mode;
+
+ if (copy_from_user(&mode, arg, sizeof(mode))) {
+ GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ GMN_DBG("%s:%d] mode %d", __func__, __LINE__, mode);
+
+ if ((mode == MSM_GMN_OUTMODE_FRAGMENTED)
+ || (mode == MSM_GMN_OUTMODE_SINGLE))
+ pgmn_dev->out_mode = mode;
+ return rc;
+}
+
+long __msm_gemini_ioctl(struct msm_gemini_device *pgmn_dev,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ switch (cmd) {
+ case MSM_GMN_IOCTL_GET_HW_VERSION:
+ GMN_DBG("%s:%d] VERSION 1\n", __func__, __LINE__);
+ rc = msm_gemini_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_RESET:
+ rc = msm_gemini_ioctl_reset(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_STOP:
+ rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_START:
+ rc = msm_gemini_start(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_INPUT_BUF_ENQUEUE:
+ rc = msm_gemini_input_buf_enqueue(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_INPUT_GET:
+ rc = msm_gemini_input_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_INPUT_GET_UNBLOCK:
+ rc = msm_gemini_input_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_GMN_IOCTL_OUTPUT_BUF_ENQUEUE:
+ if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_FRAGMENTED)
+ rc = msm_gemini_output_buf_enqueue(pgmn_dev,
+ (void __user *) arg);
+ else
+ rc = msm_gemini_set_output_buf(pgmn_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_OUTPUT_GET:
+ rc = msm_gemini_output_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_OUTPUT_GET_UNBLOCK:
+ rc = msm_gemini_output_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_GMN_IOCTL_EVT_GET:
+ rc = msm_gemini_evt_get(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_EVT_GET_UNBLOCK:
+ rc = msm_gemini_evt_get_unblock(pgmn_dev);
+ break;
+
+ case MSM_GMN_IOCTL_HW_CMD:
+ rc = msm_gemini_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_HW_CMDS:
+ rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+ break;
+
+ case MSM_GMN_IOCTL_SET_MODE:
+ rc = msm_gemini_ioctl_set_outmode(pgmn_dev, (void __user *)arg);
+ break;
+
+ default:
+ GMN_PR_ERR("%s:%d] cmd = %d not supported\n",
+ __func__, __LINE__, _IOC_NR(cmd));
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+struct msm_gemini_device *__msm_gemini_init(struct platform_device *pdev)
+{
+ struct msm_gemini_device *pgmn_dev;
+
+ pgmn_dev = kzalloc(sizeof(struct msm_gemini_device), GFP_ATOMIC);
+ if (!pgmn_dev) {
+ GMN_PR_ERR("%s:%d]no mem\n", __func__, __LINE__);
+ return NULL;
+ }
+
+ mutex_init(&pgmn_dev->lock);
+
+ pgmn_dev->pdev = pdev;
+
+ msm_gemini_q_init("evt_q", &pgmn_dev->evt_q);
+ msm_gemini_q_init("output_rtn_q", &pgmn_dev->output_rtn_q);
+ msm_gemini_q_init("output_buf_q", &pgmn_dev->output_buf_q);
+ msm_gemini_q_init("input_rtn_q", &pgmn_dev->input_rtn_q);
+ msm_gemini_q_init("input_buf_q", &pgmn_dev->input_buf_q);
+
+ return pgmn_dev;
+}
+
+int __msm_gemini_exit(struct msm_gemini_device *pgmn_dev)
+{
+ mutex_destroy(&pgmn_dev->lock);
+ kfree(pgmn_dev);
+ return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.h
new file mode 100644
index 0000000..6982a78
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.h
@@ -0,0 +1,98 @@
+/* Copyright (c) 2010,2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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_GEMINI_SYNC_H
+#define MSM_GEMINI_SYNC_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_gemini_core.h"
+
+#define GEMINI_7X 0x1
+#define GEMINI_8X60 (0x1 << 1)
+#define GEMINI_8960 (0x1 << 2)
+
+struct msm_gemini_q {
+ char const *name;
+ struct list_head q;
+ spinlock_t lck;
+ wait_queue_head_t wait;
+ int unblck;
+};
+
+struct msm_gemini_q_entry {
+ struct list_head list;
+ void *data;
+};
+
+struct msm_gemini_device {
+ struct platform_device *pdev;
+ struct resource *mem;
+ int irq;
+ void *base;
+ struct clk *gemini_clk[3];
+ struct regulator *gemini_fs;
+ uint32_t hw_version;
+
+ struct device *device;
+ struct cdev cdev;
+ struct mutex lock;
+ char open_count;
+ uint8_t op_mode;
+
+ /* event queue including frame done & err indications
+ */
+ struct msm_gemini_q evt_q;
+
+ /* output return queue
+ */
+ struct msm_gemini_q output_rtn_q;
+
+ /* output buf queue
+ */
+ struct msm_gemini_q output_buf_q;
+
+ /* input return queue
+ */
+ struct msm_gemini_q input_rtn_q;
+
+ /* input buf queue
+ */
+ struct msm_gemini_q input_buf_q;
+
+ struct v4l2_subdev subdev;
+ enum msm_gmn_out_mode out_mode;
+
+ /*single out mode parameters*/
+ struct msm_gemini_hw_buf out_buf;
+ int out_offset;
+ int out_buf_set;
+ int max_out_size;
+ int out_frag_cnt;
+
+ uint32_t bus_perf_client;
+};
+
+int __msm_gemini_open(struct msm_gemini_device *pgmn_dev);
+int __msm_gemini_release(struct msm_gemini_device *pgmn_dev);
+
+long __msm_gemini_ioctl(struct msm_gemini_device *pgmn_dev,
+ unsigned int cmd, unsigned long arg);
+
+struct msm_gemini_device *__msm_gemini_init(struct platform_device *pdev);
+int __msm_gemini_exit(struct msm_gemini_device *pgmn_dev);
+
+#endif /* MSM_GEMINI_SYNC_H */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 59858b5..88f2f08 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -80,13 +80,20 @@
}
static uint32_t msm_isp_get_buf_handle(
- struct msm_isp_buf_mgr *buf_mgr)
+ struct msm_isp_buf_mgr *buf_mgr,
+ uint32_t session_id, uint32_t stream_id)
{
int i;
if ((buf_mgr->buf_handle_cnt << 8) == 0)
buf_mgr->buf_handle_cnt++;
for (i = 0; i < buf_mgr->num_buf_q; i++) {
+ if (buf_mgr->bufq[i].session_id == session_id &&
+ buf_mgr->bufq[i].stream_id == stream_id)
+ return 0;
+ }
+
+ for (i = 0; i < buf_mgr->num_buf_q; i++) {
if (buf_mgr->bufq[i].bufq_handle == 0) {
memset(&buf_mgr->bufq[i],
0, sizeof(struct msm_isp_bufq));
@@ -604,7 +611,8 @@
return rc;
}
- buf_request->handle = msm_isp_get_buf_handle(buf_mgr);
+ buf_request->handle = msm_isp_get_buf_handle(buf_mgr,
+ buf_request->session_id, buf_request->stream_id);
if (!buf_request->handle) {
pr_err("Invalid buffer handle\n");
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index b31b3f1..ff9c9b8 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -121,6 +121,7 @@
vfe_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE;
vfe_dev->subdev.sd.entity.name = pdev->name;
+ vfe_dev->subdev.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x2;
rc = msm_sd_register(&vfe_dev->subdev);
if (rc != 0) {
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 7bc2b7d..6de6e74 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -38,6 +38,8 @@
#define VFE_PING_FLAG 0xFFFFFFFF
#define VFE_PONG_FLAG 0x0
+#define VFE_MAX_CFG_TIMEOUT 3000
+
struct vfe_device;
struct msm_vfe_axi_stream;
struct msm_vfe_stats_stream;
@@ -88,7 +90,7 @@
void (*enable_wm) (struct vfe_device *vfe_dev,
uint8_t wm_idx, uint8_t enable);
void (*cfg_io_format) (struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_req_cmd);
+ struct msm_vfe_axi_stream *stream_info);
void (*cfg_framedrop) (struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info);
void (*clear_framedrop) (struct vfe_device *vfe_dev,
@@ -103,13 +105,13 @@
struct msm_vfe_axi_stream *stream_info);
void (*cfg_wm_reg) (struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void (*clear_wm_reg) (struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
void (*cfg_wm_xbar_reg) (struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx);
void (*clear_wm_xbar_reg) (struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
@@ -231,7 +233,8 @@
enum msm_vfe_axi_stream_src stream_src;
uint8_t num_planes;
uint8_t wm[MAX_PLANES_PER_STREAM];
- uint32_t plane_offset[MAX_PLANES_PER_STREAM];
+ uint32_t output_format;/*Planar/RAW/Misc*/
+ struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
uint8_t comp_mask_index;
struct msm_isp_buffer *buf[2];
uint32_t session_id;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 679c5cb..3a94af3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -441,11 +441,11 @@
}
static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_req_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int bpp, bpp_reg = 0;
uint32_t io_format_reg;
- bpp = msm_isp_get_bit_per_pixel(stream_req_cmd->output_format);
+ bpp = msm_isp_get_bit_per_pixel(stream_info->output_format);
switch (bpp) {
case 8:
@@ -459,7 +459,7 @@
break;
}
io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8);
- switch (stream_req_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case CAMIF_RAW:
io_format_reg &= 0xFFFFCFFF;
io_format_reg |= bpp_reg << 12;
@@ -565,44 +565,40 @@
static void msm_vfe32_axi_cfg_wm_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx)
{
uint32_t val;
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
if (!stream_info->frame_based) {
/*WR_IMAGE_SIZE*/
val =
((msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_width)+1)/2 - 1) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1);
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
/*WR_BUFFER_CFG*/
val =
msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_stride) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1) << 4 | VFE32_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
} else {
msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
val =
msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_width) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1) << 4 | VFE32_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
}
@@ -624,19 +620,15 @@
static void msm_vfe32_axi_cfg_wm_xbar_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
- uint8_t plane_idx)
+ struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
{
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
struct msm_vfe_axi_plane_cfg *plane_cfg =
- &stream_cfg_cmd->plane_cfg[plane_idx];
+ &stream_info->plane_cfg[plane_idx];
uint8_t wm = stream_info->wm[plane_idx];
uint32_t xbar_cfg = 0;
uint32_t xbar_reg_cfg = 0;
- switch (stream_cfg_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case PIX_ENCODER:
case PIX_VIEWFINDER: {
if (plane_cfg->output_plane_format != CRCB_PLANE &&
@@ -644,7 +636,7 @@
/*SINGLE_STREAM_SEL*/
xbar_cfg |= plane_cfg->output_plane_format << 5;
} else {
- switch (stream_cfg_cmd->output_format) {
+ switch (stream_info->output_format) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV16:
xbar_cfg |= 0x3 << 3; /*PAIR_STREAM_SWAP_CTRL*/
@@ -652,7 +644,7 @@
}
xbar_cfg |= BIT(1); /*PAIR_STREAM_EN*/
}
- if (stream_cfg_cmd->stream_src == PIX_VIEWFINDER)
+ if (stream_info->stream_src == PIX_VIEWFINDER)
xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
break;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 756cb41..c4a1b63 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -436,6 +436,8 @@
{
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+ /*Ignore composite 3 irq which is used for dual VFE only*/
+ *irq_status0 &= ~BIT(28);
msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30);
msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34);
msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
@@ -521,14 +523,14 @@
comp_mask &= ~(0x7F << (comp_mask_index * 8));
comp_mask |= (axi_data->composite_info[comp_mask_index].
stream_composite_mask << (comp_mask_index * 8));
- if (stream_info->plane_offset[0])
+ if (stream_info->plane_cfg[0].plane_addr_offset)
comp_mask |= (axi_data->composite_info[comp_mask_index].
stream_composite_mask << 24);
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask |= 1 << (comp_mask_index + 25);
- if (stream_info->plane_offset[0] && (comp_mask >> 24))
+ if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
irq_mask |= BIT(28);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
@@ -542,14 +544,14 @@
comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
comp_mask &= ~(0x7F << (comp_mask_index * 8));
- if (stream_info->plane_offset[0])
+ if (stream_info->plane_cfg[0].plane_addr_offset)
comp_mask &= ~(axi_data->composite_info[comp_mask_index].
stream_composite_mask << 24);
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask &= ~(1 << (comp_mask_index + 25));
- if (stream_info->plane_offset[0] && !(comp_mask >> 24))
+ if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
irq_mask &= ~BIT(28);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
@@ -612,11 +614,11 @@
}
static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_req_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int bpp, bpp_reg = 0;
uint32_t io_format_reg;
- bpp = msm_isp_get_bit_per_pixel(stream_req_cmd->output_format);
+ bpp = msm_isp_get_bit_per_pixel(stream_info->output_format);
switch (bpp) {
case 8:
@@ -630,7 +632,7 @@
break;
}
io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54);
- switch (stream_req_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case CAMIF_RAW:
io_format_reg &= 0xFFFFCFFF;
io_format_reg |= bpp_reg << 12;
@@ -751,43 +753,39 @@
static void msm_vfe40_axi_cfg_wm_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx)
{
uint32_t val;
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]);
if (!stream_info->frame_based) {
/*WR_IMAGE_SIZE*/
val =
((msm_isp_cal_word_per_line(
- stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[plane_idx].
+ stream_info->output_format,
+ stream_info->plane_cfg[plane_idx].
output_width)+1)/2 - 1) << 16 |
- (stream_cfg_cmd->plane_cfg[plane_idx].
+ (stream_info->plane_cfg[plane_idx].
output_height - 1);
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
/*WR_BUFFER_CFG*/
val =
- msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[
+ msm_isp_cal_word_per_line(stream_info->output_format,
+ stream_info->plane_cfg[
plane_idx].output_stride) << 16 |
- (stream_cfg_cmd->plane_cfg[
+ (stream_info->plane_cfg[
plane_idx].output_height - 1) << 4 |
VFE40_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
} else {
msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
val =
- msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
- stream_cfg_cmd->plane_cfg[
+ msm_isp_cal_word_per_line(stream_info->output_format,
+ stream_info->plane_cfg[
plane_idx].output_width) << 16 |
- (stream_cfg_cmd->plane_cfg[
+ (stream_info->plane_cfg[
plane_idx].output_height - 1) << 4 |
VFE40_BURST_LEN;
msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
@@ -819,20 +817,16 @@
static void msm_vfe40_axi_cfg_wm_xbar_reg(
struct vfe_device *vfe_dev,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+ struct msm_vfe_axi_stream *stream_info,
uint8_t plane_idx)
{
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- (stream_cfg_cmd->axi_stream_handle & 0xFF)];
struct msm_vfe_axi_plane_cfg *plane_cfg =
- &stream_cfg_cmd->plane_cfg[plane_idx];
+ &stream_info->plane_cfg[plane_idx];
uint8_t wm = stream_info->wm[plane_idx];
uint32_t xbar_cfg = 0;
uint32_t xbar_reg_cfg = 0;
- switch (stream_cfg_cmd->stream_src) {
+ switch (stream_info->stream_src) {
case PIX_ENCODER:
case PIX_VIEWFINDER: {
if (plane_cfg->output_plane_format != CRCB_PLANE &&
@@ -840,7 +834,7 @@
/*SINGLE_STREAM_SEL*/
xbar_cfg |= plane_cfg->output_plane_format << 8;
} else {
- switch (stream_cfg_cmd->output_format) {
+ switch (stream_info->output_format) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV16:
xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/
@@ -848,7 +842,7 @@
}
xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/
}
- if (stream_cfg_cmd->stream_src == PIX_VIEWFINDER)
+ if (stream_info->stream_src == PIX_VIEWFINDER)
xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
break;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 13160ee..e3d036f6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -136,23 +136,23 @@
}
for (i = 0; i < stream_info->num_planes; i++) {
- stream_info->plane_offset[i] =
- stream_cfg_cmd->plane_cfg[i].plane_addr_offset;
+ stream_info->plane_cfg[i] = stream_cfg_cmd->plane_cfg[i];
stream_info->max_width = max(stream_info->max_width,
stream_cfg_cmd->plane_cfg[i].output_width);
}
+ stream_info->output_format = stream_cfg_cmd->output_format;
stream_info->stream_src = stream_cfg_cmd->stream_src;
stream_info->frame_based = stream_cfg_cmd->frame_base;
return 0;
}
static uint32_t msm_isp_axi_get_plane_size(
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd, int plane_idx)
+ struct msm_vfe_axi_stream *stream_info, int plane_idx)
{
uint32_t size = 0;
- struct msm_vfe_axi_plane_cfg *plane_cfg = stream_cfg_cmd->plane_cfg;
- switch (stream_cfg_cmd->output_format) {
+ struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg;
+ switch (stream_info->output_format) {
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -211,21 +211,17 @@
}
void msm_isp_axi_reserve_wm(struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int i, j;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
-
for (i = 0; i < stream_info->num_planes; i++) {
for (j = 0; j < axi_data->hw_info->num_wm; j++) {
if (!axi_data->free_wm[j]) {
axi_data->free_wm[j] =
- stream_cfg_cmd->axi_stream_handle;
+ stream_info->stream_handle;
axi_data->wm_image_size[j] =
msm_isp_axi_get_plane_size(
- stream_cfg_cmd, i);
+ stream_info, i);
axi_data->num_used_wm++;
break;
}
@@ -246,20 +242,17 @@
void msm_isp_axi_reserve_comp_mask(
struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+ struct msm_vfe_axi_stream *stream_info)
{
int i;
uint8_t comp_mask = 0;
- struct msm_vfe_axi_stream *stream_info =
- &axi_data->stream_info[
- HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
for (i = 0; i < stream_info->num_planes; i++)
comp_mask |= 1 << stream_info->wm[i];
for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) {
if (!axi_data->composite_info[i].stream_handle) {
axi_data->composite_info[i].stream_handle =
- stream_cfg_cmd->axi_stream_handle;
+ stream_info->stream_handle;
axi_data->composite_info[i].
stream_composite_mask = comp_mask;
axi_data->num_used_composite_mask++;
@@ -384,7 +377,7 @@
break;
}
- sof_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+ sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
sof_event.timestamp = ts->event_time;
msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
}
@@ -471,18 +464,18 @@
stream_info = &vfe_dev->axi_data.
stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
- msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_cfg_cmd);
+ msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_info);
if (stream_cfg_cmd->stream_src == CAMIF_RAW ||
stream_cfg_cmd->stream_src == IDEAL_RAW)
vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_io_format(vfe_dev, stream_cfg_cmd);
+ cfg_io_format(vfe_dev, stream_info);
msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
if (stream_info->num_planes > 1) {
msm_isp_axi_reserve_comp_mask(
- &vfe_dev->axi_data, stream_cfg_cmd);
+ &vfe_dev->axi_data, stream_info);
vfe_dev->hw_info->vfe_ops.axi_ops.
cfg_comp_mask(vfe_dev, stream_info);
} else {
@@ -492,10 +485,10 @@
for (i = 0; i < stream_info->num_planes; i++) {
vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_wm_reg(vfe_dev, stream_cfg_cmd, i);
+ cfg_wm_reg(vfe_dev, stream_info, i);
vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_wm_xbar_reg(vfe_dev, stream_cfg_cmd, i);
+ cfg_wm_xbar_reg(vfe_dev, stream_info, i);
}
return rc;
}
@@ -610,7 +603,7 @@
vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
vfe_dev, stream_info->wm[i],
VFE_PONG_FLAG, buf->mapped_info[i].paddr +
- stream_info->plane_offset[i]);
+ stream_info->plane_cfg[i].plane_addr_offset);
stream_info->buf[1] = buf;
}
@@ -657,7 +650,7 @@
vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
vfe_dev, stream_info->wm[i],
pingpong_status, buf->mapped_info[i].paddr +
- stream_info->plane_offset[i]);
+ stream_info->plane_cfg[i].plane_addr_offset);
pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1);
stream_info->buf[pingpong_bit] = buf;
@@ -852,7 +845,7 @@
spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
rc = wait_for_completion_interruptible_timeout(
&vfe_dev->stream_config_complete,
- msecs_to_jiffies(500));
+ msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
if (rc == 0) {
pr_err("%s: wait timeout\n", __func__);
rc = -1;
@@ -976,18 +969,33 @@
enum msm_isp_camif_update_state camif_update)
{
int i, rc = 0;
+ uint8_t wait_for_complete = 0;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
stream_info = &axi_data->stream_info[
HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
+
stream_info->state = STOP_PENDING;
+ if (stream_info->stream_type == BURST_STREAM &&
+ stream_info->runtime_num_burst_capture == 0) {
+ /*Configure AXI writemasters to stop immediately
+ *since for burst case, write masters already skip
+ *all frames.
+ */
+ msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
+ stream_info->state = INACTIVE;
+ } else {
+ wait_for_complete = 1;
+ }
}
- rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
- if (rc < 0) {
- pr_err("%s: wait for config done failed\n", __func__);
- return rc;
+ if (wait_for_complete) {
+ rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
+ if (rc < 0) {
+ pr_err("%s: wait for config done failed\n", __func__);
+ return rc;
+ }
}
msm_isp_update_stream_bandwidth(vfe_dev);
if (camif_update == DISABLE_CAMIF)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index f592a60..3d775f9 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -27,15 +27,11 @@
void msm_isp_axi_reserve_wm(
struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
-
-void msm_isp_axi_reserve_rdi(
- struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
+ struct msm_vfe_axi_stream *stream_info);
void msm_isp_axi_reserve_comp_mask(
struct msm_vfe_axi_shared_data *axi_data,
- struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
+ struct msm_vfe_axi_stream *stream_info);
int msm_isp_axi_check_stream_state(
struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index ce71235..d857a14 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -343,7 +343,7 @@
atomic_set(&vfe_dev->stats_data.stats_update, 2);
rc = wait_for_completion_interruptible_timeout(
&vfe_dev->stats_config_complete,
- msecs_to_jiffies(500));
+ msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
if (rc == 0) {
pr_err("%s: wait timeout\n", __func__);
rc = -1;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index dd8db03..ee205c0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -389,6 +389,11 @@
rc = msm_isp_update_axi_stream(vfe_dev, arg);
mutex_unlock(&vfe_dev->core_mutex);
break;
+ case MSM_SD_SHUTDOWN:
+ while (vfe_dev->vfe_open_cnt != 0)
+ msm_isp_close_node(sd, NULL);
+ break;
+
default:
pr_err("%s: Invalid ISP command\n", __func__);
rc = -EINVAL;
@@ -912,11 +917,10 @@
rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
if (rc <= 0)
- pr_err("%s: halt timeout\n", __func__);
+ pr_err("%s: halt timeout rc=%ld\n", __func__, rc);
vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr);
vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
-
vfe_dev->vfe_open_cnt--;
mutex_unlock(&vfe_dev->core_mutex);
mutex_unlock(&vfe_dev->realtime_mutex);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index a95eda7..dc1bcc3 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -91,7 +91,6 @@
BUG_ON(!ispif);
memset(ispif->sof_count, 0, sizeof(ispif->sof_count));
-
for (i = 0; i < ispif->vfe_info.num_vfe; i++) {
msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT,
@@ -105,9 +104,13 @@
ISPIF_VFE_m_IRQ_CLEAR_1(i));
msm_camera_io_w(0xFFFFFFFF, ispif->base +
ISPIF_VFE_m_IRQ_CLEAR_2(i));
+
msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INPUT_SEL(i));
- msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
- msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
+
+ msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
+ ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
+ msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
+ ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
msm_camera_io_w(0, ispif->base +
ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
@@ -905,6 +908,12 @@
switch (cmd) {
case VIDIOC_MSM_ISPIF_CFG:
return msm_ispif_cmd(sd, arg);
+ case MSM_SD_SHUTDOWN: {
+ struct ispif_device *ispif =
+ (struct ispif_device *)v4l2_get_subdevdata(sd);
+ msm_ispif_release(ispif);
+ return 0;
+ }
default:
pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd);
return -ENOIOCTLCMD;
@@ -986,6 +995,7 @@
ispif->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
ispif->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ISPIF;
ispif->msm_sd.sd.entity.name = pdev->name;
+ ispif->msm_sd.close_seq = MSM_SD_CLOSE_1ST_CATEGORY | 0x1;
rc = msm_sd_register(&ispif->msm_sd);
if (rc) {
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
index c805c3d..3cc21a7 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
@@ -91,4 +91,6 @@
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x1
+#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA
+
#endif /* __MSM_ISPIF_HWREG_V2_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
index 59b9746..509567c 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c
@@ -70,7 +70,7 @@
}
static struct msm_cam_clk_info jpeg_8x_clk_info[] = {
- {"core_clk", 228570000},
+ {"core_clk", JPEG_CLK_RATE},
{"iface_clk", -1},
{"bus_clk0", -1},
{"camss_top_ahb_clk", -1},
@@ -135,8 +135,8 @@
{
.src = MSM_BUS_MASTER_JPEG,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 1027648000,
- .ib = 1105920000,
+ .ab = JPEG_CLK_RATE * 2.5,
+ .ib = JPEG_CLK_RATE * 2.5,
},
};
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
index cd80d2e..a14b8ee 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
#include <linux/iommu.h>
#include <mach/iommu.h>
#include "msm_jpeg_sync.h"
+#define JPEG_CLK_RATE 266670000
void msm_jpeg_platform_p2v(struct msm_jpeg_device *pgmn_dev, struct file *file,
struct ion_handle **ionhandle, int domain_num);
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index be9f613..8a691c5 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -31,6 +31,7 @@
#include "msm_sd.h"
static struct v4l2_device *msm_v4l2_dev;
+static struct list_head ordered_sd_list;
static struct msm_queue_head *msm_session_q;
@@ -301,6 +302,20 @@
return rc;
}
+static void msm_add_sd_in_position(struct msm_sd_subdev *msm_subdev,
+ struct list_head *sd_list)
+{
+ struct msm_sd_subdev *temp_sd;
+
+ list_for_each_entry(temp_sd, sd_list, list) {
+ if (msm_subdev->close_seq < temp_sd->close_seq) {
+ list_add_tail(&msm_subdev->list, &temp_sd->list);
+ return;
+ }
+ }
+ list_add_tail(&msm_subdev->list, sd_list);
+}
+
int msm_sd_register(struct msm_sd_subdev *msm_subdev)
{
if (WARN_ON(!msm_subdev))
@@ -309,6 +324,7 @@
if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev))
return -EIO;
+ msm_add_sd_in_position(msm_subdev, &ordered_sd_list);
return __msm_sd_register_subdev(&msm_subdev->sd);
}
@@ -401,62 +417,35 @@
spin_unlock_irqrestore(&(session->command_ack_q.lock), flags);
}
-static inline int __msm_v4l2_subdev_shutdown(struct v4l2_subdev *sd)
-{
- return 0;
-}
-
-static void msm_sd_try_shutdown(void)
-{
- unsigned long flags;
- struct v4l2_subdev *sd;
-
- /* release all subdev's resource */
- spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
- if (!list_empty(&msm_v4l2_dev->subdevs)) {
- list_for_each_entry(sd, &msm_v4l2_dev->subdevs, list)
- __msm_v4l2_subdev_shutdown(sd);
- }
- spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
-}
-
-static inline int __msm_sd_close_session_streams(struct v4l2_subdev *sd,
+static inline int __msm_sd_close_subdevs(struct msm_sd_subdev *msm_sd,
struct msm_sd_close_ioctl *sd_close)
{
+ struct v4l2_subdev *sd;
+ sd = &msm_sd->sd;
+ pr_debug("%s: Shutting down subdev %s", __func__, sd->name);
+
+ v4l2_subdev_call(sd, core, ioctl, MSM_SD_SHUTDOWN, sd_close);
+ v4l2_subdev_call(sd, core, s_power, 0);
+
return 0;
}
static inline int __msm_destroy_session_streams(void *d1, void *d2)
{
struct msm_stream *stream = d1;
- struct msm_sd_close_ioctl *sd_close = d2;
- struct v4l2_subdev *sd;
- unsigned long flags;
- sd_close->stream = stream->stream_id;
-
- spin_lock_irqsave(&msm_v4l2_dev->lock, flags);
- if (!list_empty(&msm_v4l2_dev->subdevs))
- list_for_each_entry(sd, &msm_v4l2_dev->subdevs, list)
- __msm_sd_close_session_streams(sd, sd_close);
- spin_unlock_irqrestore(&msm_v4l2_dev->lock, flags);
INIT_LIST_HEAD(&stream->queued_list);
return 0;
}
static void msm_destroy_session_streams(struct msm_session *session)
{
- struct msm_sd_close_ioctl sd_close;
- /* to ensure error handling purpose, it needs to detach all subdevs
- * which are being connected to streams */
if (!session)
return;
- sd_close.session = session->session_id;
-
msm_queue_traverse_action(&session->stream_q, struct msm_stream, list,
- __msm_destroy_session_streams, &sd_close);
+ __msm_destroy_session_streams, NULL);
msm_queue_drain(&session->stream_q, struct msm_stream, list);
}
@@ -694,16 +683,13 @@
struct msm_v4l2_event_data *event_data =
(struct msm_v4l2_event_data *)&event.u.data[0];
struct msm_session *session = d1;
- mutex_lock(&session->lock);
+
event.type = MSM_CAMERA_V4L2_EVENT_TYPE;
event.id = MSM_CAMERA_MSM_NOTIFY;
event_data->command = MSM_CAMERA_PRIV_SHUTDOWN;
v4l2_event_queue(session->event_q.vdev, &event);
- msm_destroy_session_streams(session);
- msm_remove_session_cmd_ack_q(session);
- mutex_unlock(&session->lock);
return 0;
}
@@ -712,22 +698,23 @@
int rc = 0;
unsigned long flags;
struct msm_video_device *pvdev = video_drvdata(filep);
+ struct msm_sd_close_ioctl sd_close;
+ struct msm_sd_subdev *msm_sd;
- /* 1st thing 1st, send v4l2_event to HAL immediately,
- * to ensure error handling purpose, it needs to detach all subdevs
- * which are being connected to streams */
+ /*stop all hardware blocks immediately*/
+ if (!list_empty(&msm_v4l2_dev->subdevs))
+ list_for_each_entry(msm_sd, &ordered_sd_list, list)
+ __msm_sd_close_subdevs(msm_sd, &sd_close);
+
+ /* send v4l2_event to HAL next*/
msm_queue_traverse_action(msm_session_q, struct msm_session, list,
__msm_close_destry_session_notify_apps, NULL);
- msm_queue_drain(msm_session_q, struct msm_session, list);
-
spin_lock_irqsave(&msm_eventq_lock, flags);
msm_eventq = NULL;
spin_unlock_irqrestore(&msm_eventq_lock, flags);
v4l2_fh_release(filep);
- msm_sd_try_shutdown();
-
spin_lock_irqsave(&msm_pid_lock, flags);
put_pid(msm_pid);
msm_pid = NULL;
@@ -754,7 +741,6 @@
int rc;
unsigned long flags;
struct msm_video_device *pvdev = video_drvdata(filep);
-
BUG_ON(!pvdev);
/* !!! only ONE open is allowed !!! */
@@ -990,7 +976,7 @@
msm_init_queue(msm_session_q);
spin_lock_init(&msm_eventq_lock);
spin_lock_init(&msm_pid_lock);
-
+ INIT_LIST_HEAD(&ordered_sd_list);
goto probe_end;
v4l2_fail:
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index b0ff832..895f452 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -161,6 +161,7 @@
msm_buf_mngr_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
msm_buf_mngr_dev->subdev.sd.entity.group_id =
MSM_CAMERA_SUBDEV_BUF_MNGR;
+ msm_buf_mngr_dev->subdev.close_seq = MSM_SD_CLOSE_4TH_CATEGORY;
rc = msm_sd_register(&msm_buf_mngr_dev->subdev);
if (rc != 0) {
pr_err("%s: msm_sd_register error = %d\n", __func__, rc);
diff --git a/drivers/media/platform/msm/camera_v2/msm_sd.h b/drivers/media/platform/msm/camera_v2/msm_sd.h
index 958e030..7c1519d 100644
--- a/drivers/media/platform/msm/camera_v2/msm_sd.h
+++ b/drivers/media/platform/msm/camera_v2/msm_sd.h
@@ -50,10 +50,12 @@
#define MSM_SD_CLOSE_1ST_CATEGORY 0x00010000
#define MSM_SD_CLOSE_2ND_CATEGORY 0x00020000
#define MSM_SD_CLOSE_3RD_CATEGORY 0x00030000
+#define MSM_SD_CLOSE_4TH_CATEGORY 0x00040000
struct msm_sd_subdev {
struct v4l2_subdev sd;
int close_seq;
+ struct list_head list;
};
struct msm_sd_req_sd {
diff --git a/drivers/media/platform/msm/camera_v2/pproc/Makefile b/drivers/media/platform/msm/camera_v2/pproc/Makefile
index 854e4e7..4193adc 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/Makefile
+++ b/drivers/media/platform/msm/camera_v2/pproc/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_MSMB_CAMERA) += cpp/
+obj-$(CONFIG_MSMB_CAMERA) += vpe/
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 5a174f5..4dd3f3d 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -43,6 +43,9 @@
#define CONFIG_MSM_CPP_DBG 0
+/* dump the frame command before writing to the hardware */
+#define MSM_CPP_DUMP_FRM_CMD 0
+
#if CONFIG_MSM_CPP_DBG
#define CPP_DBG(fmt, args...) pr_err(fmt, ##args)
#else
@@ -208,7 +211,6 @@
pr_err("ION import failed\n");
goto QUEUE_BUFF_ERROR1;
}
-
rc = ion_map_iommu(cpp_dev->client, buff->map_info.ion_handle,
cpp_dev->domain_num, 0, SZ_4K, 0,
(unsigned long *)&buff->map_info.phy_addr,
@@ -237,6 +239,7 @@
static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev,
struct msm_cpp_buffer_map_list_t *buff)
{
+
ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle,
cpp_dev->domain_num, 0);
ion_free(cpp_dev->client, buff->map_info.ion_handle);
@@ -390,6 +393,8 @@
pr_err("Queue not free sessionid: %d, streamid: %d\n",
cpp_dev->buff_queue[i].session_id,
cpp_dev->buff_queue[i].stream_id);
+ msm_cpp_dequeue_buff_info_list
+ (cpp_dev, &cpp_dev->buff_queue[i]);
msm_cpp_free_buff_queue_entry(cpp_dev,
cpp_dev->buff_queue[i].session_id,
cpp_dev->buff_queue[i].stream_id);
@@ -821,9 +826,16 @@
{
uint32_t i;
struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
+
mutex_lock(&cpp_dev->mutex);
+
+ if (cpp_dev->cpp_open_cnt == 0) {
+ mutex_unlock(&cpp_dev->mutex);
+ return 0;
+ }
+
for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
- if (cpp_dev->cpp_subscribe_list[i].vfh == &fh->vfh) {
+ if (cpp_dev->cpp_subscribe_list[i].active == 1) {
cpp_dev->cpp_subscribe_list[i].active = 0;
cpp_dev->cpp_subscribe_list[i].vfh = NULL;
break;
@@ -835,7 +847,6 @@
return -ENODEV;
}
- CPP_DBG("close %d %p\n", i, &fh->vfh);
cpp_dev->cpp_open_cnt--;
if (cpp_dev->cpp_open_cnt == 0) {
msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
@@ -843,6 +854,7 @@
cpp_release_hardware(cpp_dev);
cpp_dev->state = CPP_STATE_OFF;
}
+
mutex_unlock(&cpp_dev->mutex);
return 0;
}
@@ -888,8 +900,7 @@
event_qcmd->command = processed_frame;
CPP_DBG("fid %d\n", processed_frame->frame_id);
msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata);
-
- if (!processed_frame->output_buffer_info.processed_divert) {
+ if (!processed_frame->output_buffer_info[0].processed_divert) {
memset(&buff_mgr_info, 0 ,
sizeof(struct msm_buf_mngr_info));
buff_mgr_info.session_id =
@@ -899,7 +910,7 @@
buff_mgr_info.frame_id = processed_frame->frame_id;
buff_mgr_info.timestamp = processed_frame->timestamp;
buff_mgr_info.index =
- processed_frame->output_buffer_info.index;
+ processed_frame->output_buffer_info[0].index;
rc = msm_cpp_buffer_ops(cpp_dev,
VIDIOC_MSM_BUF_MNGR_BUF_DONE,
&buff_mgr_info);
@@ -908,6 +919,28 @@
rc = -EINVAL;
}
}
+
+ if (processed_frame->duplicate_output &&
+ !processed_frame->
+ output_buffer_info[1].processed_divert) {
+ memset(&buff_mgr_info, 0 ,
+ sizeof(struct msm_buf_mngr_info));
+ buff_mgr_info.session_id =
+ ((processed_frame->duplicate_identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id =
+ (processed_frame->duplicate_identity & 0xFFFF);
+ buff_mgr_info.frame_id = processed_frame->frame_id;
+ buff_mgr_info.timestamp = processed_frame->timestamp;
+ buff_mgr_info.index =
+ processed_frame->output_buffer_info[1].index;
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("error putting buffer\n");
+ rc = -EINVAL;
+ }
+ }
v4l2_evt.id = processed_frame->inst_id;
v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);
@@ -915,6 +948,23 @@
return rc;
}
+#if MSM_CPP_DUMP_FRM_CMD
+static int msm_cpp_dump_frame_cmd(uint32_t *cmd, int32_t len)
+{
+ int i;
+ pr_err("%s: -------- cpp frame cmd msg start --------", __func__);
+ for (i = 0; i < len; i++)
+ pr_err("%s: msg[%03d] = 0x%08x", __func__, i, cmd[i]);
+ pr_err("%s: --------- cpp frame cmd msg end ---------", __func__);
+ return 0;
+}
+#else
+static int msm_cpp_dump_frame_cmd(uint32_t *cmd, int32_t len)
+{
+ return 0;
+}
+#endif
+
static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev,
struct msm_queue_cmd *frame_qcmd)
{
@@ -927,6 +977,8 @@
msm_enqueue(&cpp_dev->processing_q,
&frame_qcmd->list_frame);
msm_cpp_write(0x6, cpp_dev->base);
+ msm_cpp_dump_frame_cmd(process_frame->cpp_cmd_msg,
+ process_frame->msg_len);
for (i = 0; i < process_frame->msg_len; i++)
msm_cpp_write(process_frame->cpp_cmd_msg[i],
cpp_dev->base);
@@ -951,7 +1003,7 @@
struct msm_cpp_frame_info_t *new_frame =
kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL);
uint32_t *cpp_frame_msg;
- unsigned long in_phyaddr, out_phyaddr;
+ unsigned long in_phyaddr, out_phyaddr0, out_phyaddr1;
uint16_t num_stripes = 0;
struct msm_buf_mngr_info buff_mgr_info;
struct msm_cpp_frame_info_t *u_frame_info =
@@ -1001,7 +1053,7 @@
goto ERROR2;
}
- memset(&new_frame->output_buffer_info, 0,
+ memset(&new_frame->output_buffer_info[0], 0,
sizeof(struct msm_cpp_buffer_info_t));
memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
@@ -1013,17 +1065,49 @@
pr_debug("error getting buffer rc:%d\n", rc);
goto ERROR2;
}
-
- new_frame->output_buffer_info.index = buff_mgr_info.index;
- out_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,
- &new_frame->output_buffer_info,
+ new_frame->output_buffer_info[0].index = buff_mgr_info.index;
+ out_phyaddr0 = msm_cpp_fetch_buffer_info(cpp_dev,
+ &new_frame->output_buffer_info[0],
((new_frame->identity >> 16) & 0xFFFF),
(new_frame->identity & 0xFFFF));
- if (!out_phyaddr) {
+ if (!out_phyaddr0) {
pr_err("error gettting output physical address\n");
rc = -EINVAL;
goto ERROR3;
}
+ out_phyaddr1 = out_phyaddr0;
+
+ /* get buffer for duplicate output */
+ if (new_frame->duplicate_output) {
+ CPP_DBG("duplication enabled, dup_id=0x%x",
+ new_frame->duplicate_identity);
+ memset(&new_frame->output_buffer_info[1], 0,
+ sizeof(struct msm_cpp_buffer_info_t));
+ memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+ buff_mgr_info.session_id =
+ ((new_frame->duplicate_identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id =
+ (new_frame->duplicate_identity & 0xFFFF);
+ rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
+ &buff_mgr_info);
+ if (rc < 0) {
+ rc = -EAGAIN;
+ pr_err("error getting buffer rc:%d\n", rc);
+ goto ERROR2;
+ }
+ new_frame->output_buffer_info[1].index = buff_mgr_info.index;
+ out_phyaddr1 = msm_cpp_fetch_buffer_info(cpp_dev,
+ &new_frame->output_buffer_info[1],
+ ((new_frame->duplicate_identity >> 16) & 0xFFFF),
+ (new_frame->duplicate_identity & 0xFFFF));
+ if (!out_phyaddr1) {
+ pr_err("error gettting output physical address\n");
+ rc = -EINVAL;
+ goto ERROR3;
+ }
+ /* set duplicate enable bit */
+ cpp_frame_msg[5] |= 0x1;
+ }
num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) +
((cpp_frame_msg[12] >> 10) & 0x3FF) +
@@ -1031,10 +1115,10 @@
for (i = 0; i < num_stripes; i++) {
cpp_frame_msg[133 + i * 27] += (uint32_t) in_phyaddr;
- cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr;
- cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr;
- cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr;
- cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr;
+ cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr0;
+ cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr1;
+ cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr0;
+ cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr1;
}
frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
@@ -1245,6 +1329,13 @@
kfree(event_qcmd);
break;
}
+ case MSM_SD_SHUTDOWN: {
+ mutex_unlock(&cpp_dev->mutex);
+ while (cpp_dev->cpp_open_cnt != 0)
+ cpp_close_node(sd, NULL);
+ rc = 0;
+ break;
+ }
}
mutex_unlock(&cpp_dev->mutex);
CPP_DBG("X\n");
@@ -1446,6 +1537,7 @@
cpp_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
cpp_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CPP;
cpp_dev->msm_sd.sd.entity.name = pdev->name;
+ cpp_dev->msm_sd.close_seq = MSM_SD_CLOSE_3RD_CATEGORY;
msm_sd_register(&cpp_dev->msm_sd);
msm_cpp_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner;
msm_cpp_v4l2_subdev_fops.open = v4l2_subdev_fops.open;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile b/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile
new file mode 100644
index 0000000..65a7e34
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSMB_CAMERA) += msm_vpe.o
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
new file mode 100644
index 0000000..d53d766
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -0,0 +1,1643 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "MSM-VPE %s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/iommu.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/media-entity.h>
+#include <media/msmb_pproc.h>
+#include <media/msmb_generic_buf_mgr.h>
+#include "msm_vpe.h"
+#include "msm_camera_io_util.h"
+
+#define MSM_VPE_IDENT_TO_SESSION_ID(identity) ((identity >> 16) & 0xFFFF)
+#define MSM_VPE_IDENT_TO_STREAM_ID(identity) (identity & 0xFFFF)
+
+#define MSM_VPE_DRV_NAME "msm_vpe"
+
+#define MSM_VPE_MAX_BUFF_QUEUE 16
+
+#define CONFIG_MSM_VPE_DBG 0
+
+#if CONFIG_MSM_VPE_DBG
+#define VPE_DBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define VPE_DBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+static void vpe_mem_dump(const char * const name, const void * const addr,
+ int size)
+{
+ char line_str[128], *p_str;
+ int i;
+ u32 *p = (u32 *) addr;
+ u32 data;
+ VPE_DBG("%s: (%s) %p %d\n", __func__, name, addr, size);
+ line_str[0] = '\0';
+ p_str = line_str;
+ for (i = 0; i < size/4; i++) {
+ if (i % 4 == 0) {
+ snprintf(p_str, 12, "%08x: ", (u32) p);
+ p_str += 10;
+ }
+ data = *p++;
+ snprintf(p_str, 12, "%08x ", data);
+ p_str += 9;
+ if ((i + 1) % 4 == 0) {
+ VPE_DBG("%s\n", line_str);
+ line_str[0] = '\0';
+ p_str = line_str;
+ }
+ }
+ if (line_str[0] != '\0')
+ VPE_DBG("%s\n", line_str);
+}
+
+static inline long long vpe_do_div(long long num, long long den)
+{
+ do_div(num, den);
+ return num;
+}
+
+#define msm_dequeue(queue, member) ({ \
+ unsigned long flags; \
+ struct msm_device_queue *__q = (queue); \
+ struct msm_queue_cmd *qcmd = 0; \
+ spin_lock_irqsave(&__q->lock, flags); \
+ if (!list_empty(&__q->list)) { \
+ __q->len--; \
+ qcmd = list_first_entry(&__q->list, \
+ struct msm_queue_cmd, \
+ member); \
+ list_del_init(&qcmd->member); \
+ } \
+ spin_unlock_irqrestore(&__q->lock, flags); \
+ qcmd; \
+ })
+
+static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+{
+ spin_lock_init(&queue->lock);
+ queue->len = 0;
+ queue->max = 0;
+ queue->name = name;
+ INIT_LIST_HEAD(&queue->list);
+ init_waitqueue_head(&queue->wait);
+}
+
+static struct msm_cam_clk_info vpe_clk_info[] = {
+ {"vpe_clk", 160000000},
+ {"vpe_pclk", -1},
+};
+
+static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev);
+
+static void msm_enqueue(struct msm_device_queue *queue,
+ struct list_head *entry)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&queue->lock, flags);
+ queue->len++;
+ if (queue->len > queue->max) {
+ queue->max = queue->len;
+ pr_debug("queue %s new max is %d\n", queue->name, queue->max);
+ }
+ list_add_tail(entry, &queue->list);
+ wake_up(&queue->wait);
+ VPE_DBG("woke up %s\n", queue->name);
+ spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static struct msm_vpe_buff_queue_info_t *msm_vpe_get_buff_queue_entry(
+ struct vpe_device *vpe_dev, uint32_t session_id, uint32_t stream_id)
+{
+ uint32_t i = 0;
+ struct msm_vpe_buff_queue_info_t *buff_queue_info = NULL;
+
+ for (i = 0; i < vpe_dev->num_buffq; i++) {
+ if ((vpe_dev->buff_queue[i].used == 1) &&
+ (vpe_dev->buff_queue[i].session_id == session_id) &&
+ (vpe_dev->buff_queue[i].stream_id == stream_id)) {
+ buff_queue_info = &vpe_dev->buff_queue[i];
+ break;
+ }
+ }
+
+ if (buff_queue_info == NULL) {
+ pr_err("error buffer queue entry for sess:%d strm:%d not found\n",
+ session_id, stream_id);
+ }
+ return buff_queue_info;
+}
+
+static unsigned long msm_vpe_get_phy_addr(struct vpe_device *vpe_dev,
+ struct msm_vpe_buff_queue_info_t *buff_queue_info, uint32_t buff_index,
+ uint8_t native_buff)
+{
+ unsigned long phy_add = 0;
+ struct list_head *buff_head;
+ struct msm_vpe_buffer_map_list_t *buff, *save;
+
+ if (native_buff)
+ buff_head = &buff_queue_info->native_buff_head;
+ else
+ buff_head = &buff_queue_info->vb2_buff_head;
+
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ if (buff->map_info.buff_info.index == buff_index) {
+ phy_add = buff->map_info.phy_addr;
+ break;
+ }
+ }
+
+ return phy_add;
+}
+
+static unsigned long msm_vpe_queue_buffer_info(struct vpe_device *vpe_dev,
+ struct msm_vpe_buff_queue_info_t *buff_queue,
+ struct msm_vpe_buffer_info_t *buffer_info)
+{
+ struct list_head *buff_head;
+ struct msm_vpe_buffer_map_list_t *buff, *save;
+ int rc = 0;
+
+ if (buffer_info->native_buff)
+ buff_head = &buff_queue->native_buff_head;
+ else
+ buff_head = &buff_queue->vb2_buff_head;
+
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ if (buff->map_info.buff_info.index == buffer_info->index) {
+ pr_err("error buffer index already queued\n");
+ return -EINVAL;
+ }
+ }
+
+ buff = kzalloc(
+ sizeof(struct msm_vpe_buffer_map_list_t), GFP_KERNEL);
+ if (!buff) {
+ pr_err("error allocating memory\n");
+ return -EINVAL;
+ }
+
+ buff->map_info.buff_info = *buffer_info;
+ buff->map_info.ion_handle = ion_import_dma_buf(vpe_dev->client,
+ buffer_info->fd);
+ if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) {
+ pr_err("ION import failed\n");
+ goto queue_buff_error1;
+ }
+
+ rc = ion_map_iommu(vpe_dev->client, buff->map_info.ion_handle,
+ vpe_dev->domain_num, 0, SZ_4K, 0,
+ (unsigned long *)&buff->map_info.phy_addr,
+ &buff->map_info.len, 0, 0);
+ if (rc < 0) {
+ pr_err("ION mmap failed\n");
+ goto queue_buff_error2;
+ }
+
+ INIT_LIST_HEAD(&buff->entry);
+ list_add_tail(&buff->entry, buff_head);
+
+ return buff->map_info.phy_addr;
+
+queue_buff_error2:
+ ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle,
+ vpe_dev->domain_num, 0);
+queue_buff_error1:
+ ion_free(vpe_dev->client, buff->map_info.ion_handle);
+ buff->map_info.ion_handle = NULL;
+ kzfree(buff);
+
+ return 0;
+}
+
+static void msm_vpe_dequeue_buffer_info(struct vpe_device *vpe_dev,
+ struct msm_vpe_buffer_map_list_t *buff)
+{
+ ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle,
+ vpe_dev->domain_num, 0);
+ ion_free(vpe_dev->client, buff->map_info.ion_handle);
+ buff->map_info.ion_handle = NULL;
+
+ list_del_init(&buff->entry);
+ kzfree(buff);
+
+ return;
+}
+
+static unsigned long msm_vpe_fetch_buffer_info(struct vpe_device *vpe_dev,
+ struct msm_vpe_buffer_info_t *buffer_info, uint32_t session_id,
+ uint32_t stream_id)
+{
+ unsigned long phy_addr = 0;
+ struct msm_vpe_buff_queue_info_t *buff_queue_info;
+ uint8_t native_buff = buffer_info->native_buff;
+
+ buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id,
+ stream_id);
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+ session_id, stream_id);
+ return phy_addr;
+ }
+
+ phy_addr = msm_vpe_get_phy_addr(vpe_dev, buff_queue_info,
+ buffer_info->index, native_buff);
+ if ((phy_addr == 0) && (native_buff)) {
+ phy_addr = msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info,
+ buffer_info);
+ }
+ return phy_addr;
+}
+
+static int32_t msm_vpe_enqueue_buff_info_list(struct vpe_device *vpe_dev,
+ struct msm_vpe_stream_buff_info_t *stream_buff_info)
+{
+ uint32_t j;
+ struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+ buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev,
+ (stream_buff_info->identity >> 16) & 0xFFFF,
+ stream_buff_info->identity & 0xFFFF);
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+ (stream_buff_info->identity >> 16) & 0xFFFF,
+ stream_buff_info->identity & 0xFFFF);
+ return -EINVAL;
+ }
+
+ for (j = 0; j < stream_buff_info->num_buffs; j++) {
+ msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info,
+ &stream_buff_info->buffer_info[j]);
+ }
+ return 0;
+}
+
+static int32_t msm_vpe_dequeue_buff_info_list(struct vpe_device *vpe_dev,
+ struct msm_vpe_buff_queue_info_t *buff_queue_info)
+{
+ struct msm_vpe_buffer_map_list_t *buff, *save;
+ struct list_head *buff_head;
+
+ buff_head = &buff_queue_info->native_buff_head;
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ msm_vpe_dequeue_buffer_info(vpe_dev, buff);
+ }
+
+ buff_head = &buff_queue_info->vb2_buff_head;
+ list_for_each_entry_safe(buff, save, buff_head, entry) {
+ msm_vpe_dequeue_buffer_info(vpe_dev, buff);
+ }
+
+ return 0;
+}
+
+static int32_t msm_vpe_add_buff_queue_entry(struct vpe_device *vpe_dev,
+ uint16_t session_id, uint16_t stream_id)
+{
+ uint32_t i;
+ struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+ for (i = 0; i < vpe_dev->num_buffq; i++) {
+ if (vpe_dev->buff_queue[i].used == 0) {
+ buff_queue_info = &vpe_dev->buff_queue[i];
+ buff_queue_info->used = 1;
+ buff_queue_info->session_id = session_id;
+ buff_queue_info->stream_id = stream_id;
+ INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+ INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+ return 0;
+ }
+ }
+ pr_err("buffer queue full. error for sessionid: %d streamid: %d\n",
+ session_id, stream_id);
+ return -EINVAL;
+}
+
+static int32_t msm_vpe_free_buff_queue_entry(struct vpe_device *vpe_dev,
+ uint32_t session_id, uint32_t stream_id)
+{
+ struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+ buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id,
+ stream_id);
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+ session_id, stream_id);
+ return -EINVAL;
+ }
+
+ buff_queue_info->used = 0;
+ buff_queue_info->session_id = 0;
+ buff_queue_info->stream_id = 0;
+ INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+ INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+ return 0;
+}
+
+static int32_t msm_vpe_create_buff_queue(struct vpe_device *vpe_dev,
+ uint32_t num_buffq)
+{
+ struct msm_vpe_buff_queue_info_t *buff_queue;
+ buff_queue = kzalloc(
+ sizeof(struct msm_vpe_buff_queue_info_t) * num_buffq,
+ GFP_KERNEL);
+ if (!buff_queue) {
+ pr_err("Buff queue allocation failure\n");
+ return -ENOMEM;
+ }
+
+ if (vpe_dev->buff_queue) {
+ pr_err("Buff queue not empty\n");
+ kzfree(buff_queue);
+ return -EINVAL;
+ } else {
+ vpe_dev->buff_queue = buff_queue;
+ vpe_dev->num_buffq = num_buffq;
+ }
+ return 0;
+}
+
+static void msm_vpe_delete_buff_queue(struct vpe_device *vpe_dev)
+{
+ uint32_t i;
+
+ for (i = 0; i < vpe_dev->num_buffq; i++) {
+ if (vpe_dev->buff_queue[i].used == 1) {
+ pr_err("Queue not free sessionid: %d, streamid: %d\n",
+ vpe_dev->buff_queue[i].session_id,
+ vpe_dev->buff_queue[i].stream_id);
+ msm_vpe_free_buff_queue_entry(vpe_dev,
+ vpe_dev->buff_queue[i].session_id,
+ vpe_dev->buff_queue[i].stream_id);
+ }
+ }
+ kzfree(vpe_dev->buff_queue);
+ vpe_dev->buff_queue = NULL;
+ vpe_dev->num_buffq = 0;
+ return;
+}
+
+void vpe_release_ion_client(struct kref *ref)
+{
+ struct vpe_device *vpe_dev = container_of(ref,
+ struct vpe_device, refcount);
+ ion_client_destroy(vpe_dev->client);
+}
+
+static int vpe_init_mem(struct vpe_device *vpe_dev)
+{
+ kref_init(&vpe_dev->refcount);
+ kref_get(&vpe_dev->refcount);
+ vpe_dev->client = msm_ion_client_create(-1, "vpe");
+
+ if (!vpe_dev->client) {
+ pr_err("couldn't create ion client\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void vpe_deinit_mem(struct vpe_device *vpe_dev)
+{
+ kref_put(&vpe_dev->refcount, vpe_release_ion_client);
+}
+
+static irqreturn_t msm_vpe_irq(int irq_num, void *data)
+{
+ unsigned long flags;
+ uint32_t irq_status;
+ struct msm_vpe_tasklet_queue_cmd *queue_cmd;
+ struct vpe_device *vpe_dev = (struct vpe_device *) data;
+
+ irq_status = msm_camera_io_r_mb(vpe_dev->base +
+ VPE_INTR_STATUS_OFFSET);
+
+ spin_lock_irqsave(&vpe_dev->tasklet_lock, flags);
+ queue_cmd = &vpe_dev->tasklet_queue_cmd[vpe_dev->taskletq_idx];
+ if (queue_cmd->cmd_used) {
+ VPE_DBG("%s: vpe tasklet queue overflow\n", __func__);
+ list_del(&queue_cmd->list);
+ } else {
+ atomic_add(1, &vpe_dev->irq_cnt);
+ }
+ queue_cmd->irq_status = irq_status;
+
+ queue_cmd->cmd_used = 1;
+ vpe_dev->taskletq_idx =
+ (vpe_dev->taskletq_idx + 1) % MSM_VPE_TASKLETQ_SIZE;
+ list_add_tail(&queue_cmd->list, &vpe_dev->tasklet_q);
+ spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+
+ tasklet_schedule(&vpe_dev->vpe_tasklet);
+
+ msm_camera_io_w_mb(irq_status, vpe_dev->base + VPE_INTR_CLEAR_OFFSET);
+ msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+ VPE_DBG("%s: irq_status=0x%x.\n", __func__, irq_status);
+
+ return IRQ_HANDLED;
+}
+
+static void msm_vpe_do_tasklet(unsigned long data)
+{
+ unsigned long flags;
+ struct vpe_device *vpe_dev = (struct vpe_device *)data;
+ struct msm_vpe_tasklet_queue_cmd *queue_cmd;
+
+ while (atomic_read(&vpe_dev->irq_cnt)) {
+ spin_lock_irqsave(&vpe_dev->tasklet_lock, flags);
+ queue_cmd = list_first_entry(&vpe_dev->tasklet_q,
+ struct msm_vpe_tasklet_queue_cmd, list);
+ if (!queue_cmd) {
+ atomic_set(&vpe_dev->irq_cnt, 0);
+ spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+ return;
+ }
+ atomic_sub(1, &vpe_dev->irq_cnt);
+ list_del(&queue_cmd->list);
+ queue_cmd->cmd_used = 0;
+
+ spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+
+ VPE_DBG("Frame done!!\n");
+ msm_vpe_notify_frame_done(vpe_dev);
+ }
+}
+
+static int vpe_init_hardware(struct vpe_device *vpe_dev)
+{
+ int rc = 0;
+
+ if (vpe_dev->fs_vpe == NULL) {
+ vpe_dev->fs_vpe =
+ regulator_get(&vpe_dev->pdev->dev, "vdd");
+ if (IS_ERR(vpe_dev->fs_vpe)) {
+ pr_err("Regulator vpe vdd get failed %ld\n",
+ PTR_ERR(vpe_dev->fs_vpe));
+ vpe_dev->fs_vpe = NULL;
+ rc = -ENODEV;
+ goto fail;
+ } else if (regulator_enable(vpe_dev->fs_vpe)) {
+ pr_err("Regulator vpe vdd enable failed\n");
+ regulator_put(vpe_dev->fs_vpe);
+ vpe_dev->fs_vpe = NULL;
+ rc = -ENODEV;
+ goto fail;
+ }
+ }
+
+ rc = msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info,
+ vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 1);
+ if (rc < 0) {
+ rc = -ENODEV;
+ pr_err("clk enable failed\n");
+ goto disable_and_put_regulator;
+ }
+
+ vpe_dev->base = ioremap(vpe_dev->mem->start,
+ resource_size(vpe_dev->mem));
+ if (!vpe_dev->base) {
+ rc = -ENOMEM;
+ pr_err("ioremap failed\n");
+ goto disable_and_put_regulator;
+ }
+
+ if (vpe_dev->state != VPE_STATE_BOOT) {
+ rc = request_irq(vpe_dev->irq->start, msm_vpe_irq,
+ IRQF_TRIGGER_RISING,
+ "vpe", vpe_dev);
+ if (rc < 0) {
+ pr_err("irq request fail! start=%u\n",
+ vpe_dev->irq->start);
+ rc = -EBUSY;
+ goto unmap_base;
+ } else {
+ VPE_DBG("Got irq! %d\n", vpe_dev->irq->start);
+ }
+ } else {
+ VPE_DBG("Skip requesting the irq since device is booting\n");
+ }
+ vpe_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev();
+
+ msm_vpe_create_buff_queue(vpe_dev, MSM_VPE_MAX_BUFF_QUEUE);
+ return rc;
+
+unmap_base:
+ iounmap(vpe_dev->base);
+disable_and_put_regulator:
+ regulator_disable(vpe_dev->fs_vpe);
+ regulator_put(vpe_dev->fs_vpe);
+fail:
+ return rc;
+}
+
+static int vpe_release_hardware(struct vpe_device *vpe_dev)
+{
+ if (vpe_dev->state != VPE_STATE_BOOT) {
+ free_irq(vpe_dev->irq->start, vpe_dev);
+ tasklet_kill(&vpe_dev->vpe_tasklet);
+ atomic_set(&vpe_dev->irq_cnt, 0);
+ }
+
+ msm_vpe_delete_buff_queue(vpe_dev);
+ iounmap(vpe_dev->base);
+ msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info,
+ vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0);
+ return 0;
+}
+
+static int vpe_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ int rc = 0;
+ uint32_t i;
+ struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+
+ mutex_lock(&vpe_dev->mutex);
+ if (vpe_dev->vpe_open_cnt == MAX_ACTIVE_VPE_INSTANCE) {
+ pr_err("No free VPE instance\n");
+ rc = -ENODEV;
+ goto err_mutex_unlock;
+ }
+
+ for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+ if (vpe_dev->vpe_subscribe_list[i].active == 0) {
+ vpe_dev->vpe_subscribe_list[i].active = 1;
+ vpe_dev->vpe_subscribe_list[i].vfh = &fh->vfh;
+ break;
+ }
+ }
+ if (i == MAX_ACTIVE_VPE_INSTANCE) {
+ pr_err("No free instance\n");
+ rc = -ENODEV;
+ goto err_mutex_unlock;
+ }
+
+ VPE_DBG("open %d %p\n", i, &fh->vfh);
+ vpe_dev->vpe_open_cnt++;
+ if (vpe_dev->vpe_open_cnt == 1) {
+ rc = vpe_init_hardware(vpe_dev);
+ if (rc < 0) {
+ pr_err("%s: Couldn't init vpe hardware\n", __func__);
+ vpe_dev->vpe_open_cnt--;
+ rc = -ENODEV;
+ goto err_fixup_sub_list;
+ }
+ rc = vpe_init_mem(vpe_dev);
+ if (rc < 0) {
+ pr_err("%s: Couldn't init mem\n", __func__);
+ vpe_dev->vpe_open_cnt--;
+ rc = -ENODEV;
+ goto err_release_hardware;
+ }
+ vpe_dev->state = VPE_STATE_IDLE;
+ }
+ mutex_unlock(&vpe_dev->mutex);
+
+ return rc;
+
+err_release_hardware:
+ vpe_release_hardware(vpe_dev);
+err_fixup_sub_list:
+ for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+ if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) {
+ vpe_dev->vpe_subscribe_list[i].active = 0;
+ vpe_dev->vpe_subscribe_list[i].vfh = NULL;
+ break;
+ }
+ }
+err_mutex_unlock:
+ mutex_unlock(&vpe_dev->mutex);
+ return rc;
+}
+
+static int vpe_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ uint32_t i;
+ struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+ mutex_lock(&vpe_dev->mutex);
+ for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+ if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) {
+ vpe_dev->vpe_subscribe_list[i].active = 0;
+ vpe_dev->vpe_subscribe_list[i].vfh = NULL;
+ break;
+ }
+ }
+ if (i == MAX_ACTIVE_VPE_INSTANCE) {
+ pr_err("Invalid close\n");
+ mutex_unlock(&vpe_dev->mutex);
+ return -ENODEV;
+ }
+
+ VPE_DBG("close %d %p\n", i, &fh->vfh);
+ vpe_dev->vpe_open_cnt--;
+ if (vpe_dev->vpe_open_cnt == 0) {
+ vpe_deinit_mem(vpe_dev);
+ vpe_release_hardware(vpe_dev);
+ vpe_dev->state = VPE_STATE_OFF;
+ }
+ mutex_unlock(&vpe_dev->mutex);
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops = {
+ .open = vpe_open_node,
+ .close = vpe_close_node,
+};
+
+static int msm_vpe_buffer_ops(struct vpe_device *vpe_dev,
+ uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info)
+{
+ int rc = -EINVAL;
+
+ rc = v4l2_subdev_call(vpe_dev->buf_mgr_subdev, core, ioctl,
+ buff_mgr_ops, buff_mgr_info);
+ if (rc < 0)
+ pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+ return rc;
+}
+
+static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev)
+{
+ struct v4l2_event v4l2_evt;
+ struct msm_queue_cmd *frame_qcmd;
+ struct msm_queue_cmd *event_qcmd;
+ struct msm_vpe_frame_info_t *processed_frame;
+ struct msm_device_queue *queue = &vpe_dev->processing_q;
+ struct msm_buf_mngr_info buff_mgr_info;
+ int rc = 0;
+
+ if (queue->len > 0) {
+ frame_qcmd = msm_dequeue(queue, list_frame);
+ processed_frame = frame_qcmd->command;
+ do_gettimeofday(&(processed_frame->out_time));
+ kfree(frame_qcmd);
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+ if (!event_qcmd) {
+ pr_err("%s: Insufficient memory\n", __func__);
+ return -ENOMEM;
+ }
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = processed_frame;
+ VPE_DBG("fid %d\n", processed_frame->frame_id);
+ msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
+
+ if (!processed_frame->output_buffer_info.processed_divert) {
+ memset(&buff_mgr_info, 0 ,
+ sizeof(buff_mgr_info));
+ buff_mgr_info.session_id =
+ ((processed_frame->identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id =
+ (processed_frame->identity & 0xFFFF);
+ buff_mgr_info.frame_id = processed_frame->frame_id;
+ buff_mgr_info.timestamp = processed_frame->timestamp;
+ buff_mgr_info.index =
+ processed_frame->output_buffer_info.index;
+ rc = msm_vpe_buffer_ops(vpe_dev,
+ VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
+ __func__);
+ rc = -EINVAL;
+ }
+ }
+
+ v4l2_evt.id = processed_frame->inst_id;
+ v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
+ v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+ }
+ return rc;
+}
+
+static void vpe_update_scaler_params(struct vpe_device *vpe_dev,
+ struct msm_vpe_frame_strip_info strip_info)
+{
+ uint32_t out_ROI_width, out_ROI_height;
+ uint32_t src_ROI_width, src_ROI_height;
+
+ /*
+ * phase_step_x, phase_step_y, phase_init_x and phase_init_y
+ * are represented in fixed-point, unsigned 3.29 format
+ */
+ uint32_t phase_step_x = 0;
+ uint32_t phase_step_y = 0;
+ uint32_t phase_init_x = 0;
+ uint32_t phase_init_y = 0;
+
+ uint32_t src_roi, src_x, src_y, src_xy, temp;
+ uint32_t yscale_filter_sel, xscale_filter_sel;
+ uint32_t scale_unit_sel_x, scale_unit_sel_y;
+ uint64_t numerator, denominator;
+
+ /*
+ * assumption is both direction need zoom. this can be
+ * improved.
+ */
+ temp = msm_camera_io_r(vpe_dev->base + VPE_OP_MODE_OFFSET) | 0x3;
+ msm_camera_io_w(temp, vpe_dev->base + VPE_OP_MODE_OFFSET);
+
+ src_ROI_width = strip_info.src_w;
+ src_ROI_height = strip_info.src_h;
+ out_ROI_width = strip_info.dst_w;
+ out_ROI_height = strip_info.dst_h;
+
+ VPE_DBG("src w = %u, h=%u, dst w = %u, h =%u.\n",
+ src_ROI_width, src_ROI_height, out_ROI_width,
+ out_ROI_height);
+ src_roi = (src_ROI_height << 16) + src_ROI_width;
+
+ msm_camera_io_w(src_roi, vpe_dev->base + VPE_SRC_SIZE_OFFSET);
+
+ src_x = strip_info.src_x;
+ src_y = strip_info.src_y;
+
+ VPE_DBG("src_x = %d, src_y=%d.\n", src_x, src_y);
+
+ src_xy = src_y*(1<<16) + src_x;
+ msm_camera_io_w(src_xy, vpe_dev->base +
+ VPE_SRC_XY_OFFSET);
+ VPE_DBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi);
+
+ /* decide whether to use FIR or M/N for scaling */
+ if ((out_ROI_width == 1 && src_ROI_width < 4) ||
+ (src_ROI_width < 4 * out_ROI_width - 3))
+ scale_unit_sel_x = 0;/* use FIR scalar */
+ else
+ scale_unit_sel_x = 1;/* use M/N scalar */
+
+ if ((out_ROI_height == 1 && src_ROI_height < 4) ||
+ (src_ROI_height < 4 * out_ROI_height - 3))
+ scale_unit_sel_y = 0;/* use FIR scalar */
+ else
+ scale_unit_sel_y = 1;/* use M/N scalar */
+
+ /* calculate phase step for the x direction */
+
+ /*
+ * if destination is only 1 pixel wide, the value of
+ * phase_step_x is unimportant. Assigning phase_step_x to src
+ * ROI width as an arbitrary value.
+ */
+ if (out_ROI_width == 1)
+ phase_step_x = (uint32_t) ((src_ROI_width) <<
+ SCALER_PHASE_BITS);
+
+ /* if using FIR scalar */
+ else if (scale_unit_sel_x == 0) {
+
+ /*
+ * Calculate the quotient ( src_ROI_width - 1 ) (
+ * out_ROI_width - 1) with u3.29 precision. Quotient
+ * is rounded up to the larger 29th decimal point
+ */
+ numerator = (uint64_t)(src_ROI_width - 1) <<
+ SCALER_PHASE_BITS;
+ /*
+ * never equals to 0 because of the "(out_ROI_width ==
+ * 1 )"
+ */
+ denominator = (uint64_t)(out_ROI_width - 1);
+ /*
+ * divide and round up to the larger 29th decimal
+ * point.
+ */
+ phase_step_x = (uint32_t) vpe_do_div((numerator +
+ denominator - 1), denominator);
+ } else if (scale_unit_sel_x == 1) { /* if M/N scalar */
+ /*
+ * Calculate the quotient ( src_ROI_width ) / (
+ * out_ROI_width) with u3.29 precision. Quotient is
+ * rounded down to the smaller 29th decimal point.
+ */
+ numerator = (uint64_t)(src_ROI_width) <<
+ SCALER_PHASE_BITS;
+ denominator = (uint64_t)(out_ROI_width);
+ phase_step_x =
+ (uint32_t) vpe_do_div(numerator, denominator);
+ }
+ /* calculate phase step for the y direction */
+
+ /*
+ * if destination is only 1 pixel wide, the value of
+ * phase_step_x is unimportant. Assigning phase_step_x to src
+ * ROI width as an arbitrary value.
+ */
+ if (out_ROI_height == 1)
+ phase_step_y =
+ (uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS);
+
+ /* if FIR scalar */
+ else if (scale_unit_sel_y == 0) {
+ /*
+ * Calculate the quotient ( src_ROI_height - 1 ) / (
+ * out_ROI_height - 1) with u3.29 precision. Quotient
+ * is rounded up to the larger 29th decimal point.
+ */
+ numerator = (uint64_t)(src_ROI_height - 1) <<
+ SCALER_PHASE_BITS;
+ /*
+ * never equals to 0 because of the " ( out_ROI_height
+ * == 1 )" case
+ */
+ denominator = (uint64_t)(out_ROI_height - 1);
+ /*
+ * Quotient is rounded up to the larger 29th decimal
+ * point.
+ */
+ phase_step_y =
+ (uint32_t) vpe_do_div(
+ (numerator + denominator - 1), denominator);
+ } else if (scale_unit_sel_y == 1) { /* if M/N scalar */
+ /*
+ * Calculate the quotient ( src_ROI_height ) (
+ * out_ROI_height) with u3.29 precision. Quotient is
+ * rounded down to the smaller 29th decimal point.
+ */
+ numerator = (uint64_t)(src_ROI_height) <<
+ SCALER_PHASE_BITS;
+ denominator = (uint64_t)(out_ROI_height);
+ phase_step_y = (uint32_t) vpe_do_div(
+ numerator, denominator);
+ }
+
+ /* decide which set of FIR coefficients to use */
+ if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
+ xscale_filter_sel = 0;
+ else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
+ xscale_filter_sel = 1;
+ else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
+ xscale_filter_sel = 2;
+ else
+ xscale_filter_sel = 3;
+
+ if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
+ yscale_filter_sel = 0;
+ else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
+ yscale_filter_sel = 1;
+ else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
+ yscale_filter_sel = 2;
+ else
+ yscale_filter_sel = 3;
+
+ /* calculate phase init for the x direction */
+
+ /* if using FIR scalar */
+ if (scale_unit_sel_x == 0) {
+ if (out_ROI_width == 1)
+ phase_init_x =
+ (uint32_t) ((src_ROI_width - 1) <<
+ SCALER_PHASE_BITS);
+ else
+ phase_init_x = 0;
+ } else if (scale_unit_sel_x == 1) /* M over N scalar */
+ phase_init_x = 0;
+
+ /*
+ * calculate phase init for the y direction if using FIR
+ * scalar
+ */
+ if (scale_unit_sel_y == 0) {
+ if (out_ROI_height == 1)
+ phase_init_y =
+ (uint32_t) ((src_ROI_height -
+ 1) << SCALER_PHASE_BITS);
+ else
+ phase_init_y = 0;
+ } else if (scale_unit_sel_y == 1) /* M over N scalar */
+ phase_init_y = 0;
+
+ strip_info.phase_step_x = phase_step_x;
+ strip_info.phase_step_y = phase_step_y;
+ strip_info.phase_init_x = phase_init_x;
+ strip_info.phase_init_y = phase_init_y;
+ VPE_DBG("phase step x = %d, step y = %d.\n",
+ strip_info.phase_step_x, strip_info.phase_step_y);
+ VPE_DBG("phase init x = %d, init y = %d.\n",
+ strip_info.phase_init_x, strip_info.phase_init_y);
+
+ msm_camera_io_w(strip_info.phase_step_x, vpe_dev->base +
+ VPE_SCALE_PHASEX_STEP_OFFSET);
+ msm_camera_io_w(strip_info.phase_step_y, vpe_dev->base +
+ VPE_SCALE_PHASEY_STEP_OFFSET);
+
+ msm_camera_io_w(strip_info.phase_init_x, vpe_dev->base +
+ VPE_SCALE_PHASEX_INIT_OFFSET);
+ msm_camera_io_w(strip_info.phase_init_y, vpe_dev->base +
+ VPE_SCALE_PHASEY_INIT_OFFSET);
+}
+
+static void vpe_program_buffer_addresses(
+ struct vpe_device *vpe_dev,
+ unsigned long srcP0,
+ unsigned long srcP1,
+ unsigned long outP0,
+ unsigned long outP1)
+{
+ VPE_DBG("%s VPE Configured with:\n"
+ "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_dev->base + VPE_SRCP0_ADDR_OFFSET);
+ msm_camera_io_w(srcP1, vpe_dev->base + VPE_SRCP1_ADDR_OFFSET);
+ msm_camera_io_w(outP0, vpe_dev->base + VPE_OUTP0_ADDR_OFFSET);
+ msm_camera_io_w(outP1, vpe_dev->base + VPE_OUTP1_ADDR_OFFSET);
+}
+
+static int vpe_start(struct vpe_device *vpe_dev)
+{
+ /* enable the frame irq, bit 0 = Display list 0 ROI done */
+ msm_camera_io_w_mb(1, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+ msm_camera_io_dump(vpe_dev->base, 0x120);
+ msm_camera_io_dump(vpe_dev->base + 0x00400, 0x18);
+ msm_camera_io_dump(vpe_dev->base + 0x10000, 0x250);
+ msm_camera_io_dump(vpe_dev->base + 0x30000, 0x20);
+ msm_camera_io_dump(vpe_dev->base + 0x50000, 0x30);
+ msm_camera_io_dump(vpe_dev->base + 0x50400, 0x10);
+
+ /*
+ * This triggers the operation. When the VPE is done,
+ * msm_vpe_irq will fire.
+ */
+ msm_camera_io_w_mb(1, vpe_dev->base + VPE_DL0_START_OFFSET);
+ return 0;
+}
+
+static void vpe_config_axi_default(struct vpe_device *vpe_dev)
+{
+ msm_camera_io_w(0x25, vpe_dev->base + VPE_AXI_ARB_2_OFFSET);
+}
+
+static int vpe_reset(struct vpe_device *vpe_dev)
+{
+ uint32_t vpe_version;
+ uint32_t rc = 0;
+
+ vpe_version = msm_camera_io_r(
+ vpe_dev->base + VPE_HW_VERSION_OFFSET);
+ VPE_DBG("vpe_version = 0x%x\n", vpe_version);
+ /* disable all interrupts.*/
+ msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+ /* clear all pending interrupts*/
+ msm_camera_io_w(0x1fffff, vpe_dev->base + VPE_INTR_CLEAR_OFFSET);
+ /* write sw_reset to reset the core. */
+ msm_camera_io_w(0x10, vpe_dev->base + VPE_SW_RESET_OFFSET);
+ /* then poll the reset bit, it should be self-cleared. */
+ while (1) {
+ rc = msm_camera_io_r(vpe_dev->base + VPE_SW_RESET_OFFSET) \
+ & 0x10;
+ if (rc == 0)
+ break;
+ cpu_relax();
+ }
+ /*
+ * at this point, hardware is reset. Then pogram to default
+ * values.
+ */
+ msm_camera_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE,
+ vpe_dev->base + VPE_AXI_RD_ARB_CONFIG_OFFSET);
+
+ msm_camera_io_w(VPE_CGC_ENABLE_VALUE,
+ vpe_dev->base + VPE_CGC_EN_OFFSET);
+ msm_camera_io_w(1, vpe_dev->base + VPE_CMD_MODE_OFFSET);
+ msm_camera_io_w(VPE_DEFAULT_OP_MODE_VALUE,
+ vpe_dev->base + VPE_OP_MODE_OFFSET);
+ msm_camera_io_w(VPE_DEFAULT_SCALE_CONFIG,
+ vpe_dev->base + VPE_SCALE_CONFIG_OFFSET);
+ vpe_config_axi_default(vpe_dev);
+ return rc;
+}
+
+static void vpe_update_scale_coef(struct vpe_device *vpe_dev, uint32_t *p)
+{
+ uint32_t i, offset;
+ offset = *p;
+ for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) {
+ VPE_DBG("Setting scale table %d\n", i);
+ msm_camera_io_w(*(++p),
+ vpe_dev->base + VPE_SCALE_COEFF_LSBn(i));
+ msm_camera_io_w(*(++p),
+ vpe_dev->base + VPE_SCALE_COEFF_MSBn(i));
+ }
+}
+
+static void vpe_input_plane_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+ msm_camera_io_w(*p, vpe_dev->base + VPE_SRC_FORMAT_OFFSET);
+ msm_camera_io_w(*(++p),
+ vpe_dev->base + VPE_SRC_UNPACK_PATTERN1_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_IMAGE_SIZE_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_YSTRIDE1_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_SIZE_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_XY_OFFSET);
+}
+
+static void vpe_output_plane_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+ msm_camera_io_w(*p, vpe_dev->base + VPE_OUT_FORMAT_OFFSET);
+ msm_camera_io_w(*(++p),
+ vpe_dev->base + VPE_OUT_PACK_PATTERN1_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_YSTRIDE1_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_SIZE_OFFSET);
+ msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_XY_OFFSET);
+}
+
+static void vpe_operation_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+ msm_camera_io_w(*p, vpe_dev->base + VPE_OP_MODE_OFFSET);
+}
+
+/**
+ * msm_vpe_transaction_setup() - send setup for one frame to VPE
+ * @vpe_dev: vpe device
+ * @data: packed setup commands
+ *
+ * See msm_vpe.h for the expected format of `data'
+ */
+static void msm_vpe_transaction_setup(struct vpe_device *vpe_dev, void *data)
+{
+ int i;
+ void *iter = data;
+
+ vpe_mem_dump("vpe_transaction", data, VPE_TRANSACTION_SETUP_CONFIG_LEN);
+
+ for (i = 0; i < VPE_NUM_SCALER_TABLES; ++i) {
+ vpe_update_scale_coef(vpe_dev, (uint32_t *)iter);
+ iter += VPE_SCALER_CONFIG_LEN;
+ }
+ vpe_input_plane_config(vpe_dev, (uint32_t *)iter);
+ iter += VPE_INPUT_PLANE_CFG_LEN;
+ vpe_output_plane_config(vpe_dev, (uint32_t *)iter);
+ iter += VPE_OUTPUT_PLANE_CFG_LEN;
+ vpe_operation_config(vpe_dev, (uint32_t *)iter);
+}
+
+static int msm_vpe_send_frame_to_hardware(struct vpe_device *vpe_dev,
+ struct msm_queue_cmd *frame_qcmd)
+{
+ struct msm_vpe_frame_info_t *process_frame;
+
+ if (vpe_dev->processing_q.len < MAX_VPE_PROCESSING_FRAME) {
+ process_frame = frame_qcmd->command;
+ msm_enqueue(&vpe_dev->processing_q,
+ &frame_qcmd->list_frame);
+
+ vpe_update_scaler_params(vpe_dev, process_frame->strip_info);
+ vpe_program_buffer_addresses(
+ vpe_dev,
+ process_frame->src_phyaddr,
+ process_frame->src_phyaddr
+ + process_frame->src_chroma_plane_offset,
+ process_frame->dest_phyaddr,
+ process_frame->dest_phyaddr
+ + process_frame->dest_chroma_plane_offset);
+ vpe_start(vpe_dev);
+ do_gettimeofday(&(process_frame->in_time));
+ }
+ return 0;
+}
+
+static int msm_vpe_cfg(struct vpe_device *vpe_dev,
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+ int rc = 0;
+ struct msm_queue_cmd *frame_qcmd = NULL;
+ struct msm_vpe_frame_info_t *new_frame =
+ kzalloc(sizeof(struct msm_vpe_frame_info_t), GFP_KERNEL);
+ unsigned long in_phyaddr, out_phyaddr;
+ struct msm_buf_mngr_info buff_mgr_info;
+
+ if (!new_frame) {
+ pr_err("Insufficient memory. return\n");
+ return -ENOMEM;
+ }
+
+ rc = copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_vpe_frame_info_t));
+ if (rc) {
+ pr_err("%s:%d copy from user\n", __func__, __LINE__);
+ rc = -EINVAL;
+ goto err_free_new_frame;
+ }
+
+ in_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev,
+ &new_frame->input_buffer_info,
+ ((new_frame->identity >> 16) & 0xFFFF),
+ (new_frame->identity & 0xFFFF));
+ if (!in_phyaddr) {
+ pr_err("error gettting input physical address\n");
+ rc = -EINVAL;
+ goto err_free_new_frame;
+ }
+
+ memset(&new_frame->output_buffer_info, 0,
+ sizeof(struct msm_vpe_buffer_info_t));
+ memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+ buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
+ buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF);
+ rc = msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("error getting buffer\n");
+ rc = -EINVAL;
+ goto err_free_new_frame;
+ }
+
+ new_frame->output_buffer_info.index = buff_mgr_info.index;
+ out_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev,
+ &new_frame->output_buffer_info,
+ ((new_frame->identity >> 16) & 0xFFFF),
+ (new_frame->identity & 0xFFFF));
+ if (!out_phyaddr) {
+ pr_err("error gettting output physical address\n");
+ rc = -EINVAL;
+ goto err_put_buf;
+ }
+
+ new_frame->src_phyaddr = in_phyaddr;
+ new_frame->dest_phyaddr = out_phyaddr;
+
+ frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+ if (!frame_qcmd) {
+ pr_err("Insufficient memory. return\n");
+ rc = -ENOMEM;
+ goto err_put_buf;
+ }
+
+ atomic_set(&frame_qcmd->on_heap, 1);
+ frame_qcmd->command = new_frame;
+ rc = msm_vpe_send_frame_to_hardware(vpe_dev, frame_qcmd);
+ if (rc < 0) {
+ pr_err("error cannot send frame to hardware\n");
+ rc = -EINVAL;
+ goto err_free_frame_qcmd;
+ }
+
+ return rc;
+
+err_free_frame_qcmd:
+ kfree(frame_qcmd);
+err_put_buf:
+ msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+ &buff_mgr_info);
+err_free_new_frame:
+ kfree(new_frame);
+ return rc;
+}
+
+static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+ int rc = 0;
+
+ mutex_lock(&vpe_dev->mutex);
+ switch (cmd) {
+ case VIDIOC_MSM_VPE_TRANSACTION_SETUP: {
+ struct msm_vpe_transaction_setup_cfg *cfg;
+ VPE_DBG("VIDIOC_MSM_VPE_TRANSACTION_SETUP\n");
+ if (sizeof(*cfg) != ioctl_ptr->len) {
+ pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
+ __func__, cmd, ioctl_ptr->len,
+ sizeof(*cfg));
+ rc = -EINVAL;
+ break;
+ }
+
+ cfg = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+ if (!cfg) {
+ pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = copy_from_user(cfg, (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len);
+ if (rc) {
+ pr_err("%s:%d copy from user\n", __func__, __LINE__);
+ kfree(cfg);
+ break;
+ }
+
+ msm_vpe_transaction_setup(vpe_dev, (void *)cfg);
+ kfree(cfg);
+ break;
+ }
+ case VIDIOC_MSM_VPE_CFG: {
+ VPE_DBG("VIDIOC_MSM_VPE_CFG\n");
+ rc = msm_vpe_cfg(vpe_dev, ioctl_ptr);
+ break;
+ }
+ case VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO: {
+ struct msm_vpe_stream_buff_info_t *u_stream_buff_info;
+ struct msm_vpe_stream_buff_info_t k_stream_buff_info;
+
+ VPE_DBG("VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO\n");
+
+ if (sizeof(struct msm_vpe_stream_buff_info_t) !=
+ ioctl_ptr->len) {
+ pr_err("%s:%d: invalid length\n", __func__, __LINE__);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+ if (!u_stream_buff_info) {
+ pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = (copy_from_user(u_stream_buff_info,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len) ? -EFAULT : 0);
+ if (rc) {
+ pr_err("%s:%d copy from user\n", __func__, __LINE__);
+ kfree(u_stream_buff_info);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs;
+ k_stream_buff_info.identity = u_stream_buff_info->identity;
+ k_stream_buff_info.buffer_info =
+ kzalloc(k_stream_buff_info.num_buffs *
+ sizeof(struct msm_vpe_buffer_info_t), GFP_KERNEL);
+ if (!k_stream_buff_info.buffer_info) {
+ pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+ kfree(u_stream_buff_info);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = (copy_from_user(k_stream_buff_info.buffer_info,
+ (void __user *)u_stream_buff_info->buffer_info,
+ k_stream_buff_info.num_buffs *
+ sizeof(struct msm_vpe_buffer_info_t)) ?
+ -EFAULT : 0);
+ if (rc) {
+ pr_err("%s:%d copy from user\n", __func__, __LINE__);
+ kfree(k_stream_buff_info.buffer_info);
+ kfree(u_stream_buff_info);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ rc = msm_vpe_add_buff_queue_entry(vpe_dev,
+ ((k_stream_buff_info.identity >> 16) & 0xFFFF),
+ (k_stream_buff_info.identity & 0xFFFF));
+ if (!rc)
+ rc = msm_vpe_enqueue_buff_info_list(vpe_dev,
+ &k_stream_buff_info);
+
+ kfree(k_stream_buff_info.buffer_info);
+ kfree(u_stream_buff_info);
+ break;
+ }
+ case VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO: {
+ uint32_t identity;
+ struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+ VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n");
+
+ rc = (copy_from_user(&identity,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len) ? -EFAULT : 0);
+ if (rc) {
+ pr_err("%s:%d copy from user\n", __func__, __LINE__);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev,
+ ((identity >> 16) & 0xFFFF), (identity & 0xFFFF));
+ if (buff_queue_info == NULL) {
+ pr_err("error finding buffer queue entry for identity:%d\n",
+ identity);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ msm_vpe_dequeue_buff_info_list(vpe_dev, buff_queue_info);
+ rc = msm_vpe_free_buff_queue_entry(vpe_dev,
+ buff_queue_info->session_id,
+ buff_queue_info->stream_id);
+ break;
+ }
+ case VIDIOC_MSM_VPE_GET_EVENTPAYLOAD: {
+ struct msm_device_queue *queue = &vpe_dev->eventData_q;
+ struct msm_queue_cmd *event_qcmd;
+ struct msm_vpe_frame_info_t *process_frame;
+ VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n");
+ event_qcmd = msm_dequeue(queue, list_eventdata);
+ process_frame = event_qcmd->command;
+ VPE_DBG("fid %d\n", process_frame->frame_id);
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+ process_frame,
+ sizeof(struct msm_vpe_frame_info_t))) {
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
+
+ kfree(process_frame);
+ kfree(event_qcmd);
+ break;
+ }
+ }
+ mutex_unlock(&vpe_dev->mutex);
+ return rc;
+}
+
+static int msm_vpe_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_subscribe(fh, sub, MAX_VPE_V4l2_EVENTS);
+}
+
+static int msm_vpe_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_unsubscribe(fh, sub);
+}
+
+static struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = {
+ .ioctl = msm_vpe_subdev_ioctl,
+ .subscribe_event = msm_vpe_subscribe_event,
+ .unsubscribe_event = msm_vpe_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_ops msm_vpe_subdev_ops = {
+ .core = &msm_vpe_subdev_core_ops,
+};
+
+static struct v4l2_file_operations msm_vpe_v4l2_subdev_fops;
+
+static long msm_vpe_subdev_do_ioctl(
+ struct file *file, unsigned int cmd, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct v4l2_fh *vfh = file->private_data;
+
+ switch (cmd) {
+ case VIDIOC_DQEVENT:
+ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+ return -ENOIOCTLCMD;
+
+ return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_SUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+ case VIDIOC_MSM_VPE_GET_INST_INFO: {
+ uint32_t i;
+ struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+ struct msm_vpe_frame_info_t inst_info;
+ for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+ if (vpe_dev->vpe_subscribe_list[i].vfh == vfh) {
+ inst_info.inst_id = i;
+ break;
+ }
+ }
+ if (copy_to_user(
+ (void __user *)ioctl_ptr->ioctl_ptr, &inst_info,
+ sizeof(struct msm_vpe_frame_info_t))) {
+ return -EINVAL;
+ }
+ }
+ default:
+ return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+ }
+
+ return 0;
+}
+
+static long msm_vpe_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return video_usercopy(file, cmd, arg, msm_vpe_subdev_do_ioctl);
+}
+
+static int vpe_register_domain(void)
+{
+ struct msm_iova_partition vpe_iommu_partition = {
+ /* TODO: verify that these are correct? */
+ .start = SZ_128K,
+ .size = SZ_2G - SZ_128K,
+ };
+ struct msm_iova_layout vpe_iommu_layout = {
+ .partitions = &vpe_iommu_partition,
+ .npartitions = 1,
+ .client_name = "camera_vpe",
+ .domain_flags = 0,
+ };
+
+ return msm_register_domain(&vpe_iommu_layout);
+}
+
+static int __devinit vpe_probe(struct platform_device *pdev)
+{
+ struct vpe_device *vpe_dev;
+ int rc = 0;
+
+ vpe_dev = kzalloc(sizeof(struct vpe_device), GFP_KERNEL);
+ if (!vpe_dev) {
+ pr_err("not enough memory\n");
+ return -ENOMEM;
+ }
+
+ vpe_dev->vpe_clk = kzalloc(sizeof(struct clk *) *
+ ARRAY_SIZE(vpe_clk_info), GFP_KERNEL);
+ if (!vpe_dev->vpe_clk) {
+ pr_err("not enough memory\n");
+ rc = -ENOMEM;
+ goto err_free_vpe_dev;
+ }
+
+ v4l2_subdev_init(&vpe_dev->msm_sd.sd, &msm_vpe_subdev_ops);
+ vpe_dev->msm_sd.sd.internal_ops = &msm_vpe_internal_ops;
+ snprintf(vpe_dev->msm_sd.sd.name, ARRAY_SIZE(vpe_dev->msm_sd.sd.name),
+ "vpe");
+ vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+ v4l2_set_subdevdata(&vpe_dev->msm_sd.sd, vpe_dev);
+ platform_set_drvdata(pdev, &vpe_dev->msm_sd.sd);
+ mutex_init(&vpe_dev->mutex);
+ spin_lock_init(&vpe_dev->tasklet_lock);
+
+ vpe_dev->pdev = pdev;
+
+ vpe_dev->mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "vpe");
+ if (!vpe_dev->mem) {
+ pr_err("no mem resource?\n");
+ rc = -ENODEV;
+ goto err_free_vpe_clk;
+ }
+
+ vpe_dev->irq = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "vpe");
+ if (!vpe_dev->irq) {
+ pr_err("%s: no irq resource?\n", __func__);
+ rc = -ENODEV;
+ goto err_release_mem;
+ }
+
+ vpe_dev->domain_num = vpe_register_domain();
+ if (vpe_dev->domain_num < 0) {
+ pr_err("%s: could not register domain\n", __func__);
+ rc = -ENODEV;
+ goto err_release_mem;
+ }
+
+ vpe_dev->domain =
+ msm_get_iommu_domain(vpe_dev->domain_num);
+ if (!vpe_dev->domain) {
+ pr_err("%s: cannot find domain\n", __func__);
+ rc = -ENODEV;
+ goto err_release_mem;
+ }
+
+ vpe_dev->iommu_ctx_src = msm_iommu_get_ctx("vpe_src");
+ vpe_dev->iommu_ctx_dst = msm_iommu_get_ctx("vpe_dst");
+ if (!vpe_dev->iommu_ctx_src || !vpe_dev->iommu_ctx_dst) {
+ pr_err("%s: cannot get iommu_ctx\n", __func__);
+ rc = -ENODEV;
+ goto err_release_mem;
+ }
+
+ media_entity_init(&vpe_dev->msm_sd.sd.entity, 0, NULL, 0);
+ vpe_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ vpe_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_VPE;
+ vpe_dev->msm_sd.sd.entity.name = pdev->name;
+ msm_sd_register(&vpe_dev->msm_sd);
+ msm_vpe_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner;
+ msm_vpe_v4l2_subdev_fops.open = v4l2_subdev_fops.open;
+ msm_vpe_v4l2_subdev_fops.unlocked_ioctl = msm_vpe_subdev_fops_ioctl;
+ msm_vpe_v4l2_subdev_fops.release = v4l2_subdev_fops.release;
+ msm_vpe_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll;
+
+ vpe_dev->msm_sd.sd.devnode->fops = &msm_vpe_v4l2_subdev_fops;
+ vpe_dev->msm_sd.sd.entity.revision = vpe_dev->msm_sd.sd.devnode->num;
+ vpe_dev->state = VPE_STATE_BOOT;
+ rc = vpe_init_hardware(vpe_dev);
+ if (rc < 0) {
+ pr_err("%s: Couldn't init vpe hardware\n", __func__);
+ rc = -ENODEV;
+ goto err_unregister_sd;
+ }
+ vpe_reset(vpe_dev);
+ vpe_release_hardware(vpe_dev);
+ vpe_dev->state = VPE_STATE_OFF;
+
+ rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+ if (rc < 0) {
+ pr_err("Couldn't attach to vpe_src context bank\n");
+ rc = -ENODEV;
+ goto err_unregister_sd;
+ }
+ rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst);
+ if (rc < 0) {
+ pr_err("Couldn't attach to vpe_dst context bank\n");
+ rc = -ENODEV;
+ goto err_detach_src;
+ }
+
+ vpe_dev->state = VPE_STATE_OFF;
+
+ msm_queue_init(&vpe_dev->eventData_q, "vpe-eventdata");
+ msm_queue_init(&vpe_dev->processing_q, "vpe-frame");
+ INIT_LIST_HEAD(&vpe_dev->tasklet_q);
+ tasklet_init(&vpe_dev->vpe_tasklet, msm_vpe_do_tasklet,
+ (unsigned long)vpe_dev);
+ vpe_dev->vpe_open_cnt = 0;
+
+ return rc;
+
+err_detach_src:
+ iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+err_unregister_sd:
+ msm_sd_unregister(&vpe_dev->msm_sd);
+err_release_mem:
+ release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem));
+err_free_vpe_clk:
+ kfree(vpe_dev->vpe_clk);
+err_free_vpe_dev:
+ kfree(vpe_dev);
+ return rc;
+}
+
+static int vpe_device_remove(struct platform_device *dev)
+{
+ struct v4l2_subdev *sd = platform_get_drvdata(dev);
+ struct vpe_device *vpe_dev;
+ if (!sd) {
+ pr_err("%s: Subdevice is NULL\n", __func__);
+ return 0;
+ }
+
+ vpe_dev = (struct vpe_device *)v4l2_get_subdevdata(sd);
+ if (!vpe_dev) {
+ pr_err("%s: vpe device is NULL\n", __func__);
+ return 0;
+ }
+
+ iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst);
+ iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+ msm_sd_unregister(&vpe_dev->msm_sd);
+ release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem));
+ mutex_destroy(&vpe_dev->mutex);
+ kfree(vpe_dev);
+ return 0;
+}
+
+static struct platform_driver vpe_driver = {
+ .probe = vpe_probe,
+ .remove = __devexit_p(vpe_device_remove),
+ .driver = {
+ .name = MSM_VPE_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_vpe_init_module(void)
+{
+ return platform_driver_register(&vpe_driver);
+}
+
+static void __exit msm_vpe_exit_module(void)
+{
+ platform_driver_unregister(&vpe_driver);
+}
+
+module_init(msm_vpe_init_module);
+module_exit(msm_vpe_exit_module);
+MODULE_DESCRIPTION("MSM VPE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h
new file mode 100644
index 0000000..c02432e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h
@@ -0,0 +1,255 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_VPE_H__
+#define __MSM_VPE_H__
+
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-subdev.h>
+#include "msm_sd.h"
+
+/*********** start of register offset *********************/
+#define VPE_INTR_ENABLE_OFFSET 0x0020
+#define VPE_INTR_STATUS_OFFSET 0x0024
+#define VPE_INTR_CLEAR_OFFSET 0x0028
+#define VPE_DL0_START_OFFSET 0x0030
+#define VPE_HW_VERSION_OFFSET 0x0070
+#define VPE_SW_RESET_OFFSET 0x0074
+#define VPE_AXI_RD_ARB_CONFIG_OFFSET 0x0078
+#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET 0x007C
+#define VPE_CGC_EN_OFFSET 0x0100
+#define VPE_CMD_STATUS_OFFSET 0x10008
+#define VPE_PROFILE_EN_OFFSET 0x10010
+#define VPE_PROFILE_COUNT_OFFSET 0x10014
+#define VPE_CMD_MODE_OFFSET 0x10060
+#define VPE_SRC_SIZE_OFFSET 0x10108
+#define VPE_SRCP0_ADDR_OFFSET 0x1010C
+#define VPE_SRCP1_ADDR_OFFSET 0x10110
+#define VPE_SRC_YSTRIDE1_OFFSET 0x1011C
+#define VPE_SRC_FORMAT_OFFSET 0x10124
+#define VPE_SRC_UNPACK_PATTERN1_OFFSET 0x10128
+#define VPE_OP_MODE_OFFSET 0x10138
+#define VPE_SCALE_PHASEX_INIT_OFFSET 0x1013C
+#define VPE_SCALE_PHASEY_INIT_OFFSET 0x10140
+#define VPE_SCALE_PHASEX_STEP_OFFSET 0x10144
+#define VPE_SCALE_PHASEY_STEP_OFFSET 0x10148
+#define VPE_OUT_FORMAT_OFFSET 0x10150
+#define VPE_OUT_PACK_PATTERN1_OFFSET 0x10154
+#define VPE_OUT_SIZE_OFFSET 0x10164
+#define VPE_OUTP0_ADDR_OFFSET 0x10168
+#define VPE_OUTP1_ADDR_OFFSET 0x1016C
+#define VPE_OUT_YSTRIDE1_OFFSET 0x10178
+#define VPE_OUT_XY_OFFSET 0x1019C
+#define VPE_SRC_XY_OFFSET 0x10200
+#define VPE_SRC_IMAGE_SIZE_OFFSET 0x10208
+#define VPE_SCALE_CONFIG_OFFSET 0x10230
+#define VPE_DEINT_STATUS_OFFSET 0x30000
+#define VPE_DEINT_DECISION_OFFSET 0x30004
+#define VPE_DEINT_COEFF0_OFFSET 0x30010
+#define VPE_SCALE_STATUS_OFFSET 0x50000
+#define VPE_SCALE_SVI_PARAM_OFFSET 0x50010
+#define VPE_SCALE_SHARPEN_CFG_OFFSET 0x50020
+#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400
+#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404
+
+#define VPE_AXI_ARB_1_OFFSET 0x00408
+#define VPE_AXI_ARB_2_OFFSET 0x0040C
+
+#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n))
+#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n))
+#define VPE_SCALE_COEFF_NUM 32
+
+/*********** end of register offset ********************/
+
+
+#define VPE_HARDWARE_VERSION 0x00080308
+#define VPE_SW_RESET_VALUE 0x00000010 /* bit 4 for PPP*/
+#define VPE_AXI_RD_ARB_CONFIG_VALUE 0x124924
+#define VPE_CMD_MODE_VALUE 0x1
+#define VPE_DEFAULT_OP_MODE_VALUE 0x40FC0004
+#define VPE_CGC_ENABLE_VALUE 0xffff
+#define VPE_DEFAULT_SCALE_CONFIG 0x3c
+
+#define VPE_NORMAL_MODE_CLOCK_RATE 150000000
+#define VPE_TURBO_MODE_CLOCK_RATE 200000000
+#define VPE_SUBDEV_MAX_EVENTS 30
+
+/**************************************************/
+/*********** End of command id ********************/
+/**************************************************/
+
+#define SCALER_PHASE_BITS 29
+#define HAL_MDP_PHASE_STEP_2P50 0x50000000
+#define HAL_MDP_PHASE_STEP_1P66 0x35555555
+#define HAL_MDP_PHASE_STEP_1P25 0x28000000
+
+
+#define MAX_ACTIVE_VPE_INSTANCE 8
+#define MAX_VPE_PROCESSING_FRAME 2
+#define MAX_VPE_V4l2_EVENTS 30
+
+#define MSM_VPE_TASKLETQ_SIZE 16
+
+/**
+ * The format of the msm_vpe_transaction_setup_cfg is as follows:
+ *
+ * - vpe_update_scale_coef (65*4 uint32_t's)
+ * - Each table is 65 uint32_t's long
+ * - 1st uint32_t in each table indicates offset
+ * - Following 64 uint32_t's are the data
+ *
+ * - vpe_input_plane_config (6 uint32_t's)
+ * - VPE_SRC_FORMAT_OFFSET
+ * - VPE_SRC_UNPACK_PATTERN1_OFFSET
+ * - VPE_SRC_IMAGE_SIZE_OFFSET
+ * - VPE_SRC_YSTRIDE1_OFFSET
+ * - VPE_SRC_SIZE_OFFSET
+ * - VPE_SRC_XY_OFFSET
+ *
+ * - vpe_output_plane_config (5 uint32_t's)
+ * - VPE_OUT_FORMAT_OFFSET
+ * - VPE_OUT_PACK_PATTERN1_OFFSET
+ * - VPE_OUT_YSTRIDE1_OFFSET
+ * - VPE_OUT_SIZE_OFFSET
+ * - VPE_OUT_XY_OFFSET
+ *
+ * - vpe_operation_config (1 uint32_t)
+ * - VPE_OP_MODE_OFFSET
+ *
+ */
+
+#define VPE_SCALER_CONFIG_LEN 260
+#define VPE_INPUT_PLANE_CFG_LEN 24
+#define VPE_OUTPUT_PLANE_CFG_LEN 20
+#define VPE_OPERATION_MODE_CFG_LEN 4
+#define VPE_NUM_SCALER_TABLES 4
+
+#define VPE_TRANSACTION_SETUP_CONFIG_LEN ( \
+ (VPE_SCALER_CONFIG_LEN * VPE_NUM_SCALER_TABLES) \
+ + VPE_INPUT_PLANE_CFG_LEN \
+ + VPE_OUTPUT_PLANE_CFG_LEN \
+ + VPE_OPERATION_MODE_CFG_LEN)
+/* VPE_TRANSACTION_SETUP_CONFIG_LEN = 1088 */
+
+struct msm_vpe_transaction_setup_cfg {
+ uint8_t scaler_cfg[VPE_TRANSACTION_SETUP_CONFIG_LEN];
+};
+
+struct vpe_subscribe_info {
+ struct v4l2_fh *vfh;
+ uint32_t active;
+};
+
+enum vpe_state {
+ VPE_STATE_BOOT,
+ VPE_STATE_IDLE,
+ VPE_STATE_ACTIVE,
+ VPE_STATE_OFF,
+};
+
+struct msm_queue_cmd {
+ struct list_head list_config;
+ struct list_head list_control;
+ struct list_head list_frame;
+ struct list_head list_pict;
+ struct list_head list_vpe_frame;
+ struct list_head list_eventdata;
+ void *command;
+ atomic_t on_heap;
+ struct timespec ts;
+ uint32_t error_code;
+ uint32_t trans_code;
+};
+
+struct msm_device_queue {
+ struct list_head list;
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ int max;
+ int len;
+ const char *name;
+};
+
+struct msm_vpe_tasklet_queue_cmd {
+ struct list_head list;
+ uint32_t irq_status;
+ uint8_t cmd_used;
+};
+
+struct msm_vpe_buffer_map_info_t {
+ unsigned long len;
+ unsigned long phy_addr;
+ struct ion_handle *ion_handle;
+ struct msm_vpe_buffer_info_t buff_info;
+};
+
+struct msm_vpe_buffer_map_list_t {
+ struct msm_vpe_buffer_map_info_t map_info;
+ struct list_head entry;
+};
+
+struct msm_vpe_buff_queue_info_t {
+ uint32_t used;
+ uint16_t session_id;
+ uint16_t stream_id;
+ struct list_head vb2_buff_head;
+ struct list_head native_buff_head;
+};
+
+struct vpe_device {
+ struct platform_device *pdev;
+ struct msm_sd_subdev msm_sd;
+ struct v4l2_subdev subdev;
+ struct resource *mem;
+ struct resource *irq;
+ void __iomem *base;
+ struct clk **vpe_clk;
+ struct regulator *fs_vpe;
+ struct mutex mutex;
+ enum vpe_state state;
+
+ int domain_num;
+ struct iommu_domain *domain;
+ struct device *iommu_ctx_src;
+ struct device *iommu_ctx_dst;
+ struct ion_client *client;
+ struct kref refcount;
+
+ /* Reusing proven tasklet from msm isp */
+ atomic_t irq_cnt;
+ uint8_t taskletq_idx;
+ spinlock_t tasklet_lock;
+ struct list_head tasklet_q;
+ struct tasklet_struct vpe_tasklet;
+ struct msm_vpe_tasklet_queue_cmd
+ tasklet_queue_cmd[MSM_VPE_TASKLETQ_SIZE];
+
+ struct vpe_subscribe_info vpe_subscribe_list[MAX_ACTIVE_VPE_INSTANCE];
+ uint32_t vpe_open_cnt;
+
+ struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
+
+ /*
+ * Processing Queue: store frame info for frames sent to
+ * microcontroller
+ */
+ struct msm_device_queue processing_q;
+
+ struct msm_vpe_buff_queue_info_t *buff_queue;
+ uint32_t num_buffq;
+ struct v4l2_subdev *buf_mgr_subdev;
+};
+
+#endif /* __MSM_VPE_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index e1b978f..b115738 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -629,6 +629,9 @@
return msm_actuator_get_subdev_id(a_ctrl, argp);
case VIDIOC_MSM_ACTUATOR_CFG:
return msm_actuator_config(a_ctrl, argp);
+ case MSM_SD_SHUTDOWN:
+ msm_actuator_close(sd, NULL);
+ return 0;
default:
return -ENOIOCTLCMD;
}
@@ -710,6 +713,7 @@
media_entity_init(&act_ctrl_t->msm_sd.sd.entity, 0, NULL, 0);
act_ctrl_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
act_ctrl_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR;
+ act_ctrl_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
msm_sd_register(&act_ctrl_t->msm_sd);
CDBG("succeeded\n");
CDBG("Exit\n");
@@ -780,6 +784,7 @@
media_entity_init(&msm_actuator_t->msm_sd.sd.entity, 0, NULL, 0);
msm_actuator_t->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
msm_actuator_t->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_ACTUATOR;
+ msm_actuator_t->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
msm_sd_register(&msm_actuator_t->msm_sd);
CDBG("Exit\n");
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
index 642df76..591c464 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cam_cci_hwreg.h
@@ -43,10 +43,6 @@
#define CCI_IRQ_MASK_0_RMSK 0x7fff7ff7
#define CCI_IRQ_CLEAR_0_ADDR 0x00000c08
#define CCI_IRQ_STATUS_0_ADDR 0x00000c0c
-#define CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR_BMSK 0x40000000
-#define CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR_BMSK 0x20000000
-#define CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR_BMSK 0x10000000
-#define CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR_BMSK 0x8000000
#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK 0x4000000
#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK 0x2000000
#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK 0x1000000
@@ -55,6 +51,8 @@
#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK 0x1000
#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK 0x100
#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10
+#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6
+#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000
#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1
#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x00000c00
#endif /* __MSM_CAM_CCI_HWREG__ */
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 9300ce0..f3da41c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -271,6 +271,21 @@
master = c_ctrl->cci_info->cci_i2c_master;
read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
mutex_lock(&cci_dev->cci_master_info[master].mutex);
+
+ /*
+ * Call validate queue to make sure queue is empty before starting.
+ * If this call fails, don't proceed with i2c_read call. This is to
+ * avoid overflow / underflow of queue
+ */
+ rc = msm_cci_validate_queue(cci_dev,
+ cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1,
+ master, queue);
+ if (rc < 0) {
+ pr_err("%s:%d Initial validataion failed rc %d\n", __func__,
+ __LINE__, rc);
+ goto ERROR;
+ }
+
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,
@@ -450,6 +465,21 @@
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);
+
+ /*
+ * Call validate queue to make sure queue is empty before starting.
+ * If this call fails, don't proceed with i2c_write call. This is to
+ * avoid overflow / underflow of queue
+ */
+ rc = msm_cci_validate_queue(cci_dev,
+ cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1,
+ master, queue);
+ if (rc < 0) {
+ pr_err("%s:%d Initial validataion failed rc %d\n", __func__,
+ __LINE__, rc);
+ goto ERROR;
+ }
+
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;
@@ -694,16 +724,6 @@
(irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK)) {
cci_dev->cci_master_info[MASTER_1].status = 0;
complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
- } else if ((irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR_BMSK) ||
- (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR_BMSK)) {
- cci_dev->cci_master_info[MASTER_0].status = -EINVAL;
- msm_camera_io_w(CCI_M0_HALT_REQ_RMSK,
- cci_dev->base + CCI_HALT_REQ_ADDR);
- } else if ((irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR_BMSK) ||
- (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR_BMSK)) {
- cci_dev->cci_master_info[MASTER_1].status = -EINVAL;
- msm_camera_io_w(CCI_M1_HALT_REQ_RMSK,
- cci_dev->base + CCI_HALT_REQ_ADDR);
} else if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
msm_camera_io_w(CCI_M0_RESET_RMSK,
@@ -712,6 +732,16 @@
cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE;
msm_camera_io_w(CCI_M1_RESET_RMSK,
cci_dev->base + CCI_RESET_CMD_ADDR);
+ } else if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) {
+ pr_err("%s:%d MASTER_0 error %x\n", __func__, __LINE__, irq);
+ cci_dev->cci_master_info[MASTER_0].status = -EINVAL;
+ msm_camera_io_w(CCI_M0_HALT_REQ_RMSK,
+ cci_dev->base + CCI_HALT_REQ_ADDR);
+ } else if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) {
+ pr_err("%s:%d MASTER_1 error %x\n", __func__, __LINE__, irq);
+ cci_dev->cci_master_info[MASTER_1].status = -EINVAL;
+ msm_camera_io_w(CCI_M1_HALT_REQ_RMSK,
+ cci_dev->base + CCI_HALT_REQ_ADDR);
} else {
pr_err("%s unhandled irq 0x%x\n", __func__, irq);
cci_dev->cci_master_info[MASTER_0].status = 0;
@@ -743,6 +773,12 @@
case VIDIOC_MSM_CCI_CFG:
rc = msm_cci_config(sd, arg);
break;
+ case MSM_SD_SHUTDOWN: {
+ struct msm_camera_cci_ctrl ctrl_cmd;
+ ctrl_cmd.cmd = MSM_CCI_RELEASE;
+ rc = msm_cci_config(sd, &ctrl_cmd);
+ break;
+ }
default:
rc = -ENOIOCTLCMD;
}
@@ -977,6 +1013,7 @@
goto cci_release_mem;
}
disable_irq(new_cci_dev->irq->start);
+ new_cci_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x6;
msm_sd_register(&new_cci_dev->msm_sd);
new_cci_dev->pdev = pdev;
msm_cci_init_cci_params(new_cci_dev);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 33eaa69..4db6855 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -460,6 +460,7 @@
rc = msm_csid_cmd(csid_dev, arg);
break;
case VIDIOC_MSM_CSID_RELEASE:
+ case MSM_SD_SHUTDOWN:
rc = msm_csid_release(csid_dev);
break;
default:
@@ -552,6 +553,7 @@
media_entity_init(&new_csid_dev->msm_sd.sd.entity, 0, NULL, 0);
new_csid_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
new_csid_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSID;
+ new_csid_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x5;
msm_sd_register(&new_csid_dev->msm_sd);
rc = request_irq(new_csid_dev->irq->start, msm_csid_irq,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 7d3a1fc..429d151 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -570,6 +570,7 @@
rc = msm_csiphy_cmd(csiphy_dev, arg);
break;
case VIDIOC_MSM_CSIPHY_RELEASE:
+ case MSM_SD_SHUTDOWN:
rc = msm_csiphy_release(csiphy_dev, arg);
break;
default:
@@ -665,7 +666,7 @@
media_entity_init(&new_csiphy_dev->msm_sd.sd.entity, 0, NULL, 0);
new_csiphy_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
new_csiphy_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_CSIPHY;
-
+ new_csiphy_dev->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x4;
msm_sd_register(&new_csiphy_dev->msm_sd);
new_csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
return 0;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
index 9119a13..044fd31 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.c
@@ -81,6 +81,7 @@
media_entity_init(&fctrl->msm_sd.sd.entity, 0, NULL, 0);
fctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
fctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_LED_FLASH;
+ fctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x1;
msm_sd_register(&fctrl->msm_sd);
CDBG("probe success\n");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/imx135.c b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
index c9476ee..9b02b17 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/imx135.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
@@ -36,6 +36,12 @@
.delay = 0,
},
{
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VAF,
+ .config_val = 0,
+ .delay = 0,
+ },
+ {
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_LOW,
@@ -48,6 +54,18 @@
.delay = 30,
},
{
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 1,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 30,
+ },
+ {
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 0,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index fa63e2b..d56a5252 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -16,6 +16,9 @@
#include "msm_cci.h"
#include "msm_camera_io_util.h"
#include "msm_camera_i2c_mux.h"
+#include <mach/rpm-regulator.h>
+#include <mach/rpm-regulator-smd.h>
+#include <linux/regulator/consumer.h>
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
@@ -774,7 +777,17 @@
sensordata->slave_info->sensor_id_reg_addr = id_info[1];
sensordata->slave_info->sensor_id = id_info[2];
+ rc = of_property_read_string(of_node, "qcom,vdd-cx-name",
+ &sensordata->misc_regulator);
+ CDBG("%s qcom,misc_regulator %s, rc %d\n", __func__,
+ sensordata->misc_regulator, rc);
+ if (rc < 0) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ goto ERROR9;
+ }
+
kfree(gpio_array);
+
return rc;
ERROR9:
@@ -799,6 +812,41 @@
return rc;
}
+static void msm_sensor_misc_regulator(
+ struct msm_sensor_ctrl_t *sctrl, uint32_t enable)
+{
+ int32_t rc = 0;
+ if (enable) {
+ sctrl->misc_regulator = (void *)rpm_regulator_get(
+ &sctrl->pdev->dev, sctrl->sensordata->misc_regulator);
+ if (sctrl->misc_regulator) {
+ rc = rpm_regulator_set_mode(sctrl->misc_regulator,
+ RPM_REGULATOR_MODE_HPM);
+ if (rc < 0) {
+ pr_err("%s: Failed to set for rpm regulator on %s: %d\n",
+ __func__,
+ sctrl->sensordata->misc_regulator, rc);
+ rpm_regulator_put(sctrl->misc_regulator);
+ }
+ } else {
+ pr_err("%s: Failed to vote for rpm regulator on %s: %d\n",
+ __func__,
+ sctrl->sensordata->misc_regulator, rc);
+ }
+ } else {
+ if (sctrl->misc_regulator) {
+ rc = rpm_regulator_set_mode(
+ (struct rpm_regulator *)sctrl->misc_regulator,
+ RPM_REGULATOR_MODE_AUTO);
+ if (rc < 0)
+ pr_err("%s: Failed to set for rpm regulator on %s: %d\n",
+ __func__,
+ sctrl->sensordata->misc_regulator, rc);
+ rpm_regulator_put(sctrl->misc_regulator);
+ }
+ }
+}
+
int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl)
{
if (!s_ctrl->pdev)
@@ -814,6 +862,7 @@
kfree(s_ctrl->sensordata->sensor_info);
kfree(s_ctrl->sensordata->sensor_init_params);
kfree(s_ctrl->sensordata);
+ kfree(s_ctrl->clk_info);
return 0;
}
@@ -1001,6 +1050,7 @@
struct msm_sensor_power_setting_array *power_setting_array = NULL;
struct msm_sensor_power_setting *power_setting = NULL;
struct msm_camera_sensor_board_info *data = s_ctrl->sensordata;
+ s_ctrl->stop_setting_valid = 0;
CDBG("%s:%d\n", __func__, __LINE__);
power_setting_array = &s_ctrl->power_setting_array;
@@ -1100,9 +1150,13 @@
static void msm_sensor_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
{
- s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
- s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting);
- kfree(s_ctrl->stop_setting.reg_setting);
+ mutex_lock(s_ctrl->msm_sensor_mutex);
+ if (s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) {
+ s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+ s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting);
+ kfree(s_ctrl->stop_setting.reg_setting);
+ }
+ mutex_unlock(s_ctrl->msm_sensor_mutex);
return;
}
@@ -1119,6 +1173,7 @@
case VIDIOC_MSM_SENSOR_CFG:
return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
case VIDIOC_MSM_SENSOR_RELEASE:
+ case MSM_SD_SHUTDOWN:
msm_sensor_stop_stream(s_ctrl);
return 0;
default:
@@ -1233,6 +1288,13 @@
struct msm_camera_i2c_reg_setting conf_array;
struct msm_camera_i2c_reg_array *reg_setting = NULL;
+ if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+ pr_err("%s:%d failed: invalid state %d\n", __func__,
+ __LINE__, s_ctrl->sensor_state);
+ rc = -EFAULT;
+ break;
+ }
+
if (copy_from_user(&conf_array,
(void *)cdata->cfg.setting,
sizeof(struct msm_camera_i2c_reg_setting))) {
@@ -1267,6 +1329,13 @@
struct msm_camera_i2c_seq_reg_setting conf_array;
struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
+ if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+ pr_err("%s:%d failed: invalid state %d\n", __func__,
+ __LINE__, s_ctrl->sensor_state);
+ rc = -EFAULT;
+ break;
+ }
+
if (copy_from_user(&conf_array,
(void *)cdata->cfg.setting,
sizeof(struct msm_camera_i2c_seq_reg_setting))) {
@@ -1301,18 +1370,54 @@
}
case CFG_POWER_UP:
- if (s_ctrl->func_tbl->sensor_power_up)
- rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
- else
+ if (s_ctrl->sensor_state != MSM_SENSOR_POWER_DOWN) {
+ pr_err("%s:%d failed: invalid state %d\n", __func__,
+ __LINE__, s_ctrl->sensor_state);
rc = -EFAULT;
+ break;
+ }
+ if (s_ctrl->func_tbl->sensor_power_up) {
+ if (s_ctrl->sensordata->misc_regulator)
+ msm_sensor_misc_regulator(s_ctrl, 1);
+
+ rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+ if (rc < 0) {
+ pr_err("%s:%d failed rc %ld\n", __func__,
+ __LINE__, rc);
+ break;
+ }
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_UP;
+ pr_err("%s:%d sensor state %d\n", __func__, __LINE__,
+ s_ctrl->sensor_state);
+ } else {
+ rc = -EFAULT;
+ }
break;
case CFG_POWER_DOWN:
- if (s_ctrl->func_tbl->sensor_power_down)
+ if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
+ pr_err("%s:%d failed: invalid state %d\n", __func__,
+ __LINE__, s_ctrl->sensor_state);
+ rc = -EFAULT;
+ break;
+ }
+ if (s_ctrl->func_tbl->sensor_power_down) {
+ if (s_ctrl->sensordata->misc_regulator)
+ msm_sensor_misc_regulator(s_ctrl, 0);
+
rc = s_ctrl->func_tbl->sensor_power_down(
s_ctrl);
- else
+ if (rc < 0) {
+ pr_err("%s:%d failed rc %ld\n", __func__,
+ __LINE__, rc);
+ break;
+ }
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
+ pr_err("%s:%d sensor state %d\n", __func__, __LINE__,
+ s_ctrl->sensor_state);
+ } else {
rc = -EFAULT;
+ }
break;
case CFG_SET_STOP_STREAM_SETTING: {
@@ -1326,6 +1431,7 @@
rc = -EFAULT;
break;
}
+ s_ctrl->stop_setting_valid = 1;
reg_setting = stop_setting->reg_setting;
stop_setting->reg_setting = kzalloc(stop_setting->size *
@@ -1363,8 +1469,10 @@
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);
+ if (!on && s_ctrl->sensor_state == MSM_SENSOR_POWER_UP) {
+ s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ s_ctrl->sensor_state = MSM_SENSOR_POWER_DOWN;
+ }
if (s_ctrl->free_power_setting == true) {
kfree(s_ctrl->power_setting_array.power_setting);
s_ctrl->free_power_setting = false;
@@ -1468,12 +1576,20 @@
&msm_sensor_cci_func_tbl;
if (!s_ctrl->sensor_v4l2_subdev_ops)
s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
- s_ctrl->clk_info = cam_8974_clk_info;
+ s_ctrl->clk_info = kzalloc(sizeof(cam_8974_clk_info),
+ GFP_KERNEL);
+ if (!s_ctrl->clk_info) {
+ pr_err("%s:%d failed nomem\n", __func__, __LINE__);
+ kfree(cci_client);
+ return -ENOMEM;
+ }
+ memcpy(s_ctrl->clk_info, cam_8974_clk_info, sizeof(cam_8974_clk_info));
s_ctrl->clk_info_size = ARRAY_SIZE(cam_8974_clk_info);
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
if (rc < 0) {
pr_err("%s %s power up failed\n", __func__,
s_ctrl->sensordata->sensor_name);
+ kfree(s_ctrl->clk_info);
kfree(cci_client);
return rc;
}
@@ -1496,6 +1612,7 @@
rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
s_ctrl->sensordata->sensor_info->session_id = session_id;
+ s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
msm_sd_register(&s_ctrl->msm_sd);
CDBG("%s:%d\n", __func__, __LINE__);
@@ -1554,12 +1671,19 @@
if (!s_ctrl->sensor_v4l2_subdev_ops)
s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
- s_ctrl->clk_info = cam_8960_clk_info;
+ s_ctrl->clk_info = kzalloc(sizeof(cam_8960_clk_info),
+ GFP_KERNEL);
+ if (!s_ctrl->clk_info) {
+ pr_err("%s:%d failed nomem\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ memcpy(s_ctrl->clk_info, cam_8960_clk_info, sizeof(cam_8960_clk_info));
s_ctrl->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
if (rc < 0) {
pr_err("%s %s power up failed\n", __func__, client->name);
+ kfree(s_ctrl->clk_info);
return rc;
}
@@ -1580,6 +1704,7 @@
&session_id);
CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
s_ctrl->sensordata->sensor_info->session_id = session_id;
+ s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
msm_sd_register(&s_ctrl->msm_sd);
CDBG("%s:%d\n", __func__, __LINE__);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
index 6c36e47d..fe11a56 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
@@ -37,6 +37,11 @@
struct msm_sensor_ctrl_t;
+enum msm_sensor_state_t {
+ MSM_SENSOR_POWER_DOWN,
+ MSM_SENSOR_POWER_UP,
+};
+
struct msm_sensor_fn_t {
int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
int (*sensor_power_down)
@@ -62,9 +67,12 @@
struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
struct msm_sensor_fn_t *func_tbl;
struct msm_camera_i2c_reg_setting stop_setting;
+ bool stop_setting_valid;
bool free_power_setting;
struct msm_cam_clk_info *clk_info;
uint16_t clk_info_size;
+ void *misc_regulator;
+ enum msm_sensor_state_t sensor_state;
};
int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index b56378a..5b385a0 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -4772,6 +4772,12 @@
mutex_lock(&mpq_demux->mutex);
mpq_feed = feed->priv;
+ if (!dvb_dmx_is_video_feed(feed) && !dvb_dmx_is_pcr_feed(feed) &&
+ !feed->secure_mode.is_secured) {
+ mutex_unlock(&mpq_demux->mutex);
+ return 0;
+ }
+
event.data_length = 0;
switch (cmd->type) {
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 82a4f3c..42d4f95 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -45,6 +45,22 @@
[ilog2(HAL_H264_CABAC_MODEL_2)] = HFI_H264_CABAC_MODEL_2,
};
+static int color_format[] = {
+ [ilog2(HAL_COLOR_FORMAT_MONOCHROME)] = HFI_COLOR_FORMAT_MONOCHROME,
+ [ilog2(HAL_COLOR_FORMAT_NV12)] = HFI_COLOR_FORMAT_NV12,
+ [ilog2(HAL_COLOR_FORMAT_NV21)] = HFI_COLOR_FORMAT_NV21,
+ [ilog2(HAL_COLOR_FORMAT_NV12_4x4TILE)] = HFI_COLOR_FORMAT_NV12_4x4TILE,
+ [ilog2(HAL_COLOR_FORMAT_NV21_4x4TILE)] = HFI_COLOR_FORMAT_NV21_4x4TILE,
+ [ilog2(HAL_COLOR_FORMAT_YUYV)] = HFI_COLOR_FORMAT_YUYV,
+ [ilog2(HAL_COLOR_FORMAT_YVYU)] = HFI_COLOR_FORMAT_YVYU,
+ [ilog2(HAL_COLOR_FORMAT_UYVY)] = HFI_COLOR_FORMAT_UYVY,
+ [ilog2(HAL_COLOR_FORMAT_VYUY)] = HFI_COLOR_FORMAT_VYUY,
+ [ilog2(HAL_COLOR_FORMAT_RGB565)] = HFI_COLOR_FORMAT_RGB565,
+ [ilog2(HAL_COLOR_FORMAT_BGR565)] = HFI_COLOR_FORMAT_BGR565,
+ [ilog2(HAL_COLOR_FORMAT_RGB888)] = HFI_COLOR_FORMAT_RGB888,
+ [ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888,
+};
+
static inline int hal_to_hfi_type(int property, int hal_type)
{
if (hal_type && (roundup_pow_of_two(hal_type) != hal_type)) {
@@ -66,6 +82,9 @@
case HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL:
return (hal_type >= ARRAY_SIZE(cabac_model)) ?
-ENOTSUPP : cabac_model[hal_type];
+ case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+ return (hal_type >= ARRAY_SIZE(color_format)) ?
+ -ENOTSUPP : color_format[hal_type];
default:
return -ENOTSUPP;
}
@@ -632,11 +651,13 @@
hfi->buffer_type = buffer_type;
else
return -EINVAL;
- hfi->format = prop->format;
+ hfi->format = hal_to_hfi_type(
+ HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+ prop->format);
pkt->size += sizeof(u32) +
sizeof(struct hfi_uncompressed_format_select);
break;
- }
+ }
case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO:
break;
case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 511a478..1885379 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -1498,6 +1498,6 @@
kfree(curr->cluster);
kfree(curr);
}
-
+ v4l2_ctrl_handler_free(&inst->ctrl_handler);
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index b6e77dc..20cb08d 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -687,7 +687,7 @@
static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
{
- return height * width * 2;
+ return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height);
}
static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
@@ -2035,7 +2035,6 @@
int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
struct msm_vidc_format *fmt = NULL;
- struct hal_frame_size frame_sz;
int rc = 0;
int i;
struct hfi_device *hdev;
@@ -2063,6 +2062,9 @@
goto exit;
}
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ struct hal_uncompressed_format_select hal_fmt = {0};
+ struct hal_frame_size frame_sz;
+
inst->prop.width = f->fmt.pix_mp.width;
inst->prop.height = f->fmt.pix_mp.height;
rc = msm_vidc_check_session_supported(inst);
@@ -2101,6 +2103,29 @@
rc = -EINVAL;
goto exit;
}
+
+ switch (fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ hal_fmt.format = HAL_COLOR_FORMAT_NV12;
+ break;
+ case V4L2_PIX_FMT_NV21:
+ hal_fmt.format = HAL_COLOR_FORMAT_NV21;
+ break;
+ default:
+ /* we really shouldn't be here */
+ rc = -ENOTSUPP;
+ goto exit;
+ }
+
+ hal_fmt.buffer_type = HAL_BUFFER_INPUT;
+ rc = call_hfi_op(hdev, session_set_property, (void *)
+ inst->session, HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+ &hal_fmt);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to set input color format\n");
+ goto exit;
+ }
}
if (fmt) {
@@ -2516,6 +2541,6 @@
kfree(curr->cluster);
kfree(curr);
}
-
+ v4l2_ctrl_handler_free(&inst->ctrl_handler);
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 0fbfd72..1c43f1e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -565,6 +565,7 @@
struct msm_vidc_core *core;
struct list_head *ptr, *next;
int rc = 0;
+ int i;
if (!inst)
return -EINVAL;
@@ -592,6 +593,9 @@
if (rc)
dprintk(VIDC_ERR,
"Failed to move video instance to uninit state\n");
+ for (i = 0; i < MAX_PORT_NUM; i++)
+ vb2_queue_release(&inst->bufq[i].vb2_bufq);
+
pr_info(VIDC_DBG_TAG "Closed video instance: %p\n", VIDC_INFO, inst);
kfree(inst);
return 0;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 39d73ca..91fcdb6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -61,8 +61,29 @@
if (inst->session_type == type &&
inst->state >= MSM_VIDC_OPEN_DONE &&
inst->state < MSM_VIDC_STOP_DONE) {
- num_mbs_per_sec += NUM_MBS_PER_SEC(inst->prop.height,
- inst->prop.width, inst->prop.fps);
+ int stride, scanlines, rc;
+ struct hfi_device *hdev;
+
+ hdev = inst->core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR,
+ "No hdev (probably in bad state)\n");
+ return -EINVAL;
+ }
+
+ rc = call_hfi_op(hdev, get_stride_scanline,
+ COLOR_FMT_NV12,
+ inst->prop.width, inst->prop.height,
+ &stride, &scanlines);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to determine stride/scan when getting load. Perf. might be affected\n");
+ stride = inst->prop.width;
+ scanlines = inst->prop.height;
+ }
+
+ num_mbs_per_sec += NUM_MBS_PER_SEC(stride, scanlines,
+ inst->prop.fps);
}
mutex_unlock(&inst->lock);
}
@@ -313,6 +334,7 @@
msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
if (!rc) {
dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
+ msm_comm_recover_from_session_error(inst);
rc = -EIO;
} else {
rc = 0;
@@ -343,7 +365,7 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- if (response) {
+ if (response && !response->status) {
struct vidc_hal_session_init_done *session_init_done =
(struct vidc_hal_session_init_done *) response->data;
inst = (struct msm_vidc_inst *)response->session_id;
@@ -1230,7 +1252,8 @@
}
mutex_unlock(&temp->lock);
}
-
+ inst->state = MSM_VIDC_CORE_INVALID;
+ msm_comm_recover_from_session_error(inst);
return -ENOMEM;
}
@@ -1882,6 +1905,8 @@
if (!rc) {
dprintk(VIDC_ERR,
"Wait interrupted or timeout: %d\n", rc);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ msm_comm_recover_from_session_error(inst);
rc = -EIO;
goto exit;
}
@@ -1942,6 +1967,13 @@
mutex_unlock(&inst->lock);
rc = wait_for_sess_signal_receipt(inst,
SESSION_RELEASE_BUFFER_DONE);
+ if (rc) {
+ mutex_lock(&inst->sync_lock);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ mutex_unlock(&inst->sync_lock);
+ msm_comm_recover_from_session_error(
+ inst);
+ }
mutex_lock(&inst->lock);
}
list_del(&buf->list);
@@ -2006,6 +2038,13 @@
mutex_unlock(&inst->lock);
rc = wait_for_sess_signal_receipt(inst,
SESSION_RELEASE_BUFFER_DONE);
+ if (rc) {
+ mutex_lock(&inst->sync_lock);
+ inst->state = MSM_VIDC_CORE_INVALID;
+ mutex_unlock(&inst->sync_lock);
+ msm_comm_recover_from_session_error(
+ inst);
+ }
mutex_lock(&inst->lock);
}
list_del(&buf->list);
@@ -2344,38 +2383,27 @@
struct msm_vidc_core_capability *capability;
int rc = 0;
struct v4l2_event dqevent;
+ struct hfi_device *hdev;
- if (!inst) {
+ if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
return -EINVAL;
}
capability = &inst->capability;
+ hdev = inst->core->device;
if (inst->capability.capability_set) {
- if (msm_vp8_low_tier &&
- inst->core->hfi_type == VIDC_HFI_VENUS &&
- inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_VP8) {
- capability->width.max = DEFAULT_WIDTH;
- capability->height.max = DEFAULT_HEIGHT;
- }
- if (inst->prop.width < capability->width.min ||
- inst->prop.width > capability->width.max ||
- (inst->prop.width % capability->width.step_size != 0)) {
- dprintk(VIDC_ERR,
- "Unsupported width = %d range min(%u) - max(%u) step_size(%u)",
- inst->prop.width, capability->width.min,
- capability->width.max, capability->width.step_size);
- rc = -ENOTSUPP;
- }
+ rc = call_hfi_op(hdev, capability_check,
+ inst->fmts[OUTPUT_PORT]->fourcc,
+ inst->prop.width, &capability->width.max,
+ &capability->height.max);
- if (inst->prop.height < capability->height.min ||
- inst->prop.height > capability->height.max ||
- (inst->prop.height %
- capability->height.step_size != 0)) {
+ if (!rc && (inst->prop.height * inst->prop.width >
+ capability->width.max * capability->height.max)) {
dprintk(VIDC_ERR,
- "Unsupported height = %d range min(%u) - max(%u) step_size(%u)",
- inst->prop.height, capability->height.min,
- capability->height.max, capability->height.step_size);
+ "Unsupported WxH = (%u)x(%u), Max supported is - (%u)x(%u)",
+ inst->prop.width, inst->prop.height,
+ capability->width.max, capability->height.max);
rc = -ENOTSUPP;
}
}
@@ -2391,6 +2419,20 @@
return rc;
}
+static void msm_comm_generate_sys_error(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core;
+ enum command_response cmd = SYS_ERROR;
+ struct msm_vidc_cb_cmd_done response = {0};
+ if (!inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
+ return;
+ }
+ core = inst->core;
+ response.device_id = (u32) core->id;
+ handle_sys_error(cmd, (void *) &response);
+
+}
int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst)
{
struct hfi_device *hdev;
@@ -2400,6 +2442,12 @@
dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
return -EINVAL;
}
+ if (inst->state < MSM_VIDC_OPEN_DONE) {
+ dprintk(VIDC_WARN,
+ "No corresponding FW session. No need to send Abort");
+ inst->state = MSM_VIDC_CORE_INVALID;
+ return rc;
+ }
hdev = inst->core->device;
init_completion(&inst->completions[SESSION_MSG_INDEX
@@ -2413,10 +2461,14 @@
dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc);
return rc;
}
-
- rc = wait_for_sess_signal_receipt(inst, SESSION_ABORT_DONE);
- if (rc)
+ rc = wait_for_completion_timeout(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_ABORT_DONE)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
__func__, rc);
+ msm_comm_generate_sys_error(inst);
+ } else
+ change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 123b654..577b2b5 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -362,17 +362,18 @@
void q6_hfi_delete_device(void *device)
{
- struct q6_hfi_device *close, *dev;
+ struct q6_hfi_device *close, *tmp, *dev;
if (device) {
q6_hfi_deinit_resources(device);
dev = (struct q6_hfi_device *) device;
- list_for_each_entry(close, &hal_ctxt.dev_head, list) {
+ list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
if (close->device_id == dev->device_id) {
hal_ctxt.dev_count--;
list_del(&close->list);
destroy_workqueue(close->vidc_workq);
kfree(close);
+ break;
}
}
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index b96a6dc..bc5adc11 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -217,9 +217,12 @@
packet + ((packet_size_in_words - new_write_idx) << 2),
new_write_idx << 2);
}
+ /* Memory barrier to make sure packet is written before updating the
+ * write index */
+ mb();
queue->qhdr_write_idx = new_write_idx;
*rx_req_is_set = (1 == queue->qhdr_rx_req) ? 1 : 0;
- /*Memory barrier to make sure data is written before an
+ /*Memory barrier to make sure write index is updated before an
* interupt is raised on venus.*/
mb();
dprintk(VIDC_DBG, "Out : ");
@@ -2846,6 +2849,28 @@
return 0;
}
+int venus_hfi_capability_check(u32 fourcc, u32 width,
+ u32 *max_width, u32 *max_height)
+{
+ int rc = 0;
+ if (!max_width || !max_height) {
+ dprintk(VIDC_ERR, "%s - invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ if (msm_vp8_low_tier && fourcc == V4L2_PIX_FMT_VP8) {
+ *max_width = DEFAULT_WIDTH;
+ *max_height = DEFAULT_HEIGHT;
+ }
+ if (width > *max_width) {
+ dprintk(VIDC_ERR,
+ "Unsupported width = %u supported max width = %u",
+ width, *max_width);
+ rc = -ENOTSUPP;
+ }
+ return rc;
+}
+
static void *venus_hfi_add_device(u32 device_id,
struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback)
@@ -2928,12 +2953,12 @@
void venus_hfi_delete_device(void *device)
{
- struct venus_hfi_device *close, *dev;
+ struct venus_hfi_device *close, *tmp, *dev;
if (device) {
venus_hfi_deinit_resources(device);
dev = (struct venus_hfi_device *) device;
- list_for_each_entry(close, &hal_ctxt.dev_head, list) {
+ list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
if (close->hal_data->irq == dev->hal_data->irq) {
hal_ctxt.dev_count--;
free_irq(dev->hal_data->irq, close);
@@ -2985,6 +3010,7 @@
hdev->unload_fw = venus_hfi_unload_fw;
hdev->get_fw_info = venus_hfi_get_fw_info;
hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
+ hdev->capability_check = venus_hfi_capability_check;
}
int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index bf1c70b..01395e5 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -391,20 +391,20 @@
};
enum hal_uncompressed_format {
- HAL_COLOR_FORMAT_MONOCHROME,
- HAL_COLOR_FORMAT_NV12,
- HAL_COLOR_FORMAT_NV21,
- HAL_COLOR_FORMAT_NV12_4x4TILE,
- HAL_COLOR_FORMAT_NV21_4x4TILE,
- HAL_COLOR_FORMAT_YUYV,
- HAL_COLOR_FORMAT_YVYU,
- HAL_COLOR_FORMAT_UYVY,
- HAL_COLOR_FORMAT_VYUY,
- HAL_COLOR_FORMAT_RGB565,
- HAL_COLOR_FORMAT_BGR565,
- HAL_COLOR_FORMAT_RGB888,
- HAL_COLOR_FORMAT_BGR888,
- HAL_UNUSED_COLOR = 0x10000000,
+ HAL_COLOR_FORMAT_MONOCHROME = 0x00000001,
+ HAL_COLOR_FORMAT_NV12 = 0x00000002,
+ HAL_COLOR_FORMAT_NV21 = 0x00000004,
+ HAL_COLOR_FORMAT_NV12_4x4TILE = 0x00000008,
+ HAL_COLOR_FORMAT_NV21_4x4TILE = 0x00000010,
+ HAL_COLOR_FORMAT_YUYV = 0x00000020,
+ HAL_COLOR_FORMAT_YVYU = 0x00000040,
+ HAL_COLOR_FORMAT_UYVY = 0x00000080,
+ HAL_COLOR_FORMAT_VYUY = 0x00000100,
+ HAL_COLOR_FORMAT_RGB565 = 0x00000200,
+ HAL_COLOR_FORMAT_BGR565 = 0x00000400,
+ HAL_COLOR_FORMAT_RGB888 = 0x00000800,
+ HAL_COLOR_FORMAT_BGR888 = 0x00001000,
+ HAL_UNUSED_COLOR = 0x10000000,
};
enum hal_ssr_trigger_type {
@@ -1075,6 +1075,8 @@
int (*get_fw_info)(void *dev, enum fw_info info);
int (*get_stride_scanline)(int color_fmt, int width,
int height, int *stride, int *scanlines);
+ int (*capability_check)(u32 fourcc, u32 width,
+ u32 *max_width, u32 *max_height);
};
typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index fcadc30..9bc77be 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -278,63 +278,24 @@
svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
svc->sb_phys = pa;
- if (qseecom.qseos_version == QSEOS_VERSION_14) {
- req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
- req.listener_id = svc->svc.listener_id;
- req.sb_len = svc->sb_length;
- req.sb_ptr = (void *)svc->sb_phys;
+ req.qsee_cmd_id = QSEOS_REGISTER_LISTENER;
+ req.listener_id = svc->svc.listener_id;
+ req.sb_len = svc->sb_length;
+ req.sb_ptr = (void *)svc->sb_phys;
- resp.result = QSEOS_RESULT_INCOMPLETE;
+ resp.result = QSEOS_RESULT_INCOMPLETE;
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
sizeof(req), &resp, sizeof(resp));
- if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
- return -EINVAL;
- }
+ if (ret) {
+ pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ return -EINVAL;
+ }
- if (resp.result != QSEOS_RESULT_SUCCESS) {
- pr_err("Error SB registration req: resp.result = %d\n",
- resp.result);
- return -EPERM;
- }
- } else {
- struct qseecom_command cmd;
- struct qseecom_response resp;
- struct qse_pr_init_sb_req_s sb_init_req;
- struct qse_pr_init_sb_rsp_s sb_init_rsp;
-
- svc->sb_reg_req = kzalloc((sizeof(sb_init_req) +
- sizeof(sb_init_rsp)), GFP_KERNEL);
-
- sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
- sb_init_req.listener_id = svc->svc.listener_id;
- sb_init_req.sb_len = svc->sb_length;
- sb_init_req.sb_ptr = svc->sb_phys;
-
- memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
-
- /* It will always be a new cmd from this method */
- cmd.cmd_type = TZ_SCHED_CMD_NEW;
- cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
- cmd.sb_in_cmd_len = sizeof(sb_init_req);
-
- resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
-
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd)
- , &resp, sizeof(resp));
-
- if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
- return -EINVAL;
- }
-
- if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
- pr_err("SB registration fail resp.cmd_status %d\n",
- resp.cmd_status);
- return -EINVAL;
- }
- memset(svc->sb_virt, 0, svc->sb_length);
+ if (resp.result != QSEOS_RESULT_SUCCESS) {
+ pr_err("Error SB registration req: resp.result = %d\n",
+ resp.result);
+ return -EPERM;
}
return 0;
}
@@ -396,56 +357,24 @@
struct qseecom_command_scm_resp resp;
struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
- if (qseecom.qseos_version == QSEOS_VERSION_14) {
- req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
- req.listener_id = data->listener.id;
- resp.result = QSEOS_RESULT_INCOMPLETE;
+ req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
+ req.listener_id = data->listener.id;
+ resp.result = QSEOS_RESULT_INCOMPLETE;
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
sizeof(req), &resp, sizeof(resp));
- if (ret) {
- pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
- ret, data->listener.id);
- return ret;
- }
-
- if (resp.result != QSEOS_RESULT_SUCCESS) {
- pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
- resp.result, data->listener.id);
- return -EPERM;
- }
- } else {
- struct qse_pr_init_sb_req_s sb_init_req;
- struct qseecom_command cmd;
- struct qseecom_response resp;
- struct qseecom_registered_listener_list *svc;
-
- svc = __qseecom_find_svc(data->listener.id);
- sb_init_req.pr_cmd = TZ_SCHED_CMD_ID_REGISTER_LISTENER;
- sb_init_req.listener_id = data->listener.id;
- sb_init_req.sb_len = 0;
- sb_init_req.sb_ptr = 0;
-
- memcpy(svc->sb_reg_req, &sb_init_req, sizeof(sb_init_req));
-
- /* It will always be a new cmd from this method */
- cmd.cmd_type = TZ_SCHED_CMD_NEW;
- cmd.sb_in_cmd_addr = (u8 *)(virt_to_phys(svc->sb_reg_req));
- cmd.sb_in_cmd_len = sizeof(sb_init_req);
- resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
-
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, &cmd, sizeof(cmd),
- &resp, sizeof(resp));
- if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
- return ret;
- }
- kzfree(svc->sb_reg_req);
- if (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
- pr_err("Error with SB initialization\n");
- return -EPERM;
- }
+ if (ret) {
+ pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
+ ret, data->listener.id);
+ return ret;
}
+
+ if (resp.result != QSEOS_RESULT_SUCCESS) {
+ pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
+ resp.result, data->listener.id);
+ return -EPERM;
+ }
+
data->abort = 1;
spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
@@ -540,6 +469,8 @@
unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp;
struct qseecom_registered_listener_list *ptr_svc = NULL;
+ sigset_t new_sigset;
+ sigset_t old_sigset;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
@@ -564,17 +495,24 @@
}
pr_debug("waking up rcv_req_wq and "
"waiting for send_resp_wq\n");
- if (wait_event_freezable(qseecom.send_resp_wq,
- __qseecom_listener_has_sent_rsp(data))) {
- pr_warning("Interrupted: exiting send_cmd loop\n");
- ret = -ERESTARTSYS;
- }
- if ((data->abort) || (ret == -ERESTARTSYS)) {
+ /* initialize the new signal mask with all signals*/
+ sigfillset(&new_sigset);
+ /* block all signals */
+ sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+
+ do {
+ if (!wait_event_freezable(qseecom.send_resp_wq,
+ __qseecom_listener_has_sent_rsp(data)))
+ break;
+ } while (1);
+
+ /* restore signal mask */
+ sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+ if (data->abort) {
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
- if (data->abort)
- rc = -ENODEV;
+ rc = -ENODEV;
send_data_rsp.status = QSEOS_RESULT_FAILURE;
} else {
send_data_rsp.status = QSEOS_RESULT_SUCCESS;
@@ -821,8 +759,7 @@
bool unload = false;
bool found_app = false;
- if ((qseecom.qseos_version == QSEOS_VERSION_14) &&
- (data->client.app_id > 0)) {
+ if (data->client.app_id > 0) {
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
list) {
@@ -848,7 +785,7 @@
}
}
- if ((unload) && (qseecom.qseos_version == QSEOS_VERSION_14)) {
+ if (unload) {
struct qseecom_unload_app_ireq req;
__qseecom_cleanup_app(data);
@@ -881,19 +818,6 @@
}
}
}
-
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- data->abort = 1;
- wake_up_all(&qseecom.send_resp_wq);
- while (atomic_read(&data->ioctl_count) > 0) {
- if (wait_event_freezable(data->abort_wq,
- atomic_read(&data->ioctl_count) <= 0)) {
- pr_err("Interrupted from abort\n");
- ret = -ERESTARTSYS;
- break;
- }
- }
- }
qseecom_unmap_ion_allocated_memory(data);
data->released = true;
return ret;
@@ -905,98 +829,6 @@
return data->client.sb_phys + (virt - data->client.user_virt_sb_base);
}
-static int __qseecom_send_cmd_legacy(struct qseecom_dev_handle *data,
- struct qseecom_send_cmd_req *req)
-{
- int ret = 0;
- unsigned long flags;
- u32 reqd_len_sb_in = 0;
- struct qseecom_command cmd;
- struct qseecom_response resp;
-
-
- if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
- pr_err("cmd buffer or response buffer is null\n");
- return -EINVAL;
- }
-
- if (req->cmd_req_len <= 0 ||
- req->resp_len <= 0 ||
- req->cmd_req_len > data->client.sb_length ||
- req->resp_len > data->client.sb_length) {
- pr_err("cmd buffer length or "
- "response buffer length not valid\n");
- return -EINVAL;
- }
-
- reqd_len_sb_in = req->cmd_req_len + req->resp_len;
- if (reqd_len_sb_in > data->client.sb_length) {
- pr_debug("Not enough memory to fit cmd_buf and "
- "resp_buf. Required: %u, Available: %u\n",
- reqd_len_sb_in, data->client.sb_length);
- return -ENOMEM;
- }
- cmd.cmd_type = TZ_SCHED_CMD_NEW;
- cmd.sb_in_cmd_addr = (u8 *) data->client.sb_phys;
- cmd.sb_in_cmd_len = req->cmd_req_len;
-
- resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
- resp.sb_in_rsp_addr = (u8 *)data->client.sb_phys + req->cmd_req_len;
- resp.sb_in_rsp_len = req->resp_len;
-
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
- sizeof(cmd), &resp, sizeof(resp));
-
- if (ret) {
- pr_err("qseecom_scm_call_legacy failed with err: %d\n", ret);
- return ret;
- }
-
- while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
- /*
- * If cmd is incomplete, get the callback cmd out from SB out
- * and put it on the list
- */
- struct qseecom_registered_listener_list *ptr_svc = NULL;
- /*
- * We don't know which service can handle the command. so we
- * wake up all blocking services and let them figure out if
- * they can handle the given command.
- */
- spin_lock_irqsave(&qseecom.registered_listener_list_lock,
- flags);
- list_for_each_entry(ptr_svc,
- &qseecom.registered_listener_list_head, list) {
- ptr_svc->rcv_req_flag = 1;
- wake_up_interruptible(&ptr_svc->rcv_req_wq);
- }
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
- flags);
-
- pr_debug("waking up rcv_req_wq and "
- "waiting for send_resp_wq\n");
- if (wait_event_freezable(qseecom.send_resp_wq,
- __qseecom_listener_has_sent_rsp(data))) {
- pr_warning("qseecom Interrupted: exiting send_cmd loop\n");
- return -ERESTARTSYS;
- }
-
- if (data->abort) {
- pr_err("Aborting driver\n");
- return -ENODEV;
- }
- qseecom.send_resp_flag = 0;
- cmd.cmd_type = TZ_SCHED_CMD_PENDING;
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *)&cmd,
- sizeof(cmd), &resp, sizeof(resp));
- if (ret) {
- pr_err("qseecom_scm_call failed with err: %d\n", ret);
- return ret;
- }
- }
- return ret;
-}
-
int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
struct qseecom_send_svc_cmd_req *req_ptr,
struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
@@ -1162,10 +994,8 @@
pr_err("copy_from_user failed\n");
return ret;
}
- if (qseecom.qseos_version == QSEOS_VERSION_14)
- ret = __qseecom_send_cmd(data, &req);
- else
- ret = __qseecom_send_cmd_legacy(data, &req);
+ ret = __qseecom_send_cmd(data, &req);
+
if (ret)
return ret;
@@ -1280,12 +1110,9 @@
ret = __qseecom_update_with_phy_addr(&req);
if (ret)
return ret;
- if (qseecom.qseos_version == QSEOS_VERSION_14)
- ret = __qseecom_send_cmd(data, &send_cmd_req);
- else
- ret = __qseecom_send_cmd_legacy(data, &send_cmd_req);
- __qseecom_send_cmd_req_clean_up(&req);
+ ret = __qseecom_send_cmd(data, &send_cmd_req);
+ __qseecom_send_cmd_req_clean_up(&req);
if (ret)
return ret;
@@ -1324,12 +1151,7 @@
return -ENODEV;
}
this_lstnr->rcv_req_flag = 0;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- if (*((uint32_t *)this_lstnr->sb_virt) != 0)
- break;
- } else {
- break;
- }
+ break;
}
return ret;
}
@@ -1627,11 +1449,6 @@
uint32_t len;
ion_phys_addr_t pa;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- pr_err("This functionality is UNSUPPORTED in version 1.3\n");
- return -EINVAL;
- }
-
*handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
if (!(*handle)) {
pr_err("failed to allocate memory for kernel client handle\n");
@@ -1782,10 +1599,6 @@
unsigned long flags = 0;
bool found_handle = false;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- pr_err("This functionality is UNSUPPORTED in version 1.3\n");
- return -EINVAL;
- }
if ((handle == NULL) || (*handle == NULL)) {
pr_err("Handle is not initialized\n");
return -EINVAL;
@@ -1826,11 +1639,6 @@
struct qseecom_send_cmd_req req = {0, 0, 0, 0};
struct qseecom_dev_handle *data;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- pr_err("This functionality is UNSUPPORTED in version 1.3\n");
- return -EINVAL;
- }
-
if (handle == NULL) {
pr_err("Handle is not initialized\n");
return -EINVAL;
@@ -1918,6 +1726,10 @@
qclk = &qseecom.ce_drv;
mutex_lock(&clk_access_lock);
+
+ if (qclk->clk_access_cnt == ULONG_MAX)
+ goto err;
+
if (qclk->clk_access_cnt > 0) {
qclk->clk_access_cnt++;
mutex_unlock(&clk_access_lock);
@@ -1965,6 +1777,12 @@
qclk = &qseecom.ce_drv;
mutex_lock(&clk_access_lock);
+
+ if (qclk->clk_access_cnt == 0) {
+ mutex_unlock(&clk_access_lock);
+ return;
+ }
+
if (qclk->clk_access_cnt == 1) {
if (qclk->ce_clk != NULL)
clk_disable_unprepare(qclk->ce_clk);
@@ -2400,12 +2218,13 @@
case QSEOS_RESULT_SUCCESS:
break;
case QSEOS_RESULT_FAIL_KEY_ID_EXISTS:
+ pr_debug("process_incomplete_cmd return Key ID exists.\n");
break;
case QSEOS_RESULT_INCOMPLETE:
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret) {
if (resp.result == QSEOS_RESULT_FAIL_KEY_ID_EXISTS) {
- pr_warn("process_incomplete_cmd return Key ID exits.\n");
+ pr_debug("process_incomplete_cmd return Key ID exists.\n");
ret = 0;
} else {
pr_err("process_incomplete_cmd FAILED, resp.result %d\n",
@@ -2484,9 +2303,8 @@
return -EFAULT;
}
- if (qseecom.qsee.instance == qseecom.ce_drv.instance)
- __qseecom_enable_clk(CLK_QSEE);
- else
+ __qseecom_enable_clk(CLK_QSEE);
+ if (qseecom.qsee.instance != qseecom.ce_drv.instance)
__qseecom_enable_clk(CLK_CE_DRV);
memcpy(ireq.key_id, set_key_para->key_id, QSEECOM_KEY_ID_SIZE);
@@ -2495,8 +2313,8 @@
ireq.pipe = set_key_para->pipe;
ireq.flags = set_key_para->flags;
- /* set PIPE_ENC */
- ireq.pipe_type = QSEOS_PIPE_ENC;
+ /* set both PIPE_ENC and PIPE_ENC_XTS*/
+ ireq.pipe_type = QSEOS_PIPE_ENC|QSEOS_PIPE_ENC_XTS;
if (set_key_para->set_clear_key_flag ==
QSEECOM_SET_CE_KEY_CMD)
@@ -2510,17 +2328,9 @@
&resp, sizeof(struct qseecom_command_scm_resp));
if (ret) {
pr_err("scm call to set QSEOS_PIPE_ENC key failed : %d\n", ret);
- return ret;
- }
-
- /* set PIPE_ENC_XTS */
- ireq.pipe_type = QSEOS_PIPE_ENC_XTS;
- ret = scm_call(SCM_SVC_TZSCHEDULER, 1,
- &ireq, sizeof(struct qseecom_key_select_ireq),
- &resp, sizeof(struct qseecom_command_scm_resp));
- if (ret) {
- pr_err("scm call to set QSEOS_PIPE_ENC_XTS key failed : %d\n",
- ret);
+ __qseecom_disable_clk(CLK_QSEE);
+ if (qseecom.qsee.instance != qseecom.ce_drv.instance)
+ __qseecom_disable_clk(CLK_CE_DRV);
return ret;
}
@@ -2540,9 +2350,8 @@
break;
}
- if (qseecom.qsee.instance == qseecom.ce_drv.instance)
- __qseecom_disable_clk(CLK_QSEE);
- else
+ __qseecom_disable_clk(CLK_QSEE);
+ if (qseecom.qsee.instance != qseecom.ce_drv.instance)
__qseecom_disable_clk(CLK_CE_DRV);
return ret;
@@ -2858,11 +2667,6 @@
}
case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
data->released = true;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- pr_err("Loading External elf image unsupported in rev 0x13\n");
- ret = -EINVAL;
- break;
- }
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
ret = qseecom_load_external_elf(data, argp);
@@ -2874,11 +2678,6 @@
}
case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
data->released = true;
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- pr_err("Unloading External elf image unsupported in rev 0x13\n");
- ret = -EINVAL;
- break;
- }
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
ret = qseecom_unload_external_elf(data);
@@ -2982,23 +2781,7 @@
data->released = false;
init_waitqueue_head(&data->abort_wq);
atomic_set(&data->ioctl_count, 0);
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- int pil_error;
- mutex_lock(&pil_access_lock);
- if (pil_ref_cnt == 0) {
- pil = subsystem_get("tzapps");
- if (IS_ERR(pil)) {
- pr_err("Playready PIL image load failed\n");
- pil_error = PTR_ERR(pil);
- pil = NULL;
- pr_debug("tzapps image load FAILED\n");
- mutex_unlock(&pil_access_lock);
- return pil_error;
- }
- }
- pil_ref_cnt++;
- mutex_unlock(&pil_access_lock);
- }
+
return ret;
}
@@ -3036,13 +2819,6 @@
if (data->perf_enabled == true)
qsee_disable_clock_vote(data, CLK_DFAB);
- if (qseecom.qseos_version == QSEOS_VERSION_13) {
- mutex_lock(&pil_access_lock);
- if (pil_ref_cnt == 1)
- subsystem_put(pil);
- pil_ref_cnt--;
- mutex_unlock(&pil_access_lock);
- }
kfree(data);
return ret;
diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c
index 73cae32..501da4c8 100644
--- a/drivers/misc/tspp.c
+++ b/drivers/misc/tspp.c
@@ -33,6 +33,7 @@
#include <linux/wait.h> /* wait() macros, sleeping */
#include <linux/tspp.h> /* tspp functions */
#include <linux/bitops.h> /* BIT() macro */
+#include <linux/regulator/consumer.h>
#include <mach/sps.h> /* BAM stuff */
#include <mach/gpio.h>
#include <linux/wakelock.h> /* Locking functions */
@@ -40,6 +41,7 @@
#include <linux/jiffies.h> /* Jiffies counter */
#include <mach/dma.h>
#include <mach/msm_tspp.h>
+#include <mach/rpm-regulator-smd.h>
#include <linux/debugfs.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
@@ -447,6 +449,8 @@
/* clocks */
struct clk *tsif_pclk;
struct clk *tsif_ref_clk;
+ /* regulators */
+ struct regulator *tsif_vreg;
/* data */
struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
struct tspp_channel channels[TSPP_NUM_CHANNELS];
@@ -763,13 +767,31 @@
/*** Clock functions ***/
static int tspp_clock_start(struct tspp_device *device)
{
+ int rc;
+
if (device == NULL) {
pr_err("tspp: Can't start clocks, invalid device\n");
return -EINVAL;
}
+ if (device->tsif_vreg) {
+ rc = regulator_set_voltage(device->tsif_vreg,
+ RPM_REGULATOR_CORNER_SUPER_TURBO,
+ RPM_REGULATOR_CORNER_SUPER_TURBO);
+ if (rc) {
+ pr_err("Unable to set CX voltage.\n");
+ return rc;
+ }
+ }
+
if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
pr_err("tspp: Can't start pclk");
+
+ if (device->tsif_vreg) {
+ regulator_set_voltage(device->tsif_vreg,
+ RPM_REGULATOR_CORNER_SVS_SOC,
+ RPM_REGULATOR_CORNER_SUPER_TURBO);
+ }
return -EBUSY;
}
@@ -777,6 +799,11 @@
clk_prepare_enable(device->tsif_ref_clk) != 0) {
pr_err("tspp: Can't start ref clk");
clk_disable_unprepare(device->tsif_pclk);
+ if (device->tsif_vreg) {
+ regulator_set_voltage(device->tsif_vreg,
+ RPM_REGULATOR_CORNER_SVS_SOC,
+ RPM_REGULATOR_CORNER_SUPER_TURBO);
+ }
return -EBUSY;
}
@@ -785,6 +812,8 @@
static void tspp_clock_stop(struct tspp_device *device)
{
+ int rc;
+
if (device == NULL) {
pr_err("tspp: Can't stop clocks, invalid device\n");
return;
@@ -795,6 +824,14 @@
if (device->tsif_ref_clk)
clk_disable_unprepare(device->tsif_ref_clk);
+
+ if (device->tsif_vreg) {
+ rc = regulator_set_voltage(device->tsif_vreg,
+ RPM_REGULATOR_CORNER_SVS_SOC,
+ RPM_REGULATOR_CORNER_SUPER_TURBO);
+ if (rc)
+ pr_err("Unable to set CX voltage.\n");
+ }
}
/*** TSIF functions ***/
@@ -2667,6 +2704,7 @@
struct device_node *node = pdev->dev.of_node;
struct msm_tspp_platform_data *data;
struct msm_gpio *gpios;
+ struct property *prop;
int i, rc;
int gpio;
u32 gpio_func;
@@ -2691,6 +2729,11 @@
return NULL;
}
+ data->tsif_vreg_present = 0;
+ prop = of_find_property(node, "vdd_cx-supply", NULL);
+ if (prop)
+ data->tsif_vreg_present = 1;
+
data->num_gpios = of_gpio_count(node);
if (data->num_gpios == 0) {
pr_err("tspp: Could not find GPIO definitions\n");
@@ -2843,6 +2886,31 @@
device->pdev = pdev;
platform_set_drvdata(pdev, device);
+ /* map regulators */
+ if (data->tsif_vreg_present) {
+ device->tsif_vreg = devm_regulator_get(&pdev->dev, "vdd_cx");
+ if (IS_ERR(device->tsif_vreg)) {
+ rc = PTR_ERR(device->tsif_vreg);
+ device->tsif_vreg = NULL;
+ goto err_regultaor;
+ }
+
+ /* Set an initial voltage and enable the regulator */
+ rc = regulator_set_voltage(device->tsif_vreg,
+ RPM_REGULATOR_CORNER_SVS_SOC,
+ RPM_REGULATOR_CORNER_SUPER_TURBO);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set CX voltage.\n");
+ goto err_regultaor;
+ }
+
+ rc = regulator_enable(device->tsif_vreg);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to enable CX regulator.\n");
+ goto err_regultaor;
+ }
+ }
+
/* map clocks */
if (data->tsif_pclk) {
device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
@@ -3032,6 +3100,9 @@
if (device->tsif_pclk)
clk_put(device->tsif_pclk);
err_pclock:
+ if (device->tsif_vreg)
+ regulator_disable(device->tsif_vreg);
+err_regultaor:
kfree(device);
out:
@@ -3081,6 +3152,9 @@
if (device->tsif_pclk)
clk_put(device->tsif_pclk);
+ if (device->tsif_vreg)
+ regulator_disable(device->tsif_vreg);
+
pm_runtime_disable(&pdev->dev);
kfree(device);
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index 0b04bbf..5fda343 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -30,7 +30,7 @@
#include <linux/of.h>
#include <linux/ctype.h>
#include <mach/sps.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#define PAGE_SIZE_2K 2048
#define PAGE_SIZE_4K 4096
#define WRITE 1
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 726e9a6..be9058b 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -47,6 +47,29 @@
#define ECM_IPA_LOG_EXIT() pr_debug("end\n")
/**
+ * enum ecm_ipa_state - specify the current driver internal state.
+ *
+ * The driver internal state changes due to its API usage.
+ * The driver saves its internal state to guard from caller illegal
+ * call sequence.
+ * LOADED is the first state which is the default one.
+ * INITIALIZED is the driver state once it finished registering
+ * the network device
+ * CONNECTED is the driver state once the USB pipes were connected to IPA
+ * UP is the driver state when it allows Linux network stack start
+ * data transfer
+ */
+enum ecm_ipa_mode {
+ ECM_IPA_LOADED,
+ ECM_IPA_INITIALIZED,
+ ECM_IPA_CONNECTED,
+ ECM_IPA_UP,
+};
+
+#define ECM_IPA_MODE(ecm_ipa_ctx) \
+ pr_debug("Driver mode changed - %d", ecm_ipa_ctx->mode);
+
+/**
* struct ecm_ipa_dev - main driver context parameters
* @net: network interface struct implemented by this driver
* @directory: debugfs directory for various debuging switches
@@ -62,6 +85,7 @@
* @outstanding_high: number of outstanding packets allowed
* @outstanding_low: number of outstanding packets which shall cause
* to netdev queue start (after stopped due to outstanding_high reached)
+ * @mode: current mode of ecm_ipa driver
*/
struct ecm_ipa_dev {
struct net_device *net;
@@ -77,34 +101,29 @@
atomic_t outstanding_pkts;
u8 outstanding_high;
u8 outstanding_low;
+ enum ecm_ipa_mode mode;
};
-/**
- * struct ecm_ipa_ctx - saved pointer for the ecm_ipa network device
- * which allow ecm_ipa to be a singleton
- */
-static struct ecm_ipa_dev *ecm_ipa_ctx;
-
static int ecm_ipa_open(struct net_device *net);
static void ecm_ipa_packet_receive_notify(void *priv,
enum ipa_dp_evt_type evt, unsigned long data);
static void ecm_ipa_tx_complete_notify(void *priv,
enum ipa_dp_evt_type evt, unsigned long data);
static int ecm_ipa_stop(struct net_device *net);
-static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *ecm_ipa_ctx,
const void *dst_mac, const void *src_mac);
-static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *dev);
+static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *ecm_ipa_ctx);
static int ecm_ipa_register_properties(void);
static void ecm_ipa_deregister_properties(void);
static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
unsigned long data);
-static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev);
-static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *dev);
+static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
static bool rx_filter(struct sk_buff *skb);
static bool tx_filter(struct sk_buff *skb);
-static bool rm_enabled(struct ecm_ipa_dev *dev);
-static int resource_request(struct ecm_ipa_dev *dev);
-static void resource_release(struct ecm_ipa_dev *dev);
+static bool rm_enabled(struct ecm_ipa_dev *ecm_ipa_ctx);
+static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx);
static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
struct net_device *net);
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file);
@@ -117,12 +136,14 @@
char __user *ubuf, size_t count, loff_t *ppos);
static ssize_t ecm_ipa_debugfs_atomic_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
-static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
-static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx);
static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
static int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
u8 device_ethaddr[]);
+static bool ecm_ipa_state_validate(enum ecm_ipa_mode current_mode,
+ enum ecm_ipa_mode new_mode);
static int ecm_ipa_init_module(void);
static void ecm_ipa_cleanup_module(void);
@@ -134,7 +155,7 @@
};
const struct file_operations ecm_ipa_debugfs_dma_ops = {
- .open = ecm_ipa_debugfs_dma_open,
+ .open = ecm_ipa_debugfs_dma_open,
.read = ecm_ipa_debugfs_enable_read,
.write = ecm_ipa_debugfs_enable_write_dma,
};
@@ -146,7 +167,7 @@
/**
* ecm_ipa_init() - create network device and initializes internal
- * data structures
+ * data structures
* @params: in/out parameters required for ecm_ipa initialization
*
* Shall be called prior to pipe connection.
@@ -170,7 +191,7 @@
{
int result = 0;
struct net_device *net;
- struct ecm_ipa_dev *dev;
+ struct ecm_ipa_dev *ecm_ipa_ctx;
ECM_IPA_LOG_ENTRY();
pr_debug("%s initializing\n", DRIVER_NAME);
@@ -188,26 +209,25 @@
}
pr_debug("network device was successfully allocated\n");
- dev = netdev_priv(net);
- memset(dev, 0, sizeof(*dev));
- dev->net = net;
- ecm_ipa_ctx = dev;
- dev->tx_enable = true;
- dev->rx_enable = true;
- dev->rm_enable = true;
- dev->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
- dev->outstanding_low = DEFAULT_OUTSTANDING_LOW;
- atomic_set(&dev->outstanding_pkts, 0);
+ ecm_ipa_ctx = netdev_priv(net);
+ memset(ecm_ipa_ctx, 0, sizeof(*ecm_ipa_ctx));
+ ecm_ipa_ctx->net = net;
+ ecm_ipa_ctx->tx_enable = true;
+ ecm_ipa_ctx->rx_enable = true;
+ ecm_ipa_ctx->rm_enable = true;
+ ecm_ipa_ctx->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
+ ecm_ipa_ctx->outstanding_low = DEFAULT_OUTSTANDING_LOW;
+ atomic_set(&ecm_ipa_ctx->outstanding_pkts, 0);
snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
net->netdev_ops = &ecm_ipa_netdev_ops;
pr_debug("internal data structures were intialized and defaults set\n");
- result = ecm_ipa_debugfs_init(dev);
+ result = ecm_ipa_debugfs_init(ecm_ipa_ctx);
if (result)
goto fail_debugfs;
pr_debug("debugfs entries were created\n");
- result = ecm_ipa_create_rm_resource(dev);
+ result = ecm_ipa_create_rm_resource(ecm_ipa_ctx);
if (result) {
ECM_IPA_ERROR("fail on RM create\n");
goto fail_create_rm;
@@ -222,7 +242,7 @@
}
pr_debug("Device Ethernet address set %pM\n", net->dev_addr);
- result = ecm_ipa_rules_cfg(dev, params->host_ethaddr,
+ result = ecm_ipa_rules_cfg(ecm_ipa_ctx, params->host_ethaddr,
params->device_ethaddr);
if (result) {
ECM_IPA_ERROR("fail on ipa rules set\n");
@@ -249,7 +269,10 @@
params->ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
params->ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
- params->private = (void *)dev;
+ params->private = (void *)ecm_ipa_ctx;
+ ecm_ipa_ctx->mode = ECM_IPA_INITIALIZED;
+ ECM_IPA_MODE(ecm_ipa_ctx);
+
ECM_IPA_LOG_EXIT();
return 0;
@@ -257,12 +280,12 @@
fail_register_netdev:
ecm_ipa_deregister_properties();
fail_register_tx:
- ecm_ipa_rules_destroy(dev);
+ ecm_ipa_rules_destroy(ecm_ipa_ctx);
fail_set_device_ethernet:
fail_rules_cfg:
- ecm_ipa_destory_rm_resource(dev);
+ ecm_ipa_destory_rm_resource(ecm_ipa_ctx);
fail_create_rm:
- ecm_ipa_debugfs_destroy(dev);
+ ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
fail_debugfs:
free_netdev(net);
fail_alloc_etherdev:
@@ -270,17 +293,38 @@
}
EXPORT_SYMBOL(ecm_ipa_init);
-
+/**
+ * ecm_ipa_connect() - notify ecm_ipa for IPA<->USB pipes connection
+ * @usb_to_ipa_hdl: handle of IPA driver client for USB->IPA
+ * @ipa_to_usb_hdl: handle of IPA driver client for IPA->USB
+ * @priv: same value that was set by ecm_ipa_init(), this
+ * parameter holds the network device pointer.
+ *
+ * Once USB driver finishes the pipe connection between IPA core
+ * and USB core this method shall be called in order to
+ * allow ecm_ipa complete the data path configurations.
+ * Detailed description:
+ * - configure the IPA end-points register
+ * - notify the Linux kernel for "carrier_on"
+ * After this function is done the driver state changes to "Connected".
+ * This API is expected to be called after ecm_ipa_init() or
+ * after a call to ecm_ipa_disconnect.
+ */
int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
void *priv)
{
- struct ecm_ipa_dev *dev = priv;
+ struct ecm_ipa_dev *ecm_ipa_ctx = priv;
ECM_IPA_LOG_ENTRY();
NULL_CHECK(priv);
pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d, priv=0x%p\n",
usb_to_ipa_hdl, ipa_to_usb_hdl, priv);
+ if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_CONNECTED)) {
+ ECM_IPA_ERROR("can't call connect before driver init\n");
+ return -EPERM;
+ }
+
if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
usb_to_ipa_hdl);
@@ -291,29 +335,48 @@
ipa_to_usb_hdl);
return -EINVAL;
}
- dev->ipa_to_usb_hdl = ipa_to_usb_hdl;
- dev->usb_to_ipa_hdl = usb_to_ipa_hdl;
+ ecm_ipa_ctx->ipa_to_usb_hdl = ipa_to_usb_hdl;
+ ecm_ipa_ctx->usb_to_ipa_hdl = usb_to_ipa_hdl;
ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
pr_debug("end-point configured\n");
- netif_carrier_on(dev->net);
- if (!netif_carrier_ok(dev->net)) {
+ netif_carrier_on(ecm_ipa_ctx->net);
+ if (!netif_carrier_ok(ecm_ipa_ctx->net)) {
ECM_IPA_ERROR("netif_carrier_ok error\n");
return -EBUSY;
}
pr_debug("carrier_on notified, ecm_ipa is operational\n");
+ ecm_ipa_ctx->mode = ECM_IPA_CONNECTED;
+ ECM_IPA_MODE(ecm_ipa_ctx);
+
ECM_IPA_LOG_EXIT();
+
return 0;
}
EXPORT_SYMBOL(ecm_ipa_connect);
+/**
+ * ecm_ipa_open() - notify Linux network stack to start sending packets
+ * @net: the network interface supplied by the network stack
+ *
+ * Linux uses this API to notify the driver that the network interface
+ * transitions to the up state.
+ * The driver will instruct the Linux network stack to start
+ * delivering data packets.
+ */
static int ecm_ipa_open(struct net_device *net)
{
- struct ecm_ipa_dev *dev;
+ struct ecm_ipa_dev *ecm_ipa_ctx;
+
ECM_IPA_LOG_ENTRY();
- dev = netdev_priv(net);
+ ecm_ipa_ctx = netdev_priv(net);
+
+ if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_UP)) {
+ ECM_IPA_ERROR("can't bring driver up before cable connect\n");
+ return -EPERM;
+ }
if (!netif_carrier_ok(net))
pr_debug("carrier is not ON yet - continuing\n");
@@ -321,49 +384,68 @@
netif_start_queue(net);
pr_debug("queue started\n");
+ ecm_ipa_ctx->mode = ECM_IPA_UP;
+ ECM_IPA_MODE(ecm_ipa_ctx);
+
ECM_IPA_LOG_EXIT();
+
return 0;
}
/**
* ecm_ipa_start_xmit() - send data from APPs to USB core via IPA core
- * @skb: packet received from Linux stack
+ * @skb: packet received from Linux network stack
* @net: the network device being used to send this packet
*
* Several conditions needed in order to send the packet to IPA:
- * - we are in a valid state were the queue is not stopped
+ * - Transmit queue for the network driver is currently
+ * in "send" state
+ * - The driver internal state is in "UP" state.
* - Filter Tx switch is turned off
- * - The resources required for actual Tx are all up
+ * - The IPA resource manager state for the driver producer client
+ * is "Granted" which implies that all the resources in the dependency
+ * graph are valid for data flow.
+ * - outstanding high boundary did not reach.
*
+ * In case all of the above conditions are met, the network driver will
+ * send the packet by using the IPA API for Tx.
+ * In case the outstanding packet high boundary is reached, the driver will
+ * stop the send queue until enough packet were proceeded by the IPA core.
*/
static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
struct net_device *net)
{
int ret;
netdev_tx_t status = NETDEV_TX_BUSY;
- struct ecm_ipa_dev *dev = netdev_priv(net);
+ struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(net);
if (unlikely(netif_queue_stopped(net))) {
ECM_IPA_ERROR("interface queue is stopped\n");
goto out;
}
+ if (unlikely(ecm_ipa_ctx->mode != ECM_IPA_UP)) {
+ ECM_IPA_ERROR("can't send without network interface up\n");
+ return -NETDEV_TX_BUSY;
+ }
+
if (unlikely(tx_filter(skb))) {
dev_kfree_skb_any(skb);
pr_debug("packet got filtered out on Tx path\n");
status = NETDEV_TX_OK;
goto out;
}
- ret = resource_request(dev);
+ ret = resource_request(ecm_ipa_ctx);
if (ret) {
pr_debug("Waiting to resource\n");
netif_stop_queue(net);
goto resource_busy;
}
- if (atomic_read(&dev->outstanding_pkts) >= dev->outstanding_high) {
+ if (atomic_read(&ecm_ipa_ctx->outstanding_pkts) >=
+ ecm_ipa_ctx->outstanding_high) {
pr_debug("Outstanding high boundary reached (%d)- stopping queue\n",
- dev->outstanding_high);
+ ecm_ipa_ctx->outstanding_high);
netif_stop_queue(net);
status = -NETDEV_TX_BUSY;
goto out;
@@ -375,7 +457,7 @@
goto fail_tx_packet;
}
- atomic_inc(&dev->outstanding_pkts);
+ atomic_inc(&ecm_ipa_ctx->outstanding_pkts);
net->stats.tx_packets++;
net->stats.tx_bytes += skb->len;
status = NETDEV_TX_OK;
@@ -383,7 +465,7 @@
fail_tx_packet:
out:
- resource_release(dev);
+ resource_release(ecm_ipa_ctx);
resource_busy:
return status;
}
@@ -395,14 +477,15 @@
* @evt: event type
* @data: data provided with event
*
- * IPA will pass a packet with skb->data pointing to Ethernet packet frame
+ * IPA will pass a packet to the Linux network stack with skb->data pointing
+ * to Ethernet packet frame.
*/
static void ecm_ipa_packet_receive_notify(void *priv,
enum ipa_dp_evt_type evt,
unsigned long data)
{
struct sk_buff *skb = (struct sk_buff *)data;
- struct ecm_ipa_dev *dev = priv;
+ struct ecm_ipa_dev *ecm_ipa_ctx = priv;
int result;
if (evt != IPA_RECEIVE) {
@@ -410,8 +493,8 @@
return;
}
- skb->dev = dev->net;
- skb->protocol = eth_type_trans(skb, dev->net);
+ skb->dev = ecm_ipa_ctx->net;
+ skb->protocol = eth_type_trans(skb, ecm_ipa_ctx->net);
if (rx_filter(skb)) {
pr_debug("packet got filtered out on Rx path\n");
dev_kfree_skb_any(skb);
@@ -421,92 +504,138 @@
result = netif_rx(skb);
if (result)
ECM_IPA_ERROR("fail on netif_rx\n");
- dev->net->stats.rx_packets++;
- dev->net->stats.rx_bytes += skb->len;
+ ecm_ipa_ctx->net->stats.rx_packets++;
+ ecm_ipa_ctx->net->stats.rx_bytes += skb->len;
return;
}
+/** ecm_ipa_stop() - called when network device transitions to the down
+ * state.
+ * @net: the network device being stopped.
+ *
+ * This API is used by Linux network stack to notify the network driver that
+ * its state was changed to "down"
+ * The driver will stop the "send" queue and change its internal
+ * state to "Connected".
+ */
static int ecm_ipa_stop(struct net_device *net)
{
+ struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(net);
+
ECM_IPA_LOG_ENTRY();
- pr_debug("stopping net device\n");
+
+ if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_CONNECTED)) {
+ ECM_IPA_ERROR("can't do network interface down without up\n");
+ return -EPERM;
+ }
+
netif_stop_queue(net);
+ pr_debug("network device stopped\n");
+
+ ecm_ipa_ctx->mode = ECM_IPA_CONNECTED;
+ ECM_IPA_MODE(ecm_ipa_ctx);
+
ECM_IPA_LOG_EXIT();
return 0;
}
+/** ecm_ipa_disconnect() - called when the USB cable is unplugged.
+ * @priv: same value that was set by ecm_ipa_init(), this
+ * parameter holds the network device pointer.
+ *
+ * Once the USB cable is unplugged the USB driver will notify the network
+ * interface driver.
+ * The internal driver state will returned to its initialized state and
+ * Linux network stack will be informed for carrier off and the send queue
+ * will be stopped.
+ */
int ecm_ipa_disconnect(void *priv)
{
- struct ecm_ipa_dev *dev = priv;
+ struct ecm_ipa_dev *ecm_ipa_ctx = priv;
+
ECM_IPA_LOG_ENTRY();
- NULL_CHECK(dev);
+ NULL_CHECK(ecm_ipa_ctx);
pr_debug("priv=0x%p\n", priv);
- netif_carrier_off(dev->net);
+
+ if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_INITIALIZED)) {
+ ECM_IPA_ERROR("can't disconnect without connect first\n");
+ return -EPERM;
+ }
+
+ netif_carrier_off(ecm_ipa_ctx->net);
+ pr_debug("carrier_off notifcation was sent\n");
+
+ netif_stop_queue(ecm_ipa_ctx->net);
+ pr_debug("queue stopped\n");
+
+ ecm_ipa_ctx->mode = ECM_IPA_INITIALIZED;
+ ECM_IPA_MODE(ecm_ipa_ctx);
+
ECM_IPA_LOG_EXIT();
+
return 0;
}
EXPORT_SYMBOL(ecm_ipa_disconnect);
/**
- * ecm_ipa_cleanup() - destroys all
- * ecm information
- * @priv: main driver context parameters
+ * ecm_ipa_cleanup() - unregister the network interface driver and free
+ * internal data structs.
+ * @priv: same value that was set by ecm_ipa_init(), this
+ * parameter holds the network device pointer.
*
+ * This function shall be called once the network interface is not
+ * needed anymore, e.g: when the USB composition does not support ECM.
+ * This function shall be called after the pipes were disconnected.
+ * Detailed description:
+ * - delete the driver dependency defined for IPA resource manager and
+ * destroy the producer resource.
+ * - remove the debugfs entries
+ * - deregister the network interface from Linux network stack
+ * - free all internal data structs
*/
void ecm_ipa_cleanup(void *priv)
{
- struct ecm_ipa_dev *dev = priv;
+ struct ecm_ipa_dev *ecm_ipa_ctx = priv;
+
ECM_IPA_LOG_ENTRY();
+
pr_debug("priv=0x%p\n", priv);
- if (!dev) {
- ECM_IPA_ERROR("dev NULL pointer\n");
+
+ if (!ecm_ipa_ctx) {
+ ECM_IPA_ERROR("ecm_ipa_ctx NULL pointer\n");
return;
}
- ecm_ipa_destory_rm_resource(dev);
- ecm_ipa_debugfs_destroy(dev);
+ if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_LOADED))
+ ECM_IPA_ERROR("can't clean driver without cable disconnect\n");
- unregister_netdev(dev->net);
- free_netdev(dev->net);
+
+ ecm_ipa_destory_rm_resource(ecm_ipa_ctx);
+ ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
+
+ unregister_netdev(ecm_ipa_ctx->net);
+ free_netdev(ecm_ipa_ctx->net);
pr_debug("cleanup done\n");
ecm_ipa_ctx = NULL;
ECM_IPA_LOG_EXIT();
+
return ;
}
EXPORT_SYMBOL(ecm_ipa_cleanup);
/**
- * @ecm_ipa_rx_dp_notify: supplied callback to be called by the IPA
- * driver upon data packets received from USB pipe into IPA core.
- * @ecm_ipa_rt_dp_notify: supplied callback to be called by the IPA
- * driver upon exception packets sent from IPA pipe into USB core.
- * @priv: should be passed later on to ecm_ipa_configure, hold the network
- * structure allocated for STD ECM interface.
- *
- * Shall be called prior to pipe connection.
- * The out parameters (the callbacks) shall be supplied to ipa_connect.
- * Detailed description:
- * - set the callbacks to be used by the caller upon ipa_connect
- * - allocate the network device
- * - set the priv argument with a reference to the network device
- *
- * Returns negative errno, or zero on success
- */
-
-
-/**
* ecm_ipa_rules_cfg() - set header insertion and register Tx/Rx properties
* Headers will be commited to HW
- * @dev: main driver context parameters
+ * @ecm_ipa_ctx: main driver context parameters
* @dst_mac: destination MAC address
* @src_mac: source MAC address
*
* Returns negative errno, or zero on success
*/
-static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *ecm_ipa_ctx,
const void *dst_mac, const void *src_mac)
{
struct ipa_ioc_add_hdr *hdrs;
@@ -558,8 +687,8 @@
result = ipv6_hdr->status;
goto out_free_mem;
}
- dev->eth_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl;
- dev->eth_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl;
+ ecm_ipa_ctx->eth_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl;
+ ecm_ipa_ctx->eth_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl;
ECM_IPA_LOG_EXIT();
out_free_mem:
kfree(hdrs);
@@ -567,7 +696,14 @@
return result;
}
-static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *dev)
+/**
+ * ecm_ipa_rules_destroy() - remove the IPA core configuration done for
+ * the driver data path.
+ * @ecm_ipa_ctx: the driver context
+ *
+ * Revert the work done on ecm_ipa_rules_cfg.
+ */
+static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *ecm_ipa_ctx)
{
struct ipa_ioc_del_hdr *del_hdr;
struct ipa_hdr_del *ipv4;
@@ -580,9 +716,9 @@
del_hdr->commit = 1;
del_hdr->num_hdls = 2;
ipv4 = &del_hdr->hdl[0];
- ipv4->hdl = dev->eth_ipv4_hdr_hdl;
+ ipv4->hdl = ecm_ipa_ctx->eth_ipv4_hdr_hdl;
ipv6 = &del_hdr->hdl[1];
- ipv6->hdl = dev->eth_ipv6_hdr_hdl;
+ ipv6->hdl = ecm_ipa_ctx->eth_ipv6_hdr_hdl;
result = ipa_del_hdr(del_hdr);
if (result || ipv4->status || ipv6->status)
ECM_IPA_ERROR("ipa_del_hdr failed");
@@ -676,29 +812,25 @@
static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
unsigned long data)
{
- struct ecm_ipa_dev *dev = user_data;
+ struct ecm_ipa_dev *ecm_ipa_ctx = user_data;
ECM_IPA_LOG_ENTRY();
if (event == IPA_RM_RESOURCE_GRANTED &&
- netif_queue_stopped(dev->net)) {
+ netif_queue_stopped(ecm_ipa_ctx->net)) {
pr_debug("Resource Granted - waking queue\n");
- netif_wake_queue(dev->net);
+ netif_wake_queue(ecm_ipa_ctx->net);
} else {
pr_debug("Resource released\n");
}
ECM_IPA_LOG_EXIT();
}
-static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev)
+static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx)
{
struct ipa_rm_create_params create_params = {0};
int result;
ECM_IPA_LOG_ENTRY();
- if (!dev->rm_enable) {
- pr_debug("RM feature not used\n");
- return 0;
- }
create_params.name = IPA_RM_RESOURCE_STD_ECM_PROD;
- create_params.reg_params.user_data = dev;
+ create_params.reg_params.user_data = ecm_ipa_ctx;
create_params.reg_params.notify_cb = ecm_ipa_rm_notify;
result = ipa_rm_create_resource(&create_params);
if (result) {
@@ -730,14 +862,12 @@
return result;
}
-static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *dev)
+static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx)
{
int result;
ECM_IPA_LOG_ENTRY();
- if (!dev->rm_enable)
- return;
ipa_rm_delete_dependency(IPA_RM_RESOURCE_STD_ECM_PROD,
IPA_RM_RESOURCE_USB_CONS);
ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_STD_ECM_PROD);
@@ -750,26 +880,26 @@
static bool rx_filter(struct sk_buff *skb)
{
- struct ecm_ipa_dev *dev = netdev_priv(skb->dev);
- return !dev->rx_enable;
+ struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(skb->dev);
+ return !ecm_ipa_ctx->rx_enable;
}
static bool tx_filter(struct sk_buff *skb)
{
- struct ecm_ipa_dev *dev = netdev_priv(skb->dev);
- return !dev->tx_enable;
+ struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(skb->dev);
+ return !ecm_ipa_ctx->tx_enable;
}
-static bool rm_enabled(struct ecm_ipa_dev *dev)
+static bool rm_enabled(struct ecm_ipa_dev *ecm_ipa_ctx)
{
- return dev->rm_enable;
+ return ecm_ipa_ctx->rm_enable;
}
-static int resource_request(struct ecm_ipa_dev *dev)
+static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx)
{
int result = 0;
- if (!rm_enabled(dev))
+ if (!rm_enabled(ecm_ipa_ctx))
goto out;
result = ipa_rm_inactivity_timer_request_resource(
IPA_RM_RESOURCE_STD_ECM_PROD);
@@ -777,9 +907,9 @@
return result;
}
-static void resource_release(struct ecm_ipa_dev *dev)
+static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx)
{
- if (!rm_enabled(dev))
+ if (!rm_enabled(ecm_ipa_ctx))
goto out;
ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_STD_ECM_PROD);
out:
@@ -801,22 +931,23 @@
unsigned long data)
{
struct sk_buff *skb = (struct sk_buff *)data;
- struct ecm_ipa_dev *dev = priv;
+ struct ecm_ipa_dev *ecm_ipa_ctx = priv;
- if (!dev) {
- ECM_IPA_ERROR("dev is NULL pointer\n");
+ if (!ecm_ipa_ctx) {
+ ECM_IPA_ERROR("ecm_ipa_ctx is NULL pointer\n");
return;
}
if (evt != IPA_WRITE_DONE) {
ECM_IPA_ERROR("unsupported event on Tx callback\n");
return;
}
- atomic_dec(&dev->outstanding_pkts);
- if (netif_queue_stopped(dev->net) &&
- atomic_read(&dev->outstanding_pkts) < (dev->outstanding_low)) {
+ atomic_dec(&ecm_ipa_ctx->outstanding_pkts);
+ if (netif_queue_stopped(ecm_ipa_ctx->net) &&
+ atomic_read(&ecm_ipa_ctx->outstanding_pkts) <
+ (ecm_ipa_ctx->outstanding_low)) {
pr_debug("Outstanding low boundary reached (%d) - waking up queue\n",
- dev->outstanding_low);
- netif_wake_queue(dev->net);
+ ecm_ipa_ctx->outstanding_low);
+ netif_wake_queue(ecm_ipa_ctx->net);
}
dev_kfree_skb_any(skb);
@@ -825,9 +956,9 @@
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
{
- struct ecm_ipa_dev *dev = inode->i_private;
+ struct ecm_ipa_dev *ecm_ipa_ctx = inode->i_private;
ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->outstanding_pkts);
+ file->private_data = &(ecm_ipa_ctx->outstanding_pkts);
ECM_IPA_LOG_EXIT();
return 0;
}
@@ -835,25 +966,25 @@
static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
const char __user *buf, size_t count, loff_t *ppos)
{
- struct ecm_ipa_dev *dev = file->private_data;
+ struct ecm_ipa_dev *ecm_ipa_ctx = file->private_data;
int result;
ECM_IPA_LOG_ENTRY();
- file->private_data = &dev->dma_enable;
+ file->private_data = &ecm_ipa_ctx->dma_enable;
result = ecm_ipa_debugfs_enable_write(file, buf, count, ppos);
- if (dev->dma_enable)
- ecm_ipa_ep_registers_dma_cfg(dev->usb_to_ipa_hdl);
+ if (ecm_ipa_ctx->dma_enable)
+ ecm_ipa_ep_registers_dma_cfg(ecm_ipa_ctx->usb_to_ipa_hdl);
else
- ecm_ipa_ep_registers_cfg(dev->usb_to_ipa_hdl,
- dev->usb_to_ipa_hdl);
+ ecm_ipa_ep_registers_cfg(ecm_ipa_ctx->usb_to_ipa_hdl,
+ ecm_ipa_ctx->usb_to_ipa_hdl);
ECM_IPA_LOG_EXIT();
return result;
}
static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file)
{
- struct ecm_ipa_dev *dev = inode->i_private;
+ struct ecm_ipa_dev *ecm_ipa_ctx = inode->i_private;
ECM_IPA_LOG_ENTRY();
- file->private_data = dev;
+ file->private_data = ecm_ipa_ctx;
ECM_IPA_LOG_EXIT();
return 0;
}
@@ -915,7 +1046,7 @@
}
-static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev)
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx)
{
const mode_t flags_read_write = S_IRUGO | S_IWUGO;
const mode_t flags_read_only = S_IRUGO;
@@ -923,68 +1054,71 @@
ECM_IPA_LOG_ENTRY();
- if (!dev)
+ if (!ecm_ipa_ctx)
return -EINVAL;
- dev->directory = debugfs_create_dir("ecm_ipa", NULL);
- if (!dev->directory) {
+ ecm_ipa_ctx->directory = debugfs_create_dir("ecm_ipa", NULL);
+ if (!ecm_ipa_ctx->directory) {
ECM_IPA_ERROR("could not create debugfs directory entry\n");
goto fail_directory;
}
file = debugfs_create_bool("tx_enable", flags_read_write,
- dev->directory, &dev->tx_enable);
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->tx_enable);
if (!file) {
ECM_IPA_ERROR("could not create debugfs tx file\n");
goto fail_file;
}
file = debugfs_create_bool("rx_enable", flags_read_write,
- dev->directory, &dev->rx_enable);
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->rx_enable);
if (!file) {
ECM_IPA_ERROR("could not create debugfs rx file\n");
goto fail_file;
}
file = debugfs_create_bool("rm_enable", flags_read_write,
- dev->directory, &dev->rm_enable);
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->rm_enable);
if (!file) {
ECM_IPA_ERROR("could not create debugfs rm file\n");
goto fail_file;
}
file = debugfs_create_u8("outstanding_high", flags_read_write,
- dev->directory, &dev->outstanding_high);
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->outstanding_high);
if (!file) {
ECM_IPA_ERROR("could not create outstanding_high file\n");
goto fail_file;
}
file = debugfs_create_u8("outstanding_low", flags_read_write,
- dev->directory, &dev->outstanding_low);
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->outstanding_low);
if (!file) {
ECM_IPA_ERROR("could not create outstanding_low file\n");
goto fail_file;
}
file = debugfs_create_file("dma_enable", flags_read_write,
- dev->directory, dev, &ecm_ipa_debugfs_dma_ops);
+ ecm_ipa_ctx->directory,
+ ecm_ipa_ctx, &ecm_ipa_debugfs_dma_ops);
if (!file) {
ECM_IPA_ERROR("could not create debugfs dma file\n");
goto fail_file;
}
file = debugfs_create_file("outstanding", flags_read_only,
- dev->directory, dev, &ecm_ipa_debugfs_atomic_ops);
+ ecm_ipa_ctx->directory,
+ ecm_ipa_ctx, &ecm_ipa_debugfs_atomic_ops);
if (!file) {
ECM_IPA_ERROR("could not create outstanding file\n");
goto fail_file;
}
ECM_IPA_LOG_EXIT();
+
return 0;
fail_file:
- debugfs_remove_recursive(dev->directory);
+ debugfs_remove_recursive(ecm_ipa_ctx->directory);
fail_directory:
return -EFAULT;
}
-static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev)
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx)
{
- debugfs_remove_recursive(dev->directory);
+ debugfs_remove_recursive(ecm_ipa_ctx->directory);
}
/**
@@ -1090,6 +1224,48 @@
return 0;
}
+/** ecm_ipa_state_validate - check if a state transition is allowed
+ *
+ * Allowed transition:
+ * LOADED->INITIALIZED: ecm_ipa_init()
+ * INITIALIZED->CONNECTED: ecm_ipa_connect()
+ * CONNECTED->INITIALIZED: ecm_ipa_disconnect()
+ * CONNECTED->UP: ecm_ipa_open()
+ * UP->CONNECTED: ecm_ipa_stop()
+ * UP->INITIALIZED: ecm_ipa_disconnect()
+ * INITIALIZED-> LOADED
+ */
+static bool ecm_ipa_state_validate(enum ecm_ipa_mode current_mode,
+ enum ecm_ipa_mode new_mode)
+{
+ bool result;
+
+ switch (current_mode) {
+ case ECM_IPA_LOADED:
+ result = (new_mode == ECM_IPA_INITIALIZED);
+ break;
+ case ECM_IPA_INITIALIZED:
+ result = (new_mode == ECM_IPA_CONNECTED ||
+ new_mode == ECM_IPA_LOADED);
+ break;
+ case ECM_IPA_CONNECTED:
+ result = (new_mode == ECM_IPA_INITIALIZED ||
+ new_mode == ECM_IPA_UP);
+ break;
+ case ECM_IPA_UP:
+ result = (new_mode == ECM_IPA_CONNECTED ||
+ new_mode == ECM_IPA_INITIALIZED);
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ pr_debug("state transition (%d->%d)- %s\n", current_mode,
+ new_mode , result ? "Allowed" : "Forbidden");
+ return result;
+}
+
/**
* ecm_ipa_init_module() - module initialization
*
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index f837a06..c30f46f 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -31,6 +31,7 @@
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
+#include <linux/mfd/pm8xxx/misc.h>
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
@@ -133,6 +134,21 @@
unsigned char revision;
};
+struct wcnss_pmic_dump {
+ char reg_name[10];
+ u16 reg_addr;
+};
+
+static struct wcnss_pmic_dump wcnss_pmic_reg_dump[] = {
+ {"S2", 0x1D8},
+ {"L4", 0xB4},
+ {"L10", 0xC0},
+ {"LVS2", 0x62},
+ {"S4", 0x1E8},
+ {"LVS7", 0x06C},
+ {"LVS1", 0x060},
+};
+
#define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin"
/*
@@ -342,6 +358,25 @@
static DEVICE_ATTR(wcnss_version, S_IRUSR,
wcnss_version_show, NULL);
+void wcnss_riva_dump_pmic_regs(void)
+{
+ int i, rc;
+ u8 val;
+
+ for (i = 0; i < ARRAY_SIZE(wcnss_pmic_reg_dump); i++) {
+ val = 0;
+ rc = pm8xxx_read_register(wcnss_pmic_reg_dump[i].reg_addr,
+ &val);
+ if (rc)
+ pr_err("PMIC READ: Failed to read addr = %d\n",
+ wcnss_pmic_reg_dump[i].reg_addr);
+ else
+ pr_info_ratelimited("PMIC READ: %s addr = %x, value = %x\n",
+ wcnss_pmic_reg_dump[i].reg_name,
+ wcnss_pmic_reg_dump[i].reg_addr, val);
+ }
+}
+
/* wcnss_reset_intr() is invoked when host drivers fails to
* communicate with WCNSS over SMD; so logging these registers
* helps to know WCNSS failure reason
@@ -366,6 +401,7 @@
ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR2_OFFSET;
reg = readl_relaxed(ccu_reg);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+ wcnss_riva_dump_pmic_regs();
}
EXPORT_SYMBOL(wcnss_riva_log_debug_regs);
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index fe151b5..acd42ae3 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -107,4 +107,10 @@
help
OpenFirmware SLIMBUS accessors
+config OF_CORESIGHT
+ def_bool y
+ depends on CORESIGHT
+ help
+ OpenFirmware CoreSight accessors
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index c3a31c8..61a99f2 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -15,3 +15,4 @@
obj-$(CONFIG_OF_SPMI) += of_spmi.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_SLIMBUS) += of_slimbus.o
+obj-$(CONFIG_OF_CORESIGHT) += of_coresight.o
diff --git a/drivers/coresight/of_coresight.c b/drivers/of/of_coresight.c
similarity index 100%
rename from drivers/coresight/of_coresight.c
rename to drivers/of/of_coresight.c
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index 3ff604c..919a119 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -12,7 +12,7 @@
#include <linux/delay.h>
#include <linux/ratelimit.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
#include "ipa_i.h"
/*
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index a95eafe..d707648 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -13,6 +13,9 @@
#include <linux/delay.h>
#include "ipa_i.h"
+#define IPA_A2_HOLB_TMR_EN 0x1
+#define IPA_A2_HOLB_TMR_DEFAULT_VAL 0xff
+
static void ipa_enable_data_path(u32 clnt_hdl)
{
if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
@@ -175,6 +178,38 @@
return 0;
}
+static void ipa_program_holb(struct ipa_ep_context *ep, int ipa_ep_idx)
+{
+ u32 hol_en;
+ u32 hol_tmr;
+
+ if (IPA_CLIENT_IS_PROD(ep->client))
+ return;
+
+ switch (ep->client) {
+ case IPA_CLIENT_HSIC1_CONS:
+ case IPA_CLIENT_HSIC2_CONS:
+ case IPA_CLIENT_HSIC3_CONS:
+ case IPA_CLIENT_HSIC4_CONS:
+ hol_en = ipa_ctx->hol_en;
+ hol_tmr = ipa_ctx->hol_timer;
+ break;
+ case IPA_CLIENT_A2_TETHERED_CONS:
+ case IPA_CLIENT_A2_EMBEDDED_CONS:
+ hol_en = IPA_A2_HOLB_TMR_EN;
+ hol_tmr = IPA_A2_HOLB_TMR_DEFAULT_VAL;
+ break;
+ default:
+ return;
+ }
+
+ IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx, hol_tmr);
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ipa_ep_idx), hol_en);
+ ipa_write_reg(ipa_ctx->mmio,
+ IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ipa_ep_idx), hol_tmr);
+}
+
/**
* ipa_connect() - low-level IPA client connect
* @in: [in] input parameters from client
@@ -290,21 +325,7 @@
memcpy(&sps->desc, &ep->connect.desc, sizeof(struct sps_mem_buffer));
memcpy(&sps->data, &ep->connect.data, sizeof(struct sps_mem_buffer));
- if (in->client == IPA_CLIENT_HSIC1_CONS ||
- in->client == IPA_CLIENT_HSIC2_CONS ||
- in->client == IPA_CLIENT_HSIC3_CONS ||
- in->client == IPA_CLIENT_HSIC4_CONS ||
- in->client == IPA_CLIENT_A2_TETHERED_CONS ||
- in->client == IPA_CLIENT_A2_EMBEDDED_CONS) {
- IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx,
- ipa_ctx->hol_timer);
- ipa_write_reg(ipa_ctx->mmio,
- IPA_ENDP_INIT_HOL_BLOCK_EN_n_OFST(ipa_ep_idx),
- ipa_ctx->hol_en);
- ipa_write_reg(ipa_ctx->mmio,
- IPA_ENDP_INIT_HOL_BLOCK_TIMER_n_OFST(ipa_ep_idx),
- ipa_ctx->hol_timer);
- }
+ ipa_program_holb(ep, ipa_ep_idx);
IPADBG("client %d (ep: %d) connected\n", in->client, ipa_ep_idx);
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 76aaad0..1b6181f 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -232,7 +232,7 @@
struct ipa_tx_pkt_wrapper *tx_pkt;
unsigned long irq_flags;
int result;
- u16 sps_flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT;
+ u16 sps_flags = SPS_IOVEC_FLAG_EOT;
dma_addr_t dma_address;
u16 len;
u32 mem_flag = GFP_ATOMIC;
@@ -469,8 +469,7 @@
}
if (i == (num_desc - 1)) {
- iovec->flags |= (SPS_IOVEC_FLAG_EOT |
- SPS_IOVEC_FLAG_INT);
+ iovec->flags |= SPS_IOVEC_FLAG_EOT;
/* "mark" the last desc */
tx_pkt->cnt = IPA_LAST_DESC_CNT;
}
@@ -1018,11 +1017,8 @@
ipa_ctx->ep[ipa_ep_idx].connect.dest_pipe_index =
ipa_ctx->a5_pipe_index++;
ipa_ctx->ep[ipa_ep_idx].connect.src_pipe_index = ipa_ep_idx;
- ipa_ctx->ep[ipa_ep_idx].connect.options =
- SPS_O_AUTO_ENABLE | SPS_O_EOT | SPS_O_ACK_TRANSFERS |
+ ipa_ctx->ep[ipa_ep_idx].connect.options = SPS_O_ACK_TRANSFERS |
SPS_O_NO_DISABLE;
- if (ipa_ctx->polling_mode)
- ipa_ctx->ep[ipa_ep_idx].connect.options |= SPS_O_POLL;
} else {
ipa_ctx->ep[ipa_ep_idx].connect.mode = SPS_MODE_DEST;
ipa_ctx->ep[ipa_ep_idx].connect.source = SPS_DEV_HANDLE_MEM;
@@ -1031,13 +1027,16 @@
ipa_ctx->ep[ipa_ep_idx].connect.src_pipe_index =
ipa_ctx->a5_pipe_index++;
ipa_ctx->ep[ipa_ep_idx].connect.dest_pipe_index = ipa_ep_idx;
- ipa_ctx->ep[ipa_ep_idx].connect.options =
- SPS_O_AUTO_ENABLE | SPS_O_EOT;
- if (ipa_ctx->polling_mode)
+ if (sys_in->client == IPA_CLIENT_A5_LAN_WAN_PROD)
ipa_ctx->ep[ipa_ep_idx].connect.options |=
- SPS_O_ACK_TRANSFERS | SPS_O_POLL;
+ SPS_O_ACK_TRANSFERS;
}
+ ipa_ctx->ep[ipa_ep_idx].connect.options |= (SPS_O_AUTO_ENABLE |
+ SPS_O_EOT);
+ if (ipa_ctx->polling_mode)
+ ipa_ctx->ep[ipa_ep_idx].connect.options |= SPS_O_POLL;
+
ipa_ctx->ep[ipa_ep_idx].connect.desc.size = sys_in->desc_fifo_sz;
ipa_ctx->ep[ipa_ep_idx].connect.desc.base =
dma_alloc_coherent(NULL, ipa_ctx->ep[ipa_ep_idx].connect.desc.size,
@@ -1346,7 +1345,7 @@
ret = sps_transfer_one(sys->ep->ep_hdl, rx_pkt->dma_address,
IPA_RX_SKB_SIZE, rx_pkt,
- SPS_IOVEC_FLAG_INT);
+ 0);
if (ret) {
IPAERR("sps_transfer_one failed %d\n", ret);
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index 9062ab8..add9522 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -128,8 +128,10 @@
* @teth_wq: dedicated workqueue, used for setting up the HW bridge and for
* sending packets using the SW bridge when the system is waking up from power
* collapse
- * @a2_ipa_hdr_len: A2 to IPA header length, used to configure the A2 endpoint
- * for header removal
+ * @a2_ipa_hdr_len: A2 to IPA header length, used for configuring the A2
+ * endpoint for header removal
+ * @ipa_a2_hdr_len: IPA to A2 header length, used for configuring the A2
+ * endpoint for header removal
* @hdr_del: array to store the headers handles in order to delete them later
* @routing_del: array of routing rules handles, one array for IPv4 and one for
* IPv6
@@ -160,6 +162,7 @@
struct stats stats;
struct workqueue_struct *teth_wq;
u16 a2_ipa_hdr_len;
+ u16 ipa_a2_hdr_len;
struct ipa_ioc_del_hdr *hdr_del;
struct ipa_ioc_del_rt_rule *routing_del[TETH_IP_FAMILIES];
struct ipa_ioc_del_flt_rule *filtering_del[TETH_IP_FAMILIES];
@@ -287,6 +290,7 @@
}
hdr_cfg.hdr_len = ipa_a2_hdr_len;
+ teth_ctx->ipa_a2_hdr_len = ipa_a2_hdr_len;
res = ipa_cfg_ep_hdr(teth_ctx->ipa_a2_pipe_hdl, &hdr_cfg);
if (res) {
TETH_ERR("Header insertion config for IPA->A2 pipe failed\n");
@@ -1225,6 +1229,28 @@
enum ipa_rm_event event,
unsigned long data)
{
+ switch (event) {
+ case IPA_RM_RESOURCE_GRANTED:
+ complete(&teth_ctx->is_bridge_prod_up);
+ break;
+
+ case IPA_RM_RESOURCE_RELEASED:
+ complete(&teth_ctx->is_bridge_prod_down);
+ break;
+
+ default:
+ TETH_ERR("Unsupported notification!\n");
+ WARN_ON(1);
+ break;
+ }
+
+ return;
+}
+
+static void a2_prod_notify_cb(void *notify_cb_data,
+ enum ipa_rm_event event,
+ unsigned long data)
+{
int res;
struct ipa_ep_cfg ipa_ep_cfg;
@@ -1243,15 +1269,15 @@
/* Reset the various endpoints configuration */
memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
+ ipa_ep_cfg.hdr.hdr_len = teth_ctx->ipa_a2_hdr_len;
ipa_cfg_ep(teth_ctx->ipa_a2_pipe_hdl, &ipa_ep_cfg);
+ memset(&ipa_ep_cfg, 0, sizeof(ipa_ep_cfg));
ipa_ep_cfg.hdr.hdr_len = teth_ctx->a2_ipa_hdr_len;
ipa_cfg_ep(teth_ctx->a2_ipa_pipe_hdl, &ipa_ep_cfg);
- complete(&teth_ctx->is_bridge_prod_up);
break;
case IPA_RM_RESOURCE_RELEASED:
- complete(&teth_ctx->is_bridge_prod_down);
break;
default:
@@ -1283,6 +1309,7 @@
int teth_bridge_init(ipa_notify_cb *usb_notify_cb_ptr, void **private_data_ptr)
{
int res = 0;
+ struct ipa_rm_register_params a2_prod_reg_params;
TETH_DBG_FUNC_ENTRY();
if (usb_notify_cb_ptr == NULL) {
@@ -1323,10 +1350,22 @@
goto fail_add_dependency_3;
}
+ /* Register for A2_PROD resource notifications */
+ a2_prod_reg_params.user_data = NULL;
+ a2_prod_reg_params.notify_cb = a2_prod_notify_cb;
+ res = ipa_rm_register(IPA_RM_RESOURCE_A2_PROD, &a2_prod_reg_params);
+ if (res) {
+ TETH_ERR("ipa_rm_register() failed\n");
+ goto fail_add_dependency_4;
+ }
+
/* Return 0 as EINPROGRESS is a valid return value at this point */
res = 0;
goto bail;
+fail_add_dependency_4:
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
fail_add_dependency_3:
ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
IPA_RM_RESOURCE_A2_CONS);
@@ -1368,6 +1407,7 @@
teth_ctx->comp_hw_bridge_in_progress = false;
memset(&teth_ctx->stats, 0, sizeof(teth_ctx->stats));
teth_ctx->a2_ipa_hdr_len = 0;
+ teth_ctx->ipa_a2_hdr_len = 0;
memset(teth_ctx->hdr_del,
0,
sizeof(struct ipa_ioc_del_hdr) + TETH_TOTAL_HDR_ENTRIES *
@@ -1402,6 +1442,7 @@
int teth_bridge_disconnect(void)
{
int res;
+ struct ipa_rm_register_params a2_prod_reg_params;
TETH_DBG_FUNC_ENTRY();
if (!teth_ctx->is_connected) {
@@ -1478,6 +1519,13 @@
TETH_ERR(
"Failed deleting ipa_rm dependency BRIDGE_PROD <-> A2_CONS\n");
+ /* Deregister from A2_PROD notifications */
+ a2_prod_reg_params.user_data = NULL;
+ a2_prod_reg_params.notify_cb = a2_prod_notify_cb;
+ res = ipa_rm_deregister(IPA_RM_RESOURCE_A2_PROD, &a2_prod_reg_params);
+ if (res)
+ TETH_ERR("Failed deregistering from A2_prod notifications.\n");
+
teth_ctx->is_connected = false;
bail:
TETH_DBG_FUNC_EXIT();
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 1907adc..a85e31c 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,47 +24,51 @@
#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_RT_STS(base) (base + 0x10)
+#define QPNP_PON_PULL_CTL(base) (base + 0x70)
+#define QPNP_PON_DBC_CTL(base) (base + 0x71)
/* 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_PS_HOLD_RST_CTL(base) (base + 0x5A)
+#define QPNP_PON_WARM_RESET_REASON1(base) (base + 0xA)
+#define QPNP_PON_WARM_RESET_REASON2(base) (base + 0xB)
+#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_PS_HOLD_RST_CTL(base) (base + 0x5A)
-#define QPNP_PON_RESIN_PULL_UP BIT(0)
-#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
-#define QPNP_PON_CBLPWR_PULL_UP BIT(2)
-#define QPNP_PON_S2_CNTL_EN BIT(7)
-#define QPNP_PON_S2_RESET_ENABLE BIT(7)
-#define QPNP_PON_DELAY_BIT_SHIFT 6
+#define QPNP_PON_WARM_RESET_TFT BIT(4)
-#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_RESIN_PULL_UP BIT(0)
+#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
+#define QPNP_PON_CBLPWR_PULL_UP BIT(2)
+#define QPNP_PON_S2_CNTL_EN BIT(7)
+#define QPNP_PON_S2_RESET_ENABLE BIT(7)
+#define QPNP_PON_DELAY_BIT_SHIFT 6
-#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_CBLPWR_N_SET BIT(2)
-#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
+#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_RESET_EN BIT(7)
-#define QPNP_PON_WARM_RESET BIT(0)
-#define QPNP_PON_SHUTDOWN BIT(2)
+#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_CBLPWR_N_SET BIT(2)
+#define QPNP_PON_RESIN_BARK_N_SET BIT(4)
+
+#define QPNP_PON_RESET_EN BIT(7)
+#define QPNP_PON_WARM_RESET BIT(0)
+#define QPNP_PON_SHUTDOWN BIT(2)
/* 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_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(250)
+#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(250)
enum pon_type {
PON_KPDPWR,
@@ -175,6 +179,50 @@
}
EXPORT_SYMBOL(qpnp_pon_system_pwr_off);
+/**
+ * qpnp_pon_is_warm_reset - Checks if the PMIC went through a warm reset.
+ *
+ * Returns > 0 for warm resets, 0 for not warm reset, < 0 for errors
+ *
+ * Note that this function will only return the warm vs not-warm reset status
+ * of the PMIC that is configured as the system-reset device.
+ */
+int qpnp_pon_is_warm_reset(void)
+{
+ struct qpnp_pon *pon = sys_reset_dev;
+ int rc;
+ u8 reg;
+
+ if (!pon)
+ return -EPROBE_DEFER;
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_WARM_RESET_REASON1(pon->base), ®, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read addr=%x, rc(%d)\n",
+ QPNP_PON_WARM_RESET_REASON1(pon->base), rc);
+ return rc;
+ }
+
+ if (reg)
+ return 1;
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_WARM_RESET_REASON2(pon->base), ®, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read addr=%x, rc(%d)\n",
+ QPNP_PON_WARM_RESET_REASON2(pon->base), rc);
+ return rc;
+ }
+ if (reg & QPNP_PON_WARM_RESET_TFT)
+ return 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnp_pon_is_warm_reset);
+
static struct qpnp_pon_config *
qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type)
{
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 2d1b763..e4affc1 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -129,15 +129,40 @@
[HSIC_BAM] = hsic_cons_release_resource,
};
-static enum ipa_rm_event cur_prod_state[MAX_BAMS];
-static enum ipa_rm_event cur_cons_state[MAX_BAMS];
-static int sched_lpm;
-static int lpm_wait_handshake;
-static struct completion prod_avail[MAX_BAMS];
-static struct completion cons_avail[MAX_BAMS];
-static struct completion cons_released[MAX_BAMS];
-static struct completion prod_released[MAX_BAMS];
+struct usb_bam_ipa_handshake_info {
+ enum ipa_rm_event cur_prod_state[MAX_BAMS];
+ enum ipa_rm_event cur_cons_state[MAX_BAMS];
+ int lpm_wait_handshake;
+ int connect_complete;
+ bool lpm_wait_pipes;
+ int bus_suspend;
+ bool in_lpm;
+
+ int (*wake_cb)(void *);
+ void *wake_param;
+ void (*start)(void *, enum usb_bam_pipe_dir);
+ void (*stop)(void *, enum usb_bam_pipe_dir);
+ void *start_stop_param;
+
+ u32 src_idx;
+ u32 dst_idx;
+ bool cons_stopped;
+ bool prod_stopped;
+
+ struct completion prod_avail[MAX_BAMS];
+ struct completion cons_avail[MAX_BAMS];
+ struct completion cons_released[MAX_BAMS];
+ struct completion prod_released[MAX_BAMS];
+
+ struct mutex suspend_resume_mutex;
+ struct work_struct resume_work;
+ struct work_struct suspend_work;
+ struct work_struct finish_suspend_work;
+};
+
+static spinlock_t usb_bam_ipa_handshake_info_lock;
+static struct usb_bam_ipa_handshake_info info;
static spinlock_t usb_bam_peer_handshake_info_lock;
static struct usb_bam_peer_handshake_info peer_handshake_info;
static spinlock_t usb_bam_lock; /* Protect ctx and usb_bam_connections */
@@ -457,6 +482,7 @@
pr_err("%s: ipa_connect failed\n", __func__);
return ret;
}
+ pipe_connect->ipa_clnt_hdl = clnt_hdl;
*pipe = sps_alloc_endpoint();
if (*pipe == NULL) {
@@ -579,6 +605,31 @@
return 0;
}
+static void usb_bam_resume_core(enum usb_bam cur_bam)
+{
+ struct usb_phy *trans = usb_get_transceiver();
+
+ if (cur_bam != HSUSB_BAM)
+ return;
+ BUG_ON(trans == NULL);
+ pr_debug("%s: resume core", __func__);
+ pm_runtime_resume(trans->dev);
+}
+
+static void usb_bam_start_lpm(bool disconnect)
+{
+ struct usb_phy *trans = usb_get_transceiver();
+ BUG_ON(trans == NULL);
+ pr_debug("%s: Going to LPM\n", __func__);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.lpm_wait_handshake = false;
+ info.lpm_wait_pipes = 0;
+ if (disconnect)
+ pm_runtime_put_noidle(trans->dev);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pm_runtime_suspend(trans->dev);
+}
+
int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
{
int ret;
@@ -608,26 +659,136 @@
}
spin_lock(&usb_bam_lock);
-
/* Check if BAM requires RESET before connect and reset of first pipe */
if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
(ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
sps_device_reset(ctx.h_bam[pipe_connect->bam_type]);
+ spin_unlock(&usb_bam_lock);
ret = connect_pipe(idx, bam_pipe_idx);
if (ret) {
pr_err("%s: pipe connection[%d] failure\n", __func__, idx);
- spin_unlock(&usb_bam_lock);
return ret;
}
pipe_connect->enabled = 1;
+ spin_lock(&usb_bam_lock);
ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
-
spin_unlock(&usb_bam_lock);
+
return 0;
}
+static int ipa_suspend_pipes(void)
+{
+ struct usb_bam_pipe_connect *dst_pipe_connect, *src_pipe_connect;
+ int ret1, ret2;
+
+ dst_pipe_connect = &usb_bam_connections[info.dst_idx];
+ src_pipe_connect = &usb_bam_connections[info.src_idx];
+
+ if (dst_pipe_connect->ipa_clnt_hdl == -1 ||
+ src_pipe_connect->ipa_clnt_hdl == -1) {
+ pr_err("%s: One of handles is -1, not connected?", __func__);
+ }
+
+ ret1 = ipa_suspend(dst_pipe_connect->ipa_clnt_hdl);
+ if (ret1)
+ pr_err("%s: ipa_suspend on dst failed with %d", __func__, ret1);
+ ret2 = ipa_suspend(src_pipe_connect->ipa_clnt_hdl);
+ if (ret2)
+ pr_err("%s: ipa_suspend on src failed with %d", __func__, ret2);
+
+ return ret1 | ret2;
+}
+
+static int ipa_resume_pipes(void)
+{
+ struct usb_bam_pipe_connect *dst_pipe_connect, *src_pipe_connect;
+ int ret1, ret2;
+
+ src_pipe_connect = &usb_bam_connections[info.src_idx];
+ dst_pipe_connect = &usb_bam_connections[info.dst_idx];
+
+ if (dst_pipe_connect->ipa_clnt_hdl == -1 ||
+ src_pipe_connect->ipa_clnt_hdl == -1) {
+ pr_err("%s: One of handles is -1, not connected?", __func__);
+ }
+
+ ret1 = ipa_resume(dst_pipe_connect->ipa_clnt_hdl);
+ if (ret1)
+ pr_err("%s: ipa_resume on dst failed with %d", __func__, ret1);
+ ret2 = ipa_resume(src_pipe_connect->ipa_clnt_hdl);
+ if (ret2)
+ pr_err("%s: ipa_resume on src failed with %d", __func__, ret2);
+
+ return ret1 | ret2;
+}
+
+static void usb_bam_finish_suspend(void)
+{
+ int ret;
+ u32 cons_empty;
+ struct sps_pipe *cons_pipe = ctx.usb_bam_sps.sps_pipes[info.dst_idx];
+ struct usb_bam_pipe_connect *pipe_connect = &
+ usb_bam_connections[info.dst_idx];
+ enum usb_bam cur_bam = pipe_connect->bam_type;
+
+ if (cur_bam != HSUSB_BAM) {
+ pr_err("%s: Wrong type of BAM=%s\n", __func__,
+ bam_enable_strings[cur_bam]);
+ return;
+ }
+
+ mutex_lock(&info.suspend_resume_mutex);
+
+ /* If resume was called don't finish this work */
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (!info.bus_suspend) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_err("%s: Bus suspend in progress\n", __func__);
+ goto no_lpm;
+ }
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ ret = sps_is_pipe_empty(cons_pipe, &cons_empty);
+ if (ret) {
+ pr_err("%s: sps_is_pipe_empty failed with %d\n", __func__, ret);
+ goto no_lpm;
+ }
+
+ /* Stop CONS transfers and go to lpm if no more data in the pipe */
+ if (cons_empty) {
+ if (info.stop && !info.cons_stopped)
+ info.stop(info.start_stop_param,
+ PEER_PERIPHERAL_TO_USB);
+ pr_err("%s: Starting LPM on Bus Suspend\n", __func__);
+ info.cons_stopped = 1;
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED) {
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+ ipa_rm_resource_cons[cur_bam]);
+ }
+ ipa_suspend_pipes();
+ mutex_unlock(&info.suspend_resume_mutex);
+ usb_bam_start_lpm(0);
+ return;
+ }
+
+no_lpm:
+
+ /* Finish the handshake. Resume Sequence will start automatically
+ by the data in the pipes */
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+ ipa_rm_resource_cons[cur_bam]);
+ mutex_unlock(&info.suspend_resume_mutex);
+}
+
+void usb_bam_finish_suspend_(struct work_struct *w)
+{
+ usb_bam_finish_suspend();
+}
+
static void usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
unsigned long data)
{
@@ -637,14 +798,14 @@
case IPA_RM_RESOURCE_GRANTED:
pr_debug("%s: %s_PROD resource granted\n",
__func__, bam_enable_strings[*cur_bam]);
- cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_GRANTED;
- complete_all(&prod_avail[*cur_bam]);
+ info.cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&info.prod_avail[*cur_bam]);
break;
case IPA_RM_RESOURCE_RELEASED:
pr_debug("%s: %s_PROD resource released\n",
__func__, bam_enable_strings[*cur_bam]);
- cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&prod_released[*cur_bam]);
+ info.cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&info.prod_released[*cur_bam]);
break;
default:
break;
@@ -657,12 +818,33 @@
pr_debug("%s: Request %s_CONS resource\n",
__func__, bam_enable_strings[cur_bam]);
- cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
- complete_all(&cons_avail[cur_bam]);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&info.cons_avail[cur_bam]);
- if (ctx.pipes_enabled_per_bam[cur_bam])
+ spin_lock(&usb_bam_lock);
+ if (ctx.pipes_enabled_per_bam[cur_bam] && info.connect_complete &&
+ !info.bus_suspend && !info.prod_stopped) {
+ spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_debug("%s: ACK on cons_request", __func__);
return 0;
+ }
+ /* A2 wakeup from LPM */
+ if (cur_bam == HSUSB_BAM && ctx.pipes_enabled_per_bam[cur_bam] &&
+ info.connect_complete && info.bus_suspend) {
+ info.bus_suspend = 0;
+ spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ if (info.wake_cb)
+ info.wake_cb(info.wake_param);
+ } else {
+ spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ }
+
+ pr_debug("%s: EINPROGRESS on cons_request", __func__);
return -EINPROGRESS;
}
@@ -681,12 +863,23 @@
pr_debug("%s: Release %s_CONS resource\n",
__func__, bam_enable_strings[cur_bam]);
- cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&cons_released[cur_bam]);
+ info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&info.cons_released[cur_bam]);
- if (!ctx.pipes_enabled_per_bam[cur_bam])
+ spin_lock(&usb_bam_lock);
+ if (!ctx.pipes_enabled_per_bam[cur_bam]) {
+ spin_unlock(&usb_bam_lock);
+ pr_debug("%s: ACK on cons_release", __func__);
return 0;
+ }
+ spin_unlock(&usb_bam_lock);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (cur_bam == HSUSB_BAM && info.bus_suspend)
+ queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ pr_debug("%s: EINPROGRESS cons_release", __func__);
return -EINPROGRESS;
}
@@ -747,24 +940,24 @@
pr_debug("%s Request %s_PROD_RES\n", __func__,
bam_enable_strings[cur_bam]);
- if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
pr_debug("%s: CONS already granted for some reason\n",
__func__);
- if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+ if (info.cur_prod_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
pr_debug("%s: PROD already granted for some reason\n",
__func__);
- init_completion(&prod_avail[cur_bam]);
- init_completion(&cons_avail[cur_bam]);
+ init_completion(&info.prod_avail[cur_bam]);
+ init_completion(&info.cons_avail[cur_bam]);
ret = ipa_rm_request_resource(ipa_rm_resource_prod[cur_bam]);
if (!ret) {
- cur_prod_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
- complete_all(&prod_avail[cur_bam]);
+ info.cur_prod_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+ complete_all(&info.prod_avail[cur_bam]);
pr_debug("%s: PROD_GRANTED without wait\n", __func__);
} else if (ret == -EINPROGRESS) {
pr_debug("%s: Waiting for PROD_GRANTED\n", __func__);
- if (!wait_for_completion_timeout(&prod_avail[cur_bam],
+ if (!wait_for_completion_timeout(&info.prod_avail[cur_bam],
USB_BAM_TIMEOUT))
pr_err("%s: Timeout wainting for PROD_GRANTED\n",
__func__);
@@ -772,6 +965,261 @@
pr_err("%s: ipa_rm_request_resource ret =%d\n", __func__, ret);
}
+void wait_for_cons_granted(enum usb_bam cur_bam)
+{
+ pr_debug("%s: Waiting for CONS\n", __func__);
+ if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_GRANTED) {
+ if (!wait_for_completion_timeout(&info.cons_avail[cur_bam],
+ USB_BAM_TIMEOUT*6))
+ pr_err("%s: Timeout wainting for CONS_REQUEST\n",
+ __func__);
+ pr_err("%s: Finished waiting for CONS\n", __func__);
+ }
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.connect_complete = 1;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_debug("%s: CONS is granted\n", __func__);
+
+ if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_GRANTED) {
+ pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+ ipa_rm_resource_cons[HSUSB_BAM]);
+ }
+}
+
+void usb_bam_wait_for_cons_granted(
+ struct usb_bam_connect_ipa_params *ipa_params)
+{
+ struct usb_bam_pipe_connect *pipe_connect;
+ enum usb_bam cur_bam;
+ u8 src_idx;
+
+ src_idx = ipa_params->src_idx;
+ pipe_connect = &usb_bam_connections[src_idx];
+ cur_bam = pipe_connect->bam_type;
+
+ wait_for_cons_granted(cur_bam);
+}
+
+static void wait_for_prod_release(enum usb_bam cur_bam)
+{
+ int ret;
+
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pr_debug("%s consumer already released\n", __func__);
+ if (info.cur_prod_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pr_debug("%s producer already released\n", __func__);
+
+ init_completion(&info.prod_released[cur_bam]);
+ init_completion(&info.cons_released[cur_bam]);
+ pr_debug("%s: Releasing %s_PROD\n", __func__,
+ bam_enable_strings[cur_bam]);
+ ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
+ if (!ret) {
+ pr_debug("%s: Released without waiting\n", __func__);
+ info.cur_prod_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+ complete_all(&info.prod_released[cur_bam]);
+ } else if (ret == -EINPROGRESS) {
+ pr_debug("%s: Waiting for PROD_RELEASED\n", __func__);
+ if (!wait_for_completion_timeout(&info.prod_released[cur_bam],
+ USB_BAM_TIMEOUT))
+ pr_err("%s: Timeout waiting for PROD_RELEASED\n",
+ __func__);
+ } else
+ pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret);
+}
+
+static int check_pipes_empty(u8 src_idx, u8 dst_idx)
+{
+ struct sps_pipe *prod_pipe, *cons_pipe;
+ u32 prod_empty, cons_empty;
+
+ /* If we have any remaints in the pipes we don't go to sleep */
+ prod_pipe = ctx.usb_bam_sps.sps_pipes[src_idx];
+ cons_pipe = ctx.usb_bam_sps.sps_pipes[dst_idx];
+ if (sps_is_pipe_empty(prod_pipe, &prod_empty) ||
+ sps_is_pipe_empty(cons_pipe, &cons_empty)) {
+ pr_err("%s: sps_is_pipe_empty failed with\n", __func__);
+ return 0;
+ }
+ if (!prod_empty || !cons_empty) {
+ pr_err("%s: pipes not empty prod=%d cond=%d", __func__,
+ prod_empty, cons_empty);
+ return 0;
+ }
+
+ return 1;
+}
+
+void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params)
+{
+ struct usb_bam_pipe_connect *pipe_connect;
+ enum usb_bam cur_bam;
+ u8 src_idx, dst_idx;
+
+ if (!ipa_params) {
+ pr_err("%s: Invalid ipa params\n", __func__);
+ return;
+ }
+
+ src_idx = ipa_params->src_idx;
+ dst_idx = ipa_params->dst_idx;
+
+ if (src_idx >= ctx.max_connections || dst_idx >= ctx.max_connections) {
+ pr_err("%s: Invalid connection index src=%d dst=%d\n",
+ __func__, src_idx, dst_idx);
+ }
+
+ pipe_connect = &usb_bam_connections[src_idx];
+ cur_bam = pipe_connect->bam_type;
+ if (cur_bam != HSUSB_BAM)
+ return;
+
+ info.src_idx = src_idx;
+ info.dst_idx = dst_idx;
+
+ pr_err("%s: Starting suspend sequence(BAM=%s)\n", __func__,
+ bam_enable_strings[cur_bam]);
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.bus_suspend = 1;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ /* Stop PROD transfers */
+ if (info.stop) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.stop(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+ info.prod_stopped = true;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ }
+
+ /* Don't go to LPM if data in the pipes */
+ if (!check_pipes_empty(src_idx, dst_idx)) {
+ pr_err("%s: pipes not empty, won't start suspend", __func__);
+ return;
+ }
+
+ queue_work(ctx.usb_bam_wq, &info.suspend_work);
+}
+
+static void usb_bam_start_suspend(struct work_struct *w)
+{
+ pr_debug("%s: enter", __func__);
+ mutex_lock(&info.suspend_resume_mutex);
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (!info.bus_suspend) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_err("%s: Resume started, not suspending", __func__);
+ return;
+ }
+
+ /* Stop PROD transfers in case they were started */
+ if (info.stop && !info.prod_stopped) {
+ info.stop(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+ info.prod_stopped = true;
+ }
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ /* Don't start LPM seq if data in the pipes */
+ if (!check_pipes_empty(info.src_idx, info.dst_idx)) {
+ mutex_unlock(&info.suspend_resume_mutex);
+ return;
+ }
+
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.lpm_wait_handshake = true;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ wait_for_prod_release(HSUSB_BAM);
+
+ mutex_unlock(&info.suspend_resume_mutex);
+ if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_RELEASED)
+ usb_bam_finish_suspend();
+ else
+ pr_debug("Consumer not released yet\n");
+}
+
+static void usb_bam_finish_resume(struct work_struct *w)
+{
+ struct usb_phy *trans = usb_get_transceiver();
+
+ BUG_ON(trans == NULL);
+ pr_debug("%s: enter", __func__);
+ mutex_lock(&info.suspend_resume_mutex);
+ /* Suspend happened in the meantime */
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (info.bus_suspend) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ pr_err("%s: Bus suspended, not resuming", __func__);
+ mutex_unlock(&info.suspend_resume_mutex);
+ return;
+ }
+ info.lpm_wait_handshake = true;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ wait_for_prod_granted(HSUSB_BAM);
+ wait_for_cons_granted(HSUSB_BAM);
+ if (info.cons_stopped) {
+ ipa_resume_pipes();
+ if (info.start) {
+ pr_debug("%s: Enqueue CONS transfer", __func__);
+ info.start(info.start_stop_param,
+ PEER_PERIPHERAL_TO_USB);
+ info.cons_stopped = 0;
+ }
+ }
+
+ if (info.start) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.start(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+ info.prod_stopped = false;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ }
+ if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_GRANTED) {
+ pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+ ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+ ipa_rm_resource_cons[HSUSB_BAM]);
+ }
+ mutex_unlock(&info.suspend_resume_mutex);
+ pr_debug("%s: done", __func__);
+}
+
+void usb_bam_resume(struct usb_bam_connect_ipa_params *ipa_params)
+{
+ enum usb_bam cur_bam;
+ u8 src_idx, dst_idx;
+ struct usb_bam_pipe_connect *pipe_connect;
+
+ pr_debug("%s: Resuming\n", __func__);
+
+ if (!ipa_params) {
+ pr_err("%s: Invalid ipa params\n", __func__);
+ return;
+ }
+
+ src_idx = ipa_params->src_idx;
+ dst_idx = ipa_params->dst_idx;
+
+ if (src_idx >= ctx.max_connections || dst_idx >= ctx.max_connections) {
+ pr_err("%s: Invalid connection index src=%d dst=%d\n",
+ __func__, src_idx, dst_idx);
+ return;
+ }
+
+ pipe_connect = &usb_bam_connections[src_idx];
+ cur_bam = pipe_connect->bam_type;
+ if (cur_bam != HSUSB_BAM)
+ return;
+
+ info.in_lpm = false;
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.bus_suspend = 0;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ queue_work(ctx.usb_bam_wq, &info.resume_work);
+}
+
int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
u8 idx;
@@ -800,27 +1248,38 @@
pipe_connect = &usb_bam_connections[idx];
cur_bam = pipe_connect->bam_type;
- if (cur_bam == HSUSB_BAM) {
- spin_lock(&usb_bam_lock);
- sched_lpm = 0;
- lpm_wait_handshake = 1;
- spin_unlock(&usb_bam_lock);
- }
-
if (pipe_connect->enabled) {
- pr_debug("%s: connection %d was already established\n",
+ pr_err("%s: connection %d was already established\n",
__func__, idx);
return 0;
}
+ pr_debug("%s: enter", __func__);
+ mutex_lock(&info.suspend_resume_mutex);
+
spin_lock(&usb_bam_lock);
+ if (ctx.pipes_enabled_per_bam[cur_bam] == 0) {
+ spin_unlock(&usb_bam_lock);
+ if (cur_bam == HSUSB_BAM) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.lpm_wait_handshake = 1;
+ info.connect_complete = 0;
+ info.lpm_wait_pipes = 1;
+ info.bus_suspend = 0;
+ info.cons_stopped = 0;
+ info.prod_stopped = 0;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ }
+ usb_bam_resume_core(cur_bam);
+ } else
+ spin_unlock(&usb_bam_lock);
/* Check if BAM requires RESET before connect and reset first pipe */
+ spin_lock(&usb_bam_lock);
if ((pdata->reset_on_connect[cur_bam] == true) &&
(ctx.pipes_enabled_per_bam[cur_bam] == 0))
sps_device_reset(ctx.h_bam[cur_bam]);
-
- spin_unlock(&usb_bam_lock);
+ spin_unlock(&usb_bam_lock);
if (ipa_params->dir == USB_TO_PEER_PERIPHERAL) {
pr_debug("%s: Starting connect sequence\n", __func__);
@@ -830,23 +1289,19 @@
ret = connect_pipe_ipa(idx, ipa_params);
if (ret) {
pr_err("%s: pipe connection failure\n", __func__);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
spin_lock(&usb_bam_lock);
-
pipe_connect->enabled = 1;
ctx.pipes_enabled_per_bam[cur_bam] += 1;
-
- if (ipa_params->dir == PEER_PERIPHERAL_TO_USB &&
- cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED) {
- pr_debug("%s: Notify CONS_GRANTED\n", __func__);
- ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
- ipa_rm_resource_cons[cur_bam]);
- pr_debug("%s: Ended connect sequence\n", __func__);
- }
-
spin_unlock(&usb_bam_lock);
+ if (ipa_params->dir == PEER_PERIPHERAL_TO_USB && cur_bam == HSUSB_BAM)
+ wait_for_cons_granted(cur_bam);
+
+ mutex_unlock(&info.suspend_resume_mutex);
+ pr_debug("%s: done", __func__);
return 0;
}
@@ -904,6 +1359,14 @@
usb_bam_set_inactivity_timer(pipe_connect->bam_type);
spin_unlock(&usb_bam_lock);
+ /* A2 wakeup not from LPM (CONS was up) */
+ wait_for_prod_granted(pipe_connect->bam_type);
+ if (info.start) {
+ pr_debug("%s: Enqueue PROD transfer", __func__);
+ info.start(info.start_stop_param,
+ USB_TO_PEER_PERIPHERAL);
+ }
+
break;
case USB_BAM_EVENT_INACTIVITY:
@@ -1111,9 +1574,22 @@
int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
void *param)
{
+ info.wake_cb = callback;
+ info.wake_param = param;
return __usb_bam_register_wake_cb(idx, callback, param, true);
}
+int usb_bam_register_start_stop_cbs(
+ void (*start)(void *, enum usb_bam_pipe_dir),
+ void (*stop)(void *, enum usb_bam_pipe_dir),
+ void *param)
+{
+ info.start = start;
+ info.stop = stop;
+ info.start_stop_param = param;
+ return 0;
+}
+
int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param)
{
u32 ret = 0;
@@ -1156,78 +1632,29 @@
return 0;
}
- spin_lock(&usb_bam_lock);
-
ret = disconnect_pipe(idx);
if (ret) {
pr_err("%s: src pipe disconnection failure\n", __func__);
- spin_unlock(&usb_bam_lock);
return ret;
}
pipe_connect->enabled = 0;
-
+ spin_lock(&usb_bam_lock);
if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0)
pr_err("%s: wrong pipes enabled counter for bam_type=%d\n",
__func__, pipe_connect->bam_type);
else
ctx.pipes_enabled_per_bam[pipe_connect->bam_type] -= 1;
-
spin_unlock(&usb_bam_lock);
return 0;
}
-static void usb_bam_start_lpm(void)
-{
- struct usb_phy *trans = usb_get_transceiver();
- BUG_ON(trans == NULL);
- spin_lock(&usb_bam_lock);
- lpm_wait_handshake = 0;
- if (sched_lpm) {
- pr_debug("%s: Going to LPM\n", __func__);
- spin_unlock(&usb_bam_lock);
- pm_runtime_resume(trans->dev);
- pm_runtime_put_noidle(trans->dev);
- pm_runtime_suspend(trans->dev);
- return;
- }
- spin_unlock(&usb_bam_lock);
-}
-
-static void wait_for_prod_release(enum usb_bam cur_bam)
-{
- int ret;
-
- if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
- pr_debug("%s consumer already released\n", __func__);
- if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
- pr_debug("%s producer already released\n", __func__);
-
- init_completion(&prod_released[cur_bam]);
- init_completion(&cons_released[cur_bam]);
- pr_debug("%s: Releasing %s_PROD\n", __func__,
- bam_enable_strings[cur_bam]);
- ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
- if (!ret) {
- pr_debug("%s: Released without waiting\n", __func__);
- cur_prod_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
- complete_all(&prod_released[cur_bam]);
- } else if (ret == -EINPROGRESS) {
- pr_debug("%s: Waiting for PROD_RELEASED\n", __func__);
- if (!wait_for_completion_timeout(&prod_released[cur_bam],
- USB_BAM_TIMEOUT))
- pr_err("%s: Timeout waiting for PROD_RELEASED\n",
- __func__);
- } else
- pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret);
-}
-
static void wait_for_cons_release(enum usb_bam cur_bam)
{
pr_debug("%s: Waiting for CONS release\n", __func__);
- if (cur_prod_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
- if (!wait_for_completion_timeout(&cons_released[cur_bam],
+ if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
+ if (!wait_for_completion_timeout(&info.cons_released[cur_bam],
USB_BAM_TIMEOUT))
pr_err("%s: Timeout wainting for CONS_RELEASE\n",
__func__);
@@ -1244,13 +1671,17 @@
struct sps_connect *sps_connection;
enum usb_bam cur_bam;
-
if (!ipa_params->prod_clnt_hdl && !ipa_params->cons_clnt_hdl) {
pr_err("%s: Both of the handles is missing\n", __func__);
return -EINVAL;
}
pr_debug("%s: Starting disconnect sequence\n", __func__);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ info.connect_complete = 0;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+ mutex_lock(&info.suspend_resume_mutex);
/* Delay USB core to go into lpm before we finish our handshake */
if (ipa_params->prod_clnt_hdl) {
idx = ipa_params->dst_idx;
@@ -1258,12 +1689,15 @@
/* Do the release handshake with the A2 via RM */
cur_bam = pipe_connect->bam_type;
+ info.lpm_wait_pipes = 1;
wait_for_prod_release(cur_bam);
/* close USB -> IPA pipe */
+ usb_bam_resume_core(cur_bam);
ret = ipa_disconnect(ipa_params->prod_clnt_hdl);
if (ret) {
pr_err("%s: dst pipe disconnection failure\n",
__func__);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
@@ -1274,6 +1708,7 @@
if (ret) {
pr_err("%s: failure to disconnect pipe %d\n",
__func__, idx);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
}
@@ -1288,6 +1723,7 @@
if (ret) {
pr_err("%s: src pipe disconnection failure\n",
__func__);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
@@ -1299,17 +1735,24 @@
if (ret) {
pr_err("%s: failure to disconnect pipe %d\n",
__func__, idx);
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
- pr_debug("%s: Notify CONS release\n", __func__);
- if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+ pipe_connect->ipa_clnt_hdl = -1;
+
+ if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED) {
+ pr_debug("%s Notify CONS _RELEASED\n", __func__);
ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
ipa_rm_resource_cons[cur_bam]);
+ }
pr_debug("%s Ended disconnect sequence\n", __func__);
- usb_bam_start_lpm();
+ mutex_unlock(&info.suspend_resume_mutex);
+ usb_bam_start_lpm(1);
+ return 0;
}
+ mutex_unlock(&info.suspend_resume_mutex);
return 0;
}
EXPORT_SYMBOL(usb_bam_disconnect_ipa);
@@ -1630,6 +2073,7 @@
props.num_pipes = pdata->usb_bam_num_pipes;
props.callback = usb_bam_sps_events;
props.user = bam_enable_strings[bam_idx];
+ props.options = SPS_BAM_OPT_IRQ_WAKEUP;
/*
* HSUSB and HSIC Cores don't support RESET ACK signal to BAMs
@@ -1744,10 +2188,12 @@
spin_lock(&usb_bam_lock);
- ctx.inactivity_timer_ms[bam] = timer_d;
/* Apply new timer setting if bam has running pipes */
- if (ctx.pipes_enabled_per_bam[bam] > 0)
- usb_bam_set_inactivity_timer(bam);
+ if (ctx.inactivity_timer_ms[bam] != timer_d) {
+ ctx.inactivity_timer_ms[bam] = timer_d;
+ if (ctx.pipes_enabled_per_bam[bam] > 0)
+ usb_bam_set_inactivity_timer(bam);
+ }
spin_unlock(&usb_bam_lock);
}
@@ -1808,18 +2254,23 @@
ctx.pipes_enabled_per_bam[i] = 0;
ctx.inactivity_timer_ms[i] = 0;
ctx.is_bam_inactivity[i] = false;
- init_completion(&prod_avail[i]);
- complete(&prod_avail[i]);
- init_completion(&cons_avail[i]);
- complete(&cons_avail[i]);
- init_completion(&cons_released[i]);
- complete(&cons_released[i]);
- init_completion(&prod_released[i]);
- complete(&prod_released[i]);
- cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
- cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
+ init_completion(&info.prod_avail[i]);
+ complete(&info.prod_avail[i]);
+ init_completion(&info.cons_avail[i]);
+ complete(&info.cons_avail[i]);
+ init_completion(&info.cons_released[i]);
+ complete(&info.cons_released[i]);
+ init_completion(&info.prod_released[i]);
+ complete(&info.prod_released[i]);
+ info.cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
+ info.cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
}
+ INIT_WORK(&info.resume_work, usb_bam_finish_resume);
+ INIT_WORK(&info.suspend_work, usb_bam_start_suspend);
+ INIT_WORK(&info.finish_suspend_work, usb_bam_finish_suspend_);
+ mutex_init(&info.suspend_resume_mutex);
+
spin_lock_init(&usb_bam_peer_handshake_info_lock);
INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
@@ -1835,8 +2286,8 @@
destroy_workqueue(ctx.usb_bam_wq);
return ret;
}
+ spin_lock_init(&usb_bam_ipa_handshake_info_lock);
usb_bam_ipa_create_resources();
-
spin_lock_init(&usb_bam_lock);
return ret;
@@ -1909,14 +2360,14 @@
bool msm_bam_lpm_ok(void)
{
- spin_lock(&usb_bam_lock);
- if (lpm_wait_handshake) {
- sched_lpm = 1;
- spin_unlock(&usb_bam_lock);
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (info.lpm_wait_handshake || info.lpm_wait_pipes) {
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
pr_err("%s: Scheduling LPM for later\n", __func__);
return 0;
} else {
- spin_unlock(&usb_bam_lock);
+ info.in_lpm = 1;
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
pr_err("%s: Going to LPM now\n", __func__);
return 1;
}
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index c09373a..9b3973b 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -177,6 +177,9 @@
int vbatt_cutoff_count;
int low_voltage_detect;
int vbatt_cutoff_retries;
+ bool first_report_after_suspend;
+ bool soc_updated_on_resume;
+ int last_soc_at_suspend;
};
/*
@@ -2387,10 +2390,11 @@
rbatt, fcc_uah, unusable_charge_uah, cc_uah);
pr_debug("calculated SOC = %d\n", new_calculated_soc);
- if (new_calculated_soc != calculated_soc)
+ if (new_calculated_soc != calculated_soc) {
+ calculated_soc = new_calculated_soc;
update_power_supply(chip);
+ }
- calculated_soc = new_calculated_soc;
firsttime = 0;
get_current_time(&chip->last_recalc_time);
@@ -2495,15 +2499,31 @@
/* 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);
+ soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
- /* restrict soc to 1% change */
if (last_soc != -EINVAL) {
- if (soc < last_soc && soc != 0)
+ if (chip->first_report_after_suspend) {
+ chip->first_report_after_suspend = false;
+ if (chip->soc_updated_on_resume) {
+ /* coming here after a long suspend */
+ chip->soc_updated_on_resume = false;
+ if (last_soc < soc)
+ /* if soc has falsely increased during
+ * suspend, set the soc_at_suspend
+ */
+ soc = chip->last_soc_at_suspend;
+ } else {
+ /*
+ * suspended for a short time
+ * report the last_soc before suspend
+ */
+ soc = chip->last_soc_at_suspend;
+ }
+ } else if (soc < last_soc && soc != 0) {
soc = last_soc - 1;
- if (soc > last_soc && soc != 100)
+ } else if (soc > last_soc && soc != 100) {
soc = last_soc + 1;
+ }
}
last_soc = bound_soc(soc);
@@ -3560,12 +3580,11 @@
static int pm8921_bms_suspend(struct device *dev)
{
- /*
- * set the last reported soc to invalid, so that
- * next time we resume we don't want to restrict
- * the decrease of soc by only 1%
- */
- last_soc = -EINVAL;
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
+
+ cancel_delayed_work_sync(&chip->calculate_soc_delayed_work);
+
+ chip->last_soc_at_suspend = last_soc;
return 0;
}
@@ -3575,22 +3594,30 @@
int rc;
unsigned long time_since_last_recalc;
unsigned long tm_now_sec;
+ struct pm8921_bms_chip *chip = dev_get_drvdata(dev);
rc = get_current_time(&tm_now_sec);
if (rc) {
pr_err("Could not read current time: %d\n", rc);
return 0;
}
- if (tm_now_sec > the_chip->last_recalc_time) {
+
+ if (tm_now_sec > chip->last_recalc_time) {
time_since_last_recalc = tm_now_sec -
- the_chip->last_recalc_time;
+ chip->last_recalc_time;
pr_debug("Time since last recalc: %lu\n",
time_since_last_recalc);
- if (time_since_last_recalc >= the_chip->soc_calc_period) {
- the_chip->last_recalc_time = tm_now_sec;
- recalculate_soc(the_chip);
+ if ((time_since_last_recalc * 1000) >=
+ chip->soc_calc_period) {
+ chip->last_recalc_time = tm_now_sec;
+ recalculate_soc(chip);
+ chip->soc_updated_on_resume = true;
}
}
+ chip->first_report_after_suspend = true;
+ update_power_supply(chip);
+ schedule_delayed_work(&chip->calculate_soc_delayed_work,
+ msecs_to_jiffies(chip->soc_calc_period));
return 0;
}
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index 5313593..c53bcd2 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -790,6 +790,15 @@
return 0;
}
+static int pm8xxx_ccadc_suspend(struct device *dev)
+{
+ struct pm8xxx_ccadc_chip *chip = dev_get_drvdata(dev);
+
+ cancel_delayed_work_sync(&chip->calib_ccadc_work);
+
+ return 0;
+}
+
#define CCADC_CALIB_TEMP_THRESH 20
static int pm8xxx_ccadc_resume(struct device *dev)
{
@@ -823,8 +832,11 @@
|| delta_temp > CCADC_CALIB_TEMP_THRESH) {
the_chip->last_calib_time = current_time_sec;
the_chip->last_calib_temp = batt_temp;
- cancel_delayed_work(&the_chip->calib_ccadc_work);
schedule_delayed_work(&the_chip->calib_ccadc_work, 0);
+ } else {
+ schedule_delayed_work(&the_chip->calib_ccadc_work,
+ msecs_to_jiffies(the_chip->calib_delay_ms -
+ (time_since_last_calib * 1000)));
}
}
@@ -832,6 +844,7 @@
}
static const struct dev_pm_ops pm8xxx_ccadc_pm_ops = {
+ .suspend = pm8xxx_ccadc_suspend,
.resume = pm8xxx_ccadc_resume,
};
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 63fb0a5..5cdb666 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -176,6 +176,7 @@
POWER_SUPPLY_ATTR(type),
POWER_SUPPLY_ATTR(scope),
POWER_SUPPLY_ATTR(system_temp_level),
+ POWER_SUPPLY_ATTR(resistance),
/* Properties of type `const char *' */
POWER_SUPPLY_ATTR(model_name),
POWER_SUPPLY_ATTR(manufacturer),
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index eec6d39..9a642d6 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -24,6 +24,7 @@
#include <linux/rtc.h>
#include <linux/delay.h>
#include <linux/qpnp/qpnp-adc.h>
+#include <linux/qpnp/power-on.h>
#include <linux/mfd/pm8xxx/batterydata-lib.h>
/* BMS Register Offsets */
@@ -116,7 +117,9 @@
u8 revision1;
u8 revision2;
int battery_present;
+ int battery_status;
bool new_battery;
+ bool done_charging;
bool last_soc_invalid;
/* platform data */
int r_sense_uohm;
@@ -135,13 +138,16 @@
struct sf_lut *rbatt_sf_lut;
int default_rbatt_mohm;
int rbatt_capacitive_mohm;
+ int rbatt_mohm;
struct delayed_work calculate_soc_delayed_work;
struct work_struct recalc_work;
struct mutex bms_output_lock;
struct mutex last_ocv_uv_mutex;
+ struct mutex vbat_monitor_mutex;
struct mutex soc_invalidation_mutex;
+ struct mutex last_soc_mutex;
bool use_external_rsense;
bool use_ocv_thresholds;
@@ -152,22 +158,24 @@
int shutdown_iavg_ma;
struct wake_lock low_voltage_wake_lock;
- bool low_voltage_wake_lock_held;
int low_voltage_threshold;
int low_soc_calc_threshold;
int low_soc_calculate_soc_ms;
int calculate_soc_ms;
struct wake_lock soc_wake_lock;
+ struct wake_lock cv_wake_lock;
uint16_t ocv_reading_at_100;
uint16_t prev_last_good_ocv_raw;
int last_ocv_uv;
int last_ocv_temp;
int last_cc_uah;
+ unsigned long last_soc_change_sec;
unsigned long tm_sec;
+ unsigned long report_tm_sec;
bool first_time_calc_soc;
bool first_time_calc_uuc;
- int pon_ocv_uv;
+ int64_t software_cc_uah;
int iavg_samples_ma[IAVG_SAMPLES];
int iavg_index;
@@ -176,15 +184,17 @@
int last_soc;
int last_soc_est;
int last_soc_unbound;
-
- int charge_time_us;
- int catch_up_time_us;
+ bool was_charging_at_sleep;
+ int charge_start_tm_sec;
+ int catch_up_time_sec;
struct single_row_lut *adjusted_fcc_temp_lut;
+ struct qpnp_adc_tm_btm_param vbat_monitor_params;
+ struct qpnp_adc_tm_btm_param die_temp_monitor_params;
+ int temperature_margin;
unsigned int vadc_v0625;
unsigned int vadc_v1250;
- int ibat_max_ua;
int prev_uuc_iavg_ma;
int prev_pc_unusable;
int ibat_at_cv_ua;
@@ -193,6 +203,7 @@
int calculated_soc;
int prev_voltage_based_soc;
bool use_voltage_soc;
+ bool in_cv_range;
int prev_batt_terminal_uv;
int high_ocv_correction_limit_uv;
@@ -215,10 +226,9 @@
};
static enum power_supply_property msm_bms_power_props[] = {
- POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
- POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_RESISTANCE,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
};
@@ -364,12 +374,17 @@
static inline int convert_vbatt_raw_to_uv(struct qpnp_bms_chip *chip,
uint16_t reading)
{
- int uv;
+ int64_t uv;
+ int rc;
uv = vadc_reading_to_uv(reading);
- pr_debug("%u raw converted into %d uv\n", reading, uv);
+ pr_debug("%u raw converted into %lld uv\n", reading, uv);
uv = adjust_vbatt_reading(chip, uv);
- pr_debug("adjusted into %d uv\n", uv);
+ pr_debug("adjusted into %lld uv\n", uv);
+ rc = qpnp_vbat_sns_comp_result(&uv);
+ if (rc)
+ pr_debug("could not compensate vbatt\n");
+ pr_debug("compensated into %lld uv\n", uv);
return uv;
}
@@ -429,7 +444,8 @@
static int get_battery_current(struct qpnp_bms_chip *chip, int *result_ua)
{
- int vsense_uv = 0;
+ int rc, vsense_uv = 0;
+ int64_t temp_current;
if (chip->r_sense_uohm == 0) {
pr_err("r_sense is zero\n");
@@ -444,8 +460,15 @@
pr_debug("vsense_uv=%duV\n", vsense_uv);
/* cast for signed division */
- *result_ua = div_s64((vsense_uv * 1000000LL), (int)chip->r_sense_uohm);
- pr_debug("ibat=%duA\n", *result_ua);
+ temp_current = div_s64((vsense_uv * 1000000LL),
+ (int)chip->r_sense_uohm);
+
+ rc = qpnp_iadc_comp_result(&temp_current);
+ if (rc)
+ pr_debug("error compensation failed: %d\n", rc);
+
+ *result_ua = temp_current;
+ pr_debug("err compensated ibat=%duA\n", *result_ua);
return 0;
}
@@ -533,6 +556,7 @@
raw->last_good_ocv_raw);
chip->last_ocv_uv = raw->last_good_ocv_uv;
chip->last_ocv_temp = batt_temp;
+ chip->software_cc_uah = 0;
pr_debug("last_good_ocv_uv = %d\n", raw->last_good_ocv_uv);
}
@@ -564,7 +588,7 @@
pr_err("cc reenable failed: %d\n", rc);
}
-static bool is_battery_charging(struct qpnp_bms_chip *chip)
+static int get_battery_status(struct qpnp_bms_chip *chip)
{
union power_supply_propval ret = {0,};
@@ -574,7 +598,30 @@
/* if battery has been registered, use the status property */
chip->batt_psy->get_property(chip->batt_psy,
POWER_SUPPLY_PROP_STATUS, &ret);
- return ret.intval == POWER_SUPPLY_STATUS_CHARGING;
+ return ret.intval;
+ }
+
+ /* Default to false if the battery power supply is not registered. */
+ pr_debug("battery power supply is not registered\n");
+ return POWER_SUPPLY_STATUS_UNKNOWN;
+}
+
+static bool is_battery_charging(struct qpnp_bms_chip *chip)
+{
+ return get_battery_status(chip) == POWER_SUPPLY_STATUS_CHARGING;
+}
+
+static bool is_battery_present(struct qpnp_bms_chip *chip)
+{
+ union power_supply_propval ret = {0,};
+
+ if (chip->batt_psy == NULL)
+ chip->batt_psy = power_supply_get_by_name("battery");
+ if (chip->batt_psy) {
+ /* if battery has been registered, use the status property */
+ chip->batt_psy->get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_PRESENT, &ret);
+ return ret.intval;
}
/* Default to false if the battery power supply is not registered. */
@@ -584,20 +631,7 @@
static bool is_battery_full(struct qpnp_bms_chip *chip)
{
- union power_supply_propval ret = {0,};
-
- if (chip->batt_psy == NULL)
- chip->batt_psy = power_supply_get_by_name("battery");
- if (chip->batt_psy) {
- /* if battery has been registered, use the status property */
- chip->batt_psy->get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_STATUS, &ret);
- return ret.intval == POWER_SUPPLY_STATUS_FULL;
- }
-
- /* Default to true if the battery power supply is not registered. */
- pr_debug("battery power supply is not registered\n");
- return true;
+ return get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL;
}
static int get_simultaneous_batt_v_and_i(struct qpnp_bms_chip *chip,
@@ -661,24 +695,29 @@
static void reset_for_new_battery(struct qpnp_bms_chip *chip, int batt_temp)
{
chip->last_ocv_uv = estimate_ocv(chip);
+ mutex_lock(&chip->last_soc_mutex);
chip->last_soc = -EINVAL;
+ chip->last_soc_invalid = true;
+ mutex_unlock(&chip->last_soc_mutex);
chip->soc_at_cv = -EINVAL;
chip->shutdown_soc_invalid = true;
chip->shutdown_soc = 0;
chip->shutdown_iavg_ma = 0;
chip->prev_pc_unusable = -EINVAL;
reset_cc(chip);
+ chip->software_cc_uah = 0;
chip->last_cc_uah = INT_MIN;
chip->last_ocv_temp = batt_temp;
- chip->last_soc_invalid = true;
chip->prev_batt_terminal_uv = 0;
}
#define OCV_RAW_UNINITIALIZED 0xFFFF
+#define MIN_OCV_UV 2000000
static int read_soc_params_raw(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
int batt_temp)
{
+ bool warm_reset = false;
int rc;
mutex_lock(&chip->bms_output_lock);
@@ -711,13 +750,37 @@
if (chip->prev_last_good_ocv_raw == OCV_RAW_UNINITIALIZED) {
convert_and_store_ocv(chip, raw, batt_temp);
- pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
+ pr_debug("PON_OCV_UV = %d, cc = %llx\n",
+ chip->last_ocv_uv, raw->cc);
+ warm_reset = qpnp_pon_is_warm_reset();
+ if (raw->last_good_ocv_uv < MIN_OCV_UV
+ || warm_reset > 0) {
+ pr_debug("OCV is stale or bad, estimating new OCV.\n");
+ chip->last_ocv_uv = estimate_ocv(chip);
+ raw->last_good_ocv_uv = chip->last_ocv_uv;
+ reset_cc(chip);
+ pr_debug("New PON_OCV_UV = %d, cc = %llx\n",
+ chip->last_ocv_uv, raw->cc);
+ }
} else if (chip->new_battery) {
/* if a new battery was inserted, estimate the ocv */
reset_for_new_battery(chip, batt_temp);
raw->cc = 0;
raw->last_good_ocv_uv = chip->last_ocv_uv;
chip->new_battery = false;
+ } else if (chip->done_charging) {
+ chip->done_charging = false;
+ /* if we just finished charging, reset CC and fake 100% */
+ chip->ocv_reading_at_100 = raw->last_good_ocv_raw;
+ chip->last_ocv_uv = chip->max_voltage_uv;
+ raw->last_good_ocv_uv = chip->max_voltage_uv;
+ raw->cc = 0;
+ reset_cc(chip);
+ chip->last_ocv_temp = batt_temp;
+ chip->software_cc_uah = 0;
+ chip->last_cc_uah = INT_MIN;
+ pr_debug("EOC Battery full ocv_reading = 0x%x\n",
+ chip->ocv_reading_at_100);
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
convert_and_store_ocv(chip, raw, batt_temp);
/* forget the old cc value upon ocv */
@@ -726,20 +789,10 @@
raw->last_good_ocv_uv = chip->last_ocv_uv;
}
- /* fake a high OCV if done charging */
- if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
+ /* stop faking a high OCV if we get a new OCV */
+ if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw)
chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
- } else {
- /*
- * force 100% ocv by selecting the highest voltage the
- * battery could ever reach
- */
- raw->last_good_ocv_uv = chip->max_voltage_uv;
- chip->last_ocv_uv = chip->max_voltage_uv;
- chip->last_ocv_temp = batt_temp;
- reset_cc(chip);
- raw->cc = 0;
- }
+
pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
raw->last_good_ocv_raw, raw->last_good_ocv_uv);
pr_debug("cc_raw= 0x%llx\n", raw->cc);
@@ -818,11 +871,25 @@
*/
static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc)
{
- int64_t cc_voltage_uv, cc_pvh, cc_uah;
struct qpnp_iadc_calib calibration;
+ struct qpnp_vadc_result result;
+ int64_t cc_voltage_uv, cc_pvh, cc_uah;
+ int ibat_ua, rc;
+
+ rc = qpnp_vadc_read(DIE_TEMP, &result);
+ if (rc) {
+ pr_err("could not read pmic die temperature: %d\n", rc);
+ return chip->software_cc_uah;
+ }
+
+ rc = get_battery_current(chip, &ibat_ua);
+ if (rc) {
+ pr_err("could not read battery current: %d\n", rc);
+ return chip->software_cc_uah;
+ }
qpnp_iadc_get_gain_and_offset(&calibration);
- pr_debug("cc = %lld\n", cc);
+ pr_debug("cc = %lld, die_temp = %lld\n", cc, result.physical);
cc_voltage_uv = cc_reading_to_uv(cc);
cc_voltage_uv = cc_adjust_for_gain(cc_voltage_uv,
calibration.gain_raw
@@ -831,9 +898,12 @@
cc_pvh = cc_uv_to_pvh(cc_voltage_uv);
pr_debug("cc_pvh = %lld pvh\n", cc_pvh);
cc_uah = div_s64(cc_pvh, chip->r_sense_uohm);
- /* cc_raw had 4 bits of extra precision.
- By now it should be within 32 bit range */
- return (int)cc_uah;
+ rc = qpnp_iadc_comp_result(&cc_uah);
+ if (rc)
+ pr_debug("error compensation failed: %d\n", rc);
+ chip->software_cc_uah += cc_uah;
+ reset_cc(chip);
+ return (int)chip->software_cc_uah;
}
static int get_rbatt(struct qpnp_bms_chip *chip,
@@ -1123,21 +1193,22 @@
return rc;
}
-static int calculate_delta_time(struct qpnp_bms_chip *chip, int *delta_time_s)
+static int calculate_delta_time(unsigned long *time_stamp, int *delta_time_s)
{
unsigned long now_tm_sec = 0;
/* default to delta time = 0 if anything fails */
*delta_time_s = 0;
- get_current_time(&now_tm_sec);
+ if (get_current_time(&now_tm_sec)) {
+ pr_err("RTC read failed\n");
+ return 0;
+ }
- *delta_time_s = (now_tm_sec - chip->tm_sec);
- pr_debug("tm_sec = %ld, now_tm_sec = %ld delta_s = %d\n",
- chip->tm_sec, now_tm_sec, *delta_time_s);
+ *delta_time_s = (now_tm_sec - *time_stamp);
/* remember this time */
- chip->tm_sec = now_tm_sec;
+ *time_stamp = now_tm_sec;
return 0;
}
@@ -1148,7 +1219,9 @@
{
int soc_rbatt;
- calculate_delta_time(chip, ¶ms->delta_time_s);
+ calculate_delta_time(&chip->tm_sec, ¶ms->delta_time_s);
+ pr_debug("tm_sec = %ld, delta_s = %d\n",
+ chip->tm_sec, params->delta_time_s);
params->fcc_uah = calculate_fcc(chip, batt_temp);
pr_debug("FCC = %uuAh batt_temp = %d\n", params->fcc_uah, batt_temp);
@@ -1169,6 +1242,12 @@
params->rbatt_mohm = get_rbatt(chip, soc_rbatt, batt_temp);
pr_debug("rbatt_mohm = %d\n", params->rbatt_mohm);
+ if (params->rbatt_mohm != chip->rbatt_mohm
+ && chip->bms_psy.name != NULL) {
+ chip->rbatt_mohm = params->rbatt_mohm;
+ power_supply_changed(&chip->bms_psy);
+ }
+
calculate_iavg(chip, params->cc_uah, ¶ms->iavg_ua,
params->delta_time_s);
@@ -1234,9 +1313,12 @@
ocv_est_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv);
chip->last_ocv_uv = ocv_est_uv;
+ mutex_lock(&chip->last_soc_mutex);
chip->last_soc = -EINVAL;
chip->last_soc_invalid = true;
+ mutex_unlock(&chip->last_soc_mutex);
reset_cc(chip);
+ chip->software_cc_uah = 0;
chip->last_cc_uah = INT_MIN;
stop_ocv_updates(chip);
@@ -1277,25 +1359,26 @@
module_param_cb(bms_reset, &bms_reset_ops, &bms_reset, 0644);
+#define VBATT_ERROR_MARGIN 20000
static int charging_adjustments(struct qpnp_bms_chip *chip,
struct soc_params *params, int soc,
int vbat_uv, int ibat_ua, int batt_temp)
{
- int chg_soc;
- int batt_terminal_uv = vbat_uv + (ibat_ua * chip->r_conn_mohm) / 1000;
+ int chg_soc, batt_terminal_uv;
+
+ batt_terminal_uv = vbat_uv + VBATT_ERROR_MARGIN
+ + (ibat_ua * chip->r_conn_mohm) / 1000;
if (chip->soc_at_cv == -EINVAL) {
- /* In constant current charging return the calc soc */
- if (batt_terminal_uv <= chip->max_voltage_uv)
- pr_debug("CC CHG SOC %d\n", soc);
-
- /* Note the CC to CV point */
if (batt_terminal_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);
+ } else {
+ /* In constant current charging return the calc soc */
+ pr_debug("CC CHG SOC %d\n", soc);
}
chip->prev_batt_terminal_uv = batt_terminal_uv;
@@ -1349,18 +1432,40 @@
* a wakelock untill soc = 0%
*/
if (vbat_uv <= chip->low_voltage_threshold
- && !chip->low_voltage_wake_lock_held) {
+ && !wake_lock_active(&chip->low_voltage_wake_lock)) {
pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
wake_lock(&chip->low_voltage_wake_lock);
- chip->low_voltage_wake_lock_held = 1;
} else if (vbat_uv > chip->low_voltage_threshold
- && chip->low_voltage_wake_lock_held) {
+ && wake_lock_active(&chip->low_voltage_wake_lock)) {
pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
- chip->low_voltage_wake_lock_held = 0;
wake_unlock(&chip->low_voltage_wake_lock);
}
}
+#define VBATT_ERROR_MARGIN 20000
+static void cv_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv)
+{
+ /*
+ * if battery is very low (v_cutoff voltage + 20mv) hold
+ * a wakelock untill soc = 0%
+ */
+ if (wake_lock_active(&chip->cv_wake_lock)) {
+ if (chip->soc_at_cv != -EINVAL) {
+ pr_debug("hit CV, releasing cv wakelock\n");
+ wake_unlock(&chip->cv_wake_lock);
+ } else if (!is_battery_charging(chip)) {
+ pr_debug("charging stopped, releasing cv wakelock\n");
+ wake_unlock(&chip->cv_wake_lock);
+ }
+ } else if (vbat_uv > chip->max_voltage_uv - VBATT_ERROR_MARGIN
+ && chip->soc_at_cv == -EINVAL
+ && is_battery_charging(chip)
+ && !wake_lock_active(&chip->cv_wake_lock)) {
+ pr_debug("voltage = %d holding cv wakelock\n", vbat_uv);
+ wake_lock(&chip->cv_wake_lock);
+ }
+}
+
#define NO_ADJUST_HIGH_SOC_THRESHOLD 90
static int adjust_soc(struct qpnp_bms_chip *chip, struct soc_params *params,
int soc, int batt_temp)
@@ -1384,14 +1489,12 @@
}
very_low_voltage_check(chip, vbat_uv);
+ cv_voltage_check(chip, vbat_uv);
delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
ocv_est_uv = vbat_uv + (ibat_ua * params->rbatt_mohm)/1000;
- chip->ibat_max_ua = (ocv_est_uv - chip->v_cutoff_uv) * 1000
- / (params->rbatt_mohm);
-
pc_est = calculate_pc(chip, ocv_est_uv, batt_temp);
soc_est = div_s64((s64)params->fcc_uah * pc_est - params->uuc_uah*100,
(s64)params->fcc_uah - params->uuc_uah);
@@ -1529,6 +1632,7 @@
}
}
+#define SLEEP_RECALC_INTERVAL 3
static int calculate_state_of_charge(struct qpnp_bms_chip *chip,
struct raw_soc_params *raw,
int batt_temp)
@@ -1537,7 +1641,7 @@
int shutdown_soc, new_calculated_soc, remaining_usable_charge_uah;
struct soc_params params;
- if (!chip->battery_present) {
+ if (!is_battery_present(chip)) {
pr_debug("battery gone, reporting 100\n");
new_calculated_soc = 100;
goto done_calculating;
@@ -1609,7 +1713,6 @@
soc, shutdown_soc);
find_ocv_for_soc(chip, ¶ms, batt_temp,
shutdown_soc, &new_ocv_uv);
- chip->pon_ocv_uv = chip->last_ocv_uv;
chip->last_ocv_uv = new_ocv_uv;
remaining_usable_charge_uah = params.ocv_charge_uah
@@ -1640,13 +1743,30 @@
}
chip->calculated_soc = new_calculated_soc;
+ pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
+ mutex_lock(&chip->last_soc_mutex);
if (chip->last_soc_invalid) {
chip->last_soc_invalid = false;
chip->last_soc = -EINVAL;
}
- pr_debug("CC based calculated SOC = %d\n", chip->calculated_soc);
- chip->first_time_calc_soc = 0;
+ /*
+ * Check if more than a long time has passed since the last
+ * calculation (more than n times compared to the soc recalculation
+ * rate, where n is defined by SLEEP_RECALC_INTERVAL). If this is true,
+ * then the system must have gone through a long sleep, and SoC can be
+ * allowed to become unbounded by the last reported SoC
+ */
+ if (params.delta_time_s * 1000 >
+ chip->calculate_soc_ms * SLEEP_RECALC_INTERVAL
+ && !chip->first_time_calc_soc) {
+ chip->last_soc_unbound = true;
+ chip->last_soc_change_sec = chip->last_recalc_time;
+ pr_debug("last_soc unbound because elapsed time = %d\n",
+ params.delta_time_s);
+ }
+ mutex_unlock(&chip->last_soc_mutex);
get_current_time(&chip->last_recalc_time);
+ chip->first_time_calc_soc = 0;
return chip->calculated_soc;
}
@@ -1684,10 +1804,15 @@
struct qpnp_vadc_result result;
struct raw_soc_params raw;
- wake_lock(&chip->soc_wake_lock);
+ if (!wake_lock_active(&chip->soc_wake_lock))
+ wake_lock(&chip->soc_wake_lock);
+ mutex_lock(&chip->vbat_monitor_mutex);
+ qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ mutex_unlock(&chip->vbat_monitor_mutex);
if (chip->use_voltage_soc) {
soc = calculate_soc_from_voltage(chip);
} else {
+ qpnp_iadc_calibrate_for_trim();
rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
if (rc) {
pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
@@ -1726,7 +1851,7 @@
int soc = recalculate_soc(chip);
if (soc < chip->low_soc_calc_threshold
- || chip->low_voltage_wake_lock_held)
+ || wake_lock_active(&chip->low_voltage_wake_lock))
schedule_delayed_work(&chip->calculate_soc_delayed_work,
round_jiffies_relative(msecs_to_jiffies
(chip->low_soc_calculate_soc_ms)));
@@ -1762,32 +1887,20 @@
#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 qpnp_bms_chip *chip,
- int delta_time_us, int new_soc, int prev_soc)
+static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec,
+ int catch_up_sec, int new_soc, int prev_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
+ * 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 not charging, return last soc */
- if (!is_battery_charging(chip))
- return prev_soc;
-
- chg_time_sec = DIV_ROUND_UP(chip->charge_time_us, USEC_PER_SEC);
- catch_up_sec = DIV_ROUND_UP(chip->catch_up_time_us, USEC_PER_SEC);
+ pr_debug("cts = %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
if (catch_up_sec == 0)
return new_soc;
- pr_debug("cts= %d catch_up_sec = %d\n", chg_time_sec, catch_up_sec);
-
/*
* if charging for more than catch_up time, simply return
* new soc
@@ -1820,14 +1933,17 @@
return chip->prev_voltage_based_soc;
}
+#define SOC_CHANGE_PER_SEC 20
static int report_cc_based_soc(struct qpnp_bms_chip *chip)
{
- int soc;
- int delta_time_us;
+ int soc, soc_change;
+ int time_since_last_change_sec, charge_time_sec = 0;
+ unsigned long last_change_sec;
struct timespec now;
struct qpnp_vadc_result result;
int batt_temp;
int rc;
+ bool charging, charging_since_last_report;
soc = chip->calculated_soc;
@@ -1842,68 +1958,84 @@
result.measurement);
batt_temp = (int)result.physical;
- 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;
- }
+ mutex_lock(&chip->last_soc_mutex);
+ last_change_sec = chip->last_soc_change_sec;
+ calculate_delta_time(&last_change_sec, &time_since_last_change_sec);
+ charging = is_battery_charging(chip);
+ charging_since_last_report = charging || (chip->last_soc_unbound
+ && chip->was_charging_at_sleep);
/*
* account for charge time - limit it to SOC_CATCHUP_SEC to
* avoid overflows when charging continues for extended periods
*/
- if (is_battery_charging(chip)) {
- if (chip->charge_time_us == 0) {
+ if (charging) {
+ if (chip->charge_start_tm_sec == 0) {
/*
* calculating soc for the first time
* after start of chg. Initialize catchup time
*/
if (abs(soc - chip->last_soc) < MAX_CATCHUP_SOC)
- chip->catch_up_time_us =
+ chip->catch_up_time_sec =
(soc - chip->last_soc)
- * SOC_CATCHUP_SEC_PER_PERCENT
- * USEC_PER_SEC;
+ * SOC_CATCHUP_SEC_PER_PERCENT;
else
- chip->catch_up_time_us =
- SOC_CATCHUP_SEC_MAX * USEC_PER_SEC;
+ chip->catch_up_time_sec = SOC_CATCHUP_SEC_MAX;
- if (chip->catch_up_time_us < 0)
- chip->catch_up_time_us = 0;
+ if (chip->catch_up_time_sec < 0)
+ chip->catch_up_time_sec = 0;
+ chip->charge_start_tm_sec = last_change_sec;
}
- /* add charge time */
- if (chip->charge_time_us < SOC_CATCHUP_SEC_MAX * USEC_PER_SEC)
- chip->charge_time_us += delta_time_us;
+ charge_time_sec = min(SOC_CATCHUP_SEC_MAX, (int)last_change_sec
+ - chip->charge_start_tm_sec);
/* end catchup if calculated soc and last soc are same */
if (chip->last_soc == soc)
- chip->catch_up_time_us = 0;
+ chip->catch_up_time_sec = 0;
}
- /* last_soc < soc ... scale and catch up */
- if (chip->last_soc != -EINVAL && chip->last_soc < soc && soc != 100)
- soc = scale_soc_while_chg(chip, delta_time_us,
- soc, chip->last_soc);
+ if (chip->last_soc != -EINVAL) {
+ /* last_soc < soc ... if we have not been charging at all
+ * since the last time this was called, report previous SoC.
+ * Otherwise, scale and catch up.
+ */
+ if (chip->last_soc < soc && !charging_since_last_report)
+ soc = chip->last_soc;
+ else if (chip->last_soc < soc && soc != 100)
+ soc = scale_soc_while_chg(chip, charge_time_sec,
+ chip->catch_up_time_sec,
+ soc, chip->last_soc);
- if (chip->last_soc_unbound)
- chip->last_soc_unbound = false;
- else if (chip->last_soc != -EINVAL) {
+ soc_change = min((int)abs(chip->last_soc - soc),
+ time_since_last_change_sec / SOC_CHANGE_PER_SEC);
+ if (chip->last_soc_unbound) {
+ chip->last_soc_unbound = false;
+ } else {
+ /*
+ * if soc have not been unbound by resume,
+ * only change reported SoC by 1.
+ */
+ soc_change = min(1, soc_change);
+ }
+
if (soc < chip->last_soc && soc != 0)
- soc = chip->last_soc - 1;
+ soc = chip->last_soc - soc_change;
if (soc > chip->last_soc && soc != 100)
- soc = chip->last_soc + 1;
+ soc = chip->last_soc + soc_change;
}
- pr_debug("last_soc = %d, calculated_soc = %d, soc = %d\n",
- chip->last_soc, chip->calculated_soc, soc);
+ if (chip->last_soc != soc)
+ chip->last_soc_change_sec = last_change_sec;
+
+ pr_debug("last_soc = %d, calculated_soc = %d, soc = %d, time since last change = %d\n",
+ chip->last_soc, chip->calculated_soc,
+ soc, time_since_last_change_sec);
chip->last_soc = bound_soc(soc);
backup_soc_and_iavg(chip, batt_temp, chip->last_soc);
pr_debug("Reported SOC = %d\n", chip->last_soc);
chip->t_soc_queried = now;
+ mutex_unlock(&chip->last_soc_mutex);
return soc;
}
@@ -1919,16 +2051,281 @@
return report_cc_based_soc(chip);
}
+static void configure_vbat_monitor_low(struct qpnp_bms_chip *chip)
+{
+ mutex_lock(&chip->vbat_monitor_mutex);
+ if (chip->vbat_monitor_params.state_request
+ == ADC_TM_HIGH_LOW_THR_ENABLE) {
+ /*
+ * Battery is now around or below v_cutoff
+ */
+ pr_debug("battery entered cutoff range\n");
+ if (!wake_lock_active(&chip->low_voltage_wake_lock)) {
+ pr_debug("voltage low, holding wakelock\n");
+ wake_lock(&chip->low_voltage_wake_lock);
+ cancel_delayed_work_sync(
+ &chip->calculate_soc_delayed_work);
+ schedule_delayed_work(
+ &chip->calculate_soc_delayed_work, 0);
+ }
+ chip->vbat_monitor_params.state_request =
+ ADC_TM_HIGH_THR_ENABLE;
+ chip->vbat_monitor_params.high_thr =
+ (chip->low_voltage_threshold + VBATT_ERROR_MARGIN);
+ pr_debug("set low thr to %d and high to %d\n",
+ chip->vbat_monitor_params.low_thr,
+ chip->vbat_monitor_params.high_thr);
+ chip->vbat_monitor_params.low_thr = 0;
+ } else if (chip->vbat_monitor_params.state_request
+ == ADC_TM_LOW_THR_ENABLE) {
+ /*
+ * Battery is in normal operation range.
+ */
+ pr_debug("battery entered normal range\n");
+ if (wake_lock_active(&chip->cv_wake_lock)) {
+ wake_unlock(&chip->cv_wake_lock);
+ pr_debug("releasing cv wake lock\n");
+ }
+ chip->in_cv_range = false;
+ chip->vbat_monitor_params.state_request =
+ ADC_TM_HIGH_LOW_THR_ENABLE;
+ chip->vbat_monitor_params.high_thr = chip->max_voltage_uv
+ - VBATT_ERROR_MARGIN;
+ chip->vbat_monitor_params.low_thr =
+ chip->low_voltage_threshold;
+ pr_debug("set low thr to %d and high to %d\n",
+ chip->vbat_monitor_params.low_thr,
+ chip->vbat_monitor_params.high_thr);
+ }
+ qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ mutex_unlock(&chip->vbat_monitor_mutex);
+}
+
+#define CV_LOW_THRESHOLD_HYST_UV 100000
+static void configure_vbat_monitor_high(struct qpnp_bms_chip *chip)
+{
+ mutex_lock(&chip->vbat_monitor_mutex);
+ if (chip->vbat_monitor_params.state_request
+ == ADC_TM_HIGH_LOW_THR_ENABLE) {
+ /*
+ * Battery is around vddmax
+ */
+ pr_debug("battery entered vddmax range\n");
+ chip->in_cv_range = true;
+ if (!wake_lock_active(&chip->cv_wake_lock)) {
+ wake_lock(&chip->cv_wake_lock);
+ pr_debug("holding cv wake lock\n");
+ }
+ schedule_work(&chip->recalc_work);
+ chip->vbat_monitor_params.state_request =
+ ADC_TM_LOW_THR_ENABLE;
+ chip->vbat_monitor_params.low_thr =
+ (chip->max_voltage_uv - CV_LOW_THRESHOLD_HYST_UV);
+ chip->vbat_monitor_params.high_thr = chip->max_voltage_uv * 2;
+ pr_debug("set low thr to %d and high to %d\n",
+ chip->vbat_monitor_params.low_thr,
+ chip->vbat_monitor_params.high_thr);
+ } else if (chip->vbat_monitor_params.state_request
+ == ADC_TM_HIGH_THR_ENABLE) {
+ /*
+ * Battery is in normal operation range.
+ */
+ pr_debug("battery entered normal range\n");
+ if (wake_lock_active(&chip->low_voltage_wake_lock)) {
+ pr_debug("voltage high, releasing wakelock\n");
+ wake_unlock(&chip->low_voltage_wake_lock);
+ }
+ chip->vbat_monitor_params.state_request =
+ ADC_TM_HIGH_LOW_THR_ENABLE;
+ chip->vbat_monitor_params.high_thr =
+ chip->max_voltage_uv - VBATT_ERROR_MARGIN;
+ chip->vbat_monitor_params.low_thr =
+ chip->low_voltage_threshold;
+ pr_debug("set low thr to %d and high to %d\n",
+ chip->vbat_monitor_params.low_thr,
+ chip->vbat_monitor_params.high_thr);
+ }
+ qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ mutex_unlock(&chip->vbat_monitor_mutex);
+}
+
+static void btm_notify_vbat(enum qpnp_tm_state state, void *ctx)
+{
+ struct qpnp_bms_chip *chip = ctx;
+ int vbat_uv;
+ struct qpnp_vadc_result result;
+ int rc;
+
+ rc = qpnp_vadc_read(VBAT_SNS, &result);
+ pr_debug("vbat = %lld, raw = 0x%x\n", result.physical, result.adc_code);
+
+ get_battery_voltage(&vbat_uv);
+ pr_debug("vbat is at %d, state is at %d\n", vbat_uv, state);
+
+ if (state == ADC_TM_LOW_STATE) {
+ pr_debug("low voltage btm notification triggered\n");
+ if (vbat_uv - VBATT_ERROR_MARGIN
+ < chip->vbat_monitor_params.low_thr) {
+ configure_vbat_monitor_low(chip);
+ } else {
+ pr_debug("faulty btm trigger, discarding\n");
+ qpnp_adc_tm_channel_measure(
+ &chip->vbat_monitor_params);
+ }
+ } else if (state == ADC_TM_HIGH_STATE) {
+ pr_debug("high voltage btm notification triggered\n");
+ if (vbat_uv + VBATT_ERROR_MARGIN
+ > chip->vbat_monitor_params.high_thr) {
+ configure_vbat_monitor_high(chip);
+ } else {
+ pr_debug("faulty btm trigger, discarding\n");
+ qpnp_adc_tm_channel_measure(
+ &chip->vbat_monitor_params);
+ }
+ } else {
+ pr_debug("unknown voltage notification state: %d\n", state);
+ }
+ power_supply_changed(&chip->bms_psy);
+}
+
+static int reset_vbat_monitoring(struct qpnp_bms_chip *chip)
+{
+ int rc;
+
+ chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_DISABLE;
+ rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ if (rc) {
+ pr_err("tm measure failed: %d\n", rc);
+ return rc;
+ }
+ mutex_lock(&chip->vbat_monitor_mutex);
+ if (wake_lock_active(&chip->low_voltage_wake_lock)) {
+ pr_debug("battery removed, releasing wakelock\n");
+ wake_unlock(&chip->low_voltage_wake_lock);
+ }
+ if (chip->in_cv_range) {
+ pr_debug("battery removed, removing in_cv_range state\n");
+ chip->in_cv_range = false;
+ }
+ mutex_unlock(&chip->vbat_monitor_mutex);
+ return 0;
+}
+
+static int setup_vbat_monitoring(struct qpnp_bms_chip *chip)
+{
+ int rc;
+
+ rc = qpnp_adc_tm_is_ready();
+ if (rc) {
+ pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
+ return -EPROBE_DEFER;
+ }
+
+ if (!is_battery_present(chip)) {
+ pr_debug("no battery inserted, do not setup vbat monitoring\n");
+ return 0;
+ }
+
+ chip->vbat_monitor_params.low_thr = chip->low_voltage_threshold;
+ chip->vbat_monitor_params.high_thr = chip->max_voltage_uv
+ - VBATT_ERROR_MARGIN;
+ chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
+ chip->vbat_monitor_params.channel = VBAT_SNS;
+ chip->vbat_monitor_params.btm_ctx = (void *)chip;
+ chip->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
+ chip->vbat_monitor_params.threshold_notification = &btm_notify_vbat;
+ pr_debug("set low thr to %d and high to %d\n",
+ chip->vbat_monitor_params.low_thr,
+ chip->vbat_monitor_params.high_thr);
+ rc = qpnp_adc_tm_channel_measure(&chip->vbat_monitor_params);
+ if (rc) {
+ pr_err("tm setup failed: %d\n", rc);
+ return rc;
+ }
+ pr_debug("setup complete\n");
+ return 0;
+}
+
+static void charging_began(struct qpnp_bms_chip *chip)
+{
+ mutex_lock(&chip->last_soc_mutex);
+ chip->charge_start_tm_sec = 0;
+ chip->catch_up_time_sec = 0;
+ mutex_unlock(&chip->last_soc_mutex);
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ chip->soc_at_cv = -EINVAL;
+ chip->prev_chg_soc = -EINVAL;
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+
+static void charging_ended(struct qpnp_bms_chip *chip)
+{
+ mutex_lock(&chip->last_soc_mutex);
+ chip->charge_start_tm_sec = 0;
+ chip->catch_up_time_sec = 0;
+ mutex_unlock(&chip->last_soc_mutex);
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ chip->soc_at_cv = -EINVAL;
+ chip->prev_chg_soc = -EINVAL;
+ if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL)
+ chip->done_charging = true;
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+
+static void battery_status_check(struct qpnp_bms_chip *chip)
+{
+ int status = get_battery_status(chip);
+
+ if (chip->battery_status != status) {
+ if (status == POWER_SUPPLY_STATUS_CHARGING) {
+ pr_debug("charging started\n");
+ charging_began(chip);
+ } else if (chip->battery_status
+ == POWER_SUPPLY_STATUS_CHARGING) {
+ pr_debug("charging ended\n");
+ charging_ended(chip);
+ }
+ chip->battery_status = status;
+ /* a new battery was inserted or removed, so force a soc
+ * recalculation to update the SoC */
+ schedule_work(&chip->recalc_work);
+ }
+}
+
+static void battery_insertion_check(struct qpnp_bms_chip *chip)
+{
+ bool present = is_battery_present(chip);
+
+ mutex_lock(&chip->vbat_monitor_mutex);
+ if (chip->battery_present != present) {
+ if (chip->battery_present != -EINVAL) {
+ if (present) {
+ setup_vbat_monitoring(chip);
+ chip->new_battery = true;
+ } else {
+ reset_vbat_monitoring(chip);
+ }
+ }
+ chip->battery_present = present;
+ /* a new battery was inserted or removed, so force a soc
+ * recalculation to update the SoC */
+ schedule_work(&chip->recalc_work);
+ }
+ mutex_unlock(&chip->vbat_monitor_mutex);
+}
+
/* Returns capacity as a SoC percentage between 0 and 100 */
static int get_prop_bms_capacity(struct qpnp_bms_chip *chip)
{
return report_state_of_charge(chip);
}
-/* Returns estimated max current that the battery can supply in uA */
-static int get_prop_bms_current_max(struct qpnp_bms_chip *chip)
+/* Returns estimated battery resistance */
+static int get_prop_bms_batt_resistance(struct qpnp_bms_chip *chip)
{
- return chip->ibat_max_ua;
+ return chip->rbatt_mohm * 1000;
}
/* Returns instantaneous current in uA */
@@ -1950,25 +2347,13 @@
return chip->fcc_mah * 1000;
}
-static int get_prop_bms_present(struct qpnp_bms_chip *chip)
-{
- return chip->battery_present;
-}
-
-static void set_prop_bms_present(struct qpnp_bms_chip *chip, int present)
-{
- if (chip->battery_present != present) {
- chip->battery_present = present;
- if (present)
- chip->new_battery = true;
- /* a new battery was inserted or removed, so force a soc
- * recalculation to update the SoC */
- schedule_work(&chip->recalc_work);
- }
-}
-
static void qpnp_bms_external_power_changed(struct power_supply *psy)
{
+ struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
+ bms_psy);
+
+ battery_insertion_check(chip);
+ battery_status_check(chip);
}
static int qpnp_bms_power_get_property(struct power_supply *psy,
@@ -1985,32 +2370,12 @@
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = get_prop_bms_current_now(chip);
break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- val->intval = get_prop_bms_current_max(chip);
+ case POWER_SUPPLY_PROP_RESISTANCE:
+ val->intval = get_prop_bms_batt_resistance(chip);
break;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = get_prop_bms_charge_full_design(chip);
break;
- case POWER_SUPPLY_PROP_PRESENT:
- val->intval = get_prop_bms_present(chip);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int qpnp_bms_power_set_property(struct power_supply *psy,
- enum power_supply_property psp,
- const union power_supply_propval *val)
-{
- struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
- bms_psy);
-
- switch (psp) {
- case POWER_SUPPLY_PROP_PRESENT:
- set_prop_bms_present(chip, val->intval);
- break;
default:
return -EINVAL;
}
@@ -2138,6 +2503,8 @@
batt_data = &palladium_1500_data;
} else if (chip->batt_type == BATT_OEM) {
batt_data = &oem_batt_data;
+ } else if (chip->batt_type == BATT_QRD_4V35_2000MAH) {
+ batt_data = &QRD_4v35_2000mAh_data;
} else {
battery_id = read_battery_id(chip);
if (battery_id < 0) {
@@ -2229,6 +2596,7 @@
SPMI_PROP_READ(ocv_low_threshold_uv,
"ocv-voltage-low-threshold-uv", rc);
SPMI_PROP_READ(low_voltage_threshold, "low-voltage-threshold", rc);
+ SPMI_PROP_READ(temperature_margin, "tm-temp-margin", rc);
if (chip->adjust_soc_low_threshold >= 45)
chip->adjust_soc_low_threshold = 45;
@@ -2255,6 +2623,8 @@
chip->calculated_soc = -EINVAL;
chip->last_soc = -EINVAL;
chip->last_soc_est = -EINVAL;
+ chip->battery_present = -EINVAL;
+ chip->battery_status = POWER_SUPPLY_STATUS_UNKNOWN;
chip->last_cc_uah = INT_MIN;
chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
chip->prev_last_good_ocv_raw = OCV_RAW_UNINITIALIZED;
@@ -2368,6 +2738,7 @@
return rc;
}
reset_cc(chip);
+ chip->software_cc_uah = 0;
}
} else {
pr_debug("Internal rsense selected\n");
@@ -2384,6 +2755,7 @@
return rc;
}
reset_cc(chip);
+ chip->software_cc_uah = 0;
}
rc = qpnp_iadc_get_rsense(&rds_rsense_nohm);
@@ -2399,10 +2771,68 @@
return 0;
}
+static int refresh_die_temp_monitor(struct qpnp_bms_chip *chip)
+{
+ struct qpnp_vadc_result result;
+ int rc;
+
+ rc = qpnp_vadc_read(DIE_TEMP, &result);
+
+ pr_debug("low = %lld, high = %lld\n",
+ result.physical - chip->temperature_margin,
+ result.physical + chip->temperature_margin);
+ chip->die_temp_monitor_params.high_temp = result.physical
+ + chip->temperature_margin;
+ chip->die_temp_monitor_params.low_temp = result.physical
+ - chip->temperature_margin;
+ chip->die_temp_monitor_params.state_request =
+ ADC_TM_HIGH_LOW_THR_ENABLE;
+ return qpnp_adc_tm_channel_measure(&chip->die_temp_monitor_params);
+}
+
+static void btm_notify_die_temp(enum qpnp_tm_state state, void *ctx)
+{
+ struct qpnp_bms_chip *chip = ctx;
+ struct qpnp_vadc_result result;
+ int rc;
+
+ rc = qpnp_vadc_read(DIE_TEMP, &result);
+
+ if (state == ADC_TM_LOW_STATE)
+ pr_debug("low state triggered\n");
+ else if (state == ADC_TM_HIGH_STATE)
+ pr_debug("high state triggered\n");
+ pr_debug("die temp = %lld, raw = 0x%x\n",
+ result.physical, result.adc_code);
+ schedule_work(&chip->recalc_work);
+ refresh_die_temp_monitor(chip);
+}
+
+static int setup_die_temp_monitoring(struct qpnp_bms_chip *chip)
+{
+ int rc = qpnp_adc_tm_is_ready();
+ if (rc) {
+ pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
+ return -EPROBE_DEFER;
+ }
+ chip->die_temp_monitor_params.channel = DIE_TEMP;
+ chip->die_temp_monitor_params.btm_ctx = (void *)chip;
+ chip->die_temp_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
+ chip->die_temp_monitor_params.threshold_notification =
+ &btm_notify_die_temp;
+ refresh_die_temp_monitor(chip);
+ if (rc) {
+ pr_err("tm setup failed: %d\n", rc);
+ return rc;
+ }
+ pr_debug("setup complete\n");
+ return 0;
+}
+
static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
{
struct qpnp_bms_chip *chip;
- union power_supply_propval retval = {0,};
+ bool warm_reset;
int rc, vbatt;
chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -2415,15 +2845,22 @@
rc = qpnp_vadc_is_ready();
if (rc) {
pr_info("vadc not ready: %d, deferring probe\n", rc);
+ rc = -EPROBE_DEFER;
goto error_read;
}
rc = qpnp_iadc_is_ready();
if (rc) {
pr_info("iadc not ready: %d, deferring probe\n", rc);
+ rc = -EPROBE_DEFER;
goto error_read;
}
+ warm_reset = qpnp_pon_is_warm_reset();
+ rc = warm_reset;
+ if (rc < 0)
+ goto error_read;
+
rc = register_spmi(chip, spmi);
if (rc) {
pr_err("error registering spmi resource %d\n", rc);
@@ -2478,12 +2915,16 @@
mutex_init(&chip->bms_output_lock);
mutex_init(&chip->last_ocv_uv_mutex);
+ mutex_init(&chip->vbat_monitor_mutex);
mutex_init(&chip->soc_invalidation_mutex);
+ mutex_init(&chip->last_soc_mutex);
wake_lock_init(&chip->soc_wake_lock, WAKE_LOCK_SUSPEND,
"qpnp_soc_lock");
wake_lock_init(&chip->low_voltage_wake_lock, WAKE_LOCK_SUSPEND,
"qpnp_low_voltage_lock");
+ wake_lock_init(&chip->cv_wake_lock, WAKE_LOCK_SUSPEND,
+ "qpnp_cv_lock");
INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
calculate_soc_work);
INIT_WORK(&chip->recalc_work, recalculate_work);
@@ -2493,15 +2934,16 @@
dev_set_drvdata(&spmi->dev, chip);
device_init_wakeup(&spmi->dev, 1);
- if (!chip->batt_psy)
- chip->batt_psy = power_supply_get_by_name("battery");
- if (chip->batt_psy) {
- chip->batt_psy->get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_PRESENT, &retval);
- chip->battery_present = retval.intval;
- pr_debug("present = %d\n", chip->battery_present);
- } else {
- chip->battery_present = 1;
+ rc = setup_vbat_monitoring(chip);
+ if (rc < 0) {
+ pr_err("failed to set up voltage notifications: %d\n", rc);
+ goto error_setup;
+ }
+
+ rc = setup_die_temp_monitoring(chip);
+ if (rc < 0) {
+ pr_err("failed to set up die temp notifications: %d\n", rc);
+ goto error_setup;
}
calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
@@ -2512,7 +2954,6 @@
chip->bms_psy.properties = msm_bms_power_props;
chip->bms_psy.num_properties = ARRAY_SIZE(msm_bms_power_props);
chip->bms_psy.get_property = qpnp_bms_power_get_property;
- chip->bms_psy.set_property = qpnp_bms_power_set_property;
chip->bms_psy.external_power_changed =
qpnp_bms_external_power_changed;
chip->bms_psy.supplied_to = qpnp_bms_supplicants;
@@ -2533,16 +2974,18 @@
goto unregister_dc;
}
- pr_info("probe success: soc =%d vbatt = %d ocv = %d r_sense_uohm = %u\n",
- get_prop_bms_capacity(chip),
- vbatt, chip->last_ocv_uv, chip->r_sense_uohm);
+ pr_info("probe success: soc =%d vbatt = %d ocv = %d r_sense_uohm = %u warm_reset = %d\n",
+ get_prop_bms_capacity(chip), vbatt, chip->last_ocv_uv,
+ chip->r_sense_uohm, warm_reset);
return 0;
unregister_dc:
+ power_supply_unregister(&chip->bms_psy);
+error_setup:
+ dev_set_drvdata(&spmi->dev, NULL);
wake_lock_destroy(&chip->soc_wake_lock);
wake_lock_destroy(&chip->low_voltage_wake_lock);
- power_supply_unregister(&chip->bms_psy);
- dev_set_drvdata(&spmi->dev, NULL);
+ wake_lock_destroy(&chip->cv_wake_lock);
error_resource:
error_read:
kfree(chip);
@@ -2564,7 +3007,7 @@
struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
cancel_delayed_work_sync(&chip->calculate_soc_delayed_work);
- chip->last_soc_unbound = true;
+ chip->was_charging_at_sleep = is_battery_charging(chip);
return 0;
}
@@ -2581,10 +3024,6 @@
if (rc) {
pr_err("Could not read current time: %d\n", rc);
} else if (tm_now_sec > chip->last_recalc_time) {
- /*
- * unbind the last soc so that the next
- * recalculation is not limited to changing by 1%
- */
time_since_last_recalc = tm_now_sec - chip->last_recalc_time;
pr_debug("Time since last recalc: %lu\n",
time_since_last_recalc);
@@ -2596,6 +3035,10 @@
time_until_next_recalc = max(0, soc_calc_period
- (int)(time_since_last_recalc * 1000));
+ if (!wake_lock_active(&chip->soc_wake_lock)
+ && time_until_next_recalc == 0)
+ wake_lock(&chip->soc_wake_lock);
+
schedule_delayed_work(&chip->calculate_soc_delayed_work,
round_jiffies_relative(msecs_to_jiffies
(time_until_next_recalc)));
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index de2e5c1..624a42f 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -81,6 +81,7 @@
#define CHGR_BAT_IF_VCP 0x42
#define CHGR_BAT_IF_BATFET_CTRL1 0x90
#define CHGR_MISC_BOOT_DONE 0x42
+#define CHGR_BUCK_COMPARATOR_OVRIDE_1 0xEB
#define CHGR_BUCK_COMPARATOR_OVRIDE_3 0xED
#define CHGR_BUCK_BCK_VBAT_REG_MODE 0x74
#define MISC_REVISION2 0x01
@@ -90,6 +91,7 @@
#define BUCK_TEST_SMBC_MODES 0xE6
#define SEC_ACCESS 0xD0
#define BAT_IF_VREF_BAT_THM_CTRL 0x4A
+#define BAT_IF_BPD_CTRL 0x48
#define REG_OFFSET_PERP_SUBTYPE 0x05
/* SMBB peripheral subtype values */
@@ -125,7 +127,11 @@
#define USB_VALID_DEB_20MS 0x03
#define BUCK_VBAT_REG_NODE_SEL_BIT BIT(0)
#define VREF_BATT_THERM_FORCE_ON 0xC0
+#define BAT_IF_BPD_CTRL_SEL 0x03
#define VREF_BAT_THM_ENABLED_FSM 0x80
+#define REV_BST_DETECTED BIT(0)
+#define BAT_THM_EN BIT(1)
+#define BAT_ID_EN BIT(0)
/* Interrupt definitions */
/* smbb_chg_interrupts */
@@ -178,6 +184,11 @@
/* Workaround flags */
#define CHG_FLAGS_VCP_WA BIT(0)
+struct qpnp_chg_irq {
+ unsigned int irq;
+ unsigned long disabled;
+};
+
/**
* struct qpnp_chg_chip - device information
* @dev: device pointer to access the parent
@@ -236,13 +247,14 @@
u16 boost_base;
u16 misc_base;
u16 freq_base;
- unsigned int usbin_valid_irq;
- unsigned int dcin_valid_irq;
- unsigned int chg_gone_irq;
- unsigned int chg_fastchg_irq;
- unsigned int chg_trklchg_irq;
- unsigned int chg_failed_irq;
- unsigned int batt_pres_irq;
+ struct qpnp_chg_irq usbin_valid;
+ struct qpnp_chg_irq dcin_valid;
+ struct qpnp_chg_irq chg_gone;
+ struct qpnp_chg_irq chg_fastchg;
+ struct qpnp_chg_irq chg_trklchg;
+ struct qpnp_chg_irq chg_failed;
+ struct qpnp_chg_irq chg_vbatdet_lo;
+ struct qpnp_chg_irq batt_pres;
bool bat_is_cool;
bool bat_is_warm;
bool chg_done;
@@ -251,6 +263,7 @@
bool batt_present;
bool charging_disabled;
bool use_default_batt_values;
+ unsigned int bpd_detection;
unsigned int max_bat_chg_current;
unsigned int warm_bat_chg_ma;
unsigned int cool_bat_chg_ma;
@@ -260,7 +273,7 @@
unsigned int warm_bat_mv;
unsigned int cool_bat_mv;
unsigned int resume_delta_mv;
- unsigned int term_current;
+ int term_current;
unsigned int maxinput_usb_ma;
unsigned int maxinput_dc_ma;
unsigned int warm_bat_decidegc;
@@ -280,13 +293,35 @@
struct qpnp_adc_tm_btm_param adc_param;
struct work_struct adc_measure_work;
struct delayed_work arb_stop_work;
+ struct delayed_work eoc_work;
+ struct wake_lock eoc_wake_lock;
};
+
static struct of_device_id qpnp_charger_match_table[] = {
{ .compatible = QPNP_CHARGER_DEV_NAME, },
{}
};
+#define BPD_MAX 3
+
+static const char *bpd_list[BPD_MAX] = {
+ "bpd_thm",
+ "bpd_id",
+ "bpd_thm_id",
+};
+
+static inline int
+get_bpd(const char *name)
+{
+ int i = 0;
+ for (i = 0 ; i < BPD_MAX; i++) {
+ if (strcmp(name, bpd_list[i]) == 0)
+ return i;
+ }
+ return -EINVAL;
+}
+
static int
qpnp_chg_read(struct qpnp_chg_chip *chip, u8 *val,
u16 base, int count)
@@ -350,6 +385,24 @@
return 0;
}
+static void
+qpnp_chg_enable_irq(struct qpnp_chg_irq *irq)
+{
+ if (__test_and_clear_bit(0, &irq->disabled)) {
+ pr_debug("number = %d\n", irq->irq);
+ enable_irq(irq->irq);
+ }
+}
+
+static void
+qpnp_chg_disable_irq(struct qpnp_chg_irq *irq)
+{
+ if (!__test_and_set_bit(0, &irq->disabled)) {
+ pr_debug("number = %d\n", irq->irq);
+ disable_irq_nosync(irq->irq);
+ }
+}
+
#define USB_OTG_EN_BIT BIT(0)
static int
qpnp_chg_is_otg_en_set(struct qpnp_chg_chip *chip)
@@ -557,6 +610,53 @@
disable ? CHGR_ON_BAT_FORCE_BIT : 0, 1);
}
+#define COMPATATOR_OVERRIDE_0 0x80
+static int
+qpnp_chg_toggle_chg_done_logic(struct qpnp_chg_chip *chip, int enable)
+{
+ int rc;
+
+ pr_debug("toggle: %d\n", enable);
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->buck_base + SEC_ACCESS, 0xA5, 0xA5, 1);
+ if (rc) {
+ pr_debug("failed to write sec access rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->buck_base + CHGR_BUCK_COMPARATOR_OVRIDE_1,
+ 0xC0, enable ? 0x00 : COMPATATOR_OVERRIDE_0, 1);
+ if (rc) {
+ pr_debug("failed to toggle chg done override rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+#define QPNP_CHG_VBATDET_MIN_MV 3240
+#define QPNP_CHG_VBATDET_MAX_MV 5780
+#define QPNP_CHG_VBATDET_STEP_MV 20
+static int
+qpnp_chg_vbatdet_set(struct qpnp_chg_chip *chip, int vbatdet_mv)
+{
+ u8 temp;
+
+ if (vbatdet_mv < QPNP_CHG_VBATDET_MIN_MV
+ || vbatdet_mv > QPNP_CHG_VBATDET_MAX_MV) {
+ pr_err("bad mV=%d asked to set\n", vbatdet_mv);
+ return -EINVAL;
+ }
+ temp = (vbatdet_mv - QPNP_CHG_VBATDET_MIN_MV)
+ / QPNP_CHG_VBATDET_STEP_MV;
+
+ pr_debug("voltage=%d setting %02x\n", vbatdet_mv, temp);
+ return qpnp_chg_write(chip, &temp,
+ chip->chgr_base + CHGR_VBAT_DET, 1);
+}
+
static void
qpnp_arb_stop_work(struct work_struct *work)
{
@@ -564,7 +664,8 @@
struct qpnp_chg_chip *chip = container_of(dwork,
struct qpnp_chg_chip, arb_stop_work);
- qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ if (!chip->chg_done)
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
}
@@ -578,6 +679,38 @@
pr_err("request ADC error\n");
}
+#define EOC_CHECK_PERIOD_MS 10000
+static irqreturn_t
+qpnp_chg_vbatdet_lo_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+ u8 chg_sts = 0;
+ int rc;
+
+ pr_debug("vbatdet-lo triggered\n");
+
+ rc = qpnp_chg_read(chip, &chg_sts, INT_RT_STS(chip->chgr_base), 1);
+ if (rc)
+ pr_err("failed to read chg_sts rc=%d\n", rc);
+
+ pr_debug("chg_done chg_sts: 0x%x triggered\n", chg_sts);
+ if (!chip->charging_disabled && (chg_sts & FAST_CHG_ON_IRQ)) {
+ schedule_delayed_work(&chip->eoc_work,
+ msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ wake_lock(&chip->eoc_wake_lock);
+ qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
+ } else {
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ }
+
+ power_supply_changed(chip->usb_psy);
+ if (chip->dc_chgpth_base)
+ power_supply_changed(&chip->dc_psy);
+ if (chip->bat_if_base)
+ power_supply_changed(&chip->batt_psy);
+ return IRQ_HANDLED;
+}
+
#define ARB_STOP_WORK_MS 1000
static irqreturn_t
qpnp_chg_usb_chg_gone_irq_handler(int irq, void *_chip)
@@ -587,7 +720,7 @@
pr_debug("chg_gone triggered\n");
if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
qpnp_chg_charge_en(chip, 0);
- qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
+ qpnp_chg_force_run_on_batt(chip, 1);
schedule_delayed_work(&chip->arb_stop_work,
msecs_to_jiffies(ARB_STOP_WORK_MS));
}
@@ -613,11 +746,15 @@
if (chip->usb_present ^ usb_present) {
chip->usb_present = usb_present;
- if (!usb_present)
+ if (!usb_present) {
qpnp_chg_usb_suspend_enable(chip, 1);
+ chip->chg_done = false;
+ } else {
+ schedule_delayed_work(&chip->eoc_work,
+ msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ }
- power_supply_set_present(chip->usb_psy,
- chip->usb_present);
+ power_supply_set_present(chip->usb_psy, chip->usb_present);
}
return IRQ_HANDLED;
@@ -635,6 +772,7 @@
if (chip->batt_present ^ batt_present) {
chip->batt_present = batt_present;
power_supply_changed(&chip->batt_psy);
+ power_supply_changed(chip->usb_psy);
if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
&& batt_present) {
@@ -642,9 +780,6 @@
}
}
- if (chip->bms_psy)
- power_supply_set_present(chip->bms_psy, batt_present);
-
return IRQ_HANDLED;
}
@@ -659,7 +794,13 @@
if (chip->dc_present ^ dc_present) {
chip->dc_present = dc_present;
+ if (!dc_present)
+ chip->chg_done = false;
+ else
+ schedule_delayed_work(&chip->eoc_work,
+ msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
power_supply_changed(&chip->dc_psy);
+ power_supply_changed(&chip->batt_psy);
}
return IRQ_HANDLED;
@@ -672,6 +813,8 @@
struct qpnp_chg_chip *chip = _chip;
int rc;
+ pr_debug("chg_failed triggered\n");
+
rc = qpnp_chg_masked_write(chip,
chip->chgr_base + CHGR_CHG_FAILED,
CHGR_CHG_FAILED_BIT,
@@ -679,6 +822,11 @@
if (rc)
pr_err("Failed to write chg_fail clear bit!\n");
+ if (chip->bat_if_base)
+ power_supply_changed(&chip->batt_psy);
+ power_supply_changed(chip->usb_psy);
+ if (chip->dc_chgpth_base)
+ power_supply_changed(&chip->dc_psy);
return IRQ_HANDLED;
}
@@ -690,7 +838,8 @@
pr_debug("TRKL IRQ triggered\n");
chip->chg_done = false;
- power_supply_changed(&chip->batt_psy);
+ if (chip->bat_if_base)
+ power_supply_changed(&chip->batt_psy);
return IRQ_HANDLED;
}
@@ -701,9 +850,13 @@
struct qpnp_chg_chip *chip = _chip;
pr_debug("FAST_CHG IRQ triggered\n");
-
chip->chg_done = false;
- power_supply_changed(&chip->batt_psy);
+ if (chip->bat_if_base)
+ power_supply_changed(&chip->batt_psy);
+ power_supply_changed(chip->usb_psy);
+ if (chip->dc_chgpth_base)
+ power_supply_changed(&chip->dc_psy);
+ qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
return IRQ_HANDLED;
}
@@ -818,7 +971,6 @@
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
- POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_TEMP,
@@ -829,6 +981,10 @@
"battery",
};
+static char *pm_batt_supplied_to[] = {
+ "bms",
+};
+
#define USB_WALL_THRESHOLD_MA 500
static int
qpnp_power_get_property_mains(struct power_supply *psy,
@@ -941,11 +1097,12 @@
int rc;
u8 chgr_sts;
- if (chip->chg_done)
+ if ((qpnp_chg_is_usb_chg_plugged_in(chip) ||
+ qpnp_chg_is_dc_chg_plugged_in(chip)) && chip->chg_done) {
return POWER_SUPPLY_STATUS_FULL;
+ }
- rc = qpnp_chg_read(chip, &chgr_sts,
- INT_RT_STS(chip->chgr_base), 1);
+ rc = qpnp_chg_read(chip, &chgr_sts, INT_RT_STS(chip->chgr_base), 1);
if (rc) {
pr_err("failed to read interrupt sts %d\n", rc);
return POWER_SUPPLY_CHARGE_TYPE_NONE;
@@ -958,21 +1115,6 @@
return POWER_SUPPLY_STATUS_DISCHARGING;
}
-static int
-get_prop_current_max(struct qpnp_chg_chip *chip)
-{
- union power_supply_propval ret = {0,};
-
- if (chip->bms_psy) {
- chip->bms_psy->get_property(chip->bms_psy,
- POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
- return ret.intval;
- } else {
- pr_debug("No BMS supply registered return 0\n");
- }
-
- return 0;
-}
static int
get_prop_current_now(struct qpnp_chg_chip *chip)
@@ -1151,9 +1293,6 @@
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = get_prop_capacity(chip);
break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- val->intval = get_prop_current_max(chip);
- break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = get_prop_current_now(chip);
break;
@@ -1282,27 +1421,7 @@
temp = (minutes - 1)/QPNP_CHG_TCHG_STEP;
return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_TCHG_MAX,
- QPNP_CHG_I_MASK, temp, 1);
-}
-#define QPNP_CHG_VBATDET_MIN_MV 3240
-#define QPNP_CHG_VBATDET_MAX_MV 5780
-#define QPNP_CHG_VBATDET_STEP_MV 20
-static int
-qpnp_chg_vbatdet_set(struct qpnp_chg_chip *chip, int vbatdet_mv)
-{
- u8 temp;
-
- if (vbatdet_mv < QPNP_CHG_VBATDET_MIN_MV
- || vbatdet_mv > QPNP_CHG_VBATDET_MAX_MV) {
- pr_err("bad mV=%d asked to set\n", vbatdet_mv);
- return -EINVAL;
- }
- temp = (vbatdet_mv - QPNP_CHG_VBATDET_MIN_MV)
- / QPNP_CHG_VBATDET_STEP_MV;
-
- pr_debug("voltage=%d setting %02x\n", vbatdet_mv, temp);
- return qpnp_chg_write(chip, &temp,
- chip->chgr_base + CHGR_VBAT_DET, 1);
+ QPNP_CHG_TCHG_MASK, temp, 1);
}
#define QPNP_CHG_V_MIN_MV 3240
@@ -1404,6 +1523,88 @@
}
}
+#define CONSECUTIVE_COUNT 3
+static void
+qpnp_eoc_work(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct qpnp_chg_chip *chip = container_of(dwork,
+ struct qpnp_chg_chip, eoc_work);
+ static int count;
+ int ibat_ma, vbat_mv, rc = 0;
+ u8 batt_sts = 0, buck_sts = 0, chg_sts = 0;
+
+ wake_lock(&chip->eoc_wake_lock);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+
+ rc = qpnp_chg_read(chip, &batt_sts, INT_RT_STS(chip->bat_if_base), 1);
+ if (rc) {
+ pr_err("failed to read batt_if rc=%d\n", rc);
+ return;
+ }
+
+ rc = qpnp_chg_read(chip, &buck_sts, INT_RT_STS(chip->buck_base), 1);
+ if (rc) {
+ pr_err("failed to read buck rc=%d\n", rc);
+ return;
+ }
+
+ rc = qpnp_chg_read(chip, &chg_sts, INT_RT_STS(chip->chgr_base), 1);
+ if (rc) {
+ pr_err("failed to read chg_sts rc=%d\n", rc);
+ return;
+ }
+
+ pr_debug("chgr: 0x%x, bat_if: 0x%x, buck: 0x%x\n",
+ chg_sts, batt_sts, buck_sts);
+
+ if (!qpnp_chg_is_usb_chg_plugged_in(chip) &&
+ !qpnp_chg_is_dc_chg_plugged_in(chip)) {
+ pr_debug("no chg connected, stopping\n");
+ goto stop_eoc;
+ }
+
+ if ((batt_sts & BAT_FET_ON_IRQ) && (chg_sts & FAST_CHG_ON_IRQ
+ || chg_sts & TRKL_CHG_ON_IRQ)) {
+ ibat_ma = get_prop_current_now(chip) / 1000;
+ vbat_mv = get_prop_battery_voltage_now(chip) / 1000;
+ pr_debug("ibat_ma: %d term_current =%d\n",
+ ibat_ma, chip->term_current);
+ if (ibat_ma > chip->term_current) {
+ pr_debug("charging but increase in current demand\n");
+ count = 0;
+ } else if ((ibat_ma * -1) < chip->term_current) {
+ if (count == CONSECUTIVE_COUNT) {
+ pr_info("End of Charging\n");
+ qpnp_chg_charge_en(chip, 0);
+ chip->chg_done = true;
+ power_supply_changed(&chip->batt_psy);
+ qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
+ goto stop_eoc;
+ } else {
+ count += 1;
+ pr_debug("EOC count = %d\n", count);
+ }
+ } else if ((!(chg_sts & VBAT_DET_LOW_IRQ)) && (vbat_mv <
+ (chip->max_voltage_mv - chip->resume_delta_mv))) {
+ pr_debug("woke up too early\n");
+ qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
+ goto stop_eoc;
+ }
+ } else {
+ pr_debug("not charging\n");
+ goto stop_eoc;
+ }
+
+ schedule_delayed_work(&chip->eoc_work,
+ msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ return;
+
+stop_eoc:
+ count = 0;
+ wake_unlock(&chip->eoc_wake_lock);
+}
+
#define HYSTERISIS_DECIDEGC 20
static void
qpnp_chg_adc_notification(enum qpnp_tm_state state, void *ctx)
@@ -1544,136 +1745,157 @@
case SMBB_CHGR_SUBTYPE:
case SMBBP_CHGR_SUBTYPE:
case SMBCL_CHGR_SUBTYPE:
- chip->chg_fastchg_irq = spmi_get_irq_byname(spmi,
+ chip->chg_fastchg.irq = spmi_get_irq_byname(spmi,
spmi_resource, "fast-chg-on");
- if (chip->chg_fastchg_irq < 0) {
+ if (chip->chg_fastchg.irq < 0) {
pr_err("Unable to get fast-chg-on irq\n");
return rc;
}
- chip->chg_trklchg_irq = spmi_get_irq_byname(spmi,
+ chip->chg_trklchg.irq = spmi_get_irq_byname(spmi,
spmi_resource, "trkl-chg-on");
- if (chip->chg_trklchg_irq < 0) {
+ if (chip->chg_trklchg.irq < 0) {
pr_err("Unable to get trkl-chg-on irq\n");
return rc;
}
- chip->chg_failed_irq = spmi_get_irq_byname(spmi,
+ chip->chg_failed.irq = spmi_get_irq_byname(spmi,
spmi_resource, "chg-failed");
- if (chip->chg_failed_irq < 0) {
+ if (chip->chg_failed.irq < 0) {
pr_err("Unable to get chg_failed irq\n");
return rc;
}
- rc |= devm_request_irq(chip->dev, chip->chg_failed_irq,
+ chip->chg_vbatdet_lo.irq = spmi_get_irq_byname(spmi,
+ spmi_resource, "vbat-det-lo");
+ if (chip->chg_vbatdet_lo.irq < 0) {
+ pr_err("Unable to get fast-chg-on irq\n");
+ return rc;
+ }
+
+ rc |= devm_request_irq(chip->dev, chip->chg_failed.irq,
qpnp_chg_chgr_chg_failed_irq_handler,
IRQF_TRIGGER_RISING, "chg-failed", chip);
if (rc < 0) {
pr_err("Can't request %d chg-failed: %d\n",
- chip->chg_failed_irq, rc);
+ chip->chg_failed.irq, rc);
return rc;
}
- rc |= devm_request_irq(chip->dev, chip->chg_fastchg_irq,
+ rc |= devm_request_irq(chip->dev, chip->chg_fastchg.irq,
qpnp_chg_chgr_chg_fastchg_irq_handler,
IRQF_TRIGGER_RISING,
"fast-chg-on", chip);
if (rc < 0) {
pr_err("Can't request %d fast-chg-on: %d\n",
- chip->chg_fastchg_irq, rc);
+ chip->chg_fastchg.irq, rc);
return rc;
}
- rc |= devm_request_irq(chip->dev, chip->chg_trklchg_irq,
+ rc |= devm_request_irq(chip->dev, chip->chg_trklchg.irq,
qpnp_chg_chgr_chg_trklchg_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"trkl-chg-on", chip);
if (rc < 0) {
pr_err("Can't request %d trkl-chg-on: %d\n",
- chip->chg_trklchg_irq, rc);
+ chip->chg_trklchg.irq, rc);
return rc;
}
- enable_irq_wake(chip->chg_fastchg_irq);
- enable_irq_wake(chip->chg_trklchg_irq);
- enable_irq_wake(chip->chg_failed_irq);
+
+ rc |= devm_request_irq(chip->dev,
+ chip->chg_vbatdet_lo.irq,
+ qpnp_chg_vbatdet_lo_irq_handler,
+ IRQF_TRIGGER_RISING,
+ "vbat-det-lo", chip);
+ if (rc < 0) {
+ pr_err("Can't request %d vbat-det-lo: %d\n",
+ chip->chg_vbatdet_lo.irq, rc);
+ return rc;
+ }
+
+ enable_irq_wake(chip->chg_trklchg.irq);
+ enable_irq_wake(chip->chg_failed.irq);
+ qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
+ enable_irq_wake(chip->chg_vbatdet_lo.irq);
break;
case SMBB_BAT_IF_SUBTYPE:
case SMBBP_BAT_IF_SUBTYPE:
case SMBCL_BAT_IF_SUBTYPE:
- chip->batt_pres_irq = spmi_get_irq_byname(spmi,
+ chip->batt_pres.irq = spmi_get_irq_byname(spmi,
spmi_resource, "batt-pres");
- if (chip->batt_pres_irq < 0) {
+ if (chip->batt_pres.irq < 0) {
pr_err("Unable to get batt-pres irq\n");
return rc;
}
- rc = devm_request_irq(chip->dev, chip->batt_pres_irq,
+ rc = devm_request_irq(chip->dev, chip->batt_pres.irq,
qpnp_chg_bat_if_batt_pres_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"batt-pres", chip);
if (rc < 0) {
pr_err("Can't request %d batt-pres irq: %d\n",
- chip->batt_pres_irq, rc);
+ chip->batt_pres.irq, rc);
return rc;
}
- enable_irq_wake(chip->batt_pres_irq);
+ enable_irq_wake(chip->batt_pres.irq);
break;
case SMBB_USB_CHGPTH_SUBTYPE:
case SMBBP_USB_CHGPTH_SUBTYPE:
case SMBCL_USB_CHGPTH_SUBTYPE:
- chip->usbin_valid_irq = spmi_get_irq_byname(spmi,
+ chip->usbin_valid.irq = spmi_get_irq_byname(spmi,
spmi_resource, "usbin-valid");
- if (chip->usbin_valid_irq < 0) {
+ if (chip->usbin_valid.irq < 0) {
pr_err("Unable to get usbin irq\n");
return rc;
}
- rc = devm_request_irq(chip->dev, chip->usbin_valid_irq,
+ rc = devm_request_irq(chip->dev, chip->usbin_valid.irq,
qpnp_chg_usb_usbin_valid_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"usbin-valid", chip);
if (rc < 0) {
pr_err("Can't request %d usbin-valid: %d\n",
- chip->usbin_valid_irq, rc);
+ chip->usbin_valid.irq, rc);
return rc;
}
- chip->chg_gone_irq = spmi_get_irq_byname(spmi,
+ chip->chg_gone.irq = spmi_get_irq_byname(spmi,
spmi_resource, "chg-gone");
- if (chip->chg_gone_irq < 0) {
+ if (chip->chg_gone.irq < 0) {
pr_err("Unable to get chg-gone irq\n");
return rc;
}
- rc = devm_request_irq(chip->dev, chip->chg_gone_irq,
+ rc = devm_request_irq(chip->dev, chip->chg_gone.irq,
qpnp_chg_usb_chg_gone_irq_handler,
IRQF_TRIGGER_RISING,
"chg-gone", chip);
if (rc < 0) {
pr_err("Can't request %d chg-gone: %d\n",
- chip->chg_gone_irq, rc);
+ chip->chg_gone.irq, rc);
return rc;
}
- enable_irq_wake(chip->usbin_valid_irq);
- enable_irq_wake(chip->chg_gone_irq);
+
+ enable_irq_wake(chip->usbin_valid.irq);
+ enable_irq_wake(chip->chg_gone.irq);
break;
case SMBB_DC_CHGPTH_SUBTYPE:
- chip->dcin_valid_irq = spmi_get_irq_byname(spmi,
+ chip->dcin_valid.irq = spmi_get_irq_byname(spmi,
spmi_resource, "dcin-valid");
- if (chip->dcin_valid_irq < 0) {
+ if (chip->dcin_valid.irq < 0) {
pr_err("Unable to get dcin irq\n");
return -rc;
}
- rc = devm_request_irq(chip->dev, chip->dcin_valid_irq,
+ rc = devm_request_irq(chip->dev, chip->dcin_valid.irq,
qpnp_chg_dc_dcin_valid_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"dcin-valid", chip);
if (rc < 0) {
pr_err("Can't request %d dcin-valid: %d\n",
- chip->dcin_valid_irq, rc);
+ chip->dcin_valid.irq, rc);
return rc;
}
- enable_irq_wake(chip->dcin_valid_irq);
+ enable_irq_wake(chip->dcin_valid.irq);
break;
}
}
@@ -1687,7 +1909,7 @@
struct spmi_resource *spmi_resource)
{
int rc = 0;
- u8 reg;
+ u8 reg = 0;
switch (subtype) {
case SMBB_CHGR_SUBTYPE:
@@ -1744,12 +1966,16 @@
/* HACK: use analog EOC */
rc = qpnp_chg_masked_write(chip, chip->chgr_base +
CHGR_IBAT_TERM_CHGR,
- 0x80, 0x00, 1);
+ 0xFF, 0x08, 1);
break;
case SMBB_BUCK_SUBTYPE:
case SMBBP_BUCK_SUBTYPE:
case SMBCL_BUCK_SUBTYPE:
+ rc = qpnp_chg_toggle_chg_done_logic(chip, 0);
+ if (rc)
+ return rc;
+
rc = qpnp_chg_masked_write(chip,
chip->chgr_base + CHGR_BUCK_BCK_VBAT_REG_MODE,
BUCK_VBAT_REG_NODE_SEL_BIT,
@@ -1762,6 +1988,20 @@
case SMBB_BAT_IF_SUBTYPE:
case SMBBP_BAT_IF_SUBTYPE:
case SMBCL_BAT_IF_SUBTYPE:
+ /* Select battery presence detection */
+ if (chip->bpd_detection == 1)
+ reg = BAT_ID_EN;
+ else if (chip->bpd_detection == 2)
+ reg = BAT_ID_EN | BAT_THM_EN;
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->bat_if_base + BAT_IF_BPD_CTRL,
+ BAT_IF_BPD_CTRL_SEL,
+ reg, 1);
+ if (rc) {
+ pr_debug("failed to chose BPD rc=%d\n", rc);
+ return rc;
+ }
/* Force on VREF_BAT_THM */
rc = qpnp_chg_masked_write(chip,
chip->bat_if_base + BAT_IF_VREF_BAT_THM_CTRL,
@@ -1775,8 +2015,7 @@
case SMBB_USB_CHGPTH_SUBTYPE:
case SMBBP_USB_CHGPTH_SUBTYPE:
case SMBCL_USB_CHGPTH_SUBTYPE:
- chip->usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
- if (chip->usb_present) {
+ if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
rc = qpnp_chg_masked_write(chip,
chip->usb_chgpth_base + CHGR_USB_ENUM_T_STOP,
ENUM_T_STOP_BIT,
@@ -1862,6 +2101,7 @@
qpnp_charger_read_dt_props(struct qpnp_chg_chip *chip)
{
int rc = 0;
+ const char *bpd;
OF_PROP_READ(chip, max_voltage_mv, "vddmax-mv", rc, 0);
OF_PROP_READ(chip, min_voltage_mv, "vinmin-mv", rc, 0);
@@ -1881,6 +2121,18 @@
if (rc)
return rc;
+ rc = of_property_read_string(chip->spmi->dev.of_node,
+ "qcom,bpd-detection", &bpd);
+ if (rc) {
+ pr_debug("no bpd-detection specified, ignored\n");
+ } else {
+ chip->bpd_detection = get_bpd(bpd);
+ if (chip->bpd_detection < 0) {
+ pr_err("failed to determine bpd schema %d\n", rc);
+ return rc;
+ }
+ }
+
/* Look up JEITA compliance parameters if cool and warm temp provided */
if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
rc = qpnp_adc_tm_is_ready();
@@ -1943,7 +2195,6 @@
struct qpnp_chg_chip *chip;
struct resource *resource;
struct spmi_resource *spmi_resource;
- bool present;
int rc = 0;
chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -2100,14 +2351,6 @@
if (rc)
goto fail_chg_enable;
- /* if bms exists, notify it of the presence of the battery */
- if (!chip->bms_psy)
- chip->bms_psy = power_supply_get_by_name("bms");
- if (chip->bms_psy) {
- present = get_prop_batt_present(chip);
- power_supply_set_present(chip->bms_psy, present);
- }
-
chip->batt_psy.name = "battery";
chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
chip->batt_psy.properties = msm_batt_power_props;
@@ -2119,6 +2362,9 @@
qpnp_batt_property_is_writeable;
chip->batt_psy.external_power_changed =
qpnp_batt_external_power_changed;
+ chip->batt_psy.supplied_to = pm_batt_supplied_to;
+ chip->batt_psy.num_supplicants =
+ ARRAY_SIZE(pm_batt_supplied_to);
rc = power_supply_register(chip->dev, &chip->batt_psy);
if (rc < 0) {
@@ -2129,6 +2375,9 @@
qpnp_bat_if_adc_measure_work);
}
+ wake_lock_init(&chip->eoc_wake_lock,
+ WAKE_LOCK_SUSPEND, "qpnp-chg-eoc-lock");
+ INIT_DELAYED_WORK(&chip->eoc_work, qpnp_eoc_work);
INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
if (chip->dc_chgpth_base) {
@@ -2150,9 +2399,6 @@
/* Turn on appropriate workaround flags */
qpnp_chg_setup_flags(chip);
- power_supply_set_present(chip->usb_psy,
- qpnp_chg_is_usb_chg_plugged_in(chip));
-
if (chip->maxinput_dc_ma && chip->dc_chgpth_base) {
rc = qpnp_chg_idcmax_set(chip, chip->maxinput_dc_ma);
if (rc) {
@@ -2189,8 +2435,18 @@
goto unregister_batt;
}
- pr_info("success chg_dis = %d, usb = %d, dc = %d b_health = %d batt_present = %d\n",
+ qpnp_chg_usb_usbin_valid_irq_handler(USBIN_VALID_IRQ, chip);
+ power_supply_set_present(chip->usb_psy,
+ qpnp_chg_is_usb_chg_plugged_in(chip));
+
+ /* Set USB psy online to avoid userspace from shutting down if battery
+ * capacity is at zero and no chargers online. */
+ if (qpnp_chg_is_usb_chg_plugged_in(chip))
+ power_supply_set_online(chip->usb_psy, 1);
+
+ pr_info("success chg_dis = %d, bpd = %d, usb = %d, dc = %d b_health = %d batt_present = %d\n",
chip->charging_disabled,
+ chip->bpd_detection,
qpnp_chg_is_usb_chg_plugged_in(chip),
qpnp_chg_is_dc_chg_plugged_in(chip),
get_prop_batt_present(chip),
@@ -2216,6 +2472,7 @@
qpnp_adc_tm_disable_chan_meas(&chip->adc_param);
}
cancel_work_sync(&chip->adc_measure_work);
+ cancel_delayed_work_sync(&chip->eoc_work);
dev_set_drvdata(&spmi->dev, NULL);
kfree(chip);
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index 2d10f89..c9d0500 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -514,8 +514,10 @@
{
struct qpnp_regulator *vreg = rdev_get_drvdata(rdev);
- if (vreg->ocp_irq)
+ if (vreg->ocp_irq) {
+ vreg->ocp_count = 0;
vreg->vs_enable_time = ktime_get();
+ }
return qpnp_regulator_common_enable(rdev);
}
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 814817b..ab59864 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -596,7 +596,14 @@
pr_info("%s: Max frequency reset for cpu%d\n",
KBUILD_MODNAME, cpu);
- ret = cpufreq_update_policy(cpu);
+ if (cpu_online(cpu)) {
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ if (!policy)
+ return ret;
+ ret = cpufreq_driver_target(policy, policy->cur,
+ CPUFREQ_RELATION_H);
+ cpufreq_cpu_put(policy);
+ }
return ret;
}
@@ -748,14 +755,56 @@
return ret;
}
+static void __cpuinit do_freq_control(long temp)
+{
+ int ret = 0;
+ int cpu = 0;
+ uint32_t max_freq = limited_max_freq;
+
+ if (temp >= msm_thermal_info.limit_temp_degC) {
+ if (limit_idx == limit_idx_low)
+ return;
+
+ limit_idx -= msm_thermal_info.freq_step;
+ if (limit_idx < limit_idx_low)
+ limit_idx = limit_idx_low;
+ max_freq = table[limit_idx].frequency;
+ } else if (temp < msm_thermal_info.limit_temp_degC -
+ msm_thermal_info.temp_hysteresis_degC) {
+ if (limit_idx == limit_idx_high)
+ return;
+
+ limit_idx += msm_thermal_info.freq_step;
+ if (limit_idx >= limit_idx_high) {
+ limit_idx = limit_idx_high;
+ max_freq = MSM_CPUFREQ_NO_LIMIT;
+ } else
+ max_freq = table[limit_idx].frequency;
+ }
+
+ if (max_freq == limited_max_freq)
+ return;
+
+ /* Update new limits */
+ for_each_possible_cpu(cpu) {
+ if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
+ continue;
+ ret = update_cpu_max_freq(cpu, max_freq);
+ if (ret)
+ pr_debug(
+ "%s: Unable to limit cpu%d max freq to %d\n",
+ KBUILD_MODNAME, cpu, max_freq);
+ }
+
+}
+
static void __cpuinit check_temp(struct work_struct *work)
{
static int limit_init;
struct tsens_device tsens_dev;
long temp = 0;
- uint32_t max_freq = limited_max_freq;
- int cpu = 0;
int ret = 0;
+
tsens_dev.sensor_num = msm_thermal_info.sensor_id;
ret = tsens_get_temp(&tsens_dev, &temp);
if (ret) {
@@ -775,38 +824,7 @@
do_core_control(temp);
do_vdd_restriction();
do_psm();
-
- if (temp >= msm_thermal_info.limit_temp_degC) {
- if (limit_idx == limit_idx_low)
- goto reschedule;
-
- limit_idx -= msm_thermal_info.freq_step;
- if (limit_idx < limit_idx_low)
- limit_idx = limit_idx_low;
- max_freq = table[limit_idx].frequency;
- } else if (temp < msm_thermal_info.limit_temp_degC -
- msm_thermal_info.temp_hysteresis_degC) {
- if (limit_idx == limit_idx_high)
- goto reschedule;
-
- limit_idx += msm_thermal_info.freq_step;
- if (limit_idx >= limit_idx_high) {
- limit_idx = limit_idx_high;
- max_freq = MSM_CPUFREQ_NO_LIMIT;
- } else
- max_freq = table[limit_idx].frequency;
- }
- if (max_freq == limited_max_freq)
- goto reschedule;
-
- /* Update new limits */
- for_each_possible_cpu(cpu) {
- ret = update_cpu_max_freq(cpu, max_freq);
- if (ret)
- pr_debug(
- "%s: Unable to limit cpu%d max freq to %d\n",
- KBUILD_MODNAME, cpu, max_freq);
- }
+ do_freq_control(temp);
reschedule:
if (enabled)
@@ -1599,6 +1617,9 @@
if (ret)
goto fail;
+ key = "qcom,freq-control-mask";
+ ret = of_property_read_u32(node, key, &data.freq_control_mask);
+
key = "qcom,core-limit-temp";
ret = of_property_read_u32(node, key, &data.core_limit_temp_degC);
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index 26a12d0..f3b29c9 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -91,8 +91,8 @@
#define QPNP_M2_ADC_CH_SEL_CTL 0x70
#define QPNP_M2_LOW_THR_LSB 0x71
#define QPNP_M2_LOW_THR_MSB 0x72
-#define QPNP_M2_HIGH_THR_LSB 0x7b
-#define QPNP_M2_HIGH_THR_MSB 0x7c
+#define QPNP_M2_HIGH_THR_LSB 0x73
+#define QPNP_M2_HIGH_THR_MSB 0x74
#define QPNP_M3_ADC_CH_SEL_CTL 0x78
#define QPNP_M3_LOW_THR_LSB 0x79
#define QPNP_M3_LOW_THR_MSB 0x7a
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index c08a259..1059a4d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1706,6 +1706,7 @@
int ret = 0;
u32 reg;
+ pm_runtime_get_sync(dwc->dev);
spin_lock_irqsave(&dwc->lock, flags);
if (dwc->gadget_driver) {
@@ -1765,6 +1766,7 @@
dwc3_ep0_out_start(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
+ pm_runtime_put(dwc->dev);
return 0;
@@ -1773,6 +1775,7 @@
err0:
spin_unlock_irqrestore(&dwc->lock, flags);
+ pm_runtime_put(dwc->dev);
return ret;
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 38f08fc..678627a 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2325,7 +2325,7 @@
/*stop charging upon reset */
if (udc->transceiver)
- usb_phy_set_power(udc->transceiver, 0);
+ usb_phy_set_power(udc->transceiver, 100);
retval = _gadget_stop_activity(&udc->gadget);
if (retval)
@@ -3793,9 +3793,7 @@
pm_runtime_no_callbacks(&udc->gadget.dev);
pm_runtime_enable(&udc->gadget.dev);
- retval = register_trace_usb_daytona_invalid_access(dump_usb_info,
- NULL);
- if (retval)
+ if (register_trace_usb_daytona_invalid_access(dump_usb_info, NULL))
pr_err("Registering trace failed\n");
_udc = udc;
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 22f8dc9..a1b02be 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -798,8 +798,6 @@
{
struct usb_request *req = mbim->not_port.notify_req;
struct usb_cdc_notification *event;
- struct usb_composite_dev *cdev = mbim->cdev;
- __le32 *data;
int status;
pr_debug("notify_state: %d", mbim->not_port.notify_state);
@@ -836,36 +834,6 @@
}
return;
-
- case NCM_NOTIFY_CONNECT:
- event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
- if (mbim->is_open)
- event->wValue = cpu_to_le16(1);
- else
- event->wValue = cpu_to_le16(0);
- event->wLength = 0;
- req->length = sizeof *event;
-
- pr_info("notify connect %s\n",
- mbim->is_open ? "true" : "false");
- mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
- break;
-
- case NCM_NOTIFY_SPEED:
- event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
- event->wValue = cpu_to_le16(0);
- event->wLength = cpu_to_le16(8);
- req->length = NCM_STATUS_BYTECOUNT;
-
- /* SPEED_CHANGE data is up/down speeds in bits/sec */
- data = req->buf + sizeof *event;
- data[0] = cpu_to_le32(mbim_bitrate(cdev->gadget));
- data[1] = data[0];
-
- pr_info("notify speed %d\n",
- mbim_bitrate(cdev->gadget));
- mbim->not_port.notify_state = NCM_NOTIFY_CONNECT;
- break;
}
event->bmRequestType = 0xA1;
@@ -888,22 +856,6 @@
}
}
-/*
- * Context: mbim->lock held
- */
-static void mbim_notify(struct f_mbim *mbim)
-{
- /*
- * If mbim_notify() is called before the second (CONNECT)
- * notification is sent, then it will reset to send the SPEED
- * notificaion again (and again, and again), but it's not a problem
- */
- pr_debug("dev:%p\n", mbim);
-
- mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
- mbim_do_notify(mbim);
-}
-
static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_mbim *mbim = req->context;
@@ -1391,7 +1343,7 @@
mbim->data_alt_int = alt;
spin_lock(&mbim->lock);
- mbim_notify(mbim);
+ mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
spin_unlock(&mbim->lock);
} else {
goto fail;
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index a395d15..5e68296 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -599,7 +599,7 @@
DBG(cdev, "activate ecm\n");
if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA) {
net = gether_qc_connect_name(&ecm->port,
- "ecm0");
+ "ecm0", true);
if (IS_ERR(net))
return PTR_ERR(net);
}
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 8b01176..baea664 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -725,7 +725,7 @@
rndis->port.cdc_filter = 0;
DBG(cdev, "RNDIS RX/TX early activation ...\n");
- net = gether_qc_connect_name(&rndis->port, "rndis0");
+ net = gether_qc_connect_name(&rndis->port, "rndis0", false);
if (IS_ERR(net))
return PTR_ERR(net);
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 1017900..1288bfd 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -74,7 +74,7 @@
static unsigned int rndis_ul_max_pkt_per_xfer = 1;
module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
- "Disable RNDIS Multi-packet support in DownLink");
+ "Maximum packets per transfer for UL aggregation");
struct f_rndis {
struct gether port;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 07f4d26..bff7eb1 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -947,6 +947,10 @@
rndis_per_dev_params[configNr].dev = dev;
rndis_per_dev_params[configNr].filter = cdc_filter;
+ /* reset aggregation stats for every set_alt */
+ rndis_ul_max_xfer_size_rcvd = 0;
+ rndis_ul_max_pkt_per_xfer_rcvd = 0;
+
return 0;
}
@@ -1060,7 +1064,7 @@
struct sk_buff *skb,
struct sk_buff_head *list)
{
- int num_pkts = 1;
+ int num_pkts = 0;
if (skb->len > rndis_ul_max_xfer_size_rcvd)
rndis_ul_max_xfer_size_rcvd = skb->len;
@@ -1072,6 +1076,8 @@
/* some rndis hosts send extra byte to avoid zlp, ignore it */
if (skb->len == 1) {
+ if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
+ rndis_ul_max_pkt_per_xfer_rcvd = num_pkts;
dev_kfree_skb_any(skb);
return 0;
}
@@ -1105,6 +1111,8 @@
return -EINVAL;
}
+ num_pkts++;
+
skb_pull(skb, data_offset + 8);
if (msg_len == skb->len) {
@@ -1122,8 +1130,6 @@
skb_pull(skb, msg_len - sizeof *hdr);
skb_trim(skb2, data_len);
skb_queue_tail(list, skb2);
-
- num_pkts++;
}
if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
@@ -1148,7 +1154,9 @@
"speed : %d\n"
"cable : %s\n"
"vendor ID : 0x%08X\n"
- "vendor : %s\n",
+ "vendor : %s\n"
+ "ul-max-xfer-size:%d max-xfer-size-rcvd: %d\n"
+ "ul-max-pkts-per-xfer:%d max-pkts-per-xfer-rcvd:%d\n",
param->confignr, (param->used) ? "y" : "n",
({ char *s = "?";
switch (param->state) {
@@ -1162,7 +1170,13 @@
param->medium,
(param->media_state) ? 0 : param->speed*100,
(param->media_state) ? "disconnected" : "connected",
- param->vendorID, param->vendorDescr);
+ param->vendorID, param->vendorDescr,
+ param->max_pkt_per_xfer *
+ (param->dev->mtu + sizeof(struct ethhdr) +
+ sizeof(struct rndis_packet_msg_type) + 22),
+ rndis_ul_max_xfer_size_rcvd,
+ param->max_pkt_per_xfer,
+ rndis_ul_max_pkt_per_xfer_rcvd);
return 0;
}
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index c05f683..b71f903 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -539,9 +539,12 @@
struct bam_ch_info *d = &port->data_ch;
int status;
- if (!port->port_usb)
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
return;
+ }
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
if (status)
pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
@@ -552,14 +555,69 @@
struct bam_ch_info *d = &port->data_ch;
int status;
- if (!port->port_usb)
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
return;
+ }
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
if (status)
pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
}
+static void gbam_stop_endless_rx(struct gbam_port *port)
+{
+ struct bam_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
+ return;
+ }
+ pr_debug("%s: dequeue\n", __func__);
+
+ status = usb_ep_dequeue(port->port_usb->out, d->rx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+
+}
+static void gbam_stop_endless_tx(struct gbam_port *port)
+{
+ struct bam_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb) {
+ pr_err("%s: port->port_usb is NULL", __func__);
+ return;
+ }
+
+ pr_debug("%s: dequeue\n", __func__);
+ status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+}
+
+static void gbam_start(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct gbam_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ gbam_start_endless_rx(port);
+ else
+ gbam_start_endless_tx(port);
+}
+
+static void gbam_stop(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct gbam_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ gbam_stop_endless_rx(port);
+ else
+ gbam_stop_endless_tx(port);
+}
+
static void gbam_start_io(struct gbam_port *port)
{
unsigned long flags;
@@ -1409,6 +1467,10 @@
pr_debug("%s: suspended port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
+ if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ usb_bam_register_start_stop_cbs(gbam_start, gbam_stop, port);
+ usb_bam_suspend(&d->ipa_params);
+ }
}
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
@@ -1426,4 +1488,6 @@
pr_debug("%s: resumed port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
+ if (trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+ usb_bam_resume(&d->ipa_params);
}
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 2abe2ef..081a09c 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -92,6 +92,7 @@
if (!port->port_usb)
return;
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
if (status)
pr_err("error enqueuing transfer, %d\n", status);
@@ -105,11 +106,40 @@
if (!port->port_usb)
return;
+ pr_debug("%s: enqueue\n", __func__);
status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
if (status)
pr_err("error enqueuing transfer, %d\n", status);
}
+static void bam_data_stop_endless_rx(struct bam_data_port *port)
+{
+ struct bam_data_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb)
+ return;
+
+ pr_debug("%s: dequeue\n", __func__);
+ status = usb_ep_dequeue(port->port_usb->out, d->rx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+
+}
+static void bam_data_stop_endless_tx(struct bam_data_port *port)
+{
+ struct bam_data_ch_info *d = &port->data_ch;
+ int status;
+
+ if (!port->port_usb)
+ return;
+
+ pr_debug("%s: dequeue\n", __func__);
+ status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
+ if (status)
+ pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+}
+
static int bam_data_peer_reset_cb(void *param)
{
struct bam_data_port *port = (struct bam_data_port *)param;
@@ -529,9 +559,28 @@
return usb_gadget_wakeup(d_port->cdev->gadget);
}
+static void bam_data_start(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct bam_data_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ bam_data_start_endless_rx(port);
+ else
+ bam_data_start_endless_tx(port);
+}
+
+static void bam_data_stop(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct bam_data_port *port = param;
+
+ if (dir == USB_TO_PEER_PERIPHERAL)
+ bam_data_stop_endless_rx(port);
+ else
+ bam_data_stop_endless_tx(port);
+}
+
void bam_data_suspend(u8 port_num)
{
-
struct bam_data_port *port;
struct bam_data_ch_info *d;
@@ -540,6 +589,11 @@
pr_debug("%s: suspended port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ usb_bam_register_start_stop_cbs(bam_data_start, bam_data_stop,
+ port);
+ usb_bam_suspend(&d->ipa_params);
+ }
}
void bam_data_resume(u8 port_num)
@@ -553,5 +607,6 @@
pr_debug("%s: resumed port %d\n", __func__, port_num);
usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+ usb_bam_resume(&d->ipa_params);
}
-
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index d4c21dd..dbffa4e 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -70,7 +70,7 @@
struct sk_buff_head rx_frames;
unsigned header_len;
- unsigned ul_max_pkts_per_xfer;
+ unsigned int ul_max_pkts_per_xfer;
struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
int (*unwrap)(struct gether *,
struct sk_buff *skb,
diff --git a/drivers/usb/gadget/u_qc_ether.c b/drivers/usb/gadget/u_qc_ether.c
index e10ec25..044da47 100644
--- a/drivers/usb/gadget/u_qc_ether.c
+++ b/drivers/usb/gadget/u_qc_ether.c
@@ -354,12 +354,13 @@
* current device speed, and any framing wrapper(s) set up.
* @netname: name for network device (for example, "usb")
* Context: irqs blocked
+ * @netif_enable: if true, net interface will be turned on
*
* This is called to let the network layer know the connection
* is active ("carrier detect").
*/
struct net_device *gether_qc_connect_name(struct qc_gether *link,
- const char *netname)
+ const char *netname, bool netif_enable)
{
struct net_device *net_dev;
struct eth_qc_dev *dev;
@@ -390,9 +391,11 @@
}
spin_unlock(&dev->lock);
- netif_carrier_on(dev->net);
- if (netif_running(dev->net))
- netif_wake_queue(dev->net);
+ if (netif_enable) {
+ netif_carrier_on(dev->net);
+ if (netif_running(dev->net))
+ netif_wake_queue(dev->net);
+ }
return dev->net;
}
diff --git a/drivers/usb/gadget/u_qc_ether.h b/drivers/usb/gadget/u_qc_ether.h
index 25562da..5d9f738 100644
--- a/drivers/usb/gadget/u_qc_ether.h
+++ b/drivers/usb/gadget/u_qc_ether.h
@@ -82,7 +82,7 @@
/* connect/disconnect is handled by individual functions */
struct net_device *gether_qc_connect_name(struct qc_gether *link,
- const char *netname);
+ const char *netname, bool netif_enable);
void gether_qc_disconnect_name(struct qc_gether *link, const char *netname);
/* each configuration may bind one instance of an ethernet link */
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index ede8bdb..d1d0f91 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -2180,7 +2180,6 @@
#ifdef CONFIG_PM_SLEEP
static int msm_hsic_pm_suspend(struct device *dev)
{
- int ret;
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -2188,15 +2187,16 @@
dbg_log_event(NULL, "PM Suspend", 0);
+ if (!atomic_read(&mehci->in_lpm)) {
+ dev_info(dev, "abort suspend\n");
+ dbg_log_event(NULL, "PM Suspend abort", 0);
+ return -EBUSY;
+ }
+
if (device_may_wakeup(dev) && !mehci->async_irq)
enable_irq_wake(hcd->irq);
- ret = msm_hsic_suspend(mehci);
-
- if (ret && device_may_wakeup(dev) && !mehci->async_irq)
- disable_irq_wake(hcd->irq);
-
- return ret;
+ return 0;
}
static int msm_hsic_pm_suspend_noirq(struct device *dev)
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index d4d7ee9..44a7aee 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -861,7 +861,7 @@
struct usb_bus *bus = phy->otg->host;
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
- bool host_bus_suspend, device_bus_suspend, dcp;
+ bool host_bus_suspend, device_bus_suspend, dcp, prop_charger;
u32 phy_ctrl_val = 0, cmd_val;
unsigned ret;
u32 portsc;
@@ -870,7 +870,7 @@
return 0;
if (motg->pdata->delay_lpm_hndshk_on_disconnect && !msm_bam_lpm_ok())
- return 0;
+ return -EBUSY;
disable_irq(motg->irq);
host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
@@ -879,6 +879,7 @@
test_bit(A_BUS_SUSPEND, &motg->inputs) &&
motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
dcp = motg->chg_type == USB_DCP_CHARGER;
+ prop_charger = motg->chg_type == USB_PROPRIETARY_CHARGER;
/*
* Abort suspend when,
@@ -887,7 +888,7 @@
*/
if ((test_bit(B_SESS_VLD, &motg->inputs) && !device_bus_suspend &&
- !dcp) || test_bit(A_BUS_REQ, &motg->inputs)) {
+ !dcp && !prop_charger) || test_bit(A_BUS_REQ, &motg->inputs)) {
enable_irq(motg->irq);
return -EBUSY;
}
@@ -955,7 +956,7 @@
*/
cmd_val = readl_relaxed(USB_USBCMD);
if (host_bus_suspend || device_bus_suspend ||
- (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
+ (motg->pdata->otg_control == OTG_PHY_CONTROL))
cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
else
cmd_val |= ULPI_STP_CTRL;
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 2c58e49..43eda51 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,4 +1,5 @@
mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o
+mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp3.o
mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 290e317..5223e66 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -48,11 +48,12 @@
#include "mdss_fb.h"
#include "mdp3_hwio.h"
#include "mdp3_ctrl.h"
+#include "mdp3_ppp.h"
#define MDP_CORE_HW_VERSION 0x03040310
struct mdp3_hw_resource *mdp3_res;
-#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
+#define MDP_BUS_VECTOR_ENTRY_DMA(ab_val, ib_val) \
{ \
.src = MSM_BUS_MASTER_MDP_PORT0, \
.dst = MSM_BUS_SLAVE_EBI_CH0, \
@@ -60,20 +61,59 @@
.ib = (ib_val), \
}
-static struct msm_bus_vectors mdp_bus_vectors[] = {
- 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_vectors mdp_bus_dma_vectors[] = {
+ MDP_BUS_VECTOR_ENTRY_DMA(0, 0),
+ MDP_BUS_VECTOR_ENTRY_DMA(SZ_128M, SZ_256M),
+ MDP_BUS_VECTOR_ENTRY_DMA(SZ_256M, SZ_512M),
+};
+static struct msm_bus_paths
+ mdp_bus_dma_usecases[ARRAY_SIZE(mdp_bus_dma_vectors)];
+static struct msm_bus_scale_pdata mdp_bus_dma_scale_table = {
+ .usecase = mdp_bus_dma_usecases,
+ .num_usecases = ARRAY_SIZE(mdp_bus_dma_usecases),
+ .name = "mdp3",
};
-static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
+#define MDP_BUS_VECTOR_ENTRY_PPP(ab_val, ib_val) \
+ { \
+ .src = MSM_BUS_MASTER_MDPE, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ab = (ab_val), \
+ .ib = (ib_val), \
+ }
-static struct msm_bus_scale_pdata mdp_bus_scale_table = {
- .usecase = mdp_bus_usecases,
- .num_usecases = ARRAY_SIZE(mdp_bus_usecases),
+static struct msm_bus_vectors mdp_bus_ppp_vectors[] = {
+ MDP_BUS_VECTOR_ENTRY_PPP(0, 0),
+ MDP_BUS_VECTOR_ENTRY_PPP(SZ_128M, SZ_256M),
+ MDP_BUS_VECTOR_ENTRY_PPP(SZ_256M, SZ_512M),
+};
+
+static struct msm_bus_paths
+ mdp_bus_ppp_usecases[ARRAY_SIZE(mdp_bus_ppp_vectors)];
+
+static struct msm_bus_scale_pdata mdp_bus_ppp_scale_table = {
+ .usecase = mdp_bus_ppp_usecases,
+ .num_usecases = ARRAY_SIZE(mdp_bus_ppp_usecases),
.name = "mdp3",
};
+struct mdp3_bus_handle_map mdp3_bus_handle[MDP3_BUS_HANDLE_MAX] = {
+ [MDP3_BUS_HANDLE_DMA] = {
+ .bus_vector = mdp_bus_dma_vectors,
+ .usecases = mdp_bus_dma_usecases,
+ .scale_pdata = &mdp_bus_dma_scale_table,
+ .current_bus_idx = 0,
+ .handle = 0,
+ },
+ [MDP3_BUS_HANDLE_PPP] = {
+ .bus_vector = mdp_bus_ppp_vectors,
+ .usecases = mdp_bus_ppp_usecases,
+ .scale_pdata = &mdp_bus_ppp_scale_table,
+ .current_bus_idx = 0,
+ .handle = 0,
+ },
+};
+
struct mdp3_iommu_domain_map mdp3_iommu_domains[MDP3_IOMMU_DOMAIN_MAX] = {
[MDP3_IOMMU_DOMAIN] = {
.domain_type = MDP3_IOMMU_DOMAIN,
@@ -213,71 +253,106 @@
static int mdp3_bus_scale_register(void)
{
+ int i;
+
if (!mdp3_res->bus_handle) {
- struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
- int i;
+ pr_err("No bus handle\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) {
+ struct mdp3_bus_handle_map *bus_handle =
+ &mdp3_res->bus_handle[i];
- for (i = 0; i < bus_pdata->num_usecases; i++) {
- mdp_bus_usecases[i].num_paths = 1;
- mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i];
- }
+ if (!bus_handle->handle) {
+ int j;
+ struct msm_bus_scale_pdata *bus_pdata =
+ bus_handle->scale_pdata;
- mdp3_res->bus_handle = msm_bus_scale_register_client(bus_pdata);
- if (!mdp3_res->bus_handle) {
- pr_err("not able to get bus scale\n");
- return -ENOMEM;
+ for (j = 0; j < bus_pdata->num_usecases; j++) {
+ bus_handle->usecases[j].num_paths = 1;
+ bus_handle->usecases[j].vectors =
+ &bus_handle->bus_vector[j];
+ }
+
+ bus_handle->handle =
+ msm_bus_scale_register_client(bus_pdata);
+ if (!bus_handle->handle) {
+ pr_err("not able to get bus scale i=%d\n", i);
+ return -ENOMEM;
+ }
+ pr_debug("register bus_hdl=%x\n",
+ bus_handle->handle);
}
- pr_debug("register bus_hdl=%x\n", mdp3_res->bus_handle);
}
return 0;
}
static void mdp3_bus_scale_unregister(void)
{
- pr_debug("unregister bus_handle=%x\n", mdp3_res->bus_handle);
-
- if (mdp3_res->bus_handle)
- msm_bus_scale_unregister_client(mdp3_res->bus_handle);
+ int i;
+ for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) {
+ pr_debug("unregister index=%d bus_handle=%x\n",
+ i, mdp3_res->bus_handle[i].handle);
+ if (mdp3_res->bus_handle[i].handle) {
+ msm_bus_scale_unregister_client(
+ mdp3_res->bus_handle[i].handle);
+ mdp3_res->bus_handle[i].handle = 0;
+ }
+ }
}
int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota)
{
- static int current_bus_idx;
+ struct mdp3_bus_handle_map *bus_handle;
+ int cur_bus_idx;
int bus_idx;
+ int client_idx;
int rc;
- if (mdp3_res->bus_handle < 1) {
- pr_err("invalid bus handle %d\n", mdp3_res->bus_handle);
+ if (client == MDP3_CLIENT_DMA_P) {
+ client_idx = MDP3_BUS_HANDLE_DMA;
+ } else if (client == MDP3_CLIENT_PPP) {
+ client_idx = MDP3_BUS_HANDLE_PPP;
+ } else {
+ pr_err("invalid client %d\n", client);
+ return -EINVAL;
+ }
+
+ bus_handle = &mdp3_res->bus_handle[client_idx];
+ cur_bus_idx = bus_handle->current_bus_idx;
+
+ if (bus_handle->handle < 1) {
+ pr_err("invalid bus handle %d\n", bus_handle->handle);
return -EINVAL;
}
if ((ab_quota | ib_quota) == 0) {
bus_idx = 0;
} else {
- int num_cases = mdp_bus_scale_table.num_usecases;
+ int num_cases = bus_handle->scale_pdata->num_usecases;
struct msm_bus_vectors *vect = NULL;
- bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
+ bus_idx = (cur_bus_idx % (num_cases - 1)) + 1;
/* aligning to avoid performing updates for small changes */
ab_quota = ALIGN(ab_quota, SZ_64M);
ib_quota = ALIGN(ib_quota, SZ_64M);
- vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
+ vect = bus_handle->scale_pdata->usecase[cur_bus_idx].vectors;
if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
pr_debug("skip bus scaling, no change in vectors\n");
return 0;
}
- vect = mdp_bus_scale_table.usecase[bus_idx].vectors;
+ vect = bus_handle->scale_pdata->usecase[bus_idx].vectors;
vect->ab = ab_quota;
vect->ib = ib_quota;
pr_debug("bus scale idx=%d ab=%llu ib=%llu\n", bus_idx,
vect->ab, vect->ib);
}
- current_bus_idx = bus_idx;
- rc = msm_bus_scale_client_update_request(mdp3_res->bus_handle, bus_idx);
+ bus_handle->current_bus_idx = bus_idx;
+ rc = msm_bus_scale_client_update_request(bus_handle->handle, bus_idx);
return rc;
}
@@ -298,7 +373,7 @@
mdp3_res->clock_ref_count[clk_idx]--;
count = mdp3_res->clock_ref_count[clk_idx];
- if (count == 1) {
+ if (count == 1 && enable) {
pr_debug("clk=%d en=%d\n", clk_idx, enable);
ret = clk_prepare_enable(clk);
} else if (count == 0) {
@@ -655,6 +730,7 @@
pr_err("fail to attach DMA-P context 0\n");
return rc;
}
+ mdp3_res->bus_handle = mdp3_bus_handle;
rc = mdp3_bus_scale_register();
if (rc) {
pr_err("unable to register bus scaling\n");
@@ -800,9 +876,28 @@
return ret;
}
+int mdp3_ppp_iommu_attach(void)
+{
+ int rc;
+ rc = mdp3_iommu_attach(MDP3_IOMMU_CTX_PPP_0);
+ rc |= mdp3_iommu_attach(MDP3_IOMMU_CTX_PPP_1);
+ return rc;
+}
+
+int mdp3_ppp_iommu_dettach(void)
+{
+ int rc;
+ rc = mdp3_iommu_dettach(MDP3_IOMMU_CTX_PPP_0);
+ rc = mdp3_iommu_dettach(MDP3_IOMMU_CTX_PPP_1);
+ return rc;
+}
+
static int mdp3_init(struct msm_fb_data_type *mfd)
{
- return mdp3_ctrl_init(mfd);
+ int rc;
+ rc = mdp3_ctrl_init(mfd);
+ rc |= mdp3_ppp_res_init();
+ return rc;
}
u32 mdp3_fb_stride(u32 fb_index, u32 xres, int bpp)
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 7e395e1..878fe25 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -35,6 +35,12 @@
};
enum {
+ MDP3_BUS_HANDLE_DMA,
+ MDP3_BUS_HANDLE_PPP,
+ MDP3_BUS_HANDLE_MAX,
+};
+
+enum {
MDP3_IOMMU_DOMAIN,
MDP3_IOMMU_DOMAIN_MAX
};
@@ -48,10 +54,16 @@
};
enum {
- MDP3_BW_CLIENT_DMA_P,
- MDP3_BW_CLIENT_DMA_S,
- MDP3_BW_CLIENT_DMA_E,
- MDP3_BW_CLIENT_PPP,
+ MDP3_CLIENT_DMA_P,
+ MDP3_CLIENT_PPP,
+};
+
+struct mdp3_bus_handle_map {
+ struct msm_bus_vectors *bus_vector;
+ struct msm_bus_paths *usecases;
+ struct msm_bus_scale_pdata *scale_pdata;
+ int current_bus_idx;
+ u32 handle;
};
struct mdp3_iommu_domain_map {
@@ -86,12 +98,14 @@
struct clk *clocks[MDP3_MAX_CLK];
int clock_ref_count[MDP3_MAX_CLK];
+ unsigned long dma_core_clk_request;
+ unsigned long ppp_core_clk_request;
char __iomem *mdp_base;
size_t mdp_reg_size;
u32 irq;
- u32 bus_handle;
+ struct mdp3_bus_handle_map *bus_handle;
struct ion_client *ion_client;
struct mdp3_iommu_domain_map *domains;
@@ -130,6 +144,8 @@
int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
int mdp3_put_img(struct mdp3_img_data *data);
int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
+int mdp3_ppp_iommu_attach(void);
+int mdp3_ppp_iommu_dettach(void);
#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index f5ac5e9..b5134a7 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -22,7 +22,9 @@
#include "mdp3_ctrl.h"
#include "mdp3.h"
+#include "mdp3_ppp.h"
+#define MDP_CORE_CLK_RATE 100000000
#define MDP_VSYNC_CLK_RATE 19200000
#define VSYNC_PERIOD 16
@@ -127,6 +129,53 @@
return 0;
}
+static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p)
+{
+ const int MAX_LIST_WINDOW = 16;
+ struct mdp_blit_req req_list[MAX_LIST_WINDOW];
+ struct mdp_blit_req_list req_list_header;
+ int rc, count, i, req_list_count;
+
+ if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
+ return -EFAULT;
+ p += sizeof(req_list_header);
+ count = req_list_header.count;
+ if (count < 0 || count >= MAX_BLIT_REQ)
+ return -EINVAL;
+ while (count > 0) {
+ /*
+ * Access the requests through a narrow window to decrease copy
+ * overhead and make larger requests accessible to the
+ * coherency management code.
+ * NOTE: The window size is intended to be larger than the
+ * typical request size, but not require more than 2
+ * kbytes of stack storage.
+ */
+ req_list_count = count;
+ if (req_list_count > MAX_LIST_WINDOW)
+ req_list_count = MAX_LIST_WINDOW;
+ if (copy_from_user(&req_list, p,
+ sizeof(struct mdp_blit_req)*req_list_count))
+ return -EFAULT;
+ /*
+ * Do the blit DMA, if required -- returning early only if
+ * there is a failure.
+ */
+ for (i = 0; i < req_list_count; i++) {
+ if (!(req_list[i].flags & MDP_NO_BLIT)) {
+ /* Do the actual blit. */
+ rc = mdp3_ppp_start_blit(mfd, &(req_list[i]));
+ if (rc)
+ return rc;
+ }
+ }
+
+ /* Go to next window of requests. */
+ count -= req_list_count;
+ p += sizeof(struct mdp_blit_req)*req_list_count;
+ }
+ return 0;
+}
static ssize_t mdp3_vsync_show_event(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -181,9 +230,9 @@
ab = panel_info->xres * panel_info->yres * 4;
ab *= panel_info->mipi.frame_rate;
ib = (ab * 3) / 2;
- rc = mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, ab, ib);
+ rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib);
} else {
- rc = mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, 0, 0);
+ rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, 0, 0);
}
return rc;
}
@@ -192,17 +241,8 @@
{
int rc = 0;
if (status) {
- struct mdss_panel_info *panel_info = mfd->panel_info;
- unsigned long core_clk;
- int vtotal;
- vtotal = panel_info->lcdc.v_back_porch +
- panel_info->lcdc.v_front_porch +
- panel_info->lcdc.v_pulse_width +
- panel_info->yres;
- core_clk = panel_info->xres * panel_info->yres;
- core_clk *= panel_info->mipi.frame_rate;
- core_clk = (core_clk / panel_info->yres) * vtotal;
- mdp3_clk_set_rate(MDP3_CLK_CORE, core_clk);
+
+ mdp3_clk_set_rate(MDP3_CLK_CORE, MDP_CORE_CLK_RATE);
mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE);
rc = mdp3_clk_enable(true);
@@ -394,6 +434,12 @@
goto on_error;
}
+ rc = mdp3_ppp_init();
+ if (rc) {
+ pr_err("ppp init failed\n");
+ goto on_error;
+ }
+
rc = mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
if (rc) {
pr_err("display interface init failed\n");
@@ -701,6 +747,9 @@
rc = -EFAULT;
}
break;
+ case MSMFB_BLIT:
+ rc = mdp3_ctrl_blit_req(mfd, argp);
+ break;
case MSMFB_METADATA_GET:
rc = copy_from_user(&metadata, argp, sizeof(metadata));
if (rc)
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index a09f503..fa2e9eb 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -218,7 +218,7 @@
* NOTE: MDP_DMA_P_FETCH_CFG: max_burst_size need to use value 4, not
* the default 16 for MDP hang issue workaround
*/
- MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x10);
+ MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x20);
MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x10);
dma->source_config = *source_config;
@@ -809,6 +809,7 @@
temp |= BIT(2);
MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_CTL_POLARITY, temp);
+ MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_UNDERFLOW_CTL, 0x800000ff);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdp3_hwio.h b/drivers/video/msm/mdss/mdp3_hwio.h
index 2763f46..1c5bf46 100644
--- a/drivers/video/msm/mdss/mdp3_hwio.h
+++ b/drivers/video/msm/mdss/mdp3_hwio.h
@@ -148,6 +148,70 @@
#define MDP3_REG_DSI_CMD_MODE_ID_MAP 0xF1000
#define MDP3_REG_DSI_CMD_MODE_TRIGGER_EN 0xF1004
+#define MDP3_PPP_CSC_PFMVn(n) (0x40400 + (4 * (n)))
+#define MDP3_PPP_CSC_PRMVn(n) (0x40440 + (4 * (n)))
+#define MDP3_PPP_CSC_PBVn(n) (0x40500 + (4 * (n)))
+#define MDP3_PPP_CSC_PLVn(n) (0x40580 + (4 * (n)))
+
+#define MDP3_PPP_CSC_SFMVn(n) (0x40480 + (4 * (n)))
+#define MDP3_PPP_CSC_SRMVn(n) (0x404C0 + (4 * (n)))
+#define MDP3_PPP_CSC_SBVn(n) (0x40540 + (4 * (n)))
+#define MDP3_PPP_CSC_SLVn(n) (0x405C0 + (4 * (n)))
+
+#define MDP3_PPP_SCALE_PHASEX_INIT 0x1013C
+#define MDP3_PPP_SCALE_PHASEY_INIT 0x10140
+#define MDP3_PPP_SCALE_PHASEX_STEP 0x10144
+#define MDP3_PPP_SCALE_PHASEY_STEP 0x10148
+
+#define MDP3_PPP_OP_MODE 0x10138
+
+#define MDP3_PPP_PRE_LUT 0x40800
+#define MDP3_PPP_POST_LUT 0x40C00
+#define MDP3_PPP_LUTn(n) ((4 * (n)))
+
+#define MDP3_PPP_BG_EDGE_REP 0x101BC
+#define MDP3_PPP_SRC_EDGE_REP 0x101B8
+
+#define MDP3_PPP_STRIDE_MASK 0x3FFF
+#define MDP3_PPP_STRIDE1_OFFSET 16
+
+#define MDP3_PPP_XY_MASK 0x0FFF
+#define MDP3_PPP_XY_OFFSET 16
+
+#define MDP3_PPP_SRC_SIZE 0x10108
+#define MDP3_PPP_SRCP0_ADDR 0x1010C
+#define MDP3_PPP_SRCP1_ADDR 0x10110
+#define MDP3_PPP_SRCP3_ADDR 0x10118
+#define MDP3_PPP_SRC_YSTRIDE1_ADDR 0x1011C
+#define MDP3_PPP_SRC_YSTRIDE2_ADDR 0x10120
+#define MDP3_PPP_SRC_FORMAT 0x10124
+#define MDP3_PPP_SRC_UNPACK_PATTERN1 0x10128
+#define MDP3_PPP_SRC_UNPACK_PATTERN2 0x1012C
+
+#define MDP3_PPP_OUT_FORMAT 0x10150
+#define MDP3_PPP_OUT_PACK_PATTERN1 0x10154
+#define MDP3_PPP_OUT_PACK_PATTERN2 0x10158
+#define MDP3_PPP_OUT_SIZE 0x10164
+#define MDP3_PPP_OUTP0_ADDR 0x10168
+#define MDP3_PPP_OUTP1_ADDR 0x1016C
+#define MDP3_PPP_OUTP3_ADDR 0x10174
+#define MDP3_PPP_OUT_YSTRIDE1_ADDR 0x10178
+#define MDP3_PPP_OUT_YSTRIDE2_ADDR 0x1017C
+#define MDP3_PPP_OUT_XY 0x1019C
+
+#define MDP3_PPP_BGP0_ADDR 0x101C0
+#define MDP3_PPP_BGP1_ADDR 0x101C4
+#define MDP3_PPP_BGP3_ADDR 0x101C8
+#define MDP3_PPP_BG_YSTRIDE1_ADDR 0x101CC
+#define MDP3_PPP_BG_YSTRIDE2_ADDR 0x101D0
+#define MDP3_PPP_BG_FORMAT 0x101D4
+#define MDP3_PPP_BG_UNPACK_PATTERN1 0x101D8
+#define MDP3_PPP_BG_UNPACK_PATTERN2 0x101DC
+
+#define MDP3_PPP_BLEND_PARAM 0x1014C
+
+#define MDP3_PPP_BLEND_BG_ALPHA_SEL 0x70010
+
/*interrupt mask*/
#define MDP3_INTR_DP0_ROI_DONE_BIT BIT(0)
@@ -212,5 +276,6 @@
#define MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT BIT(0)
#define MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT BIT(1)
+#define MDP3_PPP_DONE MDP3_INTR_DP0_ROI_DONE
#endif /* MDP3_HWIO_H */
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
new file mode 100644
index 0000000..7164086
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -0,0 +1,760 @@
+/* Copyright (c) 2007, 2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * 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/file.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include "linux/proc_fs.h"
+
+#include "mdss_fb.h"
+#include "mdp3_ppp.h"
+#include "mdp3_hwio.h"
+#include "mdp3.h"
+
+#define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT)
+
+static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = true,
+ [MDP_BGR_565] = true,
+ [MDP_RGB_888] = true,
+ [MDP_BGR_888] = true,
+ [MDP_BGRA_8888] = true,
+ [MDP_RGBA_8888] = true,
+ [MDP_ARGB_8888] = true,
+ [MDP_XRGB_8888] = true,
+ [MDP_RGBX_8888] = true,
+ [MDP_Y_CRCB_H2V2] = true,
+ [MDP_Y_CBCR_H2V2] = true,
+ [MDP_Y_CBCR_H2V2_ADRENO] = true,
+ [MDP_YCRYCB_H2V1] = true,
+ [MDP_Y_CBCR_H2V1] = true,
+ [MDP_Y_CRCB_H2V1] = true,
+};
+
+struct ppp_status {
+ int busy;
+ spinlock_t ppp_lock;
+ struct completion ppp_comp;
+ struct mutex config_mutex;
+};
+
+static struct ppp_status *ppp_stat;
+
+
+int ppp_get_bpp(uint32_t format, uint32_t fb_format)
+{
+ int bpp = -EINVAL;
+ if (format == MDP_FB_FORMAT)
+ format = fb_format;
+
+ bpp = ppp_bpp(format);
+ if (bpp <= 0)
+ pr_err("%s incorrect format %d\n", __func__, format);
+ return bpp;
+}
+
+int mdp3_ppp_get_img(struct mdp_img *img, struct mdp_blit_req *req,
+ struct mdp3_img_data *data)
+{
+ struct msmfb_data fb_data;
+ fb_data.flags = img->priv;
+ fb_data.memory_id = img->memory_id;
+ fb_data.offset = 0;
+
+ return mdp3_get_img(&fb_data, data);
+}
+
+/* Check format */
+int mdp3_ppp_verify_fmt(struct mdp_blit_req *req)
+{
+ if (MDP_IS_IMGTYPE_BAD(req->src.format) ||
+ MDP_IS_IMGTYPE_BAD(req->dst.format)) {
+ pr_err("%s: Color format out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!valid_fmt[req->src.format] ||
+ !valid_fmt[req->dst.format]) {
+ pr_err("%s: Color format not supported\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Check resolution */
+int mdp3_ppp_verify_res(struct mdp_blit_req *req)
+{
+ if ((req->src.width == 0) || (req->src.height == 0) ||
+ (req->src_rect.w == 0) || (req->src_rect.h == 0) ||
+ (req->dst.width == 0) || (req->dst.height == 0) ||
+ (req->dst_rect.w == 0) || (req->dst_rect.h == 0)) {
+ pr_err("%s: Height/width can't be 0\n", __func__);
+ return -EINVAL;
+ }
+
+ if (((req->src_rect.x + req->src_rect.w) > req->src.width) ||
+ ((req->src_rect.y + req->src_rect.h) > req->src.height)) {
+ pr_err("%s: src roi larger than boundary\n", __func__);
+ return -EINVAL;
+ }
+
+ if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) ||
+ ((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) {
+ pr_err("%s: dst roi larger than boundary\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* scaling range check */
+int mdp3_ppp_verify_scale(struct mdp_blit_req *req)
+{
+ u32 src_width, src_height, dst_width, dst_height;
+
+ src_width = req->src_rect.w;
+ src_height = req->src_rect.h;
+
+ if (req->flags & MDP_ROT_90) {
+ dst_width = req->dst_rect.h;
+ dst_height = req->dst_rect.w;
+ } else {
+ dst_width = req->dst_rect.w;
+ dst_height = req->dst_rect.h;
+ }
+
+ switch (req->dst.format) {
+ case MDP_Y_CRCB_H2V2:
+ case MDP_Y_CBCR_H2V2:
+ src_width = (src_width / 2) * 2;
+ src_height = (src_height / 2) * 2;
+ dst_width = (dst_width / 2) * 2;
+ dst_height = (dst_height / 2) * 2;
+ break;
+
+ case MDP_Y_CRCB_H2V1:
+ case MDP_Y_CBCR_H2V1:
+ case MDP_YCRYCB_H2V1:
+ src_width = (src_width / 2) * 2;
+ dst_width = (dst_width / 2) * 2;
+ break;
+
+ default:
+ break;
+ }
+
+ if (((MDP_SCALE_Q_FACTOR * dst_width) / src_width >
+ MDP_MAX_X_SCALE_FACTOR)
+ || ((MDP_SCALE_Q_FACTOR * dst_width) / src_width <
+ MDP_MIN_X_SCALE_FACTOR)) {
+ pr_err("%s: x req scale factor beyond capability\n", __func__);
+ return -EINVAL;
+ }
+
+ if (((MDP_SCALE_Q_FACTOR * dst_height) / src_height >
+ MDP_MAX_Y_SCALE_FACTOR)
+ || ((MDP_SCALE_Q_FACTOR * dst_height) / src_height <
+ MDP_MIN_Y_SCALE_FACTOR)) {
+ pr_err("%s: y req scale factor beyond capability\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* operation check */
+int mdp3_ppp_verify_op(struct mdp_blit_req *req)
+{
+ if (req->flags & MDP_DEINTERLACE) {
+ pr_err("\n%s(): deinterlace not supported", __func__);
+ return -EINVAL;
+ }
+
+ if (req->flags & MDP_SHARPENING) {
+ pr_err("\n%s(): sharpening not supported", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int mdp3_ppp_verify_req(struct mdp_blit_req *req)
+{
+ int rc;
+
+ if (req == NULL) {
+ pr_err("%s: req == null\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = mdp3_ppp_verify_fmt(req);
+ rc |= mdp3_ppp_verify_res(req);
+ rc |= mdp3_ppp_verify_scale(req);
+ rc |= mdp3_ppp_verify_op(req);
+
+ return rc;
+}
+
+int mdp3_ppp_pipe_wait(void)
+{
+ int ret = 1;
+ int wait;
+ unsigned long flag;
+
+ /*
+ * wait 5 secs for operation to complete before declaring
+ * the MDP hung
+ */
+ spin_lock_irqsave(&ppp_stat->ppp_lock, flag);
+ wait = ppp_stat->busy;
+ spin_unlock_irqrestore(&ppp_stat->ppp_lock, flag);
+
+ if (wait) {
+ ret = wait_for_completion_interruptible_timeout(
+ &ppp_stat->ppp_comp, 5 * HZ);
+ if (!ret)
+ pr_err("%s: Timed out waiting for the MDP.\n",
+ __func__);
+ }
+
+ return ret;
+}
+
+uint32_t mdp3_calc_tpval(struct ppp_img_desc *img, uint32_t old_tp)
+{
+ uint32_t tpVal;
+ uint8_t plane_tp;
+
+ tpVal = 0;
+ if ((img->color_fmt == MDP_RGB_565)
+ || (img->color_fmt == MDP_BGR_565)) {
+ /* transparent color conversion into 24 bpp */
+ plane_tp = (uint8_t) ((old_tp & 0xF800) >> 11);
+ tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 16;
+ plane_tp = (uint8_t) (old_tp & 0x1F);
+ tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 8;
+
+ plane_tp = (uint8_t) ((old_tp & 0x7E0) >> 5);
+ tpVal |= ((plane_tp << 2) | ((plane_tp & 0x30) >> 4));
+ } else {
+ /* 24bit RGB to RBG conversion */
+ tpVal = (old_tp & 0xFF00) >> 8;
+ tpVal |= (old_tp & 0xFF) << 8;
+ tpVal |= (old_tp & 0xFF0000);
+ }
+
+ return tpVal;
+}
+
+static void mdp3_ppp_intr_handler(int type, void *arg)
+{
+ spin_lock(&ppp_stat->ppp_lock);
+ ppp_stat->busy = false;
+ spin_unlock(&ppp_stat->ppp_lock);
+ complete(&ppp_stat->ppp_comp);
+ mdp3_irq_disable_nosync(type);
+}
+
+static int mdp3_ppp_callback_setup(void)
+{
+ int rc;
+ struct mdp3_intr_cb ppp_done_cb = {
+ .cb = mdp3_ppp_intr_handler,
+ .data = NULL,
+ };
+
+ rc = mdp3_set_intr_callback(MDP3_PPP_DONE, &ppp_done_cb);
+ return rc;
+}
+
+void mdp3_ppp_kickoff(void)
+{
+ unsigned long flag;
+ mdp3_irq_enable(MDP3_PPP_DONE);
+
+ init_completion(&ppp_stat->ppp_comp);
+
+ spin_lock_irqsave(&ppp_stat->ppp_lock, flag);
+ ppp_stat->busy = true;
+ spin_unlock_irqrestore(&ppp_stat->ppp_lock, flag);
+ ppp_enable();
+
+ mdp3_ppp_pipe_wait();
+}
+
+int mdp3_ppp_turnon(struct ppp_blit_op *blit_op, int on_off)
+{
+ unsigned long clk_rate = 0, dst_rate = 0, src_rate = 0;
+ int ab = 0;
+ int ib = 0;
+ if (on_off) {
+ dst_rate = blit_op->dst.roi.width * blit_op->dst.roi.height;
+ src_rate = blit_op->src.roi.width * blit_op->src.roi.height;
+ clk_rate = max(dst_rate, src_rate);
+ clk_rate = clk_rate * 36 * 12;
+
+ ab = blit_op->dst.roi.width * blit_op->dst.roi.height *
+ ppp_bpp(blit_op->dst.color_fmt) * 2 +
+ blit_op->src.roi.width * blit_op->src.roi.height *
+ ppp_bpp(blit_op->src.color_fmt);
+ ab = ab * 120;
+ ib = (ab * 3) / 2;
+ }
+ mdp3_clk_enable(on_off);
+ mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
+ return 0;
+}
+
+void mdp3_start_ppp(struct ppp_blit_op *blit_op)
+{
+ /* Wait for the pipe to clear */
+ do { } while (mdp3_ppp_pipe_wait() <= 0);
+ mutex_lock(&ppp_stat->config_mutex);
+ config_ppp_op_mode(blit_op);
+ mdp3_ppp_kickoff();
+ mutex_unlock(&ppp_stat->config_mutex);
+}
+
+static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
+ struct mdp_blit_req *req, struct mdp3_img_data *src_data,
+ struct mdp3_img_data *dst_data)
+{
+ unsigned long srcp0_start, srcp0_len, dst_start, dst_len;
+ uint32_t dst_width, dst_height;
+
+ srcp0_start = (unsigned long) src_data->addr;
+ srcp0_len = (unsigned long) src_data->len;
+ dst_start = (unsigned long) dst_data->addr;
+ dst_len = (unsigned long) dst_data->len;
+
+ blit_op->dst.prop.width = req->dst.width;
+ blit_op->dst.prop.height = req->dst.height;
+
+ blit_op->dst.color_fmt = req->dst.format;
+ blit_op->dst.p0 = (void *) dst_start;
+ blit_op->dst.p0 += req->dst.offset;
+
+ blit_op->dst.roi.x = req->dst_rect.x;
+ blit_op->dst.roi.y = req->dst_rect.y;
+ blit_op->dst.roi.width = req->dst_rect.w;
+ blit_op->dst.roi.height = req->dst_rect.h;
+
+ blit_op->src.roi.x = req->src_rect.x;
+ blit_op->src.roi.y = req->src_rect.y;
+ blit_op->src.roi.width = req->src_rect.w;
+ blit_op->src.roi.height = req->src_rect.h;
+
+ blit_op->src.prop.width = req->src.width;
+ blit_op->src.color_fmt = req->src.format;
+
+
+ blit_op->src.p0 = (void *) (srcp0_start + req->src.offset);
+ if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_ADRENO)
+ blit_op->src.p1 =
+ (void *) ((uint32_t) blit_op->src.p0 +
+ ALIGN((ALIGN(req->src.width, 32) *
+ ALIGN(req->src.height, 32)), 4096));
+ else
+ blit_op->src.p1 = (void *) ((uint32_t) blit_op->src.p0 +
+ req->src.width * req->src.height);
+
+ if (req->flags & MDP_IS_FG)
+ blit_op->mdp_op |= MDPOP_LAYER_IS_FG;
+
+ /* blending check */
+ if (req->transp_mask != MDP_TRANSP_NOP) {
+ blit_op->mdp_op |= MDPOP_TRANSP;
+ blit_op->blend.trans_color =
+ mdp3_calc_tpval(&blit_op->src, req->transp_mask);
+ } else {
+ blit_op->blend.trans_color = 0;
+ }
+
+ req->alpha &= 0xff;
+ if (req->alpha < MDP_ALPHA_NOP) {
+ blit_op->mdp_op |= MDPOP_ALPHAB;
+ blit_op->blend.const_alpha = req->alpha;
+ } else {
+ blit_op->blend.const_alpha = 0xff;
+ }
+
+ /* rotation check */
+ if (req->flags & MDP_FLIP_LR)
+ blit_op->mdp_op |= MDPOP_LR;
+ if (req->flags & MDP_FLIP_UD)
+ blit_op->mdp_op |= MDPOP_UD;
+ if (req->flags & MDP_ROT_90)
+ blit_op->mdp_op |= MDPOP_ROT90;
+ if (req->flags & MDP_DITHER)
+ blit_op->mdp_op |= MDPOP_DITHER;
+
+ if (req->flags & MDP_BLEND_FG_PREMULT)
+ blit_op->mdp_op |= MDPOP_FG_PM_ALPHA;
+
+ /* scale check */
+ if (req->flags & MDP_ROT_90) {
+ dst_width = req->dst_rect.h;
+ dst_height = req->dst_rect.w;
+ } else {
+ dst_width = req->dst_rect.w;
+ dst_height = req->dst_rect.h;
+ }
+
+ if ((blit_op->src.roi.width != dst_width) ||
+ (blit_op->src.roi.height != dst_height))
+ blit_op->mdp_op |= MDPOP_ASCALE;
+
+ if (req->flags & MDP_BLUR)
+ blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR;
+}
+
+static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op,
+ struct mdp_blit_req *req)
+{
+ int dst_h, src_w, i;
+ uint32_t mdp_op = blit_op->mdp_op;
+
+ src_w = req->src_rect.w;
+ dst_h = blit_op->dst.roi.height;
+ /* bg tile fetching HW workaround */
+ for (i = 0; i < (req->dst_rect.h / 16); i++) {
+ /* this tile size */
+ blit_op->dst.roi.height = 16;
+ blit_op->src.roi.width =
+ (16 * req->src_rect.w) / req->dst_rect.h;
+
+ /* if it's out of scale range... */
+ if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ blit_op->src.roi.width) > MDP_MAX_X_SCALE_FACTOR)
+ blit_op->src.roi.width =
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ MDP_MAX_X_SCALE_FACTOR;
+ else if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ blit_op->src.roi.width) < MDP_MIN_X_SCALE_FACTOR)
+ blit_op->src.roi.width =
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ MDP_MIN_X_SCALE_FACTOR;
+
+ mdp3_start_ppp(blit_op);
+
+ /* next tile location */
+ blit_op->dst.roi.y += 16;
+ blit_op->src.roi.x += blit_op->src.roi.width;
+
+ /* this is for a remainder update */
+ dst_h -= 16;
+ src_w -= blit_op->src.roi.width;
+ /* restore mdp_op since MDPOP_ASCALE have been cleared */
+ blit_op->mdp_op = mdp_op;
+ }
+
+ if ((dst_h < 0) || (src_w < 0))
+ pr_err
+ ("msm_fb: mdp_blt_ex() unexpected result! line:%d\n",
+ __LINE__);
+
+ /* remainder update */
+ if ((dst_h > 0) && (src_w > 0)) {
+ u32 tmp_v;
+
+ blit_op->dst.roi.height = dst_h;
+ blit_op->src.roi.width = src_w;
+
+ if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ blit_op->src.roi.width) > MDP_MAX_X_SCALE_FACTOR) {
+ tmp_v =
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ MDP_MAX_X_SCALE_FACTOR +
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) %
+ MDP_MAX_X_SCALE_FACTOR ? 1 : 0;
+
+ /* move x location as roi width gets bigger */
+ blit_op->src.roi.x -= tmp_v - blit_op->src.roi.width;
+ blit_op->src.roi.width = tmp_v;
+ } else if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ blit_op->src.roi.width) < MDP_MIN_X_SCALE_FACTOR) {
+ tmp_v =
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+ MDP_MIN_X_SCALE_FACTOR +
+ (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) %
+ MDP_MIN_X_SCALE_FACTOR ? 1 : 0;
+
+ /*
+ * we don't move x location for continuity of
+ * source image
+ */
+ blit_op->src.roi.width = tmp_v;
+ }
+
+
+ mdp3_start_ppp(blit_op);
+ }
+}
+
+static int mdp3_ppp_blit_addr(struct msm_fb_data_type *mfd,
+ struct mdp_blit_req *req, struct mdp3_img_data *src_data,
+ struct mdp3_img_data *dst_data)
+{
+ struct ppp_blit_op blit_op;
+
+ memset(&blit_op, 0, sizeof(blit_op));
+
+ if (req->dst.format == MDP_FB_FORMAT)
+ req->dst.format = mfd->fb_imgType;
+ if (req->src.format == MDP_FB_FORMAT)
+ req->src.format = mfd->fb_imgType;
+
+ if (mdp3_ppp_verify_req(req)) {
+ pr_err("%s: invalid image!\n", __func__);
+ return -EINVAL;
+ }
+
+ mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+
+ mdp3_ppp_turnon(&blit_op, 1);
+
+ if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
+ (req->src.format == MDP_ARGB_8888) ||
+ (req->src.format == MDP_BGRA_8888) ||
+ (req->src.format == MDP_RGBA_8888)) &&
+ (blit_op.mdp_op & MDPOP_ROT90) && (req->dst_rect.w <= 16)) {
+ mdp3_ppp_tile_workaround(&blit_op, req);
+ } else {
+ mdp3_start_ppp(&blit_op);
+ }
+
+ /* MDP cmd block disable */
+ mdp3_ppp_turnon(&blit_op, 0);
+
+ return 0;
+}
+
+static int mdp3_ppp_blit(struct msm_fb_data_type *mfd, struct mdp_blit_req *req)
+{
+ struct mdp3_img_data src_data;
+ struct mdp3_img_data dst_data;
+ int rc;
+ mdp3_ppp_iommu_attach();
+
+ mdp3_ppp_get_img(&req->src, req, &src_data);
+ if (src_data.len == 0) {
+ pr_err("mdp_ppp: couldn't retrieve src img from mem\n");
+ return -EINVAL;
+ }
+
+ mdp3_ppp_get_img(&req->dst, req, &dst_data);
+ if (dst_data.len == 0) {
+ mdp3_put_img(&src_data);
+ pr_err("mdp_ppp: couldn't retrieve dest img from mem\n");
+ return -EINVAL;
+ }
+
+ rc = mdp3_ppp_blit_addr(mfd, req, &src_data, &dst_data);
+ mdp3_put_img(&src_data);
+ mdp3_put_img(&dst_data);
+ mdp3_ppp_iommu_dettach();
+ return rc;
+}
+
+static int mdp3_ppp_blit_workaround(struct msm_fb_data_type *mfd,
+ struct mdp_blit_req *req, unsigned int remainder)
+{
+ int ret;
+ struct mdp_blit_req splitreq;
+ int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1;
+ int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1;
+
+ /* make new request as provide by user */
+ splitreq = *req;
+
+ /* break dest roi at width*/
+ d_y_0 = d_y_1 = req->dst_rect.y;
+ d_h_0 = d_h_1 = req->dst_rect.h;
+ d_x_0 = req->dst_rect.x;
+
+ if (remainder == 14 || remainder == 6)
+ d_w_1 = req->dst_rect.w / 2;
+ else
+ d_w_1 = (req->dst_rect.w - 1) / 2 - 1;
+
+ d_w_0 = req->dst_rect.w - d_w_1;
+ d_x_1 = d_x_0 + d_w_0;
+ /* blit first region */
+ if (((splitreq.flags & 0x07) == 0x07) ||
+ ((splitreq.flags & 0x07) == 0x05) ||
+ ((splitreq.flags & 0x07) == 0x02) ||
+ ((splitreq.flags & 0x07) == 0x0)) {
+
+ if (splitreq.flags & MDP_ROT_90) {
+ s_x_0 = s_x_1 = req->src_rect.x;
+ s_w_0 = s_w_1 = req->src_rect.w;
+ s_y_0 = req->src_rect.y;
+ s_h_1 = (req->src_rect.h * d_w_1) /
+ req->dst_rect.w;
+ s_h_0 = req->src_rect.h - s_h_1;
+ s_y_1 = s_y_0 + s_h_0;
+ if (d_w_1 >= 8 * s_h_1) {
+ s_h_1++;
+ s_y_1--;
+ }
+ } else {
+ s_y_0 = s_y_1 = req->src_rect.y;
+ s_h_0 = s_h_1 = req->src_rect.h;
+ s_x_0 = req->src_rect.x;
+ s_w_1 = (req->src_rect.w * d_w_1) /
+ req->dst_rect.w;
+ s_w_0 = req->src_rect.w - s_w_1;
+ s_x_1 = s_x_0 + s_w_0;
+ if (d_w_1 >= 8 * s_w_1) {
+ s_w_1++;
+ s_x_1--;
+ }
+ }
+
+ splitreq.src_rect.h = s_h_0;
+ splitreq.src_rect.y = s_y_0;
+ splitreq.dst_rect.h = d_h_0;
+ splitreq.dst_rect.y = d_y_0;
+ splitreq.src_rect.x = s_x_0;
+ splitreq.src_rect.w = s_w_0;
+ splitreq.dst_rect.x = d_x_0;
+ splitreq.dst_rect.w = d_w_0;
+ } else {
+ if (splitreq.flags & MDP_ROT_90) {
+ s_x_0 = s_x_1 = req->src_rect.x;
+ s_w_0 = s_w_1 = req->src_rect.w;
+ s_y_0 = req->src_rect.y;
+ s_h_1 = (req->src_rect.h * d_w_0) /
+ req->dst_rect.w;
+ s_h_0 = req->src_rect.h - s_h_1;
+ s_y_1 = s_y_0 + s_h_0;
+ if (d_w_0 >= 8 * s_h_1) {
+ s_h_1++;
+ s_y_1--;
+ }
+ } else {
+ s_y_0 = s_y_1 = req->src_rect.y;
+ s_h_0 = s_h_1 = req->src_rect.h;
+ s_x_0 = req->src_rect.x;
+ s_w_1 = (req->src_rect.w * d_w_0) /
+ req->dst_rect.w;
+ s_w_0 = req->src_rect.w - s_w_1;
+ s_x_1 = s_x_0 + s_w_0;
+ if (d_w_0 >= 8 * s_w_1) {
+ s_w_1++;
+ s_x_1--;
+ }
+ }
+ splitreq.src_rect.h = s_h_0;
+ splitreq.src_rect.y = s_y_0;
+ splitreq.dst_rect.h = d_h_1;
+ splitreq.dst_rect.y = d_y_1;
+ splitreq.src_rect.x = s_x_0;
+ splitreq.src_rect.w = s_w_0;
+ splitreq.dst_rect.x = d_x_1;
+ splitreq.dst_rect.w = d_w_1;
+ }
+
+ /* No need to split in height */
+ ret = mdp3_ppp_blit(mfd, &splitreq);
+
+ if (ret)
+ return ret;
+ /* blit second region */
+ if (((splitreq.flags & 0x07) == 0x07) ||
+ ((splitreq.flags & 0x07) == 0x05) ||
+ ((splitreq.flags & 0x07) == 0x02) ||
+ ((splitreq.flags & 0x07) == 0x0)) {
+ splitreq.src_rect.h = s_h_1;
+ splitreq.src_rect.y = s_y_1;
+ splitreq.dst_rect.h = d_h_1;
+ splitreq.dst_rect.y = d_y_1;
+ splitreq.src_rect.x = s_x_1;
+ splitreq.src_rect.w = s_w_1;
+ splitreq.dst_rect.x = d_x_1;
+ splitreq.dst_rect.w = d_w_1;
+ } else {
+ splitreq.src_rect.h = s_h_1;
+ splitreq.src_rect.y = s_y_1;
+ splitreq.dst_rect.h = d_h_0;
+ splitreq.dst_rect.y = d_y_0;
+ splitreq.src_rect.x = s_x_1;
+ splitreq.src_rect.w = s_w_1;
+ splitreq.dst_rect.x = d_x_0;
+ splitreq.dst_rect.w = d_w_0;
+ }
+
+ /* No need to split in height ... just width */
+ return mdp3_ppp_blit(mfd, &splitreq);
+}
+
+int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
+ struct mdp_blit_req *req)
+{
+ int ret;
+ unsigned int remainder = 0, is_bpp_4 = 0;
+
+ if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) {
+ pr_err("mdp_ppp: src img of zero size!\n");
+ return -EINVAL;
+ }
+ if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0))
+ return 0;
+
+ if (req->flags & MDP_ROT_90) {
+ if (((req->dst_rect.h == 1) && ((req->src_rect.w != 1) ||
+ (req->dst_rect.w != req->src_rect.h))) ||
+ ((req->dst_rect.w == 1) && ((req->src_rect.h != 1) ||
+ (req->dst_rect.h != req->src_rect.w)))) {
+ pr_err("mdp_ppp: error scaling when size is 1!\n");
+ return -EINVAL;
+ }
+ } else {
+ if (((req->dst_rect.w == 1) && ((req->src_rect.w != 1) ||
+ (req->dst_rect.h != req->src_rect.h))) ||
+ ((req->dst_rect.h == 1) && ((req->src_rect.h != 1) ||
+ (req->dst_rect.w != req->src_rect.w)))) {
+ pr_err("mdp_ppp: error scaling when size is 1!\n");
+ return -EINVAL;
+ }
+ }
+
+ /* MDP width split workaround */
+ remainder = (req->dst_rect.w) % 16;
+ ret = ppp_get_bpp(req->dst.format, mfd->fb_imgType);
+ if (ret <= 0) {
+ pr_err("mdp_ppp: incorrect bpp!\n");
+ return -EINVAL;
+ }
+ is_bpp_4 = (ret == 4) ? 1 : 0;
+
+ if ((is_bpp_4 && (remainder == 6 || remainder == 14)))
+ ret = mdp3_ppp_blit_workaround(mfd, req, remainder);
+ else
+ ret = mdp3_ppp_blit(mfd, req);
+
+ return ret;
+}
+
+int mdp3_ppp_res_init(void)
+{
+ ppp_stat = kmalloc(sizeof(struct ppp_status), GFP_KERNEL);
+ spin_lock_init(&ppp_stat->ppp_lock);
+ mutex_init(&ppp_stat->config_mutex);
+ ppp_stat->busy = false;
+ mdp3_ppp_callback_setup();
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdp3_ppp.h b/drivers/video/msm/mdss/mdp3_ppp.h
new file mode 100644
index 0000000..afac419
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp.h
@@ -0,0 +1,413 @@
+/* Copyright (c) 2007, 2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * 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 MDP3_PPP_H
+#define MDP3_PPP_H
+#include "mdp3.h"
+#include "mdss_fb.h"
+
+#define PPP_WRITEL(val, off) MDP3_REG_WRITE(off, val)
+
+#define MAX_BLIT_REQ 256
+#define PPP_UPSCALE_MAX 64
+#define PPP_BLUR_SCALE_MAX 128
+#define PPP_LUT_MAX 256
+
+/* MDP PPP Operations */
+#define MDPOP_NOP 0
+#define MDPOP_LR BIT(0) /* left to right flip */
+#define MDPOP_UD BIT(1) /* up and down flip */
+#define MDPOP_ROT90 BIT(2) /* rotate image to 90 degree */
+#define MDPOP_ROT180 (MDPOP_UD|MDPOP_LR)
+#define MDPOP_ROT270 (MDPOP_ROT90|MDPOP_UD|MDPOP_LR)
+#define MDPOP_ASCALE BIT(7)
+#define MDPOP_ALPHAB BIT(8) /* enable alpha blending */
+#define MDPOP_TRANSP BIT(9) /* enable transparency */
+#define MDPOP_DITHER BIT(10) /* enable dither */
+#define MDPOP_SHARPENING BIT(11) /* enable sharpening */
+#define MDPOP_BLUR BIT(12) /* enable blur */
+#define MDPOP_FG_PM_ALPHA BIT(13)
+#define MDPOP_LAYER_IS_FG BIT(14)
+
+#define MDPOP_ROTATION (MDPOP_ROT90|MDPOP_LR|MDPOP_UD)
+
+#define PPP_OP_CONVERT_YCBCR2RGB BIT(2)
+#define PPP_OP_CONVERT_ON BIT(3)
+#define PPP_OP_SCALE_X_ON BIT(0)
+#define PPP_OP_SCALE_Y_ON BIT(1)
+#define PPP_OP_ROT_ON BIT(8)
+#define PPP_OP_ROT_90 BIT(9)
+#define PPP_OP_FLIP_LR BIT(10)
+#define PPP_OP_FLIP_UD BIT(11)
+#define PPP_OP_BLEND_ON BIT(12)
+#define PPP_OP_BLEND_CONSTANT_ALPHA BIT(14)
+#define PPP_OP_DITHER_EN BIT(16)
+#define PPP_BLEND_CALPHA_TRNASP BIT(24)
+
+#define PPP_OP_BLEND_SRCPIXEL_ALPHA 0
+#define PPP_OP_BLEND_ALPHA_BLEND_NORMAL 0
+#define PPP_OP_BLEND_ALPHA_BLEND_REVERSE BIT(15)
+
+#define PPP_BLEND_BG_USE_ALPHA_SEL (1 << 0)
+#define PPP_BLEND_BG_ALPHA_REVERSE (1 << 3)
+#define PPP_BLEND_BG_SRCPIXEL_ALPHA (0 << 1)
+#define PPP_BLEND_BG_DSTPIXEL_ALPHA (1 << 1)
+#define PPP_BLEND_BG_CONSTANT_ALPHA (2 << 1)
+#define PPP_BLEND_BG_CONST_ALPHA_VAL(x) ((x) << 24)
+#define PPP_OP_BG_CHROMA_H2V1 BIT(25)
+
+#define CLR_G 0x0
+#define CLR_B 0x1
+#define CLR_R 0x2
+#define CLR_ALPHA 0x3
+
+#define CLR_Y CLR_G
+#define CLR_CB CLR_B
+#define CLR_CR CLR_R
+
+/* from lsb to msb */
+#define PPP_GET_PACK_PATTERN(a, x, y, z, bit) \
+ (((a)<<(bit*3))|((x)<<(bit*2))|((y)<<bit)|(z))
+
+/* Frame unpacking */
+#define PPP_C0G_8BITS (BIT(1)|BIT(0))
+#define PPP_C1B_8BITS (BIT(3)|BIT(2))
+#define PPP_C2R_8BITS (BIT(5)|BIT(4))
+#define PPP_C3A_8BITS (BIT(7)|BIT(6))
+
+#define PPP_C0G_6BITS BIT(1)
+#define PPP_C1B_6BITS BIT(3)
+#define PPP_C2R_6BITS BIT(5)
+
+#define PPP_C0G_5BITS BIT(0)
+#define PPP_C1B_5BITS BIT(2)
+#define PPP_C2R_5BITS BIT(4)
+
+#define PPP_SRC_C3_ALPHA_EN BIT(8)
+
+#define PPP_SRC_BPP_INTERLVD_1BYTES 0
+#define PPP_SRC_BPP_INTERLVD_2BYTES BIT(9)
+#define PPP_SRC_BPP_INTERLVD_3BYTES BIT(10)
+#define PPP_SRC_BPP_INTERLVD_4BYTES (BIT(10)|BIT(9))
+
+#define PPP_SRC_BPP_ROI_ODD_X BIT(11)
+#define PPP_SRC_BPP_ROI_ODD_Y BIT(12)
+#define PPP_SRC_INTERLVD_2COMPONENTS BIT(13)
+#define PPP_SRC_INTERLVD_3COMPONENTS BIT(14)
+#define PPP_SRC_INTERLVD_4COMPONENTS (BIT(14)|BIT(13))
+
+#define PPP_SRC_UNPACK_TIGHT BIT(17)
+#define PPP_SRC_UNPACK_LOOSE 0
+#define PPP_SRC_UNPACK_ALIGN_LSB 0
+#define PPP_SRC_UNPACK_ALIGN_MSB BIT(18)
+
+#define PPP_SRC_FETCH_PLANES_INTERLVD 0
+#define PPP_SRC_FETCH_PLANES_PSEUDOPLNR BIT(20)
+
+#define PPP_OP_SRC_CHROMA_H2V1 BIT(18)
+#define PPP_OP_SRC_CHROMA_H1V2 BIT(19)
+#define PPP_OP_SRC_CHROMA_420 (BIT(18)|BIT(19))
+#define PPP_OP_SRC_CHROMA_OFFSITE BIT(20)
+
+#define PPP_DST_PACKET_CNT_INTERLVD_2ELEM BIT(9)
+#define PPP_DST_PACKET_CNT_INTERLVD_3ELEM BIT(10)
+#define PPP_DST_PACKET_CNT_INTERLVD_4ELEM (BIT(10)|BIT(9))
+#define PPP_DST_PACKET_CNT_INTERLVD_6ELEM (BIT(11)|BIT(9))
+
+#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6))
+#define PPP_DST_C3ALPHA_EN BIT(8)
+
+#define PPP_DST_PACK_LOOSE 0
+#define PPP_DST_PACK_TIGHT BIT(13)
+#define PPP_DST_PACK_ALIGN_LSB 0
+#define PPP_DST_PACK_ALIGN_MSB BIT(14)
+
+#define PPP_DST_OUT_SEL_AXI 0
+#define PPP_DST_OUT_SEL_MDDI BIT(15)
+
+#define PPP_DST_BPP_2BYTES BIT(16)
+#define PPP_DST_BPP_3BYTES BIT(17)
+#define PPP_DST_BPP_4BYTES (BIT(17)|BIT(16))
+
+#define PPP_DST_PLANE_INTERLVD 0
+#define PPP_DST_PLANE_PLANAR BIT(18)
+#define PPP_DST_PLANE_PSEUDOPLN BIT(19)
+
+#define PPP_OP_DST_CHROMA_H2V1 BIT(21)
+#define PPP_OP_DST_CHROMA_420 (BIT(21)|BIT(22))
+#define PPP_OP_COLOR_SPACE_YCBCR BIT(17)
+
+#define MDP_SCALE_Q_FACTOR 512
+#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
+#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
+#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
+#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
+
+#define MDP_TOP_LUMA 16
+#define MDP_TOP_CHROMA 0
+#define MDP_BOTTOM_LUMA 19
+#define MDP_BOTTOM_CHROMA 3
+#define MDP_LEFT_LUMA 22
+#define MDP_LEFT_CHROMA 6
+#define MDP_RIGHT_LUMA 25
+#define MDP_RIGHT_CHROMA 9
+
+#define MDP_RGB_565_SRC_REG (PPP_C2R_5BITS | PPP_C0G_6BITS | \
+ PPP_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+ PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+ PPP_SRC_UNPACK_ALIGN_LSB | \
+ PPP_SRC_FETCH_PLANES_INTERLVD)
+
+#define MDP_RGB_888_SRC_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES | \
+ PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+ PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_INTERLVD)
+
+#define MDP_RGBX_8888_SRC_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_C3A_8BITS | \
+ PPP_SRC_C3_ALPHA_EN | PPP_SRC_BPP_INTERLVD_4BYTES | \
+ PPP_SRC_INTERLVD_4COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+ PPP_SRC_UNPACK_ALIGN_LSB | \
+ PPP_SRC_FETCH_PLANES_INTERLVD)
+
+#define MDP_Y_CBCR_H2V2_SRC_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+ PPP_SRC_INTERLVD_2COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+ PPP_SRC_UNPACK_ALIGN_LSB | \
+ PPP_SRC_FETCH_PLANES_PSEUDOPLNR)
+
+#define MDP_YCRYCB_H2V1_SRC_REG (PPP_C2R_8BITS | \
+ PPP_C0G_8BITS | PPP_C1B_8BITS | \
+ PPP_C3A_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+ PPP_SRC_INTERLVD_4COMPONENTS | \
+ PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB)
+
+#define MDP_Y_CRCB_H2V1_SRC_REG (PPP_C2R_8BITS | \
+ PPP_C0G_8BITS | PPP_C1B_8BITS | \
+ PPP_C3A_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+ PPP_SRC_INTERLVD_2COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+ PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR)
+
+#define MDP_RGB_565_DST_REG (PPP_C0G_6BITS | \
+ PPP_C1B_5BITS | PPP_C2R_5BITS | \
+ PPP_DST_PACKET_CNT_INTERLVD_3ELEM | \
+ PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES | \
+ PPP_DST_PLANE_INTERLVD)
+
+#define MDP_RGB_888_DST_REG (PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_C2R_8BITS | \
+ PPP_DST_PACKET_CNT_INTERLVD_3ELEM | PPP_DST_PACK_TIGHT | \
+ PPP_DST_PACK_ALIGN_LSB | PPP_DST_OUT_SEL_AXI | \
+ PPP_DST_BPP_3BYTES | PPP_DST_PLANE_INTERLVD)
+
+#define MDP_RGBX_8888_DST_REG (PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_C2R_8BITS | PPP_C3A_8BITS | \
+ PPP_DST_C3ALPHA_EN | PPP_DST_PACKET_CNT_INTERLVD_4ELEM | \
+ PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_4BYTES | \
+ PPP_DST_PLANE_INTERLVD)
+
+#define MDP_Y_CBCR_H2V2_DST_REG (PPP_C2R_8BITS | \
+ PPP_C0G_8BITS | PPP_C1B_8BITS | PPP_C3A_8BITS | \
+ PPP_DST_PACKET_CNT_INTERLVD_2ELEM | \
+ PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES)
+
+#define MDP_YCRYCB_H2V1_DST_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+ PPP_C1B_8BITS | PPP_C3A_8BITS | PPP_DST_PACKET_CNT_INTERLVD_4ELEM | \
+ PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES | \
+ PPP_DST_PLANE_INTERLVD)
+
+#define MDP_Y_CRCB_H2V1_DST_REG (PPP_C2R_8BITS | \
+ PPP_C0G_8BITS | PPP_C1B_8BITS | PPP_C3A_8BITS | \
+ PPP_DST_PACKET_CNT_INTERLVD_2ELEM | PPP_DST_PACK_TIGHT | \
+ PPP_DST_PACK_ALIGN_LSB | PPP_DST_OUT_SEL_AXI | \
+ PPP_DST_BPP_2BYTES)
+
+/* LUT */
+#define MDP_LUT_C0_EN BIT(5)
+#define MDP_LUT_C1_EN BIT(6)
+#define MDP_LUT_C2_EN BIT(7)
+
+/* Dither */
+#define MDP_OP_DITHER_EN BIT(16)
+
+/* Rotator */
+#define MDP_OP_ROT_ON BIT(8)
+#define MDP_OP_ROT_90 BIT(9)
+#define MDP_OP_FLIP_LR BIT(10)
+#define MDP_OP_FLIP_UD BIT(11)
+
+/* Blend */
+#define MDP_OP_BLEND_EN BIT(12)
+#define MDP_OP_BLEND_EQ_SEL BIT(15)
+#define MDP_OP_BLEND_TRANSP_EN BIT(24)
+#define MDP_BLEND_MASK (MDP_OP_BLEND_EN | MDP_OP_BLEND_EQ_SEL | \
+ MDP_OP_BLEND_TRANSP_EN | BIT(14) | BIT(13))
+
+#define MDP_BLEND_ALPHA_SEL 13
+#define MDP_BLEND_ALPHA_MASK 0x3
+#define MDP_BLEND_CONST_ALPHA 24
+#define MDP_BLEND_TRASP_COL_MASK 0xFFFFFF
+
+/* CSC Matrix */
+#define MDP_CSC_RGB2YUV 0
+#define MDP_CSC_YUV2RGB 1
+
+#define MDP_CSC_SIZE 9
+#define MDP_BV_SIZE 3
+#define MDP_LV_SIZE 4
+
+enum ppp_lut_type {
+ LUT_PRE_TABLE = 0,
+ LUT_POST_TABLE,
+};
+
+enum ppp_csc_matrix {
+ CSC_PRIMARY_MATRIX = 0,
+ CSC_SECONDARY_MATRIX,
+};
+
+/* scale tables */
+enum {
+ PPP_DOWNSCALE_PT2TOPT4,
+ PPP_DOWNSCALE_PT4TOPT6,
+ PPP_DOWNSCALE_PT6TOPT8,
+ PPP_DOWNSCALE_PT8TOPT1,
+ PPP_DOWNSCALE_MAX,
+};
+
+struct ppp_table {
+ uint32_t reg;
+ uint32_t val;
+};
+
+struct ppp_csc_table {
+ int direction; /* MDP_CCS_RGB2YUV or YUV2RGB */
+ uint16_t fwd_matrix[MDP_CCS_SIZE]; /* 3x3 color coefficients */
+ uint16_t rev_matrix[MDP_CCS_SIZE]; /* 3x3 color coefficients */
+ uint16_t bv[MDP_BV_SIZE]; /* 1x3 bias vector */
+ uint16_t lv[MDP_LV_SIZE]; /* 1x3 limit vector */
+};
+
+struct ppp_blend {
+ int const_alpha;
+ int trans_color; /*color keying*/
+};
+
+struct ppp_img_prop {
+ int32_t x;
+ int32_t y;
+ uint32_t width;
+ uint32_t height;
+};
+
+struct ppp_img_desc {
+ struct ppp_img_prop prop;
+ struct ppp_img_prop roi;
+ int color_fmt;
+ void *p0; /* plane 0 */
+ void *p1;
+ void *p3;
+ int stride0;
+ int stride1;
+ int stride2;
+};
+
+struct ppp_blit_op {
+ struct ppp_img_desc src;
+ struct ppp_img_desc dst;
+ struct ppp_img_desc bg;
+ struct ppp_blend blend;
+ uint32_t mdp_op; /* Operations */
+};
+
+struct ppp_edge_rep {
+ uint32_t dst_roi_width;
+ uint32_t dst_roi_height;
+ uint32_t is_scale_enabled;
+
+ /*
+ * positions of the luma pixel(relative to the image ) required for
+ * scaling the ROI
+ */
+ int32_t luma_interp_point_left;
+ int32_t luma_interp_point_right;
+ int32_t luma_interp_point_top;
+ int32_t luma_interp_point_bottom;
+
+ /*
+ * positions of the chroma pixel(relative to the image ) required for
+ * interpolating a chroma value at all required luma positions
+ */
+ int32_t chroma_interp_point_left;
+ int32_t chroma_interp_point_right;
+ int32_t chroma_interp_point_top;
+ int32_t chroma_interp_point_bottom;
+
+ /*
+ * a rectangular region within the chroma plane of the "image".
+ * Chroma pixels falling inside of this rectangle belongs to the ROI
+ */
+ int32_t chroma_bound_left;
+ int32_t chroma_bound_right;
+ int32_t chroma_bound_top;
+ int32_t chroma_bound_bottom;
+
+ /*
+ * number of chroma pixels to replicate on the left, right,
+ * top and bottom edge of the ROI.
+ */
+ int32_t chroma_repeat_left;
+ int32_t chroma_repeat_right;
+ int32_t chroma_repeat_top;
+ int32_t chroma_repeat_bottom;
+
+ /*
+ * number of luma pixels to replicate on the left, right,
+ * top and bottom edge of the ROI.
+ */
+ int32_t luma_repeat_left;
+ int32_t luma_repeat_right;
+ int32_t luma_repeat_top;
+ int32_t luma_repeat_bottom;
+};
+
+/* func for ppp register values */
+uint32_t ppp_bpp(uint32_t type);
+uint32_t ppp_src_config(uint32_t type);
+uint32_t ppp_out_config(uint32_t type);
+uint32_t ppp_pack_pattern(uint32_t type);
+uint32_t ppp_dst_op_reg(uint32_t type);
+uint32_t ppp_src_op_reg(uint32_t type);
+bool ppp_per_p_alpha(uint32_t type);
+bool ppp_multi_plane(uint32_t type);
+uint32_t *ppp_default_pre_lut(void);
+uint32_t *ppp_default_post_lut(void);
+struct ppp_csc_table *ppp_csc_rgb2yuv(void);
+struct ppp_csc_table *ppp_csc_table2(void);
+void ppp_load_up_lut(void);
+void ppp_load_gaussian_lut(void);
+void ppp_load_x_scale_table(int idx);
+void ppp_load_y_scale_table(int idx);
+
+int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
+ struct mdp_blit_req *req);
+int mdp3_ppp_res_init(void);
+int mdp3_ppp_init(void);
+int config_ppp_op_mode(struct ppp_blit_op *blit_op);
+void ppp_enable(void);
+
+#endif
diff --git a/drivers/video/msm/mdss/mdp3_ppp_data.c b/drivers/video/msm/mdss/mdp3_ppp_data.c
new file mode 100644
index 0000000..d68faad
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp_data.c
@@ -0,0 +1,1572 @@
+/* Copyright (c) 2007, 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * 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/types.h>
+
+#include "mdss_fb.h"
+#include "mdp3_ppp.h"
+
+/* bg_config_lut not needed since it is same as src */
+const uint32_t src_cfg_lut[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = MDP_RGB_565_SRC_REG,
+ [MDP_BGR_565] = MDP_RGB_565_SRC_REG,
+ [MDP_RGB_888] = MDP_RGB_888_SRC_REG,
+ [MDP_BGR_888] = MDP_RGB_888_SRC_REG,
+ [MDP_BGRA_8888] = MDP_RGBX_8888_SRC_REG,
+ [MDP_RGBA_8888] = MDP_RGBX_8888_SRC_REG,
+ [MDP_ARGB_8888] = MDP_RGBX_8888_SRC_REG,
+ [MDP_XRGB_8888] = MDP_RGBX_8888_SRC_REG,
+ [MDP_RGBX_8888] = MDP_RGBX_8888_SRC_REG,
+ [MDP_Y_CRCB_H2V2] = MDP_Y_CBCR_H2V2_SRC_REG,
+ [MDP_Y_CBCR_H2V2] = MDP_Y_CBCR_H2V2_SRC_REG,
+ [MDP_Y_CBCR_H2V2_ADRENO] = MDP_Y_CBCR_H2V2_SRC_REG,
+ [MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_SRC_REG,
+ [MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
+ [MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
+};
+
+const uint32_t out_cfg_lut[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = MDP_RGB_565_DST_REG,
+ [MDP_BGR_565] = MDP_RGB_565_DST_REG,
+ [MDP_RGB_888] = MDP_RGB_888_DST_REG,
+ [MDP_BGR_888] = MDP_RGB_888_DST_REG,
+ [MDP_BGRA_8888] = MDP_RGBX_8888_DST_REG,
+ [MDP_RGBA_8888] = MDP_RGBX_8888_DST_REG,
+ [MDP_ARGB_8888] = MDP_RGBX_8888_DST_REG,
+ [MDP_XRGB_8888] = MDP_RGBX_8888_DST_REG,
+ [MDP_RGBX_8888] = MDP_RGBX_8888_DST_REG,
+ [MDP_Y_CRCB_H2V2] = MDP_Y_CBCR_H2V2_DST_REG,
+ [MDP_Y_CBCR_H2V2] = MDP_Y_CBCR_H2V2_DST_REG,
+ [MDP_Y_CBCR_H2V2_ADRENO] = MDP_Y_CBCR_H2V2_DST_REG,
+ [MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_DST_REG,
+ [MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
+ [MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
+};
+
+const uint32_t pack_patt_lut[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+ [MDP_BGR_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+ [MDP_RGB_888] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
+ [MDP_BGR_888] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+ [MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+ CLR_G, CLR_B, 8),
+ [MDP_RGBA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+ CLR_G, CLR_B, 8),
+ [MDP_ARGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+ CLR_G, CLR_B, 8),
+ [MDP_XRGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+ CLR_G, CLR_B, 8),
+ [MDP_RGBX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+ CLR_G, CLR_B, 8),
+ [MDP_Y_CRCB_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
+ [MDP_Y_CBCR_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
+ [MDP_Y_CBCR_H2V2_ADRENO] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB,
+ CLR_CR, 8),
+ [MDP_YCRYCB_H2V1] = PPP_GET_PACK_PATTERN(CLR_Y,
+ CLR_CR, CLR_Y, CLR_CB, 8),
+ [MDP_Y_CBCR_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
+ [MDP_Y_CRCB_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
+};
+
+const uint32_t dst_op_reg[MDP_IMGTYPE_LIMIT] = {
+ [MDP_Y_CRCB_H2V2] = PPP_OP_DST_CHROMA_420,
+ [MDP_Y_CBCR_H2V2] = PPP_OP_DST_CHROMA_420,
+ [MDP_Y_CBCR_H2V1] = PPP_OP_DST_CHROMA_H2V1,
+ [MDP_Y_CRCB_H2V1] = PPP_OP_DST_CHROMA_H2V1,
+ [MDP_YCRYCB_H2V1] = PPP_OP_DST_CHROMA_H2V1,
+};
+
+const uint32_t src_op_reg[MDP_IMGTYPE_LIMIT] = {
+ [MDP_Y_CRCB_H2V2] = PPP_OP_SRC_CHROMA_420 | PPP_OP_COLOR_SPACE_YCBCR,
+ [MDP_Y_CBCR_H2V2] = PPP_OP_SRC_CHROMA_420 | PPP_OP_COLOR_SPACE_YCBCR,
+ [MDP_Y_CBCR_H2V2_ADRENO] = PPP_OP_SRC_CHROMA_420 |
+ PPP_OP_COLOR_SPACE_YCBCR,
+ [MDP_Y_CBCR_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
+ [MDP_Y_CRCB_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
+ [MDP_YCRYCB_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
+};
+
+const uint32_t bytes_per_pixel[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = 2,
+ [MDP_BGR_565] = 2,
+ [MDP_RGB_888] = 3,
+ [MDP_BGR_888] = 3,
+ [MDP_XRGB_8888] = 4,
+ [MDP_ARGB_8888] = 4,
+ [MDP_RGBA_8888] = 4,
+ [MDP_BGRA_8888] = 4,
+ [MDP_RGBX_8888] = 4,
+ [MDP_Y_CBCR_H2V1] = 1,
+ [MDP_Y_CBCR_H2V2] = 1,
+ [MDP_Y_CBCR_H2V2_ADRENO] = 1,
+ [MDP_Y_CRCB_H2V1] = 1,
+ [MDP_Y_CRCB_H2V2] = 1,
+ [MDP_YCRYCB_H2V1] = 2,
+};
+
+const bool per_pixel_alpha[MDP_IMGTYPE_LIMIT] = {
+ [MDP_BGRA_8888] = true,
+ [MDP_RGBA_8888] = true,
+ [MDP_ARGB_8888] = true,
+};
+
+const bool multi_plane[MDP_IMGTYPE_LIMIT] = {
+ [MDP_Y_CRCB_H2V2] = true,
+ [MDP_Y_CBCR_H2V2] = true,
+ [MDP_Y_CBCR_H2V1] = true,
+ [MDP_Y_CRCB_H2V1] = true,
+};
+
+/* lut default */
+uint32_t default_pre_lut_val[PPP_LUT_MAX] = {
+ 0x0,
+ 0x151515,
+ 0x1d1d1d,
+ 0x232323,
+ 0x272727,
+ 0x2b2b2b,
+ 0x2f2f2f,
+ 0x333333,
+ 0x363636,
+ 0x393939,
+ 0x3b3b3b,
+ 0x3e3e3e,
+ 0x404040,
+ 0x434343,
+ 0x454545,
+ 0x474747,
+ 0x494949,
+ 0x4b4b4b,
+ 0x4d4d4d,
+ 0x4f4f4f,
+ 0x515151,
+ 0x535353,
+ 0x555555,
+ 0x565656,
+ 0x585858,
+ 0x5a5a5a,
+ 0x5b5b5b,
+ 0x5d5d5d,
+ 0x5e5e5e,
+ 0x606060,
+ 0x616161,
+ 0x636363,
+ 0x646464,
+ 0x666666,
+ 0x676767,
+ 0x686868,
+ 0x6a6a6a,
+ 0x6b6b6b,
+ 0x6c6c6c,
+ 0x6e6e6e,
+ 0x6f6f6f,
+ 0x707070,
+ 0x717171,
+ 0x727272,
+ 0x747474,
+ 0x757575,
+ 0x767676,
+ 0x777777,
+ 0x787878,
+ 0x797979,
+ 0x7a7a7a,
+ 0x7c7c7c,
+ 0x7d7d7d,
+ 0x7e7e7e,
+ 0x7f7f7f,
+ 0x808080,
+ 0x818181,
+ 0x828282,
+ 0x838383,
+ 0x848484,
+ 0x858585,
+ 0x868686,
+ 0x878787,
+ 0x888888,
+ 0x898989,
+ 0x8a8a8a,
+ 0x8b8b8b,
+ 0x8c8c8c,
+ 0x8d8d8d,
+ 0x8e8e8e,
+ 0x8f8f8f,
+ 0x8f8f8f,
+ 0x909090,
+ 0x919191,
+ 0x929292,
+ 0x939393,
+ 0x949494,
+ 0x959595,
+ 0x969696,
+ 0x969696,
+ 0x979797,
+ 0x989898,
+ 0x999999,
+ 0x9a9a9a,
+ 0x9b9b9b,
+ 0x9c9c9c,
+ 0x9c9c9c,
+ 0x9d9d9d,
+ 0x9e9e9e,
+ 0x9f9f9f,
+ 0xa0a0a0,
+ 0xa0a0a0,
+ 0xa1a1a1,
+ 0xa2a2a2,
+ 0xa3a3a3,
+ 0xa4a4a4,
+ 0xa4a4a4,
+ 0xa5a5a5,
+ 0xa6a6a6,
+ 0xa7a7a7,
+ 0xa7a7a7,
+ 0xa8a8a8,
+ 0xa9a9a9,
+ 0xaaaaaa,
+ 0xaaaaaa,
+ 0xababab,
+ 0xacacac,
+ 0xadadad,
+ 0xadadad,
+ 0xaeaeae,
+ 0xafafaf,
+ 0xafafaf,
+ 0xb0b0b0,
+ 0xb1b1b1,
+ 0xb2b2b2,
+ 0xb2b2b2,
+ 0xb3b3b3,
+ 0xb4b4b4,
+ 0xb4b4b4,
+ 0xb5b5b5,
+ 0xb6b6b6,
+ 0xb6b6b6,
+ 0xb7b7b7,
+ 0xb8b8b8,
+ 0xb8b8b8,
+ 0xb9b9b9,
+ 0xbababa,
+ 0xbababa,
+ 0xbbbbbb,
+ 0xbcbcbc,
+ 0xbcbcbc,
+ 0xbdbdbd,
+ 0xbebebe,
+ 0xbebebe,
+ 0xbfbfbf,
+ 0xc0c0c0,
+ 0xc0c0c0,
+ 0xc1c1c1,
+ 0xc1c1c1,
+ 0xc2c2c2,
+ 0xc3c3c3,
+ 0xc3c3c3,
+ 0xc4c4c4,
+ 0xc5c5c5,
+ 0xc5c5c5,
+ 0xc6c6c6,
+ 0xc6c6c6,
+ 0xc7c7c7,
+ 0xc8c8c8,
+ 0xc8c8c8,
+ 0xc9c9c9,
+ 0xc9c9c9,
+ 0xcacaca,
+ 0xcbcbcb,
+ 0xcbcbcb,
+ 0xcccccc,
+ 0xcccccc,
+ 0xcdcdcd,
+ 0xcecece,
+ 0xcecece,
+ 0xcfcfcf,
+ 0xcfcfcf,
+ 0xd0d0d0,
+ 0xd0d0d0,
+ 0xd1d1d1,
+ 0xd2d2d2,
+ 0xd2d2d2,
+ 0xd3d3d3,
+ 0xd3d3d3,
+ 0xd4d4d4,
+ 0xd4d4d4,
+ 0xd5d5d5,
+ 0xd6d6d6,
+ 0xd6d6d6,
+ 0xd7d7d7,
+ 0xd7d7d7,
+ 0xd8d8d8,
+ 0xd8d8d8,
+ 0xd9d9d9,
+ 0xd9d9d9,
+ 0xdadada,
+ 0xdbdbdb,
+ 0xdbdbdb,
+ 0xdcdcdc,
+ 0xdcdcdc,
+ 0xdddddd,
+ 0xdddddd,
+ 0xdedede,
+ 0xdedede,
+ 0xdfdfdf,
+ 0xdfdfdf,
+ 0xe0e0e0,
+ 0xe0e0e0,
+ 0xe1e1e1,
+ 0xe1e1e1,
+ 0xe2e2e2,
+ 0xe3e3e3,
+ 0xe3e3e3,
+ 0xe4e4e4,
+ 0xe4e4e4,
+ 0xe5e5e5,
+ 0xe5e5e5,
+ 0xe6e6e6,
+ 0xe6e6e6,
+ 0xe7e7e7,
+ 0xe7e7e7,
+ 0xe8e8e8,
+ 0xe8e8e8,
+ 0xe9e9e9,
+ 0xe9e9e9,
+ 0xeaeaea,
+ 0xeaeaea,
+ 0xebebeb,
+ 0xebebeb,
+ 0xececec,
+ 0xececec,
+ 0xededed,
+ 0xededed,
+ 0xeeeeee,
+ 0xeeeeee,
+ 0xefefef,
+ 0xefefef,
+ 0xf0f0f0,
+ 0xf0f0f0,
+ 0xf1f1f1,
+ 0xf1f1f1,
+ 0xf2f2f2,
+ 0xf2f2f2,
+ 0xf2f2f2,
+ 0xf3f3f3,
+ 0xf3f3f3,
+ 0xf4f4f4,
+ 0xf4f4f4,
+ 0xf5f5f5,
+ 0xf5f5f5,
+ 0xf6f6f6,
+ 0xf6f6f6,
+ 0xf7f7f7,
+ 0xf7f7f7,
+ 0xf8f8f8,
+ 0xf8f8f8,
+ 0xf9f9f9,
+ 0xf9f9f9,
+ 0xfafafa,
+ 0xfafafa,
+ 0xfafafa,
+ 0xfbfbfb,
+ 0xfbfbfb,
+ 0xfcfcfc,
+ 0xfcfcfc,
+ 0xfdfdfd,
+ 0xfdfdfd,
+ 0xfefefe,
+ 0xfefefe,
+ 0xffffff,
+ 0xffffff,
+};
+
+uint32_t default_post_lut_val[PPP_LUT_MAX] = {
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x10101,
+ 0x20202,
+ 0x20202,
+ 0x20202,
+ 0x20202,
+ 0x20202,
+ 0x20202,
+ 0x30303,
+ 0x30303,
+ 0x30303,
+ 0x30303,
+ 0x30303,
+ 0x40404,
+ 0x40404,
+ 0x40404,
+ 0x40404,
+ 0x40404,
+ 0x50505,
+ 0x50505,
+ 0x50505,
+ 0x50505,
+ 0x60606,
+ 0x60606,
+ 0x60606,
+ 0x70707,
+ 0x70707,
+ 0x70707,
+ 0x70707,
+ 0x80808,
+ 0x80808,
+ 0x80808,
+ 0x90909,
+ 0x90909,
+ 0xa0a0a,
+ 0xa0a0a,
+ 0xa0a0a,
+ 0xb0b0b,
+ 0xb0b0b,
+ 0xb0b0b,
+ 0xc0c0c,
+ 0xc0c0c,
+ 0xd0d0d,
+ 0xd0d0d,
+ 0xe0e0e,
+ 0xe0e0e,
+ 0xe0e0e,
+ 0xf0f0f,
+ 0xf0f0f,
+ 0x101010,
+ 0x101010,
+ 0x111111,
+ 0x111111,
+ 0x121212,
+ 0x121212,
+ 0x131313,
+ 0x131313,
+ 0x141414,
+ 0x151515,
+ 0x151515,
+ 0x161616,
+ 0x161616,
+ 0x171717,
+ 0x171717,
+ 0x181818,
+ 0x191919,
+ 0x191919,
+ 0x1a1a1a,
+ 0x1b1b1b,
+ 0x1b1b1b,
+ 0x1c1c1c,
+ 0x1c1c1c,
+ 0x1d1d1d,
+ 0x1e1e1e,
+ 0x1f1f1f,
+ 0x1f1f1f,
+ 0x202020,
+ 0x212121,
+ 0x212121,
+ 0x222222,
+ 0x232323,
+ 0x242424,
+ 0x242424,
+ 0x252525,
+ 0x262626,
+ 0x272727,
+ 0x272727,
+ 0x282828,
+ 0x292929,
+ 0x2a2a2a,
+ 0x2b2b2b,
+ 0x2c2c2c,
+ 0x2c2c2c,
+ 0x2d2d2d,
+ 0x2e2e2e,
+ 0x2f2f2f,
+ 0x303030,
+ 0x313131,
+ 0x323232,
+ 0x333333,
+ 0x333333,
+ 0x343434,
+ 0x353535,
+ 0x363636,
+ 0x373737,
+ 0x383838,
+ 0x393939,
+ 0x3a3a3a,
+ 0x3b3b3b,
+ 0x3c3c3c,
+ 0x3d3d3d,
+ 0x3e3e3e,
+ 0x3f3f3f,
+ 0x404040,
+ 0x414141,
+ 0x424242,
+ 0x434343,
+ 0x444444,
+ 0x464646,
+ 0x474747,
+ 0x484848,
+ 0x494949,
+ 0x4a4a4a,
+ 0x4b4b4b,
+ 0x4c4c4c,
+ 0x4d4d4d,
+ 0x4f4f4f,
+ 0x505050,
+ 0x515151,
+ 0x525252,
+ 0x535353,
+ 0x545454,
+ 0x565656,
+ 0x575757,
+ 0x585858,
+ 0x595959,
+ 0x5b5b5b,
+ 0x5c5c5c,
+ 0x5d5d5d,
+ 0x5e5e5e,
+ 0x606060,
+ 0x616161,
+ 0x626262,
+ 0x646464,
+ 0x656565,
+ 0x666666,
+ 0x686868,
+ 0x696969,
+ 0x6a6a6a,
+ 0x6c6c6c,
+ 0x6d6d6d,
+ 0x6f6f6f,
+ 0x707070,
+ 0x717171,
+ 0x737373,
+ 0x747474,
+ 0x767676,
+ 0x777777,
+ 0x797979,
+ 0x7a7a7a,
+ 0x7c7c7c,
+ 0x7d7d7d,
+ 0x7f7f7f,
+ 0x808080,
+ 0x828282,
+ 0x838383,
+ 0x858585,
+ 0x868686,
+ 0x888888,
+ 0x898989,
+ 0x8b8b8b,
+ 0x8d8d8d,
+ 0x8e8e8e,
+ 0x909090,
+ 0x919191,
+ 0x939393,
+ 0x959595,
+ 0x969696,
+ 0x989898,
+ 0x9a9a9a,
+ 0x9b9b9b,
+ 0x9d9d9d,
+ 0x9f9f9f,
+ 0xa1a1a1,
+ 0xa2a2a2,
+ 0xa4a4a4,
+ 0xa6a6a6,
+ 0xa7a7a7,
+ 0xa9a9a9,
+ 0xababab,
+ 0xadadad,
+ 0xafafaf,
+ 0xb0b0b0,
+ 0xb2b2b2,
+ 0xb4b4b4,
+ 0xb6b6b6,
+ 0xb8b8b8,
+ 0xbababa,
+ 0xbbbbbb,
+ 0xbdbdbd,
+ 0xbfbfbf,
+ 0xc1c1c1,
+ 0xc3c3c3,
+ 0xc5c5c5,
+ 0xc7c7c7,
+ 0xc9c9c9,
+ 0xcbcbcb,
+ 0xcdcdcd,
+ 0xcfcfcf,
+ 0xd1d1d1,
+ 0xd3d3d3,
+ 0xd5d5d5,
+ 0xd7d7d7,
+ 0xd9d9d9,
+ 0xdbdbdb,
+ 0xdddddd,
+ 0xdfdfdf,
+ 0xe1e1e1,
+ 0xe3e3e3,
+ 0xe5e5e5,
+ 0xe7e7e7,
+ 0xe9e9e9,
+ 0xebebeb,
+ 0xeeeeee,
+ 0xf0f0f0,
+ 0xf2f2f2,
+ 0xf4f4f4,
+ 0xf6f6f6,
+ 0xf8f8f8,
+ 0xfbfbfb,
+ 0xfdfdfd,
+ 0xffffff,
+};
+
+struct ppp_csc_table rgb2yuv = {
+ .fwd_matrix = {
+ 0x83,
+ 0x102,
+ 0x32,
+ 0xffb5,
+ 0xff6c,
+ 0xe1,
+ 0xe1,
+ 0xff45,
+ 0xffdc,
+ },
+ .rev_matrix = {
+ 0x254,
+ 0x0,
+ 0x331,
+ 0x254,
+ 0xff38,
+ 0xfe61,
+ 0x254,
+ 0x409,
+ 0x0,
+ },
+ .bv = {
+ 0x10,
+ 0x80,
+ 0x80,
+ },
+ .lv = {
+ 0x10,
+ 0xeb,
+ 0x10,
+ 0xf0,
+ },
+};
+
+struct ppp_csc_table default_table2 = {
+ .fwd_matrix = {
+ 0x5d,
+ 0x13a,
+ 0x20,
+ 0xffcd,
+ 0xff54,
+ 0xe1,
+ 0xe1,
+ 0xff35,
+ },
+ .rev_matrix = {
+ 0x254,
+ 0x0,
+ 0x396,
+ 0x254,
+ 0xff94,
+ 0xfef0,
+ 0x254,
+ 0x43a,
+ 0x0,
+ },
+ .bv = {
+ 0x10,
+ 0x80,
+ 0x80,
+ },
+ .lv = {
+ 0x10,
+ 0xeb,
+ 0x10,
+ 0xf0,
+ },
+};
+
+const struct ppp_table upscale_table[PPP_UPSCALE_MAX] = {
+ { 0x5fffc, 0x0 },
+ { 0x50200, 0x7fc00000 },
+ { 0x5fffc, 0xff80000d },
+ { 0x50204, 0x7ec003f9 },
+ { 0x5fffc, 0xfec0001c },
+ { 0x50208, 0x7d4003f3 },
+ { 0x5fffc, 0xfe40002b },
+ { 0x5020c, 0x7b8003ed },
+ { 0x5fffc, 0xfd80003c },
+ { 0x50210, 0x794003e8 },
+ { 0x5fffc, 0xfcc0004d },
+ { 0x50214, 0x76c003e4 },
+ { 0x5fffc, 0xfc40005f },
+ { 0x50218, 0x73c003e0 },
+ { 0x5fffc, 0xfb800071 },
+ { 0x5021c, 0x708003de },
+ { 0x5fffc, 0xfac00085 },
+ { 0x50220, 0x6d0003db },
+ { 0x5fffc, 0xfa000098 },
+ { 0x50224, 0x698003d9 },
+ { 0x5fffc, 0xf98000ac },
+ { 0x50228, 0x654003d8 },
+ { 0x5fffc, 0xf8c000c1 },
+ { 0x5022c, 0x610003d7 },
+ { 0x5fffc, 0xf84000d5 },
+ { 0x50230, 0x5c8003d7 },
+ { 0x5fffc, 0xf7c000e9 },
+ { 0x50234, 0x580003d7 },
+ { 0x5fffc, 0xf74000fd },
+ { 0x50238, 0x534003d8 },
+ { 0x5fffc, 0xf6c00112 },
+ { 0x5023c, 0x4e8003d8 },
+ { 0x5fffc, 0xf6800126 },
+ { 0x50240, 0x494003da },
+ { 0x5fffc, 0xf600013a },
+ { 0x50244, 0x448003db },
+ { 0x5fffc, 0xf600014d },
+ { 0x50248, 0x3f4003dd },
+ { 0x5fffc, 0xf5c00160 },
+ { 0x5024c, 0x3a4003df },
+ { 0x5fffc, 0xf5c00172 },
+ { 0x50250, 0x354003e1 },
+ { 0x5fffc, 0xf5c00184 },
+ { 0x50254, 0x304003e3 },
+ { 0x5fffc, 0xf6000195 },
+ { 0x50258, 0x2b0003e6 },
+ { 0x5fffc, 0xf64001a6 },
+ { 0x5025c, 0x260003e8 },
+ { 0x5fffc, 0xf6c001b4 },
+ { 0x50260, 0x214003eb },
+ { 0x5fffc, 0xf78001c2 },
+ { 0x50264, 0x1c4003ee },
+ { 0x5fffc, 0xf80001cf },
+ { 0x50268, 0x17c003f1 },
+ { 0x5fffc, 0xf90001db },
+ { 0x5026c, 0x134003f3 },
+ { 0x5fffc, 0xfa0001e5 },
+ { 0x50270, 0xf0003f6 },
+ { 0x5fffc, 0xfb4001ee },
+ { 0x50274, 0xac003f9 },
+ { 0x5fffc, 0xfcc001f5 },
+ { 0x50278, 0x70003fb },
+ { 0x5fffc, 0xfe4001fb },
+ { 0x5027c, 0x34003fe },
+};
+
+const struct ppp_table mdp_gaussian_blur_table[PPP_BLUR_SCALE_MAX] = {
+ /* max variance */
+ { 0x5fffc, 0x20000080 },
+ { 0x50280, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50284, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50288, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5028c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50290, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50294, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50298, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5029c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502a0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502a4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502a8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502ac, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502b0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502b4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502b8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502bc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502c0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502c4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502c8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502cc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502d0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502d4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502d8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502dc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502e0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502e4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502e8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502ec, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502f0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502f4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502f8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502fc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50300, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50304, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50308, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5030c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50310, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50314, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50318, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5031c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50320, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50324, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50328, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5032c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50330, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50334, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50338, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5033c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50340, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50344, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50348, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5034c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50350, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50354, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50358, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5035c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50360, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50364, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50368, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5036c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50370, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50374, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50378, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5037c, 0x20000080 },
+};
+
+const struct ppp_table downscale_x_table_pt2topt4[] = {
+ { 0x5fffc, 0x740008c },
+ { 0x50280, 0x33800088 },
+ { 0x5fffc, 0x800008e },
+ { 0x50284, 0x33400084 },
+ { 0x5fffc, 0x8400092 },
+ { 0x50288, 0x33000080 },
+ { 0x5fffc, 0x9000094 },
+ { 0x5028c, 0x3300007b },
+ { 0x5fffc, 0x9c00098 },
+ { 0x50290, 0x32400077 },
+ { 0x5fffc, 0xa40009b },
+ { 0x50294, 0x32000073 },
+ { 0x5fffc, 0xb00009d },
+ { 0x50298, 0x31c0006f },
+ { 0x5fffc, 0xbc000a0 },
+ { 0x5029c, 0x3140006b },
+ { 0x5fffc, 0xc8000a2 },
+ { 0x502a0, 0x31000067 },
+ { 0x5fffc, 0xd8000a5 },
+ { 0x502a4, 0x30800062 },
+ { 0x5fffc, 0xe4000a8 },
+ { 0x502a8, 0x2fc0005f },
+ { 0x5fffc, 0xec000aa },
+ { 0x502ac, 0x2fc0005b },
+ { 0x5fffc, 0xf8000ad },
+ { 0x502b0, 0x2f400057 },
+ { 0x5fffc, 0x108000b0 },
+ { 0x502b4, 0x2e400054 },
+ { 0x5fffc, 0x114000b2 },
+ { 0x502b8, 0x2e000050 },
+ { 0x5fffc, 0x124000b4 },
+ { 0x502bc, 0x2d80004c },
+ { 0x5fffc, 0x130000b6 },
+ { 0x502c0, 0x2d000049 },
+ { 0x5fffc, 0x140000b8 },
+ { 0x502c4, 0x2c800045 },
+ { 0x5fffc, 0x150000b9 },
+ { 0x502c8, 0x2c000042 },
+ { 0x5fffc, 0x15c000bd },
+ { 0x502cc, 0x2b40003e },
+ { 0x5fffc, 0x16c000bf },
+ { 0x502d0, 0x2a80003b },
+ { 0x5fffc, 0x17c000bf },
+ { 0x502d4, 0x2a000039 },
+ { 0x5fffc, 0x188000c2 },
+ { 0x502d8, 0x29400036 },
+ { 0x5fffc, 0x19c000c4 },
+ { 0x502dc, 0x28800032 },
+ { 0x5fffc, 0x1ac000c5 },
+ { 0x502e0, 0x2800002f },
+ { 0x5fffc, 0x1bc000c7 },
+ { 0x502e4, 0x2740002c },
+ { 0x5fffc, 0x1cc000c8 },
+ { 0x502e8, 0x26c00029 },
+ { 0x5fffc, 0x1dc000c9 },
+ { 0x502ec, 0x26000027 },
+ { 0x5fffc, 0x1ec000cc },
+ { 0x502f0, 0x25000024 },
+ { 0x5fffc, 0x200000cc },
+ { 0x502f4, 0x24800021 },
+ { 0x5fffc, 0x210000cd },
+ { 0x502f8, 0x23800020 },
+ { 0x5fffc, 0x220000ce },
+ { 0x502fc, 0x2300001d },
+};
+
+static const struct ppp_table downscale_x_table_pt4topt6[] = {
+ { 0x5fffc, 0x740008c },
+ { 0x50280, 0x33800088 },
+ { 0x5fffc, 0x800008e },
+ { 0x50284, 0x33400084 },
+ { 0x5fffc, 0x8400092 },
+ { 0x50288, 0x33000080 },
+ { 0x5fffc, 0x9000094 },
+ { 0x5028c, 0x3300007b },
+ { 0x5fffc, 0x9c00098 },
+ { 0x50290, 0x32400077 },
+ { 0x5fffc, 0xa40009b },
+ { 0x50294, 0x32000073 },
+ { 0x5fffc, 0xb00009d },
+ { 0x50298, 0x31c0006f },
+ { 0x5fffc, 0xbc000a0 },
+ { 0x5029c, 0x3140006b },
+ { 0x5fffc, 0xc8000a2 },
+ { 0x502a0, 0x31000067 },
+ { 0x5fffc, 0xd8000a5 },
+ { 0x502a4, 0x30800062 },
+ { 0x5fffc, 0xe4000a8 },
+ { 0x502a8, 0x2fc0005f },
+ { 0x5fffc, 0xec000aa },
+ { 0x502ac, 0x2fc0005b },
+ { 0x5fffc, 0xf8000ad },
+ { 0x502b0, 0x2f400057 },
+ { 0x5fffc, 0x108000b0 },
+ { 0x502b4, 0x2e400054 },
+ { 0x5fffc, 0x114000b2 },
+ { 0x502b8, 0x2e000050 },
+ { 0x5fffc, 0x124000b4 },
+ { 0x502bc, 0x2d80004c },
+ { 0x5fffc, 0x130000b6 },
+ { 0x502c0, 0x2d000049 },
+ { 0x5fffc, 0x140000b8 },
+ { 0x502c4, 0x2c800045 },
+ { 0x5fffc, 0x150000b9 },
+ { 0x502c8, 0x2c000042 },
+ { 0x5fffc, 0x15c000bd },
+ { 0x502cc, 0x2b40003e },
+ { 0x5fffc, 0x16c000bf },
+ { 0x502d0, 0x2a80003b },
+ { 0x5fffc, 0x17c000bf },
+ { 0x502d4, 0x2a000039 },
+ { 0x5fffc, 0x188000c2 },
+ { 0x502d8, 0x29400036 },
+ { 0x5fffc, 0x19c000c4 },
+ { 0x502dc, 0x28800032 },
+ { 0x5fffc, 0x1ac000c5 },
+ { 0x502e0, 0x2800002f },
+ { 0x5fffc, 0x1bc000c7 },
+ { 0x502e4, 0x2740002c },
+ { 0x5fffc, 0x1cc000c8 },
+ { 0x502e8, 0x26c00029 },
+ { 0x5fffc, 0x1dc000c9 },
+ { 0x502ec, 0x26000027 },
+ { 0x5fffc, 0x1ec000cc },
+ { 0x502f0, 0x25000024 },
+ { 0x5fffc, 0x200000cc },
+ { 0x502f4, 0x24800021 },
+ { 0x5fffc, 0x210000cd },
+ { 0x502f8, 0x23800020 },
+ { 0x5fffc, 0x220000ce },
+ { 0x502fc, 0x2300001d },
+};
+
+static const struct ppp_table downscale_x_table_pt6topt8[] = {
+ { 0x5fffc, 0xfe000070 },
+ { 0x50280, 0x4bc00068 },
+ { 0x5fffc, 0xfe000078 },
+ { 0x50284, 0x4bc00060 },
+ { 0x5fffc, 0xfe000080 },
+ { 0x50288, 0x4b800059 },
+ { 0x5fffc, 0xfe000089 },
+ { 0x5028c, 0x4b000052 },
+ { 0x5fffc, 0xfe400091 },
+ { 0x50290, 0x4a80004b },
+ { 0x5fffc, 0xfe40009a },
+ { 0x50294, 0x4a000044 },
+ { 0x5fffc, 0xfe8000a3 },
+ { 0x50298, 0x4940003d },
+ { 0x5fffc, 0xfec000ac },
+ { 0x5029c, 0x48400037 },
+ { 0x5fffc, 0xff0000b4 },
+ { 0x502a0, 0x47800031 },
+ { 0x5fffc, 0xff8000bd },
+ { 0x502a4, 0x4640002b },
+ { 0x5fffc, 0xc5 },
+ { 0x502a8, 0x45000026 },
+ { 0x5fffc, 0x8000ce },
+ { 0x502ac, 0x43800021 },
+ { 0x5fffc, 0x10000d6 },
+ { 0x502b0, 0x4240001c },
+ { 0x5fffc, 0x18000df },
+ { 0x502b4, 0x40800018 },
+ { 0x5fffc, 0x24000e6 },
+ { 0x502b8, 0x3f000014 },
+ { 0x5fffc, 0x30000ee },
+ { 0x502bc, 0x3d400010 },
+ { 0x5fffc, 0x40000f5 },
+ { 0x502c0, 0x3b80000c },
+ { 0x5fffc, 0x50000fc },
+ { 0x502c4, 0x39800009 },
+ { 0x5fffc, 0x6000102 },
+ { 0x502c8, 0x37c00006 },
+ { 0x5fffc, 0x7000109 },
+ { 0x502cc, 0x35800004 },
+ { 0x5fffc, 0x840010e },
+ { 0x502d0, 0x33800002 },
+ { 0x5fffc, 0x9800114 },
+ { 0x502d4, 0x31400000 },
+ { 0x5fffc, 0xac00119 },
+ { 0x502d8, 0x2f4003fe },
+ { 0x5fffc, 0xc40011e },
+ { 0x502dc, 0x2d0003fc },
+ { 0x5fffc, 0xdc00121 },
+ { 0x502e0, 0x2b0003fb },
+ { 0x5fffc, 0xf400125 },
+ { 0x502e4, 0x28c003fa },
+ { 0x5fffc, 0x11000128 },
+ { 0x502e8, 0x268003f9 },
+ { 0x5fffc, 0x12c0012a },
+ { 0x502ec, 0x244003f9 },
+ { 0x5fffc, 0x1480012c },
+ { 0x502f0, 0x224003f8 },
+ { 0x5fffc, 0x1640012e },
+ { 0x502f4, 0x200003f8 },
+ { 0x5fffc, 0x1800012f },
+ { 0x502f8, 0x1e0003f8 },
+ { 0x5fffc, 0x1a00012f },
+ { 0x502fc, 0x1c0003f8 },
+};
+
+static const struct ppp_table downscale_x_table_pt8topt1[] = {
+ { 0x5fffc, 0x0 },
+ { 0x50280, 0x7fc00000 },
+ { 0x5fffc, 0xff80000d },
+ { 0x50284, 0x7ec003f9 },
+ { 0x5fffc, 0xfec0001c },
+ { 0x50288, 0x7d4003f3 },
+ { 0x5fffc, 0xfe40002b },
+ { 0x5028c, 0x7b8003ed },
+ { 0x5fffc, 0xfd80003c },
+ { 0x50290, 0x794003e8 },
+ { 0x5fffc, 0xfcc0004d },
+ { 0x50294, 0x76c003e4 },
+ { 0x5fffc, 0xfc40005f },
+ { 0x50298, 0x73c003e0 },
+ { 0x5fffc, 0xfb800071 },
+ { 0x5029c, 0x708003de },
+ { 0x5fffc, 0xfac00085 },
+ { 0x502a0, 0x6d0003db },
+ { 0x5fffc, 0xfa000098 },
+ { 0x502a4, 0x698003d9 },
+ { 0x5fffc, 0xf98000ac },
+ { 0x502a8, 0x654003d8 },
+ { 0x5fffc, 0xf8c000c1 },
+ { 0x502ac, 0x610003d7 },
+ { 0x5fffc, 0xf84000d5 },
+ { 0x502b0, 0x5c8003d7 },
+ { 0x5fffc, 0xf7c000e9 },
+ { 0x502b4, 0x580003d7 },
+ { 0x5fffc, 0xf74000fd },
+ { 0x502b8, 0x534003d8 },
+ { 0x5fffc, 0xf6c00112 },
+ { 0x502bc, 0x4e8003d8 },
+ { 0x5fffc, 0xf6800126 },
+ { 0x502c0, 0x494003da },
+ { 0x5fffc, 0xf600013a },
+ { 0x502c4, 0x448003db },
+ { 0x5fffc, 0xf600014d },
+ { 0x502c8, 0x3f4003dd },
+ { 0x5fffc, 0xf5c00160 },
+ { 0x502cc, 0x3a4003df },
+ { 0x5fffc, 0xf5c00172 },
+ { 0x502d0, 0x354003e1 },
+ { 0x5fffc, 0xf5c00184 },
+ { 0x502d4, 0x304003e3 },
+ { 0x5fffc, 0xf6000195 },
+ { 0x502d8, 0x2b0003e6 },
+ { 0x5fffc, 0xf64001a6 },
+ { 0x502dc, 0x260003e8 },
+ { 0x5fffc, 0xf6c001b4 },
+ { 0x502e0, 0x214003eb },
+ { 0x5fffc, 0xf78001c2 },
+ { 0x502e4, 0x1c4003ee },
+ { 0x5fffc, 0xf80001cf },
+ { 0x502e8, 0x17c003f1 },
+ { 0x5fffc, 0xf90001db },
+ { 0x502ec, 0x134003f3 },
+ { 0x5fffc, 0xfa0001e5 },
+ { 0x502f0, 0xf0003f6 },
+ { 0x5fffc, 0xfb4001ee },
+ { 0x502f4, 0xac003f9 },
+ { 0x5fffc, 0xfcc001f5 },
+ { 0x502f8, 0x70003fb },
+ { 0x5fffc, 0xfe4001fb },
+ { 0x502fc, 0x34003fe },
+};
+
+static const struct ppp_table *downscale_x_table[PPP_DOWNSCALE_MAX] = {
+ [PPP_DOWNSCALE_PT2TOPT4] = downscale_x_table_pt2topt4,
+ [PPP_DOWNSCALE_PT4TOPT6] = downscale_x_table_pt4topt6,
+ [PPP_DOWNSCALE_PT6TOPT8] = downscale_x_table_pt6topt8,
+ [PPP_DOWNSCALE_PT8TOPT1] = downscale_x_table_pt8topt1,
+};
+
+static const struct ppp_table downscale_y_table_pt2topt4[] = {
+ { 0x5fffc, 0x740008c },
+ { 0x50300, 0x33800088 },
+ { 0x5fffc, 0x800008e },
+ { 0x50304, 0x33400084 },
+ { 0x5fffc, 0x8400092 },
+ { 0x50308, 0x33000080 },
+ { 0x5fffc, 0x9000094 },
+ { 0x5030c, 0x3300007b },
+ { 0x5fffc, 0x9c00098 },
+ { 0x50310, 0x32400077 },
+ { 0x5fffc, 0xa40009b },
+ { 0x50314, 0x32000073 },
+ { 0x5fffc, 0xb00009d },
+ { 0x50318, 0x31c0006f },
+ { 0x5fffc, 0xbc000a0 },
+ { 0x5031c, 0x3140006b },
+ { 0x5fffc, 0xc8000a2 },
+ { 0x50320, 0x31000067 },
+ { 0x5fffc, 0xd8000a5 },
+ { 0x50324, 0x30800062 },
+ { 0x5fffc, 0xe4000a8 },
+ { 0x50328, 0x2fc0005f },
+ { 0x5fffc, 0xec000aa },
+ { 0x5032c, 0x2fc0005b },
+ { 0x5fffc, 0xf8000ad },
+ { 0x50330, 0x2f400057 },
+ { 0x5fffc, 0x108000b0 },
+ { 0x50334, 0x2e400054 },
+ { 0x5fffc, 0x114000b2 },
+ { 0x50338, 0x2e000050 },
+ { 0x5fffc, 0x124000b4 },
+ { 0x5033c, 0x2d80004c },
+ { 0x5fffc, 0x130000b6 },
+ { 0x50340, 0x2d000049 },
+ { 0x5fffc, 0x140000b8 },
+ { 0x50344, 0x2c800045 },
+ { 0x5fffc, 0x150000b9 },
+ { 0x50348, 0x2c000042 },
+ { 0x5fffc, 0x15c000bd },
+ { 0x5034c, 0x2b40003e },
+ { 0x5fffc, 0x16c000bf },
+ { 0x50350, 0x2a80003b },
+ { 0x5fffc, 0x17c000bf },
+ { 0x50354, 0x2a000039 },
+ { 0x5fffc, 0x188000c2 },
+ { 0x50358, 0x29400036 },
+ { 0x5fffc, 0x19c000c4 },
+ { 0x5035c, 0x28800032 },
+ { 0x5fffc, 0x1ac000c5 },
+ { 0x50360, 0x2800002f },
+ { 0x5fffc, 0x1bc000c7 },
+ { 0x50364, 0x2740002c },
+ { 0x5fffc, 0x1cc000c8 },
+ { 0x50368, 0x26c00029 },
+ { 0x5fffc, 0x1dc000c9 },
+ { 0x5036c, 0x26000027 },
+ { 0x5fffc, 0x1ec000cc },
+ { 0x50370, 0x25000024 },
+ { 0x5fffc, 0x200000cc },
+ { 0x50374, 0x24800021 },
+ { 0x5fffc, 0x210000cd },
+ { 0x50378, 0x23800020 },
+ { 0x5fffc, 0x220000ce },
+ { 0x5037c, 0x2300001d },
+};
+
+static const struct ppp_table downscale_y_table_pt4topt6[] = {
+ { 0x5fffc, 0x740008c },
+ { 0x50300, 0x33800088 },
+ { 0x5fffc, 0x800008e },
+ { 0x50304, 0x33400084 },
+ { 0x5fffc, 0x8400092 },
+ { 0x50308, 0x33000080 },
+ { 0x5fffc, 0x9000094 },
+ { 0x5030c, 0x3300007b },
+ { 0x5fffc, 0x9c00098 },
+ { 0x50310, 0x32400077 },
+ { 0x5fffc, 0xa40009b },
+ { 0x50314, 0x32000073 },
+ { 0x5fffc, 0xb00009d },
+ { 0x50318, 0x31c0006f },
+ { 0x5fffc, 0xbc000a0 },
+ { 0x5031c, 0x3140006b },
+ { 0x5fffc, 0xc8000a2 },
+ { 0x50320, 0x31000067 },
+ { 0x5fffc, 0xd8000a5 },
+ { 0x50324, 0x30800062 },
+ { 0x5fffc, 0xe4000a8 },
+ { 0x50328, 0x2fc0005f },
+ { 0x5fffc, 0xec000aa },
+ { 0x5032c, 0x2fc0005b },
+ { 0x5fffc, 0xf8000ad },
+ { 0x50330, 0x2f400057 },
+ { 0x5fffc, 0x108000b0 },
+ { 0x50334, 0x2e400054 },
+ { 0x5fffc, 0x114000b2 },
+ { 0x50338, 0x2e000050 },
+ { 0x5fffc, 0x124000b4 },
+ { 0x5033c, 0x2d80004c },
+ { 0x5fffc, 0x130000b6 },
+ { 0x50340, 0x2d000049 },
+ { 0x5fffc, 0x140000b8 },
+ { 0x50344, 0x2c800045 },
+ { 0x5fffc, 0x150000b9 },
+ { 0x50348, 0x2c000042 },
+ { 0x5fffc, 0x15c000bd },
+ { 0x5034c, 0x2b40003e },
+ { 0x5fffc, 0x16c000bf },
+ { 0x50350, 0x2a80003b },
+ { 0x5fffc, 0x17c000bf },
+ { 0x50354, 0x2a000039 },
+ { 0x5fffc, 0x188000c2 },
+ { 0x50358, 0x29400036 },
+ { 0x5fffc, 0x19c000c4 },
+ { 0x5035c, 0x28800032 },
+ { 0x5fffc, 0x1ac000c5 },
+ { 0x50360, 0x2800002f },
+ { 0x5fffc, 0x1bc000c7 },
+ { 0x50364, 0x2740002c },
+ { 0x5fffc, 0x1cc000c8 },
+ { 0x50368, 0x26c00029 },
+ { 0x5fffc, 0x1dc000c9 },
+ { 0x5036c, 0x26000027 },
+ { 0x5fffc, 0x1ec000cc },
+ { 0x50370, 0x25000024 },
+ { 0x5fffc, 0x200000cc },
+ { 0x50374, 0x24800021 },
+ { 0x5fffc, 0x210000cd },
+ { 0x50378, 0x23800020 },
+ { 0x5fffc, 0x220000ce },
+ { 0x5037c, 0x2300001d },
+};
+
+static const struct ppp_table downscale_y_table_pt6topt8[] = {
+ { 0x5fffc, 0xfe000070 },
+ { 0x50300, 0x4bc00068 },
+ { 0x5fffc, 0xfe000078 },
+ { 0x50304, 0x4bc00060 },
+ { 0x5fffc, 0xfe000080 },
+ { 0x50308, 0x4b800059 },
+ { 0x5fffc, 0xfe000089 },
+ { 0x5030c, 0x4b000052 },
+ { 0x5fffc, 0xfe400091 },
+ { 0x50310, 0x4a80004b },
+ { 0x5fffc, 0xfe40009a },
+ { 0x50314, 0x4a000044 },
+ { 0x5fffc, 0xfe8000a3 },
+ { 0x50318, 0x4940003d },
+ { 0x5fffc, 0xfec000ac },
+ { 0x5031c, 0x48400037 },
+ { 0x5fffc, 0xff0000b4 },
+ { 0x50320, 0x47800031 },
+ { 0x5fffc, 0xff8000bd },
+ { 0x50324, 0x4640002b },
+ { 0x5fffc, 0xc5 },
+ { 0x50328, 0x45000026 },
+ { 0x5fffc, 0x8000ce },
+ { 0x5032c, 0x43800021 },
+ { 0x5fffc, 0x10000d6 },
+ { 0x50330, 0x4240001c },
+ { 0x5fffc, 0x18000df },
+ { 0x50334, 0x40800018 },
+ { 0x5fffc, 0x24000e6 },
+ { 0x50338, 0x3f000014 },
+ { 0x5fffc, 0x30000ee },
+ { 0x5033c, 0x3d400010 },
+ { 0x5fffc, 0x40000f5 },
+ { 0x50340, 0x3b80000c },
+ { 0x5fffc, 0x50000fc },
+ { 0x50344, 0x39800009 },
+ { 0x5fffc, 0x6000102 },
+ { 0x50348, 0x37c00006 },
+ { 0x5fffc, 0x7000109 },
+ { 0x5034c, 0x35800004 },
+ { 0x5fffc, 0x840010e },
+ { 0x50350, 0x33800002 },
+ { 0x5fffc, 0x9800114 },
+ { 0x50354, 0x31400000 },
+ { 0x5fffc, 0xac00119 },
+ { 0x50358, 0x2f4003fe },
+ { 0x5fffc, 0xc40011e },
+ { 0x5035c, 0x2d0003fc },
+ { 0x5fffc, 0xdc00121 },
+ { 0x50360, 0x2b0003fb },
+ { 0x5fffc, 0xf400125 },
+ { 0x50364, 0x28c003fa },
+ { 0x5fffc, 0x11000128 },
+ { 0x50368, 0x268003f9 },
+ { 0x5fffc, 0x12c0012a },
+ { 0x5036c, 0x244003f9 },
+ { 0x5fffc, 0x1480012c },
+ { 0x50370, 0x224003f8 },
+ { 0x5fffc, 0x1640012e },
+ { 0x50374, 0x200003f8 },
+ { 0x5fffc, 0x1800012f },
+ { 0x50378, 0x1e0003f8 },
+ { 0x5fffc, 0x1a00012f },
+ { 0x5037c, 0x1c0003f8 },
+};
+
+static const struct ppp_table downscale_y_table_pt8topt1[] = {
+ { 0x5fffc, 0x0 },
+ { 0x50300, 0x7fc00000 },
+ { 0x5fffc, 0xff80000d },
+ { 0x50304, 0x7ec003f9 },
+ { 0x5fffc, 0xfec0001c },
+ { 0x50308, 0x7d4003f3 },
+ { 0x5fffc, 0xfe40002b },
+ { 0x5030c, 0x7b8003ed },
+ { 0x5fffc, 0xfd80003c },
+ { 0x50310, 0x794003e8 },
+ { 0x5fffc, 0xfcc0004d },
+ { 0x50314, 0x76c003e4 },
+ { 0x5fffc, 0xfc40005f },
+ { 0x50318, 0x73c003e0 },
+ { 0x5fffc, 0xfb800071 },
+ { 0x5031c, 0x708003de },
+ { 0x5fffc, 0xfac00085 },
+ { 0x50320, 0x6d0003db },
+ { 0x5fffc, 0xfa000098 },
+ { 0x50324, 0x698003d9 },
+ { 0x5fffc, 0xf98000ac },
+ { 0x50328, 0x654003d8 },
+ { 0x5fffc, 0xf8c000c1 },
+ { 0x5032c, 0x610003d7 },
+ { 0x5fffc, 0xf84000d5 },
+ { 0x50330, 0x5c8003d7 },
+ { 0x5fffc, 0xf7c000e9 },
+ { 0x50334, 0x580003d7 },
+ { 0x5fffc, 0xf74000fd },
+ { 0x50338, 0x534003d8 },
+ { 0x5fffc, 0xf6c00112 },
+ { 0x5033c, 0x4e8003d8 },
+ { 0x5fffc, 0xf6800126 },
+ { 0x50340, 0x494003da },
+ { 0x5fffc, 0xf600013a },
+ { 0x50344, 0x448003db },
+ { 0x5fffc, 0xf600014d },
+ { 0x50348, 0x3f4003dd },
+ { 0x5fffc, 0xf5c00160 },
+ { 0x5034c, 0x3a4003df },
+ { 0x5fffc, 0xf5c00172 },
+ { 0x50350, 0x354003e1 },
+ { 0x5fffc, 0xf5c00184 },
+ { 0x50354, 0x304003e3 },
+ { 0x5fffc, 0xf6000195 },
+ { 0x50358, 0x2b0003e6 },
+ { 0x5fffc, 0xf64001a6 },
+ { 0x5035c, 0x260003e8 },
+ { 0x5fffc, 0xf6c001b4 },
+ { 0x50360, 0x214003eb },
+ { 0x5fffc, 0xf78001c2 },
+ { 0x50364, 0x1c4003ee },
+ { 0x5fffc, 0xf80001cf },
+ { 0x50368, 0x17c003f1 },
+ { 0x5fffc, 0xf90001db },
+ { 0x5036c, 0x134003f3 },
+ { 0x5fffc, 0xfa0001e5 },
+ { 0x50370, 0xf0003f6 },
+ { 0x5fffc, 0xfb4001ee },
+ { 0x50374, 0xac003f9 },
+ { 0x5fffc, 0xfcc001f5 },
+ { 0x50378, 0x70003fb },
+ { 0x5fffc, 0xfe4001fb },
+ { 0x5037c, 0x34003fe },
+};
+
+static const struct ppp_table *downscale_y_table[PPP_DOWNSCALE_MAX] = {
+ [PPP_DOWNSCALE_PT2TOPT4] = downscale_y_table_pt2topt4,
+ [PPP_DOWNSCALE_PT4TOPT6] = downscale_y_table_pt4topt6,
+ [PPP_DOWNSCALE_PT6TOPT8] = downscale_y_table_pt6topt8,
+ [PPP_DOWNSCALE_PT8TOPT1] = downscale_y_table_pt8topt1,
+};
+
+void ppp_load_table(const struct ppp_table *table, int len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ PPP_WRITEL(table[i].val, table[i].reg);
+}
+
+void ppp_load_up_lut(void)
+{
+ ppp_load_table(upscale_table,
+ PPP_UPSCALE_MAX);
+}
+
+void ppp_load_gaussian_lut(void)
+{
+ ppp_load_table(mdp_gaussian_blur_table,
+ PPP_BLUR_SCALE_MAX);
+}
+
+void ppp_load_x_scale_table(int idx)
+{
+ ppp_load_table(downscale_x_table[idx], 64);
+}
+
+void ppp_load_y_scale_table(int idx)
+{
+ ppp_load_table(downscale_y_table[idx], 64);
+}
+
+uint32_t ppp_bpp(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return bytes_per_pixel[type];
+}
+
+uint32_t ppp_src_config(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return src_cfg_lut[type];
+}
+
+uint32_t ppp_out_config(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return out_cfg_lut[type];
+}
+
+uint32_t ppp_pack_pattern(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return pack_patt_lut[type];
+}
+
+uint32_t ppp_dst_op_reg(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return dst_op_reg[type];
+}
+
+uint32_t ppp_src_op_reg(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return src_op_reg[type];
+}
+
+bool ppp_per_p_alpha(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return per_pixel_alpha[type];
+}
+
+bool ppp_multi_plane(uint32_t type)
+{
+ if (type > MDP_IMGTYPE_LIMIT)
+ return 0;
+ return multi_plane[type];
+}
+
+uint32_t *ppp_default_pre_lut(void)
+{
+ return default_pre_lut_val;
+}
+
+uint32_t *ppp_default_post_lut(void)
+{
+ return default_post_lut_val;
+}
+
+struct ppp_csc_table *ppp_csc_rgb2yuv(void)
+{
+ return &rgb2yuv;
+}
+
+struct ppp_csc_table *ppp_csc_table2(void)
+{
+ return &default_table2;
+}
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
new file mode 100644
index 0000000..309effc
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -0,0 +1,1184 @@
+/* Copyright (c) 2007, 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * 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/file.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include "linux/proc_fs.h"
+
+#include "mdss_fb.h"
+#include "mdp3_ppp.h"
+#include "mdp3_hwio.h"
+
+/* SHIM Q Factor */
+#define PHI_Q_FACTOR 29
+#define PQF_PLUS_5 (PHI_Q_FACTOR + 5) /* due to 32 phases */
+#define PQF_PLUS_4 (PHI_Q_FACTOR + 4)
+#define PQF_PLUS_2 (PHI_Q_FACTOR + 2) /* to get 4.0 */
+#define PQF_MINUS_2 (PHI_Q_FACTOR - 2) /* to get 0.25 */
+#define PQF_PLUS_5_PLUS_2 (PQF_PLUS_5 + 2)
+#define PQF_PLUS_5_MINUS_2 (PQF_PLUS_5 - 2)
+
+static long long mdp_do_div(long long num, long long den)
+{
+ do_div(num, den);
+ return num;
+}
+
+static int mdp_calc_scale_params(uint32_t org, uint32_t dim_in,
+ uint32_t dim_out, bool is_W, int32_t *phase_init_ptr,
+ uint32_t *phase_step_ptr)
+{
+ bool rpa_on = false;
+ int init_phase = 0;
+ uint64_t numer = 0;
+ uint64_t denom = 0;
+ int64_t point5 = 1;
+ int64_t one = 1;
+ int64_t k1, k2, k3, k4; /* linear equation coefficients */
+ uint64_t int_mask;
+ uint64_t fract_mask;
+ uint64_t Os;
+ int64_t Osprime;
+ int64_t Od;
+ int64_t Odprime;
+ int64_t Oreq;
+ uint32_t mult;
+
+ /*
+ * The phase accumulator should really be rational for all cases in a
+ * general purpose polyphase scaler for a tiled architecture with
+ * non-zero * origin capability because there is no way to represent
+ * certain scale factors in fixed point regardless of precision.
+ * The error incurred in attempting to use fixed point is most
+ * eggregious for SF where 1/SF is an integral multiple of 1/3.
+ *
+ * Set the RPA flag for this dimension.
+ *
+ * In order for 1/SF (dim_in/dim_out) to be an integral multiple of
+ * 1/3, dim_out must be an integral multiple of 3.
+ */
+ if (!(dim_out % 3)) {
+ mult = dim_out / 3;
+ rpa_on = (!(dim_in % mult));
+ }
+
+ numer = dim_out;
+ denom = dim_in;
+
+ /*
+ * convert to U30.34 before division
+ *
+ * The K vectors carry 4 extra bits of precision
+ * and are rounded.
+ *
+ * We initially go 5 bits over then round by adding
+ * 1 and right shifting by 1
+ * so final result is U31.33
+ */
+ numer <<= PQF_PLUS_5;
+
+ /* now calculate the scale factor (aka k3) */
+ k3 = ((mdp_do_div(numer, denom) + 1) >> 1);
+
+ /* check scale factor for legal range [0.25 - 4.0] */
+ if (((k3 >> 4) < (1LL << PQF_MINUS_2)) ||
+ ((k3 >> 4) > (1LL << PQF_PLUS_2))) {
+ return -EINVAL;
+ }
+
+ /* calculate inverse scale factor (aka k1) for phase init */
+ numer = dim_in;
+ denom = dim_out;
+ numer <<= PQF_PLUS_5;
+ k1 = ((mdp_do_div(numer, denom) + 1) >> 1);
+
+ /*
+ * calculate initial phase and ROI overfetch
+ */
+ /* convert point5 & one to S39.24 (will always be positive) */
+ point5 <<= (PQF_PLUS_4 - 1);
+ one <<= PQF_PLUS_4;
+ k2 = ((k1 - one) >> 1);
+ init_phase = (int)(k2 >> 4);
+ k4 = ((k3 - one) >> 1);
+ if (k3 != one) {
+ /* calculate the masks */
+ fract_mask = one - 1;
+ int_mask = ~fract_mask;
+
+ if (!rpa_on) {
+ /*
+ * FIXED POINT IMPLEMENTATION
+ */
+ if (org) {
+ /*
+ * The complicated case; ROI origin != 0
+ * init_phase needs to be adjusted
+ * OF is also position dependent
+ */
+
+ /* map (org - .5) into destination space */
+ Os = ((uint64_t) org << 1) - 1;
+ Od = ((k3 * Os) >> 1) + k4;
+
+ /* take the ceiling */
+ Odprime = (Od & int_mask);
+ if (Odprime != Od)
+ Odprime += one;
+
+ /* now map that back to source space */
+ Osprime = (k1 * (Odprime >> PQF_PLUS_4)) + k2;
+
+ /* then floor & decrement to calc the required
+ starting coordinate */
+ Oreq = (Osprime & int_mask) - one;
+
+ /* calculate initial phase */
+ init_phase = (int)((Osprime - Oreq) >> 4);
+ }
+ } else {
+ /*
+ * RPA IMPLEMENTATION
+ *
+ * init_phase needs to be calculated in all RPA_on cases
+ * because it's a numerator, not a fixed point value.
+ */
+
+ /* map (org - .5) into destination space */
+ Os = ((uint64_t) org << PQF_PLUS_4) - point5;
+ Od = mdp_do_div((dim_out * (Os + point5)),
+ dim_in);
+ Od -= point5;
+
+ /* take the ceiling */
+ Odprime = (Od & int_mask);
+ if (Odprime != Od)
+ Odprime += one;
+
+ /* now map that back to source space */
+ Osprime =
+ mdp_do_div((dim_in * (Odprime + point5)),
+ dim_out);
+ Osprime -= point5;
+
+ /* then floor & decrement to calculate the required
+ starting coordinate */
+ Oreq = (Osprime & int_mask) - one;
+
+ /* calculate initial phase */
+ init_phase = (int)((Osprime - Oreq) >> 4);
+ }
+ }
+
+ /* return the scale parameters */
+ *phase_init_ptr = init_phase;
+ *phase_step_ptr = (uint32_t) (k1 >> 4);
+
+ return 0;
+}
+
+static int scale_idx(int factor)
+{
+ int idx;
+
+ if (factor > 80)
+ idx = PPP_DOWNSCALE_PT8TOPT1;
+ else if (factor > 60)
+ idx = PPP_DOWNSCALE_PT6TOPT8;
+ else if (factor > 40)
+ idx = PPP_DOWNSCALE_PT4TOPT6;
+ else
+ idx = PPP_DOWNSCALE_PT2TOPT4;
+
+ return idx;
+}
+
+inline int32_t comp_conv_rgb2yuv(int32_t comp, int32_t y_high,
+ int32_t y_low, int32_t c_high, int32_t c_low)
+{
+ if (comp < 0)
+ comp = 0;
+ if (comp > 255)
+ comp = 255;
+
+ /* clamp */
+ if (comp < y_low)
+ comp = y_low;
+ if (comp > y_high)
+ comp = y_high;
+ return comp;
+}
+
+static uint32_t conv_rgb2yuv(uint32_t input_pixel,
+ uint16_t *matrix_vector,
+ uint16_t *bv,
+ uint16_t *clamp_vector)
+{
+ uint8_t input_C2, input_C0, input_C1;
+ uint32_t output;
+ int32_t comp_C2, comp_C1, comp_C0, temp;
+ int32_t temp1, temp2, temp3;
+ int32_t matrix[9];
+ int32_t bias_vector[3];
+ int32_t Y_low_limit, Y_high_limit, C_low_limit, C_high_limit;
+ int32_t i;
+
+ input_C2 = (input_pixel >> 16) & 0xFF;
+ input_C1 = (input_pixel >> 8) & 0xFF;
+ input_C0 = (input_pixel >> 0) & 0xFF;
+
+ comp_C0 = input_C0;
+ comp_C1 = input_C1;
+ comp_C2 = input_C2;
+
+ for (i = 0; i < MDP_CSC_SIZE; i++)
+ matrix[i] =
+ ((int32_t) (((int32_t) matrix_vector[i]) << 20)) >> 20;
+
+ bias_vector[0] = (int32_t) (bv[0] & 0xFF);
+ bias_vector[1] = (int32_t) (bv[1] & 0xFF);
+ bias_vector[2] = (int32_t) (bv[2] & 0xFF);
+
+ Y_low_limit = (int32_t) clamp_vector[0];
+ Y_high_limit = (int32_t) clamp_vector[1];
+ C_low_limit = (int32_t) clamp_vector[2];
+ C_high_limit = (int32_t) clamp_vector[3];
+
+ /*
+ * Color Conversion
+ * reorder input colors
+ */
+ temp = comp_C2;
+ comp_C2 = comp_C1;
+ comp_C1 = comp_C0;
+ comp_C0 = temp;
+
+ /* matrix multiplication */
+ temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2];
+ temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5];
+ temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8];
+
+ comp_C0 = temp1 + 0x100;
+ comp_C1 = temp2 + 0x100;
+ comp_C2 = temp3 + 0x100;
+
+ /* take interger part */
+ comp_C0 >>= 9;
+ comp_C1 >>= 9;
+ comp_C2 >>= 9;
+
+ /* post bias (+) */
+ comp_C0 += bias_vector[0];
+ comp_C1 += bias_vector[1];
+ comp_C2 += bias_vector[2];
+
+ /* limit pixel to 8-bit */
+ comp_C0 = comp_conv_rgb2yuv(comp_C0, Y_high_limit,
+ Y_low_limit, C_high_limit, C_low_limit);
+ comp_C1 = comp_conv_rgb2yuv(comp_C1, Y_high_limit,
+ Y_low_limit, C_high_limit, C_low_limit);
+ comp_C2 = comp_conv_rgb2yuv(comp_C2, Y_high_limit,
+ Y_low_limit, C_high_limit, C_low_limit);
+
+ output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0;
+ return output;
+}
+
+inline void y_h_even_num(struct ppp_img_desc *img)
+{
+ img->roi.y = (img->roi.y / 2) * 2;
+ img->roi.height = (img->roi.height / 2) * 2;
+}
+
+inline void x_w_even_num(struct ppp_img_desc *img)
+{
+ img->roi.x = (img->roi.x / 2) * 2;
+ img->roi.width = (img->roi.width / 2) * 2;
+}
+
+bool check_if_rgb(int color)
+{
+ bool rgb = false;
+ switch (color) {
+ case MDP_RGB_565:
+ case MDP_BGR_565:
+ case MDP_RGB_888:
+ case MDP_BGR_888:
+ case MDP_BGRA_8888:
+ case MDP_RGBA_8888:
+ case MDP_ARGB_8888:
+ case MDP_XRGB_8888:
+ case MDP_RGBX_8888:
+ rgb = true;
+ default:
+ break;
+ }
+ return rgb;
+}
+
+static uint8_t *mdp_adjust_rot_addr(struct ppp_blit_op *iBuf,
+ uint8_t *addr, uint32_t bpp, uint32_t uv)
+{
+ uint32_t dest_ystride = iBuf->dst.prop.width * bpp;
+ uint32_t h_slice = 1;
+ if (0)
+ return 0;
+
+ if (uv && ((iBuf->dst.color_fmt == MDP_Y_CBCR_H2V2) ||
+ (iBuf->dst.color_fmt == MDP_Y_CRCB_H2V2)))
+ h_slice = 2;
+
+ if (((iBuf->mdp_op & MDPOP_ROT90) == MDPOP_ROT90) ^
+ ((iBuf->mdp_op & MDPOP_LR) == MDPOP_LR)) {
+ addr +=
+ (iBuf->dst.roi.width -
+ MIN(16, iBuf->dst.roi.width)) * bpp;
+ }
+ if ((iBuf->mdp_op & MDPOP_UD) == MDPOP_UD) {
+ if (1) {
+ addr +=
+ ((iBuf->dst.roi.height -
+ MIN(16, iBuf->dst.roi.height))/h_slice) *
+ dest_ystride;
+ } else {
+ addr +=
+ (iBuf->dst.roi.width -
+ MIN(16, iBuf->dst.roi.width)) * bpp;
+ }
+ }
+
+ return addr;
+}
+
+void mdp_adjust_start_addr(struct ppp_blit_op *blit_op,
+ struct ppp_img_desc *img, int v_slice,
+ int h_slice, int layer)
+{
+ uint32_t bpp = ppp_bpp(img->color_fmt);
+ int x = img->roi.x;
+ int y = img->roi.y;
+ uint32_t width = img->prop.width;
+
+ if (img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO && layer == 0)
+ img->p0 += (x + y * ALIGN(width, 32)) * bpp;
+ else
+ img->p0 += (x + y * width) * bpp;
+ if (layer != 0)
+ img->p0 = mdp_adjust_rot_addr(blit_op, img->p0, bpp, 0);
+
+ if (img->p1) {
+ /*
+ * MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now
+ * we need to shift x direction same as y dir for offsite
+ */
+ if (img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO
+ && layer == 0)
+ img->p1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 :
+ (((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2))))
+ * bpp;
+ else
+ img->p1 += ((x / h_slice) * h_slice +
+ ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
+ if (layer != 0)
+ img->p1 = mdp_adjust_rot_addr(blit_op, img->p1, bpp, 1);
+ }
+}
+
+int load_ppp_lut(int tableType, uint32_t *lut)
+{
+ int i;
+ uint32_t base_addr;
+
+ base_addr = tableType ? MDP3_PPP_POST_LUT : MDP3_PPP_PRE_LUT;
+ for (i = 0; i < PPP_LUT_MAX; i++)
+ PPP_WRITEL(lut[i], base_addr + MDP3_PPP_LUTn(i));
+
+ return 0;
+}
+
+/* Configure Primary CSC Matrix */
+int load_primary_matrix(struct ppp_csc_table *csc)
+{
+ int i;
+
+ for (i = 0; i < MDP_CSC_SIZE; i++)
+ PPP_WRITEL(csc->fwd_matrix[i], MDP3_PPP_CSC_PFMVn(i));
+
+ for (i = 0; i < MDP_CSC_SIZE; i++)
+ PPP_WRITEL(csc->rev_matrix[i], MDP3_PPP_CSC_PRMVn(i));
+
+ for (i = 0; i < MDP_BV_SIZE; i++)
+ PPP_WRITEL(csc->bv[i], MDP3_PPP_CSC_PBVn(i));
+
+ for (i = 0; i < MDP_LV_SIZE; i++)
+ PPP_WRITEL(csc->lv[i], MDP3_PPP_CSC_PLVn(i));
+
+ return 0;
+}
+
+/* Load Secondary CSC Matrix */
+int load_secondary_matrix(struct ppp_csc_table *csc)
+{
+ int i;
+
+ for (i = 0; i < MDP_CSC_SIZE; i++)
+ PPP_WRITEL(csc->fwd_matrix[i], MDP3_PPP_CSC_SFMVn(i));
+
+ for (i = 0; i < MDP_CSC_SIZE; i++)
+ PPP_WRITEL(csc->rev_matrix[i], MDP3_PPP_CSC_SRMVn(i));
+
+ for (i = 0; i < MDP_BV_SIZE; i++)
+ PPP_WRITEL(csc->bv[i], MDP3_PPP_CSC_SBVn(i));
+
+ for (i = 0; i < MDP_LV_SIZE; i++)
+ PPP_WRITEL(csc->lv[i], MDP3_PPP_CSC_SLVn(i));
+ return 0;
+}
+
+int load_csc_matrix(int matrix_type, struct ppp_csc_table *csc)
+{
+ if (matrix_type == CSC_PRIMARY_MATRIX)
+ return load_primary_matrix(csc);
+
+ return load_secondary_matrix(csc);
+}
+
+int config_ppp_src(struct ppp_img_desc *src)
+{
+ uint32_t val;
+
+ val = ((src->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) |
+ (src->roi.width & MDP3_PPP_XY_MASK);
+ PPP_WRITEL(val, MDP3_PPP_SRC_SIZE);
+
+ PPP_WRITEL(src->p0, MDP3_PPP_SRCP0_ADDR);
+ PPP_WRITEL(src->p1, MDP3_PPP_SRCP1_ADDR);
+ PPP_WRITEL(src->p3, MDP3_PPP_SRCP3_ADDR);
+
+ val = (src->stride0 & MDP3_PPP_STRIDE_MASK) |
+ ((src->stride1 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_SRC_YSTRIDE1_ADDR);
+ val = ((src->stride2 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_SRC_YSTRIDE2_ADDR);
+
+ val = ppp_src_config(src->color_fmt);
+ val |= (src->roi.x % 2) ? PPP_SRC_BPP_ROI_ODD_X : 0;
+ val |= (src->roi.y % 2) ? PPP_SRC_BPP_ROI_ODD_Y : 0;
+ PPP_WRITEL(val, MDP3_PPP_SRC_FORMAT);
+ PPP_WRITEL(ppp_pack_pattern(src->color_fmt),
+ MDP3_PPP_SRC_UNPACK_PATTERN1);
+ return 0;
+}
+
+int config_ppp_out(struct ppp_img_desc *dst)
+{
+ uint32_t val;
+ bool pseudoplanr_output = false;
+
+ switch (dst->color_fmt) {
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ pseudoplanr_output = true;
+ break;
+ default:
+ break;
+ }
+ val = ppp_out_config(dst->color_fmt);
+ if (pseudoplanr_output)
+ val |= PPP_DST_PLANE_PSEUDOPLN;
+ PPP_WRITEL(val, MDP3_PPP_OUT_FORMAT);
+ PPP_WRITEL(ppp_pack_pattern(dst->color_fmt),
+ MDP3_PPP_OUT_PACK_PATTERN1);
+
+ val = ((dst->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) |
+ (dst->roi.width & MDP3_PPP_XY_MASK);
+ PPP_WRITEL(val, MDP3_PPP_OUT_SIZE);
+
+ PPP_WRITEL(dst->p0, MDP3_PPP_OUTP0_ADDR);
+ PPP_WRITEL(dst->p1, MDP3_PPP_OUTP1_ADDR);
+ PPP_WRITEL(dst->p3, MDP3_PPP_OUTP3_ADDR);
+
+ val = (dst->stride0 & MDP3_PPP_STRIDE_MASK) |
+ ((dst->stride1 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_OUT_YSTRIDE1_ADDR);
+ val = ((dst->stride2 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_OUT_YSTRIDE2_ADDR);
+ return 0;
+}
+
+int config_ppp_background(struct ppp_img_desc *bg)
+{
+ uint32_t val;
+
+ PPP_WRITEL(bg->p0, MDP3_PPP_BGP0_ADDR);
+ PPP_WRITEL(bg->p1, MDP3_PPP_BGP1_ADDR);
+ PPP_WRITEL(bg->p3, MDP3_PPP_BGP3_ADDR);
+
+ val = (bg->stride0 & MDP3_PPP_STRIDE_MASK) |
+ ((bg->stride1 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_BG_YSTRIDE1_ADDR);
+ val = ((bg->stride2 & MDP3_PPP_STRIDE_MASK) <<
+ MDP3_PPP_STRIDE1_OFFSET);
+ PPP_WRITEL(val, MDP3_PPP_BG_YSTRIDE2_ADDR);
+
+ PPP_WRITEL(ppp_src_config(bg->color_fmt),
+ MDP3_PPP_BG_FORMAT);
+ PPP_WRITEL(ppp_pack_pattern(bg->color_fmt),
+ MDP3_PPP_BG_UNPACK_PATTERN1);
+ return 0;
+}
+
+void ppp_edge_rep_luma_pixel(struct ppp_blit_op *blit_op,
+ struct ppp_edge_rep *er)
+{
+ if (blit_op->mdp_op & MDPOP_ASCALE) {
+
+ er->is_scale_enabled = 1;
+
+ if (blit_op->mdp_op & MDPOP_ROT90) {
+ er->dst_roi_width = blit_op->dst.roi.height;
+ er->dst_roi_height = blit_op->dst.roi.width;
+ } else {
+ er->dst_roi_width = blit_op->dst.roi.width;
+ er->dst_roi_height = blit_op->dst.roi.height;
+ }
+
+ /*
+ * Find out the luma pixels needed for scaling in the
+ * x direction (LEFT and RIGHT). Locations of pixels are
+ * relative to the ROI. Upper-left corner of ROI corresponds
+ * to coordinates (0,0). Also set the number of luma pixel
+ * to repeat.
+ */
+ if (blit_op->src.roi.width > 3 * er->dst_roi_width) {
+ /* scale factor < 1/3 */
+ er->luma_interp_point_right =
+ (blit_op->src.roi.width - 1);
+ } else if (blit_op->src.roi.width == 3 * er->dst_roi_width) {
+ /* scale factor == 1/3 */
+ er->luma_interp_point_right =
+ (blit_op->src.roi.width - 1) + 1;
+ er->luma_repeat_right = 1;
+ } else if ((blit_op->src.roi.width > er->dst_roi_width) &&
+ (blit_op->src.roi.width < 3 * er->dst_roi_width)) {
+ /* 1/3 < scale factor < 1 */
+ er->luma_interp_point_left = -1;
+ er->luma_interp_point_right =
+ (blit_op->src.roi.width - 1) + 1;
+ er->luma_repeat_left = 1;
+ er->luma_repeat_right = 1;
+ } else if (blit_op->src.roi.width == er->dst_roi_width) {
+ /* scale factor == 1 */
+ er->luma_interp_point_left = -1;
+ er->luma_interp_point_right =
+ (blit_op->src.roi.width - 1) + 2;
+ er->luma_repeat_left = 1;
+ er->luma_repeat_right = 2;
+ } else {
+ /* scale factor > 1 */
+ er->luma_interp_point_left = -2;
+ er->luma_interp_point_right =
+ (blit_op->src.roi.width - 1) + 2;
+ er->luma_repeat_left = 2;
+ er->luma_repeat_right = 2;
+ }
+
+ /*
+ * Find out the number of pixels needed for scaling in the
+ * y direction (TOP and BOTTOM). Locations of pixels are
+ * relative to the ROI. Upper-left corner of ROI corresponds
+ * to coordinates (0,0). Also set the number of luma pixel
+ * to repeat.
+ */
+ if (blit_op->src.roi.height > 3 * er->dst_roi_height) {
+ er->luma_interp_point_bottom =
+ (blit_op->src.roi.height - 1);
+ } else if (blit_op->src.roi.height == 3 * er->dst_roi_height) {
+ er->luma_interp_point_bottom =
+ (blit_op->src.roi.height - 1) + 1;
+ er->luma_repeat_bottom = 1;
+ } else if ((blit_op->src.roi.height > er->dst_roi_height) &&
+ (blit_op->src.roi.height < 3 * er->dst_roi_height)) {
+ er->luma_interp_point_top = -1;
+ er->luma_interp_point_bottom =
+ (blit_op->src.roi.height - 1) + 1;
+ er->luma_repeat_top = 1;
+ er->luma_repeat_bottom = 1;
+ } else if (blit_op->src.roi.height == er->dst_roi_height) {
+ er->luma_interp_point_top = -1;
+ er->luma_interp_point_bottom =
+ (blit_op->src.roi.height - 1) + 2;
+ er->luma_repeat_top = 1;
+ er->luma_repeat_bottom = 2;
+ } else {
+ er->luma_interp_point_top = -2;
+ er->luma_interp_point_bottom =
+ (blit_op->src.roi.height - 1) + 2;
+ er->luma_repeat_top = 2;
+ er->luma_repeat_bottom = 2;
+ }
+ } else {
+ /*
+ * Since no scaling needed, Tile Fetch does not require any
+ * more luma pixel than what the ROI contains.
+ */
+ er->luma_interp_point_right =
+ (int32_t) (blit_op->src.roi.width - 1);
+ er->luma_interp_point_bottom =
+ (int32_t) (blit_op->src.roi.height - 1);
+ }
+ /* After adding the ROI offsets, we have locations of
+ * luma_interp_points relative to the image.
+ */
+ er->luma_interp_point_left += (int32_t) (blit_op->src.roi.x);
+ er->luma_interp_point_right += (int32_t) (blit_op->src.roi.x);
+ er->luma_interp_point_top += (int32_t) (blit_op->src.roi.y);
+ er->luma_interp_point_bottom += (int32_t) (blit_op->src.roi.y);
+}
+
+void ppp_edge_rep_chroma_pixel(struct ppp_blit_op *blit_op,
+ struct ppp_edge_rep *er)
+{
+ bool chroma_edge_enable = true;
+ uint32_t is_yuv_offsite_vertical = 0;
+
+ /* find out which chroma pixels are needed for chroma upsampling. */
+ switch (blit_op->src.color_fmt) {
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ er->chroma_interp_point_left = er->luma_interp_point_left >> 1;
+ er->chroma_interp_point_right =
+ (er->luma_interp_point_right + 1) >> 1;
+ er->chroma_interp_point_top = er->luma_interp_point_top;
+ er->chroma_interp_point_bottom = er->luma_interp_point_bottom;
+ break;
+
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CBCR_H2V2_ADRENO:
+ case MDP_Y_CRCB_H2V2:
+ er->chroma_interp_point_left = er->luma_interp_point_left >> 1;
+ er->chroma_interp_point_right =
+ (er->luma_interp_point_right + 1) >> 1;
+ er->chroma_interp_point_top =
+ (er->luma_interp_point_top - 1) >> 1;
+ er->chroma_interp_point_bottom =
+ (er->luma_interp_point_bottom + 1) >> 1;
+ is_yuv_offsite_vertical = 1;
+ break;
+
+ default:
+ chroma_edge_enable = false;
+ er->chroma_interp_point_left = er->luma_interp_point_left;
+ er->chroma_interp_point_right = er->luma_interp_point_right;
+ er->chroma_interp_point_top = er->luma_interp_point_top;
+ er->chroma_interp_point_bottom = er->luma_interp_point_bottom;
+
+ break;
+ }
+
+ if (chroma_edge_enable) {
+ /* Defines which chroma pixels belongs to the roi */
+ switch (blit_op->src.color_fmt) {
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ er->chroma_bound_left = blit_op->src.roi.x / 2;
+ /* there are half as many chroma pixel as luma pixels */
+ er->chroma_bound_right =
+ (blit_op->src.roi.width +
+ blit_op->src.roi.x - 1) / 2;
+ er->chroma_bound_top = blit_op->src.roi.y;
+ er->chroma_bound_bottom =
+ (blit_op->src.roi.height + blit_op->src.roi.y - 1);
+ break;
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CBCR_H2V2_ADRENO:
+ case MDP_Y_CRCB_H2V2:
+ /*
+ * cosite in horizontal dir, and offsite in vertical dir
+ * width of chroma ROI is 1/2 of size of luma ROI
+ * height of chroma ROI is 1/2 of size of luma ROI
+ */
+ er->chroma_bound_left = blit_op->src.roi.x / 2;
+ er->chroma_bound_right =
+ (blit_op->src.roi.width +
+ blit_op->src.roi.x - 1) / 2;
+ er->chroma_bound_top = blit_op->src.roi.y / 2;
+ er->chroma_bound_bottom =
+ (blit_op->src.roi.height +
+ blit_op->src.roi.y - 1) / 2;
+ break;
+
+ default:
+ /*
+ * If no valid chroma sub-sampling format specified,
+ * assume 4:4:4 ( i.e. fully sampled).
+ */
+ er->chroma_bound_left = blit_op->src.roi.x;
+ er->chroma_bound_right = blit_op->src.roi.width +
+ blit_op->src.roi.x - 1;
+ er->chroma_bound_top = blit_op->src.roi.y;
+ er->chroma_bound_bottom =
+ (blit_op->src.roi.height + blit_op->src.roi.y - 1);
+ break;
+ }
+
+ /*
+ * Knowing which chroma pixels are needed, and which chroma
+ * pixels belong to the ROI (i.e. available for fetching ),
+ * calculate how many chroma pixels Tile Fetch needs to
+ * duplicate. If any required chroma pixels falls outside
+ * of the ROI, Tile Fetch must obtain them by replicating
+ * pixels.
+ */
+ if (er->chroma_bound_left > er->chroma_interp_point_left)
+ er->chroma_repeat_left =
+ er->chroma_bound_left -
+ er->chroma_interp_point_left;
+ else
+ er->chroma_repeat_left = 0;
+
+ if (er->chroma_interp_point_right > er->chroma_bound_right)
+ er->chroma_repeat_right =
+ er->chroma_interp_point_right -
+ er->chroma_bound_right;
+ else
+ er->chroma_repeat_right = 0;
+
+ if (er->chroma_bound_top > er->chroma_interp_point_top)
+ er->chroma_repeat_top =
+ er->chroma_bound_top -
+ er->chroma_interp_point_top;
+ else
+ er->chroma_repeat_top = 0;
+
+ if (er->chroma_interp_point_bottom > er->chroma_bound_bottom)
+ er->chroma_repeat_bottom =
+ er->chroma_interp_point_bottom -
+ er->chroma_bound_bottom;
+ else
+ er->chroma_repeat_bottom = 0;
+
+ if (er->is_scale_enabled && (blit_op->src.roi.height == 1)
+ && is_yuv_offsite_vertical) {
+ er->chroma_repeat_bottom = 3;
+ er->chroma_repeat_top = 0;
+ }
+ }
+}
+
+int config_ppp_edge_rep(struct ppp_blit_op *blit_op)
+{
+ uint32_t reg = 0;
+ struct ppp_edge_rep er;
+
+ memset(&er, 0, sizeof(er));
+
+ ppp_edge_rep_luma_pixel(blit_op, &er);
+
+ /*
+ * After adding the ROI offsets, we have locations of
+ * chroma_interp_points relative to the image.
+ */
+ er.chroma_interp_point_left = er.luma_interp_point_left;
+ er.chroma_interp_point_right = er.luma_interp_point_right;
+ er.chroma_interp_point_top = er.luma_interp_point_top;
+ er.chroma_interp_point_bottom = er.luma_interp_point_bottom;
+
+ ppp_edge_rep_chroma_pixel(blit_op, &er);
+ /* ensure repeats are >=0 and no larger than 3 pixels */
+ if ((er.chroma_repeat_left < 0) || (er.chroma_repeat_right < 0) ||
+ (er.chroma_repeat_top < 0) || (er.chroma_repeat_bottom < 0))
+ return -EINVAL;
+ if ((er.chroma_repeat_left > 3) || (er.chroma_repeat_right > 3) ||
+ (er.chroma_repeat_top > 3) || (er.chroma_repeat_bottom > 3))
+ return -EINVAL;
+ if ((er.luma_repeat_left < 0) || (er.luma_repeat_right < 0) ||
+ (er.luma_repeat_top < 0) || (er.luma_repeat_bottom < 0))
+ return -EINVAL;
+ if ((er.luma_repeat_left > 3) || (er.luma_repeat_right > 3) ||
+ (er.luma_repeat_top > 3) || (er.luma_repeat_bottom > 3))
+ return -EINVAL;
+
+ reg |= (er.chroma_repeat_left & 3) << MDP_LEFT_CHROMA;
+ reg |= (er.chroma_repeat_right & 3) << MDP_RIGHT_CHROMA;
+ reg |= (er.chroma_repeat_top & 3) << MDP_TOP_CHROMA;
+ reg |= (er.chroma_repeat_bottom & 3) << MDP_BOTTOM_CHROMA;
+ reg |= (er.luma_repeat_left & 3) << MDP_LEFT_LUMA;
+ reg |= (er.luma_repeat_right & 3) << MDP_RIGHT_LUMA;
+ reg |= (er.luma_repeat_top & 3) << MDP_TOP_LUMA;
+ reg |= (er.luma_repeat_bottom & 3) << MDP_BOTTOM_LUMA;
+ PPP_WRITEL(reg, MDP3_PPP_SRC_EDGE_REP);
+ return 0;
+}
+
+int config_ppp_bg_edge_rep(struct ppp_blit_op *blit_op)
+{
+ uint32_t reg = 0;
+
+ switch (blit_op->dst.color_fmt) {
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ if (blit_op->dst.roi.y == 0)
+ reg |= BIT(MDP_TOP_CHROMA);
+
+ if ((blit_op->dst.roi.y + blit_op->dst.roi.height) ==
+ blit_op->dst.prop.height) {
+ reg |= BIT(MDP_BOTTOM_CHROMA);
+ }
+
+ if (((blit_op->dst.roi.x + blit_op->dst.roi.width) ==
+ blit_op->dst.prop.width) &&
+ ((blit_op->dst.roi.width % 2) == 0))
+ reg |= BIT(MDP_RIGHT_CHROMA);
+ break;
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ if (((blit_op->dst.roi.x + blit_op->dst.roi.width) ==
+ blit_op->dst.prop.width) &&
+ ((blit_op->dst.roi.width % 2) == 0))
+ reg |= BIT(MDP_RIGHT_CHROMA);
+ break;
+ default:
+ break;
+ }
+ PPP_WRITEL(reg, MDP3_PPP_BG_EDGE_REP);
+ return 0;
+}
+
+int config_ppp_lut(uint32_t *pppop_reg_ptr, int lut_c0_en,
+ int lut_c1_en, int lut_c2_en)
+{
+ if (lut_c0_en)
+ *pppop_reg_ptr |= MDP_LUT_C0_EN;
+ if (lut_c1_en)
+ *pppop_reg_ptr |= MDP_LUT_C1_EN;
+ if (lut_c2_en)
+ *pppop_reg_ptr |= MDP_LUT_C2_EN;
+ return 0;
+}
+
+int config_ppp_scale(struct ppp_blit_op *blit_op, uint32_t *pppop_reg_ptr)
+{
+ struct ppp_img_desc *src = &blit_op->src;
+ struct ppp_img_desc *dst = &blit_op->dst;
+ uint32_t dstW, dstH;
+ uint32_t x_fac, y_fac;
+ uint32_t mdp_blur = 0;
+ uint32_t phase_init_x, phase_init_y, phase_step_x, phase_step_y;
+ int x_idx, y_idx;
+
+ if (blit_op->mdp_op & MDPOP_ASCALE) {
+ if (blit_op->mdp_op & MDPOP_ROT90) {
+ dstW = dst->roi.height;
+ dstH = dst->roi.width;
+ } else {
+ dstW = dst->roi.width;
+ dstH = dst->roi.height;
+ }
+ *pppop_reg_ptr |=
+ (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
+
+ mdp_blur = blit_op->mdp_op & MDPOP_BLUR;
+
+ if ((dstW != src->roi.width) ||
+ (dstH != src->roi.height) || mdp_blur) {
+
+ mdp_calc_scale_params(blit_op->src.roi.x,
+ blit_op->src.roi.width,
+ dstW, 1, &phase_init_x,
+ &phase_step_x);
+ mdp_calc_scale_params(blit_op->src.roi.y,
+ blit_op->src.roi.height,
+ dstH, 0, &phase_init_y,
+ &phase_step_y);
+
+ PPP_WRITEL(phase_init_x, MDP3_PPP_SCALE_PHASEX_INIT);
+ PPP_WRITEL(phase_init_y, MDP3_PPP_SCALE_PHASEY_INIT);
+ PPP_WRITEL(phase_step_x, MDP3_PPP_SCALE_PHASEX_STEP);
+ PPP_WRITEL(phase_step_y, MDP3_PPP_SCALE_PHASEY_STEP);
+
+
+ if (dstW > src->roi.width || dstW > src->roi.height)
+ ppp_load_up_lut();
+
+ if (mdp_blur)
+ ppp_load_gaussian_lut();
+
+ if (dstW <= src->roi.width) {
+ x_fac = (dstW * 100) / src->roi.width;
+ x_idx = scale_idx(x_fac);
+ ppp_load_x_scale_table(x_idx);
+ }
+ if (dstH <= src->roi.height) {
+ y_fac = (dstH * 100) / src->roi.height;
+ y_idx = scale_idx(y_fac);
+ ppp_load_y_scale_table(y_idx);
+ }
+
+ } else {
+ blit_op->mdp_op &= ~(MDPOP_ASCALE);
+ }
+ }
+ config_ppp_edge_rep(blit_op);
+ config_ppp_bg_edge_rep(blit_op);
+ return 0;
+}
+
+int config_ppp_csc(int src_color, int dst_color, uint32_t *pppop_reg_ptr)
+{
+ bool inputRGB, outputRGB;
+
+ inputRGB = check_if_rgb(src_color);
+ outputRGB = check_if_rgb(dst_color);
+
+ if ((!inputRGB) && (outputRGB))
+ *pppop_reg_ptr |= PPP_OP_CONVERT_YCBCR2RGB |
+ PPP_OP_CONVERT_ON;
+ if ((inputRGB) && (!outputRGB))
+ *pppop_reg_ptr |= PPP_OP_CONVERT_ON;
+
+ return 0;
+}
+
+int config_ppp_blend(struct ppp_blit_op *blit_op,
+ uint32_t *pppop_reg_ptr)
+{
+ struct ppp_csc_table *csc;
+ uint32_t alpha, trans_color;
+ uint32_t val = 0;
+ int c_fmt = blit_op->src.color_fmt;
+ int bg_alpha;
+
+ csc = ppp_csc_rgb2yuv();
+ alpha = blit_op->blend.const_alpha;
+ trans_color = blit_op->blend.trans_color;
+ if (blit_op->mdp_op & MDPOP_FG_PM_ALPHA) {
+ if (ppp_per_p_alpha(c_fmt)) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA;
+ } else {
+ if ((blit_op->mdp_op & MDPOP_ALPHAB)
+ && (blit_op->blend.const_alpha == 0xff)) {
+ blit_op->mdp_op &= ~(MDPOP_ALPHAB);
+ }
+
+ if ((blit_op->mdp_op & MDPOP_ALPHAB)
+ || (blit_op->mdp_op & MDPOP_TRANSP)) {
+
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA |
+ PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+ }
+ }
+
+ bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
+ PPP_BLEND_BG_ALPHA_REVERSE;
+
+ if ((ppp_per_p_alpha(c_fmt)) && !(blit_op->mdp_op &
+ MDPOP_LAYER_IS_FG)) {
+ bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA;
+ } else {
+ bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA;
+ bg_alpha |= blit_op->blend.const_alpha << 24;
+ }
+ PPP_WRITEL(bg_alpha, MDP3_PPP_BLEND_BG_ALPHA_SEL);
+
+ if (blit_op->mdp_op & MDPOP_TRANSP)
+ *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
+ } else if (ppp_per_p_alpha(c_fmt)) {
+ if (blit_op->mdp_op & MDPOP_LAYER_IS_FG)
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA;
+ else
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_SRCPIXEL_ALPHA;
+ PPP_WRITEL(0, MDP3_PPP_BLEND_BG_ALPHA_SEL);
+ } else {
+ if ((blit_op->mdp_op & MDPOP_ALPHAB)
+ && (blit_op->blend.const_alpha == 0xff)) {
+ blit_op->mdp_op &=
+ ~(MDPOP_ALPHAB);
+ }
+
+ if ((blit_op->mdp_op & MDPOP_ALPHAB)
+ || (blit_op->mdp_op & MDPOP_TRANSP)) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA |
+ PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+ }
+
+ if (blit_op->mdp_op & MDPOP_TRANSP)
+ *pppop_reg_ptr |=
+ PPP_BLEND_CALPHA_TRNASP;
+ PPP_WRITEL(0, MDP3_PPP_BLEND_BG_ALPHA_SEL);
+ }
+
+ if (*pppop_reg_ptr & PPP_OP_BLEND_ON) {
+ blit_op->bg = blit_op->dst;
+ config_ppp_background(&blit_op->bg);
+
+ if (blit_op->dst.color_fmt == MDP_YCRYCB_H2V1) {
+ *pppop_reg_ptr |= PPP_OP_BG_CHROMA_H2V1;
+ if (blit_op->mdp_op & MDPOP_TRANSP) {
+ trans_color = conv_rgb2yuv(trans_color,
+ &csc->fwd_matrix[0],
+ &csc->bv[0],
+ &csc->lv[0]);
+ }
+ }
+ }
+ val = (alpha << MDP_BLEND_CONST_ALPHA);
+ val |= (trans_color & MDP_BLEND_TRASP_COL_MASK);
+ PPP_WRITEL(val, MDP3_PPP_BLEND_PARAM);
+ return 0;
+}
+
+int config_ppp_rotation(uint32_t mdp_op, uint32_t *pppop_reg_ptr)
+{
+ *pppop_reg_ptr |= PPP_OP_ROT_ON;
+
+ if (mdp_op & MDPOP_ROT90)
+ *pppop_reg_ptr |= PPP_OP_ROT_90;
+ if (mdp_op & MDPOP_LR)
+ *pppop_reg_ptr |= PPP_OP_FLIP_LR;
+ if (mdp_op & MDPOP_UD)
+ *pppop_reg_ptr |= PPP_OP_FLIP_UD;
+
+ return 0;
+}
+
+int config_ppp_op_mode(struct ppp_blit_op *blit_op)
+{
+ uint32_t ppp_operation_reg = 0;
+ int sv_slice, sh_slice;
+ int dv_slice, dh_slice;
+
+ sv_slice = sh_slice = dv_slice = dh_slice = 1;
+
+ ppp_operation_reg |= ppp_dst_op_reg(blit_op->dst.color_fmt);
+ switch (blit_op->dst.color_fmt) {
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ y_h_even_num(&blit_op->dst);
+ y_h_even_num(&blit_op->src);
+ dv_slice = 2;
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ x_w_even_num(&blit_op->dst);
+ x_w_even_num(&blit_op->src);
+ dh_slice = 2;
+ break;
+ default:
+ break;
+ }
+
+ ppp_operation_reg |= ppp_src_op_reg(blit_op->src.color_fmt);
+ switch (blit_op->src.color_fmt) {
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CBCR_H2V2_ADRENO:
+ case MDP_Y_CRCB_H2V2:
+ sh_slice = sv_slice = 2;
+ break;
+ case MDP_YCRYCB_H2V1:
+ x_w_even_num(&blit_op->dst);
+ x_w_even_num(&blit_op->src);
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ sh_slice = 2;
+ break;
+ default:
+ break;
+ }
+
+ config_ppp_csc(blit_op->src.color_fmt,
+ blit_op->dst.color_fmt, &ppp_operation_reg);
+
+ if (blit_op->mdp_op & MDPOP_DITHER)
+ ppp_operation_reg |= PPP_OP_DITHER_EN;
+
+ if (blit_op->mdp_op & MDPOP_ROTATION)
+ config_ppp_rotation(blit_op->mdp_op, &ppp_operation_reg);
+
+ if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_ADRENO) {
+ blit_op->src.stride0 = ALIGN(blit_op->src.prop.width, 32) *
+ ppp_bpp(blit_op->src.color_fmt);
+ blit_op->src.stride1 = 2 * ALIGN(blit_op->src.prop.width/2, 32);
+ } else {
+ blit_op->src.stride0 = blit_op->src.prop.width *
+ ppp_bpp(blit_op->src.color_fmt);
+ blit_op->src.stride1 = blit_op->src.stride0;
+ }
+
+ blit_op->dst.stride0 = blit_op->dst.prop.width *
+ ppp_bpp(blit_op->dst.color_fmt);
+
+ if (ppp_multi_plane(blit_op->dst.color_fmt)) {
+ blit_op->dst.p1 = blit_op->dst.p0;
+ blit_op->dst.p1 += blit_op->dst.prop.width *
+ blit_op->dst.prop.height *
+ ppp_bpp(blit_op->dst.color_fmt);
+ } else {
+ blit_op->dst.p1 = NULL;
+ }
+
+ /* Jumping from Y-Plane to Chroma Plane */
+ /* first pixel addr calculation */
+ mdp_adjust_start_addr(blit_op, &blit_op->src, sv_slice, sh_slice, 0);
+ mdp_adjust_start_addr(blit_op, &blit_op->dst, dv_slice, dh_slice, 2);
+
+ config_ppp_scale(blit_op, &ppp_operation_reg);
+
+ config_ppp_blend(blit_op, &ppp_operation_reg);
+
+ config_ppp_src(&blit_op->src);
+ config_ppp_out(&blit_op->dst);
+ PPP_WRITEL(ppp_operation_reg, MDP3_PPP_OP_MODE);
+ mb();
+ return 0;
+}
+
+void ppp_enable(void)
+{
+ PPP_WRITEL(0x1000, 0x30);
+ mb();
+}
+
+int mdp3_ppp_init(void)
+{
+ load_ppp_lut(LUT_PRE_TABLE, ppp_default_pre_lut());
+ load_ppp_lut(LUT_POST_TABLE, ppp_default_post_lut());
+ load_csc_matrix(CSC_PRIMARY_MATRIX, ppp_csc_rgb2yuv());
+ load_csc_matrix(CSC_SECONDARY_MATRIX, ppp_csc_table2());
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 5d56df4..c663170 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -408,12 +408,14 @@
pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
ctrl_pdata, ctrl_pdata->ndx);
- mdss_dsi_clk_disable(pdata);
- mdss_dsi_unprepare_clocks(ctrl_pdata);
+ if (pdata->panel_info.type == MIPI_CMD_PANEL)
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
/* disable DSI controller */
mdss_dsi_controller_cfg(0, pdata);
+ mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+
/* disable DSI phy */
mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
ret = mdss_dsi_panel_power_on(pdata, 0);
@@ -431,6 +433,7 @@
{
int ret = 0;
struct mipi_panel_info *mipi;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__);
@@ -439,20 +442,24 @@
return -EINVAL;
}
- mipi = &pdata->panel_info.mipi;
+ mipi = &pdata->panel_info.mipi;
- ret = mdss_dsi_panel_power_on(pdata, 1);
- if (ret) {
- pr_err("%s: Panel power on failed\n", __func__);
- return ret;
- }
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
+ ctrl_pdata, ctrl_pdata->ndx);
+
+ WARN(ctrl_pdata->panel_state != UNKNOWN_STATE,
+ "incorrect panel state=%d\n", ctrl_pdata->panel_state);
+
mdss_dsi_sw_reset(pdata);
mdss_dsi_host_init(mipi, pdata);
- pdata->panel_info.panel_power_on = 1;
-
mdss_dsi_op_mode_config(mipi->mode, pdata);
+ ctrl_pdata->panel_state = PANEL_ON;
+
pr_debug("%s-:End\n", __func__);
return ret;
}
@@ -498,8 +505,7 @@
mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
mdss_dsi_phy_init(pdata);
- mdss_dsi_prepare_clocks(ctrl_pdata);
- mdss_dsi_clk_enable(pdata);
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
clk_rate = pdata->panel_info.clk_rate;
clk_rate = min(clk_rate, pdata->panel_info.clk_max);
@@ -577,6 +583,9 @@
wmb();
}
+ if (pdata->panel_info.type == MIPI_CMD_PANEL)
+ mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+
pr_debug("%s-:\n", __func__);
return 0;
}
@@ -598,12 +607,15 @@
panel_data);
mipi = &pdata->panel_info.mipi;
- ret = ctrl_pdata->on(pdata);
- if (ret) {
- pr_err("%s: unable to initialize the panel\n", __func__);
- return ret;
+ if (ctrl_pdata->panel_state != PANEL_ON) {
+ ret = ctrl_pdata->on(pdata);
+ if (ret) {
+ pr_err("%s: unable to initialize the panel\n",
+ __func__);
+ return ret;
+ }
+ ctrl_pdata->panel_state = PANEL_ON;
}
-
mdss_dsi_op_mode_config(mipi->mode, pdata);
pr_debug("%s-:\n", __func__);
@@ -628,12 +640,14 @@
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
- ret = ctrl_pdata->off(pdata);
- if (ret) {
- pr_err("%s: Panel OFF failed\n", __func__);
- return ret;
+ if (ctrl_pdata->panel_state == PANEL_ON) {
+ ret = ctrl_pdata->off(pdata);
+ if (ret) {
+ pr_err("%s: Panel OFF failed\n", __func__);
+ return ret;
+ }
+ ctrl_pdata->panel_state = PANEL_OFF;
}
-
pr_debug("%s-:End\n", __func__);
return ret;
}
@@ -655,35 +669,38 @@
switch (event) {
case MDSS_EVENT_UNBLANK:
rc = mdss_dsi_on(pdata);
- if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) {
+ if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_unblank(pdata);
- }
break;
case MDSS_EVENT_PANEL_ON:
- if (ctrl_pdata->on_cmds->ctrl_state == DSI_HS_MODE)
+ if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE)
rc = mdss_dsi_unblank(pdata);
break;
case MDSS_EVENT_BLANK:
- if (ctrl_pdata->off_cmds->ctrl_state == DSI_HS_MODE) {
+ if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE)
rc = mdss_dsi_blank(pdata);
- }
break;
case MDSS_EVENT_PANEL_OFF:
- if (ctrl_pdata->off_cmds->ctrl_state == DSI_LP_MODE) {
+ if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_blank(pdata);
- }
rc = mdss_dsi_off(pdata);
break;
case MDSS_EVENT_CONT_SPLASH_FINISH:
- if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) {
+ if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
rc = mdss_dsi_cont_splash_on(pdata);
} else {
pr_debug("%s:event=%d, Dsi On not called: ctrl_state: %d\n",
__func__, event,
- ctrl_pdata->on_cmds->ctrl_state);
+ ctrl_pdata->on_cmds.link_state);
rc = -EINVAL;
}
break;
+ case MDSS_EVENT_PANEL_CLK_CTRL:
+ mdss_dsi_clk_req(ctrl_pdata, (int)arg);
+ break;
+ case MDSS_EVENT_DSI_CMDLIST_KOFF:
+ mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -1055,17 +1072,16 @@
ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
- ctrl_pdata->on_cmds = panel_data->dsi_panel_on_cmds;
- ctrl_pdata->off_cmds = panel_data->dsi_panel_off_cmds;
+ ctrl_pdata->on_cmds = panel_data->on_cmds;
+ ctrl_pdata->off_cmds = panel_data->off_cmds;
memcpy(&((ctrl_pdata->panel_data).panel_info),
&(panel_data->panel_info),
sizeof(struct mdss_panel_info));
- mdss_dsi_irq_handler_config(ctrl_pdata);
ctrl_pdata->panel_data.set_backlight = panel_data->bl_fnc;
ctrl_pdata->bklt_ctrl = panel_data->panel_info.bklt_ctrl;
- ctrl_pdata->pwm_gpio = panel_data->panel_info.pwm_gpio;
+ ctrl_pdata->pwm_pmic_gpio = panel_data->panel_info.pwm_pmic_gpio;
ctrl_pdata->pwm_period = panel_data->panel_info.pwm_period;
ctrl_pdata->pwm_lpg_chan = panel_data->panel_info.pwm_lpg_chan;
ctrl_pdata->bklt_max = panel_data->panel_info.bl_max;
@@ -1073,6 +1089,7 @@
if (ctrl_pdata->bklt_ctrl == BL_PWM)
mdss_dsi_panel_pwm_cfg(ctrl_pdata);
+ mdss_dsi_ctrl_init(ctrl_pdata);
/*
* register in mdp driver
*/
@@ -1090,13 +1107,20 @@
ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
ctrl_pdata->panel_data.panel_info.panel_power_on = 1;
+ rc = mdss_dsi_panel_power_on(&(ctrl_pdata->panel_data), 1);
+ if (rc) {
+ pr_err("%s: Panel power on failed\n", __func__);
+ return rc;
+ }
}
+ ctrl_pdata->pclk_rate = dsi_pclk_rate;
+ ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
+ pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
+ ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
- if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled) {
- mdss_dsi_prepare_clocks(ctrl_pdata);
- mdss_dsi_clk_enable(&(ctrl_pdata->panel_data));
- }
+ if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled)
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
if (rc) {
@@ -1111,11 +1135,6 @@
ctrl_pdata->on = panel_data->on;
ctrl_pdata->off = panel_data->off;
- ctrl_pdata->pclk_rate = dsi_pclk_rate;
- ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
- pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
- ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
-
if (panel_data->panel_info.pdest == DISPLAY_1) {
mdss_debug_register_base("dsi0",
ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
@@ -1126,6 +1145,7 @@
ctrl_pdata->ndx = 1;
}
+ ctrl_pdata->panel_state = UNKNOWN_STATE;
pr_debug("%s: Panal data initialized\n", __func__);
return 0;
}
@@ -1155,8 +1175,6 @@
{
int ret;
- mdss_dsi_init();
-
ret = mdss_dsi_register_driver();
if (ret) {
pr_err("mdss_dsi_register_driver() failed!\n");
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 197ff7a..602ed9e 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -89,6 +89,12 @@
DSI_HS_MODE,
};
+enum dsi_panel_state {
+ UNKNOWN_STATE,
+ PANEL_ON,
+ PANEL_OFF,
+};
+
#define DSI_NON_BURST_SYNCH_PULSE 0
#define DSI_NON_BURST_SYNCH_EVENT 1
#define DSI_BURST_MODE 2
@@ -127,6 +133,10 @@
#define DSI_CMD_TRIGGER_SW_SEOF 0x05 /* cmd dma only */
#define DSI_CMD_TRIGGER_SW_TE 0x06
+#define DSI_VIDEO_TERM BIT(16)
+#define DSI_MDP_TERM BIT(8)
+#define DSI_CMD_TERM BIT(0)
+
extern struct device dsi_dev;
extern int mdss_dsi_clk_on;
extern u32 dsi_irq;
@@ -182,7 +192,6 @@
#define DSI_HDR_DATA1(data) ((data) & 0x0ff)
#define DSI_HDR_WC(wc) ((wc) & 0x0ffff)
-#define DSI_BUF_SIZE 1024
#define MDSS_DSI_MRPS 0x04 /* Maximum Return Packet Size */
#define MDSS_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align */
@@ -234,35 +243,67 @@
#define DTYPE_DCS_READ1_RESP 0x21 /* 1 parameter, short */
#define DTYPE_DCS_READ2_RESP 0x22 /* 2 parameter, short */
+
+struct dsi_ctrl_hdr {
+ char dtype; /* data type */
+ char last; /* last in chain */
+ char vc; /* virtual chan */
+ char ack; /* ask ACK from peripheral */
+ char wait; /* ms */
+ short dlen; /* 16 bits */
+} __packed;
+
struct dsi_cmd_desc {
- int dtype;
- int last;
- int vc;
- int ack; /* ask ACK from peripheral */
- int wait;
- int dlen;
+ struct dsi_ctrl_hdr dchdr;
char *payload;
};
+struct dsi_panel_cmds {
+ char *buf;
+ int blen;
+ struct dsi_cmd_desc *cmds;
+ int cmd_cnt;
+ int link_state;
+};
+
+#define CMD_REQ_MAX 4
+
+typedef void (*fxn)(u32 data);
+
+#define CMD_REQ_RX 0x0001
+#define CMD_REQ_COMMIT 0x0002
+#define CMD_CLK_CTRL 0x0004
+#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];
+};
+
struct dsi_kickoff_action {
struct list_head act_entry;
void (*action) (void *);
void *data;
};
-struct dsi_panel_cmds_list {
- struct dsi_cmd_desc *buf;
- u32 size;
- char ctrl_state;
-};
-
struct mdss_panel_common_pdata {
struct mdss_panel_info panel_info;
int (*on) (struct mdss_panel_data *pdata);
int (*off) (struct mdss_panel_data *pdata);
void (*bl_fnc) (struct mdss_panel_data *pdata, u32 bl_level);
- struct dsi_panel_cmds_list *dsi_panel_on_cmds;
- struct dsi_panel_cmds_list *dsi_panel_off_cmds;
+
+ struct dsi_panel_cmds on_cmds;
+ struct dsi_panel_cmds off_cmds;
};
struct dsi_drv_cm_data {
@@ -272,17 +313,24 @@
int broadcast_enable;
};
+enum {
+ DSI_CTRL_0,
+ DSI_CTRL_1,
+ DSI_CTRL_MAX,
+};
+
struct mdss_dsi_ctrl_pdata {
- int ndx;
+ int ndx; /* panel_num */
int (*on) (struct mdss_panel_data *pdata);
int (*off) (struct mdss_panel_data *pdata);
struct mdss_panel_data panel_data;
- struct mdss_hw *mdss_hw;
unsigned char *ctrl_base;
int reg_size;
+ u32 clk_cnt;
struct clk *byte_clk;
struct clk *esc_clk;
struct clk *pixel_clk;
+ u8 panel_state;
int irq_cnt;
int mdss_dsi_clk_on;
int rst_gpio;
@@ -290,16 +338,32 @@
int disp_te_gpio;
int bklt_ctrl; /* backlight ctrl */
int pwm_period;
- int pwm_gpio;
+ int pwm_pmic_gpio;
int pwm_lpg_chan;
int bklt_max;
struct pwm_device *pwm_bl;
- struct dsi_panel_cmds_list *on_cmds;
- struct dsi_panel_cmds_list *off_cmds;
struct dsi_drv_cm_data shared_pdata;
u32 pclk_rate;
u32 byte_clk_rate;
struct dss_module_power power_data;
+ u32 dsi_irq_mask;
+ struct mdss_hw *dsi_hw;
+
+ struct dsi_panel_cmds on_cmds;
+ struct dsi_panel_cmds off_cmds;
+
+ struct dcs_cmd_list cmdlist;
+ struct completion dma_comp;
+ struct completion mdp_comp;
+ struct completion video_comp;
+ spinlock_t irq_lock;
+ spinlock_t mdp_lock;
+ int mdp_busy;
+ struct mutex mutex;
+ struct mutex cmd_mutex;
+
+ struct dsi_buf tx_buf;
+ struct dsi_buf rx_buf;
};
int dsi_panel_device_register(struct platform_device *pdev,
@@ -310,29 +374,26 @@
void mdss_dsi_init(void);
int mdss_dsi_buf_alloc(struct dsi_buf *, int size);
int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm);
-int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata,
- struct dsi_buf *dp, struct dsi_cmd_desc *cmds, int cnt);
+int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int cnt);
-int mdss_dsi_cmd_dma_tx(struct dsi_buf *dp,
- struct mdss_panel_data *pdata);
-int mdss_dsi_cmd_reg_tx(u32 data,
- unsigned char *ctrl_base);
-int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_buf *rp,
- struct dsi_cmd_desc *cmds, int len);
-int mdss_dsi_cmd_dma_rx(struct dsi_buf *tp, int rlen,
- struct mdss_panel_data *pdata);
+int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int rlen, u32 rx_flags);
+
void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
struct mdss_panel_data *pdata);
void mdss_dsi_op_mode_config(int mode,
struct mdss_panel_data *pdata);
void mdss_dsi_cmd_mode_ctrl(int enable);
void mdp4_dsi_cmd_trigger(void);
-void mdss_dsi_cmd_mdp_start(struct mdss_panel_data *pdata);
+void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl);
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(struct mdss_panel_data *pdata);
-void mdss_dsi_clk_disable(struct mdss_panel_data *pdata);
+void mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
+void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl,
+ int enable);
void mdss_dsi_controller_cfg(int enable,
struct mdss_panel_data *pdata);
void mdss_dsi_sw_reset(struct mdss_panel_data *pdata);
@@ -355,4 +416,13 @@
void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata);
void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *cmdreq);
+struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_cmdlist_kickoff(int intf);
+
#endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 3c0dfc2..6b210af 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -25,12 +25,11 @@
#include "mdss.h"
#include "mdss_dsi.h"
-static struct completion dsi_dma_comp;
-static spinlock_t dsi_irq_lock;
-static spinlock_t dsi_mdp_lock;
-static int dsi_mdp_busy;
static struct mdss_dsi_ctrl_pdata *left_ctrl_pdata;
+static struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
+
+
struct mdss_hw mdss_dsi0_hw = {
.hw_ndx = MDSS_HW_DSI0,
.ptr = NULL,
@@ -43,58 +42,128 @@
.irq_handler = mdss_dsi_isr,
};
-void mdss_dsi_init(void)
+void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
{
- init_completion(&dsi_dma_comp);
- spin_lock_init(&dsi_irq_lock);
- spin_lock_init(&dsi_mdp_lock);
-}
-
-void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl)
-{
- int ret;
-
if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
mdss_dsi0_hw.ptr = (void *)(ctrl);
- ctrl->mdss_hw = &mdss_dsi0_hw;
+ ctrl->dsi_hw = &mdss_dsi0_hw;
+ ctrl->ndx = DSI_CTRL_0;
} else {
mdss_dsi1_hw.ptr = (void *)(ctrl);
- ctrl->mdss_hw = &mdss_dsi1_hw;
+ ctrl->dsi_hw = &mdss_dsi1_hw;
+ ctrl->ndx = DSI_CTRL_1;
}
- ret = mdss_register_irq(ctrl->mdss_hw);
- if (ret)
+ ctrl_list[ctrl->ndx] = ctrl; /* keep it */
+
+ if (mdss_register_irq(ctrl->dsi_hw))
pr_err("%s: mdss_register_irq failed.\n", __func__);
+
+ pr_debug("%s: ndx=%d base=%p\n", __func__, ctrl->ndx, ctrl->ctrl_base);
+
+ init_completion(&ctrl->dma_comp);
+ init_completion(&ctrl->mdp_comp);
+ init_completion(&ctrl->video_comp);
+ spin_lock_init(&ctrl->irq_lock);
+ spin_lock_init(&ctrl->mdp_lock);
+ mutex_init(&ctrl->mutex);
+ mutex_init(&ctrl->cmd_mutex);
+ mdss_dsi_buf_alloc(&ctrl->tx_buf, SZ_4K);
+ mdss_dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
}
-void mdss_dsi_irq_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable, int isr)
+/*
+ * acquire ctrl->mutex first
+ */
+void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
{
- unsigned long flags;
-
- if (ctrl == NULL) {
- pr_err("%s: Invalid ctrl\n", __func__);
- return;
- }
-
- spin_lock_irqsave(&dsi_irq_lock, flags);
+ mutex_lock(&ctrl->mutex);
if (enable) {
- if (ctrl->irq_cnt == 0)
- mdss_enable_irq(ctrl->mdss_hw);
- ctrl->irq_cnt++;
+ if (ctrl->clk_cnt == 0) {
+ mdss_dsi_prepare_clocks(ctrl);
+ mdss_dsi_clk_enable(ctrl);
+ }
+ ctrl->clk_cnt++;
} else {
- if (ctrl->irq_cnt) {
- ctrl->irq_cnt--;
- if (ctrl->irq_cnt == 0) {
- if (isr)
- mdss_disable_irq_nosync(ctrl->mdss_hw);
- else
- mdss_disable_irq(ctrl->mdss_hw);
+ if (ctrl->clk_cnt) {
+ ctrl->clk_cnt--;
+ if (ctrl->clk_cnt == 0) {
+ mdss_dsi_clk_disable(ctrl);
+ mdss_dsi_unprepare_clocks(ctrl);
}
}
}
- pr_debug("%s: ctrl=%d enable=%d cnt=%d\n", __func__,
- ctrl->ndx, enable, ctrl->irq_cnt);
- spin_unlock_irqrestore(&dsi_irq_lock, flags);
+ pr_debug("%s: ctrl ndx=%d enabled=%d clk_cnt=%d\n",
+ __func__, ctrl->ndx, enable, ctrl->clk_cnt);
+ mutex_unlock(&ctrl->mutex);
+}
+
+void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+{
+ if (enable == 0) {
+ /* need wait before disable */
+ mutex_lock(&ctrl->cmd_mutex);
+ mdss_dsi_cmd_mdp_busy(ctrl);
+ mutex_unlock(&ctrl->cmd_mutex);
+ }
+
+ mdss_dsi_clk_ctrl(ctrl, enable);
+}
+
+void mdss_dsi_enable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl->irq_lock, flags);
+ if (ctrl->dsi_irq_mask & term) {
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+ return;
+ }
+ if (ctrl->dsi_irq_mask == 0) {
+ mdss_enable_irq(ctrl->dsi_hw);
+ pr_debug("%s: IRQ Enable, ndx=%d mask=%x term=%x\n", __func__,
+ ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
+ }
+ ctrl->dsi_irq_mask |= term;
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+}
+
+void mdss_dsi_disable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl->irq_lock, flags);
+ if (!(ctrl->dsi_irq_mask & term)) {
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+ return;
+ }
+ ctrl->dsi_irq_mask &= ~term;
+ if (ctrl->dsi_irq_mask == 0) {
+ mdss_disable_irq(ctrl->dsi_hw);
+ pr_debug("%s: IRQ Disable, ndx=%d mask=%x term=%x\n", __func__,
+ ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
+ }
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+}
+
+/*
+ * mdss_dsi_disale_irq_nosync() should be called
+ * from interrupt context
+ */
+void mdss_dsi_disable_irq_nosync(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
+{
+ spin_lock(&ctrl->irq_lock);
+ if (!(ctrl->dsi_irq_mask & term)) {
+ spin_unlock(&ctrl->irq_lock);
+ return;
+ }
+ ctrl->dsi_irq_mask &= ~term;
+ if (ctrl->dsi_irq_mask == 0) {
+ mdss_disable_irq_nosync(ctrl->dsi_hw);
+ pr_debug("%s: IRQ Disable, ndx=%d mask=%x term=%x\n", __func__,
+ ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
+ }
+ spin_unlock(&ctrl->irq_lock);
}
/*
@@ -165,18 +234,20 @@
*/
static int mdss_dsi_generic_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
char *bp;
u32 *hp;
int i, len;
+ dchdr = &cm->dchdr;
bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
/* fill up payload */
if (cm->payload) {
- len = cm->dlen;
+ len = dchdr->dlen;
len += 3;
len &= ~0x03; /* multipled by 4 */
- for (i = 0; i < cm->dlen; i++)
+ for (i = 0; i < dchdr->dlen; i++)
*bp++ = cm->payload[i];
/* append 0xff to the end */
@@ -189,11 +260,11 @@
/* fill up header */
hp = dp->hdr;
*hp = 0;
- *hp = DSI_HDR_WC(cm->dlen);
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp = DSI_HDR_WC(dchdr->dlen);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_LONG_PKT;
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -206,10 +277,12 @@
*/
static int mdss_dsi_generic_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
int len;
- if (cm->dlen && cm->payload == 0) {
+ dchdr = &cm->dchdr;
+ if (dchdr->dlen && cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return 0;
}
@@ -217,12 +290,12 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
- if (cm->last)
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
- len = (cm->dlen > 2) ? 2 : cm->dlen;
+ len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
if (len == 1) {
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
@@ -248,10 +321,12 @@
*/
static int mdss_dsi_generic_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
int len;
- if (cm->dlen && cm->payload == 0) {
+ dchdr = &cm->dchdr;
+ if (dchdr->dlen && cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return 0;
}
@@ -259,12 +334,12 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_BTA;
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
- len = (cm->dlen > 2) ? 2 : cm->dlen;
+ len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
if (len == 1) {
*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
@@ -289,10 +364,12 @@
*/
static int mdss_dsi_dcs_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
char *bp;
u32 *hp;
int i, len;
+ dchdr = &cm->dchdr;
bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
/*
@@ -300,10 +377,10 @@
* dcs command byte (first byte) followed by payload
*/
if (cm->payload) {
- len = cm->dlen;
+ len = dchdr->dlen;
len += 3;
len &= ~0x03; /* multipled by 4 */
- for (i = 0; i < cm->dlen; i++)
+ for (i = 0; i < dchdr->dlen; i++)
*bp++ = cm->payload[i];
/* append 0xff to the end */
@@ -316,11 +393,11 @@
/* fill up header */
hp = dp->hdr;
*hp = 0;
- *hp = DSI_HDR_WC(cm->dlen);
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp = DSI_HDR_WC(dchdr->dlen);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_LONG_PKT;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -333,9 +410,11 @@
*/
static int mdss_dsi_dcs_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
int len;
+ dchdr = &cm->dchdr;
if (cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return -EINVAL;
@@ -344,13 +423,13 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
- if (cm->ack) /* ask ACK trigger msg from peripeheral */
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ if (dchdr->ack) /* ask ACK trigger msg from peripeheral */
*hp |= DSI_HDR_BTA;
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
- len = (cm->dlen > 1) ? 1 : cm->dlen;
+ len = (dchdr->dlen > 1) ? 1 : dchdr->dlen;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
@@ -365,9 +444,11 @@
*/
static int mdss_dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
- if (cm->dlen < 2 || cm->payload == 0) {
+ dchdr = &cm->dchdr;
+ if (dchdr->dlen < 2 || cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return -EINVAL;
}
@@ -375,10 +456,10 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
- if (cm->ack) /* ask ACK trigger msg from peripeheral */
+ *hp |= DSI_HDR_VC(dchdr->vc);
+ if (dchdr->ack) /* ask ACK trigger msg from peripeheral */
*hp |= DSI_HDR_BTA;
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
@@ -395,8 +476,10 @@
static int mdss_dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
if (cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return -EINVAL;
@@ -405,10 +488,10 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_BTA;
*hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
*hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */
@@ -421,14 +504,16 @@
static int mdss_dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -438,14 +523,16 @@
static int mdss_dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -455,14 +542,16 @@
static int mdss_dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -472,14 +561,16 @@
static int mdss_dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -489,8 +580,10 @@
static int mdss_dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
if (cm->payload == 0) {
pr_err("%s: NO payload error\n", __func__);
return 0;
@@ -499,9 +592,9 @@
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
*hp |= DSI_HDR_DATA1(cm->payload[0]);
@@ -514,16 +607,18 @@
static int mdss_dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp = DSI_HDR_WC(cm->dlen);
+ *hp = DSI_HDR_WC(dchdr->dlen);
*hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -533,16 +628,18 @@
static int mdss_dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
u32 *hp;
+ dchdr = &cm->dchdr;
mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
hp = dp->hdr;
*hp = 0;
- *hp = DSI_HDR_WC(cm->dlen);
+ *hp = DSI_HDR_WC(dchdr->dlen);
*hp |= DSI_HDR_LONG_PKT;
- *hp |= DSI_HDR_VC(cm->vc);
+ *hp |= DSI_HDR_VC(dchdr->vc);
*hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
- if (cm->last)
+ if (dchdr->last)
*hp |= DSI_HDR_LAST;
mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -555,9 +652,12 @@
*/
int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
{
+ struct dsi_ctrl_hdr *dchdr;
int len = 0;
- switch (cm->dtype) {
+ dchdr = &cm->dchdr;
+
+ switch (dchdr->dtype) {
case DTYPE_GEN_WRITE:
case DTYPE_GEN_WRITE1:
case DTYPE_GEN_WRITE2:
@@ -606,7 +706,7 @@
break;
default:
pr_debug("%s: dtype=%x NOT supported\n",
- __func__, cm->dtype);
+ __func__, dchdr->dtype);
break;
}
@@ -820,7 +920,7 @@
wmb();
}
-void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata)
+void mdss_set_tx_power_mode(int mode, struct mdss_panel_data *pdata)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
u32 data;
@@ -1034,94 +1134,84 @@
return 4;
}
+
+static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_buf *tp);
+
+static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_buf *rp, int rlen);
/*
* mdss_dsi_cmds_tx:
- * ov_mutex need to be acquired before call this function.
+ * thread context only
*/
-int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt)
+int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int cnt)
{
+ struct dsi_buf *tp;
struct dsi_cmd_desc *cm;
- u32 dsi_ctrl, ctrl;
+ struct dsi_ctrl_hdr *dchdr;
+ u32 dsi_ctrl, data;
int i, video_mode;
- unsigned long flag;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
-
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if (pdata->panel_info.pdest == DISPLAY_1) {
+ if (ctrl->shared_pdata.broadcast_enable) {
+ if (ctrl->ndx == DSI_CTRL_0) {
pr_debug("%s: Broadcast mode. 1st ctrl\n",
__func__);
return 0;
}
+ }
+
+ if (ctrl->shared_pdata.broadcast_enable) {
+ if ((ctrl->ndx == DSI_CTRL_1)
+ && (left_ctrl_pdata != NULL)) {
+ dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
+ + 0x0004);
+ video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
+ if (video_mode) {
+ data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
+ data);
+ }
+ }
+ }
/* turn on cmd mode
* for video mode, do not send cmds more than
* one pixel line, since it only transmit it
* during BLLP.
*/
-
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if ((pdata->panel_info.pdest == DISPLAY_2)
- && (left_ctrl_pdata != NULL)) {
- dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
- + 0x0004);
- video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
- if (video_mode) {
- ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
- ctrl);
- }
- }
-
- dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
+ dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004);
video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
if (video_mode) {
- ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, ctrl);
+ data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
-
- dsi_mdp_busy = true;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
+ tp = &ctrl->tx_buf;
cm = cmds;
- mdss_dsi_buf_init(tp);
for (i = 0; i < cnt; i++) {
+ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
mdss_dsi_buf_init(tp);
mdss_dsi_cmd_dma_add(tp, cm);
- mdss_dsi_cmd_dma_tx(tp, pdata);
- if (cm->wait)
- msleep(cm->wait);
+ mdss_dsi_cmd_dma_tx(ctrl, tp);
+ dchdr = &cm->dchdr;
+ if (dchdr->wait)
+ usleep(dchdr->wait * 1000);
cm++;
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = false;
- mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
if (video_mode)
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+ MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
dsi_ctrl); /* restore */
return cnt;
}
-/* MDSS_DSI_MRPS, Maximum Return Packet Size */
+/* MIPI_DSI_MRPS, Maximum Return Packet Size */
static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
-static struct dsi_cmd_desc pkt_size_cmd[] = {
- {DTYPE_MAX_PKTSIZE, 1, 0, 0, 0,
- sizeof(max_pktsize), max_pktsize}
+static struct dsi_cmd_desc pkt_size_cmd = {
+ {DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, sizeof(max_pktsize)},
+ max_pktsize,
};
/*
@@ -1129,31 +1219,24 @@
* plus DCS header, ECC and CRC for DCS long read response
* mdss_dsi_controller only have 4x32 bits register ( 16 bytes) to
* hold data per transaction.
- * MDSS_DSI_LEN equal to 8
+ * MIPI_DSI_LEN equal to 8
* len should be either 4 or 8
- * any return data more than MDSS_DSI_LEN need to be break down
+ * any return data more than MIPI_DSI_LEN need to be break down
* to multiple transactions.
*
* ov_mutex need to be acquired before call this function.
*/
-int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata,
- struct dsi_buf *tp, struct dsi_buf *rp,
- struct dsi_cmd_desc *cmds, int rlen)
+
+int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_cmd_desc *cmds, int rlen, u32 rx_flags)
{
int cnt, len, diff, pkt_size;
- unsigned long flag;
+ struct dsi_buf *tp, *rp;
+ int no_max_pkt_size;
char cmd;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
-
- if (pdata->panel_info.mipi.no_max_pkt_size)
+ no_max_pkt_size = rx_flags & CMD_REQ_NO_MAX_PKT_SIZE;
+ if (no_max_pkt_size)
rlen = ALIGN(rlen, 4); /* Only support rlen = 4*n */
len = rlen;
@@ -1178,33 +1261,33 @@
cnt = len + 6; /* 4 bytes header + 2 bytes crc */
}
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
- dsi_mdp_busy = true;
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+ tp = &ctrl->tx_buf;
+ rp = &ctrl->rx_buf;
- if (!pdata->panel_info.mipi.no_max_pkt_size) {
+ if (!no_max_pkt_size) {
/* packet size need to be set at every read */
pkt_size = len;
max_pktsize[0] = pkt_size;
+ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
mdss_dsi_buf_init(tp);
- mdss_dsi_cmd_dma_add(tp, pkt_size_cmd);
- mdss_dsi_cmd_dma_tx(tp, pdata);
+ mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd);
+ mdss_dsi_cmd_dma_tx(ctrl, tp);
pr_debug("%s: Max packet size sent\n", __func__);
}
+ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
mdss_dsi_buf_init(tp);
mdss_dsi_cmd_dma_add(tp, cmds);
/* transmit read comamnd to client */
- mdss_dsi_cmd_dma_tx(tp, pdata);
+ mdss_dsi_cmd_dma_tx(ctrl, tp);
/*
* once cmd_dma_done interrupt received,
* return data from client is ready and stored
* at RDBK_DATA register already
*/
mdss_dsi_buf_init(rp);
- if (pdata->panel_info.mipi.no_max_pkt_size) {
+ if (no_max_pkt_size) {
/*
* expect rlen = n * 4
* short alignement for start addr
@@ -1212,14 +1295,9 @@
rp->data += 2;
}
- mdss_dsi_cmd_dma_rx(rp, cnt, pdata);
+ mdss_dsi_cmd_dma_rx(ctrl, rp, cnt);
- spin_lock_irqsave(&dsi_mdp_lock, flag);
- dsi_mdp_busy = false;
- mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
- spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
- if (pdata->panel_info.mipi.no_max_pkt_size) {
+ if (no_max_pkt_size) {
/*
* remove extra 2 bytes from previous
* rx transaction at shift register
@@ -1257,22 +1335,16 @@
return rp->len;
}
-int mdss_dsi_cmd_dma_tx(struct dsi_buf *tp,
- struct mdss_panel_data *pdata)
+#define DMA_TX_TIMEOUT 200
+
+static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_buf *tp)
{
int len;
int domain = MDSS_IOMMU_DOMAIN_UNSECURE;
char *bp;
unsigned long size, addr;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
bp = tp->data;
len = ALIGN(tp->len, 4);
@@ -1296,29 +1368,32 @@
addr = tp->dmap;
}
- INIT_COMPLETION(dsi_dma_comp);
+ INIT_COMPLETION(ctrl->dma_comp);
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if ((pdata->panel_info.pdest == DISPLAY_2)
+ if (ctrl->shared_pdata.broadcast_enable)
+ if ((ctrl->ndx == DSI_CTRL_1)
&& (left_ctrl_pdata != NULL)) {
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x048, addr);
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x04c, len);
}
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x048, addr);
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04c, len);
+ MIPI_OUTP((ctrl->ctrl_base) + 0x048, addr);
+ MIPI_OUTP((ctrl->ctrl_base) + 0x04c, len);
wmb();
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if ((pdata->panel_info.pdest == DISPLAY_2)
+ if (ctrl->shared_pdata.broadcast_enable)
+ if ((ctrl->ndx == DSI_CTRL_1)
&& (left_ctrl_pdata != NULL)) {
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x090, 0x01);
}
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x090, 0x01); /* trigger */
+ MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01); /* trigger */
wmb();
- wait_for_completion(&dsi_dma_comp);
+ if (!wait_for_completion_timeout(&ctrl->dma_comp,
+ msecs_to_jiffies(DMA_TX_TIMEOUT))) {
+ pr_err("%s: dma timeout error\n", __func__);
+ }
if (is_mdss_iommu_attached())
msm_iommu_unmap_contig_buffer(addr,
@@ -1329,20 +1404,13 @@
return tp->len;
}
-int mdss_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen,
- struct mdss_panel_data *pdata)
+static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_buf *rp, int rlen)
+
{
u32 *lp, data;
int i, off, cnt;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
lp = (u32 *)rp->data;
cnt = rlen;
cnt += 3;
@@ -1354,106 +1422,289 @@
off = 0x06c; /* DSI_RDBK_DATA0 */
off += ((cnt - 1) * 4);
-
for (i = 0; i < cnt; i++) {
- data = (u32)MIPI_INP((ctrl_pdata->ctrl_base) + off);
+ data = (u32)MIPI_INP((ctrl->ctrl_base) + off);
*lp++ = ntohl(data); /* to network byte order */
pr_debug("%s: data = 0x%x and ntohl(data) = 0x%x\n",
__func__, data, ntohl(data));
off -= 4;
rp->len += sizeof(*lp);
}
-
return rlen;
}
-void mdss_dsi_ack_err_status(unsigned char *dsi_base)
+#define VSYNC_PERIOD 17
+
+void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&ctrl->mdp_lock, flag);
+ INIT_COMPLETION(ctrl->video_comp);
+ mdss_dsi_enable_irq(ctrl, DSI_VIDEO_TERM);
+ spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
+
+ wait_for_completion_timeout(&ctrl->video_comp,
+ msecs_to_jiffies(VSYNC_PERIOD * 4));
+}
+
+static void mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ mdss_dsi_wait4video_done(ctrl);
+ /* delay 4 ms to skip BLLP */
+ usleep(4000);
+}
+
+void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&ctrl->mdp_lock, flag);
+ mdss_dsi_enable_irq(ctrl, DSI_MDP_TERM);
+ ctrl->mdp_busy = true;
+ INIT_COMPLETION(ctrl->mdp_comp);
+ spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
+}
+
+void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ unsigned long flags;
+ int need_wait = 0;
+
+ pr_debug("%s: start pid=%d\n",
+ __func__, current->pid);
+ spin_lock_irqsave(&ctrl->mdp_lock, flags);
+ if (ctrl->mdp_busy == true)
+ need_wait++;
+ spin_unlock_irqrestore(&ctrl->mdp_lock, flags);
+
+ if (need_wait) {
+ /* wait until DMA finishes the current job */
+ pr_debug("%s: pending pid=%d\n",
+ __func__, current->pid);
+ wait_for_completion(&ctrl->mdp_comp);
+ }
+ pr_debug("%s: done pid=%d\n",
+ __func__, current->pid);
+}
+
+void mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *req)
+{
+ int ret;
+
+ ret = mdss_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt);
+
+ if (req->cb)
+ req->cb(ret);
+
+}
+
+void mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *req)
+{
+ int len;
+ u32 data, *dp;
+ struct dsi_buf *rp;
+
+ len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen, req->flags);
+ rp = &ctrl->rx_buf;
+ dp = (u32 *)rp->data;
+ data = *dp;
+
+ if (req->cb)
+ req->cb(data);
+}
+
+void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+{
+ struct dcs_cmd_req *req;
+ u32 data;
+
+ mutex_lock(&ctrl->cmd_mutex);
+ req = mdss_dsi_cmdlist_get(ctrl);
+
+ /* make sure dsi_cmd_mdp is idle */
+ mdss_dsi_cmd_mdp_busy(ctrl);
+
+ if (req == NULL)
+ goto need_lock;
+
+ pr_debug("%s: from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
+ mdss_dsi_clk_ctrl(ctrl, 1);
+
+ data = MIPI_INP((ctrl->ctrl_base) + 0x0004);
+ if (data & 0x02) {
+ /* video mode, make sure video engine is busy
+ * so dcs command will be sent at start of BLLP
+ */
+ mdss_dsi_wait4video_eng_busy(ctrl);
+ } else {
+ /* command mode */
+ if (!from_mdp) { /* cmdlist_put */
+ /* make sure dsi_cmd_mdp is idle */
+ mdss_dsi_cmd_mdp_busy(ctrl);
+ }
+ }
+
+ if (req->flags & CMD_REQ_RX)
+ mdss_dsi_cmdlist_rx(ctrl, req);
+ else
+ mdss_dsi_cmdlist_tx(ctrl, req);
+
+ mdss_dsi_clk_ctrl(ctrl, 0);
+
+need_lock:
+
+ if (from_mdp) /* from pipe_commit */
+ mdss_dsi_cmd_mdp_start(ctrl);
+
+ mutex_unlock(&ctrl->cmd_mutex);
+}
+
+/*
+ * mdss_dsi_cmd_get: ctrl->cmd_mutex acquired by caller
+ */
+struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct dcs_cmd_list *clist;
+ struct dcs_cmd_req *req = NULL;
+
+ clist = &ctrl->cmdlist;
+ if (clist->get != clist->put) {
+ req = &clist->list[clist->get];
+ clist->get++;
+ clist->get %= CMD_REQ_MAX;
+ clist->tot--;
+ pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+ clist->tot, clist->put, clist->get);
+ }
+ return req;
+}
+
+int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dcs_cmd_req *cmdreq)
+{
+ struct dcs_cmd_req *req;
+ struct dcs_cmd_list *clist;
+ int ret = 0;
+
+ mutex_lock(&ctrl->cmd_mutex);
+ clist = &ctrl->cmdlist;
+ req = &clist->list[clist->put];
+ *req = *cmdreq;
+ clist->put++;
+ clist->put %= CMD_REQ_MAX;
+ clist->tot++;
+ if (clist->put == clist->get) {
+ /* drop the oldest one */
+ pr_debug("%s: DROP, tot=%d put=%d get=%d\n", __func__,
+ clist->tot, clist->put, clist->get);
+ clist->get++;
+ clist->get %= CMD_REQ_MAX;
+ clist->tot--;
+ }
+ mutex_unlock(&ctrl->cmd_mutex);
+
+ ret++;
+ pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+ clist->tot, clist->put, clist->get);
+
+ if (req->flags & CMD_REQ_COMMIT)
+ mdss_dsi_cmdlist_commit(ctrl, 0);
+
+ return ret;
+}
+
+void mdss_dsi_ack_err_status(unsigned char *base)
{
u32 status;
- status = MIPI_INP(dsi_base + 0x0068);/* DSI_ACK_ERR_STATUS */
+ status = MIPI_INP(base + 0x0068);/* DSI_ACK_ERR_STATUS */
if (status) {
- MIPI_OUTP(dsi_base + 0x0068, status);
+ MIPI_OUTP(base + 0x0068, status);
pr_debug("%s: status=%x\n", __func__, status);
}
}
-void mdss_dsi_timeout_status(unsigned char *dsi_base)
+void mdss_dsi_timeout_status(unsigned char *base)
{
u32 status;
- status = MIPI_INP(dsi_base + 0x00c0);/* DSI_TIMEOUT_STATUS */
+ status = MIPI_INP(base + 0x00c0);/* DSI_TIMEOUT_STATUS */
if (status & 0x0111) {
- MIPI_OUTP(dsi_base + 0x00c0, status);
+ MIPI_OUTP(base + 0x00c0, status);
pr_debug("%s: status=%x\n", __func__, status);
}
}
-void mdss_dsi_dln0_phy_err(unsigned char *dsi_base)
+void mdss_dsi_dln0_phy_err(unsigned char *base)
{
u32 status;
- status = MIPI_INP(dsi_base + 0x00b4);/* DSI_DLN0_PHY_ERR */
+ status = MIPI_INP(base + 0x00b4);/* DSI_DLN0_PHY_ERR */
if (status & 0x011111) {
- MIPI_OUTP(dsi_base + 0x00b4, status);
+ MIPI_OUTP(base + 0x00b4, status);
pr_debug("%s: status=%x\n", __func__, status);
}
}
-void mdss_dsi_fifo_status(unsigned char *dsi_base)
+void mdss_dsi_fifo_status(unsigned char *base)
{
u32 status;
- status = MIPI_INP(dsi_base + 0x000c);/* DSI_FIFO_STATUS */
+ status = MIPI_INP(base + 0x000c);/* DSI_FIFO_STATUS */
if (status & 0x44444489) {
- MIPI_OUTP(dsi_base + 0x000c, status);
+ MIPI_OUTP(base + 0x000c, status);
pr_debug("%s: status=%x\n", __func__, status);
}
}
-void mdss_dsi_status(unsigned char *dsi_base)
+void mdss_dsi_status(unsigned char *base)
{
u32 status;
- status = MIPI_INP(dsi_base + 0x0008);/* DSI_STATUS */
+ status = MIPI_INP(base + 0x0008);/* DSI_STATUS */
if (status & 0x80000000) {
- MIPI_OUTP(dsi_base + 0x0008, status);
+ MIPI_OUTP(base + 0x0008, status);
pr_debug("%s: status=%x\n", __func__, status);
}
}
-void mdss_dsi_error(unsigned char *dsi_base)
+void mdss_dsi_error(struct mdss_dsi_ctrl_pdata *ctrl)
{
+ unsigned char *base;
+
+ base = ctrl->ctrl_base;
+
/* DSI_ERR_INT_MASK0 */
- mdss_dsi_ack_err_status(dsi_base); /* mask0, 0x01f */
- mdss_dsi_timeout_status(dsi_base); /* mask0, 0x0e0 */
- mdss_dsi_fifo_status(dsi_base); /* mask0, 0x133d00 */
- mdss_dsi_status(dsi_base); /* mask0, 0xc0100 */
- mdss_dsi_dln0_phy_err(dsi_base); /* mask0, 0x3e00000 */
+ mdss_dsi_ack_err_status(base); /* mask0, 0x01f */
+ mdss_dsi_timeout_status(base); /* mask0, 0x0e0 */
+ mdss_dsi_fifo_status(base); /* mask0, 0x133d00 */
+ mdss_dsi_status(base); /* mask0, 0xc0100 */
+ mdss_dsi_dln0_phy_err(base); /* mask0, 0x3e00000 */
}
irqreturn_t mdss_dsi_isr(int irq, void *ptr)
{
u32 isr;
- unsigned char *dsi_base;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata =
+ struct mdss_dsi_ctrl_pdata *ctrl =
(struct mdss_dsi_ctrl_pdata *)ptr;
- dsi_base = ctrl_pdata->ctrl_base;
- if (!dsi_base)
+ if (!ctrl->ctrl_base)
pr_err("%s:%d DSI base adr no Initialized",
__func__, __LINE__);
- isr = MIPI_INP(dsi_base + 0x0110);/* DSI_INTR_CTRL */
- MIPI_OUTP(dsi_base + 0x0110, isr);
+ isr = MIPI_INP(ctrl->ctrl_base + 0x0110);/* DSI_INTR_CTRL */
+ MIPI_OUTP(ctrl->ctrl_base + 0x0110, isr);
- if (ctrl_pdata->shared_pdata.broadcast_enable)
- if ((ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_2)
+ if (ctrl->shared_pdata.broadcast_enable)
+ if ((ctrl->panel_data.panel_info.pdest == DISPLAY_2)
&& (left_ctrl_pdata != NULL)) {
u32 isr0;
isr0 = MIPI_INP(left_ctrl_pdata->ctrl_base
@@ -1461,24 +1712,38 @@
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0);
}
- pr_debug("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
+ pr_debug("%s: isr=%x", __func__, isr);
- if (isr & DSI_INTR_ERROR)
- mdss_dsi_error(dsi_base);
-
- if (isr & DSI_INTR_VIDEO_DONE) {
- /*
- * do something here
- */
+ if (isr & DSI_INTR_ERROR) {
+ pr_err("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
+ spin_lock(&ctrl->mdp_lock);
+ ctrl->mdp_busy = false;
+ mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
+ complete(&ctrl->mdp_comp);
+ mdss_dsi_error(ctrl);
+ spin_unlock(&ctrl->mdp_lock);
}
- if (isr & DSI_INTR_CMD_DMA_DONE)
- complete(&dsi_dma_comp);
+ if (isr & DSI_INTR_VIDEO_DONE) {
+ spin_lock(&ctrl->mdp_lock);
+ mdss_dsi_disable_irq_nosync(ctrl, DSI_VIDEO_TERM);
+ complete(&ctrl->video_comp);
+ spin_unlock(&ctrl->mdp_lock);
+ }
+
+ if (isr & DSI_INTR_CMD_DMA_DONE) {
+ spin_lock(&ctrl->mdp_lock);
+ mdss_dsi_disable_irq_nosync(ctrl, DSI_CMD_TERM);
+ complete(&ctrl->dma_comp);
+ spin_unlock(&ctrl->mdp_lock);
+ }
if (isr & DSI_INTR_CMD_MDP_DONE) {
- spin_lock(&dsi_mdp_lock);
- dsi_mdp_busy = false;
- spin_unlock(&dsi_mdp_lock);
+ spin_lock(&ctrl->mdp_lock);
+ ctrl->mdp_busy = false;
+ mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
+ complete(&ctrl->mdp_comp);
+ spin_unlock(&ctrl->mdp_lock);
}
return IRQ_HANDLED;
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index c56cd41..6b0f68e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -26,9 +26,6 @@
#define DT_CMD_HDR 6
-static struct dsi_buf dsi_panel_tx_buf;
-static struct dsi_buf dsi_panel_rx_buf;
-
DEFINE_LED_TRIGGER(bl_led_trigger);
static struct mdss_dsi_phy_ctrl phy_params;
@@ -37,16 +34,18 @@
{
int ret;
- if (!gpio_is_valid(ctrl->pwm_gpio)) {
- pr_err("%s: pwm_gpio=%d Invalid\n", __func__,
- ctrl->pwm_gpio);
+ if (!gpio_is_valid(ctrl->pwm_pmic_gpio)) {
+ pr_err("%s: pwm_pmic_gpio=%d Invalid\n", __func__,
+ ctrl->pwm_pmic_gpio);
+ ctrl->pwm_pmic_gpio = -1;
return;
}
- ret = gpio_request(ctrl->pwm_gpio, "disp_pwm");
+ ret = gpio_request(ctrl->pwm_pmic_gpio, "disp_pwm");
if (ret) {
- pr_err("%s: pwm_gpio=%d request failed\n", __func__,
- ctrl->pwm_gpio);
+ pr_err("%s: pwm_pmic_gpio=%d request failed\n", __func__,
+ ctrl->pwm_pmic_gpio);
+ ctrl->pwm_pmic_gpio = -1;
return;
}
@@ -54,8 +53,8 @@
if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) {
pr_err("%s: lpg_chan=%d pwm request failed", __func__,
ctrl->pwm_lpg_chan);
- gpio_free(ctrl->pwm_gpio);
- ctrl->pwm_gpio = -1;
+ gpio_free(ctrl->pwm_pmic_gpio);
+ ctrl->pwm_pmic_gpio = -1;
}
}
@@ -74,7 +73,7 @@
pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n",
__func__, ctrl->bklt_ctrl, ctrl->pwm_period,
- ctrl->pwm_gpio, ctrl->pwm_lpg_chan);
+ ctrl->pwm_pmic_gpio, ctrl->pwm_lpg_chan);
pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__,
ctrl->ndx, level, duty);
@@ -90,6 +89,71 @@
pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret);
}
+static char dcs_cmd[2] = {0x54, 0x00}; /* DTYPE_DCS_READ */
+static struct dsi_cmd_desc dcs_read_cmd = {
+ {DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(dcs_cmd)},
+ dcs_cmd
+};
+
+u32 mdss_dsi_dcs_read(struct mdss_dsi_ctrl_pdata *ctrl,
+ char cmd0, char cmd1)
+{
+ struct dcs_cmd_req cmdreq;
+
+ dcs_cmd[0] = cmd0;
+ dcs_cmd[1] = cmd1;
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = &dcs_read_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT;
+ cmdreq.rlen = 1;
+ cmdreq.cb = NULL; /* call back */
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+ /*
+ * blocked here, until call back called
+ */
+
+ return 0;
+}
+
+static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl,
+ struct dsi_panel_cmds *pcmds)
+{
+ struct dcs_cmd_req cmdreq;
+
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = pcmds->cmds;
+ cmdreq.cmds_cnt = pcmds->cmd_cnt;
+ cmdreq.flags = CMD_REQ_COMMIT;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
+static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */
+static struct dsi_cmd_desc backlight_cmd = {
+ {DTYPE_DCS_WRITE1, 1, 0, 0, 1, sizeof(led_pwm1)},
+ led_pwm1
+};
+
+static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, int level)
+{
+ struct dcs_cmd_req cmdreq;
+
+ pr_debug("%s: level=%d\n", __func__, level);
+
+ led_pwm1[1] = (unsigned char)level;
+
+ memset(&cmdreq, 0, sizeof(cmdreq));
+ cmdreq.cmds = &backlight_cmd;
+ cmdreq.cmds_cnt = 1;
+ cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL;
+ cmdreq.rlen = 0;
+ cmdreq.cb = NULL;
+
+ mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
{
@@ -152,6 +216,9 @@
case BL_PWM:
mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level);
break;
+ case BL_DCS_CMD:
+ mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);
+ break;
default:
pr_err("%s: Unknown bl_ctrl configuration\n",
__func__);
@@ -159,14 +226,6 @@
}
}
-static char set_tear_on[2] = {0x35, 0x00};
-static struct dsi_cmd_desc dsi_tear_on_cmd = {
- DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on), set_tear_on};
-
-static char set_tear_off[2] = {0x34, 0x00};
-static struct dsi_cmd_desc dsi_tear_off_cmd = {
- DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off), set_tear_off};
-
static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
{
struct mipi_panel_info *mipi;
@@ -183,14 +242,10 @@
pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
- if (ctrl->on_cmds->size)
- mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
- ctrl->on_cmds->buf,
- ctrl->on_cmds->size);
+ if (ctrl->on_cmds.cmd_cnt)
+ mdss_dsi_panel_cmds_send(ctrl, &ctrl->on_cmds);
- mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
- &dsi_tear_on_cmd, 1);
-
+ pr_debug("%s:-\n", __func__);
return 0;
}
@@ -211,17 +266,95 @@
mipi = &pdata->panel_info.mipi;
- mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
- &dsi_tear_off_cmd, 1);
+ if (ctrl->off_cmds.cmd_cnt)
+ mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds);
- if (ctrl->off_cmds->size)
- mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
- ctrl->off_cmds->buf,
- ctrl->off_cmds->size);
+ pr_debug("%s:-\n", __func__);
+ return 0;
+}
+
+
+static int mdss_dsi_parse_dcs_cmds(struct device_node *np,
+ struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key)
+{
+ const char *data;
+ int blen = 0, len;
+ char *buf, *bp;
+ struct dsi_ctrl_hdr *dchdr;
+ int i, cnt;
+
+ data = of_get_property(np, cmd_key, &blen);
+ if (!data) {
+ pr_err("%s: failed, key=%s\n", __func__, cmd_key);
+ return -ENOMEM;
+ }
+
+ buf = kzalloc(sizeof(char) * blen, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf, data, blen);
+
+ /* scan dcs commands */
+ bp = buf;
+ len = blen;
+ cnt = 0;
+ while (len > sizeof(*dchdr)) {
+ dchdr = (struct dsi_ctrl_hdr *)bp;
+ dchdr->dlen = ntohs(dchdr->dlen);
+ if (dchdr->dlen > len) {
+ pr_err("%s: dtsi cmd=%x error, len=%d",
+ __func__, dchdr->dtype, dchdr->dlen);
+ return -ENOMEM;
+ }
+ bp += sizeof(*dchdr);
+ len -= sizeof(*dchdr);
+ bp += dchdr->dlen;
+ len -= dchdr->dlen;
+ cnt++;
+ }
+
+ if (len != 0) {
+ pr_err("%s: dcs_cmd=%x len=%d error!",
+ __func__, buf[0], blen);
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc),
+ GFP_KERNEL);
+ if (!pcmds->cmds)
+ return -ENOMEM;
+
+ pcmds->cmd_cnt = cnt;
+ pcmds->buf = buf;
+ pcmds->blen = blen;
+
+ bp = buf;
+ len = blen;
+ for (i = 0; i < cnt; i++) {
+ dchdr = (struct dsi_ctrl_hdr *)bp;
+ len -= sizeof(*dchdr);
+ bp += sizeof(*dchdr);
+ pcmds->cmds[i].dchdr = *dchdr;
+ pcmds->cmds[i].payload = bp;
+ bp += dchdr->dlen;
+ len -= dchdr->dlen;
+ }
+
+ pcmds->link_state = DSI_LP_MODE; /* default */
+
+ data = of_get_property(np, link_key, NULL);
+ if (!strncmp(data, "DSI_HS_MODE", 11))
+ pcmds->link_state = DSI_HS_MODE;
+
+ pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__,
+ pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
return 0;
}
+
static int mdss_panel_parse_dt(struct platform_device *pdev,
struct mdss_panel_common_pdata *panel_data)
{
@@ -229,12 +362,8 @@
u32 res[6], tmp;
u32 fbc_res[7];
int rc, i, len;
- int cmd_plen, data_offset;
const char *data;
static const char *bl_ctrl_type, *pdest;
- static const char *on_cmds_state, *off_cmds_state;
- char *on_cmds = NULL, *off_cmds = NULL;
- int num_of_on_cmds = 0, num_of_off_cmds = 0;
bool fbc_enabled = false;
rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
@@ -301,15 +430,15 @@
} else if (!strncmp(bl_ctrl_type, "bl_ctrl_pwm", 11)) {
panel_data->panel_info.bklt_ctrl = BL_PWM;
- rc = of_property_read_u32(np, "qcom,dsi-pwm-period", &tmp);
+ rc = of_property_read_u32(np, "qcom,pwm-period", &tmp);
if (rc) {
- pr_err("%s:%d, Error, dsi pwm_period\n",
+ pr_err("%s:%d, Error, panel pwm_period\n",
__func__, __LINE__);
return -EINVAL;
}
panel_data->panel_info.pwm_period = tmp;
- rc = of_property_read_u32(np, "qcom,dsi-lpg-channel", &tmp);
+ rc = of_property_read_u32(np, "qcom,pwm-lpg-channel", &tmp);
if (rc) {
pr_err("%s:%d, Error, dsi lpg channel\n",
__func__, __LINE__);
@@ -317,8 +446,10 @@
}
panel_data->panel_info.pwm_lpg_chan = tmp;
- tmp = of_get_named_gpio(np, "qcom,dsi-pwm-gpio", 0);
- panel_data->panel_info.pwm_gpio = tmp;
+ tmp = of_get_named_gpio(np, "qcom,pwm-pmic-gpio", 0);
+ panel_data->panel_info.pwm_pmic_gpio = tmp;
+ } else if (!strncmp(bl_ctrl_type, "bl_ctrl_dcs", 11)) {
+ panel_data->panel_info.bklt_ctrl = BL_DCS_CMD;
} else {
pr_debug("%s: Unknown backlight control\n", __func__);
panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL;
@@ -529,171 +660,15 @@
panel_data->panel_info.bpp;
}
- data = of_get_property(np, "qcom,panel-on-cmds", &len);
- if (!data) {
- pr_err("%s:%d, Unable to read ON cmds", __func__, __LINE__);
- goto error;
- }
+ mdss_dsi_parse_dcs_cmds(np, &panel_data->on_cmds,
+ "qcom,panel-on-cmds", "qcom,on-cmds-dsi-state");
- on_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
- if (!on_cmds)
- return -ENOMEM;
-
- memcpy(on_cmds, data, len);
-
- data_offset = 0;
- cmd_plen = 0;
- while ((len - data_offset) >= DT_CMD_HDR) {
- data_offset += (DT_CMD_HDR - 1);
- cmd_plen = on_cmds[data_offset++];
- data_offset += cmd_plen;
- num_of_on_cmds++;
- }
- if (!num_of_on_cmds) {
- pr_err("%s:%d, No ON cmds specified", __func__, __LINE__);
- goto error;
- }
-
- panel_data->dsi_panel_on_cmds =
- kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
- if (!panel_data->dsi_panel_on_cmds)
- return -ENOMEM;
-
- (panel_data->dsi_panel_on_cmds)->buf =
- kzalloc((num_of_on_cmds * sizeof(struct dsi_cmd_desc)),
- GFP_KERNEL);
- if (!(panel_data->dsi_panel_on_cmds)->buf)
- return -ENOMEM;
-
- data_offset = 0;
- for (i = 0; i < num_of_on_cmds; i++) {
- panel_data->dsi_panel_on_cmds->buf[i].dtype =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].last =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].vc =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].ack =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].wait =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].dlen =
- on_cmds[data_offset++];
- panel_data->dsi_panel_on_cmds->buf[i].payload =
- &on_cmds[data_offset];
- data_offset += (panel_data->dsi_panel_on_cmds->buf[i].dlen);
- }
-
- if (data_offset != len) {
- pr_err("%s:%d, Incorrect ON command entries",
- __func__, __LINE__);
- goto error;
- }
-
- (panel_data->dsi_panel_on_cmds)->size = num_of_on_cmds;
-
- on_cmds_state = of_get_property(pdev->dev.of_node,
- "qcom,on-cmds-dsi-state", NULL);
- if (!strncmp(on_cmds_state, "DSI_LP_MODE", 11)) {
- (panel_data->dsi_panel_on_cmds)->ctrl_state =
- DSI_LP_MODE;
- } else if (!strncmp(on_cmds_state, "DSI_HS_MODE", 11)) {
- (panel_data->dsi_panel_on_cmds)->ctrl_state =
- DSI_HS_MODE;
- } else {
- pr_debug("%s: ON cmds state not specified. Set Default\n",
- __func__);
- (panel_data->dsi_panel_on_cmds)->ctrl_state =
- DSI_LP_MODE;
- }
-
- data = of_get_property(np, "qcom,panel-off-cmds", &len);
- if (!data) {
- pr_err("%s:%d, Unable to read OFF cmds", __func__, __LINE__);
- goto error;
- }
-
- off_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
- if (!off_cmds)
- return -ENOMEM;
-
- memcpy(off_cmds, data, len);
-
- data_offset = 0;
- cmd_plen = 0;
- while ((len - data_offset) >= DT_CMD_HDR) {
- data_offset += (DT_CMD_HDR - 1);
- cmd_plen = off_cmds[data_offset++];
- data_offset += cmd_plen;
- num_of_off_cmds++;
- }
- if (!num_of_off_cmds) {
- pr_err("%s:%d, No OFF cmds specified", __func__, __LINE__);
- goto error;
- }
-
- panel_data->dsi_panel_off_cmds =
- kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
- if (!panel_data->dsi_panel_off_cmds)
- return -ENOMEM;
-
- (panel_data->dsi_panel_off_cmds)->buf = kzalloc(num_of_off_cmds
- * sizeof(struct dsi_cmd_desc),
- GFP_KERNEL);
- if (!(panel_data->dsi_panel_off_cmds)->buf)
- return -ENOMEM;
-
- data_offset = 0;
- for (i = 0; i < num_of_off_cmds; i++) {
- panel_data->dsi_panel_off_cmds->buf[i].dtype =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].last =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].vc =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].ack =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].wait =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].dlen =
- off_cmds[data_offset++];
- panel_data->dsi_panel_off_cmds->buf[i].payload =
- &off_cmds[data_offset];
- data_offset += (panel_data->dsi_panel_off_cmds->buf[i].dlen);
- }
-
- if (data_offset != len) {
- pr_err("%s:%d, Incorrect OFF command entries",
- __func__, __LINE__);
- goto error;
- }
-
- (panel_data->dsi_panel_off_cmds)->size = num_of_off_cmds;
-
- off_cmds_state = of_get_property(pdev->dev.of_node,
- "qcom,off-cmds-dsi-state", NULL);
- if (!strncmp(off_cmds_state, "DSI_LP_MODE", 11)) {
- (panel_data->dsi_panel_off_cmds)->ctrl_state =
- DSI_LP_MODE;
- } else if (!strncmp(off_cmds_state, "DSI_HS_MODE", 11)) {
- (panel_data->dsi_panel_off_cmds)->ctrl_state =
- DSI_HS_MODE;
- } else {
- pr_debug("%s: ON cmds state not specified. Set Default\n",
- __func__);
- (panel_data->dsi_panel_off_cmds)->ctrl_state =
- DSI_LP_MODE;
- }
+ mdss_dsi_parse_dcs_cmds(np, &panel_data->off_cmds,
+ "qcom,panel-off-cmds", "qcom,off-cmds-dsi-state");
return 0;
-error:
- kfree((panel_data->dsi_panel_on_cmds)->buf);
- kfree((panel_data->dsi_panel_off_cmds)->buf);
- kfree(panel_data->dsi_panel_on_cmds);
- kfree(panel_data->dsi_panel_off_cmds);
- kfree(on_cmds);
- kfree(off_cmds);
+error:
return -EINVAL;
}
@@ -744,9 +719,6 @@
static int __init mdss_dsi_panel_init(void)
{
- mdss_dsi_buf_alloc(&dsi_panel_tx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
- mdss_dsi_buf_alloc(&dsi_panel_rx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
-
return platform_driver_register(&this_driver);
}
module_init(mdss_dsi_panel_init);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 28f61f9..e2d8cf6 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -561,6 +561,13 @@
pdata->set_backlight(pdata, temp);
mfd->bl_level = bkl_lvl;
bl_level_old = temp;
+
+ if (mfd->mdp.update_ad_input) {
+ mutex_unlock(&mfd->bl_lock);
+ /* Will trigger ad_setup which will grab bl_lock */
+ mfd->mdp.update_ad_input(mfd);
+ mutex_lock(&mfd->bl_lock);
+ }
}
}
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 5682f0b..05fdec4 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -68,6 +68,7 @@
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);
+ int (*update_ad_input)(struct msm_fb_data_type *mfd);
int (*panel_register_done)(struct mdss_panel_data *pdata);
u32 (*fb_stride)(u32 fb_index, u32 xres, int bpp);
void *private1;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index f726e79..1f0efd3 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -287,7 +287,7 @@
timeout_count = 100;
keys_state = (link0_status >> 28) & 0x7;
while ((keys_state != HDCP_KEYS_STATE_VALID) &&
- timeout_count--) {
+ --timeout_count) {
link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
keys_state = (link0_status >> 28) & 0x7;
DEV_DBG("%s: %s: Keys not ready(%d). s=%d\n, l0=%0x08x",
@@ -320,7 +320,7 @@
link0_status);
msleep(20);
}
- } while (!an_ready && timeout_count--);
+ } while (!an_ready && --timeout_count);
if (!timeout_count) {
rc = -ETIMEDOUT;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index c395a8a..fe10189 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -130,9 +130,9 @@
{0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18, 0x28, 0x28,
0x28, 0x28}, /*01*/
- {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x88, 0x00, 0x04, 0x04, 0x04,
- 0x04, 0x04}, /*02*/
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00}, /*02*/
{0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F,
0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11, 0x00, 0x00,
0x00, 0x00}, /*03*/
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 122dcb9..f3b5acec 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -486,11 +486,10 @@
struct mdp_histogram_data *hist);
void mdss_mdp_hist_intr_done(u32 isr);
-int mdss_ad_init_checks(struct msm_fb_data_type *mfd);
int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
struct mdss_ad_init_cfg *init_cfg);
int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
- struct mdss_ad_input *input);
+ struct mdss_ad_input *input, int wait);
int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index e346082..4b763aa 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1505,7 +1505,6 @@
mdss_mdp_pp_setup_locked(ctl);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
if (sctl) {
- mdss_mdp_pp_setup_locked(sctl);
mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
sctl->flush_bits);
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index eb2bd21..afbbe55 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -14,11 +14,12 @@
#include <linux/kernel.h>
#include "mdss_panel.h"
#include "mdss_mdp.h"
+#include "mdss_dsi.h"
#define VSYNC_EXPIRE_TICK 4
#define START_THRESHOLD 4
-#define CONTINUE_TRESHOLD 4
+#define CONTINUE_THRESHOLD 4
#define MAX_SESSIONS 2
@@ -26,11 +27,12 @@
#define KOFF_TIMEOUT msecs_to_jiffies(84)
struct mdss_mdp_cmd_ctx {
+ struct mdss_mdp_ctl *ctl;
u32 pp_num;
u8 ref_cnt;
+ struct completion vsync_comp;
struct completion pp_comp;
struct completion stop_comp;
- atomic_t vsync_ref;
mdp_vsync_handler_t send_vsync;
int panel_on;
int koff_cnt;
@@ -46,6 +48,7 @@
u8 tear_check;
u16 height; /* panel height */
u16 vporch; /* vertical porches */
+ u16 start_threshold;
u32 vclk_line; /* vsync clock per line */
};
@@ -83,7 +86,7 @@
ctx->height);
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_THRESH,
- (CONTINUE_TRESHOLD << 16) | (START_THRESHOLD));
+ (CONTINUE_THRESHOLD << 16) | (ctx->start_threshold));
mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_TEAR_CHECK_EN, enable);
return 0;
@@ -118,13 +121,16 @@
pinfo->lcdc.v_front_porch +
pinfo->lcdc.v_pulse_width;
+ ctx->start_threshold = START_THRESHOLD;
+
total_lines = ctx->height + ctx->vporch;
total_lines *= pinfo->mipi.frame_rate;
ctx->vclk_line = mdp_vsync_clk_speed_hz / total_lines;
- pr_debug("%s: fr=%d tline=%d vcnt=%d vrate=%d\n",
+ pr_debug("%s: fr=%d tline=%d vcnt=%d thold=%d vrate=%d\n",
__func__, pinfo->mipi.frame_rate, total_lines,
- ctx->vclk_line, mdp_vsync_clk_speed_hz);
+ ctx->vclk_line, ctx->start_threshold,
+ mdp_vsync_clk_speed_hz);
} else {
enable = 0;
}
@@ -151,6 +157,8 @@
return;
}
+ complete_all(&ctx->vsync_comp);
+
pr_debug("%s: num=%d ctx=%d expire=%d koff=%d\n", __func__, ctl->num,
ctx->pp_num, ctx->expire, ctx->koff_cnt);
@@ -226,6 +234,9 @@
mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
ctx->pp_num);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ /* disable dsi clock */
+ mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL,
+ (void *)0);
complete(&ctx->stop_comp);
pr_debug("%s: SET_CLK_OFF, pid=%d\n", __func__, current->pid);
} else {
@@ -249,11 +260,12 @@
enable = (handler->vsync_handler != NULL);
+ mutex_lock(&ctx->clk_mtx);
+
pr_debug("%s: ctx=%p ctx=%d enabled=%d %d clk_enabled=%d clk_ctrl=%d\n",
__func__, ctx, ctx->pp_num, ctx->vsync_enabled, enable,
ctx->clk_enabled, ctx->clk_control);
- mutex_lock(&ctx->clk_mtx);
if (ctx->vsync_enabled == enable) {
mutex_unlock(&ctx->clk_mtx);
return 0;
@@ -266,6 +278,8 @@
ctx->send_vsync = handler->vsync_handler;
spin_unlock_irqrestore(&ctx->clk_lock, flags);
if (ctx->clk_enabled == 0) {
+ mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL,
+ (void *)1);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
ctx->pp_num);
@@ -294,10 +308,11 @@
return;
}
+ mutex_lock(&ctx->clk_mtx);
+
pr_debug("%s: ctx=%p num=%d clk_enabled=%d\n", __func__,
ctx, ctx->pp_num, ctx->clk_enabled);
- mutex_lock(&ctx->clk_mtx);
spin_lock_irqsave(&ctx->clk_lock, flags);
ctx->koff_cnt++;
ctx->clk_control = 0;
@@ -309,6 +324,8 @@
spin_unlock_irqrestore(&ctx->clk_lock, flags);
if (set_clk_on) {
+ mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL,
+ (void *)1);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
ctx->vsync_enabled = 1;
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
@@ -331,16 +348,18 @@
pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
- rc = wait_for_completion_interruptible_timeout(&ctx->pp_comp,
+ rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
KOFF_TIMEOUT);
WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n", rc, ctl->num);
- return rc;
+ return 0;
}
int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_cmd_ctx *ctx;
+ unsigned long flags;
+ int need_wait = 0;
int rc;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
@@ -349,10 +368,21 @@
return -ENODEV;
}
- pr_debug("%s: kickoff intf_num=%d ctx=%p\n", __func__,
- ctl->intf_num, ctx);
+ spin_lock_irqsave(&ctx->clk_lock, flags);
+ if (ctx->koff_cnt > 0)
+ need_wait = 1;
+ spin_unlock_irqrestore(&ctx->clk_lock, flags);
- mdss_mdp_cmd_chk_clock(ctx);
+ pr_debug("%s: need_wait=%d intf_num=%d ctx=%p\n",
+ __func__, need_wait, ctl->intf_num, ctx);
+
+ if (need_wait) {
+ rc = wait_for_completion_interruptible_timeout(
+ &ctx->pp_comp, KOFF_TIMEOUT);
+
+ WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n",
+ rc, ctl->num);
+ }
if (ctx->panel_on == 0) {
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
@@ -364,10 +394,19 @@
WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
}
+ mdss_mdp_cmd_chk_clock(ctx);
+
+ /*
+ * tx dcs command if had any
+ */
+ mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF, NULL);
+
+ INIT_COMPLETION(ctx->vsync_comp);
INIT_COMPLETION(ctx->pp_comp);
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+ mb();
return 0;
}
@@ -454,10 +493,11 @@
return -ENODEV;
}
+ ctx->ctl = ctl;
ctx->pp_num = mixer->num;
+ init_completion(&ctx->vsync_comp);
init_completion(&ctx->pp_comp);
init_completion(&ctx->stop_comp);
- atomic_set(&ctx->vsync_ref, 0);
spin_lock_init(&ctx->clk_lock);
mutex_init(&ctx->clk_mtx);
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 3cb23f3..c96464a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -696,6 +696,7 @@
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_pipe *pipe;
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
int ret;
mutex_lock(&mdp5_data->ov_lock);
@@ -704,6 +705,9 @@
struct mdss_mdp_data *buf;
if (pipe->back_buf.num_planes) {
buf = &pipe->back_buf;
+ } else if (ctl->play_cnt == 0) {
+ pipe->params_changed++;
+ buf = &pipe->front_buf;
} else if (!pipe->params_changed) {
continue;
} else if (pipe->front_buf.num_planes) {
@@ -1544,7 +1548,7 @@
ret = mdss_mdp_ad_config(mfd, &mdp_pp.data.ad_init_cfg);
break;
case mdp_op_ad_input:
- ret = mdss_mdp_ad_input(mfd, &mdp_pp.data.ad_input);
+ ret = mdss_mdp_ad_input(mfd, &mdp_pp.data.ad_input, 1);
if (ret > 0) {
ret = 0;
copyback = 1;
@@ -1869,7 +1873,19 @@
if (!mdp5_data->ctl->power_on)
return 0;
- mdss_mdp_overlay_release_all(mfd);
+ if (!mfd->ref_cnt) {
+ mdss_mdp_overlay_release_all(mfd);
+ } else {
+ int need_cleanup;
+ mutex_lock(&mfd->lock);
+ need_cleanup = !list_empty(&mdp5_data->pipes_cleanup);
+ mutex_unlock(&mfd->lock);
+
+ if (need_cleanup) {
+ pr_debug("cleaning up some pipes\n");
+ mdss_mdp_overlay_kickoff(mfd);
+ }
+ }
rc = mdss_mdp_ctl_stop(mdp5_data->ctl);
if (rc == 0) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 0f65530..4f9ab81 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -22,6 +22,7 @@
#define SMP_MB_SIZE (mdss_res->smp_mb_size)
#define SMP_MB_CNT (mdss_res->smp_mb_cnt)
#define SMP_ENTRIES_PER_MB (SMP_MB_SIZE / 16)
+#define MAX_BPP 4
static DEFINE_MUTEX(mdss_mdp_sspp_lock);
static DEFINE_MUTEX(mdss_mdp_smp_lock);
@@ -152,6 +153,9 @@
ps.num_planes = 2;
ps.ystride[0] = pipe->src.w >> pipe->horz_deci;
ps.ystride[1] = pipe->src.h >> pipe->vert_deci;
+ } else if (pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
+ ps.ystride[0] = max(pipe->mixer->width, pipe->src.w) * MAX_BPP;
+ ps.num_planes = 1;
} else {
rc = mdss_mdp_get_plane_sizes(pipe->src_fmt->format,
pipe->src.w, pipe->src.h, &ps, 0);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 65b5fc4..9d28265 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -284,6 +284,9 @@
static void pp_sharp_config(char __iomem *offset,
struct pp_sts_type *pp_sts,
struct mdp_sharp_cfg *sharp_config);
+static int mdss_ad_init_checks(struct msm_fb_data_type *mfd);
+static struct mdss_ad_info *mdss_mdp_get_ad(struct msm_fb_data_type *mfd);
+static int pp_update_ad_input(struct msm_fb_data_type *mfd);
static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t);
static void pp_ad_cfg_write(struct mdss_ad_info *ad);
static void pp_ad_init_write(struct mdss_ad_info *ad);
@@ -885,14 +888,19 @@
return ret;
}
-static int pp_mixer_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
+static int pp_mixer_setup(u32 disp_num,
struct mdss_mdp_mixer *mixer)
{
u32 flags, offset, dspp_num, opmode = 0;
struct mdp_pgc_lut_data *pgc_config;
struct pp_sts_type *pp_sts;
+ struct mdss_mdp_ctl *ctl;
dspp_num = mixer->num;
+ if (!mixer || !mixer->ctl)
+ return -EINVAL;
+ ctl = mixer->ctl;
+
/* no corresponding dspp */
if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
(dspp_num >= MDSS_MDP_MAX_DSPP))
@@ -1000,8 +1008,7 @@
return ret;
}
-static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
- struct mdss_mdp_mixer *mixer)
+static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
{
u32 flags, base, offset, dspp_num, opmode = 0;
struct mdp_dither_cfg_data *dither_cfg;
@@ -1011,12 +1018,12 @@
char __iomem *basel;
int i, ret = 0;
struct mdss_data_type *mdata;
+ struct mdss_mdp_ctl *ctl;
- mdata = ctl->mdata;
-
- if (!mixer || !ctl || !mdata)
+ if (!mixer || !mixer->ctl || !mixer->ctl->mdata)
return -EINVAL;
-
+ ctl = mixer->ctl;
+ mdata = ctl->mdata;
dspp_num = mixer->num;
/* no corresponding dspp */
if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
@@ -1171,12 +1178,12 @@
mutex_lock(&mdss_pp_mutex);
if (ctl->mixer_left) {
- pp_mixer_setup(disp_num, ctl, ctl->mixer_left);
- pp_dspp_setup(disp_num, ctl, ctl->mixer_left);
+ pp_mixer_setup(disp_num, ctl->mixer_left);
+ pp_dspp_setup(disp_num, ctl->mixer_left);
}
if (ctl->mixer_right) {
- pp_mixer_setup(disp_num, ctl, ctl->mixer_right);
- pp_dspp_setup(disp_num, ctl, ctl->mixer_right);
+ pp_mixer_setup(disp_num, ctl->mixer_right);
+ pp_dspp_setup(disp_num, ctl->mixer_right);
}
/* clear dirty flag */
if (disp_num < MDSS_BLOCK_DISP_NUM)
@@ -2680,7 +2687,7 @@
}
#define MDSS_AD_MAX_MIXERS 1
-int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
+static int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
{
u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
u32 mixer_num;
@@ -2718,23 +2725,47 @@
return mixer_id[0];
}
+static struct mdss_ad_info *mdss_mdp_get_ad(struct msm_fb_data_type *mfd)
+{
+ int ad_num;
+ struct mdss_data_type *mdata;
+ struct mdss_ad_info *ad = NULL;
+ mdata = mfd_to_mdata(mfd);
+
+ ad_num = mdss_ad_init_checks(mfd);
+ if (ad_num >= 0)
+ ad = &mdata->ad_cfgs[ad_num];
+ return ad;
+}
+
+static int pp_update_ad_input(struct msm_fb_data_type *mfd)
+{
+ struct mdss_ad_info *ad;
+ struct mdss_ad_input input;
+
+ ad = mdss_mdp_get_ad(mfd);
+ if (!ad)
+ return -EINVAL;
+
+ pr_debug("backlight level changed, trigger update to AD");
+ input.mode = ad->cfg.mode;
+ if (MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode, MDSS_AD_INPUT_AMBIENT))
+ input.in.amb_light = ad->ad_data;
+ else
+ input.in.strength = ad->ad_data;
+ /* call to ad_input will trigger backlight read */
+ return mdss_mdp_ad_input(mfd, &input, 0);
+}
+
int mdss_mdp_ad_config(struct msm_fb_data_type *mfd,
struct mdss_ad_init_cfg *init_cfg)
{
- int ad_num;
struct mdss_ad_info *ad;
- struct mdss_data_type *mdata;
struct mdss_mdp_ctl *ctl;
- struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- ctl = mdp5_data->ctl;
-
- ad_num = mdss_ad_init_checks(mfd);
- if (ad_num < 0)
- return ad_num;
-
- mdata = mdss_mdp_get_mdata();
- ad = &mdata->ad_cfgs[ad_num];
+ ad = mdss_mdp_get_ad(mfd);
+ if (!ad)
+ return -EINVAL;
mutex_lock(&ad->lock);
if (init_cfg->ops & MDP_PP_AD_INIT) {
@@ -2760,26 +2791,20 @@
ad->mfd = mfd;
}
mutex_unlock(&ad->lock);
+ ctl = mfd_to_ctl(mfd);
mdss_mdp_pp_setup(ctl);
return 0;
}
int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
- struct mdss_ad_input *input) {
- int ad_num, ret = 0;
+ struct mdss_ad_input *input, int wait) {
+ int ret = 0;
struct mdss_ad_info *ad;
- struct mdss_data_type *mdata;
struct mdss_mdp_ctl *ctl;
- struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- ctl = mdp5_data->ctl;
-
- ad_num = mdss_ad_init_checks(mfd);
- if (ad_num < 0)
- return ad_num;
-
- mdata = mdss_mdp_get_mdata();
- ad = &mdata->ad_cfgs[ad_num];
+ ad = mdss_mdp_get_ad(mfd);
+ if (!ad)
+ return -EINVAL;
mutex_lock(&ad->lock);
if (!PP_AD_STATE_IS_INITCFG(ad->state) &&
@@ -2824,16 +2849,21 @@
error:
mutex_unlock(&ad->lock);
if (!ret) {
- mutex_lock(&ad->lock);
- init_completion(&ad->comp);
- mutex_unlock(&ad->lock);
+ if (wait) {
+ mutex_lock(&ad->lock);
+ init_completion(&ad->comp);
+ mutex_unlock(&ad->lock);
+ }
+ ctl = mfd_to_ctl(mfd);
mdss_mdp_pp_setup(ctl);
- ret = wait_for_completion_interruptible_timeout(&ad->comp,
- HIST_WAIT_TIMEOUT(1));
- if (ret == 0)
- ret = -ETIMEDOUT;
- else if (ret > 0)
- input->output = ad->last_str;
+ if (wait) {
+ ret = wait_for_completion_interruptible_timeout(
+ &ad->comp, HIST_WAIT_TIMEOUT(1));
+ if (ret == 0)
+ ret = -ETIMEDOUT;
+ else if (ret > 0)
+ input->output = ad->last_str;
+ }
}
return ret;
}
@@ -2958,19 +2988,16 @@
#define MDSS_PP_AD_BYPASS_DEF 0x101
static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
{
- int ad_num, ret = 0;
+ int ret = 0;
struct mdss_ad_info *ad;
- struct mdss_data_type *mdata;
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
char __iomem *base;
u32 bypass = MDSS_PP_AD_BYPASS_DEF;
- ad_num = mdss_ad_init_checks(mfd);
- if (ad_num < 0)
- return ad_num;
+ ad = mdss_mdp_get_ad(mfd);
+ if (!ad)
+ return -EINVAL;
- mdata = mdss_mdp_get_mdata();
- ad = &mdata->ad_cfgs[ad_num];
base = ad->base;
mutex_lock(&ad->lock);
@@ -3021,10 +3048,17 @@
bypass = 0;
ret = 1;
ad->state |= PP_AD_STATE_RUN;
+ mutex_lock(&mfd->bl_lock);
+ mfd->mdp.update_ad_input = pp_update_ad_input;
+ mutex_unlock(&mfd->bl_lock);
+
} else {
if (ad->state & PP_AD_STATE_RUN) {
ret = 1;
ad->sts |= PP_AD_STS_DIRTY_VSYNC;
+ mutex_lock(&mfd->bl_lock);
+ mfd->mdp.update_ad_input = NULL;
+ mutex_unlock(&mfd->bl_lock);
}
ad->state &= ~PP_AD_STATE_RUN;
}
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 9e8cfa7..f138420 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -81,6 +81,10 @@
* @MDSS_EVENT_FB_REGISTERED: Called after fb dev driver has been registered,
* panel driver gets ptr to struct fb_info which
* holds fb dev information.
+ * @MDSS_EVENT_PANEL_CLK_CTRL: panel clock control
+ - 0 clock disable
+ - 1 clock enable
+ * @MDSS_EVENT_DSI_CMDLIST_KOFF: kickoff sending dcs command from command list
*/
enum mdss_intf_events {
MDSS_EVENT_RESET = 1,
@@ -94,6 +98,8 @@
MDSS_EVENT_CHECK_PARAMS,
MDSS_EVENT_CONT_SPLASH_FINISH,
MDSS_EVENT_FB_REGISTERED,
+ MDSS_EVENT_PANEL_CLK_CTRL,
+ MDSS_EVENT_DSI_CMDLIST_KOFF,
};
struct lcd_panel_info {
@@ -222,7 +228,7 @@
u32 out_format;
u32 vic; /* video identification code */
int bklt_ctrl; /* backlight ctrl */
- int pwm_gpio;
+ int pwm_pmic_gpio;
int pwm_lpg_chan;
int pwm_period;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 5564ceb..12bc5e0 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -170,13 +170,10 @@
clk_unprepare(ctrl_pdata->byte_clk);
}
-void mdss_dsi_clk_enable(struct mdss_panel_data *pdata)
+void mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
u32 esc_clk_rate = 19200000;
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
if (!ctrl_pdata) {
pr_err("%s: Invalid input data\n", __func__);
return;
@@ -206,12 +203,8 @@
ctrl_pdata->mdss_dsi_clk_on = 1;
}
-void mdss_dsi_clk_disable(struct mdss_panel_data *pdata)
+void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
if (!ctrl_pdata) {
pr_err("%s: Invalid input data\n", __func__);
return;
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index aa1eba5..ce9e5b9 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -195,7 +195,7 @@
/* write pointer offset in bytes */
unsigned int write_offset;
- /* non-zero if data error occured */
+ /* non-zero if data error occurred */
int error;
};
@@ -237,7 +237,10 @@
* (dmx_sct_filter_params) and no sections were
* received for the given time.
*/
- DMX_EVENT_SECTION_TIMEOUT = 0x00000400
+ DMX_EVENT_SECTION_TIMEOUT = 0x00000400,
+
+ /* Scrambling bits change between clear and scrambled */
+ DMX_EVENT_SCRAMBLING_STATUS_CHANGE = 0x00000800
};
enum dmx_oob_cmd {
@@ -256,7 +259,7 @@
/* Discontinuity indicator was set */
#define DMX_FILTER_DISCONTINUITY_INDICATOR 0x02
-/* PES legnth in PES header is not correct */
+/* PES length in PES header is not correct */
#define DMX_FILTER_PES_LENGTH_ERROR 0x04
@@ -412,7 +415,7 @@
/*
* The PID the index entry belongs to.
* In case of recording filter, multiple PIDs may exist in the same
- * filter through DMX_ADD_PID ioctl and each can be indexed seperatly.
+ * filter through DMX_ADD_PID ioctl and each can be indexed separately.
*/
__u16 pid;
@@ -423,7 +426,7 @@
__u64 match_tsp_num;
/*
- * The TS packet number in the recorded data preceeding
+ * The TS packet number in the recorded data preceding
* match_tsp_num and has PUSI set.
*/
__u64 last_pusi_tsp_num;
@@ -432,6 +435,23 @@
__u64 stc;
};
+/* Scrambling information associated with DMX_EVENT_SCRAMBLING_STATUS_CHANGE */
+struct dmx_scrambling_status_event_info {
+ /*
+ * The PID which its scrambling bit status changed.
+ * In case of recording filter, multiple PIDs may exist in the same
+ * filter through DMX_ADD_PID ioctl, each may have
+ * different scrambling bits status.
+ */
+ __u16 pid;
+
+ /* old value of scrambling bits */
+ __u8 old_value;
+
+ /* new value of scrambling bits */
+ __u8 new_value;
+};
+
/*
* Filter's event returned through DMX_GET_EVENT.
* poll with POLLPRI would block until events are available.
@@ -447,6 +467,7 @@
struct dmx_es_data_event_info es_data;
struct dmx_marker_event_info marker;
struct dmx_index_event_info index;
+ struct dmx_scrambling_status_event_info scrambling_status;
} params;
};
@@ -754,6 +775,19 @@
__u32 identifier;
};
+struct dmx_scrambling_bits {
+ /*
+ * The PID to return its scrambling bit value.
+ * In case of recording filter, multiple PIDs may exist in the same
+ * filter through DMX_ADD_PID ioctl, each may have different
+ * scrambling bits status.
+ */
+ __u16 pid;
+
+ /* Current value of scrambling bits: 0, 1, 2 or 3 */
+ __u8 value;
+};
+
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@@ -784,5 +818,6 @@
#define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params)
#define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion)
#define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion)
+#define DMX_GET_SCRAMBLING_BITS _IOWR('o', 72, struct dmx_scrambling_bits)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
index df9569b..47a2b7b 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -18,10 +18,10 @@
#define FCC_CC_COLS 5
#define FCC_TEMP_COLS 8
-#define PC_CC_ROWS 29
+#define PC_CC_ROWS 31
#define PC_CC_COLS 13
-#define PC_TEMP_ROWS 29
+#define PC_TEMP_ROWS 31
#define PC_TEMP_COLS 8
#define MAX_SINGLE_LUT_COLS 20
@@ -74,6 +74,7 @@
BATT_PALLADIUM,
BATT_DESAY,
BATT_OEM,
+ BATT_QRD_4V35_2000MAH,
};
/**
@@ -114,6 +115,7 @@
extern struct bms_battery_data palladium_1500_data;
extern struct bms_battery_data desay_5200_data;
extern struct bms_battery_data oem_batt_data;
+extern struct bms_battery_data QRD_4v35_2000mAh_data;
int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp);
int interpolate_scalingfactor(struct sf_lut *sf_lut, int row_entry, int pc);
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index 3d159c4..a741107 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -72,6 +72,13 @@
uint16_t gain;
};
+enum msm_spkr_prot_states {
+ MSM_SPKR_PROT_CALIBRATED,
+ MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS,
+ MSM_SPKR_PROT_DISABLED,
+ MSM_SPKR_PROT_NOT_CALIBRATED
+};
+
struct msm_spk_prot_cfg {
int r0;
int t0;
diff --git a/include/linux/msm_audio_ion.h b/include/linux/msm_audio_ion.h
index 83e5dff..38b27bf 100644
--- a/include/linux/msm_audio_ion.h
+++ b/include/linux/msm_audio_ion.h
@@ -13,7 +13,12 @@
#ifndef _LINUX_MSM_AUDIO_ION_H
#define _LINUX_MSM_AUDIO_ION_H
-
+#ifdef CONFIG_SND_SOC_QDSP6V2
+#include <sound/q6asm-v2.h>
+#else
+#include <sound/q6asm.h>
+#endif
+#include <sound/pcm.h>
#include <linux/msm_ion.h>
@@ -26,9 +31,11 @@
unsigned long *ionflag, size_t bufsz,
ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr);
int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle);
-
+int msm_audio_ion_mmap(struct audio_buffer *substream,
+ struct vm_area_struct *vma);
bool msm_audio_ion_is_smmu_available(void);
+int msm_audio_ion_cache_operations(struct audio_buffer *abuff, int cache_op);
#ifdef CONFIG_SND_SOC_QDSP6V2
struct ion_client *msm_audio_ion_client_create(unsigned int heap_mask,
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 2ad040e..e8de769 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -769,7 +769,7 @@
struct kgsl_perfcounter_read_group {
unsigned int groupid;
unsigned int countable;
- uint64_t value;
+ unsigned long long value;
};
struct kgsl_perfcounter_read {
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 61e9cb1..e4df414 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -716,7 +716,7 @@
} data;
};
-#define MDP_MAX_FENCE_FD 10
+#define MDP_MAX_FENCE_FD 32
#define MDP_BUF_SYNC_FLAG_WAIT 1
struct mdp_buf_sync {
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index f14cc52..2c1fa11 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -20,6 +20,7 @@
int32_t limit_temp_degC;
int32_t temp_hysteresis_degC;
uint32_t freq_step;
+ uint32_t freq_control_mask;
int32_t core_limit_temp_degC;
int32_t core_temp_hysteresis_degC;
uint32_t core_control_mask;
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index f551e75..6d7d178 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -3069,4 +3069,32 @@
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3,
};
+/**
+ * enum nl80211_connect_failed_reason - connection request failed reasons
+ * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
+ * handled by the AP is reached.
+ * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Connection request is rejected due to ACL.
+ */
+enum nl80211_connect_failed_reason {
+ NL80211_CONN_FAIL_MAX_CLIENTS,
+ NL80211_CONN_FAIL_BLOCKED_CLIENT,
+};
+
+/**
+ * enum nl80211_acl_policy - access control policy
+ *
+ * Access control policy is applied on a MAC list set by
+ * %NL80211_CMD_START_AP and %NL80211_CMD_SET_MAC_ACL, to
+ * be used with %NL80211_ATTR_ACL_POLICY.
+ *
+ * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are
+ * listed in ACL, i.e. allow all the stations which are not listed
+ * in ACL to authenticate.
+ * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow the stations which are listed
+ * in ACL, i.e. deny all the stations which are not listed in ACL.
+ */
+enum nl80211_acl_policy {
+ NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED,
+ NL80211_ACL_POLICY_DENY_UNLESS_LISTED,
+};
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/of_coresight.h b/include/linux/of_coresight.h
index 0943dda..eb20e80 100644
--- a/include/linux/of_coresight.h
+++ b/include/linux/of_coresight.h
@@ -13,7 +13,7 @@
#ifndef __LINUX_OF_CORESIGHT_H
#define __LINUX_OF_CORESIGHT_H
-#ifdef CONFIG_OF
+#ifdef CONFIG_OF_CORESIGHT
extern struct coresight_platform_data *of_get_coresight_platform_data(
struct device *dev, struct device_node *node);
extern struct coresight_cti_data *of_get_coresight_cti_data(
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 6e30ca2..1de9aaa 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -127,6 +127,7 @@
POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */
POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
+ POWER_SUPPLY_PROP_RESISTANCE,
/* Properties of type `const char *' */
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
diff --git a/include/linux/qpnp/power-on.h b/include/linux/qpnp/power-on.h
index 85dbce9..6394988 100644
--- a/include/linux/qpnp/power-on.h
+++ b/include/linux/qpnp/power-on.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,8 +17,10 @@
#ifdef CONFIG_QPNP_POWER_ON
int qpnp_pon_system_pwr_off(bool reset);
+int qpnp_pon_is_warm_reset(void);
#else
static int qpnp_pon_system_pwr_off(bool reset) { return -ENODEV; }
+static inline int qpnp_pon_is_warm_reset(void) { return -ENODEV; }
#endif
#endif
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 13d0b80..dfb156f 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -602,6 +602,34 @@
QPNP_ADC_TM_CH_SELECT_NONE
};
+enum qpnp_comp_scheme_type {
+ COMP_ID_GF = 0,
+ COMP_ID_SMIC,
+ COMP_ID_TSMC,
+ COMP_ID_NUM,
+};
+
+enum qpnp_iadc_rev {
+ QPNP_IADC_VER_3_0 = 0x1,
+ QPNP_IADC_VER_3_1 = 0x3,
+};
+
+#define QPNP_VBAT_SNS_COEFF_1_TYPEA 3000
+#define QPNP_VBAT_SNS_COEFF_2_TYPEA 45810000
+#define QPNP_VBAT_SNS_COEFF_3 100000
+#define QPNP_VBAT_SNS_COEFF_1_TYPEB 3500
+#define QPNP_VBAT_SNS_COEFF_2_TYPEB 80000000
+
+#define QPNP_COEFF_1 969000
+#define QPNP_COEFF_2 34
+#define QPNP_COEFF_3_TYPEA 1700000
+#define QPNP_COEFF_3_TYPEB 1000000
+#define QPNP_COEFF_4 100
+#define QPNP_COEFF_5 15000
+#define QPNP_COEFF_6 100000
+#define QPNP_COEFF_7 21700
+#define QPNP_COEFF_8 100000000
+
/**
* struct qpnp_adc_tm_config - Represent ADC Thermal Monitor configuration.
* @channel: ADC channel for which thermal monitoring is requested.
@@ -1252,6 +1280,11 @@
*/
int32_t qpnp_vadc_iadc_sync_complete_request(
enum qpnp_vadc_channels channel, struct qpnp_vadc_result *result);
+/**
+ * qpnp_vadc_sns_comp_result() - Compensate vbatt readings based on temperature
+ * @result: Voltage in uV that needs compensation.
+ */
+int32_t qpnp_vbat_sns_comp_result(int64_t *result);
#else
static inline int32_t qpnp_vadc_read(uint32_t channel,
struct qpnp_vadc_result *result)
@@ -1336,6 +1369,8 @@
enum qpnp_vadc_channels channel,
struct qpnp_vadc_result *result)
{ return -ENXIO; }
+static inline int32_t qpnp_vbat_sns_comp_result(int64_t *result)
+{ return -ENXIO; }
#endif
/* Public API */
@@ -1389,6 +1424,7 @@
* @result: 0 on success.
*/
int32_t qpnp_iadc_calibrate_for_trim(void);
+int32_t qpnp_iadc_comp_result(int64_t *result);
#else
static inline int32_t qpnp_iadc_read(enum qpnp_iadc_channels channel,
struct qpnp_iadc_result *result)
@@ -1406,6 +1442,8 @@
{ return -ENXIO; }
static inline int32_t qpnp_iadc_calibrate_for_trim(void)
{ return -ENXIO; }
+static inline int32_t qpnp_iadc_comp_result(int64_t *result, int32_t sign)
+{ return -ENXIO; }
#endif
/* Public API */
diff --git a/include/linux/regulator/cpr-regulator.h b/include/linux/regulator/cpr-regulator.h
index b6fc091..6387913 100644
--- a/include/linux/regulator/cpr-regulator.h
+++ b/include/linux/regulator/cpr-regulator.h
@@ -35,7 +35,6 @@
CPR_CORNER_SVS = 1,
CPR_CORNER_NORMAL,
CPR_CORNER_TURBO,
- CPR_CORNER_SUPER_TURBO,
CPR_CORNER_MAX,
};
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 67889bf..952bcb1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2726,6 +2726,8 @@
#endif /* CONFIG_SMP */
+extern struct atomic_notifier_head migration_notifier_head;
+
extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask);
extern long sched_getaffinity(pid_t pid, struct cpumask *mask);
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index da56df6..4711ec8 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -67,6 +67,7 @@
void wcnss_riva_log_debug_regs(void);
void wcnss_pronto_log_debug_regs(void);
int wcnss_device_ready(void);
+void wcnss_riva_dump_pmic_regs(void);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
index 993a4ab..65831db 100644
--- a/include/media/msm_media_info.h
+++ b/include/media/msm_media_info.h
@@ -7,6 +7,7 @@
enum color_fmts {
COLOR_FMT_NV12,
+ COLOR_FMT_NV21,
};
static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width)
@@ -16,6 +17,7 @@
goto invalid_input;
switch (color_fmt) {
+ case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
alignment = 128;
stride = MSM_MEDIA_ALIGN(width, alignment);
@@ -34,6 +36,7 @@
goto invalid_input;
switch (color_fmt) {
+ case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
alignment = 128;
stride = MSM_MEDIA_ALIGN(width, alignment);
@@ -52,6 +55,7 @@
goto invalid_input;
switch (color_fmt) {
+ case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
alignment = 32;
sclines = MSM_MEDIA_ALIGN(height, alignment);
@@ -70,6 +74,7 @@
goto invalid_input;
switch (color_fmt) {
+ case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
alignment = 16;
sclines = MSM_MEDIA_ALIGN(((height + 1) >> 1), alignment);
@@ -96,6 +101,7 @@
y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
switch (color_fmt) {
+ case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
uv_alignment = 4096;
y_plane = y_stride * y_sclines;
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index c185096..6cd4995 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -18,6 +18,11 @@
MSM_CPP_REALTIME_FRAME,
};
+enum msm_vpe_frame_type {
+ MSM_VPE_OFFLINE_FRAME,
+ MSM_VPE_REALTIME_FRAME,
+};
+
struct msm_cpp_frame_strip_info {
int scale_v_en;
int scale_h_en;
@@ -107,9 +112,10 @@
struct timeval in_time, out_time;
void *cookie;
int32_t *status;
-
+ int32_t duplicate_output;
+ uint32_t duplicate_identity;
struct msm_cpp_buffer_info_t input_buffer_info;
- struct msm_cpp_buffer_info_t output_buffer_info;
+ struct msm_cpp_buffer_info_t output_buffer_info[2];
};
struct cpp_hw_info {
@@ -117,6 +123,57 @@
uint32_t cpp_hw_caps;
};
+struct msm_vpe_frame_strip_info {
+ uint32_t src_w;
+ uint32_t src_h;
+ uint32_t dst_w;
+ uint32_t dst_h;
+ uint32_t src_x;
+ uint32_t src_y;
+ uint32_t phase_step_x;
+ uint32_t phase_step_y;
+ uint32_t phase_init_x;
+ uint32_t phase_init_y;
+};
+
+struct msm_vpe_buffer_info_t {
+ int fd;
+ uint32_t index;
+ uint32_t offset;
+ uint8_t native_buff;
+ uint8_t processed_divert;
+};
+
+struct msm_vpe_stream_buff_info_t {
+ uint32_t identity;
+ uint32_t num_buffs;
+ struct msm_vpe_buffer_info_t *buffer_info;
+};
+
+struct msm_vpe_frame_info_t {
+ int32_t frame_id;
+ struct timeval timestamp;
+ uint32_t inst_id;
+ uint32_t identity;
+ uint32_t client_id;
+ enum msm_vpe_frame_type frame_type;
+ struct msm_vpe_frame_strip_info strip_info;
+ int src_fd;
+ int dst_fd;
+ struct ion_handle *src_ion_handle;
+ struct ion_handle *dest_ion_handle;
+ unsigned long src_phyaddr;
+ unsigned long dest_phyaddr;
+ unsigned long src_chroma_plane_offset;
+ unsigned long dest_chroma_plane_offset;
+ struct timeval in_time, out_time;
+ void *cookie;
+
+ struct msm_vpe_buffer_info_t input_buffer_info;
+ struct msm_vpe_buffer_info_t output_buffer_info;
+};
+
+
#define VIDIOC_MSM_CPP_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t)
@@ -141,7 +198,27 @@
#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO \
_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_TRANSACTION_SETUP \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_GET_EVENTPAYLOAD \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_GET_INST_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_camera_v4l2_ioctl_t)
+
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
+#define V4L2_EVENT_VPE_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 1)
struct msm_camera_v4l2_ioctl_t {
uint32_t id;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index dc29eb9..fb2b57a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -416,6 +416,26 @@
size_t probe_resp_len;
};
+struct mac_address {
+ u8 addr[ETH_ALEN];
+};
+
+/**
+ * struct cfg80211_acl_data - Access control list data
+ *
+ * @acl_policy: ACL policy to be applied on the station's
+ * entry specified by mac_addr
+ * @n_acl_entries: Number of MAC address entries passed
+ * @mac_addrs: List of MAC addresses of stations to be used for ACL
+ */
+struct cfg80211_acl_data {
+ enum nl80211_acl_policy acl_policy;
+ int n_acl_entries;
+
+ /* Keep it last */
+ struct mac_address mac_addrs[];
+};
+
/**
* struct cfg80211_ap_settings - AP configuration
*
@@ -432,6 +452,8 @@
* @privacy: the BSS uses privacy
* @auth_type: Authentication type (algorithm)
* @inactivity_timeout: time in seconds to determine station's inactivity.
+ * @acl: ACL configuration used by the drivers which has support for
+ * MAC address based access control
*/
struct cfg80211_ap_settings {
struct cfg80211_beacon_data beacon;
@@ -444,6 +466,7 @@
bool privacy;
enum nl80211_auth_type auth_type;
int inactivity_timeout;
+ const struct cfg80211_acl_data *acl;
};
/**
@@ -1559,6 +1582,13 @@
* later passes to cfg80211_probe_status().
*
* @set_noack_map: Set the NoAck Map for the TIDs.
+ * @set_mac_acl: Sets MAC address control list in AP and P2P GO mode.
+ * Parameters include ACL policy, an array of MAC address of stations
+ * and the number of MAC addresses. If there is already a list in driver
+ * this new list replaces the existing one. Driver has to clear its ACL
+ * when number of MAC addresses entries is passed as 0. Drivers which
+ * advertise the support for MAC based ACL have to implement this callback.
+ *
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1757,6 +1787,9 @@
struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_ft_ies_params *ftie);
+
+ int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
+ const struct cfg80211_acl_data *params);
};
/*
@@ -1924,10 +1957,6 @@
bool beacon_int_infra_match;
};
-struct mac_address {
- u8 addr[ETH_ALEN];
-};
-
struct ieee80211_txrx_stypes {
u16 tx, rx;
};
@@ -2068,6 +2097,9 @@
* @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
* @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden.
* If null, then none can be over-ridden.
+ *
+ * @max_acl_mac_addrs: Maximum number of MAC addresses that the device
+ * supports for ACL.
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -2089,6 +2121,8 @@
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
u16 interface_modes;
+ u16 max_acl_mac_addrs;
+
u32 flags, features;
u32 ap_sme_capa;
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 2d34d70..2138689 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -165,6 +165,8 @@
wait_queue_head_t cmd_wait;
wait_queue_head_t time_wait;
bool perf_mode;
+ /* audio cache operations fptr*/
+ int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
};
void q6asm_audio_client_free(struct audio_client *ac);
diff --git a/include/trace/events/workqueue.h b/include/trace/events/workqueue.h
index 7d49729..82f61f4 100644
--- a/include/trace/events/workqueue.h
+++ b/include/trace/events/workqueue.h
@@ -54,7 +54,7 @@
__entry->function = work->func;
__entry->workqueue = cwq->wq;
__entry->req_cpu = req_cpu;
- __entry->cpu = cwq->gcwq->cpu;
+ __entry->cpu = cwq->pool->gcwq->cpu;
),
TP_printk("work struct=%p function=%pf workqueue=%p req_cpu=%u cpu=%u",
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 862e172..1a07d2e 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -87,6 +87,8 @@
#define CREATE_TRACE_POINTS
#include <trace/events/sched.h>
+ATOMIC_NOTIFIER_HEAD(migration_notifier_head);
+
void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period)
{
unsigned long delta;
@@ -1589,15 +1591,17 @@
try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
{
unsigned long flags;
- int cpu, success = 0;
+ int cpu, src_cpu, success = 0;
smp_wmb();
raw_spin_lock_irqsave(&p->pi_lock, flags);
+ src_cpu = task_cpu(p);
+ cpu = src_cpu;
+
if (!(p->state & state))
goto out;
success = 1; /* we're going to change ->state */
- cpu = task_cpu(p);
if (p->on_rq && ttwu_remote(p, wake_flags))
goto stat;
@@ -1634,7 +1638,7 @@
p->sched_class->task_waking(p);
cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags);
- if (task_cpu(p) != cpu) {
+ if (src_cpu != cpu) {
wake_flags |= WF_MIGRATED;
set_task_cpu(p, cpu);
}
@@ -1646,6 +1650,9 @@
out:
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+ if (src_cpu != cpu && task_notify_on_migrate(p))
+ atomic_notifier_call_chain(&migration_notifier_head,
+ cpu, (void *)src_cpu);
return success;
}
@@ -5068,6 +5075,7 @@
static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
{
struct rq *rq_dest, *rq_src;
+ bool moved = false;
int ret = 0;
if (unlikely(!cpu_active(dest_cpu)))
@@ -5094,12 +5102,16 @@
set_task_cpu(p, dest_cpu);
enqueue_task(rq_dest, p, 0);
check_preempt_curr(rq_dest, p, 0);
+ moved = true;
}
done:
ret = 1;
fail:
double_rq_unlock(rq_src, rq_dest);
raw_spin_unlock(&p->pi_lock);
+ if (moved && task_notify_on_migrate(p))
+ atomic_notifier_call_chain(&migration_notifier_head,
+ dest_cpu, (void *)src_cpu);
return ret;
}
@@ -7731,6 +7743,24 @@
sched_move_task(task);
}
+static u64 cpu_notify_on_migrate_read_u64(struct cgroup *cgrp,
+ struct cftype *cft)
+{
+ struct task_group *tg = cgroup_tg(cgrp);
+
+ return tg->notify_on_migrate;
+}
+
+static int cpu_notify_on_migrate_write_u64(struct cgroup *cgrp,
+ struct cftype *cft, u64 notify)
+{
+ struct task_group *tg = cgroup_tg(cgrp);
+
+ tg->notify_on_migrate = (notify > 0);
+
+ return 0;
+}
+
#ifdef CONFIG_FAIR_GROUP_SCHED
static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype,
u64 shareval)
@@ -8002,6 +8032,11 @@
#endif /* CONFIG_RT_GROUP_SCHED */
static struct cftype cpu_files[] = {
+ {
+ .name = "notify_on_migrate",
+ .read_u64 = cpu_notify_on_migrate_read_u64,
+ .write_u64 = cpu_notify_on_migrate_write_u64,
+ },
#ifdef CONFIG_FAIR_GROUP_SCHED
{
.name = "shares",
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 7e31770..103730d 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2126,11 +2126,11 @@
static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
{
struct sched_entity *se = &p->se;
- struct cfs_rq *cfs_rq = &rq->cfs;
+ struct cfs_rq *cfs_rq = cfs_rq_of(se);
WARN_ON(task_rq(p) != rq);
- if (cfs_rq->h_nr_running > 1) {
+ if (rq->cfs.h_nr_running > 1) {
u64 slice = sched_slice(cfs_rq, se);
u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
s64 delta = slice - ran;
@@ -3101,6 +3101,8 @@
unsigned int loop_max;
};
+static DEFINE_PER_CPU(bool, dbs_boost_needed);
+
/*
* move_task - move a task from one runqueue to another runqueue.
* Both runqueues must be locked.
@@ -3111,6 +3113,8 @@
set_task_cpu(p, env->dst_cpu);
activate_task(env->dst_rq, p, 0);
check_preempt_curr(env->dst_rq, p, 0);
+ if (task_notify_on_migrate(p))
+ per_cpu(dbs_boost_needed, env->dst_cpu) = true;
}
/*
@@ -4541,9 +4545,15 @@
*/
sd->nr_balance_failed = sd->cache_nice_tries+1;
}
- } else
+ } else {
sd->nr_balance_failed = 0;
-
+ if (per_cpu(dbs_boost_needed, this_cpu)) {
+ per_cpu(dbs_boost_needed, this_cpu) = false;
+ atomic_notifier_call_chain(&migration_notifier_head,
+ this_cpu,
+ (void *)cpu_of(busiest));
+ }
+ }
if (likely(!active_balance)) {
/* We were unbalanced, so reset the balancing interval */
sd->balance_interval = sd->min_interval;
@@ -4698,6 +4708,12 @@
out_unlock:
busiest_rq->active_balance = 0;
raw_spin_unlock_irq(&busiest_rq->lock);
+ if (per_cpu(dbs_boost_needed, target_cpu)) {
+ per_cpu(dbs_boost_needed, target_cpu) = false;
+ atomic_notifier_call_chain(&migration_notifier_head,
+ target_cpu,
+ (void *)cpu_of(busiest_rq));
+ }
return 0;
}
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 8f32475..f8317df 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1604,6 +1604,7 @@
struct task_struct *next_task;
struct rq *lowest_rq;
int ret = 0;
+ bool moved = false;
if (!rq->rt.overloaded)
return 0;
@@ -1673,6 +1674,7 @@
deactivate_task(rq, next_task, 0);
set_task_cpu(next_task, lowest_rq->cpu);
+ moved = true;
activate_task(lowest_rq, next_task, 0);
ret = 1;
@@ -1683,6 +1685,11 @@
out:
put_task_struct(next_task);
+ if (moved && task_notify_on_migrate(next_task))
+ atomic_notifier_call_chain(&migration_notifier_head,
+ cpu_of(lowest_rq),
+ (void *)cpu_of(rq));
+
return ret;
}
@@ -1696,8 +1703,10 @@
static int pull_rt_task(struct rq *this_rq)
{
int this_cpu = this_rq->cpu, ret = 0, cpu;
- struct task_struct *p;
+ struct task_struct *p = NULL;
struct rq *src_rq;
+ bool moved = false;
+ int src_cpu = 0;
if (likely(!rt_overloaded(this_rq)))
return 0;
@@ -1758,6 +1767,10 @@
deactivate_task(src_rq, p, 0);
set_task_cpu(p, this_cpu);
activate_task(this_rq, p, 0);
+
+ moved = true;
+ src_cpu = cpu_of(src_rq);
+
/*
* We continue with the search, just in
* case there's an even higher prio task
@@ -1769,6 +1782,11 @@
double_unlock_balance(this_rq, src_rq);
}
+ if (moved && task_notify_on_migrate(p))
+ atomic_notifier_call_chain(&migration_notifier_head,
+ this_cpu,
+ (void *)src_cpu);
+
return ret;
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 451bd4f..5370bcb 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -104,6 +104,8 @@
struct task_group {
struct cgroup_subsys_state css;
+ bool notify_on_migrate;
+
#ifdef CONFIG_FAIR_GROUP_SCHED
/* schedulable entities of this group on each cpu */
struct sched_entity **se;
@@ -554,6 +556,11 @@
return autogroup_task_group(p, tg);
}
+static inline bool task_notify_on_migrate(struct task_struct *p)
+{
+ return task_group(p)->notify_on_migrate;
+}
+
/* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
static inline void set_task_rq(struct task_struct *p, unsigned int cpu)
{
@@ -579,7 +586,10 @@
{
return NULL;
}
-
+static inline bool task_notify_on_migrate(struct task_struct *p)
+{
+ return false;
+}
#endif /* CONFIG_CGROUP_SCHED */
static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 5abf42f..f1a6e9e 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -46,11 +46,12 @@
enum {
/* global_cwq flags */
- GCWQ_MANAGE_WORKERS = 1 << 0, /* need to manage workers */
- GCWQ_MANAGING_WORKERS = 1 << 1, /* managing workers */
- GCWQ_DISASSOCIATED = 1 << 2, /* cpu can't serve workers */
- GCWQ_FREEZING = 1 << 3, /* freeze in progress */
- GCWQ_HIGHPRI_PENDING = 1 << 4, /* highpri works on queue */
+ GCWQ_DISASSOCIATED = 1 << 0, /* cpu can't serve workers */
+ GCWQ_FREEZING = 1 << 1, /* freeze in progress */
+
+ /* pool flags */
+ POOL_MANAGE_WORKERS = 1 << 0, /* need to manage workers */
+ POOL_MANAGING_WORKERS = 1 << 1, /* managing workers */
/* worker flags */
WORKER_STARTED = 1 << 0, /* started */
@@ -72,6 +73,8 @@
TRUSTEE_RELEASE = 3, /* release workers */
TRUSTEE_DONE = 4, /* trustee is done */
+ NR_WORKER_POOLS = 2, /* # worker pools per gcwq */
+
BUSY_WORKER_HASH_ORDER = 6, /* 64 pointers */
BUSY_WORKER_HASH_SIZE = 1 << BUSY_WORKER_HASH_ORDER,
BUSY_WORKER_HASH_MASK = BUSY_WORKER_HASH_SIZE - 1,
@@ -91,6 +94,7 @@
* all cpus. Give -20.
*/
RESCUER_NICE_LEVEL = -20,
+ HIGHPRI_NICE_LEVEL = -20,
};
/*
@@ -115,6 +119,7 @@
*/
struct global_cwq;
+struct worker_pool;
/*
* The poor guys doing the actual heavy lifting. All on-duty workers
@@ -131,7 +136,7 @@
struct cpu_workqueue_struct *current_cwq; /* L: current_work's cwq */
struct list_head scheduled; /* L: scheduled works */
struct task_struct *task; /* I: worker task */
- struct global_cwq *gcwq; /* I: the associated gcwq */
+ struct worker_pool *pool; /* I: the associated pool */
/* 64 bytes boundary on 64bit, 32 on 32bit */
unsigned long last_active; /* L: last active timestamp */
unsigned int flags; /* X: flags */
@@ -139,6 +144,22 @@
struct work_struct rebind_work; /* L: rebind worker to cpu */
};
+struct worker_pool {
+ struct global_cwq *gcwq; /* I: the owning gcwq */
+ unsigned int flags; /* X: flags */
+
+ struct list_head worklist; /* L: list of pending works */
+ int nr_workers; /* L: total number of workers */
+ int nr_idle; /* L: currently idle ones */
+
+ struct list_head idle_list; /* X: list of idle workers */
+ struct timer_list idle_timer; /* L: worker idle timeout */
+ struct timer_list mayday_timer; /* L: SOS timer for workers */
+
+ struct ida worker_ida; /* L: for worker IDs */
+ struct worker *first_idle; /* L: first idle worker */
+};
+
/*
* Global per-cpu workqueue. There's one and only one for each cpu
* and all works are queued and processed here regardless of their
@@ -146,27 +167,18 @@
*/
struct global_cwq {
spinlock_t lock; /* the gcwq lock */
- struct list_head worklist; /* L: list of pending works */
unsigned int cpu; /* I: the associated cpu */
unsigned int flags; /* L: GCWQ_* flags */
- int nr_workers; /* L: total number of workers */
- int nr_idle; /* L: currently idle ones */
-
- /* workers are chained either in the idle_list or busy_hash */
- struct list_head idle_list; /* X: list of idle workers */
+ /* workers are chained either in busy_hash or pool idle_list */
struct hlist_head busy_hash[BUSY_WORKER_HASH_SIZE];
/* L: hash of busy workers */
- struct timer_list idle_timer; /* L: worker idle timeout */
- struct timer_list mayday_timer; /* L: SOS timer for dworkers */
-
- struct ida worker_ida; /* L: for worker IDs */
+ struct worker_pool pools[2]; /* normal and highpri pools */
struct task_struct *trustee; /* L: for gcwq shutdown */
unsigned int trustee_state; /* L: trustee state */
wait_queue_head_t trustee_wait; /* trustee wait */
- struct worker *first_idle; /* L: first idle worker */
} ____cacheline_aligned_in_smp;
/*
@@ -175,7 +187,7 @@
* aligned at two's power of the number of flag bits.
*/
struct cpu_workqueue_struct {
- struct global_cwq *gcwq; /* I: the associated gcwq */
+ struct worker_pool *pool; /* I: the associated pool */
struct workqueue_struct *wq; /* I: the owning workqueue */
int work_color; /* L: current color */
int flush_color; /* L: flushing color */
@@ -264,6 +276,10 @@
#define CREATE_TRACE_POINTS
#include <trace/events/workqueue.h>
+#define for_each_worker_pool(pool, gcwq) \
+ for ((pool) = &(gcwq)->pools[0]; \
+ (pool) < &(gcwq)->pools[NR_WORKER_POOLS]; (pool)++)
+
#define for_each_busy_worker(worker, i, pos, gcwq) \
for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++) \
hlist_for_each_entry(worker, pos, &gcwq->busy_hash[i], hentry)
@@ -444,7 +460,7 @@
* try_to_wake_up(). Put it in a separate cacheline.
*/
static DEFINE_PER_CPU(struct global_cwq, global_cwq);
-static DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t, gcwq_nr_running);
+static DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t, pool_nr_running[NR_WORKER_POOLS]);
/*
* Global cpu workqueue and nr_running counter for unbound gcwq. The
@@ -452,10 +468,17 @@
* workers have WORKER_UNBOUND set.
*/
static struct global_cwq unbound_global_cwq;
-static atomic_t unbound_gcwq_nr_running = ATOMIC_INIT(0); /* always 0 */
+static atomic_t unbound_pool_nr_running[NR_WORKER_POOLS] = {
+ [0 ... NR_WORKER_POOLS - 1] = ATOMIC_INIT(0), /* always 0 */
+};
static int worker_thread(void *__worker);
+static int worker_pool_pri(struct worker_pool *pool)
+{
+ return pool - pool->gcwq->pools;
+}
+
static struct global_cwq *get_gcwq(unsigned int cpu)
{
if (cpu != WORK_CPU_UNBOUND)
@@ -464,12 +487,15 @@
return &unbound_global_cwq;
}
-static atomic_t *get_gcwq_nr_running(unsigned int cpu)
+static atomic_t *get_pool_nr_running(struct worker_pool *pool)
{
+ int cpu = pool->gcwq->cpu;
+ int idx = worker_pool_pri(pool);
+
if (cpu != WORK_CPU_UNBOUND)
- return &per_cpu(gcwq_nr_running, cpu);
+ return &per_cpu(pool_nr_running, cpu)[idx];
else
- return &unbound_gcwq_nr_running;
+ return &unbound_pool_nr_running[idx];
}
static struct cpu_workqueue_struct *get_cwq(unsigned int cpu,
@@ -555,7 +581,7 @@
if (data & WORK_STRUCT_CWQ)
return ((struct cpu_workqueue_struct *)
- (data & WORK_STRUCT_WQ_DATA_MASK))->gcwq;
+ (data & WORK_STRUCT_WQ_DATA_MASK))->pool->gcwq;
cpu = data >> WORK_STRUCT_FLAG_BITS;
if (cpu == WORK_CPU_NONE)
@@ -566,60 +592,62 @@
}
/*
- * Policy functions. These define the policies on how the global
- * worker pool is managed. Unless noted otherwise, these functions
- * assume that they're being called with gcwq->lock held.
+ * Policy functions. These define the policies on how the global worker
+ * pools are managed. Unless noted otherwise, these functions assume that
+ * they're being called with gcwq->lock held.
*/
-static bool __need_more_worker(struct global_cwq *gcwq)
+static bool __need_more_worker(struct worker_pool *pool)
{
- return !atomic_read(get_gcwq_nr_running(gcwq->cpu)) ||
- gcwq->flags & GCWQ_HIGHPRI_PENDING;
+ return !atomic_read(get_pool_nr_running(pool));
}
/*
* Need to wake up a worker? Called from anything but currently
* running workers.
+ *
+ * Note that, because unbound workers never contribute to nr_running, this
+ * function will always return %true for unbound gcwq as long as the
+ * worklist isn't empty.
*/
-static bool need_more_worker(struct global_cwq *gcwq)
+static bool need_more_worker(struct worker_pool *pool)
{
- return !list_empty(&gcwq->worklist) && __need_more_worker(gcwq);
+ return !list_empty(&pool->worklist) && __need_more_worker(pool);
}
/* Can I start working? Called from busy but !running workers. */
-static bool may_start_working(struct global_cwq *gcwq)
+static bool may_start_working(struct worker_pool *pool)
{
- return gcwq->nr_idle;
+ return pool->nr_idle;
}
/* Do I need to keep working? Called from currently running workers. */
-static bool keep_working(struct global_cwq *gcwq)
+static bool keep_working(struct worker_pool *pool)
{
- atomic_t *nr_running = get_gcwq_nr_running(gcwq->cpu);
+ atomic_t *nr_running = get_pool_nr_running(pool);
- return !list_empty(&gcwq->worklist) &&
- (atomic_read(nr_running) <= 1 ||
- gcwq->flags & GCWQ_HIGHPRI_PENDING);
+ return !list_empty(&pool->worklist) && atomic_read(nr_running) <= 1;
}
/* Do we need a new worker? Called from manager. */
-static bool need_to_create_worker(struct global_cwq *gcwq)
+static bool need_to_create_worker(struct worker_pool *pool)
{
- return need_more_worker(gcwq) && !may_start_working(gcwq);
+ return need_more_worker(pool) && !may_start_working(pool);
}
/* Do I need to be the manager? */
-static bool need_to_manage_workers(struct global_cwq *gcwq)
+static bool need_to_manage_workers(struct worker_pool *pool)
{
- return need_to_create_worker(gcwq) || gcwq->flags & GCWQ_MANAGE_WORKERS;
+ return need_to_create_worker(pool) ||
+ (pool->flags & POOL_MANAGE_WORKERS);
}
/* Do we have too many workers and should some go away? */
-static bool too_many_workers(struct global_cwq *gcwq)
+static bool too_many_workers(struct worker_pool *pool)
{
- bool managing = gcwq->flags & GCWQ_MANAGING_WORKERS;
- int nr_idle = gcwq->nr_idle + managing; /* manager is considered idle */
- int nr_busy = gcwq->nr_workers - nr_idle;
+ bool managing = pool->flags & POOL_MANAGING_WORKERS;
+ int nr_idle = pool->nr_idle + managing; /* manager is considered idle */
+ int nr_busy = pool->nr_workers - nr_idle;
return nr_idle > 2 && (nr_idle - 2) * MAX_IDLE_WORKERS_RATIO >= nr_busy;
}
@@ -629,26 +657,26 @@
*/
/* Return the first worker. Safe with preemption disabled */
-static struct worker *first_worker(struct global_cwq *gcwq)
+static struct worker *first_worker(struct worker_pool *pool)
{
- if (unlikely(list_empty(&gcwq->idle_list)))
+ if (unlikely(list_empty(&pool->idle_list)))
return NULL;
- return list_first_entry(&gcwq->idle_list, struct worker, entry);
+ return list_first_entry(&pool->idle_list, struct worker, entry);
}
/**
* wake_up_worker - wake up an idle worker
- * @gcwq: gcwq to wake worker for
+ * @pool: worker pool to wake worker from
*
- * Wake up the first idle worker of @gcwq.
+ * Wake up the first idle worker of @pool.
*
* CONTEXT:
* spin_lock_irq(gcwq->lock).
*/
-static void wake_up_worker(struct global_cwq *gcwq)
+static void wake_up_worker(struct worker_pool *pool)
{
- struct worker *worker = first_worker(gcwq);
+ struct worker *worker = first_worker(pool);
if (likely(worker))
wake_up_process(worker->task);
@@ -670,7 +698,7 @@
struct worker *worker = kthread_data(task);
if (!(worker->flags & WORKER_NOT_RUNNING))
- atomic_inc(get_gcwq_nr_running(cpu));
+ atomic_inc(get_pool_nr_running(worker->pool));
}
/**
@@ -692,8 +720,8 @@
unsigned int cpu)
{
struct worker *worker = kthread_data(task), *to_wakeup = NULL;
- struct global_cwq *gcwq = get_gcwq(cpu);
- atomic_t *nr_running = get_gcwq_nr_running(cpu);
+ struct worker_pool *pool = worker->pool;
+ atomic_t *nr_running = get_pool_nr_running(pool);
if (worker->flags & WORKER_NOT_RUNNING)
return NULL;
@@ -712,8 +740,8 @@
* could be manipulating idle_list, so dereferencing idle_list
* without gcwq lock is safe.
*/
- if (atomic_dec_and_test(nr_running) && !list_empty(&gcwq->worklist))
- to_wakeup = first_worker(gcwq);
+ if (atomic_dec_and_test(nr_running) && !list_empty(&pool->worklist))
+ to_wakeup = first_worker(pool);
return to_wakeup ? to_wakeup->task : NULL;
}
@@ -733,7 +761,7 @@
static inline void worker_set_flags(struct worker *worker, unsigned int flags,
bool wakeup)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
WARN_ON_ONCE(worker->task != current);
@@ -744,12 +772,12 @@
*/
if ((flags & WORKER_NOT_RUNNING) &&
!(worker->flags & WORKER_NOT_RUNNING)) {
- atomic_t *nr_running = get_gcwq_nr_running(gcwq->cpu);
+ atomic_t *nr_running = get_pool_nr_running(pool);
if (wakeup) {
if (atomic_dec_and_test(nr_running) &&
- !list_empty(&gcwq->worklist))
- wake_up_worker(gcwq);
+ !list_empty(&pool->worklist))
+ wake_up_worker(pool);
} else
atomic_dec(nr_running);
}
@@ -769,7 +797,7 @@
*/
static inline void worker_clr_flags(struct worker *worker, unsigned int flags)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
unsigned int oflags = worker->flags;
WARN_ON_ONCE(worker->task != current);
@@ -783,7 +811,7 @@
*/
if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING))
if (!(worker->flags & WORKER_NOT_RUNNING))
- atomic_inc(get_gcwq_nr_running(gcwq->cpu));
+ atomic_inc(get_pool_nr_running(pool));
}
/**
@@ -867,43 +895,6 @@
}
/**
- * gcwq_determine_ins_pos - find insertion position
- * @gcwq: gcwq of interest
- * @cwq: cwq a work is being queued for
- *
- * A work for @cwq is about to be queued on @gcwq, determine insertion
- * position for the work. If @cwq is for HIGHPRI wq, the work is
- * queued at the head of the queue but in FIFO order with respect to
- * other HIGHPRI works; otherwise, at the end of the queue. This
- * function also sets GCWQ_HIGHPRI_PENDING flag to hint @gcwq that
- * there are HIGHPRI works pending.
- *
- * CONTEXT:
- * spin_lock_irq(gcwq->lock).
- *
- * RETURNS:
- * Pointer to inserstion position.
- */
-static inline struct list_head *gcwq_determine_ins_pos(struct global_cwq *gcwq,
- struct cpu_workqueue_struct *cwq)
-{
- struct work_struct *twork;
-
- if (likely(!(cwq->wq->flags & WQ_HIGHPRI)))
- return &gcwq->worklist;
-
- list_for_each_entry(twork, &gcwq->worklist, entry) {
- struct cpu_workqueue_struct *tcwq = get_work_cwq(twork);
-
- if (!(tcwq->wq->flags & WQ_HIGHPRI))
- break;
- }
-
- gcwq->flags |= GCWQ_HIGHPRI_PENDING;
- return &twork->entry;
-}
-
-/**
* insert_work - insert a work into gcwq
* @cwq: cwq @work belongs to
* @work: work to insert
@@ -920,7 +911,7 @@
struct work_struct *work, struct list_head *head,
unsigned int extra_flags)
{
- struct global_cwq *gcwq = cwq->gcwq;
+ struct worker_pool *pool = cwq->pool;
/* we own @work, set data and link */
set_work_cwq(work, cwq, extra_flags);
@@ -940,8 +931,8 @@
*/
smp_mb();
- if (__need_more_worker(gcwq))
- wake_up_worker(gcwq);
+ if (__need_more_worker(pool))
+ wake_up_worker(pool);
}
/*
@@ -1040,7 +1031,7 @@
if (likely(cwq->nr_active < cwq->max_active)) {
trace_workqueue_activate_work(work);
cwq->nr_active++;
- worklist = gcwq_determine_ins_pos(gcwq, cwq);
+ worklist = &cwq->pool->worklist;
} else {
work_flags |= WORK_STRUCT_DELAYED;
worklist = &cwq->delayed_works;
@@ -1189,7 +1180,8 @@
*/
static void worker_enter_idle(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
BUG_ON(worker->flags & WORKER_IDLE);
BUG_ON(!list_empty(&worker->entry) &&
@@ -1197,22 +1189,27 @@
/* can't use worker_set_flags(), also called from start_worker() */
worker->flags |= WORKER_IDLE;
- gcwq->nr_idle++;
+ pool->nr_idle++;
worker->last_active = jiffies;
/* idle_list is LIFO */
- list_add(&worker->entry, &gcwq->idle_list);
+ list_add(&worker->entry, &pool->idle_list);
if (likely(!(worker->flags & WORKER_ROGUE))) {
- if (too_many_workers(gcwq) && !timer_pending(&gcwq->idle_timer))
- mod_timer(&gcwq->idle_timer,
+ if (too_many_workers(pool) && !timer_pending(&pool->idle_timer))
+ mod_timer(&pool->idle_timer,
jiffies + IDLE_WORKER_TIMEOUT);
} else
wake_up_all(&gcwq->trustee_wait);
- /* sanity check nr_running */
- WARN_ON_ONCE(gcwq->nr_workers == gcwq->nr_idle &&
- atomic_read(get_gcwq_nr_running(gcwq->cpu)));
+ /*
+ * Sanity check nr_running. Because trustee releases gcwq->lock
+ * between setting %WORKER_ROGUE and zapping nr_running, the
+ * warning may trigger spuriously. Check iff trustee is idle.
+ */
+ WARN_ON_ONCE(gcwq->trustee_state == TRUSTEE_DONE &&
+ pool->nr_workers == pool->nr_idle &&
+ atomic_read(get_pool_nr_running(pool)));
}
/**
@@ -1226,11 +1223,11 @@
*/
static void worker_leave_idle(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
BUG_ON(!(worker->flags & WORKER_IDLE));
worker_clr_flags(worker, WORKER_IDLE);
- gcwq->nr_idle--;
+ pool->nr_idle--;
list_del_init(&worker->entry);
}
@@ -1267,7 +1264,7 @@
static bool worker_maybe_bind_and_lock(struct worker *worker)
__acquires(&gcwq->lock)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct global_cwq *gcwq = worker->pool->gcwq;
struct task_struct *task = worker->task;
while (true) {
@@ -1309,7 +1306,7 @@
static void worker_rebind_fn(struct work_struct *work)
{
struct worker *worker = container_of(work, struct worker, rebind_work);
- struct global_cwq *gcwq = worker->gcwq;
+ struct global_cwq *gcwq = worker->pool->gcwq;
if (worker_maybe_bind_and_lock(worker))
worker_clr_flags(worker, WORKER_REBIND);
@@ -1334,10 +1331,10 @@
/**
* create_worker - create a new workqueue worker
- * @gcwq: gcwq the new worker will belong to
+ * @pool: pool the new worker will belong to
* @bind: whether to set affinity to @cpu or not
*
- * Create a new worker which is bound to @gcwq. The returned worker
+ * Create a new worker which is bound to @pool. The returned worker
* can be started by calling start_worker() or destroyed using
* destroy_worker().
*
@@ -1347,16 +1344,18 @@
* RETURNS:
* Pointer to the newly created worker.
*/
-static struct worker *create_worker(struct global_cwq *gcwq, bool bind)
+static struct worker *create_worker(struct worker_pool *pool, bool bind)
{
+ struct global_cwq *gcwq = pool->gcwq;
bool on_unbound_cpu = gcwq->cpu == WORK_CPU_UNBOUND;
+ const char *pri = worker_pool_pri(pool) ? "H" : "";
struct worker *worker = NULL;
int id = -1;
spin_lock_irq(&gcwq->lock);
- while (ida_get_new(&gcwq->worker_ida, &id)) {
+ while (ida_get_new(&pool->worker_ida, &id)) {
spin_unlock_irq(&gcwq->lock);
- if (!ida_pre_get(&gcwq->worker_ida, GFP_KERNEL))
+ if (!ida_pre_get(&pool->worker_ida, GFP_KERNEL))
goto fail;
spin_lock_irq(&gcwq->lock);
}
@@ -1366,20 +1365,22 @@
if (!worker)
goto fail;
- worker->gcwq = gcwq;
+ worker->pool = pool;
worker->id = id;
if (!on_unbound_cpu)
worker->task = kthread_create_on_node(worker_thread,
- worker,
- cpu_to_node(gcwq->cpu),
- "kworker/%u:%d", gcwq->cpu, id);
+ worker, cpu_to_node(gcwq->cpu),
+ "kworker/%u:%d%s", gcwq->cpu, id, pri);
else
worker->task = kthread_create(worker_thread, worker,
- "kworker/u:%d", id);
+ "kworker/u:%d%s", id, pri);
if (IS_ERR(worker->task))
goto fail;
+ if (worker_pool_pri(pool))
+ set_user_nice(worker->task, HIGHPRI_NICE_LEVEL);
+
/*
* A rogue worker will become a regular one if CPU comes
* online later on. Make sure every worker has
@@ -1397,7 +1398,7 @@
fail:
if (id >= 0) {
spin_lock_irq(&gcwq->lock);
- ida_remove(&gcwq->worker_ida, id);
+ ida_remove(&pool->worker_ida, id);
spin_unlock_irq(&gcwq->lock);
}
kfree(worker);
@@ -1416,7 +1417,7 @@
static void start_worker(struct worker *worker)
{
worker->flags |= WORKER_STARTED;
- worker->gcwq->nr_workers++;
+ worker->pool->nr_workers++;
worker_enter_idle(worker);
wake_up_process(worker->task);
}
@@ -1432,7 +1433,8 @@
*/
static void destroy_worker(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
int id = worker->id;
/* sanity check frenzy */
@@ -1440,9 +1442,9 @@
BUG_ON(!list_empty(&worker->scheduled));
if (worker->flags & WORKER_STARTED)
- gcwq->nr_workers--;
+ pool->nr_workers--;
if (worker->flags & WORKER_IDLE)
- gcwq->nr_idle--;
+ pool->nr_idle--;
list_del_init(&worker->entry);
worker->flags |= WORKER_DIE;
@@ -1453,29 +1455,30 @@
kfree(worker);
spin_lock_irq(&gcwq->lock);
- ida_remove(&gcwq->worker_ida, id);
+ ida_remove(&pool->worker_ida, id);
}
-static void idle_worker_timeout(unsigned long __gcwq)
+static void idle_worker_timeout(unsigned long __pool)
{
- struct global_cwq *gcwq = (void *)__gcwq;
+ struct worker_pool *pool = (void *)__pool;
+ struct global_cwq *gcwq = pool->gcwq;
spin_lock_irq(&gcwq->lock);
- if (too_many_workers(gcwq)) {
+ if (too_many_workers(pool)) {
struct worker *worker;
unsigned long expires;
/* idle_list is kept in LIFO order, check the last one */
- worker = list_entry(gcwq->idle_list.prev, struct worker, entry);
+ worker = list_entry(pool->idle_list.prev, struct worker, entry);
expires = worker->last_active + IDLE_WORKER_TIMEOUT;
if (time_before(jiffies, expires))
- mod_timer(&gcwq->idle_timer, expires);
+ mod_timer(&pool->idle_timer, expires);
else {
/* it's been idle for too long, wake up manager */
- gcwq->flags |= GCWQ_MANAGE_WORKERS;
- wake_up_worker(gcwq);
+ pool->flags |= POOL_MANAGE_WORKERS;
+ wake_up_worker(pool);
}
}
@@ -1492,7 +1495,7 @@
return false;
/* mayday mayday mayday */
- cpu = cwq->gcwq->cpu;
+ cpu = cwq->pool->gcwq->cpu;
/* WORK_CPU_UNBOUND can't be set in cpumask, use cpu 0 instead */
if (cpu == WORK_CPU_UNBOUND)
cpu = 0;
@@ -1501,37 +1504,38 @@
return true;
}
-static void gcwq_mayday_timeout(unsigned long __gcwq)
+static void gcwq_mayday_timeout(unsigned long __pool)
{
- struct global_cwq *gcwq = (void *)__gcwq;
+ struct worker_pool *pool = (void *)__pool;
+ struct global_cwq *gcwq = pool->gcwq;
struct work_struct *work;
spin_lock_irq(&gcwq->lock);
- if (need_to_create_worker(gcwq)) {
+ if (need_to_create_worker(pool)) {
/*
* We've been trying to create a new worker but
* haven't been successful. We might be hitting an
* allocation deadlock. Send distress signals to
* rescuers.
*/
- list_for_each_entry(work, &gcwq->worklist, entry)
+ list_for_each_entry(work, &pool->worklist, entry)
send_mayday(work);
}
spin_unlock_irq(&gcwq->lock);
- mod_timer(&gcwq->mayday_timer, jiffies + MAYDAY_INTERVAL);
+ mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INTERVAL);
}
/**
* maybe_create_worker - create a new worker if necessary
- * @gcwq: gcwq to create a new worker for
+ * @pool: pool to create a new worker for
*
- * Create a new worker for @gcwq if necessary. @gcwq is guaranteed to
+ * Create a new worker for @pool if necessary. @pool is guaranteed to
* have at least one idle worker on return from this function. If
* creating a new worker takes longer than MAYDAY_INTERVAL, mayday is
- * sent to all rescuers with works scheduled on @gcwq to resolve
+ * sent to all rescuers with works scheduled on @pool to resolve
* possible allocation deadlock.
*
* On return, need_to_create_worker() is guaranteed to be false and
@@ -1546,52 +1550,54 @@
* false if no action was taken and gcwq->lock stayed locked, true
* otherwise.
*/
-static bool maybe_create_worker(struct global_cwq *gcwq)
+static bool maybe_create_worker(struct worker_pool *pool)
__releases(&gcwq->lock)
__acquires(&gcwq->lock)
{
- if (!need_to_create_worker(gcwq))
+ struct global_cwq *gcwq = pool->gcwq;
+
+ if (!need_to_create_worker(pool))
return false;
restart:
spin_unlock_irq(&gcwq->lock);
/* if we don't make progress in MAYDAY_INITIAL_TIMEOUT, call for help */
- mod_timer(&gcwq->mayday_timer, jiffies + MAYDAY_INITIAL_TIMEOUT);
+ mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INITIAL_TIMEOUT);
while (true) {
struct worker *worker;
- worker = create_worker(gcwq, true);
+ worker = create_worker(pool, true);
if (worker) {
- del_timer_sync(&gcwq->mayday_timer);
+ del_timer_sync(&pool->mayday_timer);
spin_lock_irq(&gcwq->lock);
start_worker(worker);
- BUG_ON(need_to_create_worker(gcwq));
+ BUG_ON(need_to_create_worker(pool));
return true;
}
- if (!need_to_create_worker(gcwq))
+ if (!need_to_create_worker(pool))
break;
__set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(CREATE_COOLDOWN);
- if (!need_to_create_worker(gcwq))
+ if (!need_to_create_worker(pool))
break;
}
- del_timer_sync(&gcwq->mayday_timer);
+ del_timer_sync(&pool->mayday_timer);
spin_lock_irq(&gcwq->lock);
- if (need_to_create_worker(gcwq))
+ if (need_to_create_worker(pool))
goto restart;
return true;
}
/**
* maybe_destroy_worker - destroy workers which have been idle for a while
- * @gcwq: gcwq to destroy workers for
+ * @pool: pool to destroy workers for
*
- * Destroy @gcwq workers which have been idle for longer than
+ * Destroy @pool workers which have been idle for longer than
* IDLE_WORKER_TIMEOUT.
*
* LOCKING:
@@ -1602,19 +1608,19 @@
* false if no action was taken and gcwq->lock stayed locked, true
* otherwise.
*/
-static bool maybe_destroy_workers(struct global_cwq *gcwq)
+static bool maybe_destroy_workers(struct worker_pool *pool)
{
bool ret = false;
- while (too_many_workers(gcwq)) {
+ while (too_many_workers(pool)) {
struct worker *worker;
unsigned long expires;
- worker = list_entry(gcwq->idle_list.prev, struct worker, entry);
+ worker = list_entry(pool->idle_list.prev, struct worker, entry);
expires = worker->last_active + IDLE_WORKER_TIMEOUT;
if (time_before(jiffies, expires)) {
- mod_timer(&gcwq->idle_timer, expires);
+ mod_timer(&pool->idle_timer, expires);
break;
}
@@ -1647,23 +1653,24 @@
*/
static bool manage_workers(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
bool ret = false;
- if (gcwq->flags & GCWQ_MANAGING_WORKERS)
+ if (pool->flags & POOL_MANAGING_WORKERS)
return ret;
- gcwq->flags &= ~GCWQ_MANAGE_WORKERS;
- gcwq->flags |= GCWQ_MANAGING_WORKERS;
+ pool->flags &= ~POOL_MANAGE_WORKERS;
+ pool->flags |= POOL_MANAGING_WORKERS;
/*
* Destroy and then create so that may_start_working() is true
* on return.
*/
- ret |= maybe_destroy_workers(gcwq);
- ret |= maybe_create_worker(gcwq);
+ ret |= maybe_destroy_workers(pool);
+ ret |= maybe_create_worker(pool);
- gcwq->flags &= ~GCWQ_MANAGING_WORKERS;
+ pool->flags &= ~POOL_MANAGING_WORKERS;
/*
* The trustee might be waiting to take over the manager
@@ -1720,10 +1727,9 @@
{
struct work_struct *work = list_first_entry(&cwq->delayed_works,
struct work_struct, entry);
- struct list_head *pos = gcwq_determine_ins_pos(cwq->gcwq, cwq);
trace_workqueue_activate_work(work);
- move_linked_works(work, pos, NULL);
+ move_linked_works(work, &cwq->pool->worklist, NULL);
__clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work));
cwq->nr_active++;
}
@@ -1796,7 +1802,8 @@
__acquires(&gcwq->lock)
{
struct cpu_workqueue_struct *cwq = get_work_cwq(work);
- struct global_cwq *gcwq = cwq->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
struct hlist_head *bwh = busy_worker_head(gcwq, work);
bool cpu_intensive = cwq->wq->flags & WQ_CPU_INTENSIVE;
work_func_t f = work->func;
@@ -1836,27 +1843,19 @@
list_del_init(&work->entry);
/*
- * If HIGHPRI_PENDING, check the next work, and, if HIGHPRI,
- * wake up another worker; otherwise, clear HIGHPRI_PENDING.
- */
- if (unlikely(gcwq->flags & GCWQ_HIGHPRI_PENDING)) {
- struct work_struct *nwork = list_first_entry(&gcwq->worklist,
- struct work_struct, entry);
-
- if (!list_empty(&gcwq->worklist) &&
- get_work_cwq(nwork)->wq->flags & WQ_HIGHPRI)
- wake_up_worker(gcwq);
- else
- gcwq->flags &= ~GCWQ_HIGHPRI_PENDING;
- }
-
- /*
* CPU intensive works don't participate in concurrency
* management. They're the scheduler's responsibility.
*/
if (unlikely(cpu_intensive))
worker_set_flags(worker, WORKER_CPU_INTENSIVE, true);
+ /*
+ * Unbound gcwq isn't concurrency managed and work items should be
+ * executed ASAP. Wake up another worker if necessary.
+ */
+ if ((worker->flags & WORKER_UNBOUND) && need_more_worker(pool))
+ wake_up_worker(pool);
+
spin_unlock_irq(&gcwq->lock);
work_clear_pending(work);
@@ -1929,7 +1928,8 @@
static int worker_thread(void *__worker)
{
struct worker *worker = __worker;
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
/* tell the scheduler that this is a workqueue worker */
worker->task->flags |= PF_WQ_WORKER;
@@ -1946,11 +1946,11 @@
worker_leave_idle(worker);
recheck:
/* no more worker necessary? */
- if (!need_more_worker(gcwq))
+ if (!need_more_worker(pool))
goto sleep;
/* do we need to manage? */
- if (unlikely(!may_start_working(gcwq)) && manage_workers(worker))
+ if (unlikely(!may_start_working(pool)) && manage_workers(worker))
goto recheck;
/*
@@ -1969,7 +1969,7 @@
do {
struct work_struct *work =
- list_first_entry(&gcwq->worklist,
+ list_first_entry(&pool->worklist,
struct work_struct, entry);
if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) {
@@ -1981,11 +1981,11 @@
move_linked_works(work, &worker->scheduled, NULL);
process_scheduled_works(worker);
}
- } while (keep_working(gcwq));
+ } while (keep_working(pool));
worker_set_flags(worker, WORKER_PREP, false);
sleep:
- if (unlikely(need_to_manage_workers(gcwq)) && manage_workers(worker))
+ if (unlikely(need_to_manage_workers(pool)) && manage_workers(worker))
goto recheck;
/*
@@ -2043,14 +2043,15 @@
for_each_mayday_cpu(cpu, wq->mayday_mask) {
unsigned int tcpu = is_unbound ? WORK_CPU_UNBOUND : cpu;
struct cpu_workqueue_struct *cwq = get_cwq(tcpu, wq);
- struct global_cwq *gcwq = cwq->gcwq;
+ struct worker_pool *pool = cwq->pool;
+ struct global_cwq *gcwq = pool->gcwq;
struct work_struct *work, *n;
__set_current_state(TASK_RUNNING);
mayday_clear_cpu(cpu, wq->mayday_mask);
/* migrate to the target cpu if possible */
- rescuer->gcwq = gcwq;
+ rescuer->pool = pool;
worker_maybe_bind_and_lock(rescuer);
/*
@@ -2058,7 +2059,7 @@
* process'em.
*/
BUG_ON(!list_empty(&rescuer->scheduled));
- list_for_each_entry_safe(work, n, &gcwq->worklist, entry)
+ list_for_each_entry_safe(work, n, &pool->worklist, entry)
if (get_work_cwq(work) == cwq)
move_linked_works(work, scheduled, &n);
@@ -2069,8 +2070,8 @@
* regular worker; otherwise, we end up with 0 concurrency
* and stalling the execution.
*/
- if (keep_working(gcwq))
- wake_up_worker(gcwq);
+ if (keep_working(pool))
+ wake_up_worker(pool);
spin_unlock_irq(&gcwq->lock);
}
@@ -2195,7 +2196,7 @@
for_each_cwq_cpu(cpu, wq) {
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
- struct global_cwq *gcwq = cwq->gcwq;
+ struct global_cwq *gcwq = cwq->pool->gcwq;
spin_lock_irq(&gcwq->lock);
@@ -2411,9 +2412,9 @@
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
bool drained;
- spin_lock_irq(&cwq->gcwq->lock);
+ spin_lock_irq(&cwq->pool->gcwq->lock);
drained = !cwq->nr_active && list_empty(&cwq->delayed_works);
- spin_unlock_irq(&cwq->gcwq->lock);
+ spin_unlock_irq(&cwq->pool->gcwq->lock);
if (drained)
continue;
@@ -2453,7 +2454,7 @@
*/
smp_rmb();
cwq = get_work_cwq(work);
- if (unlikely(!cwq || gcwq != cwq->gcwq))
+ if (unlikely(!cwq || gcwq != cwq->pool->gcwq))
goto already_gone;
} else if (wait_executing) {
worker = find_worker_executing_work(gcwq, work);
@@ -2971,13 +2972,6 @@
if (flags & WQ_MEM_RECLAIM)
flags |= WQ_RESCUER;
- /*
- * Unbound workqueues aren't concurrency managed and should be
- * dispatched to workers immediately.
- */
- if (flags & WQ_UNBOUND)
- flags |= WQ_HIGHPRI;
-
max_active = max_active ?: WQ_DFL_ACTIVE;
max_active = wq_clamp_max_active(max_active, flags, wq->name);
@@ -2998,9 +2992,10 @@
for_each_cwq_cpu(cpu, wq) {
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
struct global_cwq *gcwq = get_gcwq(cpu);
+ int pool_idx = (bool)(flags & WQ_HIGHPRI);
BUG_ON((unsigned long)cwq & WORK_STRUCT_FLAG_MASK);
- cwq->gcwq = gcwq;
+ cwq->pool = &gcwq->pools[pool_idx];
cwq->wq = wq;
cwq->flush_color = -1;
cwq->max_active = max_active;
@@ -3304,9 +3299,30 @@
__ret1 < 0 ? -1 : 0; \
})
+static bool gcwq_is_managing_workers(struct global_cwq *gcwq)
+{
+ struct worker_pool *pool;
+
+ for_each_worker_pool(pool, gcwq)
+ if (pool->flags & POOL_MANAGING_WORKERS)
+ return true;
+ return false;
+}
+
+static bool gcwq_has_idle_workers(struct global_cwq *gcwq)
+{
+ struct worker_pool *pool;
+
+ for_each_worker_pool(pool, gcwq)
+ if (!list_empty(&pool->idle_list))
+ return true;
+ return false;
+}
+
static int __cpuinit trustee_thread(void *__gcwq)
{
struct global_cwq *gcwq = __gcwq;
+ struct worker_pool *pool;
struct worker *worker;
struct work_struct *work;
struct hlist_node *pos;
@@ -3322,13 +3338,15 @@
* cancelled.
*/
BUG_ON(gcwq->cpu != smp_processor_id());
- rc = trustee_wait_event(!(gcwq->flags & GCWQ_MANAGING_WORKERS));
+ rc = trustee_wait_event(!gcwq_is_managing_workers(gcwq));
BUG_ON(rc < 0);
- gcwq->flags |= GCWQ_MANAGING_WORKERS;
+ for_each_worker_pool(pool, gcwq) {
+ pool->flags |= POOL_MANAGING_WORKERS;
- list_for_each_entry(worker, &gcwq->idle_list, entry)
- worker->flags |= WORKER_ROGUE;
+ list_for_each_entry(worker, &pool->idle_list, entry)
+ worker->flags |= WORKER_ROGUE;
+ }
for_each_busy_worker(worker, i, pos, gcwq)
worker->flags |= WORKER_ROGUE;
@@ -3349,10 +3367,12 @@
* keep_working() are always true as long as the worklist is
* not empty.
*/
- atomic_set(get_gcwq_nr_running(gcwq->cpu), 0);
+ for_each_worker_pool(pool, gcwq)
+ atomic_set(get_pool_nr_running(pool), 0);
spin_unlock_irq(&gcwq->lock);
- del_timer_sync(&gcwq->idle_timer);
+ for_each_worker_pool(pool, gcwq)
+ del_timer_sync(&pool->idle_timer);
spin_lock_irq(&gcwq->lock);
/*
@@ -3374,29 +3394,38 @@
* may be frozen works in freezable cwqs. Don't declare
* completion while frozen.
*/
- while (gcwq->nr_workers != gcwq->nr_idle ||
- gcwq->flags & GCWQ_FREEZING ||
- gcwq->trustee_state == TRUSTEE_IN_CHARGE) {
- int nr_works = 0;
+ while (true) {
+ bool busy = false;
- list_for_each_entry(work, &gcwq->worklist, entry) {
- send_mayday(work);
- nr_works++;
- }
+ for_each_worker_pool(pool, gcwq)
+ busy |= pool->nr_workers != pool->nr_idle;
- list_for_each_entry(worker, &gcwq->idle_list, entry) {
- if (!nr_works--)
- break;
- wake_up_process(worker->task);
- }
+ if (!busy && !(gcwq->flags & GCWQ_FREEZING) &&
+ gcwq->trustee_state != TRUSTEE_IN_CHARGE)
+ break;
- if (need_to_create_worker(gcwq)) {
- spin_unlock_irq(&gcwq->lock);
- worker = create_worker(gcwq, false);
- spin_lock_irq(&gcwq->lock);
- if (worker) {
- worker->flags |= WORKER_ROGUE;
- start_worker(worker);
+ for_each_worker_pool(pool, gcwq) {
+ int nr_works = 0;
+
+ list_for_each_entry(work, &pool->worklist, entry) {
+ send_mayday(work);
+ nr_works++;
+ }
+
+ list_for_each_entry(worker, &pool->idle_list, entry) {
+ if (!nr_works--)
+ break;
+ wake_up_process(worker->task);
+ }
+
+ if (need_to_create_worker(pool)) {
+ spin_unlock_irq(&gcwq->lock);
+ worker = create_worker(pool, false);
+ spin_lock_irq(&gcwq->lock);
+ if (worker) {
+ worker->flags |= WORKER_ROGUE;
+ start_worker(worker);
+ }
}
}
@@ -3411,11 +3440,18 @@
* all workers till we're canceled.
*/
do {
- rc = trustee_wait_event(!list_empty(&gcwq->idle_list));
- while (!list_empty(&gcwq->idle_list))
- destroy_worker(list_first_entry(&gcwq->idle_list,
- struct worker, entry));
- } while (gcwq->nr_workers && rc >= 0);
+ rc = trustee_wait_event(gcwq_has_idle_workers(gcwq));
+
+ i = 0;
+ for_each_worker_pool(pool, gcwq) {
+ while (!list_empty(&pool->idle_list)) {
+ worker = list_first_entry(&pool->idle_list,
+ struct worker, entry);
+ destroy_worker(worker);
+ }
+ i |= pool->nr_workers;
+ }
+ } while (i && rc >= 0);
/*
* At this point, either draining has completed and no worker
@@ -3424,7 +3460,8 @@
* Tell the remaining busy ones to rebind once it finishes the
* currently scheduled works by scheduling the rebind_work.
*/
- WARN_ON(!list_empty(&gcwq->idle_list));
+ for_each_worker_pool(pool, gcwq)
+ WARN_ON(!list_empty(&pool->idle_list));
for_each_busy_worker(worker, i, pos, gcwq) {
struct work_struct *rebind_work = &worker->rebind_work;
@@ -3449,7 +3486,8 @@
}
/* relinquish manager role */
- gcwq->flags &= ~GCWQ_MANAGING_WORKERS;
+ for_each_worker_pool(pool, gcwq)
+ pool->flags &= ~POOL_MANAGING_WORKERS;
/* notify completion */
gcwq->trustee = NULL;
@@ -3491,8 +3529,10 @@
unsigned int cpu = (unsigned long)hcpu;
struct global_cwq *gcwq = get_gcwq(cpu);
struct task_struct *new_trustee = NULL;
- struct worker *uninitialized_var(new_worker);
+ struct worker *new_workers[NR_WORKER_POOLS] = { };
+ struct worker_pool *pool;
unsigned long flags;
+ int i;
action &= ~CPU_TASKS_FROZEN;
@@ -3505,12 +3545,12 @@
kthread_bind(new_trustee, cpu);
/* fall through */
case CPU_UP_PREPARE:
- BUG_ON(gcwq->first_idle);
- new_worker = create_worker(gcwq, false);
- if (!new_worker) {
- if (new_trustee)
- kthread_stop(new_trustee);
- return NOTIFY_BAD;
+ i = 0;
+ for_each_worker_pool(pool, gcwq) {
+ BUG_ON(pool->first_idle);
+ new_workers[i] = create_worker(pool, false);
+ if (!new_workers[i++])
+ goto err_destroy;
}
}
@@ -3527,8 +3567,11 @@
wait_trustee_state(gcwq, TRUSTEE_IN_CHARGE);
/* fall through */
case CPU_UP_PREPARE:
- BUG_ON(gcwq->first_idle);
- gcwq->first_idle = new_worker;
+ i = 0;
+ for_each_worker_pool(pool, gcwq) {
+ BUG_ON(pool->first_idle);
+ pool->first_idle = new_workers[i++];
+ }
break;
case CPU_DYING:
@@ -3545,8 +3588,10 @@
gcwq->trustee_state = TRUSTEE_BUTCHER;
/* fall through */
case CPU_UP_CANCELED:
- destroy_worker(gcwq->first_idle);
- gcwq->first_idle = NULL;
+ for_each_worker_pool(pool, gcwq) {
+ destroy_worker(pool->first_idle);
+ pool->first_idle = NULL;
+ }
break;
case CPU_DOWN_FAILED:
@@ -3563,18 +3608,32 @@
* Put the first_idle in and request a real manager to
* take a look.
*/
- spin_unlock_irq(&gcwq->lock);
- kthread_bind(gcwq->first_idle->task, cpu);
- spin_lock_irq(&gcwq->lock);
- gcwq->flags |= GCWQ_MANAGE_WORKERS;
- start_worker(gcwq->first_idle);
- gcwq->first_idle = NULL;
+ for_each_worker_pool(pool, gcwq) {
+ spin_unlock_irq(&gcwq->lock);
+ kthread_bind(pool->first_idle->task, cpu);
+ spin_lock_irq(&gcwq->lock);
+ pool->flags |= POOL_MANAGE_WORKERS;
+ start_worker(pool->first_idle);
+ pool->first_idle = NULL;
+ }
break;
}
spin_unlock_irqrestore(&gcwq->lock, flags);
return notifier_from_errno(0);
+
+err_destroy:
+ if (new_trustee)
+ kthread_stop(new_trustee);
+
+ spin_lock_irqsave(&gcwq->lock, flags);
+ for (i = 0; i < NR_WORKER_POOLS; i++)
+ if (new_workers[i])
+ destroy_worker(new_workers[i]);
+ spin_unlock_irqrestore(&gcwq->lock, flags);
+
+ return NOTIFY_BAD;
}
#ifdef CONFIG_SMP
@@ -3733,6 +3792,7 @@
for_each_gcwq_cpu(cpu) {
struct global_cwq *gcwq = get_gcwq(cpu);
+ struct worker_pool *pool;
struct workqueue_struct *wq;
spin_lock_irq(&gcwq->lock);
@@ -3754,7 +3814,8 @@
cwq_activate_first_delayed(cwq);
}
- wake_up_worker(gcwq);
+ for_each_worker_pool(pool, gcwq)
+ wake_up_worker(pool);
spin_unlock_irq(&gcwq->lock);
}
@@ -3775,24 +3836,29 @@
/* initialize gcwqs */
for_each_gcwq_cpu(cpu) {
struct global_cwq *gcwq = get_gcwq(cpu);
+ struct worker_pool *pool;
spin_lock_init(&gcwq->lock);
- INIT_LIST_HEAD(&gcwq->worklist);
gcwq->cpu = cpu;
gcwq->flags |= GCWQ_DISASSOCIATED;
- INIT_LIST_HEAD(&gcwq->idle_list);
for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++)
INIT_HLIST_HEAD(&gcwq->busy_hash[i]);
- init_timer_deferrable(&gcwq->idle_timer);
- gcwq->idle_timer.function = idle_worker_timeout;
- gcwq->idle_timer.data = (unsigned long)gcwq;
+ for_each_worker_pool(pool, gcwq) {
+ pool->gcwq = gcwq;
+ INIT_LIST_HEAD(&pool->worklist);
+ INIT_LIST_HEAD(&pool->idle_list);
- setup_timer(&gcwq->mayday_timer, gcwq_mayday_timeout,
- (unsigned long)gcwq);
+ init_timer_deferrable(&pool->idle_timer);
+ pool->idle_timer.function = idle_worker_timeout;
+ pool->idle_timer.data = (unsigned long)pool;
- ida_init(&gcwq->worker_ida);
+ setup_timer(&pool->mayday_timer, gcwq_mayday_timeout,
+ (unsigned long)pool);
+
+ ida_init(&pool->worker_ida);
+ }
gcwq->trustee_state = TRUSTEE_DONE;
init_waitqueue_head(&gcwq->trustee_wait);
@@ -3801,15 +3867,20 @@
/* create the initial worker */
for_each_online_gcwq_cpu(cpu) {
struct global_cwq *gcwq = get_gcwq(cpu);
- struct worker *worker;
+ struct worker_pool *pool;
if (cpu != WORK_CPU_UNBOUND)
gcwq->flags &= ~GCWQ_DISASSOCIATED;
- worker = create_worker(gcwq, true);
- BUG_ON(!worker);
- spin_lock_irq(&gcwq->lock);
- start_worker(worker);
- spin_unlock_irq(&gcwq->lock);
+
+ for_each_worker_pool(pool, gcwq) {
+ struct worker *worker;
+
+ worker = create_worker(pool, true);
+ BUG_ON(!worker);
+ spin_lock_irq(&gcwq->lock);
+ start_worker(worker);
+ spin_unlock_irq(&gcwq->lock);
+ }
}
system_wq = alloc_workqueue("events", 0, 0);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 798c750..8a93508 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1661,6 +1661,7 @@
long min = mark;
long lowmem_reserve = z->lowmem_reserve[classzone_idx];
int o;
+ long free_cma = 0;
free_pages -= (1 << order) - 1;
if (alloc_flags & ALLOC_HIGH)
@@ -1670,9 +1671,10 @@
#ifdef CONFIG_CMA
/* If allocation can't use CMA areas don't use free CMA pages */
if (!(alloc_flags & ALLOC_CMA))
- free_pages -= zone_page_state(z, NR_FREE_CMA_PAGES);
+ free_cma = zone_page_state(z, NR_FREE_CMA_PAGES);
#endif
- if (free_pages <= min + lowmem_reserve)
+
+ if (free_pages - free_cma <= min + lowmem_reserve)
return false;
for (o = 0; o < order; o++) {
/* At the next order, this order's pages become unavailable */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index ccdfed8..674c1fa 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -505,6 +505,11 @@
ETH_ALEN)))
return -EINVAL;
+ if (WARN_ON(wiphy->max_acl_mac_addrs &&
+ (!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME) ||
+ !rdev->ops->set_mac_acl)))
+ return -EINVAL;
+
if (wiphy->addresses)
memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e1fa62e..6ed6d3e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -210,6 +210,8 @@
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
+ [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
+ [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
[NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
[NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
[NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
@@ -1066,6 +1068,11 @@
sizeof(*dev->wiphy.ht_capa_mod_mask),
dev->wiphy.ht_capa_mod_mask);
+ if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
+ dev->wiphy.max_acl_mac_addrs)
+ NLA_PUT_U32(msg, NL80211_ATTR_MAC_ACL_MAX,
+ dev->wiphy.max_acl_mac_addrs);
+
return genlmsg_end(msg, hdr);
nla_put_failure:
@@ -2105,6 +2112,97 @@
return err;
}
+/* This function returns an error or the number of nested attributes */
+static int validate_acl_mac_addrs(struct nlattr *nl_attr)
+{
+ struct nlattr *attr;
+ int n_entries = 0, tmp;
+
+ nla_for_each_nested(attr, nl_attr, tmp) {
+ if (nla_len(attr) != ETH_ALEN)
+ return -EINVAL;
+
+ n_entries++;
+ }
+
+ return n_entries;
+}
+
+/*
+ * This function parses ACL information and allocates memory for ACL data.
+ * On successful return, the calling function is responsible to free the
+ * ACL buffer returned by this function.
+ */
+static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
+ struct genl_info *info)
+{
+ enum nl80211_acl_policy acl_policy;
+ struct nlattr *attr;
+ struct cfg80211_acl_data *acl;
+ int i = 0, n_entries, tmp;
+
+ if (!wiphy->max_acl_mac_addrs)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ if (!info->attrs[NL80211_ATTR_ACL_POLICY])
+ return ERR_PTR(-EINVAL);
+
+ acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
+ if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
+ acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
+ return ERR_PTR(-EINVAL);
+
+ if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
+ return ERR_PTR(-EINVAL);
+
+ n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
+ if (n_entries < 0)
+ return ERR_PTR(n_entries);
+
+ if (n_entries > wiphy->max_acl_mac_addrs)
+ return ERR_PTR(-ENOTSUPP);
+
+ acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
+ GFP_KERNEL);
+ if (!acl)
+ return ERR_PTR(-ENOMEM);
+
+ nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
+ memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
+ i++;
+ }
+
+ acl->n_acl_entries = n_entries;
+ acl->acl_policy = acl_policy;
+
+ return acl;
+}
+
+static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct cfg80211_acl_data *acl;
+ int err;
+
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ if (!dev->ieee80211_ptr->beacon_interval)
+ return -EINVAL;
+
+ acl = parse_acl_data(&rdev->wiphy, info);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+
+ err = rdev->ops->set_mac_acl(&rdev->wiphy, dev, acl);
+
+ kfree(acl);
+
+ return err;
+}
+
static int nl80211_parse_beacon(struct genl_info *info,
struct cfg80211_beacon_data *bcn)
{
@@ -2251,9 +2349,18 @@
info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
}
+ if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
+ params.acl = parse_acl_data(&rdev->wiphy, info);
+ if (IS_ERR(params.acl))
+ return PTR_ERR(params.acl);
+ }
+
err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms);
if (!err)
wdev->beacon_interval = params.beacon_interval;
+
+ kfree(params.acl);
+
return err;
}
@@ -7063,6 +7170,14 @@
NL80211_FLAG_NEED_RTNL,
},
{
+ .cmd = NL80211_CMD_SET_MAC_ACL,
+ .doit = nl80211_set_mac_acl,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
.cmd = NL80211_CMD_UPDATE_FT_IES,
.doit = nl80211_update_ft_ies,
.policy = nl80211_policy,
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 616f8d5..58ea22d 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -45,6 +45,7 @@
#define NUM_DECIMATORS 4
#define NUM_INTERPOLATORS 3
#define BITS_PER_REG 8
+#define SITAR_RX_PORT_START_NUMBER 10
enum {
AIF1_PB = 0,
@@ -53,11 +54,11 @@
};
struct wcd9xxx_ch sitar_rx_chs[SITAR_RX_MAX] = {
- WCD9XXX_CH(10, 0),
- WCD9XXX_CH(11, 1),
- WCD9XXX_CH(12, 2),
- WCD9XXX_CH(13, 3),
- WCD9XXX_CH(14, 4)
+ WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER, 0),
+ WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 1, 1),
+ WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 2, 2),
+ WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 3, 3),
+ WCD9XXX_CH(SITAR_RX_PORT_START_NUMBER + 4, 4)
};
struct wcd9xxx_ch sitar_tx_chs[SITAR_TX_MAX] = {
@@ -1368,10 +1369,10 @@
vport_check_table[dai_id],
port_id,
sitar_p->dai)) {
- pr_info("%s: TX%u is used by other virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
__func__, port_id + 1);
mutex_unlock(&codec->mutex);
- return -EINVAL;
+ return 0;
}
widget->value |= 1 << port_id;
list_add_tail(&core->tx_chs[port_id].list,
@@ -1381,10 +1382,10 @@
list_del_init(&core->tx_chs[port_id].list);
} else {
if (enable)
- pr_info("%s: TX%u port is used by this virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u port is used by this virtual port\n",
__func__, port_id + 1);
else
- pr_info("%s: TX%u port is not used by this virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u port is not used by this virtual port\n",
__func__, port_id + 1);
/* avoid update power function */
mutex_unlock(&codec->mutex);
@@ -1446,9 +1447,13 @@
list_del_init(&core->rx_chs[port_id].list);
break;
case 1:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ SITAR_RX_PORT_START_NUMBER,
+ &sitar_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&sitar_p->dai[AIF1_PB].wcd9xxx_ch_list);
break;
@@ -1458,14 +1463,10 @@
goto err;
}
-
+rtn:
snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
-
mutex_unlock(&codec->mutex);
return 0;
-pr_err:
- pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
- __func__, port_id + 1);
err:
mutex_unlock(&codec->mutex);
return -EINVAL;
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index b71dd65..669f8e3 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -60,6 +60,7 @@
#define BITS_PER_REG 8
/* This actual number of TX ports supported in slimbus slave */
#define TAPAN_TX_PORT_NUMBER 16
+#define TAPAN_RX_PORT_START_NUMBER 16
/* Nummer of TX ports actually connected from Slimbus slave to codec Digital */
#define TAPAN_SLIM_CODEC_TX_PORTS 5
@@ -155,11 +156,11 @@
static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
static const struct wcd9xxx_ch tapan_rx_chs[TAPAN_RX_MAX] = {
- WCD9XXX_CH(16, 0),
- WCD9XXX_CH(17, 1),
- WCD9XXX_CH(18, 2),
- WCD9XXX_CH(19, 3),
- WCD9XXX_CH(20, 4),
+ WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER, 0),
+ WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 1, 1),
+ WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 2, 2),
+ WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 3, 3),
+ WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 4, 4),
};
static const struct wcd9xxx_ch tapan_tx_chs[TAPAN_TX_MAX] = {
@@ -1410,7 +1411,7 @@
dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
__func__, port_id + 1);
mutex_unlock(&codec->mutex);
- return -EINVAL;
+ return 0;
}
widget->value |= 1 << port_id;
list_add_tail(&core->tx_chs[port_id].list,
@@ -1495,23 +1496,35 @@
list_del_init(&core->rx_chs[port_id].list);
break;
case 1:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAPAN_RX_PORT_START_NUMBER,
+ &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tapan_p->dai[AIF1_PB].wcd9xxx_ch_list);
break;
case 2:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAPAN_RX_PORT_START_NUMBER,
+ &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tapan_p->dai[AIF2_PB].wcd9xxx_ch_list);
break;
case 3:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAPAN_RX_PORT_START_NUMBER,
+ &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tapan_p->dai[AIF3_PB].wcd9xxx_ch_list);
break;
@@ -1520,13 +1533,10 @@
goto err;
}
+rtn:
snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
-
mutex_unlock(&codec->mutex);
return 0;
-pr_err:
- pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
- __func__, port_id + 1);
err:
mutex_unlock(&codec->mutex);
return -EINVAL;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 29703b9..69e4cca 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -129,6 +129,8 @@
#define TABLA_GPIO_IRQ_DEBOUNCE_TIME_US 5000
#define TABLA_MBHC_GND_MIC_SWAP_THRESHOLD 2
+#define TABLA_RX_PORT_START_NUMBER 10
+
#define TABLA_ACQUIRE_LOCK(x) do { \
mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
@@ -302,13 +304,13 @@
static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
static const struct wcd9xxx_ch tabla_rx_chs[TABLA_RX_MAX] = {
- WCD9XXX_CH(10, 0),
- WCD9XXX_CH(11, 1),
- WCD9XXX_CH(12, 2),
- WCD9XXX_CH(13, 3),
- WCD9XXX_CH(14, 4),
- WCD9XXX_CH(15, 5),
- WCD9XXX_CH(16, 6)
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER, 0),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 1, 1),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 2, 2),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 3, 3),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 4, 4),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 5, 5),
+ WCD9XXX_CH(TABLA_RX_PORT_START_NUMBER + 6, 6)
};
static const struct wcd9xxx_ch tabla_tx_chs[TABLA_TX_MAX] = {
@@ -2031,10 +2033,10 @@
vtable,
port_id,
tabla_p->dai)) {
- pr_info("%s: TX%u is used by other virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
__func__, port_id + 1);
mutex_unlock(&codec->mutex);
- return -EINVAL;
+ return 0;
}
widget->value |= 1 << port_id;
list_add_tail(&core->tx_chs[port_id].list,
@@ -2045,10 +2047,10 @@
list_del_init(&core->tx_chs[port_id].list);
} else {
if (enable)
- pr_info("%s: TX%u port is used by this virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u port is used by this virtual port\n",
__func__, port_id + 1);
else
- pr_info("%s: TX%u port is not used by this virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u port is not used by this virtual port\n",
__func__, port_id + 1);
/* avoid update power function */
mutex_unlock(&codec->mutex);
@@ -2116,23 +2118,35 @@
list_del_init(&core->rx_chs[port_id].list);
break;
case 1:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TABLA_RX_PORT_START_NUMBER,
+ &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tabla_p->dai[AIF1_PB].wcd9xxx_ch_list);
break;
case 2:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TABLA_RX_PORT_START_NUMBER,
+ &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tabla_p->dai[AIF2_PB].wcd9xxx_ch_list);
break;
case 3:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TABLA_RX_PORT_START_NUMBER,
+ &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&tabla_p->dai[AIF3_PB].wcd9xxx_ch_list);
break;
@@ -2140,15 +2154,8 @@
pr_err("Unknown AIF %d\n", widget->value);
goto err;
}
-
+rtn:
snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
-
- mutex_unlock(&codec->mutex);
- return 0;
-
-pr_err:
- pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
- __func__, port_id + 1);
mutex_unlock(&codec->mutex);
return 0;
err:
@@ -2703,7 +2710,7 @@
}
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
- msleep(250);
+ msleep(20);
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
pr_debug("%s: leave\n", __func__);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 5d4f9e6..8946dce 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -41,6 +41,8 @@
#define TAIKO_MAD_SLIMBUS_TX_PORT 12
#define TAIKO_MAD_AUDIO_FIRMWARE_PATH "wcd9320/wcd9320_mad_audio.bin"
+#define TAIKO_VALIDATE_RX_SBPORT_RANGE(port) ((port >= 16) && (port <= 22))
+#define TAIKO_CONVERT_RX_SBPORT_ID(port) (port - 16) /* RX1 port ID = 0 */
#define TAIKO_HPH_PA_SETTLE_COMP_ON 3000
#define TAIKO_HPH_PA_SETTLE_COMP_OFF 13000
@@ -294,6 +296,7 @@
#define NUM_INTERPOLATORS 7
#define BITS_PER_REG 8
#define TAIKO_TX_PORT_NUMBER 16
+#define TAIKO_RX_PORT_START_NUMBER 16
#define TAIKO_I2S_MASTER_MODE_MASK 0x08
@@ -409,19 +412,19 @@
static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
static const struct wcd9xxx_ch taiko_rx_chs[TAIKO_RX_MAX] = {
- WCD9XXX_CH(16, 0),
- WCD9XXX_CH(17, 1),
- WCD9XXX_CH(18, 2),
- WCD9XXX_CH(19, 3),
- WCD9XXX_CH(20, 4),
- WCD9XXX_CH(21, 5),
- WCD9XXX_CH(22, 6),
- WCD9XXX_CH(23, 7),
- WCD9XXX_CH(24, 8),
- WCD9XXX_CH(25, 9),
- WCD9XXX_CH(26, 10),
- WCD9XXX_CH(27, 11),
- WCD9XXX_CH(28, 12),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER, 0),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 1, 1),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 2, 2),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 3, 3),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 4, 4),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 5, 5),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 6, 6),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 7, 7),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 8, 8),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 9, 9),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 10, 10),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 11, 11),
+ WCD9XXX_CH(TAIKO_RX_PORT_START_NUMBER + 12, 12),
};
static const struct wcd9xxx_ch taiko_tx_chs[TAIKO_TX_MAX] = {
@@ -2042,11 +2045,10 @@
vtable,
port_id,
taiko_p->dai)) {
- pr_debug("%s: TX%u is used by other\n"
- "virtual port\n",
+ dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
__func__, port_id + 1);
mutex_unlock(&codec->mutex);
- return -EINVAL;
+ return 0;
}
widget->value |= 1 << port_id;
list_add_tail(&core->tx_chs[port_id].list,
@@ -2057,11 +2059,11 @@
list_del_init(&core->tx_chs[port_id].list);
} else {
if (enable)
- pr_debug("%s: TX%u port is used by\n"
+ dev_dbg(codec->dev, "%s: TX%u port is used by\n"
"this virtual port\n",
__func__, port_id + 1);
else
- pr_debug("%s: TX%u port is not used by\n"
+ dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
"this virtual port\n",
__func__, port_id + 1);
/* avoid update power function */
@@ -2130,23 +2132,35 @@
list_del_init(&core->rx_chs[port_id].list);
break;
case 1:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &taiko_p->dai[AIF1_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAIKO_RX_PORT_START_NUMBER,
+ &taiko_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&taiko_p->dai[AIF1_PB].wcd9xxx_ch_list);
break;
case 2:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &taiko_p->dai[AIF2_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAIKO_RX_PORT_START_NUMBER,
+ &taiko_p->dai[AIF2_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&taiko_p->dai[AIF2_PB].wcd9xxx_ch_list);
break;
case 3:
- if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
- &taiko_p->dai[AIF3_PB].wcd9xxx_ch_list))
- goto pr_err;
+ if (wcd9xxx_rx_vport_validation(port_id +
+ TAIKO_RX_PORT_START_NUMBER,
+ &taiko_p->dai[AIF3_PB].wcd9xxx_ch_list)) {
+ dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
+ __func__, port_id + 1);
+ goto rtn;
+ }
list_add_tail(&core->rx_chs[port_id].list,
&taiko_p->dai[AIF3_PB].wcd9xxx_ch_list);
break;
@@ -2154,14 +2168,11 @@
pr_err("Unknown AIF %d\n", widget->value);
goto err;
}
-
+rtn:
snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
mutex_unlock(&codec->mutex);
return 0;
-pr_err:
- pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
- __func__, port_id + 1);
err:
mutex_unlock(&codec->mutex);
return -EINVAL;
@@ -4266,6 +4277,65 @@
return 0;
}
+static void taiko_set_rxsb_port_format(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx_codec_dai_data *cdc_dai;
+ struct wcd9xxx_ch *ch;
+ int port;
+ u8 bit_sel;
+ u16 sb_ctl_reg, field_shift;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bit_sel = 0x2;
+ taiko_p->dai[dai->id].bit_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bit_sel = 0x0;
+ taiko_p->dai[dai->id].bit_width = 24;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid format\n");
+ return;
+ }
+
+ cdc_dai = &taiko_p->dai[dai->id];
+
+ list_for_each_entry(ch, &cdc_dai->wcd9xxx_ch_list, list) {
+ port = wcd9xxx_get_slave_port(ch->ch_num);
+
+ if (IS_ERR_VALUE(port) ||
+ !TAIKO_VALIDATE_RX_SBPORT_RANGE(port)) {
+ dev_warn(codec->dev,
+ "%s: invalid port ID %d returned for RX DAI\n",
+ __func__, port);
+ return;
+ }
+
+ port = TAIKO_CONVERT_RX_SBPORT_ID(port);
+
+ if (port <= 3) {
+ sb_ctl_reg = TAIKO_A_CDC_CONN_RX_SB_B1_CTL;
+ field_shift = port << 1;
+ } else if (port <= 6) {
+ sb_ctl_reg = TAIKO_A_CDC_CONN_RX_SB_B2_CTL;
+ field_shift = (port - 4) << 1;
+ } else { /* should not happen */
+ dev_warn(codec->dev,
+ "%s: bad port ID %d\n", __func__, port);
+ return;
+ }
+
+ dev_dbg(codec->dev, "%s: sb_ctl_reg %x field_shift %x\n",
+ __func__, sb_ctl_reg, field_shift);
+ snd_soc_update_bits(codec, sb_ctl_reg, 0x3 << field_shift,
+ bit_sel << field_shift);
+ }
+}
+
static int taiko_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -4380,29 +4450,7 @@
snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_I2S_CTL,
0x03, (rx_fs_rate >> 0x05));
} else {
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_RX_SB_B1_CTL,
- 0xFF, 0xAA);
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_RX_SB_B2_CTL,
- 0xFF, 0x2A);
- taiko->dai[dai->id].bit_width = 16;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_RX_SB_B1_CTL,
- 0xFF, 0x00);
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_RX_SB_B2_CTL,
- 0xFF, 0x00);
- taiko->dai[dai->id].bit_width = 24;
- break;
- default:
- dev_err(codec->dev, "Invalid format\n");
- break;
- }
+ taiko_set_rxsb_port_format(params, dai);
taiko->dai[dai->id].rate = params_rate(params);
}
break;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index a37b4eb..cc22fd4 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -134,6 +134,14 @@
WCD9XXX_HPHR_DAC_OFF_ACK
};
+enum wcd9xxx_current_v_idx {
+ WCD9XXX_CURRENT_V_INS_H,
+ WCD9XXX_CURRENT_V_INS_HU,
+ WCD9XXX_CURRENT_V_B1_H,
+ WCD9XXX_CURRENT_V_B1_HU,
+ WCD9XXX_CURRENT_V_BR_H,
+};
+
static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
{
return mbhc->polling_active;
@@ -266,6 +274,7 @@
int cfilt_k_val;
bool override;
struct snd_soc_codec *codec;
+ struct mbhc_internal_cal_data *d = &mbhc->mbhc_data;
codec = mbhc->codec;
@@ -278,7 +287,7 @@
if (!override)
wcd9xxx_turn_onoff_override(codec, true);
/* Adjust threshold if Mic Bias voltage changes */
- if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
+ if (d->micb_mv != VDDIO_MICBIAS_MV) {
cfilt_k_val = wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
VDDIO_MICBIAS_MV);
usleep_range(10000, 10000);
@@ -286,11 +295,28 @@
mbhc->mbhc_bias_regs.cfilt_val,
0xFC, (cfilt_k_val << 2));
usleep_range(10000, 10000);
+ /* Threshods for insertion/removal */
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
- mbhc->mbhc_data.adj_v_ins_hu & 0xFF);
+ d->v_ins_hu[MBHC_V_IDX_VDDIO] & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
- (mbhc->mbhc_data.adj_v_ins_hu >> 8) &
+ (d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
0xFF);
+ /* Threshods for button press */
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+ d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+ d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
+ 0xFF);
+ /* Threshods for button release */
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+ d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) & 0xFF);
pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
__func__);
}
@@ -312,18 +338,36 @@
restartpolling)
wcd9xxx_pause_hs_polling(mbhc);
/* Reprogram thresholds */
- if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
+ if (d->micb_mv != VDDIO_MICBIAS_MV) {
cfilt_k_val =
wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
- mbhc->mbhc_data.micb_mv);
+ d->micb_mv);
snd_soc_update_bits(codec,
mbhc->mbhc_bias_regs.cfilt_val,
0xFC, (cfilt_k_val << 2));
usleep_range(10000, 10000);
+ /* Revert threshods for insertion/removal */
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
- mbhc->mbhc_data.v_ins_hu & 0xFF);
+ d->v_ins_hu[MBHC_V_IDX_CFILT] & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
- (mbhc->mbhc_data.v_ins_hu >> 8) & 0xFF);
+ (d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ /* Revert threshods for button press */
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+ d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+ (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+ d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+ (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
+ 0xFF);
+ /* Revert threshods for button release */
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+ d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+ (d->v_brh[MBHC_V_IDX_CFILT] >> 8) & 0xFF);
pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
__func__);
}
@@ -347,17 +391,37 @@
return __wcd9xxx_switch_micbias(mbhc, vddio_switch, true, true);
}
-static s16 wcd9xxx_get_current_v_ins(struct wcd9xxx_mbhc *mbhc, bool hu)
+static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
+ const enum wcd9xxx_current_v_idx idx)
{
- s16 v_ins;
+ enum mbhc_v_index vidx;
+ s16 ret = -EINVAL;
+
if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
mbhc->mbhc_micbias_switched)
- v_ins = hu ? (s16)mbhc->mbhc_data.adj_v_ins_hu :
- (s16)mbhc->mbhc_data.adj_v_ins_h;
+ vidx = MBHC_V_IDX_VDDIO;
else
- v_ins = hu ? (s16)mbhc->mbhc_data.v_ins_hu :
- (s16)mbhc->mbhc_data.v_ins_h;
- return v_ins;
+ vidx = MBHC_V_IDX_CFILT;
+
+ switch (idx) {
+ case WCD9XXX_CURRENT_V_INS_H:
+ ret = (s16)mbhc->mbhc_data.v_ins_h[vidx];
+ break;
+ case WCD9XXX_CURRENT_V_INS_HU:
+ ret = (s16)mbhc->mbhc_data.v_ins_hu[vidx];
+ break;
+ case WCD9XXX_CURRENT_V_B1_H:
+ ret = (s16)mbhc->mbhc_data.v_b1_h[vidx];
+ break;
+ case WCD9XXX_CURRENT_V_B1_HU:
+ ret = (s16)mbhc->mbhc_data.v_b1_hu[vidx];
+ break;
+ case WCD9XXX_CURRENT_V_BR_H:
+ ret = (s16)mbhc->mbhc_data.v_brh[vidx];
+ break;
+ }
+
+ return ret;
}
void *wcd9xxx_mbhc_cal_btn_det_mp(
@@ -389,27 +453,25 @@
static void wcd9xxx_calibrate_hs_polling(struct wcd9xxx_mbhc *mbhc)
{
struct snd_soc_codec *codec = mbhc->codec;
- const s16 v_ins_hu = wcd9xxx_get_current_v_ins(mbhc, true);
+ const s16 v_ins_hu = wcd9xxx_get_current_v(mbhc,
+ WCD9XXX_CURRENT_V_INS_HU);
+ const s16 v_b1_hu = wcd9xxx_get_current_v(mbhc,
+ WCD9XXX_CURRENT_V_B1_HU);
+ const s16 v_b1_h = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
+ const s16 v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
(v_ins_hu >> 8) & 0xFF);
-
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
- mbhc->mbhc_data.v_b1_hu & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
- (mbhc->mbhc_data.v_b1_hu >> 8) & 0xFF);
-
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
- mbhc->mbhc_data.v_b1_h & 0xFF);
+ (v_b1_hu >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
- (mbhc->mbhc_data.v_b1_h >> 8) & 0xFF);
-
- snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
- mbhc->mbhc_data.v_brh & 0xFF);
+ (v_b1_h >> 8) & 0xFF);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
- (mbhc->mbhc_data.v_brh >> 8) & 0xFF);
-
+ (v_brh >> 8) & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
mbhc->mbhc_data.v_brl & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
@@ -813,6 +875,19 @@
WCD9XXX_BCL_LOCK(mbhc->resmgr);
}
+static s16 scale_v_micb_vddio(struct wcd9xxx_mbhc *mbhc, int v, bool tovddio)
+{
+ int r;
+ int vddio_k, mb_k;
+ vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
+ mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
+ if (tovddio)
+ r = v * vddio_k / mb_k;
+ else
+ r = v * mb_k / vddio_k;
+ return r;
+}
+
static s16 wcd9xxx_get_current_v_hs_max(struct wcd9xxx_mbhc *mbhc)
{
s16 v_hs_max;
@@ -821,7 +896,7 @@
plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
mbhc->mbhc_micbias_switched)
- v_hs_max = mbhc->mbhc_data.adj_v_hs_max;
+ v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max, true);
else
v_hs_max = plug_type->v_hs_max;
return v_hs_max;
@@ -1032,19 +1107,6 @@
mbhc->mbhc_state = MBHC_STATE_NONE;
}
-static s16 scale_v_micb_vddio(struct wcd9xxx_mbhc *mbhc, int v, bool tovddio)
-{
- int r;
- int vddio_k, mb_k;
- vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
- mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
- if (tovddio)
- r = v * vddio_k / mb_k;
- else
- r = v * mb_k / vddio_k;
- return r;
-}
-
/* called under codec_resource_lock acquisition */
static void wcd9xxx_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
{
@@ -1680,7 +1742,8 @@
bias_value = wcd9xxx_codec_sta_dce(mbhc, 1, true);
pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
wcd9xxx_codec_sta_dce_v(mbhc, 1, bias_value), min_us);
- if (bias_value < wcd9xxx_get_current_v_ins(mbhc, false)) {
+ if (bias_value <
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H)) {
pr_debug("%s: checking false removal\n", __func__);
msleep(500);
removed = !wcd9xxx_hs_remove_settle(mbhc);
@@ -1942,7 +2005,8 @@
static void wcd9xxx_mbhc_calc_thres(struct wcd9xxx_mbhc *mbhc)
{
struct snd_soc_codec *codec;
- s16 btn_mv = 0, btn_delta_mv;
+ s16 adj_v_hs_max;
+ s16 btn_mv = 0, btn_mv_sta[MBHC_V_IDX_NUM], btn_mv_dce[MBHC_V_IDX_NUM];
struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
struct wcd9xxx_mbhc_plug_type_cfg *plug_type;
u16 *btn_high;
@@ -1953,23 +2017,21 @@
btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
- mbhc->mbhc_data.v_ins_hu =
+ mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_CFILT] =
wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max);
- mbhc->mbhc_data.v_ins_h =
+ mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_CFILT] =
wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max);
mbhc->mbhc_data.v_inval_ins_low = FAKE_INS_LOW;
mbhc->mbhc_data.v_inval_ins_high = FAKE_INS_HIGH;
if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
- mbhc->mbhc_data.adj_v_hs_max =
- scale_v_micb_vddio(mbhc, plug_type->v_hs_max, true);
- mbhc->mbhc_data.adj_v_ins_hu =
- wcd9xxx_codec_v_sta_dce(mbhc, STA,
- mbhc->mbhc_data.adj_v_hs_max);
- mbhc->mbhc_data.adj_v_ins_h =
- wcd9xxx_codec_v_sta_dce(mbhc, DCE,
- mbhc->mbhc_data.adj_v_hs_max);
+ adj_v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max,
+ true);
+ mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_VDDIO] =
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max);
+ mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_VDDIO] =
+ wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max);
mbhc->mbhc_data.v_inval_ins_low =
scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_low,
false);
@@ -1983,17 +2045,27 @@
for (i = 0; i < btn_det->num_btn; i++)
btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
- mbhc->mbhc_data.v_b1_h = wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv);
- btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
- mbhc->mbhc_data.v_b1_hu =
- wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_delta_mv);
+ btn_mv_sta[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_sta;
+ btn_mv_dce[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_cic;
+ btn_mv_sta[MBHC_V_IDX_VDDIO] =
+ scale_v_micb_vddio(mbhc, btn_mv_sta[MBHC_V_IDX_CFILT], true);
+ btn_mv_dce[MBHC_V_IDX_VDDIO] =
+ scale_v_micb_vddio(mbhc, btn_mv_dce[MBHC_V_IDX_CFILT], true);
- btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
+ mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_CFILT] =
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT]);
+ mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT] =
+ wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT]);
+ mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_VDDIO] =
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO]);
+ mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO] =
+ wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO]);
- mbhc->mbhc_data.v_b1_huc =
- wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_delta_mv);
+ mbhc->mbhc_data.v_brh[MBHC_V_IDX_CFILT] =
+ mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT];
+ mbhc->mbhc_data.v_brh[MBHC_V_IDX_VDDIO] =
+ mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO];
- mbhc->mbhc_data.v_brh = mbhc->mbhc_data.v_b1_h;
mbhc->mbhc_data.v_brl = BUTTON_MIN;
mbhc->mbhc_data.v_no_mic =
@@ -2278,12 +2350,17 @@
static int wcd9xxx_is_fake_press(struct wcd9xxx_mbhc *mbhc)
{
int i;
+ s16 mb_v;
int r = 0;
const int dces = NUM_DCE_PLUG_DETECT;
- s16 mb_v, v_ins_hu, v_ins_h;
-
- v_ins_hu = wcd9xxx_get_current_v_ins(mbhc, true);
- v_ins_h = wcd9xxx_get_current_v_ins(mbhc, false);
+ const s16 v_ins_hu =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
+ const s16 v_ins_h =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
+ const s16 v_b1_hu =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
+ const s16 v_b1_h =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
for (i = 0; i < dces; i++) {
usleep_range(10000, 10000);
@@ -2291,8 +2368,7 @@
mb_v = wcd9xxx_codec_sta_dce(mbhc, 0, true);
pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
wcd9xxx_codec_sta_dce_v(mbhc, 0, mb_v));
- if (mb_v < (s16)mbhc->mbhc_data.v_b1_hu ||
- mb_v > v_ins_hu) {
+ if (mb_v < v_b1_hu || mb_v > v_ins_hu) {
r = 1;
break;
}
@@ -2300,8 +2376,7 @@
mb_v = wcd9xxx_codec_sta_dce(mbhc, 1, true);
pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
wcd9xxx_codec_sta_dce_v(mbhc, 1, mb_v));
- if (mb_v < (s16)mbhc->mbhc_data.v_b1_h ||
- mb_v > v_ins_h) {
+ if (mb_v < v_b1_h || mb_v > v_ins_h) {
r = 1;
break;
}
@@ -2995,8 +3070,16 @@
int n = 0;
struct wcd9xxx_mbhc *mbhc = file->private_data;
const struct mbhc_internal_cal_data *p = &mbhc->mbhc_data;
- const s16 v_ins_hu_cur = wcd9xxx_get_current_v_ins(mbhc, true);
- const s16 v_ins_h_cur = wcd9xxx_get_current_v_ins(mbhc, false);
+ const s16 v_ins_hu =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
+ const s16 v_ins_h =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
+ const s16 v_b1_hu =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
+ const s16 v_b1_h =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
+ const s16 v_br_h =
+ wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
@@ -3006,35 +3089,19 @@
p->sta_z, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_z));
n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
p->sta_mb, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_mb));
- n += scnprintf(buffer + n, size - n, "t_dce = %x\n", p->t_dce);
- n += scnprintf(buffer + n, size - n, "t_sta = %x\n", p->t_sta);
- n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n",
- p->micb_mv);
- n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)%s\n",
- p->v_ins_hu,
- wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_ins_hu),
- p->v_ins_hu == v_ins_hu_cur ? "*" : "");
- n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)%s\n",
- p->v_ins_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_ins_h),
- p->v_ins_h == v_ins_h_cur ? "*" : "");
- n += scnprintf(buffer + n, size - n, "adj_v_ins_hu = %x(%dmv)%s\n",
- p->adj_v_ins_hu,
- wcd9xxx_codec_sta_dce_v(mbhc, 0, p->adj_v_ins_hu),
- p->adj_v_ins_hu == v_ins_hu_cur ? "*" : "");
- n += scnprintf(buffer + n, size - n, "adj_v_ins_h = %x(%dmv)%s\n",
- p->adj_v_ins_h,
- wcd9xxx_codec_sta_dce_v(mbhc, 1, p->adj_v_ins_h),
- p->adj_v_ins_h == v_ins_h_cur ? "*" : "");
+ n += scnprintf(buffer + n, size - n, "t_dce = %d\n", p->t_dce);
+ n += scnprintf(buffer + n, size - n, "t_sta = %d\n", p->t_sta);
+ n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n", p->micb_mv);
+ n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)\n",
+ v_ins_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_ins_hu));
+ n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)\n",
+ v_ins_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_ins_h));
n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
- p->v_b1_hu,
- wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_b1_hu));
+ v_b1_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_b1_hu));
n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
- p->v_b1_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_b1_h));
- n += scnprintf(buffer + n, size - n, "v_b1_huc = %x(%dmv)\n",
- p->v_b1_huc,
- wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_b1_huc));
+ v_b1_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_b1_h));
n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
- p->v_brh, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_brh));
+ v_br_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_br_h));
n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_brl));
n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 300e34e..4f8f3cf 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -28,6 +28,12 @@
u8 cfilt_sel;
};
+enum mbhc_v_index {
+ MBHC_V_IDX_CFILT,
+ MBHC_V_IDX_VDDIO,
+ MBHC_V_IDX_NUM,
+};
+
/* Data used by MBHC */
struct mbhc_internal_cal_data {
u16 dce_z;
@@ -38,17 +44,13 @@
u32 t_dce;
u32 t_sta;
u32 micb_mv;
- u16 v_ins_hu;
- u16 v_ins_h;
- u16 v_b1_hu;
- u16 v_b1_h;
- u16 v_b1_huc;
- u16 v_brh;
+ u16 v_ins_hu[MBHC_V_IDX_NUM];
+ u16 v_ins_h[MBHC_V_IDX_NUM];
+ u16 v_b1_hu[MBHC_V_IDX_NUM];
+ u16 v_b1_h[MBHC_V_IDX_NUM];
+ u16 v_brh[MBHC_V_IDX_NUM];
u16 v_brl;
u16 v_no_mic;
- s16 adj_v_hs_max;
- u16 adj_v_ins_hu;
- u16 adj_v_ins_h;
s16 v_inval_ins_low;
s16 v_inval_ins_high;
};
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 2c3c6df..95122b2 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1464,8 +1464,8 @@
ret = voc_set_ext_ec_ref(msm_route_ext_ec_ref, false);
break;
}
- snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
mutex_unlock(&routing_lock);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
return ret;
}
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 26e6ae6..6d0fcea 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -505,6 +505,9 @@
voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
voc_set_tty_mode(voc_get_session_id(VOICE2_SESSION_NAME), tty_mode);
+
+ voc_set_tty_mode(voc_get_session_id(VOLTE_SESSION_NAME), tty_mode);
+
return 0;
}
static int msm_voice_widevoice_put(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 08731f6..86e3d75 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -26,6 +26,7 @@
#include <mach/socinfo.h>
#include <qdsp6v2/msm-pcm-routing-v2.h>
#include "../codecs/wcd9306.h"
+#include <linux/io.h>
#define DRV_NAME "msm8226-asoc-tapan"
@@ -35,15 +36,28 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
-#define GPIO_AUX_PCM_DOUT 43
-#define GPIO_AUX_PCM_DIN 44
-#define GPIO_AUX_PCM_SYNC 45
-#define GPIO_AUX_PCM_CLK 46
-
#define WCD9XXX_MBHC_DEF_BUTTONS 8
#define WCD9XXX_MBHC_DEF_RLOADS 5
#define TAPAN_EXT_CLK_RATE 9600000
+#define NUM_OF_AUXPCM_GPIOS 4
+
+static int msm8226_auxpcm_rate = 8000;
+static atomic_t auxpcm_rsc_ref;
+static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum msm8226_auxpcm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
+#define LPAIF_OFFSET 0xFE000000
+#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
+#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
+#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
+#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
+
+#define I2S_PCM_SEL 1
+#define I2S_PCM_SEL_OFFSET 1
+
void *def_tapan_mbhc_cal(void);
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm);
@@ -62,11 +76,34 @@
.swap_gnd_mic = NULL,
};
+struct msm_auxpcm_gpio {
+ unsigned gpio_no;
+ const char *gpio_name;
+};
+
+struct msm_auxpcm_ctrl {
+ struct msm_auxpcm_gpio *pin_data;
+ u32 cnt;
+};
+
struct msm8226_asoc_mach_data {
int mclk_gpio;
u32 mclk_freq;
+ struct msm_auxpcm_ctrl *auxpcm_ctrl;
};
+#define GPIO_NAME_INDEX 0
+#define DT_PARSE_INDEX 1
+
+static char *msm_auxpcm_gpio_name[][2] = {
+ {"PRIM_AUXPCM_CLK", "qcom,prim-auxpcm-gpio-clk"},
+ {"PRIM_AUXPCM_SYNC", "qcom,prim-auxpcm-gpio-sync"},
+ {"PRIM_AUXPCM_DIN", "qcom,prim-auxpcm-gpio-din"},
+ {"PRIM_AUXPCM_DOUT", "qcom,prim-auxpcm-gpio-dout"},
+};
+
+void *lpaif_pri_muxsel_virt_addr;
+
/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
enum {
SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
@@ -292,6 +329,45 @@
return 0;
}
+static int msm8226_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm8226_auxpcm_rate;
+ return 0;
+}
+
+static int msm8226_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm8226_auxpcm_rate = 8000;
+ break;
+ case 1:
+ msm8226_auxpcm_rate = 16000;
+ break;
+ default:
+ msm8226_auxpcm_rate = 8000;
+ break;
+ }
+ return 0;
+}
+
+static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = msm8226_auxpcm_rate;
+ channels->min = channels->max = 1;
+
+ return 0;
+}
+
static int msm_proxy_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -304,6 +380,118 @@
return 0;
}
+static int msm_aux_pcm_get_gpios(struct msm_auxpcm_ctrl *auxpcm_ctrl)
+{
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ int ret = 0;
+ int i;
+ int j;
+
+ pin_data = auxpcm_ctrl->pin_data;
+ if (!pin_data) {
+ pr_err("%s: Invalid control data for AUXPCM\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ ret = gpio_request(pin_data->gpio_no,
+ pin_data->gpio_name);
+ pr_debug("%s: gpio = %d, gpio name = %s\n"
+ "ret = %d\n", __func__,
+ pin_data->gpio_no,
+ pin_data->gpio_name,
+ ret);
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, pin_data->gpio_no);
+ /* Release all GPIOs on failure */
+ if (i > 0) {
+ for (j = i; j >= 0; j--)
+ gpio_free(pin_data->gpio_no);
+ }
+ goto err;
+ }
+ }
+err:
+ return ret;
+}
+
+static int msm_aux_pcm_free_gpios(struct msm_auxpcm_ctrl *auxpcm_ctrl)
+{
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ int i;
+ int ret = 0;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Invalid control data for AUXPCM\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ gpio_free(pin_data->gpio_no);
+ pr_debug("%s: gpio = %d, gpio_name = %s\n",
+ __func__, pin_data->gpio_no,
+ pin_data->gpio_name);
+ }
+err:
+ return ret;
+}
+
+static int msm_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+
+ auxpcm_ctrl = pdata->auxpcm_ctrl;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL ||
+ lpaif_pri_muxsel_virt_addr == NULL) {
+ pr_err("%s: Invalid control data for AUXPCM\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1) {
+ iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
+ lpaif_pri_muxsel_virt_addr);
+ ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
+ }
+ if (ret < 0) {
+ pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+ return -EINVAL;
+ }
+err:
+ return ret;
+}
+
+static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+
+ auxpcm_ctrl = pdata->auxpcm_ctrl;
+
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm_aux_pcm_free_gpios(auxpcm_ctrl);
+}
+
+static struct snd_soc_ops msm_auxpcm_be_ops = {
+ .startup = msm_auxpcm_startup,
+ .shutdown = msm_auxpcm_shutdown,
+};
+
static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -358,6 +546,8 @@
msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[1],
msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", msm8226_auxpcm_enum[0],
+ msm8226_auxpcm_rate_get, msm8226_auxpcm_rate_put),
};
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -893,6 +1083,35 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ /* AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6.4106",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1
+ /* this dainlink has playback support */
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6.4107",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
+ .ignore_suspend = 1
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
@@ -1053,6 +1272,70 @@
.num_links = ARRAY_SIZE(msm8226_dai),
};
+static int msm8226_dtparse_auxpcm(struct platform_device *pdev,
+ struct msm_auxpcm_ctrl **auxpcm_ctrl,
+ char *msm_auxpcm_gpio_name[][2])
+{
+ int ret = 0;
+ int i = 0;
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ struct msm_auxpcm_ctrl *ctrl;
+ unsigned int gpio_no[NUM_OF_AUXPCM_GPIOS];
+ enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
+ int auxpcm_cnt = 0;
+
+ pin_data = devm_kzalloc(&pdev->dev, (ARRAY_SIZE(gpio_no) *
+ sizeof(struct msm_auxpcm_gpio)),
+ GFP_KERNEL);
+ if (!pin_data) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(gpio_no); i++) {
+ gpio_no[i] = of_get_named_gpio_flags(pdev->dev.of_node,
+ msm_auxpcm_gpio_name[i][DT_PARSE_INDEX],
+ 0, &flags);
+
+ if (gpio_no[i] > 0) {
+ pin_data[i].gpio_name =
+ msm_auxpcm_gpio_name[auxpcm_cnt][GPIO_NAME_INDEX];
+ pin_data[i].gpio_no = gpio_no[i];
+ dev_dbg(&pdev->dev, "%s:GPIO gpio[%s] =\n"
+ "0x%x\n", __func__,
+ pin_data[i].gpio_name,
+ pin_data[i].gpio_no);
+ auxpcm_cnt++;
+ } else {
+ dev_err(&pdev->dev, "%s:Invalid AUXPCM GPIO[%s]= %x\n",
+ __func__,
+ msm_auxpcm_gpio_name[i][GPIO_NAME_INDEX],
+ gpio_no[i]);
+ ret = -ENODEV;
+ goto err;
+ }
+ }
+
+ ctrl = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_auxpcm_ctrl), GFP_KERNEL);
+ if (!ctrl) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ctrl->pin_data = pin_data;
+ ctrl->cnt = auxpcm_cnt;
+ *auxpcm_ctrl = ctrl;
+ return ret;
+
+err:
+ if (pin_data)
+ devm_kfree(&pdev->dev, pin_data);
+ return ret;
+}
+
static int msm8226_prepare_codec_mclk(struct snd_soc_card *card)
{
struct msm8226_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
@@ -1074,6 +1357,7 @@
struct snd_soc_card *card = &snd_soc_card_msm8226;
struct msm8226_asoc_mach_data *pdata;
int ret;
+ const char *auxpcm_pri_gpio_set = NULL;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "No platform supplied from device tree\n");
@@ -1088,6 +1372,15 @@
goto err;
}
+ /* Parse AUXPCM info from DT */
+ ret = msm8226_dtparse_auxpcm(pdev, &pdata->auxpcm_ctrl,
+ msm_auxpcm_gpio_name);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Auxpcm pin data parse failed\n", __func__);
+ goto err;
+ }
+
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, pdata);
@@ -1146,6 +1439,9 @@
}
}
+ mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
+ "qcom,headset-jack-type-NO");
+
ret = msm8226_prepare_codec_mclk(card);
if (ret)
goto err_vdd_spkr;
@@ -1158,6 +1454,30 @@
}
mutex_init(&cdc_mclk_mutex);
+ ret = of_property_read_string(pdev->dev.of_node,
+ "qcom,prim-auxpcm-gpio-set", &auxpcm_pri_gpio_set);
+ if (ret) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,prim-auxpcm-gpio-set",
+ pdev->dev.of_node->full_name);
+ goto err_vdd_spkr;
+ }
+ if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
+ lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+ } else if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-tert")) {
+ lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_TER_MODE_MUXSEL, 4);
+ } else {
+ dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
+ auxpcm_pri_gpio_set);
+ ret = -EINVAL;
+ goto err_vdd_spkr;
+ }
+ if (lpaif_pri_muxsel_virt_addr == NULL) {
+ pr_err("%s Pri muxsel virt addr is null\n", __func__);
+ ret = -EINVAL;
+ goto err_vdd_spkr;
+ }
+
return 0;
err_vdd_spkr:
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 51334f2..ae92ca4 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1260,6 +1260,22 @@
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;
+ channels->min = channels->max = 2;
+
+ return 0;
+}
+
static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1933,6 +1949,52 @@
.codec_name = "snd-soc-dummy",
.be_id = MSM_FRONTEND_DAI_LSM1,
},
+ /* Multiple Tunnel instances */
+ {
+ .name = "MSM8974 Compr2",
+ .stream_name = "COMPR2",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
+ {
+ .name = "MSM8974 Compr3",
+ .stream_name = "COMPR3",
+ .cpu_dai_name = "MultiMedia7",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+ },
+ {
+ .name = "MSM8974 Compr4",
+ .stream_name = "COMPR4",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
@@ -2195,7 +2257,7 @@
.codec_name = "taiko_codec",
.codec_dai_name = "taiko_vifeedback",
.be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
- .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .be_hw_params_fixup = msm_slim_4_tx_be_hw_params_fixup,
.ops = &msm8974_be_ops,
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
@@ -2388,7 +2450,7 @@
{
struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
int ret;
- if (pdata->us_euro_gpio) {
+ if (pdata->us_euro_gpio >= 0) {
dev_dbg(card->dev, "%s : us_euro gpio request %d", __func__,
pdata->us_euro_gpio);
ret = gpio_request(pdata->us_euro_gpio, "TAIKO_CODEC_US_EURO");
@@ -2524,7 +2586,7 @@
pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,us-euro-gpios", 0);
if (pdata->us_euro_gpio < 0) {
- dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ dev_info(&pdev->dev, "property %s not detected in node %s",
"qcom,us-euro-gpios",
pdev->dev.of_node->full_name);
} else {
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index bb13695..60f4669 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -1058,7 +1058,9 @@
}
/* Set encoder properties. */
switch (common.mvs_info.media_type) {
- case VSS_MEDIA_ID_EVRC_MODEM: {
+ case VSS_MEDIA_ID_EVRC_MODEM:
+ case VSS_MEDIA_ID_4GV_NB_MODEM:
+ case VSS_MEDIA_ID_4GV_WB_MODEM: {
struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
pr_debug("Setting EVRC min-max rate\n");
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index a2e0b87..3b6a415 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -1010,10 +1010,11 @@
case AUDIO_GET_SPEAKER_PROT:
mutex_lock(&acdb_data.acdb_mutex);
/*Indicates calibration was succesfull*/
- if (!acdb_data.spk_prot_cfg.mode) {
+ if (acdb_data.spk_prot_cfg.mode == MSM_SPKR_PROT_CALIBRATED) {
prot_status.r0 = acdb_data.spk_prot_cfg.r0;
prot_status.status = 0;
- } else if (acdb_data.spk_prot_cfg.mode == 1) {
+ } else if (acdb_data.spk_prot_cfg.mode ==
+ MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS) {
/*Call AFE to query the status*/
acdb_spk_status.status = -EINVAL;
acdb_spk_status.r0 = -1;
@@ -1021,7 +1022,8 @@
prot_status.r0 = acdb_spk_status.r0;
prot_status.status = acdb_spk_status.status;
if (!acdb_spk_status.status) {
- acdb_data.spk_prot_cfg.mode = 0;
+ acdb_data.spk_prot_cfg.mode =
+ MSM_SPKR_PROT_CALIBRATED;
acdb_data.spk_prot_cfg.r0 = prot_status.r0;
}
} else {
@@ -1206,7 +1208,7 @@
{
memset(&acdb_data, 0, sizeof(acdb_data));
/*Speaker protection disabled*/
- acdb_data.spk_prot_cfg.mode = -1;
+ acdb_data.spk_prot_cfg.mode = MSM_SPKR_PROT_DISABLED;
mutex_init(&acdb_data.acdb_mutex);
atomic_set(&usage_count, 0);
atomic_set(&acdb_data.valid_adm_custom_top, 1);
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 08d7277..bedaba0 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -243,7 +243,7 @@
struct ocmem_buf *buf = NULL;
struct avcs_cmd_rsp_get_low_power_segments_info_t *lp_segptr;
- pr_debug("%s\n", __func__);
+ pr_debug("%s, %p\n", __func__, &audio_ocmem_lcl);
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
if (audio_ocmem_lcl.lp_memseg_ptr == NULL) {
/* Retrieve low power segments */
@@ -329,6 +329,7 @@
if (ret) {
pr_err("%s: ocmem_map failed\n", __func__);
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_FAIL);
+ goto fail_cmd1;
}
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
@@ -372,7 +373,7 @@
pr_err("%s: ocmem_unmap failed, state[%d]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
@@ -384,7 +385,7 @@
pr_err("%s: ocmem_shrink failed, state[%d]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
clear_bit_pos(audio_ocmem_lcl.audio_state,
@@ -405,7 +406,7 @@
pr_err("%s: ocmem_map failed, state[%d]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
(atomic_read(&audio_ocmem_lcl.audio_state) &
@@ -428,7 +429,7 @@
pr_err("%s: ocmem_unmap failed, state[0x%x]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
wait_event_interruptible(
audio_ocmem_lcl.audio_wait,
@@ -446,14 +447,16 @@
pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
clear_bit_pos(audio_ocmem_lcl.audio_state,
OCMEM_STATE_SHRINK);
}
- pr_debug("%s: calling ocmem free\n", __func__);
+ pr_debug("%s: calling ocmem free, state:0x%x\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
if (ret == -EAGAIN) {
pr_debug("%s: received EAGAIN\n", __func__);
@@ -466,7 +469,7 @@
pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
+ goto fail_cmd1;
}
pr_debug("calling free after EAGAIN");
ret = ocmem_free(OCMEM_LP_AUDIO,
@@ -474,19 +477,19 @@
if (ret) {
pr_err("%s: ocmem_free failed\n",
__func__);
- goto fail_cmd;
+ goto fail_cmd2;
}
} else {
pr_debug("%s: shrink callback already processed\n",
__func__);
- goto fail_cmd;
+ goto fail_cmd1;
}
} else if (ret) {
pr_err("%s: ocmem_free failed, state[0x%x], ret:%d\n",
__func__,
atomic_read(&audio_ocmem_lcl.audio_state),
ret);
- goto fail_cmd;
+ goto fail_cmd2;
}
pr_debug("%s: ocmem_free success\n", __func__);
/* Fall through */
@@ -508,6 +511,14 @@
mutex_unlock(&audio_ocmem_lcl.state_process_lock);
}
ret = 0;
+ goto fail_cmd;
+
+fail_cmd1:
+ ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
+ if (ret)
+ pr_err("%s: ocmem_free failed\n", __func__);
+fail_cmd2:
+ mutex_unlock(&audio_ocmem_lcl.state_process_lock);
fail_cmd:
pr_debug("%s: exit\n", __func__);
audio_ocmem_lcl.audio_ocmem_running = false;
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 9dbbf20..620f667 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -29,6 +29,7 @@
#include <sound/pcm_params.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
#include <sound/timer.h>
@@ -496,6 +497,10 @@
if (!atomic_cmpxchg(&compressed_audio.audio_ocmem_req,
0, 1))
audio_ocmem_process_req(AUDIO, true);
+ else
+ atomic_inc(&compressed_audio.audio_ocmem_req);
+ pr_debug("%s: req: %d\n", __func__,
+ atomic_read(&compressed_audio.audio_ocmem_req));
}
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
@@ -618,7 +623,6 @@
populate_codec_list(compr, runtime);
runtime->private_data = compr;
atomic_set(&prtd->eos, 0);
- atomic_set(&compressed_audio.audio_ocmem_req, 0);
compressed_audio.prtd = &compr->prtd;
return 0;
@@ -652,8 +656,14 @@
dir = IN;
atomic_set(&prtd->pending_buffer, 0);
- if (atomic_cmpxchg(&compressed_audio.audio_ocmem_req, 1, 0))
+
+ if (atomic_read(&compressed_audio.audio_ocmem_req) > 1)
+ atomic_dec(&compressed_audio.audio_ocmem_req);
+ else if (atomic_cmpxchg(&compressed_audio.audio_ocmem_req, 1, 0))
audio_ocmem_process_req(AUDIO, false);
+
+ pr_debug("%s: req: %d\n", __func__,
+ atomic_read(&compressed_audio.audio_ocmem_req));
prtd->pcm_irq_pos = 0;
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
compressed_audio.prtd = NULL;
@@ -728,25 +738,14 @@
static int msm_compr_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
- int result = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct compr_audio *compr = runtime->private_data;
- struct msm_audio *prtd = &compr->prtd;
-
- pr_debug("%s\n", __func__);
+ struct msm_audio *prtd = runtime->private_data;
+ struct audio_client *ac = prtd->audio_client;
+ struct audio_port_data *apd = ac->port;
+ struct audio_buffer *ab = &(apd[IN].buf[0]);
prtd->mmap_flag = 1;
- runtime->render_flag = SNDRV_NON_DMA_MODE;
- 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;
+
+ return msm_audio_ion_mmap(ab, vma);
}
static int msm_compr_hw_params(struct snd_pcm_substream *substream,
@@ -1181,6 +1180,8 @@
dev_info(&pdev->dev, "%s: dev name %s\n",
__func__, dev_name(&pdev->dev));
+
+ atomic_set(&compressed_audio.audio_ocmem_req, 0);
return snd_soc_register_platform(&pdev->dev,
&msm_soc_platform);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 27b3f56..7055c57 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -29,6 +29,8 @@
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
+#include <linux/msm_audio_ion.h>
+
#include <sound/compress_params.h>
#include <sound/compress_offload.h>
#include <sound/compress_driver.h>
@@ -421,24 +423,14 @@
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__);
+ struct audio_client *ac = prtd->audio_client;
+ struct audio_port_data *apd = ac->port;
+ struct audio_buffer *ab = &(apd[IN].buf[0]);
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;
+ return msm_audio_ion_mmap(ab, vma);
}
static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 9fbf749..f4ca5b8 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -27,6 +27,7 @@
#include <sound/control.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
+#include <linux/msm_audio_ion.h>
#include <linux/of_device.h>
#include <sound/pcm_params.h>
@@ -628,25 +629,14 @@
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__);
+ struct audio_client *ac = prtd->audio_client;
+ struct audio_port_data *apd = ac->port;
+ struct audio_buffer *ab = &(apd[IN].buf[0]);
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;
+ return msm_audio_ion_mmap(ab, vma);
}
static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 643f280..70db200 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -257,6 +257,12 @@
{INVALID_SESSION, INVALID_SESSION},
/* MULTIMEDIA5 */
{INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA6 */
+ {INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA7 */
+ {INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA8 */
+ {INVALID_SESSION, INVALID_SESSION},
};
static uint8_t is_be_dai_extproc(int be_dai)
@@ -379,6 +385,10 @@
else if (msm_bedais[i].format ==
SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
+
+ if (msm_bedais[i].port_id == VOICE_RECORD_RX ||
+ msm_bedais[i].port_id == VOICE_RECORD_TX)
+ topology = DEFAULT_COPP_TOPOLOGY;
if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
(channels > 0))
adm_multi_ch_copp_open(msm_bedais[i].port_id,
@@ -508,6 +518,10 @@
if (msm_bedais[reg].format == SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
+ if (msm_bedais[reg].port_id == VOICE_RECORD_RX ||
+ msm_bedais[reg].port_id == VOICE_RECORD_TX)
+ topology = DEFAULT_COPP_TOPOLOGY;
+
if ((session_type == SESSION_TYPE_RX) &&
(channels > 0)) {
perf_mode = test_bit(val,
@@ -1345,6 +1359,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
@@ -1363,6 +1386,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
@@ -1381,6 +1413,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
@@ -1399,6 +1440,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
@@ -1417,6 +1467,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
@@ -1450,6 +1509,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_hl_mixer_controls[] = {
@@ -1477,6 +1545,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
@@ -1495,6 +1572,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
/* incall music delivery mixer */
static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
@@ -1531,6 +1617,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
@@ -1549,6 +1644,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
@@ -1567,6 +1671,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -1585,6 +1698,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -1603,6 +1725,15 @@
SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
@@ -2555,6 +2686,9 @@
SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
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),
@@ -2855,6 +2989,9 @@
{"PRI_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"PRI_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"PRI_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
{"SEC_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2862,6 +2999,9 @@
{"SEC_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SEC_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"SEC_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2869,6 +3009,9 @@
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
{"HDMI Mixer", "MultiMedia1", "MM_DL1"},
@@ -2876,6 +3019,9 @@
{"HDMI Mixer", "MultiMedia3", "MM_DL3"},
{"HDMI Mixer", "MultiMedia4", "MM_DL4"},
{"HDMI Mixer", "MultiMedia5", "MM_DL5"},
+ {"HDMI Mixer", "MultiMedia6", "MM_DL6"},
+ {"HDMI Mixer", "MultiMedia7", "MM_DL7"},
+ {"HDMI Mixer", "MultiMedia8", "MM_DL8"},
{"HDMI", NULL, "HDMI Mixer"},
/* incall */
@@ -2896,6 +3042,9 @@
{"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"MI2S_RX", NULL, "MI2S_RX Audio Mixer"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2948,6 +3097,9 @@
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Audio Mixer"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2955,6 +3107,9 @@
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"INTERNAL_FM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"INTERNAL_FM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"INT_FM_RX", NULL, "INTERNAL_FM_RX Audio Mixer"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2962,6 +3117,9 @@
{"AFE_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AFE_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"AFE_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"PCM_RX", NULL, "AFE_PCM_RX Audio Mixer"},
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
@@ -2982,6 +3140,9 @@
{"AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"AUX_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
@@ -2989,6 +3150,9 @@
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX Audio Mixer"},
{"MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
@@ -3348,6 +3512,10 @@
if (bedai->format == SNDRV_PCM_FORMAT_S24_LE)
bits_per_sample = 24;
+ if (bedai->port_id == VOICE_RECORD_RX ||
+ bedai->port_id == VOICE_RECORD_TX)
+ topology = DEFAULT_COPP_TOPOLOGY;
+
if ((playback) && (channels > 0)) {
perf_mode = test_bit(i, &(bedai->perf_mode));
adm_multi_ch_copp_open(bedai->port_id,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 4a58369..9750756 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -67,6 +67,9 @@
MSM_FRONTEND_DAI_MULTIMEDIA3,
MSM_FRONTEND_DAI_MULTIMEDIA4,
MSM_FRONTEND_DAI_MULTIMEDIA5,
+ MSM_FRONTEND_DAI_MULTIMEDIA6,
+ MSM_FRONTEND_DAI_MULTIMEDIA7,
+ MSM_FRONTEND_DAI_MULTIMEDIA8,
MSM_FRONTEND_DAI_CS_VOICE,
MSM_FRONTEND_DAI_VOIP,
MSM_FRONTEND_DAI_AFE_RX,
@@ -79,8 +82,8 @@
MSM_FRONTEND_DAI_MAX,
};
-#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA5 + 1)
-#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA5
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA8 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA8
enum {
MSM_BACKEND_DAI_PRI_I2S_RX = 0,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index b5ce28f..9b3cc8d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -1145,6 +1145,7 @@
static const struct of_device_id msm_voip_dt_match[] = {
{.compatible = "qcom,msm-voip-dsp"},
+ {}
};
MODULE_DEVICE_TABLE(of, msm_voip_dt_match);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 29c06cb..ed4e090 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -1003,8 +1003,8 @@
} else if (channel_mode == 6) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
- open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
- open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_FC;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_LFE;
open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
} else if (channel_mode == 8) {
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index ce5e816..f05f772 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -56,6 +56,9 @@
#define TIMEOUT_MS 1000
#define Q6AFE_MAX_VOLUME 0x3FFF
+#define Q6AFE_MSM_SPKR_PROCESSING 0
+#define Q6AFE_MSM_SPKR_CALIBRATION 1
+
static int pcm_afe_instance[2];
static int proxy_afe_instance[2];
bool afe_close_done[2] = {true, true};
@@ -515,25 +518,31 @@
/*Get spkr protection cfg data*/
get_spk_protection_cfg(&prot_cfg);
- if ((!prot_cfg.mode || prot_cfg.mode == 1) &&
+ if ((prot_cfg.mode != MSM_SPKR_PROT_DISABLED) &&
(this_afe.vi_tx_port == port_id)) {
afe_spk_config.mode_rx_cfg.minor_version = 1;
- afe_spk_config.mode_rx_cfg.mode =
- (uint32_t)prot_cfg.mode;
+ if (prot_cfg.mode == MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS)
+ afe_spk_config.mode_rx_cfg.mode =
+ Q6AFE_MSM_SPKR_CALIBRATION;
+ else
+ afe_spk_config.mode_rx_cfg.mode =
+ Q6AFE_MSM_SPKR_PROCESSING;
if (afe_spk_prot_prepare(port_id,
AFE_PARAM_ID_MODE_VI_PROC_CFG,
&afe_spk_config))
pr_err("%s TX VI_PROC_CFG failed\n", __func__);
- afe_spk_config.vi_proc_cfg.minor_version = 1;
- afe_spk_config.vi_proc_cfg.r0_cali_q24 =
- (uint32_t) prot_cfg.r0;
- afe_spk_config.vi_proc_cfg.t0_cali_q6 =
- (uint32_t) prot_cfg.t0;
- if (afe_spk_prot_prepare(port_id,
- AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG,
- &afe_spk_config))
- pr_err("%s SPKR_CALIB_VI_PROC_CFG failed\n",
- __func__);
+ if (prot_cfg.mode != MSM_SPKR_PROT_NOT_CALIBRATED) {
+ afe_spk_config.vi_proc_cfg.minor_version = 1;
+ afe_spk_config.vi_proc_cfg.r0_cali_q24 =
+ (uint32_t) prot_cfg.r0;
+ afe_spk_config.vi_proc_cfg.t0_cali_q6 =
+ (uint32_t) prot_cfg.t0;
+ if (afe_spk_prot_prepare(port_id,
+ AFE_PARAM_ID_SPKR_CALIB_VI_PROC_CFG,
+ &afe_spk_config))
+ pr_err("%s SPKR_CALIB_VI_PROC_CFG failed\n",
+ __func__);
+ }
}
}
@@ -545,9 +554,13 @@
/*Get spkr protection cfg data*/
get_spk_protection_cfg(&prot_cfg);
- if (!prot_cfg.mode || prot_cfg.mode == 1) {
- afe_spk_config.mode_rx_cfg.mode =
- (uint32_t)prot_cfg.mode;
+ if (prot_cfg.mode != MSM_SPKR_PROT_DISABLED) {
+ if (prot_cfg.mode == MSM_SPKR_PROT_CALIBRATION_IN_PROGRESS)
+ afe_spk_config.mode_rx_cfg.mode =
+ Q6AFE_MSM_SPKR_CALIBRATION;
+ else
+ afe_spk_config.mode_rx_cfg.mode =
+ Q6AFE_MSM_SPKR_PROCESSING;
afe_spk_config.mode_rx_cfg.minor_version = 1;
if (afe_spk_prot_prepare(port_id,
AFE_PARAM_ID_FBSP_MODE_RX_CFG,
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index af8e873..ac26d0c 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -331,6 +331,7 @@
mutex_unlock(&session_lock);
ac->session = 0;
ac->perf_mode = 0;
+ ac->fptr_cache_ops = NULL;
return;
}
@@ -610,6 +611,7 @@
ac->priv = priv;
ac->io_mode = SYNC_IO_MODE;
ac->perf_mode = false;
+ ac->fptr_cache_ops = NULL;
ac->apr = apr_register("ADSP", "ASM", \
(apr_fn)q6asm_callback,\
((ac->session) << 8 | 0x0001),\
@@ -3361,6 +3363,7 @@
u32 lbuf_addr_lsw;
u32 liomode;
u32 io_compressed;
+ int dir = 0;
if (!ac || ac->apr == NULL) {
pr_err("%s: APR handle NULL\n", __func__);
@@ -3378,15 +3381,21 @@
read.seq_id = param->uid;
liomode = (NT_MODE | ASYNC_IO_MODE);
io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
- if (ac->io_mode == liomode)
+ if (ac->io_mode == liomode) {
lbuf_addr_lsw = (read.buf_addr_lsw - 32);
- else if (ac->io_mode == io_compressed)
+ /*legacy wma driver case*/
+ dir = IN;
+ } else if (ac->io_mode == io_compressed) {
lbuf_addr_lsw = (read.buf_addr_lsw - 64);
- else
+ dir = OUT;
+ } else {
lbuf_addr_lsw = read.buf_addr_lsw;
+ dir = OUT;
+ }
- list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
- buf_node = list_entry(ptr, struct asm_buffer_node, list);
+ list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
if (buf_node->buf_addr_lsw == lbuf_addr_lsw) {
read.mem_map_handle = buf_node->mmap_hdl;
break;
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 42cbcd1..5fec0c1 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -29,7 +29,7 @@
struct apr_svc *core_handle_q;
wait_queue_head_t bus_bw_req_wait;
u32 bus_bw_resp_received;
- struct avcs_cmd_rsp_get_low_power_segments_info_t *lp_ocm_payload;
+ struct avcs_cmd_rsp_get_low_power_segments_info_t lp_ocm_payload;
};
static struct q6core_str q6core_lcl;
@@ -74,19 +74,19 @@
pr_info("%s: cmd = AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO num_segments = 0x%x\n",
__func__, payload1[0]);
nseg = payload1[0];
- q6core_lcl.lp_ocm_payload->num_segments = nseg;
- q6core_lcl.lp_ocm_payload->bandwidth = payload1[1];
+ q6core_lcl.lp_ocm_payload.num_segments = nseg;
+ q6core_lcl.lp_ocm_payload.bandwidth = payload1[1];
for (i = 0, j = 2; i < nseg; i++) {
- q6core_lcl.lp_ocm_payload->mem_segment[i].type =
+ q6core_lcl.lp_ocm_payload.mem_segment[i].type =
(payload1[j] & 0xffff);
- q6core_lcl.lp_ocm_payload->mem_segment[i].category =
+ q6core_lcl.lp_ocm_payload.mem_segment[i].category =
((payload1[j++] >> 16) & 0xffff);
- q6core_lcl.lp_ocm_payload->mem_segment[i].size =
+ q6core_lcl.lp_ocm_payload.mem_segment[i].size =
payload1[j++];
- q6core_lcl.lp_ocm_payload->
+ q6core_lcl.lp_ocm_payload.
mem_segment[i].start_address_lsw =
payload1[j++];
- q6core_lcl.lp_ocm_payload->
+ q6core_lcl.lp_ocm_payload.
mem_segment[i].start_address_msw =
payload1[j++];
}
@@ -152,7 +152,6 @@
struct avcs_cmd_rsp_get_low_power_segments_info_t **lp_memseg)
{
struct avcs_cmd_get_low_power_segments_info lp_ocm_cmd;
- u8 *cptr = NULL;
int ret = 0;
pr_debug("%s: ", __func__);
@@ -163,16 +162,6 @@
return -ENODEV;
}
- cptr = kzalloc(
- sizeof(struct avcs_cmd_rsp_get_low_power_segments_info_t),
- GFP_KERNEL);
- if (!cptr) {
- pr_err("%s: Failed to allocate memory for low power segment struct\n",
- __func__);
- return -ENOMEM;
- }
- q6core_lcl.lp_ocm_payload =
- (struct avcs_cmd_rsp_get_low_power_segments_info_t *) cptr;
lp_ocm_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -201,7 +190,7 @@
goto fail_cmd;
}
- *lp_memseg = q6core_lcl.lp_ocm_payload;
+ *lp_memseg = &q6core_lcl.lp_ocm_payload;
return 0;
fail_cmd:
@@ -215,14 +204,6 @@
q6core_lcl.bus_bw_resp_received = 0;
q6core_lcl.core_handle_q = NULL;
- q6core_lcl.lp_ocm_payload = kzalloc(
- sizeof(struct avcs_cmd_rsp_get_low_power_segments_info_t), GFP_KERNEL);
-
- if (!q6core_lcl.lp_ocm_payload) {
- pr_err("%s: Failed to allocate memory for low power segment struct\n",
- __func__);
- return -ENOMEM;
- }
return 0;
}
@@ -230,7 +211,7 @@
static void __exit core_exit(void)
{
- kfree(q6core_lcl.lp_ocm_payload);
+
}
module_exit(core_exit);
MODULE_DESCRIPTION("ADSP core driver");
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index e9d0a7e..5f89e4a 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -1207,7 +1207,9 @@
}
/* Set encoder properties. */
switch (common.mvs_info.media_type) {
- case VSS_MEDIA_ID_EVRC_MODEM: {
+ case VSS_MEDIA_ID_EVRC_MODEM:
+ case VSS_MEDIA_ID_4GV_NB_MODEM:
+ case VSS_MEDIA_ID_4GV_WB_MODEM: {
struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
pr_debug("Setting EVRC min-max rate\n");