Merge "ASoC: mdm9615: Add support for secondary I2S"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 843da69..3684a3f 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -11,7 +11,7 @@
KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules
KERNEL_IMG=$(KERNEL_OUT)/arch/arm/boot/Image
-DTS_NAMES ?= $(shell $(PERL) -e 'while (<>) {$$a = $$1 if /CONFIG_ARCH_((?:MSM|QSD)[a-zA-Z0-9]+)=y/; $$r = $$1 if /CONFIG_MSM_SOC_REV_(?!NONE)(\w+)=y/; $$arch = $$arch.lc("$$a$$r ") if /CONFIG_ARCH_((?:MSM|QSD)[a-zA-Z0-9]+)=y/} print $$arch;' $(KERNEL_CONFIG))
+DTS_NAMES ?= $(shell $(PERL) -e 'while (<>) {$$a = $$1 if /CONFIG_ARCH_((?:MSM|QSD|MPQ)[a-zA-Z0-9]+)=y/; $$r = $$1 if /CONFIG_MSM_SOC_REV_(?!NONE)(\w+)=y/; $$arch = $$arch.lc("$$a$$r ") if /CONFIG_ARCH_((?:MSM|QSD|MPQ)[a-zA-Z0-9]+)=y/} print $$arch;' $(KERNEL_CONFIG))
KERNEL_USE_OF ?= $(shell $(PERL) -e '$$of = "n"; while (<>) { if (/CONFIG_USE_OF=y/) { $$of = "y"; break; } } print $$of;' kernel/arch/arm/configs/$(KERNEL_DEFCONFIG))
ifeq "$(KERNEL_USE_OF)" "y"
diff --git a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
index a39356c..b7dd427 100644
--- a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
+++ b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
@@ -5,74 +5,139 @@
Required properties:
-- qcom,core-max-time-us: Maximum time limit in micorseconds for switching clock rate.
- Limited to this value if switching time takes longer than this limit. Typical value is 100000.
-- qcom,algo-slack-time-us: Time in microseconds after which the QoS guarantee will kick in
- and the clock rate will increased as necessary. Typical value is about 30000.
-- qcom,algo-disable-pc-threshold: If core frequency (kHz) is higher than this value, power collapse is disallowed. Set to 0 for GPU.
-- qcom,algo-ss-window-size: Steady state window size in microseconds.
-- qcom,algo-ss-util-pct: When determining the steady state level, this percentage value is used to provide headroom
- from the utilized cpu to the selected level.
-- qcom,algo-ee-max-util-pct: When determining the level with the lowest energy, any level that exceeds this busy
- percentage, for the measured work in the last window, is disqualified for performance reasons.
-- qcom,algo-ss-iobusy-conv: Used to convert correlation time into assumed IO Busy time, which is removed
- from measured elapsed time when computing cpu utilization.
+- qcom,core-core-type: indicates whether this core is a CPU(0) or a GPU(1)
+- qcom,num-cores: The number of cores this entry represents
+- qcom,sensors: The vector of sensor ids for the cores
+
+- qcom,algo-disable-pc-threshold: sets highest frequency at which DCVS
+ will allow the CPU to power collapse.
+- qcom,algo-em-win-size-min-us: sets minimum Energy Minimization(EM)
+ window size.
+
+- qcom,algo-em-win-size-max-us: sets maximum EM window size.
+- qcom,algo-em-max-util-pct: sets maximum CPU utilization that will
+ not be exceeded by any core when
+ MP-decision decides the number of
+ online cores.
+- qcom,algo-group-id: specifies a group index of a core.
+- qcom,algo-max-freq-chg-time-us: shows time taken for the most recent
+ frequency change.
+- qcom,algo-slack-mode-dynamic: specifies if dynamic slack mode is
+ enabled or not.
+- qcom,algo-slack-weight-thresh-pct: sets occurrence percentage of CPU
+ activity that will make slack timer
+ triggered.
+- qcom,algo-slack-time-min-us: specifies the slack time that slack
+ timer would be set if the current clock
+ frequency is zero.
+- qcom,algo-slack-time-max-us: sets maximum slack timer value to be
+ used by slack timer.
+- qcom,algo-ss-win-size-min-us: sets minimum steady state window size.
+- qcom,algo-ss-win-size-max-us: sets maximum steady state window size.
+- qcom,algo-ss-util-pct: sets target CPU utilization during
+ steady-state.
+- qcom,algo-ss-iobusy-conv: specifies how wait time (i/o busy time)
+ is incorporated into the steady-state
+ algorithm.
+
+- qcom,energy-active-coeff-a: sets active power equation coefficient a.
+- qcom,energy-active-coeff-b: sets active power equation coefficient b.
+- qcom,energy-active-coeff-c: sets active power equation coefficient c.
+- qcom,energy-leakage-coeff-a: sets leakage power equation coefficient a.
+- qcom,energy-leakage-coeff-b: sets leakage power equation coefficient b.
+- qcom,energy-leakage-coeff-c: sets leakage power equation coefficient c.
+- qcom,energy-leakage-coeff-d: sets leakage power equation coefficient d.
+
+- qcom,power-current-temp: the current temperature in degCelcius.
+- qcom,power-num-freq: the number of freq this core supports.
A number of frequency levels are represented as sub-nodes:
required properties:
- reg: The index of the frequency entry
- qcom,freq The frequency of the DVS entry (in kHZ)
-- qcom,idle-energy: The idle energy cost of the entry (in micro watts)
-- qcom,active-energy: The active energy cost of the entry (in micro watts)
+- qcom,is_trans_level This frequency is transient step for DCVS
+- qcom,active-energy-offset: The active energy cost of the entry
+- qcom,leakage-energy-offset: The leakage energy cost of the entry
Sample:
qcom,kgsl-3d0@fdb00000 {
...
- qcom,dcvs-core-info {
- #address-cells = <1>;
- #size-cells = <0>;
+ qcom,dcvs-core-info {
+ #address-cells = <1>;
+ #size-cells = <0>;
- compatible = "qcom,dcvs-core-info";
+ compatible = "qcom,dcvs-core-info";
- qcom,core-max-time-us = <100000>;
- qcom,algo-slack-time-us = <39000>;
- qcom,algo-disable-pc-threshold = <86000>;
- qcom,algo-ss-window-size = <1000000>;
- qcom,algo-ss-util-pct = <95>;
- qcom,algo-em-max-util-pct = <97>;
- qcom,algo-ss-iobusy-conv = <100>;
+ qcom,num-cores = <1>;
+ qcom,sensors = <0>;
- qcom,dcvs-freq@0 {
- reg = <0>;
- qcom,freq = <0>;
- qcom,idle-energy = <0>;
- qcom,active-energy = <333932>;
+ qcom,core-core-type = <1>;
+
+ qcom,algo-disable-pc-threshold = <0>;
+ qcom,algo-em-win-size-min-us = <100000>;
+ qcom,algo-em-win-size-max-us = <300000>;
+ qcom,algo-em-max-util-pct = <97>;
+ qcom,algo-group-id = <95>;
+ qcom,algo-max-freq-chg-time-us = <100000>;
+ qcom,algo-slack-mode-dynamic = <100000>;
+ qcom,algo-slack-weight-thresh-pct = <0>;
+ qcom,algo-slack-time-min-us = <39000>;
+ qcom,algo-slack-time-max-us = <39000>;
+ qcom,algo-ss-win-size-min-us = <1000000>;
+ qcom,algo-ss-win-size-max-us = <1000000>;
+ qcom,algo-ss-util-pct = <95>;
+ qcom,algo-ss-iobusy-conv = <100>;
+
+ qcom,energy-active-coeff-a = <2492>;
+ qcom,energy-active-coeff-b = <0>;
+ qcom,energy-active-coeff-c = <0>;
+ qcom,energy-leakage-coeff-a = <11>;
+ qcom,energy-leakage-coeff-b = <157150>;
+ qcom,energy-leakage-coeff-c = <0>;
+ qcom,energy-leakage-coeff-d = <0>;
+
+ qcom,power-current-temp = <25>;
+ qcom,power-num-freq = <4>;
+
+ qcom,dcvs-freq@0 {
+ reg = <0>;
+ qcom,freq = <0>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <100>;
+ qcom,leakage-energy-offset = <0>;
+ };
+
+ qcom,dcvs-freq@1 {
+ reg = <1>;
+ qcom,freq = <0>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <100>;
+ qcom,leakage-energy-offset = <0>;
+ };
+
+ qcom,dcvs-freq@2 {
+ reg = <2>;
+ qcom,freq = <0>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <100>;
+ qcom,leakage-energy-offset = <0>;
+ };
+
+ qcom,dcvs-freq@3 {
+ reg = <3>;
+ qcom,freq = <0>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <844545>;
+ qcom,leakage-energy-offset = <0>;
+ };
};
-
- qcom,dcvs-freq@1 {
- reg = <1>;
- qcom,freq = <0>;
- qcom,idle-energy = <0>;
- qcom,active-energy = <497532>;
- };
-
- qcom,dcvs-freq@2 {
- reg = <2>;
- qcom,freq = <0>;
- qcom,idle-energy = <0>;
- qcom,active-energy = <707610>;
- };
-
- qcom,dcvs-freq@3 {
- reg = <3>;
- qcom,freq = <0>;
- qcom,idle-energy = <0>;
- qcom,active-energy = <844545>;
- };
- };
...
};
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
index b16d40f..7f2a21b 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-resources.txt
@@ -8,13 +8,25 @@
that need to be monitored for usage requirement to check if a given low power
state can be entered.Each resource is identified by a combination of the name,
id,type and key which is also used by the RPM to identify a shared resource.
+The name and resource-type are required nodes; the type, id and key are
+optional nodes which are needed if the resource type is RPM shared resource
+(MSM_LPM_RPM_RS_TYPE).
-The required nodes for lpm-resources are:
+The nodes for lpm-resources are:
+
+Required Nodes:
- compatible: "qcom,lpm-resources"
- reg: The numeric level id
- qcom,name: The name of the low power resource represented
as a string.
+- qcom,resource-type: The type of the LPM resource.
+ MSM_LPM_RPM_RS_TYPE = 0
+ MSM_LPM_LOCAL_RS_TYPE = 1
+
+
+Optional Nodes:
+
- qcom,type: The type of resource used like smps or pxo
represented as a hex value.
- qcom,id: The id representing a device within a resource type.
@@ -25,6 +37,7 @@
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
+ qcom,resource-type = <0>;
qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x02>;
qcom,key = <0x6e726f63>; /* "corn" */
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt b/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt
new file mode 100644
index 0000000..e5fd1b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/qcom-wdog-debug.txt
@@ -0,0 +1,16 @@
+* Qualcomm's Watchdog Debug Image Controller
+
+The Qualcomm's Watchdog debug image controller is used for enabling/disabling of
+watchdog debug image feature.
+
+Required properties:
+- compatible : should be "qcom,msm-wdog-debug"
+- reg : base page aligned physical base address of the controller and length of
+ memory mapped region.
+
+Example:
+
+ qcom,msm-wdog-debug@fc401000 {
+ compatible = "qcom,msm-wdogi-debug";
+ reg = <0xfc401000 0x1000>;
+ };
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index c584073..f860618 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -31,6 +31,7 @@
component
- coresight-child-ports : list of input port numbers of the children
- coresight-default-sink : represents the default compile time CoreSight sink
+- qcom,pc-save : program counter save implemented
Examples:
@@ -103,4 +104,5 @@
coresight-outports = <0>;
coresight-child-list = <&funnel_kpss>;
coresight-child-ports = <0>;
+ qcom,pc-save;
};
diff --git a/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
index 5c2c021..4e810e1 100644
--- a/Documentation/devicetree/bindings/gpio/gpio_keys.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
@@ -4,6 +4,7 @@
- compatible = "gpio-keys";
Optional properties:
+ - input-name: input name of the device
- autorepeat: Boolean, Enable auto repeat feature of Linux input
subsystem.
@@ -28,6 +29,7 @@
#address-cells = <1>;
#size-cells = <0>;
autorepeat;
+ input-name = "gpio-keys";
button@21 {
label = "GPIO Key UP";
linux,code = <103>;
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 16925fb..38b2721 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -62,6 +62,7 @@
- qcom,chipid: If it exists this property is used to replace
the chip identification read from the GPU hardware.
This is used to override faulty hardware readings.
+- qcom,strtstp-sleepwake: Boolean. Enables use of GPU SLUMBER instead of SLEEP for power savings
Example of A330 GPU in MSM8974:
diff --git a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
index a6c83d0..88fca69 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/atmel-mxt-ts.txt
@@ -27,6 +27,8 @@
- vcc_i2c-supply : Power source required to pull up i2c bus
- atmel,dig-reg-support : specify to indicate digital regulator is
needed
+ - atmel,need-calibration : specify to indicate whether calibration is
+ needed during wakeup.
Example:
i2c@f9966000 {
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu.txt b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
index f5a2590..dcf023d 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu.txt
@@ -13,12 +13,24 @@
- qcom,iommu-ctx-sids : List of stream identifiers associated with this
translation context.
- label : Name of the context bank
- - qcom,iommu-smt-size : Number of SMR entries in the SMT of this HW block
- vdd-supply : vdd-supply: phandle to GDSC regulator controlling this IOMMU.
Optional properties:
- qcom,needs-alt-core-clk : boolean to enable the secondary core clock for
access to the IOMMU configuration registers
+- qcom,iommu-bfb-regs : An array of unsigned 32-bit integers corresponding to
+ BFB register addresses that need to be configured for performance tuning
+ purposes. If this property is present, the qcom,iommu-bfb-data must also be
+ present. Register addresses are specified as an offset from the base of the
+ IOMMU hardware block. This property may be omitted if no BFB register
+ configuration needs to be done for a particular IOMMU hardware instance. The
+ registers specified by this property shall fall within the IOMMU
+ implementation-defined register region.
+- qcom,iommu-bfb-data : An array of unsigned 32-bit integers representing the
+ values to be programmed into the corresponding registers given by the
+ qcom,iommu-bfb-regs property. If this property is present, the
+ qcom,iommu-bfb-regs property shall also be present, and the lengths of both
+ properties shall be the same.
Example:
@@ -26,6 +38,8 @@
compatible = "qcom,msm-smmu-v2";
reg = <0xfda64000 0x10000>;
vdd-supply = <&gdsc_iommu>;
+ qcom,iommu-bfb-regs = <0x204c 0x2050>;
+ qcom,iommu-bfb-data = <0xffff 0xffce>;
qcom,iommu-ctx@fda6c000 {
reg = <0xfda6c000 0x1000>;
diff --git a/Documentation/devicetree/bindings/pil/pil-mba.txt b/Documentation/devicetree/bindings/pil/pil-mba.txt
index 7aafd219..9692059 100644
--- a/Documentation/devicetree/bindings/pil/pil-mba.txt
+++ b/Documentation/devicetree/bindings/pil/pil-mba.txt
@@ -10,6 +10,8 @@
first corresponds to the Relay Message Buffer (RMB)
register base. The second specifies the address at which
the primary modem image metadata should be stored.
+- reg-names: Names for the above base addresses. "rmb_base" and
+ "metadata_base" are expected.
- qcom,firmware-name: Base name of the firmware image. Ex. "modem"
Optional properties:
@@ -21,6 +23,7 @@
compatible = "qcom,pil-mba";
reg = <0xfc820000 0x0020>,
<0x0d1f0000 0x4000>;
+ reg-names = "rmb_base", "metadata_base";
qcom,firmware-name = "modem";
qcom,depends-on = "mba";
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index 6193b68..e123bdb 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -7,9 +7,9 @@
Required properties:
- compatible: "pil-pronto"
-- reg: offset and length of the register set for the device. The first pair
- corresponds to PRONTO_PMU, the second pair corresponds to CLK_CTL_WCNSS
- the third pair corresponds to WCNSS_HALTREQ.
+- reg: offset and length of the register set for the device.
+- reg-names: names of the bases for the above registers. "pmu_base", "clk_base",
+ and "halt_base" are expected.
- vdd_pronto_pll-supply: regulator to supply pronto pll.
- qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
@@ -19,6 +19,7 @@
reg = <0xfb21b000 0x3000>,
<0xfc401700 0x4>,
<0xfd485300 0xc>;
+ reg-names = "pmu_base", "clk_base", "halt_base";
vdd_pronto_pll-supply = <&pm8941_l12>;
qcom,firmware-name = "wcnss";
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index 308f992..d39c98c 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -7,9 +7,10 @@
Required properties:
- compatible: Must be "qcom,pil-q6v5-lpass"
-- reg: Two pairs of physical base addresses and region sizes
- of memory mapped registers. The first region corresponds
- to QDSP6SS_PUB, and the second to LPASS_HALTREQ.
+- reg: Pairs of physical base addresses and region sizes of
+ memory mapped registers.
+- reg-names: Names of the bases for the above registers. "qdsp6_base"
+ and "halt_base" are expected.
- qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
Example:
@@ -17,6 +18,7 @@
compatible = "qcom,pil-q6v5-lpass";
reg = <0xfe200000 0x00100>,
<0xfd485100 0x00010>;
+ reg-names = "qdsp6_base", "halt_base";
qcom,firmware-name = "lpass";
};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 32c9c35..41ffd8a 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -7,12 +7,11 @@
Required properties:
- compatible: Must be "qcom,pil-q6v5-mss"
-- reg: Five pairs of physical base addresses and region sizes of
- memory mapped registers. The first region corresponds to
- QDSP6SS_PUB, the second to the bus port halt register
- base, the third to the MSS_RELAY_MSG_BUFFER base, the
- fourth to the MSS_RESTART register, and the fifth to the
- MSS_CLAMP_IO register.
+- reg: Pairs of physical base addresses and region sizes of
+ memory mapped registers.
+- reg-names: Names of the bases for the above registers. "qdsp6_base",
+ "halt_base", "rmb_base", "restart_reg" and "clamp_reg"
+ are expected.
- vdd_mss-supply: Reference to the regulator that supplies the processor.
- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
- qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
@@ -27,6 +26,8 @@
<0xfc820000 0x020>,
<0xfc401680 0x004>,
<0xfc980008 0x004>;
+ reg-names = "qdsp6_base", "halt_base", "rmb_base",
+ "restart_reg", "clamp_reg";
vdd_mss-supply = <&pm8841_s3>;
qcom,firmware-name = "mba";
diff --git a/Documentation/devicetree/bindings/pil/pil-venus.txt b/Documentation/devicetree/bindings/pil/pil-venus.txt
index 93cba32..4b87f17 100644
--- a/Documentation/devicetree/bindings/pil/pil-venus.txt
+++ b/Documentation/devicetree/bindings/pil/pil-venus.txt
@@ -7,8 +7,9 @@
Required properties:
- compatible: "pil-venus"
-- reg: offset and length of the register set for the device. The first pair
- corresponds to VENUS_WRAPPER, the second pair corresponds to VENUS_VBIF.
+- reg: offset and length of the register set for the device.
+- reg-names: names of the bases for the above registers. "wrapper_base" and
+ "vbif_base" are expected.
- vdd-supply: regulator to supply venus.
- qcom,firmware-name: Base name of the firmware image. Ex. "venus"
- qcom,firmware-min-paddr: The lowest addr boundary for firmware image in DDR
@@ -19,6 +20,7 @@
compatible = "qcom,pil-venus";
reg = <0xfdce0000 0x4000>,
<0xfdc80208 0x8>;
+ reg-names = "wrapper_base", "vbif_base";
vdd-supply = <&gdsc_venus>;
qcom,firmware-name = "venus";
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 21d376a..adb93b8 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -11,18 +11,24 @@
- compatible: Must be "qcom,qpnp-power-on"
- reg: Specifies the SPMI address and size for this PON (power-on) peripheral
- interrupts: Specifies the interrupt associated with PON.
+- interrupt-names: Specify the interrupt names associated with interrupts. Must be
+ one of "kpdpwr", "kpdpwr-bark", "resin", "resin-bark", "cblpwr".
+ Bark interrupts are associated with system reset configuration
+ to allow default reset configuration to be activated. If system
+ reset configuration is not supported then bark interrupts are
+ nops.
Optional properties:
-- qcom,pon-dbc-delay The debouce delay for the power-key interrupt
- specifed in us. The value ranges from 2 seconds
+- qcom,pon-dbc-delay The debounce delay for the power-key interrupt
+ specified in us. The value ranges from 2 seconds
to 1/64 of a second. Possible values are -
- 2, 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64
- Intermediate value is rounded down to the
nearest valid value.
- qcom,pon_1 ...pon_n These represent the child nodes which describe
the properties (reset, key) for each of the pon
- reset source. All the child nodes are optional,
- if none of them are specified the driver fails
+ reset source. All the child nodes are optional.
+ If none of them is specified, the driver fails
to register.
- qcom,system-reset Specifies that this PON peripheral can be used
to reset the system. This property can only be
@@ -32,32 +38,32 @@
All the below properties are in the sub-node section (properties of the child
node).
+Sub-node required properties:
+- qcom,pon-type The type of PON/RESET source. The driver
+ currently supports KPDPWR(0), RESIN(1) and
+ CBLPWR(2) pon/reset sources.
+
+Sub-node optional properties:
- qcom,pull-up The initial state of the reset pin under
consideration.
0 = No pull-up
1 = pull-up enabled
- This property is optional and is set to '0'
- if not specified.
-- qcom,pon-type The type of PON/RESET source. The driver
- currently supports KPDPWR(0) and RESIN(1)
- pon/reset sources. This property must be
- specified.
+ This property is set to '0' if not specified.
- qcom,support-reset Indicates if this PON source supports
reset functionality.
0 = Not supported
1 = Supported
- This property is optional and is set to '0'
- if not specified.
-- qcom,s1-timer The debouce timer for the BARK interrupt for
+ This property is set to '0' if not specified.
+- qcom,s1-timer The debounce timer for the BARK interrupt for
that reset source. Value is specified in ms.
Supported values are -
- 0, 32, 56, 80, 128, 184, 272, 408, 608, 904
1352, 2048, 3072, 4480, 6720, 10256
This property must be specified only if
'support-reset' is set to 1.
-- qcom,s2-timer The debouce timer for the S2 reset specified
+- qcom,s2-timer The debounce timer for the S2 reset specified
in ms. On the expiry of this timer, the PMIC
- executes the reset sequence. Supoprted values -
+ executes the reset sequence. Supported values -
- 0, 10, 50, 100, 250, 500, 1000, 2000
This property is required only if
'support-reset' is set to 1.
@@ -68,7 +74,7 @@
'support-reset' is set to 1.
- linux,code The input key-code associated with the reset source.
The reset source in its default configuration can be
- used to support standard keys. This property is optional.
+ used to support standard keys.
Example:
qcom,power-on@800 {
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
new file mode 100644
index 0000000..244e622
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -0,0 +1,209 @@
+Qualcomm QPNP Charger
+
+The charger supports the switch mode battery charger and boost (SMBB)
+peripherals on Qualcomm PMIC chips.
+
+There are seven different peripherals adding the following functionality.
+Each of these peripherals are implemented as subnodes in the example at the
+end of this file.
+
+- qcom,chg-chgr: Supports charging control and status
+ reporting.
+- qcom,chg-bat-if: Battery status reporting such as presence,
+ temperature reporting and voltage collapse
+ protection.
+- qcom,chg-buck: Charger buck configuration and status
+ reporting with regards to several regulation
+ loops such as vdd, ibat etc.
+- qcom,usb-chgpth: USB charge path detection and input current
+ limiting configuration.
+- qcom,dc-chgpth: DC charge path detection and input current
+ limiting configuration.
+- qcom,chg-misc: Miscellaneous features such as buck frequency
+ settings, comparator override features etc.
+
+Parent node required properties:
+- qcom,chg-vddmax-mv: Target voltage of battery in mV
+- qcom,chg-vddsafe-mv: Maximum Vdd voltage in mV
+- qcom,chg-vinmin-mv: Minimum input voltage in mV
+- qcom,chg-ibatmax-ma: Maximum battery charge current in mA
+- qcom,chg-ibatterm-ma: Current at which charging is terminated in mA.
+
+Sub node required structure:
+- A qcom,chg node must be a child of an SPMI node that has specified
+ the spmi-dev-container property. Each subnode reflects
+ a hardware peripheral which adds a unique set of features
+ to the collective charging device. For example USB detection
+ and the battery interface are each seperate peripherals and
+ each should be their own subnode.
+
+Sub node required properties:
+- compatible: Must be "qcom,charger".
+- reg: Specifies the SPMI address and size for this peripheral.
+- interrupts: Specifies the interrupt associated with the peripheral.
+- interrupt-names: Specifies the interrupt names for the peripheral. Every
+ available interrupt needs to have an associated name
+ with it to indentify its purpose.
+
+ The following lists each subnode and their corresponding
+ required interrupt names:
+
+ qcom,usb-chgpth:
+ - usbin-valid
+ qcom,chg-chgr:
+ - chg-done
+ - chg-failed
+
+ The following interrupts are available:
+
+ qcom,chg-chgr:
+ - chg-done: Triggers on charge completion.
+ - chg-failed: Notifies of charge failures.
+ - fast-chg-on: Notifies of fast charging state.
+ - trkl-chg-on: Indicates trickle charging.
+ - state-change: Notifies of a state change in
+ the charger state machine.
+ - chgwdog: Charger watchdog interrupt.
+ - vbat-det-hi: Triggers on vbat-det-hi voltage
+ setting,can be used as
+ battery alarm.
+ - vbat-det-hi: Triggers on vbat-det-low voltage
+ setting, can be used as
+ battery alarm.
+
+ qcom,chg-buck:
+ - vdd-loop: VDD loop change interrupt.
+ - ibat-loop: Ibat loop change interrupt.
+ - ichg-loop: Charge current loop change.
+ - vchg-loop: Charge voltage loop change.
+ - overtemp: Overtemperature interrupt.
+ - vref-ov: Reference overvoltage interrupt.
+ - vbat-ov: Battery overvoltage interrupt.
+
+ qcom,chg-bat-if:
+ - psi: PMIC serial interface interrupt.
+ - vcp-on: Voltage collapse protection
+ status interrupt.
+ - bat-fet-on: BATFET status interrupt.
+ - bat-temp-ok: Battery temperature status
+ interrupt.
+ - batt-pres: Battery presence status
+ interrupt.
+
+ qcom,usb-chgpth:
+ - usbin-valid: Indicates valid USB connection.
+ - coarse-det-usb: Coarse detect interrupt triggers
+ at low voltage on USB_IN.
+ - chg-gone: Triggers on VCHG line.
+
+ qcom,dc-chgpth:
+ - dcin-valid: Indicates a valid DC charger
+ connection.
+ - coarse-det-dc: Coarse detect interrupt triggers
+ at low voltage on DC_IN.
+
+ qcom,boost:
+ - limit-error: Limiting error on SMBB boost.
+ - boost-pwr-ok: Status of boost power.
+
+Example:
+ pm8941-chg {
+ spmi-dev-container;
+ compatible = "qcom,charger";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ qcom,chg-vddmax-mv = <4200>;
+ qcom,chg-vddsafe-mv = <4200>;
+ qcom,chg-vinmin-mv = <4200>;
+ qcom,chg-ibatmax-mv = <1500>;
+ qcom,chg-ibatterm-mv = <200>;
+
+ qcom,chg-chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts = <0x0 0x10 0x0>,
+ <0x0 0x10 0x1>,
+ <0x0 0x10 0x2>,
+ <0x0 0x10 0x3>,
+ <0x0 0x10 0x4>,
+ <0x0 0x10 0x5>,
+ <0x0 0x10 0x6>,
+ <0x0 0x10 0x7>;
+
+ interrupt-names = "chg-done",
+ "chg-failed",
+ "fast-chg-on",
+ "trkl-chg-on",
+ "state-change",
+ "chgwdog",
+ "vbat-det-hi",
+ "vbat-det-lo";
+ };
+
+ qcom,chg-buck@1100 {
+ reg = <0x1100 0x100>;
+ interrupts = <0x0 0x11 0x0>,
+ <0x0 0x11 0x1>,
+ <0x0 0x11 0x2>,
+ <0x0 0x11 0x3>,
+ <0x0 0x11 0x4>,
+ <0x0 0x11 0x5>,
+ <0x0 0x11 0x6>;
+
+ interrupt-names = "vdd-loop",
+ "ibat-loop",
+ "ichg-loop",
+ "vchg-loop",
+ "overtemp",
+ "vref-ov",
+ "vbat-ov";
+ };
+
+ qcom,chg-bat-if@1200 {
+ reg = <0x1200 0x100>;
+ interrupts = <0x0 0x12 0x0>,
+ <0x0 0x12 0x1>,
+ <0x0 0x12 0x2>,
+ <0x0 0x12 0x3>,
+ <0x0 0x12 0x4>;
+
+ interrupt-names = "psi",
+ "vcp-on",
+ "bat-fet-on",
+ "bat-temp-ok",
+ "batt-pres";
+ };
+
+ qcom,chg-usb-chgpth@1300 {
+ reg = <0x1300 0x100>;
+ interrupts = <0 0x13 0x0>,
+ <0 0x13 0x1>,
+ <0x0 0x13 0x2>;
+
+ interrupt-names = "usbin-valid",
+ "coarse-det-usb",
+ "chg-gone";
+ };
+
+ qcom,chg-dc-chgpth@1400 {
+ reg = <0x1400 0x100>;
+ interrupts = <0x0 0x14 0x0>,
+ <0x0 0x14 0x1>;
+
+ interrupt-names = "dcin-valid",
+ "coarse-det-dc";
+ };
+
+ qcom,chg-boost@1500 {
+ reg = <0x1500 0x100>;
+ interrupts = <0x0 0x15 0x0>,
+ <0x0 0x15 0x1>;
+
+ interrupt-names = "limit-error",
+ "boost-pwr-ok";
+ };
+
+ qcom,chg-misc@1600 {
+ reg = <0x1600 0x100>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/qseecom/qseecom.txt b/Documentation/devicetree/bindings/qseecom/qseecom.txt
index 8b17ba9..5e7c42a 100644
--- a/Documentation/devicetree/bindings/qseecom/qseecom.txt
+++ b/Documentation/devicetree/bindings/qseecom/qseecom.txt
@@ -2,9 +2,21 @@
Required properties:
- compatible : Should be "qcom,qseecom"
+- qcom, msm_bus,name: Should be "qseecom-noc"
+- qcom, msm_bus,num_cases: Depends on the use cases for bus scaling
+- qcom, msm_bus,num_paths: The paths for source and destination ports
+- qcom, msm_bus,vectors: Vectors for bus topology.
Example:
-
qcom,qseecom@fe806000 {
compatible = "qcom,qseecom";
+ qcom,msm_bus,name = "qseecom-noc";
+ qcom,msm_bus,num_cases = <4>;
+ qcom,msm_bus,active_only = <0>;
+ qcom,msm_bus,num_paths = <1>;
+ qcom,msm_bus,vectors =
+ <55 512 0 0>,
+ <55 512 3936000000 393600000>,
+ <55 512 3936000000 393600000>,
+ <55 512 3936000000 393600000>;
};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 0eb186e..cb2c1e1 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -48,6 +48,12 @@
- compatible : "qcom,msm-dai-fe"
+* msm-pcm-afe
+
+Required properties:
+
+ - compatible : "qcom,msm-pcm-afe"
+
* msm-dai-q6
[First Level Nodes]
@@ -63,6 +69,8 @@
- compatible : "qcom,msm-dai-q6-dev"
- qcom,msm-dai-q6-dev-id : The slimbus multi channel port ID
Value is from 16384 to 16393
+ BT SCO port ID value from 12288 to 12289
+ RT Proxy port ID values from 224 to 225 and 240 to 241
* msm-auxpcm
@@ -115,15 +123,36 @@
- compatible : "qcom,msm-ocmem-audio"
- - qcom,msm-ocmem-audio-src-id: Master port id
+ - qcom,msm_bus,name: Client name
- - qcom,msm-ocmem-audio-dst-id: Slave port id
+ - qcom,msm_bus,num_cases: Total number of use cases
- - qcom,msm-ocmem-audio-ab: arbitrated bandwidth
- in Bytes/s
+ - qcom,msm_bus,active_only: Context flag for requests in active or
+ dual (active & sleep) contex
- - qcom,msm-ocmem-audio-ib: instantaneous bandwidth
- in Bytes/s
+ - qcom,msm_bus,num_paths: Total number of master-slave pairs
+
+ - qcom,msm_bus,vectors: Arrays of unsigned integers representing:
+ master-id, slave-id, arbitrated bandwidth,
+ instantaneous bandwidth
+* wcd9xxx_intc
+
+Required properties:
+
+ - compatible : "qcom,wcd9xxx-irq"
+
+ - interrupt-controller : Mark this device node as an interrupt
+ controller
+
+ - #interrupt-cells : Should be 1
+
+ - interrupt-parent : Parent interrupt controller
+
+ - interrupts : Interrupt number on the parent
+ interrupt controller
+
+ - interrupt-names : Name of interrupt on the parent
+ interrupt controller
Example:
@@ -166,6 +195,36 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <16385>;
};
+
+ qcom,msm-dai-q6-bt-sco-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12288>;
+ };
+
+ qcom,msm-dai-q6-bt-sco-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12289>;
+ };
+
+ qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
};
qcom,msm-auxpcm {
@@ -196,10 +255,22 @@
qcom,msm-ocmem-audio {
compatible = "qcom,msm-ocmem-audio";
- qcom,msm-ocmem-audio-src-id = <11>;
- qcom,msm-ocmem-audio-dst-id = <604>;
- qcom,msm-ocmem-audio-ab = <209715200>;
- qcom,msm-ocmem-audio-ib = <471859200>;
+ qcom,msm_bus,name = "audio-ocmem";
+ qcom,msm_bus,num_cases = <2>;
+ qcom,msm_bus,active_only = <0>;
+ qcom,msm_bus,num_paths = <1>;
+ qcom,msm_bus,vectors =
+ <11 604 0 0>,
+ <11 604 32505856 325058560>;
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <72 0>;
+ interrupt-names = "cdc-int";
};
* MSM8974 ASoC Machine driver
diff --git a/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
index b5ca08e..63c1e87 100644
--- a/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
+++ b/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
@@ -10,6 +10,10 @@
- qcom,pmic-arb-channel : the assigned channel number for channel registers.
- qcom,pmic-arb-ppid-map : an array used to map a 12-bit PPID to 8-bit APID.
+Optional properties:
+- qcom,not-wakeup : boolean property which indicates that SPMI PMIC interrupts
+ should not be treated as wakeup sources
+
Peripherals on the SPMI bus are identified with a 12-bit identifier (PPID)
which is composed of a 4-bit slave address and an 8-bit peripheral identifier.
The PMIC Arbiter hardware uses an 8-bit APID (Arbiter Peripheral Identifier)
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 9c2ce6c..12fbfec 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -6,6 +6,8 @@
- compatible : should be "qcom,hsusb-otg"
- regs : offset and length of the register set in the memory map
- interrupts: IRQ line
+- interrupt-names: OTG interrupt name(s) referenced in interrupts above
+ HSUSB OTG expects "core_irq" and optionally "async_irq".
- qcom,hsusb-otg-phy-type: PHY type can be one of
1 - Chipidea 45nm PHY
2 - Synopsis 28nm PHY
@@ -48,6 +50,7 @@
compatible = "qcom,hsusb-otg";
reg = <0xf9690000 0x400>;
interrupts = <134>;
+ interrupt-names = "core_irq";
qcom,hsusb-otg-phy-type = <2>;
qcom,hsusb-otg-mode = <1>;
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 08f7312..7dde34f 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -25,6 +25,15 @@
running parallel lmdd write and lmdd read operations and calculating
the max number of packed writes requests.
+ min_sectors_to_check_bkops_status This attribute is used to
+ determine whether the status bit that indicates the need for BKOPS
+ should be checked. The value is stored in this attribute represents
+ the minimum number of sectors that needs to be changed in the device
+ (written or discarded) in order to require the status-bit of BKOPS
+ to be checked. The value can modified via sysfs by writing the
+ required value to:
+ /sys/block/<block_dev_name>/min_sectors_to_check_bkops_status
+
SD and MMC Device Attributes
============================
diff --git a/arch/Kconfig b/arch/Kconfig
index 0d88760..0a3ffe4 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -169,13 +169,6 @@
bool
depends on PERF_EVENTS
-config HAVE_HW_BRKPT_RESERVED_RW_ACCESS
- bool
- depends on HAVE_HW_BREAKPOINT
- help
- Some of the hardware might not have r/w access beyond a certain number
- of breakpoint register access.
-
config HAVE_MIXED_BREAKPOINTS_REGS
bool
depends on HAVE_HW_BREAKPOINT
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d7ebcfe..5d5f9de 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -29,7 +29,7 @@
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
select HAVE_REGS_AND_STACK_ACCESS_API
- #select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
+ select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
select HAVE_C_RECORDMCOUNT
select HAVE_GENERIC_HARDIRQS
select GENERIC_IRQ_SHOW
diff --git a/arch/arm/boot/dts/mpq8092-iommu.dtsi b/arch/arm/boot/dts/mpq8092-iommu.dtsi
new file mode 100644
index 0000000..6a88992
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092-iommu.dtsi
@@ -0,0 +1,33 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "msm-iommu.dtsi"
+
+&jpeg_iommu {
+ status = "ok";
+};
+
+&mdp_iommu {
+ status = "ok";
+};
+
+&venus_iommu {
+ status = "ok";
+};
+
+&kgsl_iommu {
+ status = "ok";
+};
+
+&vfe_iommu {
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index f73abe7..ac984a1 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -12,37 +12,19 @@
/dts-v1/;
-/include/ "skeleton.dtsi"
+/include/ "mpq8092.dtsi"
/ {
model = "Qualcomm MPQ8092 Simulator";
compatible = "qcom,mpq8092-sim", "qcom,mpq8092";
- interrupt-parent = <&intc>;
-
- intc: interrupt-controller@f9000000 {
- compatible = "qcom,msm-qgic2";
- interrupt-controller;
- #interrupt-cells = <3>;
- reg = <0xf9000000 0x1000>,
- <0xf9002000 0x1000>;
- };
-
- timer {
- compatible = "qcom,msm-qtimer", "arm,armv7-timer";
- interrupts = <1 2 0>, <1 3 0>;
- clock-frequency = <19200000>;
- };
+ qcom,msm-id = <126 16 0>;
serial@f991f000 {
- compatible = "qcom,msm-lsuart-v14";
- reg = <0xf991f000 0x1000>;
- interrupts = <0 109 0>;
+ status = "ok";
};
serial@f995e000 {
- compatible = "qcom,msm-lsuart-v14";
- reg = <0xf995e000 0x1000>;
- interrupts = <0 114 0>;
+ status = "ok";
};
};
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
new file mode 100644
index 0000000..9b51ceb
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -0,0 +1,58 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "skeleton.dtsi"
+/include/ "mpq8092-iommu.dtsi"
+/include/ "msm-gdsc.dtsi"
+
+/ {
+ model = "Qualcomm MPQ8092";
+ compatible = "qcom,mpq8092";
+ interrupt-parent = <&intc>;
+
+ 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>;
+ };
+
+ timer {
+ compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+ interrupts = <1 2 0>, <1 3 0>;
+ clock-frequency = <19200000>;
+ };
+
+ serial@f991f000 {
+ compatible = "qcom,msm-lsuart-v14";
+ reg = <0xf991f000 0x1000>;
+ interrupts = <0 109 0>;
+ status = "disabled";
+ };
+
+ serial@f995e000 {
+ compatible = "qcom,msm-lsuart-v14";
+ reg = <0xf995e000 0x1000>;
+ interrupts = <0 114 0>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/msm-iommu.dtsi b/arch/arm/boot/dts/msm-iommu.dtsi
index e907de8..709f40a 100755
--- a/arch/arm/boot/dts/msm-iommu.dtsi
+++ b/arch/arm/boot/dts/msm-iommu.dtsi
@@ -18,7 +18,6 @@
ranges;
reg = <0xfda64000 0x10000>;
vdd-supply = <&gdsc_jpeg>;
- qcom,iommu-smt-size = <16>;
status = "disabled";
qcom,iommu-ctx@fda6c000 {
@@ -50,7 +49,6 @@
ranges;
reg = <0xfd928000 0x10000>;
vdd-supply = <&gdsc_mdss>;
- qcom,iommu-smt-size = <16>;
status = "disabled";
qcom,iommu-ctx@fd930000 {
@@ -75,7 +73,6 @@
ranges;
reg = <0xfdc84000 0x10000>;
vdd-supply = <&gdsc_venus>;
- qcom,iommu-smt-size = <16>;
qcom,needs-alt-core-clk;
status = "disabled";
@@ -108,10 +105,35 @@
ranges;
reg = <0xfdb10000 0x10000>;
vdd-supply = <&gdsc_oxili_cx>;
- qcom,iommu-smt-size = <32>;
qcom,needs-alt-core-clk;
status = "disabled";
+ qcom,iommu-bfb-regs = <0x204c
+ 0x2050
+ 0x2514
+ 0x2540
+ 0x256c
+ 0x20ac
+ 0x215c
+ 0x220c
+ 0x2314
+ 0x2394
+ 0x2414
+ 0x2008>;
+
+ qcom,iommu-bfb-data = <0xffffffff
+ 0xffffffff
+ 0x00000004
+ 0x00000010
+ 0x00000000
+ 0x00000000
+ 0x00000001
+ 0x00000021
+ 0x0
+ 0x1
+ 0x81
+ 0x0>;
+
qcom,iommu-ctx@fdb18000 {
reg = <0xfdb18000 0x1000>;
interrupts = <0 241 0>;
@@ -134,7 +156,6 @@
ranges;
reg = <0xfda44000 0x10000>;
vdd-supply = <&gdsc_vfe>;
- qcom,iommu-smt-size = <32>;
status = "disabled";
qcom,iommu-ctx@fda4c000 {
diff --git a/arch/arm/boot/dts/msm-pm8019-rpm-regulator.dtsi b/arch/arm/boot/dts/msm-pm8019-rpm-regulator.dtsi
new file mode 100644
index 0000000..c48f67d
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8019-rpm-regulator.dtsi
@@ -0,0 +1,301 @@
+/* Copyright (c) 2012, 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.
+ */
+
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-s1 {
+ regulator-name = "8019_s1";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-smpa2 {
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-s2 {
+ regulator-name = "8019_s2";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-s3 {
+ regulator-name = "8019_s3";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-s4 {
+ regulator-name = "8019_s4";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l1 {
+ regulator-name = "8019_l1";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l2 {
+ regulator-name = "8019_l2";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l3 {
+ regulator-name = "8019_l3";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l4 {
+ regulator-name = "8019_l4";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l5 {
+ regulator-name = "8019_l5";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <6>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l6 {
+ regulator-name = "8019_l6";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <7>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l7 {
+ regulator-name = "8019_l7";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <8>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l8 {
+ regulator-name = "8019_l8";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <9>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l9 {
+ regulator-name = "8019_l9";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <10>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l10 {
+ regulator-name = "8019_l10";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <11>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l11 {
+ regulator-name = "8019_l11";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <12>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l12 {
+ regulator-name = "8019_l12";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <13>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l13 {
+ regulator-name = "8019_l13";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <14>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ compatible = "qcom,rpm-regulator-smd-resource";
+ status = "disabled";
+
+ regulator-l14 {
+ regulator-name = "8019_l14";
+ qcom,set = <3>;
+ status = "disabled";
+ compatible = "qcom,rpm-regulator-smd";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
new file mode 100755
index 0000000..e70eb36
--- /dev/null
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -0,0 +1,355 @@
+/* Copyright (c) 2012, 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.
+ */
+
+&spmi_bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+
+ qcom,pm8019@0 {
+ spmi-slave-container;
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ qcom,power_on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0x2>;
+ interrupt-names = "cblpwr";
+ qcom,pon-dbc-delay = <15625>;
+ qcom,system-reset;
+
+ qcom,pon_1 {
+ qcom,pon-type = <2>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+ };
+
+ clkdiv@5b00 {
+ reg = <0x5b00 0x100>;
+ compatible = "qcom,qpnp-clkdiv";
+ qcom,cxo-freq = <19200000>;
+ };
+
+ clkdiv@5c00 {
+ reg = <0x5c00 0x100>;
+ compatible = "qcom,qpnp-clkdiv";
+ qcom,cxo-freq = <19200000>;
+ };
+
+ clkdiv@5d00 {
+ reg = <0x5d00 0x100>;
+ compatible = "qcom,qpnp-clkdiv";
+ qcom,cxo-freq = <19200000>;
+ };
+
+ rtc {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-rtc";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,qpnp-rtc-write = <0>;
+ qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+ qcom,pm8019_rtc_rw@6000 {
+ reg = <0x6000 0x100>;
+ };
+
+ qcom,pm8019_rtc_alarm@6100 {
+ reg = <0x6100 0x100>;
+ interrupts = <0x0 0x61 0x1>;
+ };
+ };
+
+ pm8019_gpios: gpios {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8019-gpio";
+
+ gpio@c000 {
+ reg = <0xc000 0x100>;
+ qcom,pin-num = <1>;
+ };
+
+ gpio@c100 {
+ reg = <0xc100 0x100>;
+ qcom,pin-num = <2>;
+ };
+
+ gpio@c200 {
+ reg = <0xc200 0x100>;
+ qcom,pin-num = <3>;
+ };
+
+ gpio@c300 {
+ reg = <0xc300 0x100>;
+ qcom,pin-num = <4>;
+ };
+
+ gpio@c400 {
+ reg = <0xc400 0x100>;
+ qcom,pin-num = <5>;
+ };
+
+ gpio@c500 {
+ reg = <0xc500 0x100>;
+ qcom,pin-num = <6>;
+ };
+ };
+
+ pm8019_mpps: mpps {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8019-mpp";
+
+ mpp@a000 {
+ reg = <0xa000 0x100>;
+ qcom,pin-num = <1>;
+ };
+
+ mpp@a100 {
+ reg = <0xa100 0x100>;
+ qcom,pin-num = <2>;
+ };
+
+ mpp@a200 {
+ reg = <0xa200 0x100>;
+ qcom,pin-num = <3>;
+ };
+
+ mpp@a300 {
+ reg = <0xa300 0x100>;
+ qcom,pin-num = <4>;
+ };
+
+ mpp@a400 {
+ reg = <0xa400 0x100>;
+ qcom,pin-num = <5>;
+ };
+
+ mpp@a500 {
+ reg = <0xa500 0x100>;
+ qcom,pin-num = <6>;
+ };
+ };
+ };
+
+ qcom,pm8019@1 {
+ spmi-slave-container;
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ regulator@1400 {
+ regulator-name = "8019_s1";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qpnp-regulator";
+ reg = <0x1400 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1400 {
+ reg = <0x1400 0x100>;
+ };
+ qcom,ps@1500 {
+ reg = <0x1500 0x100>;
+ };
+ qcom,freq@1600 {
+ reg = <0x1600 0x100>;
+ };
+ };
+
+ regulator@1700 {
+ regulator-name = "8019_s2";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qpnp-regulator";
+ reg = <0x1700 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1700 {
+ reg = <0x1700 0x100>;
+ };
+ qcom,ps@1800 {
+ reg = <0x1800 0x100>;
+ };
+ qcom,freq@1900 {
+ reg = <0x1900 0x100>;
+ };
+ };
+
+ regulator@1a00 {
+ regulator-name = "8019_s3";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qpnp-regulator";
+ reg = <0x1a00 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1a00 {
+ reg = <0x1a00 0x100>;
+ };
+ qcom,ps@1b00 {
+ reg = <0x1b00 0x100>;
+ };
+ qcom,freq@1c00 {
+ reg = <0x1c00 0x100>;
+ };
+ };
+
+ regulator@1d00 {
+ regulator-name = "8019_s4";
+ spmi-dev-container;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "qcom,qpnp-regulator";
+ reg = <0x1d00 0x300>;
+ status = "disabled";
+
+ qcom,ctl@1d00 {
+ reg = <0x1d00 0x100>;
+ };
+ qcom,ps@1e00 {
+ reg = <0x1e00 0x100>;
+ };
+ qcom,freq@1f00 {
+ reg = <0x1f00 0x100>;
+ };
+ };
+
+ regulator@4000 {
+ regulator-name = "8019_l1";
+ reg = <0x4000 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4100 {
+ regulator-name = "8019_l2";
+ reg = <0x4100 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4200 {
+ regulator-name = "8019_l3";
+ reg = <0x4200 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4300 {
+ regulator-name = "8019_l4";
+ reg = <0x4300 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4400 {
+ regulator-name = "8019_l5";
+ reg = <0x4400 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4500 {
+ regulator-name = "8019_l6";
+ reg = <0x4500 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4600 {
+ regulator-name = "8019_l7";
+ reg = <0x4600 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4700 {
+ regulator-name = "8019_l8";
+ reg = <0x4700 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4800 {
+ regulator-name = "8019_l9";
+ reg = <0x4800 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4900 {
+ regulator-name = "8019_l10";
+ reg = <0x4900 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4a00 {
+ regulator-name = "8019_l11";
+ reg = <0x4a00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4b00 {
+ regulator-name = "8019_l12";
+ reg = <0x4b00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4c00 {
+ regulator-name = "8019_l13";
+ reg = <0x4c00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4d00 {
+ regulator-name = "8019_l14";
+ reg = <0x4d00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4e00 {
+ regulator-name = "8019_ldo_xo";
+ reg = <0x4e00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+
+ regulator@4f00 {
+ regulator-name = "8019_ldo_rfclk";
+ reg = <0x4f00 0x100>;
+ compatible = "qcom,qpnp-regulator";
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
index 967d5ec..ea83231 100644
--- a/arch/arm/boot/dts/msm-pm8841.dtsi
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -22,7 +22,7 @@
#address-cells = <1>;
#size-cells = <1>;
- pm8841_mpps {
+ pm8841_mpps: mpps {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
gpio-controller;
@@ -34,25 +34,21 @@
mpp@a000 {
reg = <0xa000 0x100>;
qcom,pin-num = <1>;
- status = "disabled";
};
mpp@a100 {
reg = <0xa100 0x100>;
qcom,pin-num = <2>;
- status = "disabled";
};
mpp@a200 {
reg = <0xa200 0x100>;
qcom,pin-num = <3>;
- status = "disabled";
};
mpp@a300 {
reg = <0xa300 0x100>;
qcom,pin-num = <4>;
- status = "disabled";
};
};
};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 869a357..f1e18cf 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -49,6 +49,41 @@
};
};
+ bms@4000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "qcom,qpnp-bms";
+ 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,bms-r-sense-mohm = <10>;
+ qcom,bms-v-cutoff-uv = <3400000>;
+ qcom,bms-max-voltage-uv = <4200000>;
+ qcom,bms-r-conn-mohm = <18>;
+ qcom,bms-shutdown-soc-valid-limit = <20>;
+ qcom,bms-adjust-soc-low-threshold = <25>;
+ qcom,bms-adjust-soc-high-threshold = <45>;
+ qcom,bms-chg-term-ua = <100000>;
+ };
+
clkdiv@5b00 {
reg = <0x5b00 0x100>;
compatible = "qcom,qpnp-clkdiv";
@@ -168,7 +203,7 @@
};
};
- pm8941_gpios {
+ pm8941_gpios: gpios {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
gpio-controller;
@@ -180,221 +215,185 @@
gpio@c000 {
reg = <0xc000 0x100>;
qcom,pin-num = <1>;
- status = "disabled";
};
gpio@c100 {
reg = <0xc100 0x100>;
qcom,pin-num = <2>;
- status = "disabled";
};
gpio@c200 {
reg = <0xc200 0x100>;
qcom,pin-num = <3>;
- status = "disabled";
};
gpio@c300 {
reg = <0xc300 0x100>;
qcom,pin-num = <4>;
- status = "disabled";
};
gpio@c400 {
reg = <0xc400 0x100>;
qcom,pin-num = <5>;
- status = "disabled";
};
gpio@c500 {
reg = <0xc500 0x100>;
qcom,pin-num = <6>;
- status = "disabled";
};
gpio@c600 {
reg = <0xc600 0x100>;
qcom,pin-num = <7>;
- status = "disabled";
};
gpio@c700 {
reg = <0xc700 0x100>;
qcom,pin-num = <8>;
- status = "disabled";
};
gpio@c800 {
reg = <0xc800 0x100>;
qcom,pin-num = <9>;
- status = "disabled";
};
gpio@c900 {
reg = <0xc900 0x100>;
qcom,pin-num = <10>;
- status = "disabled";
};
gpio@ca00 {
reg = <0xca00 0x100>;
qcom,pin-num = <11>;
- status = "disabled";
};
gpio@cb00 {
reg = <0xcb00 0x100>;
qcom,pin-num = <12>;
- status = "disabled";
};
gpio@cc00 {
reg = <0xcc00 0x100>;
qcom,pin-num = <13>;
- status = "disabled";
};
gpio@cd00 {
reg = <0xcd00 0x100>;
qcom,pin-num = <14>;
- status = "disabled";
};
gpio@ce00 {
reg = <0xce00 0x100>;
qcom,pin-num = <15>;
- status = "disabled";
};
gpio@cf00 {
reg = <0xcf00 0x100>;
qcom,pin-num = <16>;
- status = "disabled";
};
gpio@d000 {
reg = <0xd000 0x100>;
qcom,pin-num = <17>;
- status = "disabled";
};
gpio@d100 {
reg = <0xd100 0x100>;
qcom,pin-num = <18>;
- status = "disabled";
};
gpio@d200 {
reg = <0xd200 0x100>;
qcom,pin-num = <19>;
- status = "disabled";
};
gpio@d300 {
reg = <0xd300 0x100>;
qcom,pin-num = <20>;
- status = "disabled";
};
gpio@d400 {
reg = <0xd400 0x100>;
qcom,pin-num = <21>;
- status = "disabled";
};
gpio@d500 {
reg = <0xd500 0x100>;
qcom,pin-num = <22>;
- status = "disabled";
};
gpio@d600 {
reg = <0xd600 0x100>;
qcom,pin-num = <23>;
- status = "disabled";
};
gpio@d700 {
reg = <0xd700 0x100>;
qcom,pin-num = <24>;
- status = "disabled";
};
gpio@d800 {
reg = <0xd800 0x100>;
qcom,pin-num = <25>;
- status = "disabled";
};
gpio@d900 {
reg = <0xd900 0x100>;
qcom,pin-num = <26>;
- status = "disabled";
};
gpio@da00 {
reg = <0xda00 0x100>;
qcom,pin-num = <27>;
- status = "disabled";
};
gpio@db00 {
reg = <0xdb00 0x100>;
qcom,pin-num = <28>;
- status = "disabled";
};
gpio@dc00 {
reg = <0xdc00 0x100>;
qcom,pin-num = <29>;
- status = "disabled";
};
gpio@dd00 {
reg = <0xdd00 0x100>;
qcom,pin-num = <30>;
- status = "disabled";
};
gpio@de00 {
reg = <0xde00 0x100>;
qcom,pin-num = <31>;
- status = "disabled";
};
gpio@df00 {
reg = <0xdf00 0x100>;
qcom,pin-num = <32>;
- status = "disabled";
};
gpio@e000 {
reg = <0xe000 0x100>;
qcom,pin-num = <33>;
- status = "disabled";
};
gpio@e100 {
reg = <0xe100 0x100>;
qcom,pin-num = <34>;
- status = "disabled";
};
gpio@e200 {
reg = <0xe200 0x100>;
qcom,pin-num = <35>;
- status = "disabled";
};
gpio@e300 {
reg = <0xe300 0x100>;
qcom,pin-num = <36>;
- status = "disabled";
};
};
- pm8941_mpps {
+ pm8941_mpps: mpps {
spmi-dev-container;
compatible = "qcom,qpnp-pin";
gpio-controller;
@@ -406,49 +405,41 @@
mpp@a000 {
reg = <0xa000 0x100>;
qcom,pin-num = <1>;
- status = "disabled";
};
mpp@a100 {
reg = <0xa100 0x100>;
qcom,pin-num = <2>;
- status = "disabled";
};
mpp@a200 {
reg = <0xa200 0x100>;
qcom,pin-num = <3>;
- status = "disabled";
};
mpp@a300 {
reg = <0xa300 0x100>;
qcom,pin-num = <4>;
- status = "disabled";
};
mpp@a400 {
reg = <0xa400 0x100>;
qcom,pin-num = <5>;
- status = "disabled";
};
mpp@a500 {
reg = <0xa500 0x100>;
qcom,pin-num = <6>;
- status = "disabled";
};
mpp@a600 {
reg = <0xa600 0x100>;
qcom,pin-num = <7>;
- status = "disabled";
};
mpp@a700 {
reg = <0xa700 0x100>;
qcom,pin-num = <8>;
- status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 4330849..aeda1d8 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -58,4 +58,21 @@
reg = <0xf995e000 0x1000>;
interrupts = <0 114 0>;
};
+
+ usb@f9a55000 {
+ compatible = "qcom,hsusb-otg";
+ reg = <0xf9a55000 0x400>;
+ interrupts = <0 134 0>;
+ interrupt-names = "core_irq";
+
+ qcom,hsusb-otg-phy-type = <2>;
+ qcom,hsusb-otg-mode = <1>;
+ qcom,hsusb-otg-otg-control = <1>;
+ qcom,hsusb-otg-disable-reset;
+ };
+
+ android_usb {
+ compatible = "qcom,android-usb";
+ };
+
};
diff --git a/arch/arm/boot/dts/msm8910-sim.dts b/arch/arm/boot/dts/msm8910-sim.dts
new file mode 100644
index 0000000..268e1f8
--- /dev/null
+++ b/arch/arm/boot/dts/msm8910-sim.dts
@@ -0,0 +1,51 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8910 Simulator";
+ compatible = "qcom,msm8910-sim", "qcom,msm8910";
+ qcom,msm-id = <147 1 0>;
+ interrupt-parent = <&intc>;
+
+ 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";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0xfd510000 0x4000>;
+ #gpio-cells = <2>;
+ };
+
+ timer: msm-qtimer@f9021000 {
+ compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+ reg = <0xf9021000 0x1000>;
+ interrupts = <0 7 0 0 8 0>;
+ irq-is-not-percpu;
+ clock-frequency = <19200000>;
+ };
+
+ serial@f991f000 {
+ compatible = "qcom,msm-lsuart-v14";
+ reg = <0xf991f000 0x1000>;
+ interrupts = <0 109 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index c92188a..fd652a0 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -181,7 +181,6 @@
reg = <0x6e 0x0>;
qcom,csi-if = <1>;
qcom,csid-core = <0>;
- qcom,is-vpe = <1>;
qcom,flash-type = <0>;
qcom,mount-angle = <90>;
qcom,sensor-name = "s5k3l1yx";
@@ -222,8 +221,7 @@
compatible = "qcom,ov2720";
reg = <0x6c 0x0>;
qcom,csi-if = <1>;
- qcom,csid-core = <1>;
- qcom,is-vpe = <1>;
+ qcom,csid-core = <0>;
qcom,flash-type = <0>;
qcom,mount-angle = <0>;
qcom,sensor-name = "ov2720";
@@ -257,5 +255,40 @@
qcom,camera-type = <1>;
qcom,sensor-type = <0>;
};
+
+ qcom,camera@90 {
+ compatible = "qcom,mt9m114";
+ reg = <0x90 0x0>;
+ qcom,csi-if = <1>;
+ qcom,csid-core = <0>;
+ qcom,flash-type = <0>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "mt9m114";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+ qcom,cam-vreg-type = <0 0 1>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-op-mode = <105000 80000 0>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 16 0>,
+ <&msmgpio 92 0>;
+ qcom,gpio-common-tbl-num = <0>;
+ qcom,gpio-common-tbl-flags = <1>;
+ qcom,gpio-common-tbl-label = "CAMIF_MCLK";
+ qcom,gpio-req-tbl-num = <1>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,csi-phy-sel = <1>;
+ qcom,camera-type = <1>;
+ qcom,sensor-type = <1>;
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8974-cdp.dts b/arch/arm/boot/dts/msm8974-cdp.dts
index 7aeb33c..05fcc4f 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dts
+++ b/arch/arm/boot/dts/msm8974-cdp.dts
@@ -112,6 +112,7 @@
gpio_keys {
compatible = "gpio-keys";
+ input-name = "gpio-keys";
camera_snapshot {
label = "camera_snapshot";
@@ -168,3 +169,196 @@
cd-gpios = <&msmgpio 62 0x1>;
wp-gpios = <&pm8941_gpios 29 0x1>;
};
+
+&pm8941_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-select = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+
+ gpio@d600 { /* GPIO 23 */
+ };
+
+ gpio@d700 { /* GPIO 24 */
+ };
+
+ gpio@d800 { /* GPIO 25 */
+ };
+
+ gpio@d900 { /* GPIO 26 */
+ };
+
+ gpio@da00 { /* GPIO 27 */
+ };
+
+ gpio@db00 { /* GPIO 28 */
+ };
+
+ gpio@dc00 { /* GPIO 29 */
+ qcom,pull = <0>; /* set to default pull */
+ qcom,master-en = <1>;
+ qcom,vin-sel = <2>; /* select 1.8 V source */
+ };
+
+ gpio@dd00 { /* GPIO 30 */
+ };
+
+ gpio@de00 { /* GPIO 31 */
+ };
+
+ gpio@df00 { /* GPIO 32 */
+ };
+
+ gpio@e000 { /* GPIO 33 */
+ };
+
+ gpio@e100 { /* GPIO 34 */
+ };
+
+ gpio@e200 { /* GPIO 35 */
+ };
+
+ gpio@e300 { /* GPIO 36 */
+ };
+};
+
+&pm8941_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* SPI_ETH config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* SPI_ETH_RST config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8841_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index 0b09bc8..ee3df10 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -141,6 +141,7 @@
coresight-outports = <0>;
coresight-child-list = <&funnel_kpss>;
coresight-child-ports = <0>;
+ qcom,pc-save;
};
etm1: etm@fc33d000 {
@@ -153,6 +154,7 @@
coresight-outports = <0>;
coresight-child-list = <&funnel_kpss>;
coresight-child-ports = <1>;
+ qcom,pc-save;
};
etm2: etm@fc33e000 {
@@ -165,6 +167,7 @@
coresight-outports = <0>;
coresight-child-list = <&funnel_kpss>;
coresight-child-ports = <2>;
+ qcom,pc-save;
};
etm3: etm@fc33f000 {
@@ -177,6 +180,7 @@
coresight-outports = <0>;
coresight-child-list = <&funnel_kpss>;
coresight-child-ports = <3>;
+ qcom,pc-save;
};
csr: csr@fc302000 {
diff --git a/arch/arm/boot/dts/msm8974-fluid.dts b/arch/arm/boot/dts/msm8974-fluid.dts
new file mode 100644
index 0000000..b1d467e
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-fluid.dts
@@ -0,0 +1,366 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm8974.dtsi"
+/include/ "dsi-panel-toshiba-720p-video.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8974 FLUID";
+ compatible = "qcom,msm8974-fluid", "qcom,msm8974";
+ qcom,msm-id = <126 3 0>;
+
+ serial@f991e000 {
+ status = "ok";
+ };
+
+ qcom,mdss_dsi@fd922800 {
+ qcom,mdss_dsi_toshiba_720p_video {
+ status = "ok";
+ };
+ };
+
+ i2c@f9924000 {
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <61 0x2>;
+ vdd_ana-supply = <&pm8941_l18>;
+ vcc_i2c-supply = <&pm8941_lvs1>;
+ atmel,reset-gpio = <&msmgpio 60 0x00>;
+ atmel,irq-gpio = <&msmgpio 61 0x00>;
+ atmel,panel-coords = <0 0 760 1424>;
+ atmel,display-coords = <0 0 720 1280>;
+ atmel,i2c-pull-up = <1>;
+ atmel,cfg_1 {
+ atmel,family-id = <0x82>;
+ atmel,variant-id = <0x19>;
+ atmel,version = <0x10>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 15 00 02 10 08 0C 00 00
+ /* Object 7, Instance = 0 */
+ FF FF 32 03
+ /* Object 8, Instance = 0 */
+ 0F 00 0A 0A 00 00 0A 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 18 0E 00 70 32 02 01
+ 00 03 01 01 05 0A 0A 0A 90 05
+ F8 02 00 00 0F 0F 00 00 48 2D
+ 07 0C 00 00 00 00
+ /* Object 15, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 23, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 40, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 00 00 10 10 00 00 03 00 00 01
+ /* Object 47, Instance = 0 */
+ 08 0A 28 0A 02 0A 00 8C 00 20
+ 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 56, Instance = 0 */
+ 03 00 01 18 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 05 05
+ 05 05 05 05 05 05 05 05 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00
+ /* Object 57, Instance = 0 */
+ 00 00 00
+ /* Object 61, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 61, Instance = 1 */
+ 00 00 00 00 00
+ /* Object 62, Instance = 0 */
+ 7F 03 00 16 00 00 00 00 00 00
+ 04 08 10 18 05 00 0A 05 05 50
+ 14 19 34 1A 64 00 00 04 40 00
+ 00 00 00 00 30 32 02 00 01 00
+ 05 00 00 00 00 00 00 00 00 00
+ 00 00 0C 00
+ ];
+ };
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&pm8941_gpios 3 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&pm8941_gpios 4 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ spi@f9923000 {
+ ethernet-switch@2 {
+ compatible = "micrel,ks8851";
+ reg = <2>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <94 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&pm8941_mpps 6 0>;
+ vdd-io-supply = <&spi_eth_vreg>;
+ vdd-phy-supply = <&spi_eth_vreg>;
+ };
+ };
+};
+
+&sdcc1 {
+ qcom,sdcc-bus-width = <4>;
+};
+
+&sdcc2 {
+ #address-cells = <0>;
+ interrupt-parent = <&sdcc2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 220 0
+ 2 &msmgpio 62 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+};
+
+&pm8941_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-select = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+
+ gpio@d600 { /* GPIO 23 */
+ };
+
+ gpio@d700 { /* GPIO 24 */
+ };
+
+ gpio@d800 { /* GPIO 25 */
+ };
+
+ gpio@d900 { /* GPIO 26 */
+ };
+
+ gpio@da00 { /* GPIO 27 */
+ };
+
+ gpio@db00 { /* GPIO 28 */
+ };
+
+ gpio@dc00 { /* GPIO 29 */
+ qcom,pull = <0>; /* set to default pull */
+ qcom,master-en = <1>;
+ qcom,vin-sel = <2>; /* select 1.8 V source */
+ };
+
+ gpio@dd00 { /* GPIO 30 */
+ };
+
+ gpio@de00 { /* GPIO 31 */
+ };
+
+ gpio@df00 { /* GPIO 32 */
+ };
+
+ gpio@e000 { /* GPIO 33 */
+ };
+
+ gpio@e100 { /* GPIO 34 */
+ };
+
+ gpio@e200 { /* GPIO 35 */
+ };
+
+ gpio@e300 { /* GPIO 36 */
+ };
+};
+
+&pm8941_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* SPI_ETH config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* SPI_ETH_RST config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8841_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
deleted file mode 100644
index dac87a3..0000000
--- a/arch/arm/boot/dts/msm8974-gpio.dtsi
+++ /dev/null
@@ -1,273 +0,0 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-&spmi_bus {
-
- qcom,pm8941@0 {
-
- pm8941_gpios: pm8941_gpios {
-
- gpio@c000 {
- status = "ok";
- };
-
- gpio@c100 {
- status = "ok";
- };
-
- gpio@c200 {
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- status = "ok";
- };
-
- gpio@c300 {
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- status = "ok";
- };
-
- gpio@c400 {
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <2>;
- qcom,select = <0>;
- status = "ok";
- };
-
- gpio@c500 {
- status = "ok";
- };
-
- gpio@c600 {
- status = "ok";
- };
-
- gpio@c700 {
- status = "ok";
- };
-
- gpio@c800 {
- status = "ok";
- };
-
- gpio@c900 {
- status = "ok";
- };
-
- gpio@ca00 {
- status = "ok";
- };
-
- gpio@cb00 {
- status = "ok";
- };
-
- gpio@cc00 {
- status = "ok";
- };
-
- gpio@cd00 {
- status = "ok";
- };
-
- gpio@ce00 {
- status = "ok";
- qcom,mode = <1>;
- qcom,output-type = <0>;
- qcom,pull = <5>;
- qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
- qcom,src-select = <2>;
- qcom,master-en = <1>;
- };
-
- gpio@cf00 {
- status = "ok";
- };
-
- gpio@d000 {
- status = "ok";
- };
-
- gpio@d100 {
- status = "ok";
- };
-
- gpio@d200 {
- status = "ok";
- qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
- qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
- qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
- qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
- qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
- qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
- qcom,master-en = <1>;
- };
-
- gpio@d300 {
- status = "ok";
- };
-
- gpio@d400 {
- status = "ok";
- };
-
- gpio@d500 {
- status = "ok";
- };
-
- gpio@d600 {
- status = "ok";
- };
-
- gpio@d700 {
- status = "ok";
- };
-
- gpio@d800 {
- qcom,out-strength = <1>;
- status = "ok";
- };
-
- gpio@d900 {
- qcom,out-strength = <1>;
- status = "ok";
- };
-
- gpio@da00 {
- qcom,out-strength = <1>;
- status = "ok";
- };
-
- gpio@db00 {
- qcom,out-strength = <1>;
- status = "ok";
- };
-
- gpio@dc00 {
- qcom,pull = <0>; /* set to default pull */
- qcom,master-en = <1>;
- qcom,vin-sel = <2>; /* select 1.8 V source */
- status = "ok";
- };
-
- gpio@dd00 {
- qcom,out-strength = <1>;
- status = "ok";
- };
-
- gpio@de00 {
- qcom,out-strength = <1>;
- status = "ok";
- };
-
- gpio@df00 {
- qcom,out-strength = <1>;
- status = "ok";
- };
-
- gpio@e000 {
- qcom,out-strength = <1>;
- status = "ok";
- };
-
- gpio@e100 {
- qcom,out-strength = <1>;
- status = "ok";
- };
-
- gpio@e200 {
- qcom,out-strength = <1>;
- status = "ok";
- };
-
- gpio@e300 {
- qcom,out-strength = <1>;
- status = "ok";
- };
- };
-
- pm8941_mpps: pm8941_mpps {
-
- mpp@a000 {
- status = "ok";
- };
-
- mpp@a100 {
- status = "ok";
- };
-
- mpp@a200 {
- status = "ok";
- };
-
- mpp@a300 {
- status = "ok";
- };
-
- mpp@a400 {
- status = "ok";
- /* SPI_ETH config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a500 {
- status = "ok";
- /* SPI_ETH_RST config */
- qcom,mode = <1>; /* DIG_OUT */
- qcom,output-type = <0>; /* CMOS */
- qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
- qcom,src-select = <0>; /* CONSTANT */
- qcom,master-en = <1>; /* ENABLE MPP */
- };
-
- mpp@a600 {
- status = "ok";
- };
-
- mpp@a700 {
- status = "ok";
- };
- };
- };
-
- qcom,pm8841@4 {
-
- pm8841_mpps: pm8841_mpps {
-
- mpp@a000 {
- status = "ok";
- };
-
- mpp@a100 {
- status = "ok";
- };
-
- mpp@a200 {
- status = "ok";
- };
-
- mpp@a300 {
- status = "ok";
- };
- };
- };
-};
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 2312b02..6d00b01 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -25,6 +25,7 @@
qcom,idle-timeout = <83>; //<HZ/12>
qcom,nap-allowed = <1>;
+ qcom,strtstp-sleepwake;
qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
/* Bus Scale Settings */
@@ -85,40 +86,71 @@
compatible = "qcom,dcvs-core-info";
- qcom,core-max-time-us = <100000>;
- qcom,algo-slack-time-us = <39000>;
- qcom,algo-disable-pc-threshold = <86000>;
- qcom,algo-ss-window-size = <1000000>;
- qcom,algo-ss-util-pct = <95>;
+ qcom,num-cores = <1>;
+ qcom,sensors = <0>;
+
+ qcom,core-core-type = <1>;
+
+ qcom,algo-disable-pc-threshold = <0>;
+ qcom,algo-em-win-size-min-us = <100000>;
+ qcom,algo-em-win-size-max-us = <300000>;
qcom,algo-em-max-util-pct = <97>;
+ qcom,algo-group-id = <95>;
+ qcom,algo-max-freq-chg-time-us = <100000>;
+ qcom,algo-slack-mode-dynamic = <100000>;
+ qcom,algo-slack-weight-thresh-pct = <0>;
+ qcom,algo-slack-time-min-us = <39000>;
+ qcom,algo-slack-time-max-us = <39000>;
+ qcom,algo-ss-win-size-min-us = <1000000>;
+ qcom,algo-ss-win-size-max-us = <1000000>;
+ qcom,algo-ss-util-pct = <95>;
qcom,algo-ss-iobusy-conv = <100>;
+ qcom,energy-active-coeff-a = <2492>;
+ qcom,energy-active-coeff-b = <0>;
+ qcom,energy-active-coeff-c = <0>;
+ qcom,energy-leakage-coeff-a = <11>;
+ qcom,energy-leakage-coeff-b = <157150>;
+ qcom,energy-leakage-coeff-c = <0>;
+ qcom,energy-leakage-coeff-d = <0>;
+
+ qcom,power-current-temp = <25>;
+ qcom,power-num-freq = <4>;
+
qcom,dcvs-freq@0 {
reg = <0>;
qcom,freq = <0>;
- qcom,idle-energy = <0>;
- qcom,active-energy = <333932>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <100>;
+ qcom,leakage-energy-offset = <0>;
};
qcom,dcvs-freq@1 {
reg = <1>;
qcom,freq = <0>;
- qcom,idle-energy = <0>;
- qcom,active-energy = <497532>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <100>;
+ qcom,leakage-energy-offset = <0>;
};
qcom,dcvs-freq@2 {
reg = <2>;
qcom,freq = <0>;
- qcom,idle-energy = <0>;
- qcom,active-energy = <707610>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <100>;
+ qcom,leakage-energy-offset = <0>;
};
qcom,dcvs-freq@3 {
reg = <3>;
qcom,freq = <0>;
- qcom,idle-energy = <0>;
- qcom,active-energy = <844545>;
+ qcom,voltage = <0>;
+ qcom,is_trans_level = <0>;
+ qcom,active-energy-offset = <844545>;
+ qcom,leakage-energy-offset = <0>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 1893ae4..9b5aaac 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -70,7 +70,7 @@
reg = <28>;
qcom,heap-align = <0x1000>;
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
- qcom,memory-reservation-size = <0x2B4000>;
+ qcom,memory-reservation-size = <0x314000>;
};
};
};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dts b/arch/arm/boot/dts/msm8974-liquid.dts
index 5de2d43..bf4adaf 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dts
+++ b/arch/arm/boot/dts/msm8974-liquid.dts
@@ -22,6 +22,229 @@
serial@f991e000 {
status = "ok";
};
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ home {
+ label = "home";
+ gpios = <&pm8941_gpios 1 0x1>;
+ linux,input-type = <1>;
+ linux,code = <102>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_down {
+ label = "volume_down";
+ gpios = <&pm8941_gpios 2 0x1>;
+ linux,input-type = <1>;
+ linux,code = <114>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
};
+&pm8941_gpios {
+ gpio@c000 { /* GPIO 1 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+ gpio@c100 { /* GPIO 2 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-select = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+
+ gpio@d600 { /* GPIO 23 */
+ };
+
+ gpio@d700 { /* GPIO 24 */
+ };
+
+ gpio@d800 { /* GPIO 25 */
+ };
+
+ gpio@d900 { /* GPIO 26 */
+ };
+
+ gpio@da00 { /* GPIO 27 */
+ };
+
+ gpio@db00 { /* GPIO 28 */
+ };
+
+ gpio@dc00 { /* GPIO 29 */
+ qcom,pull = <0>; /* set to default pull */
+ qcom,master-en = <1>;
+ qcom,vin-sel = <2>; /* select 1.8 V source */
+ };
+
+ gpio@dd00 { /* GPIO 30 */
+ };
+
+ gpio@de00 { /* GPIO 31 */
+ };
+
+ gpio@df00 { /* GPIO 32 */
+ };
+
+ gpio@e000 { /* GPIO 33 */
+ };
+
+ gpio@e100 { /* GPIO 34 */
+ };
+
+ gpio@e200 { /* GPIO 35 */
+ };
+
+ gpio@e300 { /* GPIO 36 */
+ };
+};
+
+&pm8941_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* SPI_ETH config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* SPI_ETH_RST config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8841_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 344aa7f..ca98706 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -18,6 +18,8 @@
reg-names = "mdp_phys", "vbif_phys";
interrupts = <0 72 0>;
vdd-supply = <&gdsc_mdss>;
+ qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+ qcom,memory-reservation-size = <0x800000>; /* size 8MB */
};
mdss_dsi: qcom,mdss_dsi@fd922800 {
@@ -55,7 +57,7 @@
qcom,mdss_wb_panel {
compatible = "qcom,mdss_wb";
- qcom,mdss_pan_res = <640 480>;
+ qcom,mdss_pan_res = <1920 1080>;
qcom,mdss_pan_bpp = <24>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
index d3e0bc3..e0d6ad3 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -112,6 +112,7 @@
gpio_keys {
compatible = "gpio-keys";
+ input-name = "gpio-keys";
camera_snapshot {
label = "camera_snapshot";
@@ -167,3 +168,196 @@
interrupt-names = "core_irq", "bam_irq", "status_irq";
cd-gpios = <&msmgpio 62 0x1>;
};
+
+&pm8941_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-select = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-select = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+
+ gpio@d600 { /* GPIO 23 */
+ };
+
+ gpio@d700 { /* GPIO 24 */
+ };
+
+ gpio@d800 { /* GPIO 25 */
+ };
+
+ gpio@d900 { /* GPIO 26 */
+ };
+
+ gpio@da00 { /* GPIO 27 */
+ };
+
+ gpio@db00 { /* GPIO 28 */
+ };
+
+ gpio@dc00 { /* GPIO 29 */
+ qcom,pull = <0>; /* set to default pull */
+ qcom,master-en = <1>;
+ qcom,vin-sel = <2>; /* select 1.8 V source */
+ };
+
+ gpio@dd00 { /* GPIO 30 */
+ };
+
+ gpio@de00 { /* GPIO 31 */
+ };
+
+ gpio@df00 { /* GPIO 32 */
+ };
+
+ gpio@e000 { /* GPIO 33 */
+ };
+
+ gpio@e100 { /* GPIO 34 */
+ };
+
+ gpio@e200 { /* GPIO 35 */
+ };
+
+ gpio@e300 { /* GPIO 36 */
+ };
+};
+
+&pm8941_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* SPI_ETH config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ /* SPI_ETH_RST config */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,vin-sel = <2>; /* PM8941_S3 1.8V > 1.6V */
+ qcom,src-select = <0>; /* CONSTANT */
+ qcom,master-en = <1>; /* ENABLE MPP */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8841_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index da0e1e5..9770ecf 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -42,6 +42,15 @@
reg = <0xfd510000 0x4000>;
};
+ wcd9xxx_intc: wcd9xxx-irq {
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <72 0>;
+ interrupt-names = "cdc-int";
+ };
+
timer {
compatible = "qcom,msm-qtimer", "arm,armv7-timer";
interrupts = <1 2 0 1 3 0>;
@@ -239,6 +248,19 @@
qcom,bam-dma-res-pipes = <6>;
};
+ spi@f9966000 {
+ compatible = "qcom,spi-qup-v2";
+ cell-index = <7>;
+ reg = <0xf9966000 0x1000>;
+ interrupts = <0 104 0>;
+ spi-max-frequency = <19200000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&msmgpio 56 0>, /* CLK */
+ <&msmgpio 54 0>, /* MISO */
+ <&msmgpio 53 0>; /* MOSI */
+ cs-gpios = <&msmgpio 55 0>;
+ };
slim@fe12f000 {
cell-index = <1>;
@@ -255,6 +277,9 @@
compatible = "qcom,taiko-slim-pgd";
elemental-addr = [00 01 A0 00 17 02];
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28>;
+
qcom,cdc-reset-gpio = <&msmgpio 63 0>;
cdc-vdd-buck-supply = <&pm8941_s2>;
@@ -306,7 +331,6 @@
qcom,audio-routing =
"RX_BIAS", "MCLK",
"LDO_H", "MCLK",
- "HEADPHONE", "LDO_H",
"Ext Spk Bottom Pos", "LINEOUT1",
"Ext Spk Bottom Neg", "LINEOUT3",
"Ext Spk Top Pos", "LINEOUT2",
@@ -633,6 +657,7 @@
compatible = "qcom,pil-q6v5-lpass";
reg = <0xfe200000 0x00100>,
<0xfd485100 0x00010>;
+ reg-names = "qdsp6_base", "halt_base";
qcom,firmware-name = "adsp";
};
@@ -673,6 +698,10 @@
compatible = "qcom,msm-dai-fe";
};
+ qcom,msm-pcm-afe {
+ compatible = "qcom,msm-pcm-afe";
+ };
+
qcom,msm-dai-q6 {
compatible = "qcom,msm-dai-q6";
qcom,msm-dai-q6-sb-0-rx {
@@ -684,6 +713,36 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <16385>;
};
+
+ qcom,msm-dai-q6-bt-sco-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12288>;
+ };
+
+ qcom,msm-dai-q6-bt-sco-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12289>;
+ };
+
+ qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
};
qcom,msm-auxpcm {
@@ -714,10 +773,13 @@
qcom,msm-ocmem-audio {
compatible = "qcom,msm-ocmem-audio";
- qcom,msm-ocmem-audio-src-id = <11>;
- qcom,msm-ocmem-audio-dst-id = <604>;
- qcom,msm-ocmem-audio-ab = <32505856>;
- qcom,msm-ocmem-audio-ib = <32505856>;
+ qcom,msm_bus,name = "audio-ocmem";
+ qcom,msm_bus,num_cases = <2>;
+ qcom,msm_bus,active_only = <0>;
+ qcom,msm_bus,num_paths = <1>;
+ qcom,msm_bus,vectors =
+ <11 604 0 0>,
+ <11 604 32505856 32505856>;
};
qcom,mss@fc880000 {
@@ -727,6 +789,9 @@
<0xfc820000 0x020>,
<0xfc401680 0x004>,
<0xfc980008 0x004>;
+ reg-names = "qdsp6_base", "halt_base", "rmb_base",
+ "restart_reg", "clamp_reg";
+
vdd_mss-supply = <&pm8841_s3>;
qcom,firmware-name = "mba";
@@ -737,6 +802,7 @@
compatible = "qcom,pil-mba";
reg = <0xfc820000 0x0020>,
<0x0d1fc000 0x4000>;
+ reg-names = "rmb_base", "metadata_base";
qcom,firmware-name = "modem";
qcom,depends-on = "mba";
@@ -747,6 +813,7 @@
reg = <0xfb21b000 0x3000>,
<0xfc401700 0x4>,
<0xfd485300 0xc>;
+ reg-names = "pmu_base", "clk_base", "halt_base";
vdd_pronto_pll-supply = <&pm8941_l12>;
qcom,firmware-name = "wcnss";
@@ -831,6 +898,15 @@
qcom,qseecom@fe806000 {
compatible = "qcom,qseecom";
+ qcom,msm_bus,name = "qseecom-noc";
+ qcom,msm_bus,num_cases = <4>;
+ qcom,msm_bus,active_only = <0>;
+ qcom,msm_bus,num_paths = <1>;
+ qcom,msm_bus,vectors =
+ <55 512 0 0>,
+ <55 512 3936000000 393600000>,
+ <55 512 3936000000 393600000>,
+ <55 512 3936000000 393600000>;
};
qcom,wdt@f9017000 {
@@ -842,15 +918,16 @@
qcom,ipi-ping = <1>;
};
- qcom,tz-log@fe805720 {
+ qcom,tz-log@fc03000 {
compatible = "qcom,tz-log";
- reg = <0xfe805720 0x1000>;
+ reg = <0x0fc03000 0x1000>;
};
qcom,venus@fdce0000 {
compatible = "qcom,pil-venus";
reg = <0xfdce0000 0x4000>,
<0xfdc80208 0x8>;
+ reg-names = "wrapper_base", "vbif_base";
vdd-supply = <&gdsc_venus>;
qcom,firmware-name = "venus";
@@ -992,11 +1069,16 @@
reg = <0xfc834000 0x7000>;
interrupts = <0 29 1>;
};
+
+ qcom,msm-wdog-debug@fc401000 {
+ compatible = "qcom,msm-wdog-debug";
+ reg = <0xfc401000 0x1000>;
+ };
+
};
/include/ "msm-pm8x41-rpm-regulator.dtsi"
/include/ "msm-pm8841.dtsi"
/include/ "msm-pm8941.dtsi"
/include/ "msm8974-regulator.dtsi"
-/include/ "msm8974-gpio.dtsi"
/include/ "msm8974-clock.dtsi"
diff --git a/arch/arm/boot/dts/msm8974_pm.dtsi b/arch/arm/boot/dts/msm8974_pm.dtsi
index 8e3f4b8..b2f3fec 100644
--- a/arch/arm/boot/dts/msm8974_pm.dtsi
+++ b/arch/arm/boot/dts/msm8974_pm.dtsi
@@ -28,6 +28,8 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
+ 0b 00 42 1b 0f];
qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
10 0b 30 06 26 30 0f];
qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
@@ -49,6 +51,8 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
+ 0b 00 42 1b 0f];
qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
10 0b 30 06 26 30 0f];
qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
@@ -70,6 +74,8 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
+ 0b 00 42 1b 0f];
qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
10 0b 30 06 26 30 0f];
qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
@@ -91,6 +97,8 @@
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d0 c0 a0 90 03 d0 98 a2 c0
+ 0b 00 42 1b 0f];
qcom,saw2-spm-cmd-spc = [00 20 80 10 90 a0 b0 03 3b 98 a2 b0 82
10 0b 30 06 26 30 0f];
qcom,saw2-spm-cmd-pc = [00 20 80 10 90 a0 b0 07 3b 98 a2 b0 82
@@ -117,10 +125,9 @@
qcom,vctl-port = <0x0>;
qcom,phase-port = <0x1>;
qcom,saw2-spm-cmd-ret = [00 20 03 22 00 0f];
- qcom,saw2-spm-cmd-gdhs = [00 20 32 0b 42 07 44 22 50 02 32 50
- 0f];
- qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 0b 42 07 01 b0 12 44 a0
- 50 02 32 a0 50 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 20 32 42 07 44 22 50 02 32 50 0f];
+ qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
+ 50 02 32 50 0f];
};
qcom,lpm-resources {
@@ -131,6 +138,7 @@
qcom,lpm-resources@0 {
reg = <0x0>;
qcom,name = "vdd-dig";
+ qcom,resource-type = <0>;
qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x02>;
qcom,key = <0x6e726f63>; /* "corn" */
@@ -139,6 +147,7 @@
qcom,lpm-resources@1 {
reg = <0x1>;
qcom,name = "vdd-mem";
+ qcom,resource-type = <0>;
qcom,type = <0x62706d73>; /* "smpb" */
qcom,id = <0x01>;
qcom,key = <0x7675>; /* "uv" */
@@ -147,10 +156,17 @@
qcom,lpm-resources@2 {
reg = <0x2>;
qcom,name = "pxo";
+ qcom,resource-type = <0>;
qcom,type = <0x306b6c63>; /* "clk0" */
qcom,id = <0x00>;
qcom,key = <0x62616e45>; /* "Enab" */
};
+
+ qcom,lpm-resources@3 {
+ reg = <0x3>;
+ qcom,name = "l2";
+ qcom,resource-type = <1>;
+ };
};
qcom,lpm-levels {
@@ -175,6 +191,22 @@
qcom,lpm-level@1 {
reg = <0x1>;
+ qcom,mode = <4>; /* MSM_PM_SLEEP_MODE_RETENTION*/
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <5>; /* MAX */
+ qcom,vdd-dig-lower-bound = <3>; /* ACTIVE */
+ qcom,latency-us = <1500>;
+ qcom,ss-power = <200>;
+ qcom,energy-overhead = <576000>;
+ qcom,time-overhead = <2000>;
+ };
+
+
+ qcom,lpm-level@2 {
+ reg = <0x2>;
qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
qcom,l2 = <3>; /* ACTIVE */
@@ -188,8 +220,8 @@
qcom,time-overhead = <2000>;
};
- qcom,lpm-level@2 {
- reg = <0x2>;
+ qcom,lpm-level@3 {
+ reg = <0x3>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
qcom,l2 = <1>; /* GDHS */
@@ -203,8 +235,8 @@
qcom,time-overhead = <8500>;
};
- qcom,lpm-level@3 {
- reg = <0x3>;
+ qcom,lpm-level@4 {
+ reg = <0x4>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
qcom,l2 = <0>; /* OFF */
@@ -218,8 +250,8 @@
qcom,time-overhead = <9000>;
};
- qcom,lpm-level@4 {
- reg = <0x4>;
+ qcom,lpm-level@5 {
+ reg = <0x5>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <1>; /* ON */
qcom,l2 = <0>; /* OFF */
@@ -233,8 +265,8 @@
qcom,time-overhead = <10000>;
};
- qcom,lpm-level@5 {
- reg = <0x5>;
+ qcom,lpm-level@6 {
+ reg = <0x6>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <1>; /* GDHS */
@@ -248,8 +280,8 @@
qcom,time-overhead = <12000>;
};
- qcom,lpm-level@6 {
- reg = <0x6>;
+ qcom,lpm-level@7 {
+ reg = <0x7>;
qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
@@ -263,8 +295,8 @@
qcom,time-overhead = <18000>;
};
- qcom,lpm-level@7 {
- reg = <0x7>;
+ qcom,lpm-level@8 {
+ reg = <0x8>;
qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
@@ -278,8 +310,8 @@
qcom,time-overhead = <23500>;
};
- qcom,lpm-level@8 {
- reg = <0x8>;
+ qcom,lpm-level@9 {
+ reg = <0x9>;
qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
qcom,xo = <0>; /* OFF */
qcom,l2 = <0>; /* OFF */
@@ -385,8 +417,8 @@
<40 95>;
};
- qcom,pc-cntr@fe800000 {
+ qcom,pc-cntr@fe805664 {
compatible = "qcom,pc-cntr";
- reg = <0xfe800664 0x40>;
+ reg = <0xfe805664 0x40>;
};
};
diff --git a/arch/arm/boot/dts/msm9625-cdp.dts b/arch/arm/boot/dts/msm9625-cdp.dts
index 6733f59..aa1ec92 100644
--- a/arch/arm/boot/dts/msm9625-cdp.dts
+++ b/arch/arm/boot/dts/msm9625-cdp.dts
@@ -19,3 +19,44 @@
compatible = "qcom,msm9625-cdp", "qcom,msm9625";
qcom,msm-id = <134 1 0>;
};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+};
+
+&pm8019_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-ion.dtsi b/arch/arm/boot/dts/msm9625-ion.dtsi
new file mode 100644
index 0000000..8183264
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-ion.dtsi
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ qcom,ion {
+ compatible = "qcom,msm-ion";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ion-heap@30 { /* SYSTEM HEAP */
+ reg = <30>;
+ };
+
+ qcom,ion-heap@25 { /* IOMMU HEAP */
+ reg = <25>;
+ };
+
+ 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 = <0xAF000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-mtp.dts b/arch/arm/boot/dts/msm9625-mtp.dts
index 32185dc..3ec949f 100644
--- a/arch/arm/boot/dts/msm9625-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-mtp.dts
@@ -19,3 +19,44 @@
compatible = "qcom,msm9625-mtp", "qcom,msm9625";
qcom,msm-id = <134 8 0>;
};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+};
+
+&pm8019_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-regulator.dtsi b/arch/arm/boot/dts/msm9625-regulator.dtsi
new file mode 100644
index 0000000..1b5b03b
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-regulator.dtsi
@@ -0,0 +1,252 @@
+/* Copyright (c) 2012, 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.
+ */
+
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ status = "okay";
+ pm8019_s1: regulator-s1 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,init-voltage = <1050000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa2 {
+ status = "okay";
+ qcom,allow-atomic = <1>;
+ pm8019_s2: regulator-s2 {
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ qcom,init-voltage = <1250000>;
+ qcom,init-current = <100>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ status = "okay";
+ pm8019_s3: regulator-s3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,init-voltage = <1100000>;
+ qcom,init-current = <100>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ status = "okay";
+ };
+ pm8019_s3_ao: regulator-s3-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8019_s3_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1100000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ status = "okay";
+ pm8019_s4: regulator-s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2075000>;
+ qcom,init-voltage = <2075000>;
+ qcom,init-current = <100>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pm8019_l1: regulator-l1 {
+ parent-supply = <&pm8019_s2>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pm8019_l2: regulator-l2 {
+ parent-supply = <&pm8019_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pm8019_l3: regulator-l3 {
+ parent-supply = <&pm8019_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa4 {
+ status = "okay";
+ pm8019_l4: regulator-l4 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ qcom,init-voltage = <3075000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pm8019_l5: regulator-l5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pm8019_l6: regulator-l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pm8019_l7: regulator-l7 {
+ parent-supply = <&pm8019_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pm8019_l8: regulator-l8 {
+ parent-supply = <&pm8019_s4>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,init-voltage = <2050000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pm8019_l9: regulator-l9 {
+ parent-supply = <&pm8019_s2>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1200000>;
+ qcom,init-current = <10>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pm8019_l10: regulator-l10 {
+ parent-supply = <&pm8019_s3>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1050000>;
+ status = "okay";
+ };
+ pm8019_l10_corner: regulator-l10-corner {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8019_l10_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ status = "okay";
+ qcom,consumer-supplies = "vdd_dig", "";
+ };
+ pm8019_l10_corner_ao: regulator-l10-corner-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8019_l10_corner_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,use-voltage-corner;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ status = "okay";
+ pm8019_l11: regulator-l11 {
+ parent-supply = <&pm8019_s4>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-current = <10>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ status = "okay";
+ pm8019_l12: regulator-l12 {
+ parent-supply = <&pm8019_s3>;
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1050000>;
+ status = "okay";
+ };
+ pm8019_l12_ao: regulator-l12-ao {
+ compatible = "qcom,rpm-regulator-smd";
+ regulator-name = "8019_l12_ao";
+ qcom,set = <1>;
+ parent-supply = <&pm8019_s3_ao>;
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1050000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ status = "okay";
+ pm8019_l13: regulator-l13 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa14 {
+ status = "okay";
+ pm8019_l14: regulator-l14 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ qcom,init-voltage = <2700000>;
+ status = "okay";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-rumi.dts b/arch/arm/boot/dts/msm9625-rumi.dts
index e4fa000..dadb3f7 100644
--- a/arch/arm/boot/dts/msm9625-rumi.dts
+++ b/arch/arm/boot/dts/msm9625-rumi.dts
@@ -18,4 +18,9 @@
model = "Qualcomm MSM 9625 RUMI";
compatible = "qcom,msm9625-rumi", "qcom,msm9625";
qcom,msm-id = <134 15 0>;
+
+ chosen{
+ bootargs = "root=/dev/ram rw init=/init console=ttyHSL0,115200n8 initrd=0x00000000,0x00000000 mem=29M@0x00200000 mem=10M@0x07600000";
+
+ };
};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 8ad3b66..a8a2bf1 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -11,6 +11,7 @@
*/
/include/ "skeleton.dtsi"
+/include/ "msm9625-ion.dtsi"
/ {
model = "Qualcomm MSM 9625";
@@ -48,7 +49,7 @@
reg = <0xF9021000 0x1000>;
interrupts = <0 7 0>;
irq-is-not-percpu;
- clock-frequency = <5000000>;
+ clock-frequency = <19200000>;
};
qcom,sps@f9980000 {
@@ -66,6 +67,26 @@
interrupts = <0 109 0>;
};
+ usb@f9a55000 {
+ compatible = "qcom,hsusb-otg";
+ reg = <0xf9a55000 0x400>;
+ interrupts = <0 134 0 0 140 0>;
+ interrupt-names = "core_irq", "async_irq";
+ HSUSB_VDDCX-supply = <&pm8019_l12>;
+ HSUSB_1p8-supply = <&pm8019_l2>;
+ HSUSB_3p3-supply = <&pm8019_l4>;
+
+ qcom,hsusb-otg-phy-type = <2>;
+ qcom,hsusb-otg-mode = <1>;
+ qcom,hsusb-otg-otg-control = <1>;
+ qcom,hsusb-otg-disable-reset;
+ };
+
+ android_usb@fc42b0c8 {
+ compatible = "qcom,android-usb";
+ reg = <0xfc42b0c8 0xc8>;
+ };
+
qcom,nand@f9ac0000 {
compatible = "qcom,msm-nand";
reg = <0xf9ac0000 0x1000>,
@@ -106,4 +127,41 @@
qcom,pet-time = <10000>;
qcom,ipi-ping = <0>;
};
+
+ rpm_bus: qcom,rpm-smd {
+ compatible = "qcom,rpm-smd";
+ rpm-channel-name = "rpm_requests";
+ rpm-channel-type = <15>; /* SMD_APPS_RPM */
+ };
+
+ spmi_bus: qcom,spmi@fc4c0000 {
+ cell-index = <0>;
+ compatible = "qcom,spmi-pmic-arb";
+ reg = <0xfc4cf000 0x1000>,
+ <0Xfc4cb000 0x1000>;
+ /* 190,ee0_krait_hlos_spmi_periph_irq */
+ /* 187,channel_0_krait_hlos_trans_done_irq */
+ interrupts = <0 190 0 0 187 0>;
+ qcom,not-wakeup;
+ qcom,pmic-arb-ee = <0>;
+ qcom,pmic-arb-channel = <0>;
+ qcom,pmic-arb-ppid-map = <0x02400000>, /* TEMP_ALARM */
+ <0x03100001>, /* VADC1_USR */
+ <0x06100002>, /* RTC_ALARM */
+ <0x06200003>, /* RTC_TIMER */
+ <0x0a000004>, /* MPP1 */
+ <0x0a100005>, /* MPP2 */
+ <0x0a200006>, /* MPP3 */
+ <0x0a300007>, /* MPP4 */
+ <0x0a400008>, /* MPP5 */
+ <0x0a500009>, /* MPP6 */
+ <0x0c20000a>, /* GPIO3 */
+ <0x0c30000b>, /* GPIO4 */
+ <0x0c50000c>, /* GPIO6 */
+ <0x0080000d>; /* PON */
+ };
};
+
+/include/ "msm-pm8019-rpm-regulator.dtsi"
+/include/ "msm-pm8019.dtsi"
+/include/ "msm9625-regulator.dtsi"
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 9dd4347..6b8a374 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -1167,41 +1167,35 @@
/*
* Configure the GIC after we come out of power collapse.
* This function will configure some of the GIC registers so as to prepare the
- * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
- * core1 out of GDFS.
+ * secondary cores to receive an SPI(ACSR_MP_CORE_IPC1/IPC2/IPC3, 40/92/93),
+ * which will bring cores out of GDFS.
*/
-void core1_gic_configure_and_raise(void)
+void gic_configure_and_raise(unsigned int irq, unsigned int cpu)
{
struct gic_chip_data *gic = &gic_data[0];
+ struct irq_data *d = irq_get_irq_data(irq);
void __iomem *base = gic_data_dist_base(gic);
- unsigned int value = 0;
+ unsigned int value = 0, byte_offset, offset, bit;
unsigned long flags;
+ offset = ((gic_irq(d) / 32) * 4);
+ bit = BIT(gic_irq(d) % 32);
+
raw_spin_lock_irqsave(&irq_controller_lock, flags);
- value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
- value |= BIT(8);
- __raw_writel(value, base + GIC_DIST_ACTIVE_BIT + 0x4);
+ value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + offset);
+ __raw_writel(value | bit, base + GIC_DIST_ACTIVE_BIT + offset);
mb();
- value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
- value |= BIT(13);
- __raw_writel(value, base + GIC_DIST_TARGET + 0x24);
+ value = __raw_readl(base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
+ byte_offset = (gic_irq(d) % 4) * 8;
+ value |= 1 << (cpu + byte_offset);
+ __raw_writel(value, base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
mb();
- value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
- value |= BIT(1);
- __raw_writel(value, base + GIC_DIST_TARGET + 0x28);
+ value = __raw_readl(base + GIC_DIST_ENABLE_SET + offset);
+ __raw_writel(value | bit, base + GIC_DIST_ENABLE_SET + offset);
mb();
- value = __raw_readl(base + GIC_DIST_ENABLE_SET + 0x4);
- value |= BIT(8);
- __raw_writel(value, base + GIC_DIST_ENABLE_SET + 0x4);
- mb();
-
- value = __raw_readl(base + GIC_DIST_PENDING_SET + 0x4);
- value |= BIT(8);
- __raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
- mb();
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
}
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 4ba55de..93e84e9 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -39,6 +39,9 @@
# CONFIG_QSD_AUDIO is not set
# CONFIG_SURF_FFA_GPIO_KEYPAD is not set
CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_VMSPLIT_2G=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index ad1b6a6..c45063f 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -38,6 +38,9 @@
# CONFIG_QSD_AUDIO is not set
# CONFIG_SURF_FFA_GPIO_KEYPAD is not set
CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_VMSPLIT_2G=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 7f10641..9a0bfba 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -55,6 +55,9 @@
CONFIG_MSM_MULTIMEDIA_USE_ION=y
CONFIG_MSM_CPR=y
CONFIG_MSM_VP_REGULATOR=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_ARM_THUMBEE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 0e0653f..60a2d72 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -57,6 +57,9 @@
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_CPR=y
CONFIG_MSM_VP_REGULATOR=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_ARM_THUMBEE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 188ee03..401654d 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -44,6 +44,9 @@
CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index 5c5a152..0e066d9 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -44,6 +44,9 @@
CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
CONFIG_MSM_MULTIMEDIA_USE_ION=y
+CONFIG_MSM_RPC_PMIC=y
+CONFIG_MSM_RPC_USB=y
+CONFIG_MSM_RPC_PMAPP=y
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm8910_defconfig b/arch/arm/configs/msm8910_defconfig
new file mode 100644
index 0000000..ebcc6f5
--- /dev/null
+++ b/arch/arm/configs/msm8910_defconfig
@@ -0,0 +1,100 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=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_FAIR_GROUP_SCHED is not set
+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_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_PARTITION_ADVANCED=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8910=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_DIRECT_SCLK_ACCESS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_USE_OF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_ANDROID_PMEM is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index afe528d..6a6bfda 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -71,7 +71,8 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_AVS_HW=y
# CONFIG_MSM_HW3D is not set
-CONFIG_MSM_PIL_QDSP6V4=y
+CONFIG_MSM_PIL_LPASS_QDSP6V4=y
+CONFIG_MSM_PIL_MODEM_QDSP6V4=y
CONFIG_MSM_PIL_RIVA=y
CONFIG_MSM_PIL_TZAPPS=y
CONFIG_MSM_PIL_DSPS=y
@@ -347,6 +348,7 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_MSM_WFD=y
CONFIG_USER_RC_INPUT=y
CONFIG_IR_GPIO_CIR=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
@@ -505,3 +507,4 @@
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CONTROL_TRACE=m
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 4c9383d..cf2dd23 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -70,7 +70,8 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_AVS_HW=y
# CONFIG_MSM_HW3D is not set
-CONFIG_MSM_PIL_QDSP6V4=y
+CONFIG_MSM_PIL_LPASS_QDSP6V4=y
+CONFIG_MSM_PIL_MODEM_QDSP6V4=y
CONFIG_MSM_PIL_RIVA=y
CONFIG_MSM_PIL_TZAPPS=y
CONFIG_MSM_PIL_DSPS=y
@@ -351,6 +352,7 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_MSM_WFD=y
CONFIG_USER_RC_INPUT=y
CONFIG_IR_GPIO_CIR=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
@@ -513,6 +515,7 @@
CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_PID_IN_CONTEXTIDR=y
@@ -522,3 +525,4 @@
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CONTROL_TRACE=m
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 392e062..2f1833e 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -57,6 +57,7 @@
CONFIG_MSM_PIL_PRONTO=y
CONFIG_MSM_MODEM_SSR_8974=y
CONFIG_MSM_ADSP_SSR_8974=y
+CONFIG_MSM_WCNSS_SSR_8974=y
CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_BUS_SCALING=y
@@ -297,6 +298,7 @@
CONFIG_MSM_CSI2_REGISTER=y
CONFIG_MSM_ISPIF=y
CONFIG_S5K3L1YX=y
+CONFIG_MT9M114=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
@@ -369,6 +371,7 @@
CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU=y
CONFIG_MSM_QDSS=y
+CONFIG_MSM_QDSS_ETM_PCSAVE_DEFAULT_ENABLE=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -399,3 +402,4 @@
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 7e3aad7..1230fbe 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -49,6 +49,7 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_HW3D is not set
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_MBA=y
@@ -56,6 +57,7 @@
CONFIG_MSM_PIL_PRONTO=y
CONFIG_MSM_MODEM_SSR_8974=y
CONFIG_MSM_ADSP_SSR_8974=y
+CONFIG_MSM_WCNSS_SSR_8974=y
CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_BUS_SCALING=y
@@ -71,8 +73,9 @@
CONFIG_MSM_L1_ERR_PANIC=y
CONFIG_MSM_L1_ERR_LOG=y
CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=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_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -272,6 +275,7 @@
CONFIG_GPIO_QPNP_PIN_DEBUG=y
CONFIG_POWER_SUPPLY=y
# CONFIG_BATTERY_MSM is not set
+CONFIG_QPNP_BMS=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_SENSORS_QPNP_ADC_CURRENT=y
CONFIG_THERMAL=y
@@ -287,7 +291,7 @@
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MSM_CAMERA_V4L2=y
-CONFIG_MSM_WFD=y
+CONFIG_MT9M114=y
CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
@@ -299,6 +303,7 @@
CONFIG_MSM_CSI2_REGISTER=y
CONFIG_MSM_ISPIF=y
CONFIG_S5K3L1YX=y
+CONFIG_MSM_WFD=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
@@ -371,6 +376,7 @@
CONFIG_QPNP_CLKDIV=y
CONFIG_MSM_IOMMU=y
CONFIG_MSM_QDSS=y
+CONFIG_MSM_QDSS_ETM_PCSAVE_DEFAULT_ENABLE=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -392,7 +398,6 @@
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_ATOMIC_SLEEP=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
@@ -404,6 +409,7 @@
CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_PID_IN_CONTEXTIDR=y
@@ -415,3 +421,4 @@
CONFIG_CRYPTO_DEV_QCE=m
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 2cc801e..7c3d5b0 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -49,6 +49,8 @@
CONFIG_MSM_SUBSYSTEM_RESTART=y
# CONFIG_MSM_SYSMON_COMM is not set
CONFIG_MSM_MODEM_8960=y
+CONFIG_MSM_PIL_LPASS_QDSP6V4=y
+CONFIG_MSM_PIL_MODEM_QDSP6V4=y
CONFIG_MSM_LPASS_8960=y
CONFIG_MSM_RPM_LOG=y
CONFIG_MSM_RPM_STATS_LOG=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 0057062..b439ec6 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -35,6 +35,9 @@
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_RPM_REGULATOR_SMD=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_NO_HZ=y
@@ -45,24 +48,23 @@
CONFIG_HIGHMEM=y
CONFIG_VMALLOC_RESERVE=0x19000000
CONFIG_USE_OF=y
-CONFIG_ARM_APPENDED_DTB=y
-CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_SUSPEND is not set
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_OF_PARTS=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_MTD_MSM_NAND is not set
-CONFIG_MTD_MSM_QPIC_NAND=y
+CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IPV6=y
# CONFIG_WIRELESS is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_MTD_MSM_NAND is not set
+CONFIG_MTD_MSM_QPIC_NAND=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
# CONFIG_ANDROID_PMEM is not set
@@ -89,18 +91,37 @@
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_SPI=y
CONFIG_SPI_QUP=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_HWMON is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
CONFIG_SPS=y
+CONFIG_USB_BAM=y
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_POWER_ON=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_YAFFS_FS=y
@@ -134,3 +155,12 @@
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_MMC_UNSAFE_RESUME=y
diff --git a/arch/arm/mach-msm/cp14.h b/arch/arm/include/asm/hardware/cp14.h
similarity index 99%
rename from arch/arm/mach-msm/cp14.h
rename to arch/arm/include/asm/hardware/cp14.h
index d640412..8acf0c7 100644
--- a/arch/arm/mach-msm/cp14.h
+++ b/arch/arm/include/asm/hardware/cp14.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*/
-#ifndef _ARCH_ARM_MACH_MSM_CP14_H_
-#define _ARCH_ARM_MACH_MSM_CP14_H_
+#ifndef __ASM_HARDWARE_CP14_H
+#define __ASM_HARDWARE_CP14_H
#include <linux/types.h>
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index ad12bcd..72c3c27 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -62,7 +62,7 @@
void msm_gic_save(void);
void msm_gic_restore(void);
-void core1_gic_configure_and_raise(void);
+void gic_configure_and_raise(unsigned int irq, unsigned int cpu);
#endif
#endif
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index ff2c0ad..1692129 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -216,6 +216,20 @@
return core_has_mismatch_brps() ? brps - 1 : brps;
}
+/* Determine if halting mode is enabled */
+static int halting_mode_enabled(void)
+{
+ u32 dscr;
+
+ ARM_DBG_READ(c1, 0, dscr);
+
+ if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN,
+ "halting debug mode enabled. "
+ "Unable to access hardware resources.\n"))
+ return -EPERM;
+ return 0;
+}
+
/*
* In order to access the breakpoint/watchpoint control registers,
* we must be running in debug monitor mode. Unfortunately, we can
@@ -225,16 +239,14 @@
static int enable_monitor_mode(void)
{
u32 dscr;
- int ret = 0;
+ int ret;
ARM_DBG_READ(c1, 0, dscr);
/* Ensure that halting mode is disabled. */
- if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN,
- "halting debug mode enabled. Unable to access hardware resources.\n")) {
- ret = -EPERM;
+ ret = halting_mode_enabled();
+ if (ret)
goto out;
- }
/* If monitor mode is already enabled, just return. */
if (dscr & ARM_DSCR_MDBGEN)
@@ -853,18 +865,6 @@
return ret;
}
-static void reset_brps_reserved_reg(int n)
-{
- int i;
-
- /* we must also reset any reserved registers. */
- for (i = 0; i < n; ++i) {
- write_wb_reg(ARM_BASE_BCR + i, 0UL);
- write_wb_reg(ARM_BASE_BVR + i, 0UL);
- }
-
-}
-
/*
* One-time initialisation.
*/
@@ -947,19 +947,21 @@
isb();
reset_regs:
- if (enable_monitor_mode())
+ if (halting_mode_enabled())
return;
-#ifdef CONFIG_HAVE_HW_BRKPT_RESERVED_RW_ACCESS
- reset_brps_reserved_reg(core_num_brps);
-#else
- reset_brps_reserved_reg(core_num_brps + core_num_reserved_brps);
-#endif
+ /* We must also reset any reserved registers. */
+ raw_num_brps = get_num_brp_resources();
+ for (i = 0; i < raw_num_brps; ++i) {
+ write_wb_reg(ARM_BASE_BCR + i, 0UL);
+ write_wb_reg(ARM_BASE_BVR + i, 0UL);
+ }
for (i = 0; i < core_num_wrps; ++i) {
write_wb_reg(ARM_BASE_WCR + i, 0UL);
write_wb_reg(ARM_BASE_WVR + i, 0UL);
}
+ enable_monitor_mode();
}
static int __cpuinit dbg_reset_notify(struct notifier_block *self,
diff --git a/arch/arm/kernel/perf_event_msm.c b/arch/arm/kernel/perf_event_msm.c
index 90c9c9e..8f58adf 100644
--- a/arch/arm/kernel/perf_event_msm.c
+++ b/arch/arm/kernel/perf_event_msm.c
@@ -709,8 +709,6 @@
static struct arm_pmu scorpion_pmu = {
.handle_irq = armv7pmu_handle_irq,
- .request_pmu_irq = msm_request_irq,
- .free_pmu_irq = msm_free_irq,
.enable = scorpion_pmu_enable_event,
.disable = scorpion_pmu_disable_event,
.read_counter = armv7pmu_read_counter,
@@ -731,6 +729,9 @@
scorpion_pmu.name = "ARMv7 Scorpion";
scorpion_pmu.num_events = armv7_read_num_pmnc_events();
scorpion_pmu.pmu.attr_groups = msm_l1_pmu_attr_grps;
+ /* Unicore can't use the percpu IRQ API. */
+ scorpion_pmu.request_pmu_irq = armpmu_generic_request_irq;
+ scorpion_pmu.free_pmu_irq = armpmu_generic_free_irq;
scorpion_clear_pmuregs();
return &scorpion_pmu;
}
@@ -741,6 +742,8 @@
scorpion_pmu.name = "ARMv7 Scorpion-MP";
scorpion_pmu.num_events = armv7_read_num_pmnc_events();
scorpion_pmu.pmu.attr_groups = msm_l1_pmu_attr_grps;
+ scorpion_pmu.request_pmu_irq = msm_request_irq;
+ scorpion_pmu.free_pmu_irq = msm_free_irq;
scorpion_clear_pmuregs();
return &scorpion_pmu;
}
diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
index 8d8f47a..eec614b 100644
--- a/arch/arm/kernel/perf_event_msm_krait.c
+++ b/arch/arm/kernel/perf_event_msm_krait.c
@@ -540,8 +540,8 @@
int err = 0;
int cpu;
- err = request_percpu_irq(irq, *handle_irq, "krait-l1-armpmu",
- &cpu_hw_events);
+ err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
+ &cpu_hw_events);
if (!err) {
for_each_cpu(cpu, cpu_online_mask) {
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index c9b786c..cdc435c 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -315,6 +315,7 @@
select GIC_SECURE
select ARCH_MSM_CORTEX_A5
select CPU_V7
+ select MIGHT_HAVE_CACHE_L2X0
select GPIO_MSM_V2
select MSM_GPIOMUX
select MSM_RPM
@@ -355,8 +356,31 @@
select MSM_SMP
select CPU_V7
select MSM_GPIOMUX
+ select MSM_RPM_SMD
+ select MSM_NATIVE_RESTART
+ 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
+ select SPARSE_IRQ
+ select MSM_MULTIMEDIA_USE_ION
+
+config ARCH_MSM8910
+ bool "MSM8910"
+ select ARM_GIC
+ select GIC_SECURE
+ select SMP
+ select ARCH_MSM_CORTEXMP
+ select CPU_V7
+ select MSM_SCM if SMP
+ select MAY_HAVE_SPARSE_IRQ
+ select SPARSE_IRQ
+ select MULTI_IRQ_HANDLER
+ select GPIO_MSM_V3
+ select MSM_GPIOMUX
endmenu
choice
@@ -410,7 +434,6 @@
select HAVE_ARCH_HAS_CURRENT_TIMER
select MSM_JTAG if MSM_QDSS
bool
- select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
config ARCH_MSM_CORTEXMP
select MSM_SMP
@@ -424,7 +447,6 @@
config ARCH_MSM_CORTEX_A5
bool
- select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
config ARCH_MSM7X27A
bool
@@ -926,8 +948,9 @@
default "0x00000000" if ARCH_MSM8974
default "0x00000000" if ARCH_MPQ8092
default "0x00000000" if ARCH_MSM8226
+ default "0x00000000" if ARCH_MSM8910
default "0x10000000" if ARCH_FSM9XXX
- default "0x20200000" if ARCH_MSM9625
+ default "0x00200000" if ARCH_MSM9625
default "0x00200000" if !MSM_STACKED_MEMORY
default "0x00000000" if ARCH_QSD8X50 && MSM_SOC_REV_A
default "0x20000000" if ARCH_QSD8X50
@@ -1903,24 +1926,36 @@
config MSM_PIL_MODEM
tristate "Modem (ARM11) Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down ARM11 Modem processors.
config MSM_PIL_QDSP6V3
tristate "QDSP6v3 (Hexagon) Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down QDSP6v3 processors (hexagon).
The QDSP6 is a low power DSP used in audio software applications.
-config MSM_PIL_QDSP6V4
- tristate "QDSP6v4 (Hexagon) Boot Support"
- depends on MSM_PIL
+config MSM_PIL_LPASS_QDSP6V4
+ tristate "LPASS QDSP6v4 (Hexagon) Boot Support"
+ depends on MSM_SUBSYSTEM_RESTART
help
- Support for booting and shutting down QDSP6v4 processors (hexagon).
- The QDSP6 is a low power DSP used in audio, modem firmware, and modem
- software applications.
+ Support for booting and shutting down QDSP6v4 processors (hexagon)
+ in low power audio subsystems. If you would like to record or
+ play audio then say Y here.
+
+ If unsure, say N.
+
+config MSM_PIL_MODEM_QDSP6V4
+ tristate "Modem QDSP6v4 (Hexagon) Boot Support"
+ depends on MSM_SUBSYSTEM_RESTART
+ help
+ Support for booting and shutting down QDSP6v4 processors (hexagon)
+ in modem subsystems. If you would like to make or receive phone
+ calls then say Y here.
+
+ If unsure, say N.
config MSM_PIL_LPASS_QDSP6V5
tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
@@ -1945,7 +1980,7 @@
config MSM_PIL_RIVA
tristate "RIVA (WCNSS) Boot Support"
- depends on MSM_PIL
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down the RIVA processor (WCNSS).
Riva is the wireless subsystem processor used in bluetooth, wireless
@@ -1984,8 +2019,8 @@
Venus is the Video subsystem processor used for video codecs.
config MSM_PIL_GSS
- tristate "GSS (Coretx A5) Boot Support"
- depends on MSM_PIL
+ tristate "GSS (Cortex A5) Boot Support"
+ depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
help
Support for booting and shutting down Cortex A5 processors which run
GPS subsystem firmware.
@@ -2002,38 +2037,6 @@
bool "Secure Channel Manager (SCM) support"
default n
-config MSM_MODEM_8960
- bool "MSM 8960 Modem driver"
- depends on (ARCH_MSM8960 || ARCH_MSM9615)
- help
- This option enables the modem driver for the MSM8960 and MSM9615, which monitors
- modem hardware watchdog interrupt lines and plugs into the subsystem
- restart and PIL drivers. For MSM9615, it only supports a full chip reset.
-
-config MSM_LPASS_8960
- tristate "MSM 8960 Lpass driver"
- depends on (ARCH_MSM8960 || ARCH_MSM9615)
- help
- This option enables the lpass driver for the MSM8960 and MSM9615. This monitors
- lpass hardware watchdog interrupt lines and plugs into the subsystem
- restart and PIL drivers. For MSM9615, it only supports a full chip reset.
-
-config MSM_WCNSS_SSR_8960
- tristate "MSM 8960 WCNSS restart module"
- depends on (ARCH_MSM8960)
- help
- This option enables the WCNSS restart module for MSM8960, which
- monitors WCNSS hardware watchdog interrupt lines and plugs WCNSS
- into the subsystem restart framework.
-
-config MSM_GSS_SSR_8064
- bool "MSM 8064 GSS restart driver"
- depends on (ARCH_APQ8064)
- help
- This option enables the gps subsystem restart driver for APQ8064, which monitors
- gss hardware watchdog interrupt lines and plugs into the subsystem
- restart and PIL drivers.
-
config MSM_MODEM_SSR_8974
bool "MSM 8974 Modem restart driver"
depends on (ARCH_MSM8974)
@@ -2052,6 +2055,15 @@
restarts the adsp or the 8974 when the adsp encounters a fatal error,
depending on the restart level selected in the subsystem restart driver.
+config MSM_WCNSS_SSR_8974
+ tristate "MSM 8974 WCNSS restart module"
+ depends on (ARCH_MSM8974)
+ help
+ This option enables the WCNSS restart module for MSM8974. It monitors
+ WCNSS SMSM status bits and WCNSS hardware watchdog interrupt line; and
+ depending on the restart level, it will restart WCNSS when a fatal error
+ occurs at WCNSS.
+
config SCORPION_Uni_45nm_BUG
bool "Scorpion Uni 45nm(SC45U): Workaround for ICIMVAU and BPIMVA"
depends on ARCH_MSM7X30 || (ARCH_QSD8X50 && MSM_SOC_REV_A)
@@ -2607,4 +2619,39 @@
can be read and written to send character data to the sysmon port of
the modem over USB.
+config MSM_RPC_PMIC
+ tristate "MSM RPC PMIC driver"
+ depends on MSM_ONCRPCROUTER
+ help
+ This driver supports the PMIC functionality over RPC for those MSM's
+ which do not have a direct access to PMIC. It supports ability to
+ configure MPP, GPIO and all the other supported peripherals of the
+ PMIC.
+
+config MSM_RPC_USB
+ tristate "MSM RPC USB driver"
+ depends on MSM_ONCRPCROUTER
+ help
+ This driver supports the USB configuration support over the RPC
+ interface. It support the HS USB module connected to the MSM
+ and FS USB which is connected over the PMIC. This support is
+ required for MSMs on which the APPS does not have a direct access
+ to the PMIC.
+
+config MSM_RPC_PMAPP
+ tristate "MSM RPC PMIC APP driver"
+ depends on MSM_ONCRPCROUTER
+ help
+ This driver supports the configuration of various PMIC APP modules
+ such as display backlight, vreg pin-ctrl, smps clock over the RPC
+ interface. This support is required for MSMs on which the APPS
+ does not have a direct access to the PMIC.
+
+config MSM_ENABLE_WDOG_DEBUG_CONTROL
+ bool "MSM Watchdog driver to disable debug Image"
+ help
+ This driver supports the configuration of the GCC_WDOG_DEBUG register
+ used to control debug image.
+ This support is currently required for MSM8974 to disable debug image
+ on PS HOLD reset
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d8e625a..e6c6ca6 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -65,12 +65,15 @@
$(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_SCM) += scm.o scm-boot.o
obj-$(CONFIG_MSM_SECURE_IO) += scm-io.o
obj-$(CONFIG_MSM_PIL) += peripheral-loader.o
obj-$(CONFIG_MSM_PIL) += scm-pas.o
obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
-obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
+obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V4) += pil-q6v4.o pil-q6v4-lpass.o
+obj-$(CONFIG_MSM_PIL_MODEM_QDSP6V4) += pil-q6v4.o pil-q6v4-mss.o
obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V5) += pil-q6v5.o pil-q6v5-lpass.o
obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-q6v5-mss.o
obj-$(CONFIG_MSM_PIL_MBA) += pil-mba.o
@@ -96,22 +99,7 @@
ifdef CONFIG_DEBUG_FS
obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging_debug.o
endif
-obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o
obj-y += socinfo.o
-ifndef CONFIG_ARCH_MSM9615
-ifndef CONFIG_ARCH_APQ8064
-ifndef CONFIG_ARCH_MSM8960
-ifndef CONFIG_ARCH_MSM8X60
-ifndef CONFIG_ARCH_MSM8974
-ifndef CONFIG_ARCH_MPQ8092
- obj-$(CONFIG_MSM_SMD) += pmic.o
- obj-$(CONFIG_MSM_ONCRPCROUTER) += rpc_hsusb.o rpc_pmapp.o rpc_fsusb.o
-endif
-endif
-endif
-endif
-endif
-endif
ifndef CONFIG_ARCH_MSM8960
ifndef CONFIG_ARCH_MSM8X60
ifndef CONFIG_ARCH_APQ8064
@@ -119,6 +107,7 @@
ifndef CONFIG_ARCH_MSM8226
ifndef CONFIG_ARCH_MSM9625
ifndef CONFIG_ARCH_MPQ8092
+ifndef CONFIG_ARCH_MSM8910
obj-y += nand_partitions.o
endif
endif
@@ -127,6 +116,7 @@
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
@@ -208,21 +198,18 @@
obj-y += subsystem_notif.o
obj-y += subsystem_restart.o
obj-y += ramdump.o
- obj-$(CONFIG_ARCH_MSM8X60) += modem-8660.o lpass-8660.o
endif
obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
-obj-$(CONFIG_MSM_MODEM_8960) += modem-8960.o
obj-$(CONFIG_MSM_MODEM_SSR_8974) += modem-ssr-8974.o
-obj-$(CONFIG_MSM_LPASS_8960) += lpass-8960.o
obj-$(CONFIG_MSM_ADSP_SSR_8974) += adsp-8974.o
-obj-$(CONFIG_MSM_WCNSS_SSR_8960) += wcnss-ssr-8960.o
-obj-$(CONFIG_MSM_GSS_SSR_8064) += gss-8064.o
+obj-$(CONFIG_MSM_WCNSS_SSR_8974) += wcnss-ssr-8974.o
ifdef CONFIG_CPU_IDLE
obj-$(CONFIG_ARCH_APQ8064) += cpuidle.o
obj-$(CONFIG_ARCH_MSM8960) += cpuidle.o
obj-$(CONFIG_ARCH_MSM8X60) += cpuidle.o
obj-$(CONFIG_ARCH_MSM9615) += cpuidle.o
+ obj-$(CONFIG_ARCH_MSM9625) += cpuidle.o
obj-$(CONFIG_ARCH_MSM8974) += cpuidle.o
endif
@@ -288,7 +275,7 @@
obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
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
+obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.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
@@ -305,6 +292,7 @@
obj-$(CONFIG_ARCH_MSM8930) += acpuclock-8930.o acpuclock-8627.o acpuclock-8930aa.o
obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
+obj-$(CONFIG_ARCH_MSM8910) += board-8910.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
@@ -331,6 +319,7 @@
endif
ifdef CONFIG_MSM_RPM_SMD
obj-$(CONFIG_ARCH_MSM8974) += lpm_levels.o lpm_resources.o
+ obj-$(CONFIG_ARCH_MSM9625) += lpm_levels.o lpm_resources.o
endif
obj-$(CONFIG_MSM_MPM_OF) += mpm-of.o
obj-$(CONFIG_MSM_MPM) += mpm.o
@@ -362,9 +351,10 @@
obj-$(CONFIG_ARCH_MSM9625) += 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_MSM8910) += 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_dcvs_idle.o
+obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_mpdecision.o
obj-$(CONFIG_MSM_RUN_QUEUE_STATS) += msm_rq_stats.o
obj-$(CONFIG_MSM_SHOW_RESUME_IRQ) += msm_show_resume_irq.o
obj-$(CONFIG_BT_MSM_PINTEST) += btpintest.o
@@ -393,6 +383,11 @@
obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o
obj-$(CONFIG_MSM_CPR) += msm_cpr.o
obj-$(CONFIG_MSM_VP_REGULATOR) += msm_vp.o
+obj-$(CONFIG_MSM_RPC_PMIC) += pmic.o
+obj-$(CONFIG_MSM_RPC_USB) += rpc_hsusb.o rpc_fsusb.o
+obj-$(CONFIG_MSM_RPC_PMAPP) += rpc_pmapp.o
+
+obj-$(CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL) += wdog_debug.o
ifdef CONFIG_MSM_CPR
obj-$(CONFIG_DEBUG_FS) += msm_cpr-debug.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 526616a..cf1f401 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -52,7 +52,7 @@
zreladdr-$(CONFIG_ARCH_MSM9615) := 0x40808000
# MSM9625
- zreladdr-$(CONFIG_ARCH_MSM9625) := 0x20208000
+ zreladdr-$(CONFIG_ARCH_MSM9625) := 0x00208000
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000
@@ -65,3 +65,5 @@
# MPQ8092
zreladdr-$(CONFIG_ARCH_MPQ8092) := 0x00008000
+# MSM8910
+ zreladdr-$(CONFIG_ARCH_MSM8910) := 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 6788cbe..5c4a923 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -719,6 +719,7 @@
*/
clk_enable(pll_clk[backup_s->pll].clk);
acpuclk_set_div(backup_s);
+ update_jiffies(cpu, backup_s->lpj);
}
/* Make sure PLL4 is off before reprogramming */
if ((plls_enabled & (1 << tgt_s->pll))) {
@@ -736,6 +737,7 @@
*/
clk_enable(pll_clk[backup_s->pll].clk);
acpuclk_set_div(backup_s);
+ update_jiffies(cpu, backup_s->lpj);
}
}
diff --git a/arch/arm/mach-msm/acpuclock-8064.c b/arch/arm/mach-msm/acpuclock-8064.c
index 06c2579..d1613d9 100644
--- a/arch/arm/mach-msm/acpuclock-8064.c
+++ b/arch/arm/mach-msm/acpuclock-8064.c
@@ -18,6 +18,7 @@
#include <mach/msm_bus_board.h>
#include <mach/msm_bus.h>
+#include "mach/socinfo.h"
#include "acpuclock.h"
#include "acpuclock-krait.h"
@@ -44,6 +45,7 @@
.hfpll_phys_base = 0x00903200,
.aux_clk_sel_phys = 0x02088014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x4501,
.vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000 },
@@ -54,6 +56,7 @@
.hfpll_phys_base = 0x00903240,
.aux_clk_sel_phys = 0x02098014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x5501,
.vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait1_mem", 1150000 },
@@ -64,6 +67,7 @@
.hfpll_phys_base = 0x00903280,
.aux_clk_sel_phys = 0x020A8014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x6501,
.vreg[VREG_CORE] = { "krait2", 1300000 },
.vreg[VREG_MEM] = { "krait2_mem", 1150000 },
@@ -74,6 +78,7 @@
.hfpll_phys_base = 0x009032C0,
.aux_clk_sel_phys = 0x020B8014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x7501,
.vreg[VREG_CORE] = { "krait3", 1300000 },
.vreg[VREG_MEM] = { "krait3_mem", 1150000 },
@@ -84,11 +89,16 @@
.hfpll_phys_base = 0x00903300,
.aux_clk_sel_phys = 0x02011028,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x0500,
.vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
},
};
+/*
+ * The correct maximum rate for 8064ab in 600 MHZ.
+ * We rely on the RPM rounding requests up here.
+*/
static struct msm_bus_paths bw_level_tbl[] __initdata = {
[0] = BW_MBPS(640), /* At least 80 MHz on bus. */
[1] = BW_MBPS(1064), /* At least 133 MHz on bus. */
@@ -105,110 +115,191 @@
.name = "acpuclk-8064",
};
-static struct l2_level l2_freq_tbl[] __initdata __initdata = {
- [0] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
- [2] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
- [3] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
- [6] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
- [7] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
- [8] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
- [9] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 5 },
- [11] = { { 972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 5 },
- [12] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 5 },
- [13] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 5 },
- [14] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 5 },
- [15] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 5 },
+static struct l2_level l2_freq_tbl[] __initdata = {
+ [0] = { { 384000, PLL_8, 0, 0x00 }, 950000, 1050000, 1 },
+ [1] = { { 432000, HFPLL, 2, 0x20 }, 1050000, 1050000, 2 },
+ [2] = { { 486000, HFPLL, 2, 0x24 }, 1050000, 1050000, 2 },
+ [3] = { { 540000, HFPLL, 2, 0x28 }, 1050000, 1050000, 2 },
+ [4] = { { 594000, HFPLL, 1, 0x16 }, 1050000, 1050000, 2 },
+ [5] = { { 648000, HFPLL, 1, 0x18 }, 1050000, 1050000, 4 },
+ [6] = { { 702000, HFPLL, 1, 0x1A }, 1050000, 1050000, 4 },
+ [7] = { { 756000, HFPLL, 1, 0x1C }, 1150000, 1150000, 4 },
+ [8] = { { 810000, HFPLL, 1, 0x1E }, 1150000, 1150000, 4 },
+ [9] = { { 864000, HFPLL, 1, 0x20 }, 1150000, 1150000, 4 },
+ [10] = { { 918000, HFPLL, 1, 0x22 }, 1150000, 1150000, 5 },
+ [11] = { { 972000, HFPLL, 1, 0x24 }, 1150000, 1150000, 5 },
+ [12] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 5 },
+ [13] = { { 1080000, HFPLL, 1, 0x28 }, 1150000, 1150000, 5 },
+ [14] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 5 },
+ [15] = { { 1188000, HFPLL, 1, 0x2C }, 1150000, 1150000, 5 },
+ /* L2 Level 16 is for 8064ab only */
+ [16] = { { 1242000, HFPLL, 1, 0x2E }, 1150000, 1150000, 5 },
{ }
};
-static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 950000 },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 975000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 975000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 1000000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 1000000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1025000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1025000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(6), 1075000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(6), 1075000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(6), 1100000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(6), 1100000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(6), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(6), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1250000 },
+static struct acpu_level tbl_slow[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 975000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 975000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 1025000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1125000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
{ 0, { 0 } }
};
-static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 900000 },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 925000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 925000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 950000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 950000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 975000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 975000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(6), 1025000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(6), 1025000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(6), 1050000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(6), 1050000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(6), 1075000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(6), 1075000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1125000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1125000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1150000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1150000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1175000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1175000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1187500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1187500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1200000 },
+static struct acpu_level tbl_nom[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 925000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 925000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 950000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 950000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 975000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 975000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 1025000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1025000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1050000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1050000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1075000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1075000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1125000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1125000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1150000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1150000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1175000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1175000 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1187500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1187500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1200000 },
{ 0, { 0 } }
};
-static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 850000 },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 875000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 875000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 900000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 900000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 925000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 925000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(6), 975000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(6), 975000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(6), 1000000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(6), 1000000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(6), 1025000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(6), 1025000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1075000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1075000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1100000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1100000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1125000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1125000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1137500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1137500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1150000 },
+static struct acpu_level tbl_fast[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 850000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 875000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 900000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 900000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 925000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 925000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 975000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 975000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1000000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1000000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1025000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1025000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1075000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1075000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1100000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1100000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1125000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1125000 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1137500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1137500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1150000 },
{ 0, { 0 } }
};
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-[PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
-[PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
-[PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
-/* TODO: update the faster table when data is available */
-[PVS_FASTER] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
+static struct acpu_level tbl_slow_1p7[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 975000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 975000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 1025000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1125000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
+ { 1, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1250000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1250000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level tbl_slow_2p0[] __initdata = {
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 975000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 975000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 1025000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1125000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(15), 1237500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(15), 1250000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(15), 1250000 },
+ { 1, { 1620000, HFPLL, 1, 0x3C }, L2(15), 1250000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(15), 1250000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(15), 1250000 },
+ { 1, { 1782000, HFPLL, 1, 0x42 }, L2(15), 1250000 },
+ { 1, { 1836000, HFPLL, 1, 0x44 }, L2(15), 1250000 },
+ { 1, { 1890000, HFPLL, 1, 0x46 }, L2(15), 1250000 },
+ { 1, { 1944000, HFPLL, 1, 0x48 }, L2(15), 1250000 },
+ { 1, { 1998000, HFPLL, 1, 0x4A }, L2(15), 1250000 },
+ { 0, { 0 } }
+};
+
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+ [0][PVS_SLOW] = {tbl_slow, sizeof(tbl_slow), 0 },
+ [0][PVS_NOMINAL] = {tbl_nom, sizeof(tbl_nom), 25000 },
+ [0][PVS_FAST] = {tbl_fast, sizeof(tbl_fast), 25000 },
+ [0][PVS_FASTER] = {tbl_fast, sizeof(tbl_fast), 25000 },
+
+ [1][0] = { tbl_slow_1p7, sizeof(tbl_slow_1p7), 0 },
+ [1][1] = { tbl_slow_1p7, sizeof(tbl_slow_1p7), 0 },
+ [1][2] = { tbl_slow_1p7, sizeof(tbl_slow_1p7), 0 },
+ [1][3] = { tbl_slow_1p7, sizeof(tbl_slow_1p7), 0 },
+ [1][4] = { tbl_slow_1p7, sizeof(tbl_slow_1p7), 0 },
+ [1][5] = { tbl_slow_1p7, sizeof(tbl_slow_1p7), 0 },
+ [1][6] = { tbl_slow_1p7, sizeof(tbl_slow_1p7), 0 },
+
+ [2][0] = { tbl_slow_2p0, sizeof(tbl_slow_2p0), 0 },
+ [2][1] = { tbl_slow_2p0, sizeof(tbl_slow_2p0), 0 },
+ [2][2] = { tbl_slow_2p0, sizeof(tbl_slow_2p0), 0 },
+ [2][3] = { tbl_slow_2p0, sizeof(tbl_slow_2p0), 0 },
+ [2][4] = { tbl_slow_2p0, sizeof(tbl_slow_2p0), 0 },
+ [2][5] = { tbl_slow_2p0, sizeof(tbl_slow_2p0), 0 },
+ [2][6] = { tbl_slow_2p0, sizeof(tbl_slow_2p0), 0 },
};
static struct acpuclk_krait_params acpuclk_8064_params __initdata = {
@@ -225,6 +316,12 @@
static int __init acpuclk_8064_probe(struct platform_device *pdev)
{
+ if (cpu_is_apq8064ab() ||
+ SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) {
+ acpuclk_8064_params.hfpll_data->low_vdd_l_max = 37;
+ acpuclk_8064_params.hfpll_data->nom_vdd_l_max = 74;
+ }
+
return acpuclk_krait_init(&pdev->dev, &acpuclk_8064_params);
}
diff --git a/arch/arm/mach-msm/acpuclock-8627.c b/arch/arm/mach-msm/acpuclock-8627.c
index 9e6662d..ac29cac 100644
--- a/arch/arm/mach-msm/acpuclock-8627.c
+++ b/arch/arm/mach-msm/acpuclock-8627.c
@@ -50,6 +50,7 @@
.hfpll_phys_base = 0x00903200,
.aux_clk_sel_phys = 0x02088014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x4501,
.vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000 },
@@ -60,6 +61,7 @@
.hfpll_phys_base = 0x00903300,
.aux_clk_sel_phys = 0x02098014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x5501,
.vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait1_mem", 1150000 },
@@ -70,6 +72,7 @@
.hfpll_phys_base = 0x00903400,
.aux_clk_sel_phys = 0x02011028,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x0500,
.vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
},
@@ -92,42 +95,42 @@
/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 2, 0x00 }, LVL_NOM, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0, 0x20 }, LVL_NOM, 1050000, 1 },
- [2] = { { 486000, HFPLL, 2, 0, 0x24 }, LVL_NOM, 1050000, 1 },
- [3] = { { 540000, HFPLL, 2, 0, 0x28 }, LVL_NOM, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0, 0x16 }, LVL_NOM, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0, 0x18 }, LVL_NOM, 1050000, 2 },
- [6] = { { 702000, HFPLL, 1, 0, 0x1A }, LVL_NOM, 1050000, 3 },
- [7] = { { 756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 3 },
- [8] = { { 810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 3 },
- [9] = { { 864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 4 },
- [11] = { { 972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 4 },
+ [0] = { { 384000, PLL_8, 0, 0x00 }, LVL_NOM, 1050000, 1 },
+ [1] = { { 432000, HFPLL, 2, 0x20 }, LVL_NOM, 1050000, 1 },
+ [2] = { { 486000, HFPLL, 2, 0x24 }, LVL_NOM, 1050000, 1 },
+ [3] = { { 540000, HFPLL, 2, 0x28 }, LVL_NOM, 1050000, 2 },
+ [4] = { { 594000, HFPLL, 1, 0x16 }, LVL_NOM, 1050000, 2 },
+ [5] = { { 648000, HFPLL, 1, 0x18 }, LVL_NOM, 1050000, 2 },
+ [6] = { { 702000, HFPLL, 1, 0x1A }, LVL_NOM, 1050000, 3 },
+ [7] = { { 756000, HFPLL, 1, 0x1C }, LVL_HIGH, 1150000, 3 },
+ [8] = { { 810000, HFPLL, 1, 0x1E }, LVL_HIGH, 1150000, 3 },
+ [9] = { { 864000, HFPLL, 1, 0x20 }, LVL_HIGH, 1150000, 4 },
+ [10] = { { 918000, HFPLL, 1, 0x22 }, LVL_HIGH, 1150000, 4 },
+ [11] = { { 972000, HFPLL, 1, 0x24 }, LVL_HIGH, 1150000, 4 },
{ }
};
/* TODO: Update core voltages when data is available. */
static struct acpu_level acpu_freq_tbl[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 900000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(4), 925000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(4), 925000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(4), 937500 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(4), 962500 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(8), 987500 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(8), 1000000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(8), 1025000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(8), 1062500 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1062500 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1087500 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(11), 1100000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 432000, HFPLL, 2, 0x20 }, L2(4), 925000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(4), 925000 },
+ { 1, { 540000, HFPLL, 2, 0x28 }, L2(4), 937500 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(4), 962500 },
+ { 1, { 648000, HFPLL, 1, 0x18 }, L2(8), 987500 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(8), 1000000 },
+ { 1, { 756000, HFPLL, 1, 0x1C }, L2(8), 1025000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(8), 1062500 },
+ { 1, { 864000, HFPLL, 1, 0x20 }, L2(11), 1062500 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(11), 1087500 },
+ { 1, { 972000, HFPLL, 1, 0x24 }, L2(11), 1100000 },
{ 0, { 0 } }
};
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
- [PVS_SLOW] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 0 },
- [PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 25000 },
- [PVS_FAST] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 25000 },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+ [0][PVS_SLOW] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 0 },
+ [0][PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 25000 },
+ [0][PVS_FAST] = { acpu_freq_tbl, sizeof(acpu_freq_tbl), 25000 },
};
static struct acpuclk_krait_params acpuclk_8627_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8930.c b/arch/arm/mach-msm/acpuclock-8930.c
index b8ca865..e46599a 100644
--- a/arch/arm/mach-msm/acpuclock-8930.c
+++ b/arch/arm/mach-msm/acpuclock-8930.c
@@ -50,6 +50,7 @@
.hfpll_phys_base = 0x00903200,
.aux_clk_sel_phys = 0x02088014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x4501,
.vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000 },
@@ -61,6 +62,7 @@
.hfpll_phys_base = 0x00903300,
.aux_clk_sel_phys = 0x02098014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x5501,
.vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait1_mem", 1150000 },
@@ -72,6 +74,7 @@
.hfpll_phys_base = 0x00903400,
.aux_clk_sel_phys = 0x02011028,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x0500,
.vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
.vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
@@ -83,6 +86,7 @@
.hfpll_phys_base = 0x00903200,
.aux_clk_sel_phys = 0x02088014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x4501,
.vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000 },
@@ -93,6 +97,7 @@
.hfpll_phys_base = 0x00903300,
.aux_clk_sel_phys = 0x02098014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x5501,
.vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait1_mem", 1150000 },
@@ -103,6 +108,7 @@
.hfpll_phys_base = 0x00903400,
.aux_clk_sel_phys = 0x02011028,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x0500,
.vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
},
@@ -128,89 +134,89 @@
/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 2, 0x00 }, LVL_NOM, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0, 0x20 }, LVL_NOM, 1050000, 2 },
- [2] = { { 486000, HFPLL, 2, 0, 0x24 }, LVL_NOM, 1050000, 2 },
- [3] = { { 540000, HFPLL, 2, 0, 0x28 }, LVL_NOM, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0, 0x16 }, LVL_NOM, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0, 0x18 }, LVL_NOM, 1050000, 4 },
- [6] = { { 702000, HFPLL, 1, 0, 0x1A }, LVL_NOM, 1050000, 4 },
- [7] = { { 756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 4 },
- [8] = { { 810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 4 },
- [9] = { { 864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 7 },
- [11] = { { 972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 7 },
- [12] = { { 1026000, HFPLL, 1, 0, 0x26 }, LVL_HIGH, 1150000, 7 },
- [13] = { { 1080000, HFPLL, 1, 0, 0x28 }, LVL_HIGH, 1150000, 7 },
- [14] = { { 1134000, HFPLL, 1, 0, 0x2A }, LVL_HIGH, 1150000, 7 },
- [15] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
+ [0] = { { 384000, PLL_8, 0, 0x00 }, LVL_NOM, 1050000, 1 },
+ [1] = { { 432000, HFPLL, 2, 0x20 }, LVL_NOM, 1050000, 2 },
+ [2] = { { 486000, HFPLL, 2, 0x24 }, LVL_NOM, 1050000, 2 },
+ [3] = { { 540000, HFPLL, 2, 0x28 }, LVL_NOM, 1050000, 2 },
+ [4] = { { 594000, HFPLL, 1, 0x16 }, LVL_NOM, 1050000, 2 },
+ [5] = { { 648000, HFPLL, 1, 0x18 }, LVL_NOM, 1050000, 4 },
+ [6] = { { 702000, HFPLL, 1, 0x1A }, LVL_NOM, 1050000, 4 },
+ [7] = { { 756000, HFPLL, 1, 0x1C }, LVL_HIGH, 1150000, 4 },
+ [8] = { { 810000, HFPLL, 1, 0x1E }, LVL_HIGH, 1150000, 4 },
+ [9] = { { 864000, HFPLL, 1, 0x20 }, LVL_HIGH, 1150000, 4 },
+ [10] = { { 918000, HFPLL, 1, 0x22 }, LVL_HIGH, 1150000, 7 },
+ [11] = { { 972000, HFPLL, 1, 0x24 }, LVL_HIGH, 1150000, 7 },
+ [12] = { { 1026000, HFPLL, 1, 0x26 }, LVL_HIGH, 1150000, 7 },
+ [13] = { { 1080000, HFPLL, 1, 0x28 }, LVL_HIGH, 1150000, 7 },
+ [14] = { { 1134000, HFPLL, 1, 0x2A }, LVL_HIGH, 1150000, 7 },
+ [15] = { { 1188000, HFPLL, 1, 0x2C }, LVL_HIGH, 1150000, 7 },
{ }
};
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(5), 975000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(5), 1000000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(5), 1025000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(10), 1075000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(10), 1100000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(10), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
+ { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
+ { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
+ { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
+ { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
+ { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
+ { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
+ { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
{ 0, { 0 } }
};
static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 925000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(5), 950000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(5), 950000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(5), 975000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(5), 975000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(5), 1000000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(5), 1000000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(10), 1050000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(10), 1050000 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(10), 1075000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(10), 1075000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(10), 1100000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1100000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1150000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1150000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1175000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
+ { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
+ { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 975000 },
+ { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1000000 },
+ { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
+ { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
+ { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
+ { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
+ { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
{ 0, { 0 } }
};
static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 900000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(5), 900000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(5), 900000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(5), 925000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(5), 925000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(5), 950000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(5), 950000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(10), 1000000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(10), 1000000 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(10), 1025000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(10), 1025000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(10), 1050000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1050000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1100000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1100000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1125000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
+ { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
+ { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 950000 },
+ { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
+ { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
+ { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
+ { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
+ { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
{ 0, { 0 } }
};
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-[PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
-[PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
-[PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+[0][PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+[0][PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
+[0][PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
};
static struct acpuclk_krait_params acpuclk_8930_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8930aa.c b/arch/arm/mach-msm/acpuclock-8930aa.c
index d589f1a..9d2b6fc 100644
--- a/arch/arm/mach-msm/acpuclock-8930aa.c
+++ b/arch/arm/mach-msm/acpuclock-8930aa.c
@@ -50,6 +50,7 @@
.hfpll_phys_base = 0x00903200,
.aux_clk_sel_phys = 0x02088014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x4501,
.vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000 },
@@ -60,6 +61,7 @@
.hfpll_phys_base = 0x00903300,
.aux_clk_sel_phys = 0x02098014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x5501,
.vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait1_mem", 1150000 },
@@ -70,6 +72,7 @@
.hfpll_phys_base = 0x00903400,
.aux_clk_sel_phys = 0x02011028,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x0500,
.vreg[VREG_HFPLL_A] = { "l2_hfpll", 1800000 },
},
@@ -95,101 +98,101 @@
/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 2, 0x00 }, LVL_NOM, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0, 0x20 }, LVL_NOM, 1050000, 2 },
- [2] = { { 486000, HFPLL, 2, 0, 0x24 }, LVL_NOM, 1050000, 2 },
- [3] = { { 540000, HFPLL, 2, 0, 0x28 }, LVL_NOM, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0, 0x16 }, LVL_NOM, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0, 0x18 }, LVL_NOM, 1050000, 4 },
- [6] = { { 702000, HFPLL, 1, 0, 0x1A }, LVL_NOM, 1050000, 4 },
- [7] = { { 756000, HFPLL, 1, 0, 0x1C }, LVL_HIGH, 1150000, 4 },
- [8] = { { 810000, HFPLL, 1, 0, 0x1E }, LVL_HIGH, 1150000, 4 },
- [9] = { { 864000, HFPLL, 1, 0, 0x20 }, LVL_HIGH, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0, 0x22 }, LVL_HIGH, 1150000, 7 },
- [11] = { { 972000, HFPLL, 1, 0, 0x24 }, LVL_HIGH, 1150000, 7 },
- [12] = { { 1026000, HFPLL, 1, 0, 0x26 }, LVL_HIGH, 1150000, 7 },
- [13] = { { 1080000, HFPLL, 1, 0, 0x28 }, LVL_HIGH, 1150000, 7 },
- [14] = { { 1134000, HFPLL, 1, 0, 0x2A }, LVL_HIGH, 1150000, 7 },
- [15] = { { 1188000, HFPLL, 1, 0, 0x2C }, LVL_HIGH, 1150000, 7 },
+ [0] = { { 384000, PLL_8, 0, 0x00 }, LVL_NOM, 1050000, 1 },
+ [1] = { { 432000, HFPLL, 2, 0x20 }, LVL_NOM, 1050000, 2 },
+ [2] = { { 486000, HFPLL, 2, 0x24 }, LVL_NOM, 1050000, 2 },
+ [3] = { { 540000, HFPLL, 2, 0x28 }, LVL_NOM, 1050000, 2 },
+ [4] = { { 594000, HFPLL, 1, 0x16 }, LVL_NOM, 1050000, 2 },
+ [5] = { { 648000, HFPLL, 1, 0x18 }, LVL_NOM, 1050000, 4 },
+ [6] = { { 702000, HFPLL, 1, 0x1A }, LVL_NOM, 1050000, 4 },
+ [7] = { { 756000, HFPLL, 1, 0x1C }, LVL_HIGH, 1150000, 4 },
+ [8] = { { 810000, HFPLL, 1, 0x1E }, LVL_HIGH, 1150000, 4 },
+ [9] = { { 864000, HFPLL, 1, 0x20 }, LVL_HIGH, 1150000, 4 },
+ [10] = { { 918000, HFPLL, 1, 0x22 }, LVL_HIGH, 1150000, 7 },
+ [11] = { { 972000, HFPLL, 1, 0x24 }, LVL_HIGH, 1150000, 7 },
+ [12] = { { 1026000, HFPLL, 1, 0x26 }, LVL_HIGH, 1150000, 7 },
+ [13] = { { 1080000, HFPLL, 1, 0x28 }, LVL_HIGH, 1150000, 7 },
+ [14] = { { 1134000, HFPLL, 1, 0x2A }, LVL_HIGH, 1150000, 7 },
+ [15] = { { 1188000, HFPLL, 1, 0x2C }, LVL_HIGH, 1150000, 7 },
{ }
};
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 950000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(5), 975000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(5), 975000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(5), 1000000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(5), 1000000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(5), 1025000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(5), 1025000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(10), 1075000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(10), 1075000 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(10), 1100000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(10), 1100000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(10), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1125000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
- { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
- { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 975000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 975000 },
+ { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 1000000 },
+ { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1025000 },
+ { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1075000 },
+ { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1100000 },
+ { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1125000 },
+ { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1175000 },
+ { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1200000 },
+ { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1225000 },
+ { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1237500 },
{ 0, { 0 } }
};
static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 925000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(5), 950000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(5), 950000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(5), 975000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(5), 975000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(5), 1000000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(5), 1000000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(10), 1050000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(10), 1050000 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(10), 1075000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(10), 1075000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(10), 1100000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1100000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1150000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1150000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1175000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1175000 },
- { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1200000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1200000 },
- { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1212500 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 925000 },
+ { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 950000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 950000 },
+ { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 975000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 975000 },
+ { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 1000000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 1000000 },
+ { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1050000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1050000 },
+ { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1075000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1075000 },
+ { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1100000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1100000 },
+ { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1150000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1150000 },
+ { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1175000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1175000 },
+ { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1200000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1200000 },
+ { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1212500 },
{ 0, { 0 } }
};
static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 900000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(5), 900000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(5), 900000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(5), 925000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(5), 925000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(5), 950000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(5), 950000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(10), 1000000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(10), 1000000 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(10), 1025000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(10), 1025000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(10), 1050000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(10), 1050000 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1100000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1100000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1125000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1125000 },
- { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1150000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1150000 },
- { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1162500 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 432000, HFPLL, 2, 0x20 }, L2(5), 900000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(5), 900000 },
+ { 1, { 540000, HFPLL, 2, 0x28 }, L2(5), 925000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(5), 925000 },
+ { 1, { 648000, HFPLL, 1, 0x18 }, L2(5), 950000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(5), 950000 },
+ { 1, { 756000, HFPLL, 1, 0x1C }, L2(10), 1000000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(10), 1000000 },
+ { 1, { 864000, HFPLL, 1, 0x20 }, L2(10), 1025000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(10), 1025000 },
+ { 1, { 972000, HFPLL, 1, 0x24 }, L2(10), 1050000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(10), 1050000 },
+ { 1, { 1080000, HFPLL, 1, 0x28 }, L2(15), 1100000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(15), 1100000 },
+ { 1, { 1188000, HFPLL, 1, 0x2C }, L2(15), 1125000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(15), 1125000 },
+ { 1, { 1296000, HFPLL, 1, 0x30 }, L2(15), 1150000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(15), 1150000 },
+ { 1, { 1404000, HFPLL, 1, 0x34 }, L2(15), 1162500 },
{ 0, { 0 } }
};
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-[PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
-[PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
-[PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+[0][PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+[0][PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
+[0][PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
};
static struct acpuclk_krait_params acpuclk_8930aa_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index e16c6b6..d7d3edd 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -44,6 +44,7 @@
.hfpll_phys_base = 0x00903200,
.aux_clk_sel_phys = 0x02088014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x4501,
.vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000 },
@@ -55,6 +56,7 @@
.hfpll_phys_base = 0x00903300,
.aux_clk_sel_phys = 0x02098014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x5501,
.vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait1_mem", 1150000 },
@@ -66,6 +68,7 @@
.hfpll_phys_base = 0x00903400,
.aux_clk_sel_phys = 0x02011028,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x0500,
.vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
.vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
@@ -90,112 +93,112 @@
};
static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
- [1] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
- [2] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
- [3] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
- [4] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
- [5] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
- [6] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
- [7] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
- [8] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
- [9] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
- [10] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 6 },
- [11] = { { 972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 6 },
- [12] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 6 },
- [13] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 6 },
- [14] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 6 },
- [15] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 6 },
- [16] = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 6 },
- [17] = { { 1296000, HFPLL, 1, 0, 0x30 }, 1150000, 1150000, 6 },
- [18] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 6 },
+ [0] = { { 384000, PLL_8, 0, 0x00 }, 1050000, 1050000, 1 },
+ [1] = { { 432000, HFPLL, 2, 0x20 }, 1050000, 1050000, 2 },
+ [2] = { { 486000, HFPLL, 2, 0x24 }, 1050000, 1050000, 2 },
+ [3] = { { 540000, HFPLL, 2, 0x28 }, 1050000, 1050000, 2 },
+ [4] = { { 594000, HFPLL, 1, 0x16 }, 1050000, 1050000, 2 },
+ [5] = { { 648000, HFPLL, 1, 0x18 }, 1050000, 1050000, 4 },
+ [6] = { { 702000, HFPLL, 1, 0x1A }, 1050000, 1050000, 4 },
+ [7] = { { 756000, HFPLL, 1, 0x1C }, 1150000, 1150000, 4 },
+ [8] = { { 810000, HFPLL, 1, 0x1E }, 1150000, 1150000, 4 },
+ [9] = { { 864000, HFPLL, 1, 0x20 }, 1150000, 1150000, 4 },
+ [10] = { { 918000, HFPLL, 1, 0x22 }, 1150000, 1150000, 6 },
+ [11] = { { 972000, HFPLL, 1, 0x24 }, 1150000, 1150000, 6 },
+ [12] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 6 },
+ [13] = { { 1080000, HFPLL, 1, 0x28 }, 1150000, 1150000, 6 },
+ [14] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 6 },
+ [15] = { { 1188000, HFPLL, 1, 0x2C }, 1150000, 1150000, 6 },
+ [16] = { { 1242000, HFPLL, 1, 0x2E }, 1150000, 1150000, 6 },
+ [17] = { { 1296000, HFPLL, 1, 0x30 }, 1150000, 1150000, 6 },
+ [18] = { { 1350000, HFPLL, 1, 0x32 }, 1150000, 1150000, 6 },
{ }
};
#define AVS(x) .avsdscr_setting = (x)
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 950000, AVS(0x40001F) },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 975000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 975000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 1000000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 1000000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1025000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1025000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(6), 1075000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(6), 1075000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(6), 1100000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(6), 1100000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(6), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(6), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1175000, AVS(0x400015) },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1175000, AVS(0x400015) },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1200000, AVS(0x400015) },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1200000, AVS(0x400015) },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1225000, AVS(0x400015) },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1225000, AVS(0x400015) },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1237500, AVS(0x400015) },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1237500, AVS(0x100018) },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1250000, AVS(0x400012) },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000, AVS(0x40001F) },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 975000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 975000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 1025000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1125000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(18), 1175000, AVS(0x400015) },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(18), 1175000, AVS(0x400015) },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(18), 1200000, AVS(0x400015) },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(18), 1200000, AVS(0x400015) },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(18), 1225000, AVS(0x400015) },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(18), 1225000, AVS(0x400015) },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(18), 1237500, AVS(0x400015) },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(18), 1237500, AVS(0x100018) },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(18), 1250000, AVS(0x400012) },
{ 0, { 0 } }
};
static struct acpu_level acpu_freq_tbl_nom[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 900000, AVS(0x40007F) },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 925000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 925000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 950000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 950000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 975000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 975000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(6), 1025000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(6), 1025000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(6), 1050000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(6), 1050000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(6), 1075000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(6), 1075000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1125000, AVS(0x400015) },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1125000, AVS(0x400015) },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1150000, AVS(0x400015) },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1150000, AVS(0x400015) },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1175000, AVS(0x400015) },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1175000, AVS(0x400015) },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1187500, AVS(0x400015) },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1187500, AVS(0x100018) },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1200000, AVS(0x400012) },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 900000, AVS(0x40007F) },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 925000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 925000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 950000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 950000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 975000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 975000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 1025000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 1025000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1050000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1050000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1075000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1075000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(18), 1125000, AVS(0x400015) },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(18), 1125000, AVS(0x400015) },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(18), 1150000, AVS(0x400015) },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(18), 1150000, AVS(0x400015) },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(18), 1175000, AVS(0x400015) },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(18), 1175000, AVS(0x400015) },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(18), 1187500, AVS(0x400015) },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(18), 1187500, AVS(0x100018) },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(18), 1200000, AVS(0x400012) },
{ 0, { 0 } }
};
static struct acpu_level acpu_freq_tbl_fast[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 850000, AVS(0x4000FF) },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 875000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 875000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 900000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 900000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 925000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 925000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(6), 975000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(6), 975000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(6), 1000000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(6), 1000000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(6), 1025000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(6), 1025000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(18), 1075000, AVS(0x10001B) },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(18), 1075000, AVS(0x10001B) },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(18), 1100000, AVS(0x10001B) },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(18), 1100000, AVS(0x10001B) },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(18), 1125000, AVS(0x10001B) },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(18), 1125000, AVS(0x400012) },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(18), 1137500, AVS(0x400012) },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(18), 1137500, AVS(0x400012) },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(18), 1150000, AVS(0x400012) },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 850000, AVS(0x4000FF) },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(6), 875000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(6), 875000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(6), 900000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(6), 900000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(6), 925000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(6), 925000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(6), 975000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(6), 975000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(6), 1000000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(6), 1000000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(6), 1025000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(6), 1025000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(18), 1075000, AVS(0x10001B) },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(18), 1075000, AVS(0x10001B) },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(18), 1100000, AVS(0x10001B) },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(18), 1100000, AVS(0x10001B) },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(18), 1125000, AVS(0x10001B) },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(18), 1125000, AVS(0x400012) },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(18), 1137500, AVS(0x400012) },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(18), 1137500, AVS(0x400012) },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(18), 1150000, AVS(0x400012) },
{ 0, { 0 } }
};
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-[PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
-[PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
-[PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+[0][PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+[0][PVS_NOMINAL] = { acpu_freq_tbl_nom, sizeof(acpu_freq_tbl_nom), 25000 },
+[0][PVS_FAST] = { acpu_freq_tbl_fast, sizeof(acpu_freq_tbl_fast), 25000 },
};
static struct acpuclk_krait_params acpuclk_8960_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8960ab.c b/arch/arm/mach-msm/acpuclock-8960ab.c
index 628e1ba..ae1cd7b 100644
--- a/arch/arm/mach-msm/acpuclock-8960ab.c
+++ b/arch/arm/mach-msm/acpuclock-8960ab.c
@@ -44,6 +44,7 @@
.hfpll_phys_base = 0x00903200,
.aux_clk_sel_phys = 0x02088014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x4501,
.vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000 },
@@ -55,6 +56,7 @@
.hfpll_phys_base = 0x00903300,
.aux_clk_sel_phys = 0x02098014,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x5501,
.vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait1_mem", 1150000 },
@@ -66,6 +68,7 @@
.hfpll_phys_base = 0x00903400,
.aux_clk_sel_phys = 0x02011028,
.aux_clk_sel = 3,
+ .sec_clk_sel = 2,
.l2cpmr_iaddr = 0x0500,
.vreg[VREG_HFPLL_A] = { "l2_s8", 2050000 },
.vreg[VREG_HFPLL_B] = { "l2_l23", 1800000 },
@@ -89,53 +92,53 @@
};
static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
- [1] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
- [2] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
- [3] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
- [4] = { { 810000, HFPLL, 1, 0, 0x1E }, 1050000, 1050000, 4 },
- [5] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 5 },
- [6] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 5 },
- [7] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 5 },
- [8] = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 5 },
- [9] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 5 },
+ [0] = { { 384000, PLL_8, 0, 0x00 }, 1050000, 1050000, 1 },
+ [1] = { { 486000, HFPLL, 2, 0x24 }, 1050000, 1050000, 2 },
+ [2] = { { 594000, HFPLL, 1, 0x16 }, 1050000, 1050000, 2 },
+ [3] = { { 702000, HFPLL, 1, 0x1A }, 1050000, 1050000, 4 },
+ [4] = { { 810000, HFPLL, 1, 0x1E }, 1050000, 1050000, 4 },
+ [5] = { { 918000, HFPLL, 1, 0x22 }, 1150000, 1150000, 5 },
+ [6] = { { 1026000, HFPLL, 1, 0x26 }, 1150000, 1150000, 5 },
+ [7] = { { 1134000, HFPLL, 1, 0x2A }, 1150000, 1150000, 5 },
+ [8] = { { 1242000, HFPLL, 1, 0x2E }, 1150000, 1150000, 5 },
+ [9] = { { 1350000, HFPLL, 1, 0x32 }, 1150000, 1150000, 5 },
{ }
};
static struct acpu_level acpu_freq_tbl_slow[] __initdata = {
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(0), 950000 },
- { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(3), 975000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(3), 975000 },
- { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(3), 1000000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(3), 1000000 },
- { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(3), 1025000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(3), 1025000 },
- { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(3), 1075000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(3), 1075000 },
- { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(3), 1100000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(3), 1100000 },
- { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(3), 1125000 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(3), 1125000 },
- { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(9), 1175000 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(9), 1175000 },
- { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(9), 1200000 },
- { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(9), 1200000 },
- { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(9), 1225000 },
- { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(9), 1225000 },
- { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(9), 1237500 },
- { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(9), 1237500 },
- { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(9), 1250000 },
- { 1, { 1566000, HFPLL, 1, 0, 0x3A }, L2(9), 1250000 },
- { 1, { 1620000, HFPLL, 1, 0, 0x3C }, L2(9), 1250000 },
- { 1, { 1674000, HFPLL, 1, 0, 0x3E }, L2(9), 1250000 },
- { 1, { 1728000, HFPLL, 1, 0, 0x40 }, L2(9), 1250000 },
+ { 1, { 384000, PLL_8, 0, 0x00 }, L2(0), 950000 },
+ { 0, { 432000, HFPLL, 2, 0x20 }, L2(3), 975000 },
+ { 1, { 486000, HFPLL, 2, 0x24 }, L2(3), 975000 },
+ { 0, { 540000, HFPLL, 2, 0x28 }, L2(3), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0x16 }, L2(3), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0x18 }, L2(3), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0x1A }, L2(3), 1025000 },
+ { 0, { 756000, HFPLL, 1, 0x1C }, L2(3), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0x1E }, L2(3), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0x20 }, L2(3), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0x22 }, L2(3), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0x24 }, L2(3), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0x26 }, L2(3), 1125000 },
+ { 0, { 1080000, HFPLL, 1, 0x28 }, L2(9), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0x2A }, L2(9), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0x2C }, L2(9), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0x2E }, L2(9), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0x30 }, L2(9), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0x32 }, L2(9), 1225000 },
+ { 0, { 1404000, HFPLL, 1, 0x34 }, L2(9), 1237500 },
+ { 1, { 1458000, HFPLL, 1, 0x36 }, L2(9), 1237500 },
+ { 1, { 1512000, HFPLL, 1, 0x38 }, L2(9), 1250000 },
+ { 1, { 1566000, HFPLL, 1, 0x3A }, L2(9), 1250000 },
+ { 1, { 1620000, HFPLL, 1, 0x3C }, L2(9), 1250000 },
+ { 1, { 1674000, HFPLL, 1, 0x3E }, L2(9), 1250000 },
+ { 1, { 1728000, HFPLL, 1, 0x40 }, L2(9), 1250000 },
{ 0, { 0 } }
};
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
-[PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
-[PVS_NOMINAL] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
-[PVS_FAST] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+[0][PVS_SLOW] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+[0][PVS_NOMINAL] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
+[0][PVS_FAST] = { acpu_freq_tbl_slow, sizeof(acpu_freq_tbl_slow), 0 },
};
static struct acpuclk_krait_params acpuclk_8960ab_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index ee2ca45..098f854 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -36,8 +36,8 @@
.has_user_reg = true,
.user_offset = 0x10,
.config_offset = 0x14,
- /* TODO: Verify magic numbers when final values are available. */
.user_val = 0x8,
+ .user_vco_mask = BIT(20),
.config_val = 0x04D0405D,
.low_vco_l_max = 65,
.low_vdd_l_max = 52,
@@ -52,6 +52,7 @@
[CPU0] = {
.hfpll_phys_base = 0xF908A000,
.l2cpmr_iaddr = 0x4501,
+ .sec_clk_sel = 2,
.vreg[VREG_CORE] = { "krait0", 1050000 },
.vreg[VREG_MEM] = { "krait0_mem", 1050000 },
.vreg[VREG_DIG] = { "krait0_dig", LVL_HIGH },
@@ -61,6 +62,7 @@
[CPU1] = {
.hfpll_phys_base = 0xF909A000,
.l2cpmr_iaddr = 0x5501,
+ .sec_clk_sel = 2,
.vreg[VREG_CORE] = { "krait1", 1050000 },
.vreg[VREG_MEM] = { "krait1_mem", 1050000 },
.vreg[VREG_DIG] = { "krait1_dig", LVL_HIGH },
@@ -70,6 +72,7 @@
[CPU2] = {
.hfpll_phys_base = 0xF90AA000,
.l2cpmr_iaddr = 0x6501,
+ .sec_clk_sel = 2,
.vreg[VREG_CORE] = { "krait2", 1050000 },
.vreg[VREG_MEM] = { "krait2_mem", 1050000 },
.vreg[VREG_DIG] = { "krait2_dig", LVL_HIGH },
@@ -79,6 +82,7 @@
[CPU3] = {
.hfpll_phys_base = 0xF90BA000,
.l2cpmr_iaddr = 0x7501,
+ .sec_clk_sel = 2,
.vreg[VREG_CORE] = { "krait3", 1050000 },
.vreg[VREG_MEM] = { "krait3_mem", 1050000 },
.vreg[VREG_DIG] = { "krait3_dig", LVL_HIGH },
@@ -88,6 +92,7 @@
[L2] = {
.hfpll_phys_base = 0xF9016000,
.l2cpmr_iaddr = 0x0500,
+ .sec_clk_sel = 2,
.vreg[VREG_HFPLL_A] = { "l2_hfpll_a", 2150000 },
.vreg[VREG_HFPLL_B] = { "l2_hfpll_b", 1800000 },
},
@@ -108,67 +113,67 @@
};
static struct l2_level l2_freq_tbl[] __initdata = {
- [0] = { { 300000, PLL_0, 0, 2, 0 }, LVL_LOW, 950000, 0 },
- [1] = { { 384000, HFPLL, 2, 0, 40 }, LVL_NOM, 950000, 1 },
- [2] = { { 460800, HFPLL, 2, 0, 48 }, LVL_NOM, 950000, 1 },
- [3] = { { 537600, HFPLL, 1, 0, 28 }, LVL_NOM, 950000, 2 },
- [4] = { { 576000, HFPLL, 1, 0, 30 }, LVL_NOM, 950000, 2 },
- [5] = { { 652800, HFPLL, 1, 0, 34 }, LVL_NOM, 950000, 2 },
- [6] = { { 729600, HFPLL, 1, 0, 38 }, LVL_NOM, 950000, 2 },
- [7] = { { 806400, HFPLL, 1, 0, 42 }, LVL_NOM, 950000, 2 },
- [8] = { { 883200, HFPLL, 1, 0, 46 }, LVL_HIGH, 1050000, 2 },
- [9] = { { 960000, HFPLL, 1, 0, 50 }, LVL_HIGH, 1050000, 2 },
- [10] = { { 1036800, HFPLL, 1, 0, 54 }, LVL_HIGH, 1050000, 3 },
- [11] = { { 1113600, HFPLL, 1, 0, 58 }, LVL_HIGH, 1050000, 3 },
- [12] = { { 1190400, HFPLL, 1, 0, 62 }, LVL_HIGH, 1050000, 3 },
- [13] = { { 1267200, HFPLL, 1, 0, 66 }, LVL_HIGH, 1050000, 3 },
- [14] = { { 1344000, HFPLL, 1, 0, 70 }, LVL_HIGH, 1050000, 3 },
- [15] = { { 1420800, HFPLL, 1, 0, 74 }, LVL_HIGH, 1050000, 3 },
- [16] = { { 1497600, HFPLL, 1, 0, 78 }, LVL_HIGH, 1050000, 3 },
- [17] = { { 1574400, HFPLL, 1, 0, 82 }, LVL_HIGH, 1050000, 3 },
- [18] = { { 1651200, HFPLL, 1, 0, 86 }, LVL_HIGH, 1050000, 3 },
- [19] = { { 1728000, HFPLL, 1, 0, 90 }, LVL_HIGH, 1050000, 3 },
- [20] = { { 1804800, HFPLL, 1, 0, 94 }, LVL_HIGH, 1050000, 3 },
- [21] = { { 1881600, HFPLL, 1, 0, 98 }, LVL_HIGH, 1050000, 3 },
- [22] = { { 1958400, HFPLL, 1, 0, 102 }, LVL_HIGH, 1050000, 3 },
- [23] = { { 2035200, HFPLL, 1, 0, 106 }, LVL_HIGH, 1050000, 3 },
- [24] = { { 2112000, HFPLL, 1, 0, 110 }, LVL_HIGH, 1050000, 3 },
- [25] = { { 2188800, HFPLL, 1, 0, 114 }, LVL_HIGH, 1050000, 3 },
+ [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 950000, 0 },
+ [1] = { { 384000, HFPLL, 2, 40 }, LVL_NOM, 950000, 1 },
+ [2] = { { 460800, HFPLL, 2, 48 }, LVL_NOM, 950000, 1 },
+ [3] = { { 537600, HFPLL, 1, 28 }, LVL_NOM, 950000, 2 },
+ [4] = { { 576000, HFPLL, 1, 30 }, LVL_NOM, 950000, 2 },
+ [5] = { { 652800, HFPLL, 1, 34 }, LVL_NOM, 950000, 2 },
+ [6] = { { 729600, HFPLL, 1, 38 }, LVL_NOM, 950000, 2 },
+ [7] = { { 806400, HFPLL, 1, 42 }, LVL_NOM, 950000, 2 },
+ [8] = { { 883200, HFPLL, 1, 46 }, LVL_HIGH, 1050000, 2 },
+ [9] = { { 960000, HFPLL, 1, 50 }, LVL_HIGH, 1050000, 2 },
+ [10] = { { 1036800, HFPLL, 1, 54 }, LVL_HIGH, 1050000, 3 },
+ [11] = { { 1113600, HFPLL, 1, 58 }, LVL_HIGH, 1050000, 3 },
+ [12] = { { 1190400, HFPLL, 1, 62 }, LVL_HIGH, 1050000, 3 },
+ [13] = { { 1267200, HFPLL, 1, 66 }, LVL_HIGH, 1050000, 3 },
+ [14] = { { 1344000, HFPLL, 1, 70 }, LVL_HIGH, 1050000, 3 },
+ [15] = { { 1420800, HFPLL, 1, 74 }, LVL_HIGH, 1050000, 3 },
+ [16] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 3 },
+ [17] = { { 1574400, HFPLL, 1, 82 }, LVL_HIGH, 1050000, 3 },
+ [18] = { { 1651200, HFPLL, 1, 86 }, LVL_HIGH, 1050000, 3 },
+ [19] = { { 1728000, HFPLL, 1, 90 }, LVL_HIGH, 1050000, 3 },
+ [20] = { { 1804800, HFPLL, 1, 94 }, LVL_HIGH, 1050000, 3 },
+ [21] = { { 1881600, HFPLL, 1, 98 }, LVL_HIGH, 1050000, 3 },
+ [22] = { { 1958400, HFPLL, 1, 102 }, LVL_HIGH, 1050000, 3 },
+ [23] = { { 2035200, HFPLL, 1, 106 }, LVL_HIGH, 1050000, 3 },
+ [24] = { { 2112000, HFPLL, 1, 110 }, LVL_HIGH, 1050000, 3 },
+ [25] = { { 2188800, HFPLL, 1, 114 }, LVL_HIGH, 1050000, 3 },
{ }
};
static struct acpu_level acpu_freq_tbl[] __initdata = {
- { 1, { 300000, PLL_0, 0, 2, 0 }, L2(0), 950000, 3200000 },
- { 1, { 384000, HFPLL, 2, 0, 40 }, L2(3), 950000, 3200000 },
- { 1, { 460800, HFPLL, 2, 0, 48 }, L2(3), 950000, 3200000 },
- { 1, { 537600, HFPLL, 1, 0, 28 }, L2(5), 950000, 3200000 },
- { 1, { 576000, HFPLL, 1, 0, 30 }, L2(5), 950000, 3200000 },
- { 1, { 652800, HFPLL, 1, 0, 34 }, L2(5), 950000, 3200000 },
- { 1, { 729600, HFPLL, 1, 0, 38 }, L2(5), 950000, 3200000 },
- { 1, { 806400, HFPLL, 1, 0, 42 }, L2(7), 950000, 3200000 },
- { 1, { 883200, HFPLL, 1, 0, 46 }, L2(7), 950000, 3200000 },
- { 1, { 960000, HFPLL, 1, 0, 50 }, L2(7), 950000, 3200000 },
- { 1, { 1036800, HFPLL, 1, 0, 54 }, L2(7), 950000, 3200000 },
- { 1, { 1113600, HFPLL, 1, 0, 58 }, L2(12), 1050000, 3200000 },
- { 1, { 1190400, HFPLL, 1, 0, 62 }, L2(12), 1050000, 3200000 },
- { 1, { 1267200, HFPLL, 1, 0, 66 }, L2(12), 1050000, 3200000 },
- { 1, { 1344000, HFPLL, 1, 0, 70 }, L2(15), 1050000, 3200000 },
- { 1, { 1420800, HFPLL, 1, 0, 74 }, L2(15), 1050000, 3200000 },
- { 1, { 1497600, HFPLL, 1, 0, 78 }, L2(16), 1050000, 3200000 },
- { 0, { 1574400, HFPLL, 1, 0, 82 }, L2(20), 1050000, 3200000 },
- { 0, { 1651200, HFPLL, 1, 0, 86 }, L2(20), 1050000, 3200000 },
- { 0, { 1728000, HFPLL, 1, 0, 90 }, L2(20), 1050000, 3200000 },
- { 0, { 1804800, HFPLL, 1, 0, 94 }, L2(25), 1050000, 3200000 },
- { 0, { 1881600, HFPLL, 1, 0, 98 }, L2(25), 1050000, 3200000 },
- { 0, { 1958400, HFPLL, 1, 0, 102 }, L2(25), 1050000, 3200000 },
- { 0, { 1996800, HFPLL, 1, 0, 104 }, L2(25), 1050000, 3200000 },
+ { 1, { 300000, PLL_0, 0, 0 }, L2(0), 950000, 3200000 },
+ { 1, { 384000, HFPLL, 2, 40 }, L2(3), 950000, 3200000 },
+ { 1, { 460800, HFPLL, 2, 48 }, L2(3), 950000, 3200000 },
+ { 1, { 537600, HFPLL, 1, 28 }, L2(5), 950000, 3200000 },
+ { 1, { 576000, HFPLL, 1, 30 }, L2(5), 950000, 3200000 },
+ { 1, { 652800, HFPLL, 1, 34 }, L2(5), 950000, 3200000 },
+ { 1, { 729600, HFPLL, 1, 38 }, L2(5), 950000, 3200000 },
+ { 1, { 806400, HFPLL, 1, 42 }, L2(7), 950000, 3200000 },
+ { 1, { 883200, HFPLL, 1, 46 }, L2(7), 950000, 3200000 },
+ { 1, { 960000, HFPLL, 1, 50 }, L2(7), 950000, 3200000 },
+ { 1, { 1036800, HFPLL, 1, 54 }, L2(7), 950000, 3200000 },
+ { 1, { 1113600, HFPLL, 1, 58 }, L2(12), 1050000, 3200000 },
+ { 1, { 1190400, HFPLL, 1, 62 }, L2(12), 1050000, 3200000 },
+ { 1, { 1267200, HFPLL, 1, 66 }, L2(12), 1050000, 3200000 },
+ { 1, { 1344000, HFPLL, 1, 70 }, L2(15), 1050000, 3200000 },
+ { 1, { 1420800, HFPLL, 1, 74 }, L2(15), 1050000, 3200000 },
+ { 1, { 1497600, HFPLL, 1, 78 }, L2(16), 1050000, 3200000 },
+ { 0, { 1574400, HFPLL, 1, 82 }, L2(20), 1050000, 3200000 },
+ { 0, { 1651200, HFPLL, 1, 86 }, L2(20), 1050000, 3200000 },
+ { 0, { 1728000, HFPLL, 1, 90 }, L2(20), 1050000, 3200000 },
+ { 0, { 1804800, HFPLL, 1, 94 }, L2(25), 1050000, 3200000 },
+ { 0, { 1881600, HFPLL, 1, 98 }, L2(25), 1050000, 3200000 },
+ { 0, { 1958400, HFPLL, 1, 102 }, L2(25), 1050000, 3200000 },
+ { 0, { 1996800, HFPLL, 1, 104 }, L2(25), 1050000, 3200000 },
{ 0, { 0 } }
};
-static struct pvs_table pvs_tables[NUM_PVS] __initdata = {
- [PVS_SLOW] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
- [PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
- [PVS_FAST] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+static struct pvs_table pvs_tables[NUM_SPEED_BINS][NUM_PVS] __initdata = {
+ [0][PVS_SLOW] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+ [0][PVS_NOMINAL] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
+ [0][PVS_FAST] = { acpu_freq_tbl, sizeof(acpu_freq_tbl) },
};
static struct acpuclk_krait_params acpuclk_8974_params __initdata = {
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index 2951c1a..57c4411 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -42,8 +42,8 @@
#define PRI_SRC_SEL_SEC_SRC 0
#define PRI_SRC_SEL_HFPLL 1
#define PRI_SRC_SEL_HFPLL_DIV2 2
-#define SEC_SRC_SEL_L2PLL 1
-#define SEC_SRC_SEL_AUX 2
+
+#define SECCLKAGD BIT(4)
static DEFINE_MUTEX(driver_lock);
static DEFINE_SPINLOCK(l2_lock);
@@ -79,14 +79,24 @@
}
/* Select a source on the secondary MUX. */
-static void set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
+static void __cpuinit set_sec_clk_src(struct scalable *sc, u32 sec_src_sel)
{
u32 regval;
+ /* 8064 Errata: disable sec_src clock gating during switch. */
regval = get_l2_indirect_reg(sc->l2cpmr_iaddr);
+ regval |= SECCLKAGD;
+ set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+ /* Program the MUX */
regval &= ~(0x3 << 2);
regval |= ((sec_src_sel & 0x3) << 2);
set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
+ /* 8064 Errata: re-enabled sec_src clock gating. */
+ regval &= ~SECCLKAGD;
+ set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
+
/* Wait for switch to complete. */
mb();
udelay(1);
@@ -220,7 +230,6 @@
* Move to an always-on source running at a frequency
* that does not require an elevated CPU voltage.
*/
- set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
/* Re-program HFPLL. */
@@ -231,15 +240,12 @@
/* Move to HFPLL. */
set_pri_clk_src(sc, tgt_s->pri_src_sel);
} else if (strt_s->src == HFPLL && tgt_s->src != HFPLL) {
- set_sec_clk_src(sc, tgt_s->sec_src_sel);
set_pri_clk_src(sc, tgt_s->pri_src_sel);
hfpll_disable(sc, false);
} else if (strt_s->src != HFPLL && tgt_s->src == HFPLL) {
hfpll_set_rate(sc, tgt_s);
hfpll_enable(sc, false);
set_pri_clk_src(sc, tgt_s->pri_src_sel);
- } else {
- set_sec_clk_src(sc, tgt_s->sec_src_sel);
}
sc->cur_speed = tgt_s;
@@ -709,7 +715,7 @@
}
/* Switch away from the HFPLL while it's re-initialized. */
- set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
+ set_sec_clk_src(sc, sc->sec_clk_sel);
set_pri_clk_src(sc, PRI_SRC_SEL_SEC_SRC);
hfpll_init(sc, tgt_s);
@@ -719,7 +725,6 @@
set_l2_indirect_reg(sc->l2cpmr_iaddr, regval);
/* Switch to the target clock source. */
- set_sec_clk_src(sc, tgt_s->sec_src_sel);
set_pri_clk_src(sc, tgt_s->pri_src_sel);
sc->cur_speed = tgt_s;
@@ -730,7 +735,6 @@
struct scalable *sc)
{
s->pri_src_sel = get_l2_indirect_reg(sc->l2cpmr_iaddr) & 0x3;
- s->sec_src_sel = (get_l2_indirect_reg(sc->l2cpmr_iaddr) >> 2) & 0x3;
s->pll_l_val = readl_relaxed(sc->hfpll_base + drv.hfpll_data->l_offset);
}
@@ -738,7 +742,6 @@
const struct core_speed *s2)
{
return (s1->pri_src_sel == s2->pri_src_sel &&
- s1->sec_src_sel == s2->sec_src_sel &&
s1->pll_l_val == s2->pll_l_val);
}
@@ -943,58 +946,68 @@
}
}
-static int __init select_freq_plan(u32 pte_efuse_phys)
+static int __init get_speed_bin(u32 pte_efuse)
+{
+ uint32_t speed_bin;
+
+ speed_bin = pte_efuse & 0xF;
+ if (speed_bin == 0xF)
+ speed_bin = (pte_efuse >> 4) & 0xF;
+
+ if (speed_bin == 0xF) {
+ speed_bin = 0;
+ dev_warn(drv.dev, "SPEED BIN: Defaulting to %d\n", speed_bin);
+ } else {
+ dev_info(drv.dev, "SPEED BIN: %d\n", speed_bin);
+ }
+
+ return speed_bin;
+}
+
+static int __init get_pvs_bin(u32 pte_efuse)
+{
+ uint32_t pvs_bin;
+
+ pvs_bin = (pte_efuse >> 10) & 0x7;
+ if (pvs_bin == 0x7)
+ pvs_bin = (pte_efuse >> 13) & 0x7;
+
+ if (pvs_bin == 0x7) {
+ pvs_bin = 0;
+ dev_warn(drv.dev, "ACPU PVS: Defaulting to %d\n", pvs_bin);
+ } else {
+ dev_info(drv.dev, "ACPU PVS: %d\n", pvs_bin);
+ }
+
+ return pvs_bin;
+}
+
+static struct pvs_table * __init select_freq_plan(u32 pte_efuse_phys,
+ struct pvs_table (*pvs_tables)[NUM_PVS])
{
void __iomem *pte_efuse;
- u32 pte_efuse_val, pvs, tbl_idx;
- char *pvs_names[] = { "Slow", "Nominal", "Fast", "Faster", "Unknown" };
+ u32 pte_efuse_val, tbl_idx, bin_idx;
pte_efuse = ioremap(pte_efuse_phys, 4);
- /* Select frequency tables. */
- if (pte_efuse) {
- pte_efuse_val = readl_relaxed(pte_efuse);
- pvs = (pte_efuse_val >> 10) & 0x7;
- iounmap(pte_efuse);
- if (pvs == 0x7)
- pvs = (pte_efuse_val >> 13) & 0x7;
-
- switch (pvs) {
- case 0x0:
- case 0x7:
- tbl_idx = PVS_SLOW;
- break;
- case 0x1:
- tbl_idx = PVS_NOMINAL;
- break;
- case 0x3:
- tbl_idx = PVS_FAST;
- break;
- case 0x4:
- tbl_idx = PVS_FASTER;
- break;
- default:
- tbl_idx = PVS_UNKNOWN;
- break;
- }
- } else {
- tbl_idx = PVS_UNKNOWN;
+ if (!pte_efuse) {
dev_err(drv.dev, "Unable to map QFPROM base\n");
- }
- if (tbl_idx == PVS_UNKNOWN) {
- tbl_idx = PVS_SLOW;
- dev_warn(drv.dev, "ACPU PVS: Defaulting to %s\n",
- pvs_names[tbl_idx]);
- } else {
- dev_info(drv.dev, "ACPU PVS: %s\n", pvs_names[tbl_idx]);
+ return NULL;
}
- return tbl_idx;
+ pte_efuse_val = readl_relaxed(pte_efuse);
+ iounmap(pte_efuse);
+
+ /* Select frequency tables. */
+ bin_idx = get_speed_bin(pte_efuse_val);
+ tbl_idx = get_pvs_bin(pte_efuse_val);
+
+ return &pvs_tables[bin_idx][tbl_idx];
}
static void __init drv_data_init(struct device *dev,
const struct acpuclk_krait_params *params)
{
- int tbl_idx;
+ struct pvs_table *pvs;
drv.dev = dev;
drv.scalable = kmemdup(params->scalable, params->scalable_size,
@@ -1017,12 +1030,12 @@
GFP_KERNEL);
BUG_ON(!drv.bus_scale->usecase);
- tbl_idx = select_freq_plan(params->pte_efuse_phys);
- drv.acpu_freq_tbl = kmemdup(params->pvs_tables[tbl_idx].table,
- params->pvs_tables[tbl_idx].size,
- GFP_KERNEL);
+ pvs = select_freq_plan(params->pte_efuse_phys, params->pvs_tables);
+ BUG_ON(!pvs->table);
+
+ drv.acpu_freq_tbl = kmemdup(pvs->table, pvs->size, GFP_KERNEL);
BUG_ON(!drv.acpu_freq_tbl);
- drv.boost_uv = params->pvs_tables[tbl_idx].boost_uv;
+ drv.boost_uv = pvs->boost_uv;
acpuclk_krait_data.power_collapse_khz = params->stby_khz;
acpuclk_krait_data.wait_for_irq_khz = params->stby_khz;
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index d615b85..3fa10e3 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -46,14 +46,18 @@
*/
enum pvs {
PVS_SLOW = 0,
- PVS_NOMINAL,
- PVS_FAST,
- PVS_FASTER,
- PVS_UNKNOWN,
- NUM_PVS
+ PVS_NOMINAL = 1,
+ PVS_FAST = 3,
+ PVS_FASTER = 4,
+ NUM_PVS = 7
};
/**
+ * The maximum number of speed bins.
+ */
+#define NUM_SPEED_BINS (16)
+
+/**
* enum scalables - IDs of frequency scalable hardware blocks.
*/
enum scalables {
@@ -111,14 +115,12 @@
* @khz: Clock rate in KHz.
* @src: Clock source ID.
* @pri_src_sel: Input to select on the primary MUX.
- * @sec_src_sel: Input to select on the secondary MUX.
* @pll_l_val: HFPLL "L" value to be applied when an HFPLL source is selected.
*/
struct core_speed {
unsigned long khz;
int src;
u32 pri_src_sel;
- u32 sec_src_sel;
u32 pll_l_val;
};
@@ -188,8 +190,8 @@
const bool has_droop_ctl;
const u32 droop_offset;
const u32 droop_val;
- const u32 low_vdd_l_max;
- const u32 nom_vdd_l_max;
+ u32 low_vdd_l_max;
+ u32 nom_vdd_l_max;
const u32 low_vco_l_max;
const int vdd[NUM_HFPLL_VDD];
};
@@ -200,6 +202,7 @@
* @hfpll_base: Virtual base address of HFPLL registers.
* @aux_clk_sel_phys: Physical address of auxiliary MUX.
* @aux_clk_sel: Auxiliary mux input to select at boot.
+ * @sec_clk_sel: Secondary mux input to select at boot.
* @l2cpmr_iaddr: Indirect address of the CPMR MUX/divider CP15 register.
* @cur_speed: Pointer to currently-set speed.
* @l2_vote: L2 performance level vote associate with the current CPU speed.
@@ -212,6 +215,7 @@
void __iomem *hfpll_base;
const phys_addr_t aux_clk_sel_phys;
const u32 aux_clk_sel;
+ const u32 sec_clk_sel;
const u32 l2cpmr_iaddr;
const struct core_speed *cur_speed;
unsigned int l2_vote;
@@ -237,7 +241,7 @@
* @scalable: Array of scalables.
* @scalable_size: Size of @scalable.
* @hfpll_data: HFPLL configuration data.
- * @pvs_tables: CPU frequency tables.
+ * @pvs_tables: 2D array of CPU frequency tables.
* @l2_freq_tbl: L2 frequency table.
* @l2_freq_tbl_size: Size of @l2_freq_tbl.
* @pte_efuse_phys: Physical address of PTE EFUSE.
@@ -248,7 +252,7 @@
struct scalable *scalable;
size_t scalable_size;
struct hfpll_data *hfpll_data;
- struct pvs_table *pvs_tables;
+ struct pvs_table (*pvs_tables)[NUM_PVS];
struct l2_level *l2_freq_tbl;
size_t l2_freq_tbl_size;
phys_addr_t pte_efuse_phys;
diff --git a/arch/arm/mach-msm/adsp-8974.c b/arch/arm/mach-msm/adsp-8974.c
index 050a24b..fa7d9d4 100644
--- a/arch/arm/mach-msm/adsp-8974.c
+++ b/arch/arm/mach-msm/adsp-8974.c
@@ -119,12 +119,17 @@
wmb();
}
+static void restart_adsp(void)
+{
+ adsp_log_failure_reason();
+ subsystem_restart("adsp");
+}
+
static void adsp_fatal_fn(struct work_struct *work)
{
pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
__func__);
- adsp_log_failure_reason();
- panic(MODULE_NAME ": Resetting the SoC");
+ restart_adsp();
}
static void adsp_smsm_state_cb(void *data, uint32_t old_state,
@@ -137,8 +142,7 @@
if (new_state & SMSM_RESET) {
pr_debug("%s: ADSP SMSM state changed to SMSM_RESET, new_state= 0x%x, old_state = 0x%x\n",
__func__, new_state, old_state);
- adsp_log_failure_reason();
- panic(MODULE_NAME ": Resetting the SoC");
+ restart_adsp();
}
}
@@ -156,7 +160,7 @@
/* The write needs to go through before the q6 is shutdown. */
mb();
- pil_force_shutdown("q6");
+ pil_force_shutdown("adsp");
disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
return 0;
@@ -171,7 +175,7 @@
msleep(10000);
}
- ret = pil_force_boot("q6");
+ ret = pil_force_boot("adsp");
enable_irq(ADSP_Q6SS_WDOG_EXPIRED);
return ret;
}
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index d5e4638..7ba22f4 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -171,7 +171,6 @@
#define A2_NUM_PIPES 6
#define A2_SUMMING_THRESHOLD 4096
-#define A2_DEFAULT_DESCRIPTORS 32
#define A2_PHYS_BASE 0x124C2000
#define A2_PHYS_SIZE 0x2000
#define BUFFER_SIZE 2048
@@ -223,6 +222,7 @@
static void rx_timer_work_func(struct work_struct *work);
static DECLARE_WORK(rx_timer_work, rx_timer_work_func);
+static struct delayed_work queue_rx_work;
static struct workqueue_struct *bam_mux_rx_workqueue;
static struct workqueue_struct *bam_mux_tx_workqueue;
@@ -430,21 +430,27 @@
rx_len_cached = bam_rx_pool_len;
mutex_unlock(&bam_rx_pool_mutexlock);
- while (rx_len_cached < NUM_BUFFERS) {
+ while (bam_connection_is_active && rx_len_cached < NUM_BUFFERS) {
if (in_global_reset)
goto fail;
- info = kmalloc(sizeof(struct rx_pkt_info), GFP_KERNEL);
+ info = kmalloc(sizeof(struct rx_pkt_info),
+ GFP_NOWAIT | __GFP_NOWARN);
if (!info) {
- pr_err("%s: unable to alloc rx_pkt_info\n", __func__);
+ DMUX_LOG_KERR(
+ "%s: unable to alloc rx_pkt_info, will retry later\n",
+ __func__);
goto fail;
}
INIT_WORK(&info->work, handle_bam_mux_cmd);
- info->skb = __dev_alloc_skb(BUFFER_SIZE, GFP_KERNEL);
+ info->skb = __dev_alloc_skb(BUFFER_SIZE,
+ GFP_NOWAIT | __GFP_NOWARN);
if (info->skb == NULL) {
- DMUX_LOG_KERR("%s: unable to alloc skb\n", __func__);
+ DMUX_LOG_KERR(
+ "%s: unable to alloc skb, will retry later\n",
+ __func__);
goto fail_info;
}
ptr = skb_put(info->skb, BUFFER_SIZE);
@@ -488,11 +494,16 @@
fail:
if (rx_len_cached == 0) {
- DMUX_LOG_KERR("%s: RX queue failure\n", __func__);
- in_global_reset = 1;
+ DMUX_LOG_KERR("%s: rescheduling\n", __func__);
+ schedule_delayed_work(&queue_rx_work, msecs_to_jiffies(100));
}
}
+static void queue_rx_work_func(struct work_struct *work)
+{
+ queue_rx();
+}
+
static void bam_mux_process_data(struct sk_buff *rx_skb)
{
unsigned long flags;
@@ -2422,6 +2433,7 @@
init_completion(&bam_connection_completion);
init_completion(&dfab_unvote_completion);
INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
+ INIT_DELAYED_WORK(&queue_rx_work, queue_rx_work_func);
wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
diff --git a/arch/arm/mach-msm/batterydata-lib.c b/arch/arm/mach-msm/batterydata-lib.c
new file mode 100644
index 0000000..2be591c
--- /dev/null
+++ b/arch/arm/mach-msm/batterydata-lib.c
@@ -0,0 +1,338 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
+
+int linear_interpolate(int y0, int x0, int y1, int x1, int x)
+{
+ if (y0 == y1 || x == x0)
+ return y0;
+ if (x1 == x0 || x == x1)
+ return y1;
+
+ return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
+}
+
+int is_between(int left, int right, int value)
+{
+ if (left >= right && left >= value && value >= right)
+ return 1;
+ if (left <= right && left <= value && value <= right)
+ return 1;
+ return 0;
+}
+
+static int interpolate_single_lut(struct single_row_lut *lut, int x)
+{
+ int i, result;
+
+ if (x < lut->x[0]) {
+ pr_debug("x %d less than known range return y = %d lut = %pS\n",
+ x, lut->y[0], lut);
+ return lut->y[0];
+ }
+ if (x > lut->x[lut->cols - 1]) {
+ pr_debug("x %d more than known range return y = %d lut = %pS\n",
+ x, lut->y[lut->cols - 1], lut);
+ return lut->y[lut->cols - 1];
+ }
+
+ for (i = 0; i < lut->cols; i++)
+ if (x <= lut->x[i])
+ break;
+ if (x == lut->x[i]) {
+ result = lut->y[i];
+ } else {
+ result = linear_interpolate(
+ lut->y[i - 1],
+ lut->x[i - 1],
+ lut->y[i],
+ lut->x[i],
+ x);
+ }
+ return result;
+}
+
+int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp)
+{
+ /* batt_temp is in tenths of degC - convert it to degC for lookups */
+ batt_temp = batt_temp/10;
+ return interpolate_single_lut(fcc_temp_lut, batt_temp);
+}
+
+int interpolate_scalingfactor_fcc(struct single_row_lut *fcc_sf_lut,
+ int cycles)
+{
+ /*
+ * sf table could be null when no battery aging data is available, in
+ * that case return 100%
+ */
+ if (fcc_sf_lut)
+ return interpolate_single_lut(fcc_sf_lut, cycles);
+ else
+ return 100;
+}
+
+int interpolate_scalingfactor(struct sf_lut *sf_lut, int row_entry, int pc)
+{
+ int i, scalefactorrow1, scalefactorrow2, scalefactor, rows, cols;
+ int row1 = 0;
+ int row2 = 0;
+
+ /*
+ * sf table could be null when no battery aging data is available, in
+ * that case return 100%
+ */
+ if (!sf_lut)
+ return 100;
+
+ rows = sf_lut->rows;
+ cols = sf_lut->cols;
+ if (pc > sf_lut->percent[0]) {
+ pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
+ row1 = 0;
+ row2 = 0;
+ }
+ if (pc < sf_lut->percent[rows - 1]) {
+ pr_debug("pc %d less than known pc ranges for sf\n", pc);
+ row1 = rows - 1;
+ row2 = rows - 1;
+ }
+ for (i = 0; i < rows; i++) {
+ if (pc == sf_lut->percent[i]) {
+ row1 = i;
+ row2 = i;
+ break;
+ }
+ if (pc > sf_lut->percent[i]) {
+ row1 = i - 1;
+ row2 = i;
+ break;
+ }
+ }
+
+ if (row_entry < sf_lut->row_entries[0])
+ row_entry = sf_lut->row_entries[0];
+ if (row_entry > sf_lut->row_entries[cols - 1])
+ row_entry = sf_lut->row_entries[cols - 1];
+
+ for (i = 0; i < cols; i++)
+ if (row_entry <= sf_lut->row_entries[i])
+ break;
+ if (row_entry == sf_lut->row_entries[i]) {
+ scalefactor = linear_interpolate(
+ sf_lut->sf[row1][i],
+ sf_lut->percent[row1],
+ sf_lut->sf[row2][i],
+ sf_lut->percent[row2],
+ pc);
+ return scalefactor;
+ }
+
+ scalefactorrow1 = linear_interpolate(
+ sf_lut->sf[row1][i - 1],
+ sf_lut->row_entries[i - 1],
+ sf_lut->sf[row1][i],
+ sf_lut->row_entries[i],
+ row_entry);
+
+ scalefactorrow2 = linear_interpolate(
+ sf_lut->sf[row2][i - 1],
+ sf_lut->row_entries[i - 1],
+ sf_lut->sf[row2][i],
+ sf_lut->row_entries[i],
+ row_entry);
+
+ scalefactor = linear_interpolate(
+ scalefactorrow1,
+ sf_lut->percent[row1],
+ scalefactorrow2,
+ sf_lut->percent[row2],
+ pc);
+
+ return scalefactor;
+}
+
+/* get ocv given a soc -- reverse lookup */
+int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
+ int batt_temp_degc, int pc)
+{
+ int i, ocvrow1, ocvrow2, ocv, rows, cols;
+ int row1 = 0;
+ int row2 = 0;
+
+ rows = pc_temp_ocv->rows;
+ cols = pc_temp_ocv->cols;
+ if (pc > pc_temp_ocv->percent[0]) {
+ pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
+ row1 = 0;
+ row2 = 0;
+ }
+ if (pc < pc_temp_ocv->percent[rows - 1]) {
+ pr_debug("pc %d less than known pc ranges for sf\n", pc);
+ row1 = rows - 1;
+ row2 = rows - 1;
+ }
+ for (i = 0; i < rows; i++) {
+ if (pc == pc_temp_ocv->percent[i]) {
+ row1 = i;
+ row2 = i;
+ break;
+ }
+ if (pc > pc_temp_ocv->percent[i]) {
+ row1 = i - 1;
+ row2 = i;
+ break;
+ }
+ }
+
+ if (batt_temp_degc < pc_temp_ocv->temp[0])
+ batt_temp_degc = pc_temp_ocv->temp[0];
+ if (batt_temp_degc > pc_temp_ocv->temp[cols - 1])
+ batt_temp_degc = pc_temp_ocv->temp[cols - 1];
+
+ for (i = 0; i < cols; i++)
+ if (batt_temp_degc <= pc_temp_ocv->temp[i])
+ break;
+ if (batt_temp_degc == pc_temp_ocv->temp[i]) {
+ ocv = linear_interpolate(
+ pc_temp_ocv->ocv[row1][i],
+ pc_temp_ocv->percent[row1],
+ pc_temp_ocv->ocv[row2][i],
+ pc_temp_ocv->percent[row2],
+ pc);
+ return ocv;
+ }
+
+ ocvrow1 = linear_interpolate(
+ pc_temp_ocv->ocv[row1][i - 1],
+ pc_temp_ocv->temp[i - 1],
+ pc_temp_ocv->ocv[row1][i],
+ pc_temp_ocv->temp[i],
+ batt_temp_degc);
+
+ ocvrow2 = linear_interpolate(
+ pc_temp_ocv->ocv[row2][i - 1],
+ pc_temp_ocv->temp[i - 1],
+ pc_temp_ocv->ocv[row2][i],
+ pc_temp_ocv->temp[i],
+ batt_temp_degc);
+
+ ocv = linear_interpolate(
+ ocvrow1,
+ pc_temp_ocv->percent[row1],
+ ocvrow2,
+ pc_temp_ocv->percent[row2],
+ pc);
+
+ return ocv;
+}
+
+int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv,
+ int batt_temp_degc, int ocv)
+{
+ int i, j, pcj, pcj_minus_one, pc;
+ int rows = pc_temp_ocv->rows;
+ int cols = pc_temp_ocv->cols;
+
+ if (batt_temp_degc < pc_temp_ocv->temp[0]) {
+ pr_debug("batt_temp %d < known temp range\n", batt_temp_degc);
+ batt_temp_degc = pc_temp_ocv->temp[0];
+ }
+
+ if (batt_temp_degc > pc_temp_ocv->temp[cols - 1]) {
+ pr_debug("batt_temp %d > known temp range\n", batt_temp_degc);
+ batt_temp_degc = pc_temp_ocv->temp[cols - 1];
+ }
+
+ for (j = 0; j < cols; j++)
+ if (batt_temp_degc <= pc_temp_ocv->temp[j])
+ break;
+ if (batt_temp_degc == pc_temp_ocv->temp[j]) {
+ /* found an exact match for temp in the table */
+ if (ocv >= pc_temp_ocv->ocv[0][j])
+ return pc_temp_ocv->percent[0];
+ if (ocv <= pc_temp_ocv->ocv[rows - 1][j])
+ return pc_temp_ocv->percent[rows - 1];
+ for (i = 0; i < rows; i++) {
+ if (ocv >= pc_temp_ocv->ocv[i][j]) {
+ if (ocv == pc_temp_ocv->ocv[i][j])
+ return pc_temp_ocv->percent[i];
+ pc = linear_interpolate(
+ pc_temp_ocv->percent[i],
+ pc_temp_ocv->ocv[i][j],
+ pc_temp_ocv->percent[i - 1],
+ pc_temp_ocv->ocv[i - 1][j],
+ ocv);
+ return pc;
+ }
+ }
+ }
+
+ /*
+ * batt_temp_degc is within temperature for
+ * column j-1 and j
+ */
+ if (ocv >= pc_temp_ocv->ocv[0][j])
+ return pc_temp_ocv->percent[0];
+ if (ocv <= pc_temp_ocv->ocv[rows - 1][j - 1])
+ return pc_temp_ocv->percent[rows - 1];
+
+ pcj_minus_one = 0;
+ pcj = 0;
+ for (i = 0; i < rows-1; i++) {
+ if (pcj == 0
+ && is_between(pc_temp_ocv->ocv[i][j],
+ pc_temp_ocv->ocv[i+1][j], ocv)) {
+ pcj = linear_interpolate(
+ pc_temp_ocv->percent[i],
+ pc_temp_ocv->ocv[i][j],
+ pc_temp_ocv->percent[i + 1],
+ pc_temp_ocv->ocv[i+1][j],
+ ocv);
+ }
+
+ if (pcj_minus_one == 0
+ && is_between(pc_temp_ocv->ocv[i][j-1],
+ pc_temp_ocv->ocv[i+1][j-1], ocv)) {
+ pcj_minus_one = linear_interpolate(
+ pc_temp_ocv->percent[i],
+ pc_temp_ocv->ocv[i][j-1],
+ pc_temp_ocv->percent[i + 1],
+ pc_temp_ocv->ocv[i+1][j-1],
+ ocv);
+ }
+
+ if (pcj && pcj_minus_one) {
+ pc = linear_interpolate(
+ pcj_minus_one,
+ pc_temp_ocv->temp[j-1],
+ pcj,
+ pc_temp_ocv->temp[j],
+ batt_temp_degc);
+ return pc;
+ }
+ }
+
+ if (pcj)
+ return pcj;
+
+ if (pcj_minus_one)
+ return pcj_minus_one;
+
+ pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%\n",
+ ocv, batt_temp_degc);
+ return 100;
+}
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
index f362a72..d9fa061 100644
--- a/arch/arm/mach-msm/bms-batterydata-desay.c
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mfd/pm8xxx/pm8921-bms.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
static struct single_row_lut desay_5200_fcc_temp = {
.x = {-20, 0, 25, 40},
@@ -76,7 +76,7 @@
},
};
-struct pm8921_bms_battery_data desay_5200_data = {
+struct bms_battery_data desay_5200_data = {
.fcc = 5200,
.fcc_temp_lut = &desay_5200_fcc_temp,
.fcc_sf_lut = &desay_5200_fcc_sf,
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 81ab121..fb4f967 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-#include <linux/mfd/pm8xxx/pm8921-bms.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
static struct single_row_lut fcc_temp = {
.x = {-20, 0, 25, 40, 65},
@@ -99,7 +99,7 @@
}
};
-struct pm8921_bms_battery_data palladium_1500_data = {
+struct bms_battery_data palladium_1500_data = {
.fcc = 1500,
.fcc_temp_lut = &fcc_temp,
.pc_temp_ocv_lut = &pc_temp_ocv,
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index c79f82f..0a95e51 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -503,6 +503,34 @@
.i2c_mux_mode = MODE_L,
};
+static struct msm_camera_sensor_flash_data flash_imx135 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_csi_lane_params imx135_csi_lane_params = {
+ .csi_lane_assign = 0xE4,
+ .csi_lane_mask = 0xF,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx135 = {
+ .mount_angle = 90,
+ .cam_vreg = apq_8064_cam_vreg,
+ .num_vreg = ARRAY_SIZE(apq_8064_cam_vreg),
+ .gpio_conf = &apq8064_back_cam_gpio_conf,
+ .i2c_conf = &apq8064_back_cam_i2c_conf,
+ .csi_lane_params = &imx135_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx135_data = {
+ .sensor_name = "imx135",
+ .pdata = &msm_camera_csi_device_data[0],
+ .flash_data = &flash_imx135,
+ .sensor_platform_info = &sensor_board_info_imx135,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
+};
+
static struct msm_camera_sensor_flash_data flash_imx074 = {
.flash_type = MSM_CAMERA_FLASH_LED,
.flash_src = &msm_flash_src
@@ -700,6 +728,10 @@
.platform_data = &msm_camera_sensor_imx074_data,
},
{
+ I2C_BOARD_INFO("imx135", 0x10),
+ .platform_data = &msm_camera_sensor_imx135_data,
+ },
+ {
I2C_BOARD_INFO("mt9m114", 0x48),
.platform_data = &msm_camera_sensor_mt9m114_data,
},
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index a08f45c..cb03d4b 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -31,6 +31,7 @@
.drv = GPIOMUX_DRV_8MA,
.func = GPIOMUX_FUNC_GPIO,
};
+#endif
/* The SPI configurations apply to GSBI 5*/
static struct gpiomux_setting gpio_spi_config = {
@@ -60,6 +61,7 @@
.pull = GPIOMUX_PULL_UP,
};
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
struct msm_gpiomux_config apq8064_ethernet_configs[] = {
{
.gpio = 43,
@@ -361,6 +363,22 @@
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting audio_auxpcm[] = {
+/* Suspended state */
+ {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+/* Active state */
+ {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+};
+
+
static struct gpiomux_setting wcnss_5wire_suspend_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -682,7 +700,6 @@
[GPIOMUX_SUSPENDED] = &gsbi1_uart_config,
},
},
-#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
{
.gpio = 51, /* GSBI5 QUP SPI_DATA_MOSI */
.settings = {
@@ -713,7 +730,6 @@
[GPIOMUX_SUSPENDED] = &gpio_spi_config,
},
},
-#endif
{
.gpio = 30, /* FP CS */
.settings = {
@@ -846,6 +862,37 @@
},
};
+static struct msm_gpiomux_config mpq8064_audio_auxpcm_configs[] __initdata = {
+ {
+ .gpio = 43,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 44,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 45,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+ {
+ .gpio = 46,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_auxpcm[0],
+ [GPIOMUX_ACTIVE] = &audio_auxpcm[1],
+ },
+ },
+};
+
/* External 3.3 V regulator enable */
static struct msm_gpiomux_config apq8064_ext_regulator_configs[] __initdata = {
{
@@ -1527,6 +1574,10 @@
if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
machine_is_mpq8064_dtv()) {
+
+ msm_gpiomux_install(mpq8064_audio_auxpcm_configs,
+ ARRAY_SIZE(mpq8064_audio_auxpcm_configs));
+
msm_gpiomux_install(mpq8064_spkr_i2s_config,
ARRAY_SIZE(mpq8064_spkr_i2s_config));
}
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 122505e..fad7092 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,26 +24,51 @@
#ifdef CONFIG_MSM_DCVS
static struct msm_dcvs_freq_entry grp3d_freq[] = {
- {0, 0, 333932},
- {0, 0, 497532},
- {0, 0, 707610},
- {0, 0, 844545},
+ {0, 900, 0, 0, 0},
+ {0, 950, 0, 0, 0},
+ {0, 950, 0, 0, 0},
+ {0, 1200, 1, 100, 100},
};
static struct msm_dcvs_core_info grp3d_core_info = {
- .freq_tbl = &grp3d_freq[0],
- .core_param = {
- .max_time_us = 100000,
- .num_freq = ARRAY_SIZE(grp3d_freq),
+ .freq_tbl = &grp3d_freq[0],
+ .num_cores = 1,
+ .sensors = (int[]){0},
+ .thermal_poll_ms = 60000,
+ .core_param = {
+ .core_type = MSM_DCVS_CORE_TYPE_GPU,
},
- .algo_param = {
- .slack_time_us = 39000,
- .disable_pc_threshold = 86000,
- .ss_window_size = 1000000,
- .ss_util_pct = 95,
- .em_max_util_pct = 97,
- .ss_iobusy_conv = 100,
+ .algo_param = {
+ .disable_pc_threshold = 0,
+ .em_win_size_min_us = 100000,
+ .em_win_size_max_us = 300000,
+ .em_max_util_pct = 97,
+ .group_id = 0,
+ .max_freq_chg_time_us = 100000,
+ .slack_mode_dynamic = 0,
+ .slack_time_min_us = 39000,
+ .slack_time_max_us = 39000,
+ .ss_win_size_min_us = 1000000,
+ .ss_win_size_max_us = 1000000,
+ .ss_util_pct = 95,
+ .ss_iobusy_conv = 100,
},
+
+ .energy_coeffs = {
+ .leakage_coeff_a = -17720,
+ .leakage_coeff_b = 37,
+ .leakage_coeff_c = 3329,
+ .leakage_coeff_d = -277,
+
+ .active_coeff_a = 2492,
+ .active_coeff_b = 0,
+ .active_coeff_c = 0
+ },
+
+ .power_param = {
+ .current_temp = 25,
+ .num_freq = ARRAY_SIZE(grp3d_freq),
+ }
};
#endif /* CONFIG_MSM_DCVS */
@@ -251,11 +276,17 @@
{
unsigned int version = socinfo_get_version();
- if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
- (SOCINFO_VERSION_MINOR(version) == 1))
- kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 1);
- else
- kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 0);
+ if (cpu_is_apq8064ab())
+ kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 450000000;
+ if (SOCINFO_VERSION_MAJOR(version) == 2) {
+ kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 2);
+ } else {
+ if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+ (SOCINFO_VERSION_MINOR(version) == 1))
+ kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 1);
+ else
+ kgsl_3d0_pdata.chipid = ADRENO_CHIPID(3, 2, 0, 0);
+ }
platform_device_register(&device_kgsl_3d0);
}
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 3b47d2e..f6423c8 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -115,7 +115,6 @@
/* Initial PM8921 GPIO configurations */
static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
PM8921_GPIO_OUTPUT(14, 1, HIGH), /* HDMI Mux Selector */
- PM8921_GPIO_OUTPUT(23, 0, HIGH), /* touchscreen power FET */
PM8921_GPIO_OUTPUT_BUFCONF(25, 0, LOW, CMOS), /* DISP_RESET_N */
PM8921_GPIO_OUTPUT_FUNC(26, 0, PM_GPIO_FUNC_2), /* Bl: Off, PWM mode */
PM8921_GPIO_OUTPUT_VIN(30, 1, PM_GPIO_VIN_VPH), /* SMB349 susp line */
@@ -146,10 +145,13 @@
PM8921_GPIO_OUTPUT(37, 0, LOW), /* MUX1_SEL */
};
+static struct pm8xxx_gpio_init touchscreen_gpios[] __initdata = {
+ PM8921_GPIO_OUTPUT(23, 0, HIGH), /* touchscreen power FET */
+};
+
/* Initial PM8917 GPIO configurations */
static struct pm8xxx_gpio_init pm8917_gpios[] __initdata = {
PM8921_GPIO_OUTPUT(14, 1, HIGH), /* HDMI Mux Selector */
- PM8921_GPIO_OUTPUT(23, 0, HIGH), /* touchscreen power FET */
PM8921_GPIO_OUTPUT_BUFCONF(25, 0, LOW, CMOS), /* DISP_RESET_N */
PM8921_GPIO_OUTPUT(26, 1, HIGH), /* Backlight: on */
PM8921_GPIO_OUTPUT_BUFCONF(36, 1, LOW, OPEN_DRAIN),
@@ -210,6 +212,8 @@
apq8064_configure_gpios(pm8917_gpios, ARRAY_SIZE(pm8917_gpios));
if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid()) {
+ apq8064_configure_gpios(touchscreen_gpios,
+ ARRAY_SIZE(touchscreen_gpios));
if (socinfo_get_pmic_model() != PMIC_MODEL_PM8917)
apq8064_configure_gpios(pm8921_cdp_kp_gpios,
ARRAY_SIZE(pm8921_cdp_kp_gpios));
@@ -395,6 +399,8 @@
.max_voltage = MAX_VOLTAGE_MV,
.min_voltage = 3200,
.uvd_thresh_voltage = 4050,
+ .alarm_low_mv = 3400,
+ .alarm_high_mv = 4000,
.resume_voltage_delta = 100,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 6cdafbc..851f7d9 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -64,6 +64,7 @@
VREG_CONSUMERS(L8) = {
REGULATOR_SUPPLY("8921_l8", NULL),
REGULATOR_SUPPLY("cam_vana", "4-001a"),
+ REGULATOR_SUPPLY("cam_vana", "4-0010"),
REGULATOR_SUPPLY("cam_vana", "4-0048"),
REGULATOR_SUPPLY("cam_vana", "4-006c"),
REGULATOR_SUPPLY("cam_vana", "4-0034"),
@@ -84,6 +85,7 @@
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("cam_vdig", "4-001a"),
+ REGULATOR_SUPPLY("cam_vdig", "4-0010"),
REGULATOR_SUPPLY("cam_vdig", "4-0048"),
REGULATOR_SUPPLY("cam_vdig", "4-006c"),
REGULATOR_SUPPLY("cam_vdig", "4-0034"),
@@ -102,6 +104,7 @@
VREG_CONSUMERS(L16) = {
REGULATOR_SUPPLY("8921_l16", NULL),
REGULATOR_SUPPLY("cam_vaf", "4-001a"),
+ REGULATOR_SUPPLY("cam_vaf", "4-0010"),
REGULATOR_SUPPLY("cam_vaf", "4-0048"),
REGULATOR_SUPPLY("cam_vaf", "4-006c"),
REGULATOR_SUPPLY("cam_vaf", "4-0034"),
@@ -121,8 +124,6 @@
};
VREG_CONSUMERS(L23) = {
REGULATOR_SUPPLY("8921_l23", NULL),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
REGULATOR_SUPPLY("HSUSB_1p8", "msm_ehci_host.0"),
REGULATOR_SUPPLY("HSUSB_1p8", "msm_ehci_host.1"),
};
@@ -141,15 +142,13 @@
};
VREG_CONSUMERS(L26) = {
REGULATOR_SUPPLY("8921_l26", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.0"),
+ REGULATOR_SUPPLY("core_vdd", "pil-q6v4-lpass"),
};
VREG_CONSUMERS(L27) = {
REGULATOR_SUPPLY("8921_l27", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.2"),
};
VREG_CONSUMERS(L28) = {
REGULATOR_SUPPLY("8921_l28", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.1"),
};
VREG_CONSUMERS(L29) = {
REGULATOR_SUPPLY("8921_l29", NULL),
@@ -218,6 +217,7 @@
VREG_CONSUMERS(LVS5) = {
REGULATOR_SUPPLY("8921_lvs5", NULL),
REGULATOR_SUPPLY("cam_vio", "4-001a"),
+ REGULATOR_SUPPLY("cam_vio", "4-0010"),
REGULATOR_SUPPLY("cam_vio", "4-0048"),
REGULATOR_SUPPLY("cam_vio", "4-006c"),
REGULATOR_SUPPLY("cam_vio", "4-0034"),
@@ -771,4 +771,10 @@
= ARRAY_SIZE(vreg_consumers_8917_S1);
}
}
+
+ /*
+ * Switch to 8960_PM8917 rpm-regulator version so that TCXO workaround
+ * is applied to PM8917 regulators L25, L26, L27, and L28.
+ */
+ apq8064_rpm_regulator_pdata.version = RPM_VREG_VERSION_8960_PM8917;
}
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index c81a637..379d7ae 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -338,6 +338,11 @@
apq8064_add_sdcc(2, apq8064_sdc2_pdata);
if (apq8064_sdc3_pdata) {
+ if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+ apq8064_sdc3_pdata->uhs_caps &= ~(MMC_CAP_UHS_SDR12 |
+ MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_DDR50 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104);
+ }
if (!machine_is_apq8064_cdp()) {
apq8064_sdc3_pdata->wpswitch_gpio = 0;
apq8064_sdc3_pdata->is_wpswitch_active_low = false;
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 07acac6..b3add3b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -470,7 +470,8 @@
const struct ion_platform_heap *heap =
&(apq8064_ion_pdata.heaps[i]);
- if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+ if (heap->type == (enum ion_heap_type) ION_HEAP_TYPE_CP
+ && heap->extra_data) {
struct ion_cp_heap_pdata *data = heap->extra_data;
reusable_count += (data->reusable) ? 1 : 0;
@@ -492,7 +493,7 @@
int fixed_position = NOT_FIXED;
int mem_is_fmem = 0;
- switch (heap->type) {
+ switch ((int)heap->type) {
case ION_HEAP_TYPE_CP:
mem_is_fmem = ((struct ion_cp_heap_pdata *)
heap->extra_data)->mem_is_fmem;
@@ -553,7 +554,7 @@
int fixed_position = NOT_FIXED;
struct ion_cp_heap_pdata *pdata = NULL;
- switch (heap->type) {
+ switch ((int) heap->type) {
case ION_HEAP_TYPE_CP:
pdata =
(struct ion_cp_heap_pdata *)heap->extra_data;
@@ -604,6 +605,11 @@
#endif
}
+static void __init reserve_mpdcvs_memory(void)
+{
+ apq8064_reserve_table[MEMTYPE_EBI1].size += SZ_32K;
+}
+
static void __init apq8064_calculate_reserve_sizes(void)
{
size_pmem_devices();
@@ -612,6 +618,7 @@
reserve_mdp_memory();
reserve_rtb_memory();
reserve_cache_dump_memory();
+ reserve_mpdcvs_memory();
}
static struct reserve_info apq8064_reserve_info __initdata = {
@@ -926,7 +933,8 @@
static void __init apq8064_ehci_host_init(void)
{
if (machine_is_apq8064_liquid() || machine_is_mpq8064_cdp() ||
- machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+ machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv() ||
+ machine_is_apq8064_cdp()) {
if (machine_is_apq8064_liquid())
msm_ehci_host_pdata3.dock_connect_irq =
PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9);
@@ -1768,6 +1776,27 @@
},
};
+static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 70000000UL,
+ .ib = 70000000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT1,
+ .dst = MSM_BUS_SLAVE_GSBI1_UART,
+ .ab = 2480000000UL,
+ .ib = 2480000000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPDM,
+ .dst = MSM_BUS_SLAVE_SPDM,
+ .ib = (64 * 8) * 1000000UL,
+ .ab = (64 * 8) * 100000UL,
+ },
+};
+
static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
{
ARRAY_SIZE(qseecom_clks_init_vectors),
@@ -1781,6 +1810,10 @@
ARRAY_SIZE(qseecom_enable_sfpb_vectors),
qseecom_enable_sfpb_vectors,
},
+ {
+ ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors),
+ qseecom_enable_dfab_sfpb_vectors,
+ },
};
static struct msm_bus_scale_pdata qseecom_bus_pdata = {
@@ -1930,6 +1963,7 @@
.ramdump_delay_ms = 2000,
.early_power_on = 1,
.sfr_query = 1,
+ .send_shdn = 1,
.vddmin_resource = &mdm_vddmin_rscs,
.peripheral_platform_device = &apq8064_device_hsic_host,
.ramdump_timeout_ms = 120000,
@@ -2440,7 +2474,6 @@
&apq8064_device_ext_3p3v_vreg,
&apq8064_device_ssbi_pmic1,
&apq8064_device_ssbi_pmic2,
- &apq8064_device_ext_ts_sw_vreg,
};
static struct platform_device *pm8917_common_devices[] __initdata = {
@@ -2448,7 +2481,6 @@
&apq8064_device_ext_3p3v_vreg,
&apq8064_device_ssbi_pmic1,
&apq8064_device_ssbi_pmic2,
- &apq8064_device_ext_ts_sw_vreg,
};
static struct platform_device *common_devices[] __initdata = {
@@ -2530,6 +2562,7 @@
&apq8064_rpm_device,
&apq8064_rpm_log_device,
&apq8064_rpm_stat_device,
+ &apq8064_rpm_master_stat_device,
&apq_device_tz_log,
&msm_bus_8064_apps_fabric,
&msm_bus_8064_sys_fabric,
@@ -2542,7 +2575,7 @@
&msm_pil_vidc,
&msm_gss,
&apq8064_rtb_device,
- &apq8064_cpu_idle_device,
+ &apq8064_msm_gov_device,
&apq8064_device_cache_erp,
&msm8960_device_ebi1_ch0_erp,
&msm8960_device_ebi1_ch1_erp,
@@ -2566,6 +2599,7 @@
#ifdef CONFIG_BATTERY_BCL
&battery_bcl_device,
#endif
+ &apq8064_msm_mpd_device,
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -2575,6 +2609,7 @@
#ifdef CONFIG_MSM_ROTATOR
&msm_rotator_device,
#endif
+ &msm8064_pc_cntr,
};
static struct platform_device
@@ -3344,6 +3379,8 @@
else
platform_add_devices(pm8917_common_devices,
ARRAY_SIZE(pm8917_common_devices));
+ if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
+ platform_device_register(&apq8064_device_ext_ts_sw_vreg);
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
machine_is_mpq8064_dtv()))
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 9545c7a..767736f 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -46,6 +46,8 @@
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("iface_clk", HSUSB_IFACE_CLK, "msm_otg", OFF),
+ CLK_DUMMY("core_clk", HSUSB_CORE_CLK, "msm_otg", OFF),
};
struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -62,6 +64,8 @@
static struct of_dev_auxdata msm8226_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
"msm_serial_hsl.0", NULL),
+ OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
+ "msm_otg", NULL),
{}
};
diff --git a/arch/arm/mach-msm/board-8910.c b/arch/arm/mach-msm/board-8910.c
new file mode 100644
index 0000000..18463e3
--- /dev/null
+++ b/arch/arm/mach-msm/board-8910.c
@@ -0,0 +1,94 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/memory.h>
+#include <asm/mach/map.h>
+#include <asm/arch_timer.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#ifdef CONFIG_ION_MSM
+#include <mach/ion.h>
+#endif
+#include <mach/socinfo.h>
+#include <mach/board.h>
+#include <mach/clk-provider.h>
+#include "clock.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),
+};
+
+struct clock_init_data msm_dummy_clock_init_data __initdata = {
+ .table = msm_clocks_dummy,
+ .size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+static struct of_device_id irq_match[] __initdata = {
+ { .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
+ { .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+ {},
+};
+
+static void __init msm8910_dt_timer_init(void)
+{
+ arch_timer_of_register();
+}
+
+static struct sys_timer msm8910_dt_timer = {
+ .init = msm8910_dt_timer_init
+};
+
+void __init msm8910_init_irq(void)
+{
+ of_irq_init(irq_match);
+}
+
+void __init msm8910_init(void)
+{
+ msm_clock_init(&msm_dummy_clock_init_data);
+
+ if (socinfo_init() < 0)
+ pr_err("%s: socinfo_init() failed\n", __func__);
+
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *msm8910_dt_match[] __initconst = {
+ "qcom,msm8910",
+ NULL
+};
+
+DT_MACHINE_START(MSM8910_DT, "Qualcomm MSM 8910 (Flattened Device Tree)")
+ .map_io = msm_map_msm8910_io,
+ .init_irq = msm8910_init_irq,
+ .init_machine = msm8910_init,
+ .handle_irq = gic_handle_irq,
+ .timer = &msm8910_dt_timer,
+ .dt_compat = msm8910_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 59e4ba1..402aec4 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -320,6 +320,8 @@
.max_voltage = MAX_VOLTAGE_MV,
.min_voltage = 3200,
.uvd_thresh_voltage = 4050,
+ .alarm_low_mv = 3400,
+ .alarm_high_mv = 4000,
.resume_voltage_delta = 100,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index 208f15b..16a82b4 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -117,7 +117,7 @@
};
VREG_CONSUMERS(L16) = {
REGULATOR_SUPPLY("8038_l16", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.2"),
+ REGULATOR_SUPPLY("sw_core_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L17) = {
REGULATOR_SUPPLY("8038_l17", NULL),
@@ -127,7 +127,7 @@
};
VREG_CONSUMERS(L19) = {
REGULATOR_SUPPLY("8038_l19", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.1"),
+ REGULATOR_SUPPLY("fw_core_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L20) = {
REGULATOR_SUPPLY("8038_l20", NULL),
@@ -151,8 +151,7 @@
REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"),
REGULATOR_SUPPLY("hdmi_vcc", "hdmi_msm.0"),
REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
+ REGULATOR_SUPPLY("pll_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L24) = {
REGULATOR_SUPPLY("8038_l24", NULL),
@@ -166,7 +165,7 @@
};
VREG_CONSUMERS(L27) = {
REGULATOR_SUPPLY("8038_l27", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.0"),
+ REGULATOR_SUPPLY("core_vdd", "pil-q6v4-lpass"),
};
VREG_CONSUMERS(S1) = {
REGULATOR_SUPPLY("8038_s1", NULL),
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index db40e5d..8898b50 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -547,11 +547,11 @@
RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL, 0, 1p60, NONE, NONE),
RPM_SMPS(S3, 0, 1, 1, 500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, LPM),
- RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, NONE, NONE),
+ RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, AUTO, AUTO),
RPM_SMPS(S8, 1, 1, 1, 2050000, 2050000, NULL, 100000, 1p60, NONE, NONE),
/* ID a_on pd ss min_uV max_uV supply sys_uA init_ip */
- RPM_LDO(L1, 1, 1, 0, 1050000, 1050000, "8917_s4", 0, 10000),
+ RPM_LDO(L1, 0, 1, 0, 1050000, 1050000, "8917_s4", 0, 10000),
RPM_LDO(L2, 0, 1, 0, 1200000, 1200000, "8917_s4", 0, 0),
RPM_LDO(L3, 0, 1, 0, 3075000, 3075000, NULL, 0, 0),
RPM_LDO(L4, 1, 1, 0, 1800000, 1800000, NULL, 10000, 10000),
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index ab35948..f0f59ec 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -518,7 +518,8 @@
const struct ion_platform_heap *heap =
&(msm8930_ion_pdata.heaps[i]);
- if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+ if (heap->type == (enum ion_heap_type) ION_HEAP_TYPE_CP
+ && heap->extra_data) {
struct ion_cp_heap_pdata *data = heap->extra_data;
reusable_count += (data->reusable) ? 1 : 0;
@@ -540,7 +541,7 @@
int fixed_position = NOT_FIXED;
int mem_is_fmem = 0;
- switch (heap->type) {
+ switch ((int) heap->type) {
case ION_HEAP_TYPE_CP:
mem_is_fmem = ((struct ion_cp_heap_pdata *)
heap->extra_data)->mem_is_fmem;
@@ -601,7 +602,7 @@
int fixed_position = NOT_FIXED;
struct ion_cp_heap_pdata *pdata = NULL;
- switch (heap->type) {
+ switch ((int) heap->type) {
case ION_HEAP_TYPE_CP:
pdata =
(struct ion_cp_heap_pdata *)heap->extra_data;
@@ -1047,6 +1048,27 @@
},
};
+static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ib = (492 * 8) * 1000000UL,
+ .ab = (492 * 8) * 100000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_SPS,
+ .ib = (492 * 8) * 1000000UL,
+ .ab = (492 * 8) * 100000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPDM,
+ .dst = MSM_BUS_SLAVE_SPDM,
+ .ib = (64 * 8) * 1000000UL,
+ .ab = (64 * 8) * 100000UL,
+ },
+};
+
static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
{
ARRAY_SIZE(qseecom_clks_init_vectors),
@@ -1060,6 +1082,10 @@
ARRAY_SIZE(qseecom_enable_sfpb_vectors),
qseecom_enable_sfpb_vectors,
},
+ {
+ ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors),
+ qseecom_enable_dfab_sfpb_vectors,
+ },
};
static struct msm_bus_scale_pdata qseecom_bus_pdata = {
@@ -2321,8 +2347,7 @@
static struct platform_device *common_devices[] __initdata = {
&msm_8960_q6_lpass,
- &msm_8960_q6_mss_fw,
- &msm_8960_q6_mss_sw,
+ &msm_8960_q6_mss,
&msm_8960_riva,
&msm_pil_tzapps,
&msm_pil_vidc,
@@ -2372,6 +2397,7 @@
&msm8930_rpm_log_device,
&msm8930_rpm_rbcpr_device,
&msm8930_rpm_stat_device,
+ &msm8930_rpm_master_stat_device,
#ifdef CONFIG_ION_MSM
&msm8930_ion_dev,
#endif
@@ -2387,8 +2413,6 @@
&gpio_keys_8930,
#endif
&msm8930_rtb_device,
- &msm8930_cpu_idle_device,
- &msm8930_msm_gov_device,
&msm_bus_8930_apps_fabric,
&msm_bus_8930_sys_fabric,
&msm_bus_8930_mm_fabric,
@@ -2398,6 +2422,7 @@
&msm8930_iommu_domain_device,
&msm_tsens_device,
&msm8930_cache_dump_device,
+ &msm8930_pc_cntr,
};
static struct platform_device *cdp_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 9bb6e09..88fd527 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -752,6 +752,33 @@
.eeprom_info = &imx091_eeprom_info,
};
+static struct msm_camera_sensor_flash_data flash_imx135 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_csi_lane_params imx135_csi_lane_params = {
+ .csi_lane_assign = 0xE4,
+ .csi_lane_mask = 0xF,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx135 = {
+ .mount_angle = 90,
+ .cam_vreg = msm_8960_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8960_cam_vreg),
+ .gpio_conf = &msm_8960_back_cam_gpio_conf,
+ .csi_lane_params = &imx135_csi_lane_params,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx135_data = {
+ .sensor_name = "imx135",
+ .pdata = &msm_camera_csi_device_data[0],
+ .flash_data = &flash_imx135,
+ .sensor_platform_info = &sensor_board_info_imx135,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
+ .sensor_type = BAYER_SENSOR,
+};
+
static struct pm8xxx_mpp_config_data privacy_light_on_config = {
.type = PM8XXX_MPP_TYPE_SINK,
.level = PM8XXX_MPP_CS_OUT_5MA,
@@ -838,6 +865,10 @@
.platform_data = &msm_camera_sensor_ov2720_data,
},
{
+ I2C_BOARD_INFO("imx135", 0x10),
+ .platform_data = &msm_camera_sensor_imx135_data,
+ },
+ {
I2C_BOARD_INFO("mt9m114", 0x48),
.platform_data = &msm_camera_sensor_mt9m114_data,
},
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index ae74285..f6c3653 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -401,6 +401,8 @@
.max_voltage = MAX_VOLTAGE_MV,
.min_voltage = 3200,
.uvd_thresh_voltage = 4050,
+ .alarm_low_mv = 3400,
+ .alarm_high_mv = 4000,
.resume_voltage_delta = 100,
.term_current = CHG_TERM_MA,
.cool_temp = 10,
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 2fa98b6..f9e2c8e 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -78,6 +78,7 @@
REGULATOR_SUPPLY("cam_vana", "4-0048"),
REGULATOR_SUPPLY("cam_vana", "4-0020"),
REGULATOR_SUPPLY("cam_vana", "4-0034"),
+ REGULATOR_SUPPLY("cam_vana", "4-0010"),
};
VREG_CONSUMERS(L12) = {
REGULATOR_SUPPLY("8921_l12", NULL),
@@ -86,6 +87,7 @@
REGULATOR_SUPPLY("cam_vdig", "4-0048"),
REGULATOR_SUPPLY("cam_vdig", "4-0020"),
REGULATOR_SUPPLY("cam_vdig", "4-0034"),
+ REGULATOR_SUPPLY("cam_vdig", "4-0010"),
};
VREG_CONSUMERS(L14) = {
REGULATOR_SUPPLY("8921_l14", NULL),
@@ -101,6 +103,7 @@
REGULATOR_SUPPLY("cam_vaf", "4-0048"),
REGULATOR_SUPPLY("cam_vaf", "4-0020"),
REGULATOR_SUPPLY("cam_vaf", "4-0034"),
+ REGULATOR_SUPPLY("cam_vaf", "4-0010"),
};
VREG_CONSUMERS(L17) = {
REGULATOR_SUPPLY("8921_l17", NULL),
@@ -120,8 +123,7 @@
REGULATOR_SUPPLY("dsi_pll_vddio", "mdp.0"),
REGULATOR_SUPPLY("hdmi_avdd", "hdmi_msm.0"),
REGULATOR_SUPPLY("pll_vdd", "pil_riva"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.1"),
- REGULATOR_SUPPLY("pll_vdd", "pil_qdsp6v4.2"),
+ REGULATOR_SUPPLY("pll_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L24) = {
REGULATOR_SUPPLY("8921_l24", NULL),
@@ -136,15 +138,15 @@
};
VREG_CONSUMERS(L26) = {
REGULATOR_SUPPLY("8921_l26", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.0"),
+ REGULATOR_SUPPLY("core_vdd", "pil-q6v4-lpass"),
};
VREG_CONSUMERS(L27) = {
REGULATOR_SUPPLY("8921_l27", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.2"),
+ REGULATOR_SUPPLY("sw_core_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L28) = {
REGULATOR_SUPPLY("8921_l28", NULL),
- REGULATOR_SUPPLY("core_vdd", "pil_qdsp6v4.1"),
+ REGULATOR_SUPPLY("fw_core_vdd", "pil-q6v4-modem"),
};
VREG_CONSUMERS(L29) = {
REGULATOR_SUPPLY("8921_l29", NULL),
@@ -221,6 +223,7 @@
REGULATOR_SUPPLY("cam_vio", "4-0048"),
REGULATOR_SUPPLY("cam_vio", "4-0020"),
REGULATOR_SUPPLY("cam_vio", "4-0034"),
+ REGULATOR_SUPPLY("cam_vio", "4-0010"),
};
/* This mapping is used for CDP only. */
VREG_CONSUMERS(CDP_LVS6) = {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 8ed9666..7e96edf 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -562,7 +562,8 @@
const struct ion_platform_heap *heap =
&(msm8960_ion_pdata.heaps[i]);
- if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+ if (heap->type == (enum ion_heap_type) ION_HEAP_TYPE_CP
+ && heap->extra_data) {
struct ion_cp_heap_pdata *data = heap->extra_data;
reusable_count += (data->reusable) ? 1 : 0;
@@ -587,7 +588,7 @@
int fixed_position = NOT_FIXED;
int mem_is_fmem = 0;
- switch (heap->type) {
+ switch ((int) heap->type) {
case ION_HEAP_TYPE_CP:
mem_is_fmem = ((struct ion_cp_heap_pdata *)
heap->extra_data)->mem_is_fmem;
@@ -666,7 +667,7 @@
int fixed_position = NOT_FIXED;
struct ion_cp_heap_pdata *pdata = NULL;
- switch (heap->type) {
+ switch ((int) heap->type) {
case ION_HEAP_TYPE_CP:
pdata =
(struct ion_cp_heap_pdata *)heap->extra_data;
@@ -1112,6 +1113,27 @@
},
};
+static struct msm_bus_vectors qseecom_enable_dfab_sfpb_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ib = (492 * 8) * 1000000UL,
+ .ab = (492 * 8) * 100000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_SPS,
+ .ib = (492 * 8) * 1000000UL,
+ .ab = (492 * 8) * 100000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_SPDM,
+ .dst = MSM_BUS_SLAVE_SPDM,
+ .ib = (64 * 8) * 1000000UL,
+ .ab = (64 * 8) * 100000UL,
+ },
+};
+
static struct msm_bus_paths qseecom_hw_bus_scale_usecases[] = {
{
ARRAY_SIZE(qseecom_clks_init_vectors),
@@ -1125,6 +1147,10 @@
ARRAY_SIZE(qseecom_enable_sfpb_vectors),
qseecom_enable_sfpb_vectors,
},
+ {
+ ARRAY_SIZE(qseecom_enable_dfab_sfpb_vectors),
+ qseecom_enable_dfab_sfpb_vectors,
+ },
};
static struct msm_bus_scale_pdata qseecom_bus_pdata = {
@@ -2727,6 +2753,7 @@
&msm8960_rpm_device,
&msm8960_rpm_log_device,
&msm8960_rpm_stat_device,
+ &msm8960_rpm_master_stat_device,
&msm_device_tz_log,
&coresight_tpiu_device,
&coresight_etb_device,
@@ -2736,14 +2763,13 @@
&msm_device_dspcrashd_8960,
&msm8960_device_watchdog,
&msm8960_rtb_device,
- &msm8960_cpu_idle_device,
- &msm8960_msm_gov_device,
&msm8960_device_cache_erp,
&msm8960_device_ebi1_ch0_erp,
&msm8960_device_ebi1_ch1_erp,
&msm8960_cache_dump_device,
&msm8960_iommu_domain_device,
&msm_tsens_device,
+ &msm8960_pc_cntr,
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -3158,13 +3184,22 @@
#endif
}
+static void __init msm8960_tsens_init(void)
+{
+ if (cpu_is_msm8960())
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
+ return;
+
+ msm_tsens_early_init(&msm_tsens_pdata);
+}
+
static void __init msm8960_cdp_init(void)
{
if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
pr_err("meminfo_init() failed!\n");
platform_device_register(&msm_gpio_device);
- msm_tsens_early_init(&msm_tsens_pdata);
+ msm8960_tsens_init();
msm_thermal_init(&msm_thermal_pdata);
BUG_ON(msm_rpm_init(&msm8960_rpm_data));
BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
@@ -3246,10 +3281,8 @@
msm8960_pm8921_gpio_mpp_init();
/* Don't add modem devices on APQ targets */
- if (socinfo_get_id() != 124) {
- platform_device_register(&msm_8960_q6_mss_fw);
- platform_device_register(&msm_8960_q6_mss_sw);
- }
+ if (socinfo_get_id() != 124)
+ platform_device_register(&msm_8960_q6_mss);
platform_add_devices(cdp_devices, ARRAY_SIZE(cdp_devices));
msm8960_init_smsc_hub();
msm8960_init_hsic();
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 479dec6..50b59e1 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -128,6 +128,12 @@
.dir = GPIOMUX_OUT_LOW,
};
+static struct gpiomux_setting taiko_int = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct msm_gpiomux_config msm_touch_configs[] __initdata = {
{
.gpio = 60, /* TOUCH RESET */
@@ -271,6 +277,30 @@
[GPIOMUX_SUSPENDED] = &gpio_uart_config,
},
},
+ {
+ .gpio = 53, /* BLSP2 QUP4 SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 54, /* BLSP2 QUP4 SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 56, /* BLSP2 QUP4 SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 55, /* BLSP2 QUP4 SPI_CS0_N */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
};
static struct msm_gpiomux_config msm8974_slimbus_config[] __initdata = {
@@ -290,22 +320,49 @@
static struct gpiomux_setting cam_settings[] = {
{
- .func = GPIOMUX_FUNC_1, /*active 1*/
+ .func = GPIOMUX_FUNC_1, /*active 1*/ /* 0 */
.drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_NONE,
},
{
- .func = GPIOMUX_FUNC_1, /*suspend*/
+ .func = GPIOMUX_FUNC_1, /*suspend*/ /* 1 */
.drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_DOWN,
},
{
- .func = GPIOMUX_FUNC_1, /*i2c suspend*/
+ .func = GPIOMUX_FUNC_1, /*i2c suspend*/ /* 2 */
.drv = GPIOMUX_DRV_2MA,
.pull = GPIOMUX_PULL_KEEPER,
},
+
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*active 0*/ /* 3 */
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*suspend 0*/ /* 4 */
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ },
+};
+
+static struct gpiomux_setting sd_card_det_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_IN,
+};
+
+static struct msm_gpiomux_config sd_card_det __initdata = {
+ .gpio = 62,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sd_card_det_config,
+ [GPIOMUX_SUSPENDED] = &sd_card_det_config,
+ },
};
static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
@@ -333,8 +390,8 @@
{
.gpio = 18, /* WEBCAM1_RESET_N / CAM_MCLK3 */
.settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[0],
- [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &cam_settings[4],
},
},
{
@@ -480,7 +537,13 @@
.settings = {
[GPIOMUX_SUSPENDED] = &taiko_reset,
},
- }
+ },
+ {
+ .gpio = 72, /* CDC_INT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &taiko_int,
+ },
+ },
};
void __init msm_8974_init_gpiomux(void)
@@ -507,6 +570,8 @@
msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
+ msm_gpiomux_install(&sd_card_det, 1);
+
msm_gpiomux_install(msm_taiko_config, ARRAY_SIZE(msm_taiko_config));
msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs));
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index dcc0d01..7fe45b8 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -27,6 +27,7 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/krait-regulator.h>
#include <linux/msm_thermal.h>
+#include <linux/mfd/wcd9xxx/core.h>
#include <asm/mach/map.h>
#include <asm/hardware/gic.h>
#include <mach/board.h>
@@ -488,6 +489,7 @@
{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
{ .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
+ { .compatible = "qcom,wcd9xxx-irq", .data = wcd9xxx_irq_of_init, },
{}
};
static struct of_device_id mpm_match[] __initdata = {
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 9e95d42..b9da615 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -870,6 +870,8 @@
#ifdef CONFIG_LTC4088_CHARGER
&msm_device_charger,
#endif
+ &msm_9615_q6_lpass,
+ &msm_9615_q6_mss,
&msm_device_otg,
&msm_device_hsic_peripheral,
&msm_device_gadget_peripheral,
@@ -935,6 +937,7 @@
&msm_bus_def_fab,
&msm9615_rpm_log_device,
&msm9615_rpm_stat_device,
+ &msm9615_rpm_master_stat_device,
&msm_tsens_device,
};
diff --git a/arch/arm/mach-msm/board-9625-gpiomux.c b/arch/arm/mach-msm/board-9625-gpiomux.c
index 2919f06..fe7670b 100644
--- a/arch/arm/mach-msm/board-9625-gpiomux.c
+++ b/arch/arm/mach-msm/board-9625-gpiomux.c
@@ -18,8 +18,8 @@
#include <mach/gpiomux.h>
static struct gpiomux_setting gpio_uart_config = {
- .func = GPIOMUX_FUNC_2,
- .drv = GPIOMUX_DRV_16MA,
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
.pull = GPIOMUX_PULL_NONE,
.dir = GPIOMUX_OUT_HIGH,
};
@@ -38,13 +38,13 @@
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
- .gpio = 45, /* BLSP1 UART TX */
+ .gpio = 8, /* BLSP1 UART TX */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_uart_config,
},
},
{
- .gpio = 46, /* BLSP1 UART RX */
+ .gpio = 9, /* BLSP1 UART RX */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_uart_config,
},
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 99b9f16..90428ce 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -28,9 +28,48 @@
#include <asm/mach/time.h>
#include <mach/socinfo.h>
#include <mach/board.h>
+#include <mach/restart.h>
#include <mach/gpio.h>
#include <mach/clk-provider.h>
+#include <mach/qpnp-int.h>
+#include <mach/msm_memtypes.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_smd.h>
+#include <mach/rpm-smd.h>
+#include <mach/rpm-regulator-smd.h>
#include "clock.h"
+#include "modem_notifier.h"
+#include "lpm_resources.h"
+#include "spm.h"
+
+#define MSM_KERNEL_EBI_SIZE 0x51000
+
+static struct memtype_reserve msm9625_reserve_table[] __initdata = {
+ [MEMTYPE_SMI] = {
+ },
+ [MEMTYPE_EBI0] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+ [MEMTYPE_EBI1] = {
+ .flags = MEMTYPE_FLAGS_1M_ALIGN,
+ },
+};
+
+static int msm9625_paddr_to_memtype(unsigned int paddr)
+{
+ return MEMTYPE_EBI1;
+}
+
+static void __init msm9625_calculate_reserve_sizes(void)
+{
+ msm9625_reserve_table[MEMTYPE_EBI1].size += MSM_KERNEL_EBI_SIZE;
+}
+
+static struct reserve_info msm9625_reserve_info __initdata = {
+ .memtype_reserve_table = msm9625_reserve_table,
+ .calculate_reserve_sizes = msm9625_calculate_reserve_sizes,
+ .paddr_to_memtype = msm9625_paddr_to_memtype,
+};
#define L2CC_AUX_CTRL ((0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | \
(0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | \
@@ -62,6 +101,7 @@
static struct of_device_id irq_match[] __initdata = {
{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+ { .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
{}
};
@@ -75,6 +115,8 @@
"msm_serial_hsl.0", NULL),
OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9928000, \
"spi_qsd.1", NULL),
+ OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
+ "spmi-pmic-arb.0", NULL),
{}
};
@@ -93,6 +135,162 @@
.init = msm_dt_timer_init
};
+static void __init msm9625_reserve(void)
+{
+ reserve_info = &msm9625_reserve_info;
+ msm_reserve();
+}
+
+static struct resource smd_resource[] = {
+ {
+ .name = "modem_smd_in",
+ .start = 32 + 25, /* mss_sw_to_kpss_ipc_irq0 */
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "modem_smsm_in",
+ .start = 32 + 26, /* mss_sw_to_kpss_ipc_irq1 */
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "adsp_smd_in",
+ .start = 32 + 156, /* lpass_to_kpss_ipc_irq0 */
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "adsp_smsm_in",
+ .start = 32 + 157, /* lpass_to_kpss_ipc_irq1 */
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rpm_smd_in",
+ .start = 32 + 168, /* rpm_to_kpss_ipc_irq4 */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct smd_subsystem_config smd_config_list[] = {
+ {
+ .irq_config_id = SMD_MODEM,
+ .subsys_name = "modem",
+ .edge = SMD_APPS_MODEM,
+
+ .smd_int.irq_name = "modem_smd_in",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 12,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = "modem_smsm_in",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smsm_dev",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1 << 13,
+ .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smsm_int.out_offset = 0x8,
+ },
+ {
+ .irq_config_id = SMD_Q6,
+ .subsys_name = "adsp",
+ .edge = SMD_APPS_QDSP,
+
+ .smd_int.irq_name = "adsp_smd_in",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 8,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = "adsp_smsm_in",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smsm_dev",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1 << 9,
+ .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smsm_int.out_offset = 0x8,
+ },
+ {
+ .irq_config_id = SMD_RPM,
+ .subsys_name = NULL, /* do not use PIL to load RPM */
+ .edge = SMD_APPS_RPM,
+
+ .smd_int.irq_name = "rpm_smd_in",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 0,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = NULL, /* RPM does not support SMSM */
+ .smsm_int.flags = 0,
+ .smsm_int.irq_id = 0,
+ .smsm_int.device_name = NULL,
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 0,
+ .smsm_int.out_base = NULL,
+ .smsm_int.out_offset = 0,
+ },
+};
+
+static struct smd_smem_regions aux_smem_areas[] = {
+ {
+ .phys_addr = (void *)(0xfc428000),
+ .size = 0x4000,
+ },
+};
+
+static struct smd_subsystem_restart_config smd_ssr_cfg = {
+ .disable_smsm_reset_handshake = 1,
+};
+
+static struct smd_platform smd_platform_data = {
+ .num_ss_configs = ARRAY_SIZE(smd_config_list),
+ .smd_ss_configs = smd_config_list,
+ .smd_ssr_config = &smd_ssr_cfg,
+ .num_smem_areas = ARRAY_SIZE(aux_smem_areas),
+ .smd_smem_areas = aux_smem_areas,
+};
+
+struct platform_device msm_device_smd_9625 = {
+ .name = "msm_smd",
+ .id = -1,
+ .resource = smd_resource,
+ .num_resources = ARRAY_SIZE(smd_resource),
+ .dev = {
+ .platform_data = &smd_platform_data,
+ }
+};
+
+void __init msm9625_add_devices(void)
+{
+ platform_device_register(&msm_device_smd_9625);
+}
+
+/*
+ * 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.
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msm9625_add_drivers(void)
+{
+ msm_init_modem_notifier_list();
+ msm_smd_init();
+ msm_rpm_driver_init();
+ msm_lpmrs_module_init();
+ rpm_regulator_smd_driver_init();
+ msm_spm_device_init();
+}
+
void __init msm9625_init(void)
{
if (socinfo_init() < 0)
@@ -102,6 +300,8 @@
msm_clock_init(&msm_dummy_clock_init_data);
of_platform_populate(NULL, of_default_bus_match_table,
msm9625_auxdata_lookup, NULL);
+ msm9625_add_devices();
+ msm9625_add_drivers();
}
DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)")
@@ -111,5 +311,6 @@
.handle_irq = gic_handle_irq,
.timer = &msm_dt_timer,
.dt_compat = msm9625_dt_match,
- .nr_irqs = -1,
+ .reserve = msm9625_reserve,
+ .restart = msm_restart,
MACHINE_END
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index b4f6968..1d6eb01 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -941,6 +941,8 @@
static void __init fsm9xxx_init(void)
{
+ msm_clock_init(&fsm9xxx_clock_init_data);
+
regulator_has_full_constraints();
#if defined(CONFIG_I2C_SSBI) || defined(CONFIG_MSM_SSBI)
@@ -977,7 +979,6 @@
{
msm_shared_ram_phys = 0x00100000;
msm_map_fsm9xxx_io();
- msm_clock_init(&fsm9xxx_clock_init_data);
if (socinfo_init() < 0)
pr_err("%s: socinfo_init() failed!\n",
__func__);
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 47e8381..6e3d10a 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -266,16 +266,16 @@
/* T6 Object */
0, 0, 0, 0, 0, 0,
/* T38 Object */
- 20, 0, 0, 0, 0, 0, 0, 0,
+ 20, 1, 0, 25, 9, 12, 0, 0,
/* T7 Object */
24, 12, 10,
/* T8 Object */
- 30, 0, 20, 20, 0, 0, 9, 45, 10, 192,
+ 30, 0, 20, 20, 0, 0, 0, 0, 10, 192,
/* T9 Object */
- 3, 0, 0, 18, 11, 0, 16, 60, 3, 1,
- 0, 1, 1, 0, 10, 10, 10, 10, 107, 3,
- 223, 1, 0, 0, 0, 0, 0, 0, 0, 0,
- 20, 15, 0, 0, 2,
+ 131, 0, 0, 18, 11, 0, 16, 70, 2, 1,
+ 0, 2, 1, 62, 10, 10, 10, 10, 107, 3,
+ 223, 1, 2, 2, 20, 20, 172, 40, 139, 110,
+ 10, 15, 0, 0, 0,
/* T15 Object */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
@@ -291,7 +291,7 @@
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
/* T40 Object */
- 17, 0, 0, 30, 30,
+ 0, 0, 0, 0, 0,
/* T42 Object */
3, 20, 45, 40, 128, 0, 0, 0,
/* T46 Object */
@@ -299,12 +299,12 @@
/* T47 Object */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* T48 Object */
- 1, 128, 96, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 6, 6, 0, 0, 63, 4, 64,
- 10, 0, 32, 5, 0, 38, 0, 8, 0, 0,
+ 1, 12, 64, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 6, 6, 0, 0, 100, 4, 64,
+ 10, 0, 20, 5, 0, 38, 0, 20, 0, 0,
0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
+ 10, 10, 10, 0, 0, 15, 15, 154, 58, 145,
+ 80, 100, 15, 3,
};
static struct mxt_config_info mxt_config_array[] = {
@@ -822,6 +822,7 @@
mxt_config_array[0].config_length =
ARRAY_SIZE(mxt_config_data_evt);
mxt_platform_data.panel_maxy = 875;
+ mxt_platform_data.need_calibration = true;
mxt_vkey_setup();
}
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 2a51e66..13c4be2 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -841,7 +841,7 @@
static void __init msm8625_reserve(void)
{
msm7x27a_reserve();
- memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+ memblock_remove(MSM8625_CPU_PHYS, SZ_8);
memblock_remove(MSM8625_WARM_BOOT_PHYS, SZ_32);
}
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 205db58..ee13e04 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -5190,7 +5190,7 @@
int bahama_not_marimba = bahama_present();
- if (bahama_not_marimba == -1) {
+ if (bahama_not_marimba < 0) {
printk(KERN_WARNING "%s: bahama_present: %d\n",
__func__, bahama_not_marimba);
return -ENODEV;
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index a889d39..d831ad2 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -5478,7 +5478,8 @@
for (i = 0; i < ion_pdata.nr; i++) {
struct ion_platform_heap *heap = &(ion_pdata.heaps[i]);
- if (heap->extra_data && heap->type == ION_HEAP_TYPE_CP) {
+ if (heap->extra_data &&
+ heap->type == (enum ion_heap_type) ION_HEAP_TYPE_CP) {
int map_all = ((struct ion_cp_heap_pdata *)
heap->extra_data)->iommu_map_all;
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index f6b0c4f..ec8e438 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -276,6 +276,7 @@
static struct msm_hsusb_gadget_platform_data msm_gadget_pdata = {
.is_phy_status_timer_on = 1,
+ .prop_chg = 0,
};
#ifdef CONFIG_SERIAL_MSM_HS
@@ -811,7 +812,7 @@
static void __init msm8625_reserve(void)
{
- memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+ memblock_remove(MSM8625_CPU_PHYS, SZ_8);
msm7627a_reserve();
}
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 9ff039f0..285b037 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -1534,6 +1534,11 @@
static CLK_SDC(sdc4_clk, 4, 3, 33000000, 67000000);
static CLK_SDC(sdc5_clk, 5, 2, 33000000, 67000000);
+static unsigned long fmax_sdc1_8064v2[MAX_VDD_LEVELS] __initdata = {
+ [VDD_DIG_LOW] = 100000000,
+ [VDD_DIG_NOMINAL] = 200000000,
+};
+
#define F_TSIF_REF(f, s, d, m, n) \
{ \
.freq_hz = f, \
@@ -1907,6 +1912,7 @@
F_CE3( 0, gnd, 1),
F_CE3( 48000000, pll8, 8),
F_CE3(100000000, pll3, 12),
+ F_CE3(120000000, pll3, 10),
F_END
};
@@ -1929,6 +1935,11 @@
},
};
+static unsigned long fmax_ce3_8064v2[MAX_VDD_LEVELS] __initdata = {
+ [VDD_DIG_LOW] = 57000000,
+ [VDD_DIG_NOMINAL] = 120000000,
+};
+
static struct branch_clk ce3_core_clk = {
.b = {
.ctl_reg = CE3_CORE_CLK_CTL_REG,
@@ -3540,11 +3551,12 @@
F_GFX3D(145455000, pll2, 2, 11),
F_GFX3D(160000000, pll2, 1, 5),
F_GFX3D(177778000, pll2, 2, 9),
+ F_GFX3D(192000000, pll8, 1, 2),
F_GFX3D(200000000, pll2, 1, 4),
F_GFX3D(228571000, pll2, 2, 7),
F_GFX3D(266667000, pll2, 1, 3),
- F_GFX3D(325000000, pll15, 1, 3),
F_GFX3D(400000000, pll2, 1, 2),
+ F_GFX3D(450000000, pll15, 1, 2),
F_END
};
@@ -3570,6 +3582,12 @@
F_END
};
+static unsigned long fmax_gfx3d_8064ab[MAX_VDD_LEVELS] __initdata = {
+ [VDD_DIG_LOW] = 128000000,
+ [VDD_DIG_NOMINAL] = 325000000,
+ [VDD_DIG_HIGH] = 450000000
+};
+
static unsigned long fmax_gfx3d_8064[MAX_VDD_LEVELS] __initdata = {
[VDD_DIG_LOW] = 128000000,
[VDD_DIG_NOMINAL] = 325000000,
@@ -4295,6 +4313,7 @@
F_VCODEC(133330000, pll2, 1, 6),
F_VCODEC(200000000, pll2, 1, 4),
F_VCODEC(228570000, pll2, 2, 7),
+ F_VCODEC(266670000, pll2, 1, 3),
F_END
};
@@ -4325,6 +4344,12 @@
},
};
+static unsigned long fmax_vcodec_8064v2[MAX_VDD_LEVELS] __initdata = {
+ [VDD_DIG_LOW] = 100000000,
+ [VDD_DIG_NOMINAL] = 200000000,
+ [VDD_DIG_HIGH] = 266670000,
+};
+
#define F_VPE(f, s, d) \
{ \
.freq_hz = f, \
@@ -5065,6 +5090,8 @@
writel_relaxed(0x80|BVAL(5, 3, clk_sel), GCC_APCS_CLK_DIAG);
measure->sample_ticks = 0x4000;
measure->multiplier = 2;
+ if (cpu_is_krait_v3())
+ measure->multiplier = 8;
break;
default:
ret = -EPERM;
@@ -5189,9 +5216,7 @@
CLK_LOOKUP("pwm_clk", cxo_clk.c, "0-0048"),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
- CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.1"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.2"),
+ CLK_LOOKUP("xo", pxo_clk.c, "pil-q6v4-lpass"),
CLK_LOOKUP("xo", cxo_clk.c, "pil_gss"),
CLK_LOOKUP("xo", cxo_clk.c, "BAM_RMNT"),
CLK_LOOKUP("xo", cxo_clk.c, "msm_xo"),
@@ -5326,6 +5351,7 @@
CLK_LOOKUP("core_clk", pmic_ssbi2_clk.c, ""),
CLK_LOOKUP("mem_clk", rpm_msg_ram_p_clk.c, ""),
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-001a"),
+ CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0010"),
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0034"),
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0020"),
CLK_LOOKUP("cam_clk", cam1_clk.c, "4-0048"),
@@ -5450,6 +5476,10 @@
CLK_LOOKUP("osr_clk", spare_i2s_mic_osr_clk.c,
"msm-dai-q6.5"),
CLK_LOOKUP("bit_clk", codec_i2s_spkr_bit_clk.c,
+ "msm-dai-q6.0"),
+ CLK_LOOKUP("osr_clk", codec_i2s_spkr_osr_clk.c,
+ "msm-dai-q6.0"),
+ CLK_LOOKUP("bit_clk", codec_i2s_spkr_bit_clk.c,
"msm-dai-q6.16384"),
CLK_LOOKUP("osr_clk", codec_i2s_spkr_osr_clk.c,
"msm-dai-q6.16384"),
@@ -5531,9 +5561,8 @@
CLK_LOOKUP("xo", pxo_a_clk.c, ""),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
- CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.1"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.2"),
+ CLK_LOOKUP("xo", pxo_clk.c, "pil-q6v4-lpass"),
+ CLK_LOOKUP("xo", cxo_clk.c, "pil-q6v4-modem"),
CLK_LOOKUP("xo", cxo_clk.c, "BAM_RMNT"),
CLK_LOOKUP("xo", cxo_clk.c, "msm_xo"),
CLK_LOOKUP("vref_buff", cxo_clk.c, "rpm-regulator"),
@@ -5683,6 +5712,7 @@
CLK_LOOKUP("cam_clk", cam2_clk.c, NULL),
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0020"),
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0034"),
+ CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0010"),
CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_csid.0"),
CLK_LOOKUP("csi_src_clk", csi1_src_clk.c, "msm_csid.1"),
CLK_LOOKUP("csi_src_clk", csi2_src_clk.c, "msm_csid.2"),
@@ -5793,6 +5823,10 @@
CLK_LOOKUP("osr_clk", spare_i2s_mic_osr_clk.c,
"msm-dai-q6.5"),
CLK_LOOKUP("bit_clk", codec_i2s_spkr_bit_clk.c,
+ "msm-dai-q6.0"),
+ CLK_LOOKUP("osr_clk", codec_i2s_spkr_osr_clk.c,
+ "msm-dai-q6.0"),
+ CLK_LOOKUP("bit_clk", codec_i2s_spkr_bit_clk.c,
"msm-dai-q6.16384"),
CLK_LOOKUP("osr_clk", codec_i2s_spkr_osr_clk.c,
"msm-dai-q6.16384"),
@@ -5880,9 +5914,8 @@
CLK_LOOKUP("xo", cxo_clk.c, "msm_xo"),
CLK_LOOKUP("cxo", cxo_clk.c, "wcnss_wlan.0"),
CLK_LOOKUP("cxo", cxo_clk.c, "pil_riva"),
- CLK_LOOKUP("xo", pxo_clk.c, "pil_qdsp6v4.0"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.1"),
- CLK_LOOKUP("xo", cxo_clk.c, "pil_qdsp6v4.2"),
+ CLK_LOOKUP("xo", pxo_clk.c, "pil-q6v4-lpass"),
+ CLK_LOOKUP("xo", cxo_clk.c, "pil-q6v4-modem"),
CLK_LOOKUP("xo", cxo_clk.c, "BAM_RMNT"),
CLK_LOOKUP("vref_buff", cxo_clk.c, "rpm-regulator"),
CLK_LOOKUP("pll2", pll2_clk.c, NULL),
@@ -6125,6 +6158,10 @@
CLK_LOOKUP("osr_clk", spare_i2s_mic_osr_clk.c,
"msm-dai-q6.5"),
CLK_LOOKUP("bit_clk", codec_i2s_spkr_bit_clk.c,
+ "msm-dai-q6.0"),
+ CLK_LOOKUP("osr_clk", codec_i2s_spkr_osr_clk.c,
+ "msm-dai-q6.0"),
+ CLK_LOOKUP("bit_clk", codec_i2s_spkr_bit_clk.c,
"msm-dai-q6.16384"),
CLK_LOOKUP("osr_clk", codec_i2s_spkr_osr_clk.c,
"msm-dai-q6.16384"),
@@ -6290,7 +6327,7 @@
writel_relaxed(0x3C7097F9, AHB_EN2_REG);
}
- if (cpu_is_apq8064())
+ if (cpu_is_apq8064() || cpu_is_apq8064ab())
rmwreg(0x00000001, AHB_EN3_REG, 0x00000001);
/* Deassert all locally-owned MM AHB resets. */
@@ -6313,7 +6350,7 @@
rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
- if (cpu_is_apq8064())
+ if (cpu_is_apq8064() || cpu_is_apq8064ab())
rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627())
rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
@@ -6351,7 +6388,8 @@
rmwreg(0x80FF0000, VFE_CC_REG, 0xE0FF4010);
rmwreg(0x800000FF, VFE_CC2_REG, 0xE00000FF);
rmwreg(0x80FF0000, VPE_CC_REG, 0xE0FF0010);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064()) {
+ if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064()
+ || cpu_is_apq8064ab()) {
rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
@@ -6369,7 +6407,7 @@
rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
rmwreg(0x80FF0000, GFX2D1_CC_REG, 0xE0FF0010);
}
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
rmwreg(0x00000000, TV_CC_REG, 0x00004010);
rmwreg(0x80FF0000, VCAP_CC_REG, 0xE0FF1010);
}
@@ -6380,7 +6418,7 @@
* and wake-up value to max.
*/
rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
}
@@ -6402,7 +6440,8 @@
/* Source the dsi_byte_clks from the DSI PHY PLLs */
rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064())
+ if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_apq8064()
+ || cpu_is_apq8064ab())
rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
/* Source the dsi1_esc_clk from the DSI1 PHY PLLs */
@@ -6412,7 +6451,7 @@
* Source the sata_phy_ref_clk from PXO and set predivider of
* sata_pmalive_clk to 1.
*/
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
}
@@ -6421,7 +6460,7 @@
* TODO: Programming below PLLs and prng_clk is temporary and
* needs to be removed after bootloaders program them.
*/
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
u32 is_pll_enabled;
/* Program pxo_src_clk to source from PXO */
@@ -6433,9 +6472,6 @@
/* Ref clk = 27MHz and program pll14 to 480MHz */
configure_sr_pll(&pll14_config, &pll14_regs, 1);
- /* Program PLL15 to 975MHz with ref clk = 27MHz */
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
-
/* Check if PLL4 is active */
is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
if (!is_pll_enabled)
@@ -6450,6 +6486,17 @@
writel_relaxed(0x2B, PRNG_CLK_NS_REG);
}
+ if (cpu_is_apq8064()) {
+ /* Program PLL15 to 975MHz with ref clk = 27MHz */
+ configure_sr_pll(&pll15_config, &pll15_regs, 0);
+ } else if (cpu_is_apq8064ab()) {
+ /* Program PLL15 to 900MHZ */
+ pll15_config.l = 0x21 | BVAL(31, 7, 0x620);
+ pll15_config.m = 0x1;
+ pll15_config.n = 0x3;
+ configure_sr_pll(&pll15_config, &pll15_regs, 0);
+ }
+
/*
* Program PLL15 to 900MHz with ref clk = 27MHz and
* only enable PLL main output.
@@ -6470,7 +6517,7 @@
/* Initialize clock registers. */
reg_init();
- if (cpu_is_apq8064())
+ if (cpu_is_apq8064() || cpu_is_apq8064ab())
vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
@@ -6512,13 +6559,32 @@
}
/*
* Change the freq tables for and voltage requirements for
- * clocks which differ between 8960 and 8064.
+ * clocks which differ between chips.
*/
if (cpu_is_apq8064()) {
gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8064,
sizeof(gfx3d_clk.c.fmax));
+ }
+ if (cpu_is_apq8064ab()) {
+ gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8064;
+
+ memcpy(gfx3d_clk.c.fmax, fmax_gfx3d_8064ab,
+ sizeof(gfx3d_clk.c.fmax));
+ }
+ if ((cpu_is_apq8064() &&
+ SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) ||
+ cpu_is_apq8064ab()) {
+
+ memcpy(vcodec_clk.c.fmax, fmax_vcodec_8064v2,
+ sizeof(vcodec_clk.c.fmax));
+ memcpy(ce3_src_clk.c.fmax, fmax_ce3_8064v2,
+ sizeof(ce3_src_clk.c.fmax));
+ memcpy(sdc1_clk.c.fmax, fmax_sdc1_8064v2,
+ sizeof(sdc1_clk.c.fmax));
+ }
+ if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
memcpy(ijpeg_clk.c.fmax, fmax_ijpeg_8064,
sizeof(ijpeg_clk.c.fmax));
memcpy(mdp_clk.c.fmax, fmax_mdp_8064,
@@ -6594,7 +6660,7 @@
clk_set_rate(&tsif_ref_clk.c, 105000);
clk_set_rate(&tssc_clk.c, 27000000);
clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
}
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index ca0dd20..b21e60e 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -632,7 +632,6 @@
#define CXO_ID 0x0
#define QDSS_ID 0x1
-#define RPM_SCALING_ENABLE_ID 0x2
#define PNOC_ID 0x0
#define SNOC_ID 0x1
@@ -789,7 +788,6 @@
static DEFINE_CLK_VOTER(pnoc_sdcc4_clk, &pnoc_clk.c, 0);
static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, 0);
-static DEFINE_CLK_VOTER(pnoc_qseecom_clk, &pnoc_clk.c, 0);
static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
F(125000000, gpll0, 1, 5, 24),
@@ -2183,6 +2181,18 @@
},
};
+struct branch_clk gcc_sys_noc_usb3_axi_clk = {
+ .cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
+ .parent = &usb30_master_clk_src.c,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sys_noc_usb3_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
+ },
+};
+
static struct branch_clk gcc_usb30_master_clk = {
.cbcr_reg = USB30_MASTER_CBCR,
.bcr_reg = USB_30_BCR,
@@ -2193,6 +2203,7 @@
.dbg_name = "gcc_usb30_master_clk",
.ops = &clk_ops_branch,
CLK_INIT(gcc_usb30_master_clk.c),
+ .depends = &gcc_sys_noc_usb3_axi_clk.c,
},
};
@@ -2207,18 +2218,6 @@
},
};
-struct branch_clk gcc_sys_noc_usb3_axi_clk = {
- .cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
- .parent = &usb30_master_clk_src.c,
- .has_sibling = 1,
- .base = &virt_bases[GCC_BASE],
- .c = {
- .dbg_name = "gcc_sys_noc_usb3_axi_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
- },
-};
-
struct branch_clk gcc_usb30_sleep_clk = {
.cbcr_reg = USB30_SLEEP_CBCR,
.has_sibling = 1,
@@ -2366,9 +2365,12 @@
static struct clk_freq_tbl ftbl_mmss_axi_clk[] = {
F_MM( 19200000, cxo, 1, 0, 0),
+ F_MM( 37500000, gpll0, 16, 0, 0),
+ F_MM( 50000000, gpll0, 12, 0, 0),
+ F_MM( 75000000, gpll0, 8, 0, 0),
+ F_MM(100000000, gpll0, 6, 0, 0),
F_MM(150000000, gpll0, 4, 0, 0),
F_MM(282000000, mmpll1, 3, 0, 0),
- F_MM(320000000, mmpll0, 2.5, 0, 0),
F_MM(400000000, mmpll0, 2, 0, 0),
F_END
};
@@ -2390,6 +2392,10 @@
static struct clk_freq_tbl ftbl_ocmemnoc_clk[] = {
F_MM( 19200000, cxo, 1, 0, 0),
+ F_MM( 37500000, gpll0, 16, 0, 0),
+ F_MM( 50000000, gpll0, 12, 0, 0),
+ F_MM( 75000000, gpll0, 8, 0, 0),
+ F_MM(100000000, gpll0, 6, 0, 0),
F_MM(150000000, gpll0, 4, 0, 0),
F_MM(282000000, mmpll1, 3, 0, 0),
F_MM(400000000, mmpll0, 2, 0, 0),
@@ -2925,7 +2931,7 @@
};
static struct clk_freq_tbl ftbl_mdss_edplink_clk[] = {
- F_MDSS(135000000, edppll_270, 2, 0, 0),
+ F_MDSS(162000000, edppll_270, 2, 0, 0),
F_MDSS(270000000, edppll_270, 11, 0, 0),
F_END
};
@@ -2945,7 +2951,7 @@
};
static struct clk_freq_tbl ftbl_mdss_edppixel_clk[] = {
- F_MDSS(175000000, edppll_350, 2, 0, 0),
+ F_MDSS(148500000, edppll_350, 2, 0, 0),
F_MDSS(350000000, edppll_350, 11, 0, 0),
F_END
};
@@ -5032,6 +5038,7 @@
CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9967000.i2c"),
+ CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f9966000.spi"),
CLK_LOOKUP("iface_clk", gcc_blsp2_ahb_clk.c, "f995e000.serial"),
CLK_LOOKUP("core_clk", gcc_blsp2_qup1_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup1_spi_apps_clk.c, ""),
@@ -5040,8 +5047,8 @@
CLK_LOOKUP("core_clk", gcc_blsp2_qup3_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup3_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup4_i2c_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp2_qup4_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup5_i2c_apps_clk.c, "f9967000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp2_qup4_spi_apps_clk.c, "f9966000.spi"),
CLK_LOOKUP("core_clk", gcc_blsp2_qup5_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup6_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp2_qup6_spi_apps_clk.c, ""),
@@ -5070,6 +5077,11 @@
CLK_LOOKUP("bus_clk", gcc_ce2_axi_clk.c, "qcrypto.0"),
CLK_LOOKUP("core_clk_src", ce2_clk_src.c, "qcrypto.0"),
+ CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "qseecom"),
+ CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "qseecom"),
+ CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "qseecom"),
+ CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "qseecom"),
+
CLK_LOOKUP("core_clk", gcc_gp1_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_gp2_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_gp3_clk.c, ""),
@@ -5113,15 +5125,18 @@
/* Multimedia clocks */
CLK_LOOKUP("bus_clk_src", axi_clk_src.c, ""),
CLK_LOOKUP("bus_clk", mmss_mmssnoc_axi_clk.c, ""),
- CLK_LOOKUP("core_clk", mdss_edpaux_clk.c, ""),
- CLK_LOOKUP("core_clk", mdss_edppixel_clk.c, ""),
+ CLK_LOOKUP("core_clk", mdss_edpaux_clk.c, "fd923400.qcom,mdss_edp"),
+ CLK_LOOKUP("pixel_clk", mdss_edppixel_clk.c, "fd923400.qcom,mdss_edp"),
+ CLK_LOOKUP("link_clk", mdss_edplink_clk.c, "fd923400.qcom,mdss_edp"),
CLK_LOOKUP("byte_clk", mdss_byte0_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("byte_clk", mdss_byte1_clk.c, ""),
CLK_LOOKUP("core_clk", mdss_esc0_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("core_clk", mdss_esc1_clk.c, ""),
CLK_LOOKUP("pixel_clk", mdss_pclk0_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, ""),
- CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
+ CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
+ CLK_LOOKUP("alt_iface_clk", mdss_hdmi_ahb_clk.c,
+ "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("extp_clk", mdss_extpclk_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
@@ -5132,8 +5147,10 @@
/* MM sensor clocks */
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6e.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "6c.qcom,camera"),
+ CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6e.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "6c.qcom,camera"),
+ CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, "90.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk1_clk.c, ""),
CLK_LOOKUP("cam_clk", camss_mclk2_clk.c, ""),
CLK_LOOKUP("cam_clk", camss_mclk3_clk.c, ""),
@@ -5270,6 +5287,7 @@
CLK_LOOKUP("core_clk", camss_vfe_cpp_clk.c, "fda44000.qcom,iommu"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdp.0"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdss_dsi_clk_ctrl"),
+ CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd923400.qcom,mdss_edp"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "mdp.0"),
@@ -5348,7 +5366,6 @@
CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
- CLK_LOOKUP("bus_clk", pnoc_qseecom_clk.c, "qseecom"),
CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
@@ -5733,24 +5750,6 @@
#define APCS_GCC_CC_PHYS 0xF9011000
#define APCS_GCC_CC_SIZE SZ_4K
-static void __init enable_rpm_scaling(void)
-{
- int rc, value = 0x1;
- struct msm_rpm_kvp kvp = {
- .key = RPM_SMD_KEY_ENABLE,
- .data = (void *)&value,
- .length = sizeof(value),
- };
-
- rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_SLEEP_SET,
- RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
- WARN(rc < 0, "RPM clock scaling (sleep set) did not enable!\n");
-
- rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_ACTIVE_SET,
- RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
- WARN(rc < 0, "RPM clock scaling (active set) did not enable!\n");
-}
-
static void __init msm8974_clock_pre_init(void)
{
virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index e942173..8bd4433 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -218,6 +218,28 @@
.release = seq_release,
};
+static int clock_parent_show(struct seq_file *m, void *unused)
+{
+ struct clk *clock = m->private;
+ struct clk *parent = clk_get_parent(clock);
+
+ seq_printf(m, "%s\n", (parent ? parent->dbg_name : "None"));
+
+ return 0;
+}
+
+static int clock_parent_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clock_parent_show, inode->i_private);
+}
+
+static const struct file_operations clock_parent_fops = {
+ .open = clock_parent_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static struct dentry *debugfs_base;
static u32 debug_suspend;
@@ -274,6 +296,10 @@
S_IRUGO, clk_dir, clock, &fmax_rates_fops))
goto error;
+ if (!debugfs_create_file("parent", S_IRUGO, clk_dir, clock,
+ &clock_parent_fops))
+ goto error;
+
return 0;
error:
debugfs_remove_recursive(clk_dir);
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index e06eb4b..daf83e2 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -297,6 +297,27 @@
return HANDOFF_ENABLED_CLK;
}
+#define RPM_MISC_CLK_TYPE 0x306b6c63
+#define RPM_SCALING_ENABLE_ID 0x2
+
+void enable_rpm_scaling(void)
+{
+ int rc, value = 0x1;
+ struct msm_rpm_kvp kvp = {
+ .key = RPM_SMD_KEY_ENABLE,
+ .data = (void *)&value,
+ .length = sizeof(value),
+ };
+
+ rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_SLEEP_SET,
+ RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
+ WARN(rc < 0, "RPM clock scaling (sleep set) did not enable!\n");
+
+ rc = msm_rpm_send_message_noirq(MSM_RPM_CTX_ACTIVE_SET,
+ RPM_MISC_CLK_TYPE, RPM_SCALING_ENABLE_ID, &kvp, 1);
+ WARN(rc < 0, "RPM clock scaling (active set) did not enable!\n");
+}
+
struct clk_ops clk_ops_rpm = {
.enable = rpm_clk_enable,
.disable = rpm_clk_disable,
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index 2f0b729..252e8cb 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -54,6 +54,12 @@
return container_of(clk, struct rpm_clk, c);
}
+/*
+ * RPM scaling enable function used for target that has an RPM resource for
+ * rpm clock scaling enable.
+ */
+void enable_rpm_scaling(void);
+
extern struct clk_rpmrs_data clk_rpmrs_data;
extern struct clk_rpmrs_data clk_rpmrs_data_smd;
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 1ea18f4..c30bd79 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -72,15 +72,14 @@
/* Vote for a voltage level. */
int vote_vdd_level(struct clk_vdd_class *vdd_class, int level)
{
- unsigned long flags;
int rc;
- spin_lock_irqsave(&vdd_class->lock, flags);
+ mutex_lock(&vdd_class->lock);
vdd_class->level_votes[level]++;
rc = update_vdd(vdd_class);
if (rc)
vdd_class->level_votes[level]--;
- spin_unlock_irqrestore(&vdd_class->lock, flags);
+ mutex_unlock(&vdd_class->lock);
return rc;
}
@@ -88,10 +87,9 @@
/* Remove vote for a voltage level. */
int unvote_vdd_level(struct clk_vdd_class *vdd_class, int level)
{
- unsigned long flags;
int rc = 0;
- spin_lock_irqsave(&vdd_class->lock, flags);
+ mutex_lock(&vdd_class->lock);
if (WARN(!vdd_class->level_votes[level],
"Reference counts are incorrect for %s level %d\n",
vdd_class->class_name, level))
@@ -101,7 +99,7 @@
if (rc)
vdd_class->level_votes[level]++;
out:
- spin_unlock_irqrestore(&vdd_class->lock, flags);
+ mutex_unlock(&vdd_class->lock);
return rc;
}
@@ -135,6 +133,18 @@
unvote_vdd_level(clk->vdd_class, level);
}
+/* Returns true if the rate is valid without voting for it */
+static bool is_rate_valid(struct clk *clk, unsigned long rate)
+{
+ int level;
+
+ if (!clk->vdd_class)
+ return true;
+
+ level = find_vdd_level(clk, rate);
+ return level >= 0;
+}
+
int clk_prepare(struct clk *clk)
{
int ret = 0;
@@ -333,14 +343,16 @@
/* Enforce vdd requirements for target frequency. */
rc = vote_rate_vdd(clk, rate);
if (rc)
- goto err_vote_vdd;
+ goto out;
rc = clk->ops->set_rate(clk, rate);
if (rc)
goto err_set_rate;
/* Release vdd requirements for starting frequency. */
unvote_rate_vdd(clk, start_rate);
- } else {
+ } else if (is_rate_valid(clk, rate)) {
rc = clk->ops->set_rate(clk, rate);
+ } else {
+ rc = -EINVAL;
}
if (!rc)
@@ -351,7 +363,6 @@
err_set_rate:
unvote_rate_vdd(clk, rate);
-err_vote_vdd:
goto out;
}
EXPORT_SYMBOL(clk_set_rate);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index e66881b..a49a145 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -99,6 +99,24 @@
/* Address of PCIE20 */
#define PCIE20_PHYS 0x1b500000
#define PCIE20_SIZE SZ_4K
+#define MSM8064_PC_CNTR_PHYS (APQ8064_IMEM_PHYS + 0x664)
+#define MSM8064_PC_CNTR_SIZE 0x40
+#define MSM8064_RPM_MASTER_STATS_BASE 0x10BB00
+
+static struct resource msm8064_resources_pccntr[] = {
+ {
+ .start = MSM8064_PC_CNTR_PHYS,
+ .end = MSM8064_PC_CNTR_PHYS + MSM8064_PC_CNTR_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm8064_pc_cntr = {
+ .name = "pc-cntr",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm8064_resources_pccntr),
+ .resource = msm8064_resources_pccntr,
+};
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
@@ -1945,6 +1963,11 @@
.end = 0x10008000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
+ {
+ .start = GSS_A5_WDOG_EXPIRED,
+ .end = GSS_A5_WDOG_EXPIRED,
+ .flags = IORESOURCE_IRQ,
+ },
};
struct platform_device msm_gss = {
@@ -2329,6 +2352,37 @@
},
};
+static struct resource resources_rpm_master_stats[] = {
+ {
+ .start = MSM8064_RPM_MASTER_STATS_BASE,
+ .end = MSM8064_RPM_MASTER_STATS_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static char *master_names[] = {
+ "KPSS",
+ "MPSS",
+ "LPASS",
+ "RIVA",
+ "DSPS",
+};
+
+static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
+ .masters = master_names,
+ .nomasters = ARRAY_SIZE(master_names),
+};
+
+struct platform_device apq8064_rpm_master_stat_device = {
+ .name = "msm_rpm_master_stat",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_rpm_master_stats),
+ .resource = resources_rpm_master_stats,
+ .dev = {
+ .platform_data = &msm_rpm_master_stat_pdata,
+ },
+};
+
static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
.phys_addr_base = 0x0010C000,
.reg_offsets = {
@@ -2350,17 +2404,18 @@
/* Sensors DSPS platform data */
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
-#define PPSS_DSPS_PIPE_BASE 0x12800000
-#define PPSS_DSPS_PIPE_SIZE 0x4000
-#define PPSS_DSPS_DDR_BASE 0x8fe00000
-#define PPSS_DSPS_DDR_SIZE 0x100000
-#define PPSS_SMEM_BASE 0x80000000
-#define PPSS_SMEM_SIZE 0x200000
-#define PPSS_REG_PHYS_BASE 0x12080000
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
+#define PPSS_DSPS_PIPE_BASE 0x12800000
+#define PPSS_DSPS_PIPE_SIZE 0x4000
+#define PPSS_DSPS_DDR_BASE 0x8fe00000
+#define PPSS_DSPS_DDR_SIZE 0x100000
+#define PPSS_SMEM_BASE 0x80000000
+#define PPSS_SMEM_SIZE 0x200000
+#define PPSS_REG_PHYS_BASE 0x12080000
+#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
static struct dsps_clk_info dsps_clks[] = {};
static struct dsps_regulator_info dsps_regs[] = {};
@@ -2388,6 +2443,7 @@
.ddr_size = PPSS_DSPS_DDR_SIZE,
.smem_start = PPSS_SMEM_BASE,
.smem_size = PPSS_SMEM_SIZE,
+ .ppss_wdog_unmasked_int_en_reg = PPSS_WDOG_UNMASKED_INT_EN,
.signature = DSPS_SIGNATURE,
};
@@ -2625,50 +2681,86 @@
.num_resources = ARRAY_SIZE(i2s_mdm_resources),
.resource = i2s_mdm_resources,
};
-static int apq8064_LPM_latency = 1000; /* >100 usec for WFI */
-
-struct platform_device apq8064_cpu_idle_device = {
- .name = "msm_cpu_idle",
- .id = -1,
- .dev = {
- .platform_data = &apq8064_LPM_latency,
- },
-};
static struct msm_dcvs_freq_entry apq8064_freq[] = {
- { 384000, 166981, 345600},
- { 702000, 213049, 632502},
- {1026000, 285712, 925613},
- {1242000, 383945, 1176550},
- {1458000, 419729, 1465478},
- {1512000, 434116, 1546674},
-
+ { 384000, 900, 0, 0, 0},
+ { 594000, 950, 0, 0, 0},
+ { 702000, 975, 0, 0, 0},
+ {1026000, 1075, 0, 0, 0},
+ {1242000, 1150, 0, 100, 100},
+ {1458000, 1188, 0, 100, 100},
+ {1512000, 1200, 1, 100, 100},
};
static struct msm_dcvs_core_info apq8064_core_info = {
- .freq_tbl = &apq8064_freq[0],
- .core_param = {
- .max_time_us = 100000,
- .num_freq = ARRAY_SIZE(apq8064_freq),
+ .freq_tbl = &apq8064_freq[0],
+ .num_cores = 4,
+ .sensors = (int[]){7, 8, 9, 10},
+ .thermal_poll_ms = 60000,
+ .core_param = {
+ .core_type = MSM_DCVS_CORE_TYPE_CPU,
},
- .algo_param = {
- .slack_time_us = 58000,
- .scale_slack_time = 0,
- .scale_slack_time_pct = 0,
- .disable_pc_threshold = 1458000,
- .em_window_size = 100000,
- .em_max_util_pct = 97,
- .ss_window_size = 1000000,
- .ss_util_pct = 95,
- .ss_iobusy_conv = 100,
+ .algo_param = {
+ .disable_pc_threshold = 1458000,
+ .em_win_size_min_us = 100000,
+ .em_win_size_max_us = 300000,
+ .em_max_util_pct = 97,
+ .group_id = 1,
+ .max_freq_chg_time_us = 100000,
+ .slack_mode_dynamic = 0,
+ .slack_weight_thresh_pct = 3,
+ .slack_time_min_us = 45000,
+ .slack_time_max_us = 45000,
+ .ss_iobusy_conv = 100,
+ .ss_win_size_min_us = 1000000,
+ .ss_win_size_max_us = 1000000,
+ .ss_util_pct = 95,
},
+ .energy_coeffs = {
+ .active_coeff_a = 336,
+ .active_coeff_b = 0,
+ .active_coeff_c = 0,
+
+ .leakage_coeff_a = -17720,
+ .leakage_coeff_b = 37,
+ .leakage_coeff_c = 3329,
+ .leakage_coeff_d = -277,
+ },
+ .power_param = {
+ .current_temp = 25,
+ .num_freq = ARRAY_SIZE(apq8064_freq),
+ }
+};
+
+#define APQ8064_LPM_LATENCY 1000 /* >100 usec for WFI */
+
+static struct msm_gov_platform_data gov_platform_data = {
+ .info = &apq8064_core_info,
+ .latency = APQ8064_LPM_LATENCY,
};
struct platform_device apq8064_msm_gov_device = {
.name = "msm_dcvs_gov",
.id = -1,
.dev = {
- .platform_data = &apq8064_core_info,
+ .platform_data = &gov_platform_data,
+ },
+};
+
+static struct msm_mpd_algo_param apq8064_mpd_algo_param = {
+ .em_win_size_min_us = 10000,
+ .em_win_size_max_us = 100000,
+ .em_max_util_pct = 90,
+ .online_util_pct_min = 60,
+ .slack_time_min_us = 50000,
+ .slack_time_max_us = 100000,
+};
+
+struct platform_device apq8064_msm_mpd_device = {
+ .name = "msm_mpdecision",
+ .id = -1,
+ .dev = {
+ .platform_data = &apq8064_mpd_algo_param,
},
};
@@ -2715,8 +2807,8 @@
{
.src = MSM_BUS_MASTER_VIDEO_CAP,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 1920 * 1080 * 3 * 60,
- .ib = 1920 * 1080 * 3 * 60 * 1.5,
+ .ab = 1920 * 1080 * 10 * 60,
+ .ib = 1920 * 1080 * 10 * 60 * 1.5,
},
};
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index ad89a86..30a99cd 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,7 +18,6 @@
#include <mach/msm_iomap.h>
#include <mach/irqs-8930.h>
#include <mach/rpm.h>
-#include <mach/msm_dcvs.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#include <mach/board.h>
@@ -37,6 +36,24 @@
#ifdef CONFIG_MSM_MPM
#include <mach/mpm.h>
#endif
+#define MSM8930_PC_CNTR_PHYS (MSM8930_IMEM_PHYS + 0x664)
+#define MSM8930_PC_CNTR_SIZE 0x40
+#define MSM8930_RPM_MASTER_STATS_BASE 0x10B100
+
+static struct resource msm8930_resources_pccntr[] = {
+ {
+ .start = MSM8930_PC_CNTR_PHYS,
+ .end = MSM8930_PC_CNTR_PHYS + MSM8930_PC_CNTR_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm8930_pc_cntr = {
+ .name = "pc-cntr",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm8930_resources_pccntr),
+ .resource = msm8930_resources_pccntr,
+};
struct msm_rpm_platform_data msm8930_rpm_data __initdata = {
.reg_base_addrs = {
@@ -542,6 +559,36 @@
},
};
+static struct resource resources_rpm_master_stats[] = {
+ {
+ .start = MSM8930_RPM_MASTER_STATS_BASE,
+ .end = MSM8930_RPM_MASTER_STATS_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static char *master_names[] = {
+ "KPSS",
+ "MPSS",
+ "LPASS",
+ "RIVA",
+};
+
+static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
+ .masters = master_names,
+ .nomasters = ARRAY_SIZE(master_names),
+};
+
+struct platform_device msm8930_rpm_master_stat_device = {
+ .name = "msm_rpm_master_stat",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_rpm_master_stats),
+ .resource = resources_rpm_master_stats,
+ .dev = {
+ .platform_data = &msm_rpm_master_stat_pdata,
+ },
+};
+
static struct resource msm_rpm_rbcpr_resource = {
.start = 0x0010DB00,
.end = 0x0010DB00 + SZ_8K - 1,
@@ -567,53 +614,6 @@
.resource = &msm_rpm_rbcpr_resource,
};
-static int msm8930_LPM_latency = 1000; /* >100 usec for WFI */
-
-struct platform_device msm8930_cpu_idle_device = {
- .name = "msm_cpu_idle",
- .id = -1,
- .dev = {
- .platform_data = &msm8930_LPM_latency,
- },
-};
-
-static struct msm_dcvs_freq_entry msm8930_freq[] = {
- { 384000, 166981, 345600},
- { 702000, 213049, 632502},
- {1026000, 285712, 925613},
- {1242000, 383945, 1176550},
- {1458000, 419729, 1465478},
- {1512000, 434116, 1546674},
-
-};
-
-static struct msm_dcvs_core_info msm8930_core_info = {
- .freq_tbl = &msm8930_freq[0],
- .core_param = {
- .max_time_us = 100000,
- .num_freq = ARRAY_SIZE(msm8930_freq),
- },
- .algo_param = {
- .slack_time_us = 58000,
- .scale_slack_time = 0,
- .scale_slack_time_pct = 0,
- .disable_pc_threshold = 1458000,
- .em_window_size = 100000,
- .em_max_util_pct = 97,
- .ss_window_size = 1000000,
- .ss_util_pct = 95,
- .ss_iobusy_conv = 100,
- },
-};
-
-struct platform_device msm8930_msm_gov_device = {
- .name = "msm_dcvs_gov",
- .id = -1,
- .dev = {
- .platform_data = &msm8930_core_info,
- },
-};
-
struct platform_device msm_bus_8930_sys_fabric = {
.name = "msm_bus_fabric",
.id = MSM_BUS_FAB_SYSTEM,
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 64b901f..5b04fa7 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -103,6 +103,25 @@
#define MSM8960_HSUSB_PHYS 0x12500000
#define MSM8960_HSUSB_SIZE SZ_4K
+#define MSM8960_PC_CNTR_PHYS (MSM8960_IMEM_PHYS + 0x664)
+#define MSM8960_PC_CNTR_SIZE 0x40
+#define MSM8960_RPM_MASTER_STATS_BASE 0x10BB00
+
+static struct resource msm8960_resources_pccntr[] = {
+ {
+ .start = MSM8960_PC_CNTR_PHYS,
+ .end = MSM8960_PC_CNTR_PHYS + MSM8960_PC_CNTR_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm8960_pc_cntr = {
+ .name = "pc-cntr",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm8960_resources_pccntr),
+ .resource = msm8960_resources_pccntr,
+};
+
static struct resource resources_otg[] = {
{
.start = MSM8960_HSUSB_PHYS,
@@ -1316,108 +1335,106 @@
},
};
-#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
-#define SFAB_LPASS_Q6_ACLK_CTL (MSM_CLK_CTL_BASE + 0x23A0)
-
static struct resource msm_8960_q6_lpass_resources[] = {
{
- .start = MSM_LPASS_QDSP6SS_PHYS,
- .end = MSM_LPASS_QDSP6SS_PHYS + SZ_256 - 1,
+ .start = 0x28800000,
+ .end = 0x28800000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
+ {
+ .start = LPASS_Q6SS_WDOG_EXPIRED,
+ .end = LPASS_Q6SS_WDOG_EXPIRED,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct pil_q6v4_pdata msm_8960_q6_lpass_data = {
.strap_tcm_base = 0x01460000,
.strap_ahb_upper = 0x00290000,
.strap_ahb_lower = 0x00000280,
- .aclk_reg = SFAB_LPASS_Q6_ACLK_CTL,
+ .aclk_reg = MSM_CLK_CTL_BASE + 0x23A0,
.name = "q6",
.pas_id = PAS_Q6,
.bus_port = MSM_BUS_MASTER_LPASS_PROC,
};
struct platform_device msm_8960_q6_lpass = {
- .name = "pil_qdsp6v4",
- .id = 0,
+ .name = "pil-q6v4-lpass",
+ .id = -1,
.num_resources = ARRAY_SIZE(msm_8960_q6_lpass_resources),
.resource = msm_8960_q6_lpass_resources,
.dev.platform_data = &msm_8960_q6_lpass_data,
};
-#define MSM_MSS_ENABLE_PHYS 0x08B00000
-#define MSM_FW_QDSP6SS_PHYS 0x08800000
-#define MSS_Q6FW_JTAG_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C6C)
-#define SFAB_MSS_Q6_FW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2044)
-
-static struct resource msm_8960_q6_mss_fw_resources[] = {
+static struct resource msm_8960_q6_mss_resources[] = {
{
- .start = MSM_FW_QDSP6SS_PHYS,
- .end = MSM_FW_QDSP6SS_PHYS + SZ_256 - 1,
+ .start = 0x08800000,
+ .end = 0x08800000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
{
- .start = MSM_MSS_ENABLE_PHYS,
- .end = MSM_MSS_ENABLE_PHYS + 4 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct pil_q6v4_pdata msm_8960_q6_mss_fw_data = {
- .strap_tcm_base = 0x00400000,
- .strap_ahb_upper = 0x00090000,
- .strap_ahb_lower = 0x00000080,
- .aclk_reg = SFAB_MSS_Q6_FW_ACLK_CTL,
- .jtag_clk_reg = MSS_Q6FW_JTAG_CLK_CTL,
- .name = "modem_fw",
- .depends = "q6",
- .pas_id = PAS_MODEM_FW,
- .bus_port = MSM_BUS_MASTER_MSS_FW_PROC,
-};
-
-struct platform_device msm_8960_q6_mss_fw = {
- .name = "pil_qdsp6v4",
- .id = 1,
- .num_resources = ARRAY_SIZE(msm_8960_q6_mss_fw_resources),
- .resource = msm_8960_q6_mss_fw_resources,
- .dev.platform_data = &msm_8960_q6_mss_fw_data,
-};
-
-#define MSM_SW_QDSP6SS_PHYS 0x08900000
-#define SFAB_MSS_Q6_SW_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2040)
-#define MSS_Q6SW_JTAG_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C68)
-
-static struct resource msm_8960_q6_mss_sw_resources[] = {
- {
- .start = MSM_SW_QDSP6SS_PHYS,
- .end = MSM_SW_QDSP6SS_PHYS + SZ_256 - 1,
+ .start = 0x08B00000,
+ .end = 0x08B00000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
{
- .start = MSM_MSS_ENABLE_PHYS,
- .end = MSM_MSS_ENABLE_PHYS + 4 - 1,
+ .start = 0x08882000,
+ .end = 0x08882000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
+ {
+ .start = 0x08900000,
+ .end = 0x08900000 + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x08982000,
+ .end = 0x08982000 + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = Q6FW_WDOG_EXPIRED_IRQ,
+ .end = Q6FW_WDOG_EXPIRED_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = Q6SW_WDOG_EXPIRED_IRQ,
+ .end = Q6SW_WDOG_EXPIRED_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
};
-static struct pil_q6v4_pdata msm_8960_q6_mss_sw_data = {
- .strap_tcm_base = 0x00420000,
- .strap_ahb_upper = 0x00090000,
- .strap_ahb_lower = 0x00000080,
- .aclk_reg = SFAB_MSS_Q6_SW_ACLK_CTL,
- .jtag_clk_reg = MSS_Q6SW_JTAG_CLK_CTL,
- .name = "modem",
- .depends = "modem_fw",
- .pas_id = PAS_MODEM_SW,
- .bus_port = MSM_BUS_MASTER_MSS_SW_PROC,
+static struct pil_q6v4_pdata msm_8960_q6_mss_data[2] = {
+ {
+ .strap_tcm_base = 0x00400000,
+ .strap_ahb_upper = 0x00090000,
+ .strap_ahb_lower = 0x00000080,
+ .aclk_reg = MSM_CLK_CTL_BASE + 0x2C6C,
+ .jtag_clk_reg = MSM_CLK_CTL_BASE + 0x2044,
+ .name = "modem_fw",
+ .depends = "q6",
+ .pas_id = PAS_MODEM_FW,
+ .bus_port = MSM_BUS_MASTER_MSS_FW_PROC,
+ },
+ {
+ .strap_tcm_base = 0x00420000,
+ .strap_ahb_upper = 0x00090000,
+ .strap_ahb_lower = 0x00000080,
+ .aclk_reg = MSM_CLK_CTL_BASE + 0x2040,
+ .jtag_clk_reg = MSM_CLK_CTL_BASE + 0x2C68,
+ .name = "modem",
+ .depends = "modem_fw",
+ .pas_id = PAS_MODEM_SW,
+ .bus_port = MSM_BUS_MASTER_MSS_SW_PROC,
+ }
};
-struct platform_device msm_8960_q6_mss_sw = {
- .name = "pil_qdsp6v4",
- .id = 2,
- .num_resources = ARRAY_SIZE(msm_8960_q6_mss_sw_resources),
- .resource = msm_8960_q6_mss_sw_resources,
- .dev.platform_data = &msm_8960_q6_mss_sw_data,
+struct platform_device msm_8960_q6_mss = {
+ .name = "pil-q6v4-modem",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm_8960_q6_mss_resources),
+ .resource = msm_8960_q6_mss_resources,
+ .dev.platform_data = msm_8960_q6_mss_data,
};
static struct resource msm_8960_riva_resources[] = {
@@ -1426,6 +1443,11 @@
.end = 0x03204000 + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
+ {
+ .start = RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
+ .end = RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
};
struct platform_device msm_8960_riva = {
@@ -2917,46 +2939,89 @@
};
static struct msm_dcvs_freq_entry grp3d_freq[] = {
- {0, 0, 333932},
- {0, 0, 497532},
- {0, 0, 707610},
- {0, 0, 844545},
+ {0, 900, 0, 0, 0},
+ {0, 950, 0, 0, 0},
+ {0, 950, 0, 0, 0},
+ {0, 1200, 1, 100, 100},
};
static struct msm_dcvs_freq_entry grp2d_freq[] = {
- {0, 0, 86000},
- {0, 0, 200000},
+ {0, 900, 0, 0, 0},
+ {0, 950, 1, 100, 100},
};
static struct msm_dcvs_core_info grp3d_core_info = {
- .freq_tbl = &grp3d_freq[0],
- .core_param = {
- .max_time_us = 100000,
- .num_freq = ARRAY_SIZE(grp3d_freq),
+ .freq_tbl = &grp3d_freq[0],
+ .core_param = {
+ .core_type = MSM_DCVS_CORE_TYPE_GPU,
},
- .algo_param = {
- .slack_time_us = 39000,
- .disable_pc_threshold = 86000,
- .ss_window_size = 1000000,
- .ss_util_pct = 95,
- .em_max_util_pct = 97,
- .ss_iobusy_conv = 100,
+ .algo_param = {
+ .disable_pc_threshold = 0,
+ .em_win_size_min_us = 100000,
+ .em_win_size_max_us = 300000,
+ .em_max_util_pct = 97,
+ .group_id = 0,
+ .max_freq_chg_time_us = 100000,
+ .slack_mode_dynamic = 0,
+ .slack_weight_thresh_pct = 0,
+ .slack_time_min_us = 39000,
+ .slack_time_max_us = 39000,
+ .ss_win_size_min_us = 1000000,
+ .ss_win_size_max_us = 1000000,
+ .ss_util_pct = 95,
+ .ss_iobusy_conv = 100,
},
+ .energy_coeffs = {
+ .active_coeff_a = 2492,
+ .active_coeff_b = 0,
+ .active_coeff_c = 0,
+
+ .leakage_coeff_a = -17720,
+ .leakage_coeff_b = 37,
+ .leakage_coeff_c = 2729,
+ .leakage_coeff_d = -277,
+ },
+ .power_param = {
+ .current_temp = 25,
+ .num_freq = ARRAY_SIZE(grp3d_freq),
+ }
};
static struct msm_dcvs_core_info grp2d_core_info = {
- .freq_tbl = &grp2d_freq[0],
- .core_param = {
- .max_time_us = 100000,
- .num_freq = ARRAY_SIZE(grp2d_freq),
+ .freq_tbl = &grp2d_freq[0],
+ .core_param = {
+ .core_type = MSM_DCVS_CORE_TYPE_GPU,
},
- .algo_param = {
- .slack_time_us = 39000,
- .disable_pc_threshold = 90000,
- .ss_window_size = 1000000,
- .ss_util_pct = 90,
- .em_max_util_pct = 95,
+ .algo_param = {
+ .disable_pc_threshold = 0,
+ .em_win_size_min_us = 100000,
+ .em_win_size_max_us = 300000,
+ .em_max_util_pct = 97,
+ .group_id = 0,
+ .max_freq_chg_time_us = 100000,
+ .slack_mode_dynamic = 0,
+ .slack_weight_thresh_pct = 0,
+ .slack_time_min_us = 39000,
+ .slack_time_max_us = 39000,
+ .ss_win_size_min_us = 1000000,
+ .ss_win_size_max_us = 1000000,
+ .ss_util_pct = 95,
+ .ss_iobusy_conv = 100,
},
+ .energy_coeffs = {
+ .active_coeff_a = 2492,
+ .active_coeff_b = 0,
+ .active_coeff_c = 0,
+
+ .leakage_coeff_a = -17720,
+ .leakage_coeff_b = 37,
+ .leakage_coeff_c = 2729,
+ .leakage_coeff_d = -277,
+ },
+ .power_param = {
+ .current_temp = 25,
+ .num_freq = ARRAY_SIZE(grp2d_freq),
+ }
};
#ifdef CONFIG_MSM_BUS_SCALING
@@ -3681,6 +3746,37 @@
},
};
+static struct resource resources_rpm_master_stats[] = {
+ {
+ .start = MSM8960_RPM_MASTER_STATS_BASE,
+ .end = MSM8960_RPM_MASTER_STATS_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static char *master_names[] = {
+ "KPSS",
+ "GPSS",
+ "LPASS",
+ "RIVA",
+ "DSPS",
+};
+
+static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
+ .masters = master_names,
+ .nomasters = ARRAY_SIZE(master_names),
+};
+
+struct platform_device msm8960_rpm_master_stat_device = {
+ .name = "msm_rpm_master_stat",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_rpm_master_stats),
+ .resource = resources_rpm_master_stats,
+ .dev = {
+ .platform_data = &msm_rpm_master_stat_pdata,
+ },
+};
+
struct platform_device msm_bus_sys_fabric = {
.name = "msm_bus_fabric",
.id = MSM_BUS_FAB_SYSTEM,
@@ -3705,17 +3801,18 @@
/* Sensors DSPS platform data */
#ifdef CONFIG_MSM_DSPS
-#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
-#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
-#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
-#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
-#define PPSS_DSPS_PIPE_BASE 0x12800000
-#define PPSS_DSPS_PIPE_SIZE 0x4000
-#define PPSS_DSPS_DDR_BASE 0x8fe00000
-#define PPSS_DSPS_DDR_SIZE 0x100000
-#define PPSS_SMEM_BASE 0x80000000
-#define PPSS_SMEM_SIZE 0x200000
-#define PPSS_REG_PHYS_BASE 0x12080000
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
+#define PPSS_DSPS_PIPE_BASE 0x12800000
+#define PPSS_DSPS_PIPE_SIZE 0x4000
+#define PPSS_DSPS_DDR_BASE 0x8fe00000
+#define PPSS_DSPS_DDR_SIZE 0x100000
+#define PPSS_SMEM_BASE 0x80000000
+#define PPSS_SMEM_SIZE 0x200000
+#define PPSS_REG_PHYS_BASE 0x12080000
+#define PPSS_WDOG_UNMASKED_INT_EN 0x1808
static struct dsps_clk_info dsps_clks[] = {};
static struct dsps_regulator_info dsps_regs[] = {};
@@ -3743,6 +3840,7 @@
.ddr_size = PPSS_DSPS_DDR_SIZE,
.smem_start = PPSS_SMEM_BASE,
.smem_size = PPSS_SMEM_SIZE,
+ .ppss_wdog_unmasked_int_en_reg = PPSS_WDOG_UNMASKED_INT_EN,
.signature = DSPS_SIGNATURE,
};
@@ -4003,53 +4101,6 @@
.resource = msm_ebi1_ch1_erp_resources,
};
-static int msm8960_LPM_latency = 1000; /* >100 usec for WFI */
-
-struct platform_device msm8960_cpu_idle_device = {
- .name = "msm_cpu_idle",
- .id = -1,
- .dev = {
- .platform_data = &msm8960_LPM_latency,
- },
-};
-
-static struct msm_dcvs_freq_entry msm8960_freq[] = {
- { 384000, 166981, 345600},
- { 702000, 213049, 632502},
- {1026000, 285712, 925613},
- {1242000, 383945, 1176550},
- {1458000, 419729, 1465478},
- {1512000, 434116, 1546674},
-
-};
-
-static struct msm_dcvs_core_info msm8960_core_info = {
- .freq_tbl = &msm8960_freq[0],
- .core_param = {
- .max_time_us = 100000,
- .num_freq = ARRAY_SIZE(msm8960_freq),
- },
- .algo_param = {
- .slack_time_us = 58000,
- .scale_slack_time = 0,
- .scale_slack_time_pct = 0,
- .disable_pc_threshold = 1458000,
- .em_window_size = 100000,
- .em_max_util_pct = 97,
- .ss_window_size = 1000000,
- .ss_util_pct = 95,
- .ss_iobusy_conv = 100,
- },
-};
-
-struct platform_device msm8960_msm_gov_device = {
- .name = "msm_dcvs_gov",
- .id = -1,
- .dev = {
- .platform_data = &msm8960_core_info,
- },
-};
-
static struct resource msm_cache_erp_resources[] = {
{
.name = "l1_irq",
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index aedd310..fe3a4d5 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -64,6 +64,7 @@
#define MSM_GPIO_I2C_CLK 16
#define MSM_GPIO_I2C_SDA 17
+#define MSM9615_RPM_MASTER_STATS_BASE 0x10A700
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
@@ -713,6 +714,41 @@
.id = -1,
};
+static struct resource msm_9615_q6_lpass_resources[] = {
+ {
+ .start = LPASS_Q6SS_WDOG_EXPIRED,
+ .end = LPASS_Q6SS_WDOG_EXPIRED,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm_9615_q6_lpass = {
+ .name = "pil-q6v4-lpass",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm_9615_q6_lpass_resources),
+ .resource = msm_9615_q6_lpass_resources,
+};
+
+static struct resource msm_9615_q6_mss_resources[] = {
+ {
+ .start = Q6FW_WDOG_EXPIRED_IRQ,
+ .end = Q6FW_WDOG_EXPIRED_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = Q6SW_WDOG_EXPIRED_IRQ,
+ .end = Q6SW_WDOG_EXPIRED_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm_9615_q6_mss = {
+ .name = "pil-q6v4-modem",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(msm_9615_q6_mss_resources),
+ .resource = msm_9615_q6_mss_resources,
+};
+
#ifdef CONFIG_HW_RANDOM_MSM
/* PRNG device */
#define MSM_PRNG_PHYS 0x1A500000
@@ -1325,8 +1361,8 @@
};
static struct msm_rpmstats_platform_data msm_rpm_stat_pdata = {
- .phys_addr_base = 0x0010D204,
- .phys_size = SZ_8K,
+ .phys_addr_base = 0x0010DD04,
+ .phys_size = SZ_256,
};
struct platform_device msm9615_rpm_stat_device = {
@@ -1337,6 +1373,35 @@
},
};
+static struct resource resources_rpm_master_stats[] = {
+ {
+ .start = MSM9615_RPM_MASTER_STATS_BASE,
+ .end = MSM9615_RPM_MASTER_STATS_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static char *master_names[] = {
+ "KPSS",
+ "MPSS",
+ "LPASS",
+};
+
+static struct msm_rpm_master_stats_platform_data msm_rpm_master_stat_pdata = {
+ .masters = master_names,
+ .nomasters = ARRAY_SIZE(master_names),
+};
+
+struct platform_device msm9615_rpm_master_stat_device = {
+ .name = "msm_rpm_master_stat",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_rpm_master_stats),
+ .resource = resources_rpm_master_stats,
+ .dev = {
+ .platform_data = &msm_rpm_master_stat_pdata,
+ },
+};
+
static struct msm_rpm_log_platform_data msm_rpm_log_pdata = {
.phys_addr_base = 0x0010AC00,
.reg_offsets = {
diff --git a/arch/arm/mach-msm/devices-iommu.c b/arch/arm/mach-msm/devices-iommu.c
index acf577e..6434a63 100644
--- a/arch/arm/mach-msm/devices-iommu.c
+++ b/arch/arm/mach-msm/devices-iommu.c
@@ -1017,13 +1017,13 @@
ARRAY_SIZE(msm_iommu_gfx2d_devs));
}
- if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
+ if (cpu_is_apq8064() || cpu_is_msm8960ab() || cpu_is_apq8064ab()) {
platform_add_devices(msm_iommu_jpegd_devs,
ARRAY_SIZE(msm_iommu_jpegd_devs));
platform_add_devices(msm_iommu_adreno3xx_gfx_devs,
ARRAY_SIZE(msm_iommu_adreno3xx_gfx_devs));
}
- if (cpu_is_apq8064())
+ if (cpu_is_apq8064() || cpu_is_apq8064ab())
platform_add_devices(msm_iommu_vcap_devs,
ARRAY_SIZE(msm_iommu_vcap_devs));
@@ -1039,14 +1039,14 @@
ARRAY_SIZE(msm_iommu_gfx2d_ctx_devs));
}
- if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
+ if (cpu_is_apq8064() || cpu_is_msm8960ab() || cpu_is_apq8064ab()) {
platform_add_devices(msm_iommu_jpegd_ctx_devs,
ARRAY_SIZE(msm_iommu_jpegd_ctx_devs));
platform_add_devices(msm_iommu_adreno3xx_ctx_devs,
ARRAY_SIZE(msm_iommu_adreno3xx_ctx_devs));
}
- if (cpu_is_apq8064())
+ if (cpu_is_apq8064() || cpu_is_apq8064ab())
platform_add_devices(msm_iommu_vcap_ctx_devs,
ARRAY_SIZE(msm_iommu_vcap_ctx_devs));
@@ -1081,12 +1081,12 @@
for (i = 0; i < ARRAY_SIZE(msm_iommu_jpegd_devs); i++)
platform_device_unregister(msm_iommu_jpegd_devs[i]);
}
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
for (i = 0; i < ARRAY_SIZE(msm_iommu_vcap_ctx_devs); i++)
platform_device_unregister(msm_iommu_vcap_ctx_devs[i]);
}
- if (cpu_is_apq8064() || cpu_is_msm8960ab()) {
+ if (cpu_is_apq8064() || cpu_is_msm8960ab() || cpu_is_apq8064ab()) {
for (i = 0; i < ARRAY_SIZE(msm_iommu_adreno3xx_ctx_devs);
i++)
platform_device_unregister(
@@ -1097,7 +1097,7 @@
platform_device_unregister(
msm_iommu_jpegd_ctx_devs[i]);
- if (cpu_is_apq8064()) {
+ if (cpu_is_apq8064() || cpu_is_apq8064ab()) {
for (i = 0; i < ARRAY_SIZE(msm_iommu_vcap_devs);
i++)
platform_device_unregister(
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 343ea76..c0ad39b 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -1606,6 +1606,26 @@
},
};
+static struct resource pl310_resources[] = {
+ {
+ .start = 0xC0400000,
+ .end = 0xC0400000 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "l2_irq",
+ .start = MSM8625_INT_L2CC_INTR,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device pl310_erp_device = {
+ .name = "pl310_erp",
+ .id = -1,
+ .resource = pl310_resources,
+ .num_resources = ARRAY_SIZE(pl310_resources),
+};
+
enum {
MSM8625,
MSM8625A,
@@ -1664,12 +1684,13 @@
* These are various Vdd levels supported by PMIC
*/
static uint32_t msm_c2_pmic_mv[] __initdata = {
- 1300000, 1287500, 1275000, 1262500, 1250000,
- 1237500, 1225000, 1212500, 1200000, 1187500,
- 1175000, 1162500, 1150000, 1137500, 1125000,
- 1112500, 1100000, 1087500, 1075000, 1062500,
- 1050000, 1037500, 1025000, 1012500, 0, 0, 0,
- 0, 0, 0, 0, 1000,
+ 1350000, 1337500, 1325000, 1312500, 1300000,
+ 1287500, 1275000, 1262500, 1250000, 1237500,
+ 1225000, 1212500, 1200000, 1187500, 1175000,
+ 1162500, 1150000, 1137500, 1125000, 1112500,
+ 1100000, 1087500, 1075000, 1062500, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1050000,
};
/**
@@ -1709,9 +1730,9 @@
.step_quot = ~0,
.tgt_volt_offset = 0,
.turbo_Vmax = 1350000,
- .turbo_Vmin = 950000,
+ .turbo_Vmin = 1100000,
.nom_Vmax = 1350000,
- .nom_Vmin = 950000,
+ .nom_Vmin = 1100000,
.calibrated_uV = 1300000,
},
};
@@ -1729,7 +1750,7 @@
uint32_t quot;
/* This formula is as per chip characterization data */
- quot = max_quot - (((max_freq - new_freq) * 5) / 10);
+ quot = max_quot - (((max_freq - new_freq) * 7) / 10);
return quot;
}
@@ -1749,7 +1770,7 @@
static struct msm_cpr_config msm_cpr_pdata = {
.ref_clk_khz = 19200,
- .delay_us = 25000,
+ .delay_us = 1000,
.irq_line = 0,
.cpr_mode_data = msm_cpr_mode_data,
.tgt_count_div_N = 1,
@@ -1757,7 +1778,7 @@
.ceiling = 40,
.sw_vlevel = 20,
.up_threshold = 1,
- .dn_threshold = 2,
+ .dn_threshold = 4,
.up_margin = 0,
.dn_margin = 0,
.max_nom_freq = 700800,
@@ -1819,6 +1840,22 @@
* enough to represent the value of maximum quot
*/
msm_cpr_pdata.max_quot = cpr_info->turbo_quot * 10 + 600;
+ /**
+ * Fused Quot value for 1.2GHz on a 1.2GHz part is lower than
+ * the quot value calculated using the scaling factor formula for
+ * 1.2GHz when running on a 1.4GHz part. So, prop up the Quot for
+ * a 1.2GHz part by a chip characterization recommended value.
+ * Ditto for a 1.0GHz part.
+ */
+ if (msm8625_cpu_id() == MSM8625A) {
+ msm_cpr_pdata.max_quot += 100;
+ if (msm_cpr_pdata.max_quot > 1400)
+ msm_cpr_pdata.max_quot = 1400;
+ } else if (msm8625_cpu_id() == MSM8625) {
+ msm_cpr_pdata.max_quot += 120;
+ if (msm_cpr_pdata.max_quot > 1350)
+ msm_cpr_pdata.max_quot = 1350;
+ }
/**
* Bits 4:0 of pvs_fuse provide mapping to the safe boot up voltage.
@@ -1937,6 +1974,11 @@
(SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2))
msm_cpr_init();
+ if (!cpu_is_msm8625())
+ pl310_resources[1].start = INT_L2CC_INTR;
+
+ platform_device_register(&pl310_erp_device);
+
return 0;
}
@@ -2022,6 +2064,7 @@
static struct notifier_block panic_handler = {
.notifier_call = msm7627a_panic_handler,
+ .priority = INT_MAX,
};
static int __init panic_register(void)
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 8b59b14..614037c 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -33,6 +33,6 @@
void __init msm8x25_spm_device_init(void);
void __init msm_pm_register_cpr_ops(void);
void __init msm8x25_kgsl_3d0_init(void);
-void __iomem *core1_reset_base(void);
+void __iomem *core_reset_base(unsigned int);
extern void setup_mm_for_reboot(void);
#endif
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 7bffd9b..37cdc98 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -192,7 +192,9 @@
gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, (void *)MSM_QGIC_CPU_BASE);
}
-#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
+#define MSM_LPASS_QDSP6SS_PHYS 0x28800000
+#define MSM_LPASS_QDSP6SS_WDOG_PHYS 0x28882000
+#define MSM_LPASS_QDSP6SS_IM_PHYS 0x288A0000
static struct resource msm_8660_q6_resources[] = {
{
@@ -200,6 +202,21 @@
.end = MSM_LPASS_QDSP6SS_PHYS + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
+ {
+ .start = MSM_LPASS_QDSP6SS_IM_PHYS,
+ .end = MSM_LPASS_QDSP6SS_IM_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MSM_LPASS_QDSP6SS_WDOG_PHYS,
+ .end = MSM_LPASS_QDSP6SS_WDOG_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = LPASS_Q6SS_WDOG_EXPIRED,
+ .end = LPASS_Q6SS_WDOG_EXPIRED,
+ .flags = IORESOURCE_IRQ,
+ },
};
struct platform_device msm_pil_q6v3 = {
@@ -210,6 +227,7 @@
};
#define MSM_MSS_REGS_PHYS 0x10200000
+#define MSM_MSS_WDOG_PHYS 0x10020000
static struct resource msm_8660_modem_resources[] = {
{
@@ -217,6 +235,16 @@
.end = MSM_MSS_REGS_PHYS + SZ_256 - 1,
.flags = IORESOURCE_MEM,
},
+ {
+ .start = MSM_MSS_WDOG_PHYS,
+ .end = MSM_MSS_WDOG_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MARM_WDOG_EXPIRED,
+ .end = MARM_WDOG_EXPIRED,
+ .flags = IORESOURCE_IRQ,
+ },
};
struct platform_device msm_pil_modem = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 319e6f5..8f02050 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -109,6 +109,10 @@
extern struct platform_device msm_device_sdc3;
extern struct platform_device msm_device_sdc4;
+extern struct platform_device msm8960_pc_cntr;
+extern struct platform_device msm8064_pc_cntr;
+extern struct platform_device msm8930_pc_cntr;
+
extern struct platform_device msm_device_gadget_peripheral;
extern struct platform_device msm_device_hsusb_host;
extern struct platform_device msm_device_hsusb_host2;
@@ -248,8 +252,9 @@
extern struct platform_device msm_pil_dsps;
extern struct platform_device msm_pil_vidc;
extern struct platform_device msm_8960_q6_lpass;
-extern struct platform_device msm_8960_q6_mss_fw;
-extern struct platform_device msm_8960_q6_mss_sw;
+extern struct platform_device msm_9615_q6_lpass;
+extern struct platform_device msm_8960_q6_mss;
+extern struct platform_device msm_9615_q6_mss;
extern struct platform_device msm_8960_riva;
extern struct platform_device msm_gss;
@@ -332,10 +337,12 @@
extern struct platform_device msm8960_rpm_device;
extern struct platform_device msm8960_rpm_stat_device;
+extern struct platform_device msm8960_rpm_master_stat_device;
extern struct platform_device msm8960_rpm_log_device;
extern struct platform_device msm8930_rpm_device;
extern struct platform_device msm8930_rpm_stat_device;
+extern struct platform_device msm8930_rpm_master_stat_device;
extern struct platform_device msm8930_rpm_log_device;
extern struct platform_device msm8930_rpm_rbcpr_device;
@@ -345,10 +352,12 @@
extern struct platform_device msm9615_rpm_device;
extern struct platform_device msm9615_rpm_stat_device;
+extern struct platform_device msm9615_rpm_master_stat_device;
extern struct platform_device msm9615_rpm_log_device;
extern struct platform_device apq8064_rpm_device;
extern struct platform_device apq8064_rpm_stat_device;
+extern struct platform_device apq8064_rpm_master_stat_device;
extern struct platform_device apq8064_rpm_log_device;
extern struct platform_device msm_device_rng;
@@ -391,12 +400,6 @@
extern struct platform_device *msm_8974_stub_regulator_devices[];
extern int msm_8974_stub_regulator_devices_len;
-extern struct platform_device msm8960_cpu_idle_device;
-extern struct platform_device msm8930_cpu_idle_device;
-extern struct platform_device apq8064_cpu_idle_device;
-
-extern struct platform_device msm8960_msm_gov_device;
-extern struct platform_device msm8930_msm_gov_device;
extern struct platform_device apq8064_msm_gov_device;
extern struct platform_device msm_bus_8930_apps_fabric;
@@ -444,6 +447,8 @@
extern struct platform_device msm8960ab_device_acpuclk;
extern struct platform_device msm9615_device_acpuclk;
+extern struct platform_device apq8064_msm_mpd_device;
+
extern struct platform_device msm_gpio_device;
extern struct platform_device apq_cpudai_mi2s;
diff --git a/arch/arm/mach-msm/etm.c b/arch/arm/mach-msm/etm.c
index 6cceff2..ae42733 100644
--- a/arch/arm/mach-msm/etm.c
+++ b/arch/arm/mach-msm/etm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,8 +24,7 @@
#include <linux/pm_qos.h>
#include <asm/atomic.h>
-
-#include "cp14.h"
+#include <asm/hardware/cp14.h>
#define LOG_BUF_LEN 32768
/* each slot is 4 bytes, 8kb total */
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
deleted file mode 100644
index e528650..0000000
--- a/arch/arm/mach-msm/gss-8064.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-
-#include <mach/irqs.h>
-#include <mach/msm_smsm.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-#include <mach/socinfo.h>
-
-#include "smd_private.h"
-#include "modem_notifier.h"
-#include "ramdump.h"
-
-static struct gss_8064_data {
- struct miscdevice gss_dev;
- void *pil_handle;
- void *gss_ramdump_dev;
- void *smem_ramdump_dev;
-} gss_data;
-
-static int crash_shutdown;
-
-static struct subsys_device *gss_8064_dev;
-
-#define MAX_SSR_REASON_LEN 81U
-
-static void log_gss_sfr(void)
-{
- u32 size;
- char *smem_reason, reason[MAX_SSR_REASON_LEN];
-
- smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
- if (!smem_reason || !size) {
- pr_err("GSS subsystem failure reason: (unknown, smem_get_entry failed).\n");
- return;
- }
- if (!smem_reason[0]) {
- pr_err("GSS subsystem failure reason: (unknown, init string found).\n");
- return;
- }
-
- size = min(size, MAX_SSR_REASON_LEN-1);
- memcpy(reason, smem_reason, size);
- reason[size] = '\0';
- pr_err("GSS subsystem failure reason: %s.\n", reason);
-
- smem_reason[0] = '\0';
- wmb();
-}
-
-static void restart_gss(void)
-{
- log_gss_sfr();
- subsystem_restart_dev(gss_8064_dev);
-}
-
-static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
-{
- /* Ignore if we're the one that set SMSM_RESET */
- if (crash_shutdown)
- return;
-
- if (new_state & SMSM_RESET) {
- pr_err("GSS SMSM state changed to SMSM_RESET.\n"
- "Probable err_fatal on the GSS. "
- "Calling subsystem restart...\n");
- restart_gss();
- }
-}
-
-#define Q6_FW_WDOG_ENABLE 0x08882024
-#define Q6_SW_WDOG_ENABLE 0x08982024
-static int gss_shutdown(const struct subsys_desc *desc)
-{
- pil_force_shutdown("gss");
- disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
-
- return 0;
-}
-
-static int gss_powerup(const struct subsys_desc *desc)
-{
- pil_force_boot("gss");
- enable_irq(GSS_A5_WDOG_EXPIRED);
- return 0;
-}
-
-void gss_crash_shutdown(const struct subsys_desc *desc)
-{
- crash_shutdown = 1;
- smsm_reset_modem(SMSM_RESET);
-}
-
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment gss_segments[] = {
- {0x89000000, 0x00D00000}
-};
-
-static struct ramdump_segment smem_segments[] = {
- {0x80000000, 0x00200000},
-};
-
-static int gss_ramdump(int enable,
- const struct subsys_desc *crashed_subsys)
-{
- int ret = 0;
-
- if (enable) {
- ret = do_ramdump(gss_data.gss_ramdump_dev, gss_segments,
- ARRAY_SIZE(gss_segments));
-
- if (ret < 0) {
- pr_err("Unable to dump gss memory (rc = %d).\n",
- ret);
- goto out;
- }
-
- ret = do_ramdump(gss_data.smem_ramdump_dev, smem_segments,
- ARRAY_SIZE(smem_segments));
-
- if (ret < 0) {
- pr_err("Unable to dump smem memory (rc = %d).\n", ret);
- goto out;
- }
- }
-
-out:
- return ret;
-}
-
-static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
-{
- pr_err("Watchdog bite received from GSS!\n");
- restart_gss();
-
- return IRQ_HANDLED;
-}
-
-static struct subsys_desc gss_8064 = {
- .name = "gss",
- .shutdown = gss_shutdown,
- .powerup = gss_powerup,
- .ramdump = gss_ramdump,
- .crash_shutdown = gss_crash_shutdown
-};
-
-static int gss_subsystem_restart_init(void)
-{
- gss_8064_dev = subsys_register(&gss_8064);
- if (IS_ERR(gss_8064_dev))
- return PTR_ERR(gss_8064_dev);
- return 0;
-}
-
-static int gss_open(struct inode *inode, struct file *filep)
-{
- void *ret;
- gss_data.pil_handle = ret = pil_get("gss");
- if (!ret)
- pr_debug("%s - pil_get returned NULL\n", __func__);
- return 0;
-}
-
-static int gss_release(struct inode *inode, struct file *filep)
-{
- pil_put(gss_data.pil_handle);
- pr_debug("%s pil_put called on GSS\n", __func__);
- return 0;
-}
-
-const struct file_operations gss_file_ops = {
- .open = gss_open,
- .release = gss_release,
-};
-
-static int __init gss_8064_init(void)
-{
- int ret;
-
- if (!cpu_is_apq8064())
- return -ENODEV;
-
- ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
- smsm_state_cb, 0);
-
- if (ret < 0)
- pr_err("%s: Unable to register SMSM callback! (%d)\n",
- __func__, ret);
-
- ret = request_irq(GSS_A5_WDOG_EXPIRED, gss_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "gss_a5_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request gss watchdog IRQ. (%d)\n",
- __func__, ret);
- disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
- goto out;
- }
-
- ret = gss_subsystem_restart_init();
-
- if (ret < 0) {
- pr_err("%s: Unable to reg with subsystem restart. (%d)\n",
- __func__, ret);
- goto out;
- }
-
- gss_data.gss_dev.minor = MISC_DYNAMIC_MINOR;
- gss_data.gss_dev.name = "gss";
- gss_data.gss_dev.fops = &gss_file_ops;
- ret = misc_register(&gss_data.gss_dev);
-
- if (ret) {
- pr_err("%s: misc_registers failed for %s (%d)", __func__,
- gss_data.gss_dev.name, ret);
- goto out;
- }
-
- gss_data.gss_ramdump_dev = create_ramdump_device("gss");
-
- if (!gss_data.gss_ramdump_dev) {
- pr_err("%s: Unable to create gss ramdump device. (%d)\n",
- __func__, -ENOMEM);
- ret = -ENOMEM;
- goto out;
- }
-
- gss_data.smem_ramdump_dev = create_ramdump_device("smem-gss");
-
- if (!gss_data.smem_ramdump_dev) {
- pr_err("%s: Unable to create smem ramdump device. (%d)\n",
- __func__, -ENOMEM);
- ret = -ENOMEM;
- goto out;
- }
-
- pr_info("%s: gss fatal driver init'ed.\n", __func__);
-out:
- return ret;
-}
-
-module_init(gss_8064_init);
diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S
index e5ad312..0537421 100644
--- a/arch/arm/mach-msm/headsmp.S
+++ b/arch/arm/mach-msm/headsmp.S
@@ -35,8 +35,6 @@
* we've been released from the holding pen: secondary_stack
* should now contain the SVC stack for this core
*/
- mvn r7, #0 @ -1 to registers
- str r7,[r6] @ back to the pen for ack
b secondary_startup
ENDPROC(msm_secondary_startup)
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index d1d9f4b..f296aae 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -43,7 +43,7 @@
{
}
-static inline void platform_do_lowpower(unsigned int cpu)
+static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
{
/* Just enter wfi for now. TODO: Properly shut off the cpu. */
for (;;) {
@@ -53,9 +53,6 @@
/*
* OK, proper wakeup, we're done
*/
- pen_release = -1;
- dmac_flush_range((char *)&pen_release,
- (char *)&pen_release + sizeof(pen_release));
break;
}
@@ -67,9 +64,7 @@
* possible, since we are currently running incoherently, and
* therefore cannot safely call printk() or anything else
*/
- dmac_inv_range((char *)&pen_release,
- (char *)&pen_release + sizeof(pen_release));
- pr_debug("CPU%u: spurious wakeup call\n", cpu);
+ (*spurious)++;
}
}
@@ -85,6 +80,8 @@
*/
void platform_cpu_die(unsigned int cpu)
{
+ int spurious = 0;
+
if (unlikely(cpu != smp_processor_id())) {
pr_crit("%s: running on %u, should be %u\n",
__func__, smp_processor_id(), cpu);
@@ -95,10 +92,13 @@
* we're ready for shutdown now, so do it
*/
cpu_enter_lowpower();
- platform_do_lowpower(cpu);
+ platform_do_lowpower(cpu, &spurious);
pr_debug("CPU%u: %s: normal wakeup\n", cpu, __func__);
cpu_leave_lowpower();
+
+ if (spurious)
+ pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
}
int platform_cpu_disable(unsigned int cpu)
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 8eed48d..1d8f313 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -330,9 +330,14 @@
ldr pc, [r1] /* jump */
ENTRY(msm_pm_set_l2_flush_flag)
- ldr r1, =msm_pm_flush_l2_flag
- str r0, [r1]
- bx lr
+ ldr r1, =msm_pm_flush_l2_flag
+ str r0, [r1]
+ bx lr
+
+ENTRY(msm_pm_get_l2_flush_flag)
+ ldr r1, =msm_pm_flush_l2_flag
+ ldr r0, [r1]
+ bx lr
.data
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 4abdd04..7a939ab 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -38,6 +38,7 @@
#ifdef CONFIG_CPU_V7
void msm_pm_boot_entry(void);
void msm_pm_set_l2_flush_flag(unsigned int flag);
+int msm_pm_get_l2_flush_flag(void);
extern unsigned long msm_pm_pc_pgd;
extern unsigned long msm_pm_boot_vector[NR_CPUS];
extern uint32_t target_type;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 433fee3..0b53bad 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -586,6 +586,8 @@
void msm_map_msm8226_io(void);
void msm8226_init_irq(void);
void msm8226_init_gpiomux(void);
+void msm_map_msm8910_io(void);
+void msm8910_init_irq(void);
struct mmc_platform_data;
int msm_add_sdcc(unsigned int controller,
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index cf36388..f5a158f 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -95,6 +95,7 @@
VFE_MSG_OUTPUT_SECONDARY,
VFE_MSG_OUTPUT_TERTIARY1,
VFE_MSG_OUTPUT_TERTIARY2,
+ VFE_MSG_V2X_LIVESHOT_PRIMARY,
};
enum vpe_resp_msg {
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 0da0b33..770713d 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -20,6 +20,7 @@
#include <linux/list.h>
#include <linux/clkdev.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <mach/clk.h>
/*
@@ -53,7 +54,7 @@
int (*set_vdd)(struct clk_vdd_class *v_class, int level);
int level_votes[MAX_VDD_LEVELS];
unsigned long cur_level;
- spinlock_t lock;
+ struct mutex lock;
};
#define DEFINE_VDD_CLASS(_name, _set_vdd) \
@@ -61,7 +62,7 @@
.class_name = #_name, \
.set_vdd = _set_vdd, \
.cur_level = ARRAY_SIZE(_name.level_votes), \
- .lock = __SPIN_LOCK_UNLOCKED(lock) \
+ .lock = __MUTEX_INITIALIZER(_name.lock) \
}
enum handoff {
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index b14f145..41a59af6 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -38,6 +38,8 @@
/* Maximum number of SMT entries allowed by the system */
#define MAX_NUM_SMR 128
+#define MAX_NUM_BFB_REGS 32
+
/**
* struct msm_iommu_dev - a single IOMMU hardware instance
* name Human-readable name given to this IOMMU HW instance
@@ -64,6 +66,17 @@
int mids[MAX_NUM_MIDS];
};
+/**
+ * struct msm_iommu_bfb_settings - a set of IOMMU BFB tuning parameters
+ * regs An array of register offsets to configure
+ * data Values to write to corresponding registers
+ * length Number of valid entries in the offset/val arrays
+ */
+struct msm_iommu_bfb_settings {
+ unsigned int regs[MAX_NUM_BFB_REGS];
+ unsigned int data[MAX_NUM_BFB_REGS];
+ int length;
+};
/**
* struct msm_iommu_drvdata - A single IOMMU hardware instance
@@ -75,7 +88,7 @@
* @aclk: Alternate clock for this IOMMU core, if any
* @name: Human-readable name of this IOMMU device
* @gdsc: Regulator needed to power this HW block (v2 only)
- * @nsmr: Size of the SMT on this HW block (v2 only)
+ * @bfb_settings: Optional BFB performance tuning parameters
*
* A msm_iommu_drvdata holds the global driver data about a single piece
* of an IOMMU hardware instance.
@@ -89,7 +102,7 @@
struct clk *aclk;
const char *name;
struct regulator *gdsc;
- unsigned int nsmr;
+ struct msm_iommu_bfb_settings *bfb_settings;
};
/**
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v2.h b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
index b01dbd8..c4991bf 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v2.h
@@ -15,6 +15,8 @@
#define CTX_SHIFT 12
#define CTX_OFFSET 0x8000
+#define IMPLDEF_OFFSET 0x2000
+#define IMPLDEF_LENGTH 0xDFF
#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
#define GET_CTX_REG(reg, base, ctx) \
diff --git a/arch/arm/mach-msm/include/mach/irqs-8625.h b/arch/arm/mach-msm/include/mach/irqs-8625.h
index 413a778..2ec0e21 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8625.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8625.h
@@ -87,6 +87,8 @@
#define MSM8625_INT_CPR_IRQ0 (GIC_SPI_START + 32 + 25)
#define MSM8625_INT_CPR_IRQ1 (GIC_SPI_START + 32 + 26)
#define MSM8625_INT_CPR_IRQ2 (GIC_SPI_START + 32 + 27)
+#define MSM8625_INT_ACSR_MP_CORE_IPC2 (GIC_SPI_START + 32 + 28)
+#define MSM8625_INT_ACSR_MP_CORE_IPC3 (GIC_SPI_START + 32 + 29)
#define MSM8625_INT_ADSP_A11_SMSM MSM8625_INT_ADSP_A11
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8910.h b/arch/arm/mach-msm/include/mach/irqs-8910.h
new file mode 100644
index 0000000..22fdc16
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-8910.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_8910_H
+#define __ASM_ARCH_MSM_IRQS_8910_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15: STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+: SPI (shared peripheral interrupts)
+ */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define INT_ARMQC_PERFMON (GIC_PPI_START + 10)
+
+#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
+#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
+
+#define NR_MSM_IRQS 256
+#define NR_GPIO_IRQS 146
+#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
+#define NR_BOARD_IRQS NR_QPNP_IRQS
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8974.h b/arch/arm/mach-msm/include/mach/irqs-8974.h
index d10b537..8152eca 100644
--- a/arch/arm/mach-msm/include/mach/irqs-8974.h
+++ b/arch/arm/mach-msm/include/mach/irqs-8974.h
@@ -24,9 +24,7 @@
#define GIC_PPI_START 16
#define GIC_SPI_START 32
-#define AVS_SVICINT (GIC_PPI_START + 6)
-#define AVS_SVICINTSWDONE (GIC_PPI_START + 7)
-#define INT_ARMQC_PERFMON (GIC_PPI_START + 10)
+#define INT_ARMQC_PERFMON (GIC_PPI_START + 7)
/* PPI 15 is unused */
#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index f562c40..7aff770 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -60,6 +60,8 @@
#if defined(CONFIG_ARCH_MSM8974)
#include "irqs-8974.h"
+#elif defined(CONFIG_ARCH_MSM8910)
+#include "irqs-8910.h"
#elif defined(CONFIG_ARCH_MPQ8092)
#include "irqs-8092.h"
#elif defined(CONFIG_ARCH_MSM9615)
diff --git a/arch/arm/mach-msm/include/mach/mdm2.h b/arch/arm/mach-msm/include/mach/mdm2.h
index 6ec12c1..fd63fd2 100644
--- a/arch/arm/mach-msm/include/mach/mdm2.h
+++ b/arch/arm/mach-msm/include/mach/mdm2.h
@@ -33,6 +33,7 @@
const unsigned int ramdump_timeout_ms;
int image_upgrade_supported;
struct gpiomux_setting *mdm2ap_status_gpio_run_cfg;
+ int send_shdn;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
index fa7e6f0..e81cee4 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,12 @@
#define CORE_NAME_MAX (32)
#define CORES_MAX (10)
+#define CPU_OFFSET 1 /* used to notify TZ the core number */
+#define GPU_OFFSET (CORES_MAX * 2/3) /* there will be more cpus than gpus,
+ * let the GPU be assigned fewer core
+ * elements and start later
+ */
+
enum msm_core_idle_state {
MSM_DCVS_IDLE_ENTER,
MSM_DCVS_IDLE_EXIT,
@@ -30,43 +36,14 @@
MSM_DCVS_DISABLE_HIGH_LATENCY_MODES,
};
-/**
- * struct msm_dcvs_idle
- *
- * API for idle code to register and send idle enter/exit
- * notifications to msm_dcvs driver.
- */
-struct msm_dcvs_idle {
- const char *core_name;
- /* Enable/Disable idle state/notifications */
- int (*enable)(struct msm_dcvs_idle *self,
- enum msm_core_control_event event);
+struct msm_gov_platform_data {
+ struct msm_dcvs_core_info *info;
+ int latency;
};
/**
- * msm_dcvs_idle_source_register
- * @drv: Pointer to the source driver
- * @return: Handle to be used for sending idle state notifications.
- *
- * Register the idle driver with the msm_dcvs driver to send idle
- * state notifications for the core.
- */
-extern int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv);
-
-/**
- * msm_dcvs_idle_source_unregister
- * @drv: Pointer to the source driver
- * @return:
- * 0 on success
- * -EINVAL
- *
- * Description: Unregister the idle driver with the msm_dcvs driver
- */
-extern int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv);
-
-/**
* msm_dcvs_idle
- * @handle: Handle provided back at registration
+ * @dcvs_core_id: The id returned by msm_dcvs_register_core
* @state: The enter/exit idle state the core is in
* @iowaited: iowait in us
* on iMSM_DCVS_IDLE_EXIT.
@@ -78,7 +55,7 @@
*
* Send idle state notifications to the msm_dcvs driver
*/
-int msm_dcvs_idle(int handle, enum msm_core_idle_state state,
+int msm_dcvs_idle(int dcvs_core_id, enum msm_core_idle_state state,
uint32_t iowaited);
/**
@@ -88,16 +65,22 @@
* before the sink driver can be registered.
*/
struct msm_dcvs_core_info {
- struct msm_dcvs_freq_entry *freq_tbl;
- struct msm_dcvs_core_param core_param;
- struct msm_dcvs_algo_param algo_param;
+ int num_cores;
+ int *sensors;
+ int thermal_poll_ms;
+ struct msm_dcvs_freq_entry *freq_tbl;
+ struct msm_dcvs_core_param core_param;
+ struct msm_dcvs_algo_param algo_param;
+ struct msm_dcvs_energy_curve_coeffs energy_coeffs;
+ struct msm_dcvs_power_params power_param;
};
/**
* msm_dcvs_register_core
- * @core_name: Unique name identifier for the core.
- * @group_id: Cores that are to be grouped for synchronized frequency scaling
+ * @type: whether this is a CPU or a GPU
+ * @type_core_num: The number of the core for a type
* @info: The core specific algorithm parameters.
+ * @sensor: The thermal sensor number of the core in question
* @return :
* 0 on success,
* -ENOSYS,
@@ -106,37 +89,29 @@
* Register the core with msm_dcvs driver. Done once at init before calling
* msm_dcvs_freq_sink_register
* Cores that need to run synchronously must share the same group id.
- * If a core doesnt care to be in any group, the group_id should be 0.
*/
-extern int msm_dcvs_register_core(const char *core_name, uint32_t group_id,
- struct msm_dcvs_core_info *info);
+extern int msm_dcvs_register_core(
+ enum msm_dcvs_core_type type,
+ int type_core_num,
+ struct msm_dcvs_core_info *info,
+ int (*set_frequency)(int type_core_num, unsigned int freq),
+ unsigned int (*get_frequency)(int type_core_num),
+ int (*idle_enable)(int type_core_num,
+ enum msm_core_control_event event),
+ int sensor);
/**
- * struct msm_dcvs_freq
- *
- * API for clock driver code to register and receive frequency change
- * request for the core from the msm_dcvs driver.
- */
-struct msm_dcvs_freq {
- const char *core_name;
- /* Callback from msm_dcvs to set the core frequency */
- int (*set_frequency)(struct msm_dcvs_freq *self,
- unsigned int freq);
- unsigned int (*get_frequency)(struct msm_dcvs_freq *self);
-};
-
-/**
- * msm_dcvs_freq_sink_register
+ * msm_dcvs_freq_sink_start
* @drv: The sink driver
* @return: Handle unique to the core.
*
* Register the clock driver code with the msm_dvs driver to get notified about
* frequency change requests.
*/
-extern int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv);
+extern int msm_dcvs_freq_sink_start(int dcvs_core_id);
/**
- * msm_dcvs_freq_sink_unregister
+ * msm_dcvs_freq_sink_stop
* @drv: The sink driver
* @return:
* 0 on success,
@@ -145,6 +120,13 @@
* Unregister the sink driver for the core. This will cause the source driver
* for the core to stop sending idle pulses.
*/
-extern int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv);
+extern int msm_dcvs_freq_sink_stop(int dcvs_core_id);
+/**
+ * msm_dcvs_update_limits
+ * @drv: The sink driver
+ *
+ * Update the frequency known to dcvs when the limits are changed.
+ */
+extern void msm_dcvs_update_limits(int dcvs_core_id);
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
index 3cc2595..597fdc0 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs_scm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,38 +13,87 @@
#ifndef _ARCH_ARM_MACH_MSM_MSM_DCVS_SCM_H
#define _ARCH_ARM_MACH_MSM_MSM_DCVS_SCM_H
+enum msm_dcvs_core_type {
+ MSM_DCVS_CORE_TYPE_CPU = 0,
+ MSM_DCVS_CORE_TYPE_GPU = 1,
+};
+
+enum msm_dcvs_algo_param_type {
+ MSM_DCVS_ALGO_DCVS_PARAM = 0,
+ MSM_DCVS_ALGO_MPD_PARAM = 1,
+};
+
enum msm_dcvs_scm_event {
- MSM_DCVS_SCM_IDLE_ENTER,
- MSM_DCVS_SCM_IDLE_EXIT,
- MSM_DCVS_SCM_QOS_TIMER_EXPIRED,
- MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
- MSM_DCVS_SCM_ENABLE_CORE,
- MSM_DCVS_SCM_RESET_CORE,
+ MSM_DCVS_SCM_IDLE_ENTER = 0, /* Core enters idle */
+ MSM_DCVS_SCM_IDLE_EXIT = 1, /* Core exits idle */
+ MSM_DCVS_SCM_QOS_TIMER_EXPIRED = 2, /* Core slack timer expired */
+ MSM_DCVS_SCM_CLOCK_FREQ_UPDATE = 3, /* Core freq change complete */
+ MSM_DCVS_SCM_CORE_ONLINE = 4, /* Core is online */
+ MSM_DCVS_SCM_CORE_OFFLINE = 5, /* Core is offline */
+ MSM_DCVS_SCM_CORE_UNAVAILABLE = 6, /* Core is offline + unavailable */
+ MSM_DCVS_SCM_DCVS_ENABLE = 7, /* DCVS is enabled/disabled for core */
+ MSM_DCVS_SCM_MPD_ENABLE = 8, /* Enable/disable MP Decision */
+ MSM_DCVS_SCM_RUNQ_UPDATE = 9, /* Update running threads */
+ MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED = 10, /* MPDecision slack timer */
};
struct msm_dcvs_algo_param {
- uint32_t slack_time_us;
- uint32_t scale_slack_time;
- uint32_t scale_slack_time_pct;
uint32_t disable_pc_threshold;
- uint32_t em_window_size;
+ uint32_t em_win_size_min_us;
+ uint32_t em_win_size_max_us;
uint32_t em_max_util_pct;
- uint32_t ss_window_size;
- uint32_t ss_util_pct;
+ uint32_t group_id;
+ uint32_t max_freq_chg_time_us;
+ uint32_t slack_mode_dynamic;
+ uint32_t slack_time_min_us;
+ uint32_t slack_time_max_us;
+ uint32_t slack_weight_thresh_pct;
uint32_t ss_iobusy_conv;
+ uint32_t ss_win_size_min_us;
+ uint32_t ss_win_size_max_us;
+ uint32_t ss_util_pct;
};
struct msm_dcvs_freq_entry {
- uint32_t freq; /* Core freq in MHz */
- uint32_t idle_energy;
- uint32_t active_energy;
+ uint32_t freq;
+ uint32_t voltage;
+ uint32_t is_trans_level;
+ uint32_t active_energy_offset;
+ uint32_t leakage_energy_offset;
};
-struct msm_dcvs_core_param {
- uint32_t max_time_us;
+struct msm_dcvs_energy_curve_coeffs {
+ int32_t active_coeff_a;
+ int32_t active_coeff_b;
+ int32_t active_coeff_c;
+
+ int32_t leakage_coeff_a;
+ int32_t leakage_coeff_b;
+ int32_t leakage_coeff_c;
+ int32_t leakage_coeff_d;
+};
+
+struct msm_dcvs_power_params {
+ uint32_t current_temp;
uint32_t num_freq; /* number of msm_dcvs_freq_entry passed */
};
+struct msm_dcvs_core_param {
+ uint32_t core_type;
+ uint32_t core_bitmask_id;
+};
+
+struct msm_mpd_algo_param {
+ uint32_t em_win_size_min_us;
+ uint32_t em_win_size_max_us;
+ uint32_t em_max_util_pct;
+ uint32_t mp_em_rounding_point_min;
+ uint32_t mp_em_rounding_point_max;
+ uint32_t online_util_pct_min;
+ uint32_t online_util_pct_max;
+ uint32_t slack_time_min_us;
+ uint32_t slack_time_max_us;
+};
#ifdef CONFIG_MSM_DCVS
/**
@@ -61,20 +110,9 @@
extern int msm_dcvs_scm_init(size_t size);
/**
- * Create an empty core group
- *
- * @return:
- * 0 on success.
- * -ENOMEM: Insufficient memory.
- * -EINVAL: Invalid args.
- */
-extern int msm_dcvs_scm_create_group(uint32_t id);
-
-/**
- * Registers cores as part of a group
+ * Registers cores with the DCVS algo.
*
* @core_id: The core identifier that will be used for communication with DCVS
- * @group_id: The group to which this core will be added to.
* @param: The core parameters
* @freq: Array of frequency and energy values
*
@@ -83,9 +121,8 @@
* -ENOMEM: Insufficient memory.
* -EINVAL: Invalid args.
*/
-extern int msm_dcvs_scm_register_core(uint32_t core_id, uint32_t group_id,
- struct msm_dcvs_core_param *param,
- struct msm_dcvs_freq_entry *freq);
+extern int msm_dcvs_scm_register_core(uint32_t core_id,
+ struct msm_dcvs_core_param *param);
/**
* Set DCVS algorithm parameters
@@ -101,6 +138,33 @@
struct msm_dcvs_algo_param *param);
/**
+ * Set MPDecision algorithm parameters
+ *
+ * @param: The param data structure
+ * 0 on success.
+ * -EINVAL: Invalid args.
+ */
+extern int msm_mpd_scm_set_algo_params(struct msm_mpd_algo_param *param);
+
+/**
+ * Set frequency and power characteristics for the core.
+ *
+ * @param core_id: The core identifier that will be used to interace with the
+ * DCVS algo.
+ * @param pwr_param: power params
+ * @param freq_entry: frequency characteristics desired
+ * @param coeffs: Coefficients that will describe the power curve
+ *
+ * @return int
+ * 0 on success.
+ * -EINVAL: Invalid args.
+ */
+extern int msm_dcvs_scm_set_power_params(uint32_t core_id,
+ struct msm_dcvs_power_params *pwr_param,
+ struct msm_dcvs_freq_entry *freq_entry,
+ struct msm_dcvs_energy_curve_coeffs *coeffs);
+
+/**
* Do an SCM call.
*
* @core_id: The core identifier.
@@ -126,19 +190,44 @@
* @param1: time taken in usec to switch to the frequency
* @ret0: New QoS timer value for the core in usec
* @ret1: unused
- * MSM_DCVS_SCM_ENABLE_CORE
- * @param0: enable(1) or disable(0) core
- * @param1: active clock frequency of the core in KHz
- * @ret0: New clock frequency for the core in KHz
- * @ret1: unused
- * MSM_DCVS_SCM_RESET_CORE
+ * MSM_DCVS_SCM_CORE_ONLINE
* @param0: active clock frequency of the core in KHz
+ * @param1: time taken to online the core
+ * @ret0: unused
+ * @ret1: unused
+ * MSM_DCVS_SCM_CORE_OFFLINE
+ * @param0: time taken to offline the core
+ * @param1: unused
+ * @ret0: unused
+ * @ret1: unused
+ * MSM_DCVS_SCM_CORE_UNAVAILABLE
+ * @param0: TODO:bitmask
+ * @param1: unused
+ * @ret0: Bitmask of cores to bring online/offline.
+ * @ret1: Mp Decision slack time. Common to all cores.
+ * MSM_DCVS_SCM_DCVS_ENABLE
+ * @param0: 1 to enable; 0 to disable DCVS
* @param1: unused
* @ret0: New clock frequency for the core in KHz
* @ret1: unused
- * @return:
- * 0 on success,
- * SCM return values
+ * MSM_DCVS_SCM_MPD_ENABLE
+ * @param0: 1 to enable; 0 to disable MP Decision
+ * @param1: unused
+ * @ret0: unused
+ * @ret1: unused
+ * MSM_DCVS_SCM_RUNQ_UPDATE
+ * @param0: run q value
+ * @param1: unused
+ * @ret0: Bitmask of cores online
+ * @ret1: New QoS timer for MP Decision (usec)
+ * MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED
+ * @param0: unused
+ * @param1: unused
+ * @ret0: Bitmask of cores online
+ * @ret1: New QoS timer for MP Decision (usec)
+ * @return:
+ * 0 on success,
+ * SCM return values
*/
extern int msm_dcvs_scm_event(uint32_t core_id,
enum msm_dcvs_scm_event event_id,
@@ -148,16 +237,21 @@
#else
static inline int msm_dcvs_scm_init(uint32_t phy, size_t bytes)
{ return -ENOSYS; }
-static inline int msm_dcvs_scm_create_group(uint32_t id)
-{ return -ENOSYS; }
static inline int msm_dcvs_scm_register_core(uint32_t core_id,
- uint32_t group_id,
struct msm_dcvs_core_param *param,
struct msm_dcvs_freq_entry *freq)
{ return -ENOSYS; }
static inline int msm_dcvs_scm_set_algo_params(uint32_t core_id,
struct msm_dcvs_algo_param *param)
{ return -ENOSYS; }
+static inline int msm_mpd_scm_set_algo_params(
+ struct msm_mpd_algo_param *param)
+{ return -ENOSYS; }
+static inline int msm_dcvs_set_power_params(uint32_t core_id,
+ struct msm_dcvs_power_params *pwr_param,
+ struct msm_dcvs_freq_entry *freq_entry,
+ struct msm_dcvs_energy_curve_coeffs *coeffs)
+{ return -ENOSYS; }
static inline int msm_dcvs_scm_event(uint32_t core_id,
enum msm_dcvs_scm_event event_id,
uint32_t param0, uint32_t param1,
diff --git a/arch/arm/mach-msm/include/mach/msm_dsps.h b/arch/arm/mach-msm/include/mach/msm_dsps.h
index 0f9dba6..a876798 100644
--- a/arch/arm/mach-msm/include/mach/msm_dsps.h
+++ b/arch/arm/mach-msm/include/mach/msm_dsps.h
@@ -86,6 +86,7 @@
* @smem_start - start of the smem region as physical address
* @smem_size - size of the smem region in bytes
* @ppss_pause_reg - Offset to the PPSS_PAUSE register
+ * @ppss_wdog_unmasked_int_en_reg - Offset to PPSS_WDOG_UNMASKED_INT_EN register
* @signature - signature for validity check.
*/
struct msm_dsps_platform_data {
@@ -109,6 +110,7 @@
int smem_start;
int smem_size;
int ppss_pause_reg;
+ int ppss_wdog_unmasked_int_en_reg;
u32 signature;
};
diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb.h b/arch/arm/mach-msm/include/mach/msm_hsusb.h
index 4e22b0f..c6eb527 100644
--- a/arch/arm/mach-msm/include/mach/msm_hsusb.h
+++ b/arch/arm/mach-msm/include/mach/msm_hsusb.h
@@ -138,6 +138,7 @@
int self_powered;
int is_phy_status_timer_on;
+ bool prop_chg;
};
struct msm_otg_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h b/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h
index 82542b2..831b40e 100644
--- a/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h
+++ b/arch/arm/mach-msm/include/mach/msm_hsusb_hw.h
@@ -100,6 +100,8 @@
#define CONFIG_MAX_PKT(n) ((n) << 16)
#define CONFIG_ZLT (1 << 29) /* stop on zero-len xfer */
#define CONFIG_IOS (1 << 15) /* IRQ on setup */
+#define CONFIG_MULT (3 << 30)
+#define CONFIG_MULT_SHIFT 11
struct ept_queue_item {
unsigned next;
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8092.h b/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
index dec8a58..732aaff 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8092.h
@@ -23,7 +23,7 @@
*
*/
-#define MPQ8092_SHARED_RAM_PHYS 0x0FA00000
+#define MPQ8092_MSM_SHARED_RAM_PHYS 0x0FA00000
#define MPQ8092_QGIC_DIST_PHYS 0xF9000000
#define MPQ8092_QGIC_DIST_SIZE SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
new file mode 100644
index 0000000..e4cd312
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * 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_8910_H
+#define __ASM_ARCH_MSM_IOMAP_8910_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 MSM8910_MSM_SHARED_RAM_PHYS 0x0FA00000
+
+#define MSM8910_APCS_GCC_PHYS 0xF9011000
+#define MSM8910_APCS_GCC_SIZE SZ_4K
+
+#define MSM8910_TLMM_PHYS 0xFD510000
+#define MSM8910_TLMM_SIZE SZ_16K
+
+#define MSM8910_IMEM_PHYS 0xFC42B000
+#define MSM8910_IMEM_SIZE SZ_4K
+
+#ifdef CONFIG_DEBUG_MSM8910_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-9625.h b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
index eecdd67..652563c 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
@@ -34,9 +34,30 @@
#define MSM9625_TLMM_PHYS 0xFD510000
#define MSM9625_TLMM_SIZE SZ_16K
+/*
+ * TODO: Revert IMEM_PHYS back to actual
+ * address 0xfe807800
+ * after IMEM issues resolved.
+ *
+ */
+#define MSM9625_IMEM_PHYS 0xFC42B000
+#define MSM9625_IMEM_SIZE SZ_2K
+
+#define MSM9625_MPM2_PSHOLD_PHYS 0xFC4AB000
+#define MSM9625_MPM2_PSHOLD_SIZE SZ_4K
+
#ifdef CONFIG_DEBUG_MSM9625_UART
#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
#define MSM_DEBUG_UART_PHYS 0xF991E000
#endif
+/*
+ * IMEM is retained for secure watchdog reset
+ * Debug Image looks at actual IMEM to
+ * do memory dumping.
+ */
+
+#define MSM9625_DBG_IMEM_PHYS 0xFE807800
+#define MSM9625_DBG_IMEM_SIZE SZ_4K
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 6f925d4..f372b1e 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -54,7 +54,7 @@
defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
defined(CONFIG_ARCH_MSM9625) || defined(CONFIG_ARCH_MPQ8092) || \
- defined(CONFIG_ARCH_MSM8226)
+ defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8910)
/* Unified iomap */
@@ -101,7 +101,7 @@
#define MSM_DBG_IMEM_BASE IOMEM(0xFB600000) /* 4K */
#define MSM_STRONGLY_ORDERED_PAGE 0xFA0F0000
-#define MSM8625_SECONDARY_PHYS 0x0FE00000
+#define MSM8625_CPU_PHYS 0x0FE00000
#if defined(CONFIG_ARCH_MSM9615) || defined(CONFIG_ARCH_MSM7X27) \
@@ -122,6 +122,7 @@
#include "msm_iomap-9625.h"
#include "msm_iomap-8092.h"
#include "msm_iomap-8226.h"
+#include "msm_iomap-8910.h"
#else
/* Legacy single-target iomap */
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 133a1b3..44b52b6 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -57,8 +57,7 @@
#define SMSM_PWRC 0x00000200
#define SMSM_TIMEWAIT 0x00000400
#define SMSM_TIMEINIT 0x00000800
-#define SMSM_PWRC_EARLY_EXIT 0x00001000
-#define SMSM_LTE_COEX_AWAKE 0x00001000
+#define SMSM_PROC_AWAKE 0x00001000
#define SMSM_WFPI 0x00002000
#define SMSM_SLEEP 0x00004000
#define SMSM_SLEEPEXIT 0x00008000
@@ -97,47 +96,6 @@
#define SMSM_SUBSYS2AP_STATUS 0x00008000
-#ifdef CONFIG_MSM_SMD
-void *smem_alloc(unsigned id, unsigned size);
-#else
-void *smem_alloc(unsigned id, unsigned size)
-{
- return NULL;
-}
-#endif
-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);
-
-/*
- * Changes the global interrupt mask. The set and clear masks are re-applied
- * every time the global interrupt mask is updated for callback registration
- * and de-registration.
- *
- * The clear mask is applied first, so if a bit is set to 1 in both the clear
- * mask and the set mask, the result will be that the interrupt is set.
- *
- * @smsm_entry SMSM entry to change
- * @clear_mask 1 = clear bit, 0 = no-op
- * @set_mask 1 = set bit, 0 = no-op
- *
- * @returns 0 for success, < 0 for error
- */
-int smsm_change_intr_mask(uint32_t smsm_entry,
- uint32_t clear_mask, uint32_t set_mask);
-int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask);
-uint32_t smsm_get_state(uint32_t smsm_entry);
-int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
- void (*notify)(void *, uint32_t old_state, uint32_t new_state),
- void *data);
-int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
- void (*notify)(void *, uint32_t, uint32_t), void *data);
-void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
- uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
-void smsm_reset_modem(unsigned mode);
-void smsm_reset_modem_cont(void);
-void smd_sleep_exit(void);
#define SMEM_NUM_SMD_STREAM_CHANNELS 64
#define SMEM_NUM_SMD_BLOCK_CHANNELS 64
@@ -250,8 +208,128 @@
SMSM_NUM_INTR_MUX = 8,
};
+#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);
+
+/*
+ * Changes the global interrupt mask. The set and clear masks are re-applied
+ * every time the global interrupt mask is updated for callback registration
+ * and de-registration.
+ *
+ * The clear mask is applied first, so if a bit is set to 1 in both the clear
+ * mask and the set mask, the result will be that the interrupt is set.
+ *
+ * @smsm_entry SMSM entry to change
+ * @clear_mask 1 = clear bit, 0 = no-op
+ * @set_mask 1 = set bit, 0 = no-op
+ *
+ * @returns 0 for success, < 0 for error
+ */
+int smsm_change_intr_mask(uint32_t smsm_entry,
+ uint32_t clear_mask, uint32_t set_mask);
+int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask);
+uint32_t smsm_get_state(uint32_t smsm_entry);
+int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
+ void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+ void *data);
+int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
+ void (*notify)(void *, uint32_t, uint32_t), void *data);
+void smsm_print_sleep_info(uint32_t sleep_delay, uint32_t sleep_limit,
+ uint32_t irq_mask, uint32_t wakeup_reason, uint32_t pending_irqs);
+void smsm_reset_modem(unsigned mode);
+void smsm_reset_modem_cont(void);
+void smd_sleep_exit(void);
+
+
int smsm_check_for_modem_crash(void);
void *smem_find(unsigned id, unsigned size);
void *smem_get_entry(unsigned id, unsigned *size);
+#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)
+{
+ return -ENODEV;
+}
+
+/*
+ * Changes the global interrupt mask. The set and clear masks are re-applied
+ * every time the global interrupt mask is updated for callback registration
+ * and de-registration.
+ *
+ * The clear mask is applied first, so if a bit is set to 1 in both the clear
+ * mask and the set mask, the result will be that the interrupt is set.
+ *
+ * @smsm_entry SMSM entry to change
+ * @clear_mask 1 = clear bit, 0 = no-op
+ * @set_mask 1 = set bit, 0 = no-op
+ *
+ * @returns 0 for success, < 0 for error
+ */
+static inline int smsm_change_intr_mask(uint32_t smsm_entry,
+ uint32_t clear_mask, uint32_t set_mask)
+{
+ return -ENODEV;
+}
+
+static inline int smsm_get_intr_mask(uint32_t smsm_entry, uint32_t *intr_mask)
+{
+ return -ENODEV;
+}
+static inline uint32_t smsm_get_state(uint32_t smsm_entry)
+{
+ return 0;
+}
+static inline int smsm_state_cb_register(uint32_t smsm_entry, uint32_t mask,
+ void (*notify)(void *, uint32_t old_state, uint32_t new_state),
+ void *data)
+{
+ return -ENODEV;
+}
+static inline int smsm_state_cb_deregister(uint32_t smsm_entry, uint32_t mask,
+ void (*notify)(void *, uint32_t, uint32_t), void *data)
+{
+ return -ENODEV;
+}
+static inline void smsm_print_sleep_info(uint32_t sleep_delay,
+ uint32_t sleep_limit, uint32_t irq_mask, uint32_t wakeup_reason,
+ uint32_t pending_irqs)
+{
+}
+static inline void smsm_reset_modem(unsigned mode)
+{
+}
+static inline void smsm_reset_modem_cont(void)
+{
+}
+static inline void smd_sleep_exit(void)
+{
+}
+static inline int smsm_check_for_modem_crash(void)
+{
+ return -ENODEV;
+}
+static inline void *smem_find(unsigned id, unsigned size)
+{
+ return NULL;
+}
+#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h b/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
index 92dfe12..2cfdabf 100644
--- a/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
+++ b/arch/arm/mach-msm/include/mach/qdsp5v2/codec_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010, 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -123,7 +123,8 @@
uint64_t bytecount_given;
uint64_t bytecount_query;
- struct list_head pmem_region_queue; /* protected by lock */
+ struct list_head ion_region_queue; /* protected by lock */
+ struct ion_client *client;
int eq_enable;
int eq_needs_commit;
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
index 487e814..da639ce 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
@@ -78,7 +78,7 @@
} __packed;
/* Max number of static located transparent data (bytes) */
-#define USM_MAX_CFG_DATA_SIZE 20
+#define USM_MAX_CFG_DATA_SIZE 100
struct usm_encode_cfg_blk {
u32 frames_per_buf;
u32 format_id;
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.h b/arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
similarity index 81%
rename from arch/arm/mach-msm/qdsp6v2/q6core.h
rename to arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
index cb25d6b..ea345fb 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/q6core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -45,8 +45,18 @@
uint32_t power_collapse;
};
+#define ADSP_CMD_SET_DTS_MODEL_ID 0x00012917
+
+struct adsp_dts_modelid {
+ struct apr_hdr hdr;
+ uint32_t model_ID_size;
+ uint8_t model_ID[128];
+};
+
int core_req_bus_bandwith(u16 bus_id, u32 ab_bps, u32 ib_bps);
uint32_t core_get_adsp_version(void);
+uint32_t core_set_dts_model_id(uint32_t id_size, uint8_t *id);
+
#endif /* __Q6CORE_H__ */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index f6e082d..075d20f 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -32,7 +32,8 @@
RPM_VREG_VERSION_9615,
RPM_VREG_VERSION_8930,
RPM_VREG_VERSION_8930_PM8917,
- RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8930_PM8917,
+ RPM_VREG_VERSION_8960_PM8917,
+ RPM_VREG_VERSION_MAX = RPM_VREG_VERSION_8960_PM8917,
};
#define RPM_VREG_PIN_CTRL_NONE 0x00
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 546cbaf..86045b9 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -54,6 +54,12 @@
of_machine_is_compatible("qcom,msm8226")
#define machine_is_msm8226_sim() \
of_machine_is_compatible("qcom,msm8226-sim")
+#define early_machine_is_msm8910() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8910")
+#define machine_is_msm8910() \
+ of_machine_is_compatible("qcom,msm8910")
+#define machine_is_msm8910_sim() \
+ of_machine_is_compatible("qcom,msm8910-sim")
#else
#define early_machine_is_msm8974() 0
#define machine_is_msm8974() 0
@@ -66,6 +72,9 @@
#define early_machine_is_msm8226() 0
#define machine_is_msm8226() 0
#define machine_is_msm8226_sim() 0
+#define early_machine_is_msm8910() 0
+#define machine_is_msm8910() 0
+#define machine_is_msm8910_sim() 0
#endif
@@ -89,6 +98,7 @@
MSM_CPU_7X25AA,
MSM_CPU_7X25AB,
MSM_CPU_8064,
+ MSM_CPU_8064AB,
MSM_CPU_8930,
MSM_CPU_8930AA,
MSM_CPU_7X27AA,
@@ -98,7 +108,8 @@
MSM_CPU_8625,
MSM_CPU_9625,
MSM_CPU_8092,
- MSM_CPU_8226
+ MSM_CPU_8226,
+ MSM_CPU_8910,
};
enum pmic_model {
@@ -304,6 +315,15 @@
#endif
}
+static inline int cpu_is_apq8064ab(void)
+{
+#ifdef CONFIG_ARCH_APQ8064
+ return read_msm_cpu_type() == MSM_CPU_8064AB;
+#else
+ return 0;
+#endif
+}
+
static inline int cpu_is_msm8930(void)
{
#ifdef CONFIG_ARCH_MSM8930
@@ -405,4 +425,15 @@
#endif
}
+static inline int cpu_is_msm8910(void)
+{
+#ifdef CONFIG_ARCH_MSM8910
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_8910;
+#else
+ return 0;
+#endif
+}
#endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index e0fec65..4b81ce7 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -461,7 +461,9 @@
static struct map_desc msm9625_io_desc[] __initdata = {
MSM_CHIP_DEVICE(APCS_GCC, MSM9625),
MSM_CHIP_DEVICE(TLMM, MSM9625),
+ MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM9625),
MSM_CHIP_DEVICE(TMR, MSM9625),
+ MSM_CHIP_DEVICE(IMEM, MSM9625),
{
.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
.length = MSM_SHARED_RAM_SIZE,
@@ -470,6 +472,7 @@
#ifdef CONFIG_DEBUG_MSM9625_UART
MSM_DEVICE(DEBUG_UART),
#endif
+ MSM_CHIP_DEVICE(DBG_IMEM, MSM9625),
};
void __init msm_map_msm9625_io(void)
@@ -497,7 +500,7 @@
void __init msm_map_mpq8092_io(void)
{
- msm_shared_ram_phys = MSM8092_MSM_SHARED_RAM_PHYS;
+ msm_shared_ram_phys = MPQ8092_MSM_SHARED_RAM_PHYS;
msm_map_io(mpq8092_io_desc, ARRAY_SIZE(mpq8092_io_desc));
}
#endif /* CONFIG_ARCH_MPQ8092 */
@@ -527,3 +530,22 @@
msm_map_io(msm_8226_io_desc, ARRAY_SIZE(msm_8226_io_desc));
}
#endif /* CONFIG_ARCH_MSM8226 */
+
+#ifdef CONFIG_ARCH_MSM8910
+static struct map_desc msm8910_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(APCS_GCC, MSM8910),
+ MSM_CHIP_DEVICE(TLMM, MSM8910),
+ MSM_CHIP_DEVICE(IMEM, MSM8910),
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init msm_map_msm8910_io(void)
+{
+ msm_shared_ram_phys = MSM8910_MSM_SHARED_RAM_PHYS;
+ msm_map_io(msm8910_io_desc, ARRAY_SIZE(msm8910_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8910 */
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
index 4f14b19..24e1c41 100644
--- a/arch/arm/mach-msm/jtag.c
+++ b/arch/arm/mach-msm/jtag.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,11 +20,10 @@
#include <linux/printk.h>
#include <linux/ratelimit.h>
#include <linux/coresight.h>
+#include <asm/hardware/cp14.h>
#include <mach/scm.h>
#include <mach/jtag.h>
-#include "cp14.h"
-
/* DBGv7 with baseline CP14 registers implemented */
#define ARM_DEBUG_ARCH_V7B (0x3)
/* DBGv7 with all CP14 registers implemented */
diff --git a/arch/arm/mach-msm/lpass-8660.c b/arch/arm/mach-msm/lpass-8660.c
deleted file mode 100644
index be18b68..0000000
--- a/arch/arm/mach-msm/lpass-8660.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-
-#include "smd_private.h"
-#include "modem_notifier.h"
-#include "ramdump.h"
-
-#define Q6SS_WDOG_ENABLE 0x28882024
-#define Q6SS_SOFT_INTR_WAKEUP 0x288A001C
-#define MODULE_NAME "lpass_8x60"
-#define SCM_Q6_NMI_CMD 0x1
-
-static struct subsys_device *subsys_8x60_q6_dev;
-
-/* Subsystem restart: QDSP6 data, functions */
-static void *q6_ramdump_dev;
-static void q6_fatal_fn(struct work_struct *);
-static DECLARE_WORK(q6_fatal_work, q6_fatal_fn);
-static void __iomem *q6_wakeup_intr;
-
-static void q6_fatal_fn(struct work_struct *work)
-{
- pr_err("%s: Watchdog bite received from Q6!\n", MODULE_NAME);
- subsystem_restart_dev(subsys_8x60_q6_dev);
- enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
-}
-
-static void send_q6_nmi(void)
-{
- /* Send NMI to QDSP6 via an SCM call. */
- scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
-
- /* Wakeup the Q6 */
- if (q6_wakeup_intr)
- writel_relaxed(0x2000, q6_wakeup_intr);
- else
- pr_warn("lpass-8660: Unable to send wakeup interrupt to Q6.\n");
-
- /* Q6 requires atleast 100ms to dump caches etc.*/
- mdelay(100);
-
- pr_info("subsystem-fatal-8x60: Q6 NMI was sent.\n");
-}
-
-int subsys_q6_shutdown(const struct subsys_desc *crashed_subsys)
-{
- void __iomem *q6_wdog_addr =
- ioremap_nocache(Q6SS_WDOG_ENABLE, 8);
-
- send_q6_nmi();
- writel_relaxed(0x0, q6_wdog_addr);
- /* The write needs to go through before the q6 is shutdown. */
- mb();
- iounmap(q6_wdog_addr);
-
- pil_force_shutdown("q6");
- disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
-
- return 0;
-}
-
-int subsys_q6_powerup(const struct subsys_desc *crashed_subsys)
-{
- int ret = pil_force_boot("q6");
- enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
- return ret;
-}
-
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment q6_segments[] = { {0x46700000, 0x47F00000 -
- 0x46700000}, {0x28400000, 0x12800} };
-static int subsys_q6_ramdump(int enable,
- const struct subsys_desc *crashed_subsys)
-{
- if (enable)
- return do_ramdump(q6_ramdump_dev, q6_segments,
- ARRAY_SIZE(q6_segments));
- else
- return 0;
-}
-
-void subsys_q6_crash_shutdown(const struct subsys_desc *crashed_subsys)
-{
- send_q6_nmi();
-}
-
-static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
-{
- int ret;
-
- ret = schedule_work(&q6_fatal_work);
- disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
-
- return IRQ_HANDLED;
-}
-
-static struct subsys_desc subsys_8x60_q6 = {
- .name = "lpass",
- .shutdown = subsys_q6_shutdown,
- .powerup = subsys_q6_powerup,
- .ramdump = subsys_q6_ramdump,
- .crash_shutdown = subsys_q6_crash_shutdown
-};
-
-static void __exit lpass_fatal_exit(void)
-{
- subsys_unregister(subsys_8x60_q6_dev);
- iounmap(q6_wakeup_intr);
- free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
-}
-
-static int __init lpass_fatal_init(void)
-{
- int ret;
-
- ret = request_irq(LPASS_Q6SS_WDOG_EXPIRED, lpass_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "q6_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request LPASS_Q6SS_WDOG_EXPIRED irq.",
- __func__);
- goto out;
- }
-
- q6_ramdump_dev = create_ramdump_device("lpass");
-
- if (!q6_ramdump_dev) {
- ret = -ENOMEM;
- goto out;
- }
-
- q6_wakeup_intr = ioremap_nocache(Q6SS_SOFT_INTR_WAKEUP, 8);
-
- if (!q6_wakeup_intr)
- pr_warn("lpass-8660: Unable to ioremap q6 wakeup address.");
-
- subsys_8x60_q6_dev = subsys_register(&subsys_8x60_q6);
- if (IS_ERR(subsys_8x60_q6_dev))
- ret = PTR_ERR(subsys_8x60_q6_dev);
-out:
- return ret;
-}
-
-module_init(lpass_fatal_init);
-module_exit(lpass_fatal_exit);
-
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
deleted file mode 100644
index b714a7f..0000000
--- a/arch/arm/mach-msm/lpass-8960.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-
-#include "smd_private.h"
-#include "ramdump.h"
-#include "sysmon.h"
-
-#define SCM_Q6_NMI_CMD 0x1
-#define MODULE_NAME "lpass_8960"
-#define MAX_BUF_SIZE 0x51
-
-/* Subsystem restart: QDSP6 data, functions */
-static void lpass_fatal_fn(struct work_struct *);
-static DECLARE_WORK(lpass_fatal_work, lpass_fatal_fn);
-struct lpass_ssr {
- void *lpass_ramdump_dev;
-} lpass_ssr;
-
-static struct lpass_ssr lpass_ssr_8960;
-static int q6_crash_shutdown;
-
-static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
- void *ss_handle)
-{
- int ret;
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("%s: R-Notify: Shutdown started\n", __func__);
- ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
- SUBSYS_BEFORE_SHUTDOWN);
- if (ret < 0)
- pr_err("%s: sysmon_send_event error %d", __func__,
- ret);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static void *ssr_notif_hdle;
-static struct notifier_block rnb = {
- .notifier_call = riva_notifier_cb,
-};
-
-static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
- void *ss_handle)
-{
- int ret;
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("%s: M-Notify: Shutdown started\n", __func__);
- ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
- SUBSYS_BEFORE_SHUTDOWN);
- if (ret < 0)
- pr_err("%s: sysmon_send_event error %d", __func__,
- ret);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static void *ssr_modem_notif_hdle;
-static struct notifier_block mnb = {
- .notifier_call = modem_notifier_cb,
-};
-
-static void lpass_log_failure_reason(void)
-{
- char *reason;
- char buffer[MAX_BUF_SIZE];
- unsigned size;
-
- reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
-
- if (!reason) {
- pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
- MODULE_NAME);
- return;
- }
-
- if (reason[0] == '\0') {
- pr_err("%s: subsystem failure reason: (unknown, init value found)",
- MODULE_NAME);
- return;
- }
-
- size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
- memcpy(buffer, reason, size);
- buffer[size] = '\0';
- pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
- memset((void *)reason, 0x0, size);
- wmb();
-}
-
-static void lpass_fatal_fn(struct work_struct *work)
-{
- pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
- __func__);
- lpass_log_failure_reason();
- panic(MODULE_NAME ": Resetting the SoC");
-}
-
-static void lpass_smsm_state_cb(void *data, uint32_t old_state,
- uint32_t new_state)
-{
- /* Ignore if we're the one that set SMSM_RESET */
- if (q6_crash_shutdown)
- return;
-
- if (new_state & SMSM_RESET) {
- pr_err("%s: LPASS SMSM state changed to SMSM_RESET,"
- " new_state = 0x%x, old_state = 0x%x\n", __func__,
- new_state, old_state);
- lpass_log_failure_reason();
- panic(MODULE_NAME ": Resetting the SoC");
- }
-}
-
-static void send_q6_nmi(void)
-{
- /* Send NMI to QDSP6 via an SCM call. */
- uint32_t cmd = 0x1;
-
- scm_call(SCM_SVC_UTIL, SCM_Q6_NMI_CMD,
- &cmd, sizeof(cmd), NULL, 0);
-
- /* Q6 requires worstcase 100ms to dump caches etc.*/
- mdelay(100);
- pr_debug("%s: Q6 NMI was sent.\n", __func__);
-}
-
-static int lpass_shutdown(const struct subsys_desc *subsys)
-{
- send_q6_nmi();
- pil_force_shutdown("q6");
- disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
-
- return 0;
-}
-
-static int lpass_powerup(const struct subsys_desc *subsys)
-{
- int ret = pil_force_boot("q6");
- enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
- return ret;
-}
-/* RAM segments - address and size for 8960 */
-static struct ramdump_segment q6_segments[] = { {0x8da00000, 0x8f200000 -
- 0x8da00000}, {0x28400000, 0x20000} };
-static int lpass_ramdump(int enable, const struct subsys_desc *subsys)
-{
- pr_debug("%s: enable[%d]\n", __func__, enable);
- if (enable)
- return do_ramdump(lpass_ssr_8960.lpass_ramdump_dev,
- q6_segments,
- ARRAY_SIZE(q6_segments));
- else
- return 0;
-}
-
-static void lpass_crash_shutdown(const struct subsys_desc *subsys)
-{
- q6_crash_shutdown = 1;
- send_q6_nmi();
-}
-
-static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
-{
- int ret;
-
- pr_debug("%s: rxed irq[0x%x]", __func__, irq);
- disable_irq_nosync(LPASS_Q6SS_WDOG_EXPIRED);
- ret = schedule_work(&lpass_fatal_work);
-
- return IRQ_HANDLED;
-}
-
-static struct subsys_device *lpass_8960_dev;
-
-static struct subsys_desc lpass_8960 = {
- .name = "lpass",
- .shutdown = lpass_shutdown,
- .powerup = lpass_powerup,
- .ramdump = lpass_ramdump,
- .crash_shutdown = lpass_crash_shutdown
-};
-
-static int __init lpass_restart_init(void)
-{
- lpass_8960_dev = subsys_register(&lpass_8960);
- if (IS_ERR(lpass_8960_dev))
- return PTR_ERR(lpass_8960_dev);
- return 0;
-}
-
-static int __init lpass_fatal_init(void)
-{
- int ret;
-
- ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
- lpass_smsm_state_cb, 0);
-
- if (ret < 0)
- pr_err("%s: Unable to register SMSM callback! (%d)\n",
- __func__, ret);
-
- ret = request_irq(LPASS_Q6SS_WDOG_EXPIRED, lpass_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "q6_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request LPASS_Q6SS_WDOG_EXPIRED irq.",
- __func__);
- goto out;
- }
- ret = lpass_restart_init();
- if (ret < 0) {
- pr_err("%s: Unable to reg with lpass ssr. (%d)\n",
- __func__, ret);
- goto out;
- }
-
- lpass_ssr_8960.lpass_ramdump_dev = create_ramdump_device("lpass");
-
- if (!lpass_ssr_8960.lpass_ramdump_dev) {
- pr_err("%s: Unable to create ramdump device.\n",
- __func__);
- ret = -ENOMEM;
- goto out;
- }
- ssr_notif_hdle = subsys_notif_register_notifier("riva",
- &rnb);
- if (IS_ERR(ssr_notif_hdle) < 0) {
- ret = PTR_ERR(ssr_notif_hdle);
- pr_err("%s: subsys_register_notifier for Riva: err = %d\n",
- __func__, ret);
- free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
- goto out;
- }
-
- ssr_modem_notif_hdle = subsys_notif_register_notifier("modem",
- &mnb);
- if (IS_ERR(ssr_modem_notif_hdle) < 0) {
- ret = PTR_ERR(ssr_modem_notif_hdle);
- pr_err("%s: subsys_register_notifier for Modem: err = %d\n",
- __func__, ret);
- subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
- free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
- goto out;
- }
-
- pr_info("%s: lpass SSR driver init'ed.\n", __func__);
-out:
- return ret;
-}
-
-static void __exit lpass_fatal_exit(void)
-{
- subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
- subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
- subsys_unregister(lpass_8960_dev);
- free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
-}
-
-module_init(lpass_fatal_init);
-module_exit(lpass_fatal_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 8218a42..4854fc48 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -22,6 +22,18 @@
#include "pm.h"
#include "rpm-notifier.h"
+
+enum {
+ MSM_LPM_LVL_DBG_SUSPEND_LIMITS = BIT(0),
+ MSM_LPM_LVL_DBG_IDLE_LIMITS = BIT(1),
+};
+
+static int msm_lpm_lvl_dbg_msk;
+
+module_param_named(
+ debug_mask, msm_lpm_lvl_dbg_msk, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
static struct msm_rpmrs_level *msm_lpm_levels;
static int msm_lpm_level_count;
@@ -41,6 +53,7 @@
bool from_idle, bool notify_rpm)
{
int ret = 0;
+ int debug_mask;
struct msm_rpmrs_limits *l = (struct msm_rpmrs_limits *)limits;
ret = msm_rpm_enter_sleep();
@@ -49,6 +62,21 @@
__func__, ret);
goto bail;
}
+ if (from_idle)
+ debug_mask = msm_lpm_lvl_dbg_msk &
+ MSM_LPM_LVL_DBG_IDLE_LIMITS;
+ else
+ debug_mask = msm_lpm_lvl_dbg_msk &
+ MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+
+ if (debug_mask)
+ pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
+ __func__, l->pxo, l->l2_cache,
+ l->vdd_mem_lower_bound,
+ l->vdd_mem_upper_bound,
+ l->vdd_dig_lower_bound,
+ l->vdd_dig_upper_bound);
+
ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
bail:
return ret;
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 48d31f3..364f297 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -104,6 +104,11 @@
struct msm_rpm_request *handle;
};
+enum {
+ MSM_LPM_RPM_RS_TYPE = 0,
+ MSM_LPM_LOCAL_RS_TYPE = 1,
+};
+
struct msm_lpm_resource {
struct msm_lpm_rs_data rs_data;
uint32_t sleep_value;
@@ -126,7 +131,7 @@
.aggregate = msm_lpm_aggregate_l2,
.flush = msm_lpm_flush_l2,
.notify = NULL,
- .valid = true,
+ .valid = false,
.rs_data = {
.value = MSM_LPM_L2_CACHE_ACTIVE,
.default_value = MSM_LPM_L2_CACHE_ACTIVE,
@@ -787,6 +792,7 @@
struct msm_lpm_resource *rs = NULL;
const char *val;
int i;
+ uint32_t resource_type;
key = "qcom,name";
ret = of_property_read_string(node, key, &val);
@@ -810,49 +816,73 @@
continue;
}
- key = "qcom,type";
- ret = of_property_read_u32(node, key, &rs->rs_data.type);
+ key = "qcom,resource-type";
+ ret = of_property_read_u32(node, key, &resource_type);
if (ret) {
- pr_err("Failed to read type\n");
+ pr_err("Failed to read resource-type\n");
goto fail;
}
- key = "qcom,id";
- ret = of_property_read_u32(node, key, &rs->rs_data.id);
- if (ret) {
- pr_err("Failed to read id\n");
+ switch (resource_type) {
+ case MSM_LPM_RPM_RS_TYPE:
+ key = "qcom,type";
+ ret = of_property_read_u32(node, key,
+ &rs->rs_data.type);
+ if (ret) {
+ pr_err("Failed to read type\n");
+ goto fail;
+ }
+
+ key = "qcom,id";
+ ret = of_property_read_u32(node, key, &rs->rs_data.id);
+ if (ret) {
+ pr_err("Failed to read id\n");
+ goto fail;
+ }
+
+ key = "qcom,key";
+ ret = of_property_read_u32(node, key, &rs->rs_data.key);
+ if (ret) {
+ pr_err("Failed to read key\n");
+ goto fail;
+ }
+
+ rs->rs_data.handle = msm_lpm_create_rpm_request(
+ rs->rs_data.type,
+ rs->rs_data.id);
+
+ if (!rs->rs_data.handle) {
+ pr_err("%s: Failed to allocate handle for %s\n",
+ __func__, rs->name);
+ ret = -1;
+ goto fail;
+ }
+ /* fall through */
+
+ case MSM_LPM_LOCAL_RS_TYPE:
+ rs->valid = true;
+ break;
+ default:
+ pr_err("%s: Invalid resource type %d", __func__,
+ resource_type);
goto fail;
}
-
- key = "qcom,key";
- ret = of_property_read_u32(node, key, &rs->rs_data.key);
- if (ret) {
- pr_err("Failed to read key\n");
- goto fail;
- }
-
- rs->rs_data.handle = msm_lpm_create_rpm_request(
- rs->rs_data.type, rs->rs_data.id);
-
- if (!rs->rs_data.handle) {
- pr_err("%s: Failed to allocate handle for %s\n",
- __func__, rs->name);
- ret = -1;
- goto fail;
- }
-
- rs->valid = true;
}
msm_rpm_register_notifier(&msm_lpm_rpm_nblk);
msm_lpm_init_rpm_ctl();
- register_hotcpu_notifier(&msm_lpm_cpu_nblk);
- /* For UP mode, set the default to HSFS OPEN*/
- if (num_possible_cpus() == 1) {
- msm_lpm_l2.rs_data.default_value = MSM_LPM_L2_CACHE_HSFS_OPEN;
- msm_lpm_l2.rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
- }
- msm_pm_set_l2_flush_flag(0);
- return 0;
+
+ if (msm_lpm_l2.valid) {
+ register_hotcpu_notifier(&msm_lpm_cpu_nblk);
+ /* For UP mode, set the default to HSFS OPEN*/
+ if (num_possible_cpus() == 1) {
+ msm_lpm_l2.rs_data.default_value =
+ MSM_LPM_L2_CACHE_HSFS_OPEN;
+ msm_lpm_l2.rs_data.value = MSM_LPM_L2_CACHE_HSFS_OPEN;
+ }
+ msm_pm_set_l2_flush_flag(0);
+ } else
+ msm_pm_set_l2_flush_flag(1);
+
fail:
return ret;
}
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index f548417..77eeb53 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -110,8 +110,12 @@
/* Wait for the modem to complete its power down actions. */
for (i = 20; i > 0; i--) {
- if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+ if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
+ if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
+ pr_info("%s: mdm2ap_status went low, i = %d\n",
+ __func__, i);
break;
+ }
msleep(100);
}
if (i == 0) {
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index ea15a17..58b26f2 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -290,6 +290,17 @@
} else
pr_debug("%s Image upgrade not supported\n", __func__);
break;
+ case SHUTDOWN_CHARM:
+ if (!mdm_drv->pdata->send_shdn)
+ break;
+ mdm_drv->mdm_ready = 0;
+ if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
+ pr_info("Sending shutdown request to mdm\n");
+ ret = sysmon_send_shutdown(SYSMON_SS_EXT_MODEM);
+ if (ret)
+ pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
+ __func__, ret);
+ break;
default:
pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
ret = -EINVAL;
@@ -382,6 +393,9 @@
{
int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
+ if ((mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG) && (value == 0))
+ pr_info("%s: mdm2ap_status went low\n", __func__);
+
pr_debug("%s: mdm sent status change interrupt\n", __func__);
if (value == 0 && mdm_drv->mdm_ready == 1) {
pr_info("%s: unexpected reset external modem\n", __func__);
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index c406b89a..9e865c5 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -14,6 +14,7 @@
#define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
#define MDM_DEBUG_MASK_VDDMIN_SETUP (0x00000002)
+#define MDM_DEBUG_MASK_SHDN_LOG (0x00000004)
#define GPIO_IS_VALID(gpio) \
(gpio != -1)
struct mdm_modem_drv;
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 74c1c4a..a785389 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -173,63 +173,29 @@
struct reserve_info *reserve_info;
-static unsigned long stable_size(struct membank *mb,
- unsigned long unstable_limit)
-{
- unsigned long upper_limit = mb->start + mb->size;
-
- if (!unstable_limit)
- return mb->size;
-
- /* Check for 32 bit roll-over */
- if (upper_limit >= mb->start) {
- /* If we didn't roll over we can safely make the check below */
- if (upper_limit <= unstable_limit)
- return mb->size;
- }
-
- if (mb->start >= unstable_limit)
- return 0;
- return unstable_limit - mb->start;
-}
-
-/* stable size of all memory banks contiguous to and below this one */
-static unsigned long total_stable_size(unsigned long bank)
-{
- int i;
- struct membank *mb = &meminfo.bank[bank];
- int memtype = reserve_info->paddr_to_memtype(mb->start);
- unsigned long size;
-
- size = stable_size(mb, reserve_info->low_unstable_address);
- for (i = bank - 1, mb = &meminfo.bank[bank - 1]; i >= 0; i--, mb--) {
- if (mb->start + mb->size != (mb + 1)->start)
- break;
- if (reserve_info->paddr_to_memtype(mb->start) != memtype)
- break;
- size += stable_size(mb, reserve_info->low_unstable_address);
- }
- return size;
-}
-
+/**
+ * calculate_reserve_limits() - calculate reserve limits for all
+ * memtypes
+ *
+ * for each memtype in the reserve_info->memtype_reserve_table, sets
+ * the `limit' field to the largest size of any memblock of that
+ * memtype.
+ */
static void __init calculate_reserve_limits(void)
{
- int i;
- struct membank *mb;
+ struct memblock_region *mr;
int memtype;
struct memtype_reserve *mt;
- unsigned long size;
- for (i = 0, mb = &meminfo.bank[0]; i < meminfo.nr_banks; i++, mb++) {
- memtype = reserve_info->paddr_to_memtype(mb->start);
+ for_each_memblock(memory, mr) {
+ memtype = reserve_info->paddr_to_memtype(mr->base);
if (memtype == MEMTYPE_NONE) {
- pr_warning("unknown memory type for bank at %lx\n",
- (long unsigned int)mb->start);
+ pr_warning("unknown memory type for region at %lx\n",
+ (long unsigned int)mr->base);
continue;
}
mt = &reserve_info->memtype_reserve_table[memtype];
- size = total_stable_size(i);
- mt->limit = max(mt->limit, size);
+ mt->limit = max_t(unsigned long, mt->limit, mr->size);
}
}
@@ -252,50 +218,38 @@
static void __init reserve_memory_for_mempools(void)
{
- int i, memtype, membank_type;
+ int memtype, memreg_type;
struct memtype_reserve *mt;
- struct membank *mb;
+ struct memblock_region *mr, *mr_candidate = NULL;
int ret;
- unsigned long size;
mt = &reserve_info->memtype_reserve_table[0];
for (memtype = 0; memtype < MEMTYPE_MAX; memtype++, mt++) {
if (mt->flags & MEMTYPE_FLAGS_FIXED || !mt->size)
continue;
- /* We know we will find memory bank(s) of the proper size
- * as we have limited the size of the memory pool for
- * each memory type to the largest total size of the memory
- * banks which are contiguous and of the correct memory type.
- * Choose the memory bank with the highest physical
+ /* Choose the memory block with the highest physical
* address which is large enough, so that we will not
* take memory from the lowest memory bank which the kernel
* is in (and cause boot problems) and so that we might
* be able to steal memory that would otherwise become
- * highmem. However, do not use unstable memory.
+ * highmem.
*/
- for (i = meminfo.nr_banks - 1; i >= 0; i--) {
- mb = &meminfo.bank[i];
- membank_type =
- reserve_info->paddr_to_memtype(mb->start);
- if (memtype != membank_type)
+ for_each_memblock(memory, mr) {
+ memreg_type =
+ reserve_info->paddr_to_memtype(mr->base);
+ if (memtype != memreg_type)
continue;
- size = total_stable_size(i);
- if (size >= mt->size) {
- size = stable_size(mb,
- reserve_info->low_unstable_address);
- if (!size)
- continue;
- /* mt->size may be larger than size, all this
- * means is that we are carving the memory pool
- * out of multiple contiguous memory banks.
- */
- mt->start = mb->start + (size - mt->size);
- ret = memblock_remove(mt->start, mt->size);
- BUG_ON(ret);
- break;
- }
+ if (mr->size >= mt->size
+ && (mr_candidate == NULL
+ || mr->base > mr_candidate->base))
+ mr_candidate = mr;
}
+ BUG_ON(mr_candidate == NULL);
+ /* bump mt up against the top of the region */
+ mt->start = mr_candidate->base + mr_candidate->size - mt->size;
+ ret = memblock_remove(mt->start, mt->size);
+ BUG_ON(ret);
}
}
diff --git a/arch/arm/mach-msm/modem-8660.c b/arch/arm/mach-msm/modem-8660.c
deleted file mode 100644
index 096ed9c..0000000
--- a/arch/arm/mach-msm/modem-8660.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-
-#include "smd_private.h"
-#include "modem_notifier.h"
-#include "ramdump.h"
-
-#define MODEM_HWIO_MSS_RESET_ADDR 0x00902C48
-#define MODULE_NAME "modem_8660"
-#define MODEM_WDOG_ENABLE 0x10020008
-#define MODEM_CLEANUP_DELAY_MS 20
-
-#define SUBSYS_FATAL_DEBUG
-
-#if defined(SUBSYS_FATAL_DEBUG)
-static void debug_crash_modem_fn(struct work_struct *);
-static int reset_modem;
-static int ignore_smsm_ack;
-
-static DECLARE_DELAYED_WORK(debug_crash_modem_work,
- debug_crash_modem_fn);
-
-module_param(reset_modem, int, 0644);
-#endif
-
-static struct subsys_device *modem_8660_dev;
-
-/* Subsystem restart: Modem data, functions */
-static void *modem_ramdump_dev;
-static void modem_fatal_fn(struct work_struct *);
-static void modem_unlock_timeout(struct work_struct *work);
-static int modem_notif_handler(struct notifier_block *this,
- unsigned long code,
- void *_cmd);
-static DECLARE_WORK(modem_fatal_work, modem_fatal_fn);
-static DECLARE_DELAYED_WORK(modem_unlock_timeout_work,
- modem_unlock_timeout);
-
-static struct notifier_block modem_notif_nb = {
- .notifier_call = modem_notif_handler,
-};
-
-static void modem_unlock_timeout(struct work_struct *work)
-{
- void __iomem *hwio_modem_reset_addr =
- ioremap_nocache(MODEM_HWIO_MSS_RESET_ADDR, 8);
- pr_crit("%s: Timeout waiting for modem to unlock.\n", MODULE_NAME);
-
- /* Set MSS_MODEM_RESET to 0x0 since the unlock didn't work */
- writel_relaxed(0x0, hwio_modem_reset_addr);
- /* Write needs to go through before the modem is restarted. */
- mb();
- iounmap(hwio_modem_reset_addr);
-
- subsystem_restart_dev(modem_8660_dev);
- enable_irq(MARM_WDOG_EXPIRED);
-}
-
-static void modem_fatal_fn(struct work_struct *work)
-{
- uint32_t modem_state;
- uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
- uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
- SMSM_SYSTEM_PWRDWN_USR;
-
- pr_err("%s: Watchdog bite received from modem!\n", MODULE_NAME);
-
- modem_state = smsm_get_state(SMSM_MODEM_STATE);
- pr_err("%s: Modem SMSM state = 0x%x!", MODULE_NAME, modem_state);
-
- if (modem_state == 0 || modem_state & panic_smsm_states) {
-
- subsystem_restart_dev(modem_8660_dev);
- enable_irq(MARM_WDOG_EXPIRED);
-
- } else if (modem_state & reset_smsm_states) {
-
- pr_err("%s: User-invoked system reset/powerdown.",
- MODULE_NAME);
- kernel_restart(NULL);
-
- } else {
-
- int ret;
- void *hwio_modem_reset_addr =
- ioremap_nocache(MODEM_HWIO_MSS_RESET_ADDR, 8);
-
- pr_err("%s: Modem AHB locked up.\n", MODULE_NAME);
- pr_err("%s: Trying to free up modem!\n", MODULE_NAME);
-
- writel_relaxed(0x3, hwio_modem_reset_addr);
-
- /* If we are still alive after 6 seconds (allowing for
- * the 5-second-delayed-panic-reboot), modem is either
- * still wedged or SMSM didn't come through. Force panic
- * in that case.
- */
- ret = schedule_delayed_work(&modem_unlock_timeout_work,
- msecs_to_jiffies(6000));
-
- iounmap(hwio_modem_reset_addr);
- }
-}
-
-static int modem_notif_handler(struct notifier_block *this,
- unsigned long code,
- void *_cmd)
-{
- if (code == MODEM_NOTIFIER_START_RESET) {
- if (ignore_smsm_ack) {
- ignore_smsm_ack = 0;
- goto out;
- }
- pr_err("%s: Modem error fatal'ed.", MODULE_NAME);
- subsystem_restart_dev(modem_8660_dev);
- }
-out:
- return NOTIFY_DONE;
-}
-
-static int modem_shutdown(const struct subsys_desc *crashed_subsys)
-{
- void __iomem *modem_wdog_addr;
-
- /* If the modem didn't already crash, setting SMSM_RESET
- * here will help flush caches etc. The ignore_smsm_ack
- * flag is set to ignore the SMSM_RESET notification
- * that is generated due to the modem settings its own
- * SMSM_RESET bit in response to the apps setting the
- * apps SMSM_RESET bit.
- */
- if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
- ignore_smsm_ack = 1;
- smsm_reset_modem(SMSM_RESET);
- }
-
- /* Disable the modem watchdog to allow clean modem bootup */
- modem_wdog_addr = ioremap_nocache(MODEM_WDOG_ENABLE, 8);
- writel_relaxed(0x0, modem_wdog_addr);
-
- /*
- * The write above needs to go through before the modem is
- * powered up again (subsystem restart).
- */
- mb();
- iounmap(modem_wdog_addr);
-
- /* Wait here to allow the modem to clean up caches etc. */
- msleep(MODEM_CLEANUP_DELAY_MS);
- pil_force_shutdown("modem");
- disable_irq_nosync(MARM_WDOG_EXPIRED);
-
-
-
- return 0;
-}
-
-static int modem_powerup(const struct subsys_desc *crashed_subsys)
-{
- int ret;
-
- ret = pil_force_boot("modem");
- enable_irq(MARM_WDOG_EXPIRED);
-
- return ret;
-}
-
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment modem_segments[] = {
- {0x42F00000, 0x46000000 - 0x42F00000} };
-
-static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
-{
- if (enable)
- return do_ramdump(modem_ramdump_dev, modem_segments,
- ARRAY_SIZE(modem_segments));
- else
- return 0;
-}
-
-static void modem_crash_shutdown(const struct subsys_desc *crashed_subsys)
-{
- /* If modem hasn't already crashed, send SMSM_RESET. */
- if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
- modem_unregister_notifier(&modem_notif_nb);
- smsm_reset_modem(SMSM_RESET);
- }
-
- /* Wait to allow the modem to clean up caches etc. */
- mdelay(5);
-}
-
-static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
-{
- int ret;
-
- ret = schedule_work(&modem_fatal_work);
- disable_irq_nosync(MARM_WDOG_EXPIRED);
-
- return IRQ_HANDLED;
-}
-
-static struct subsys_desc subsys_8660_modem = {
- .name = "modem",
- .shutdown = modem_shutdown,
- .powerup = modem_powerup,
- .ramdump = modem_ramdump,
- .crash_shutdown = modem_crash_shutdown
-};
-
-static int __init modem_8660_init(void)
-{
- int ret;
-
- /* Need to listen for SMSM_RESET always */
- modem_register_notifier(&modem_notif_nb);
-
-#if defined(SUBSYS_FATAL_DEBUG)
- schedule_delayed_work(&debug_crash_modem_work, msecs_to_jiffies(5000));
-#endif
-
- ret = request_irq(MARM_WDOG_EXPIRED, modem_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "modem_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request MARM_WDOG_EXPIRED irq.",
- __func__);
- goto out;
- }
-
- modem_ramdump_dev = create_ramdump_device("modem");
-
- if (!modem_ramdump_dev) {
- ret = -ENOMEM;
- goto out;
- }
-
- modem_8660_dev = subsys_register(&subsys_8660_modem);
- if (IS_ERR(modem_8660_dev))
- ret = PTR_ERR(modem_8660_dev);
-out:
- return ret;
-}
-
-static void __exit modem_8660_exit(void)
-{
- subsys_unregister(modem_8660_dev);
- free_irq(MARM_WDOG_EXPIRED, NULL);
-}
-
-#ifdef SUBSYS_FATAL_DEBUG
-static void debug_crash_modem_fn(struct work_struct *work)
-{
- if (reset_modem == 1)
- smsm_reset_modem(SMSM_RESET);
-
- reset_modem = 0;
- schedule_delayed_work(&debug_crash_modem_work, msecs_to_jiffies(1000));
-}
-#endif
-
-module_init(modem_8660_init);
-module_exit(modem_8660_exit);
-
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
deleted file mode 100644
index f0a123b..0000000
--- a/arch/arm/mach-msm/modem-8960.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-#include <mach/socinfo.h>
-#include <mach/msm_smsm.h>
-
-#include "smd_private.h"
-#include "modem_notifier.h"
-#include "ramdump.h"
-
-static int crash_shutdown;
-
-static struct subsys_device *modem_8960_dev;
-
-#define MAX_SSR_REASON_LEN 81U
-
-static void log_modem_sfr(void)
-{
- u32 size;
- char *smem_reason, reason[MAX_SSR_REASON_LEN];
-
- smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
- if (!smem_reason || !size) {
- pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
- return;
- }
- if (!smem_reason[0]) {
- pr_err("modem subsystem failure reason: (unknown, init string found).\n");
- return;
- }
-
- size = min(size, MAX_SSR_REASON_LEN-1);
- memcpy(reason, smem_reason, size);
- reason[size] = '\0';
- pr_err("modem subsystem failure reason: %s.\n", reason);
-
- smem_reason[0] = '\0';
- wmb();
-}
-
-static void restart_modem(void)
-{
- log_modem_sfr();
- subsystem_restart_dev(modem_8960_dev);
-}
-
-static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
-{
- /* Ignore if we're the one that set SMSM_RESET */
- if (crash_shutdown)
- return;
-
- if (new_state & SMSM_RESET) {
- pr_err("Probable fatal error on the modem.\n");
- restart_modem();
- }
-}
-
-#define Q6_FW_WDOG_ENABLE 0x08882024
-#define Q6_SW_WDOG_ENABLE 0x08982024
-
-static int modem_shutdown(const struct subsys_desc *subsys)
-{
- void __iomem *q6_fw_wdog_addr;
- void __iomem *q6_sw_wdog_addr;
-
- /*
- * Disable the modem watchdog since it keeps running even after the
- * modem is shutdown.
- */
- q6_fw_wdog_addr = ioremap_nocache(Q6_FW_WDOG_ENABLE, 4);
- if (!q6_fw_wdog_addr)
- return -ENOMEM;
-
- q6_sw_wdog_addr = ioremap_nocache(Q6_SW_WDOG_ENABLE, 4);
- if (!q6_sw_wdog_addr) {
- iounmap(q6_fw_wdog_addr);
- return -ENOMEM;
- }
-
- writel_relaxed(0x0, q6_fw_wdog_addr);
- writel_relaxed(0x0, q6_sw_wdog_addr);
- mb();
- iounmap(q6_sw_wdog_addr);
- iounmap(q6_fw_wdog_addr);
-
- pil_force_shutdown("modem");
- pil_force_shutdown("modem_fw");
- disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
- disable_irq_nosync(Q6SW_WDOG_EXPIRED_IRQ);
-
- return 0;
-}
-
-#define MODEM_WDOG_CHECK_TIMEOUT_MS 10000
-
-static int modem_powerup(const struct subsys_desc *subsys)
-{
- pil_force_boot("modem_fw");
- pil_force_boot("modem");
- enable_irq(Q6FW_WDOG_EXPIRED_IRQ);
- enable_irq(Q6SW_WDOG_EXPIRED_IRQ);
- return 0;
-}
-
-void modem_crash_shutdown(const struct subsys_desc *subsys)
-{
- crash_shutdown = 1;
- smsm_reset_modem(SMSM_RESET);
-}
-
-/* FIXME: Get address, size from PIL */
-static struct ramdump_segment modemsw_segments[] = {
- {0x89000000, 0x8D400000 - 0x89000000},
-};
-
-static struct ramdump_segment modemfw_segments[] = {
- {0x8D400000, 0x8DA00000 - 0x8D400000},
-};
-
-static struct ramdump_segment smem_segments[] = {
- {0x80000000, 0x00200000},
-};
-
-static void *modemfw_ramdump_dev;
-static void *modemsw_ramdump_dev;
-static void *smem_ramdump_dev;
-
-static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
-{
- int ret = 0;
-
- if (enable) {
- ret = do_ramdump(modemsw_ramdump_dev, modemsw_segments,
- ARRAY_SIZE(modemsw_segments));
-
- if (ret < 0) {
- pr_err("Unable to dump modem sw memory (rc = %d).\n",
- ret);
- goto out;
- }
-
- ret = do_ramdump(modemfw_ramdump_dev, modemfw_segments,
- ARRAY_SIZE(modemfw_segments));
-
- if (ret < 0) {
- pr_err("Unable to dump modem fw memory (rc = %d).\n",
- ret);
- goto out;
- }
-
- ret = do_ramdump(smem_ramdump_dev, smem_segments,
- ARRAY_SIZE(smem_segments));
-
- if (ret < 0) {
- pr_err("Unable to dump smem memory (rc = %d).\n", ret);
- goto out;
- }
- }
-
-out:
- return ret;
-}
-
-static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
-{
- switch (irq) {
-
- case Q6SW_WDOG_EXPIRED_IRQ:
- pr_err("Watchdog bite received from modem software!\n");
- restart_modem();
- break;
- case Q6FW_WDOG_EXPIRED_IRQ:
- pr_err("Watchdog bite received from modem firmware!\n");
- restart_modem();
- break;
- break;
-
- default:
- pr_err("%s: Unknown IRQ!\n", __func__);
- }
-
- return IRQ_HANDLED;
-}
-
-static struct subsys_desc modem_8960 = {
- .name = "modem",
- .shutdown = modem_shutdown,
- .powerup = modem_powerup,
- .ramdump = modem_ramdump,
- .crash_shutdown = modem_crash_shutdown
-};
-
-static int modem_subsystem_restart_init(void)
-{
- modem_8960_dev = subsys_register(&modem_8960);
- if (IS_ERR(modem_8960_dev))
- return PTR_ERR(modem_8960_dev);
- return 0;
-}
-
-static int modem_debug_set(void *data, u64 val)
-{
- if (val == 1)
- subsystem_restart_dev(modem_8960_dev);
-
- return 0;
-}
-
-static int modem_debug_get(void *data, u64 *val)
-{
- *val = 0;
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(modem_debug_fops, modem_debug_get, modem_debug_set,
- "%llu\n");
-
-static int modem_debugfs_init(void)
-{
- struct dentry *dent;
- dent = debugfs_create_dir("modem_debug", 0);
-
- if (IS_ERR(dent))
- return PTR_ERR(dent);
-
- debugfs_create_file("reset_modem", 0644, dent, NULL,
- &modem_debug_fops);
- return 0;
-}
-
-static int __init modem_8960_init(void)
-{
- int ret;
-
- if (cpu_is_apq8064())
- return -ENODEV;
-
- ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
- smsm_state_cb, 0);
-
- if (ret < 0)
- pr_err("%s: Unable to register SMSM callback! (%d)\n",
- __func__, ret);
-
- ret = request_irq(Q6FW_WDOG_EXPIRED_IRQ, modem_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "modem_wdog_fw", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request q6fw watchdog IRQ. (%d)\n",
- __func__, ret);
- goto out;
- }
-
- ret = request_irq(Q6SW_WDOG_EXPIRED_IRQ, modem_wdog_bite_irq,
- IRQF_TRIGGER_RISING, "modem_wdog_sw", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to request q6sw watchdog IRQ. (%d)\n",
- __func__, ret);
- disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
- goto out;
- }
-
- ret = modem_subsystem_restart_init();
-
- if (ret < 0) {
- pr_err("%s: Unable to reg with subsystem restart. (%d)\n",
- __func__, ret);
- goto out;
- }
-
- modemfw_ramdump_dev = create_ramdump_device("modem_fw");
-
- if (!modemfw_ramdump_dev) {
- pr_err("%s: Unable to create modem fw ramdump device. (%d)\n",
- __func__, -ENOMEM);
- ret = -ENOMEM;
- goto out;
- }
-
- modemsw_ramdump_dev = create_ramdump_device("modem_sw");
-
- if (!modemsw_ramdump_dev) {
- pr_err("%s: Unable to create modem sw ramdump device. (%d)\n",
- __func__, -ENOMEM);
- ret = -ENOMEM;
- goto out;
- }
-
- smem_ramdump_dev = create_ramdump_device("smem-modem");
-
- if (!smem_ramdump_dev) {
- pr_err("%s: Unable to create smem ramdump device. (%d)\n",
- __func__, -ENOMEM);
- ret = -ENOMEM;
- goto out;
- }
-
- ret = modem_debugfs_init();
-
- pr_info("%s: modem fatal driver init'ed.\n", __func__);
-out:
- return ret;
-}
-
-module_init(modem_8960_init);
diff --git a/arch/arm/mach-msm/modem-ssr-8974.c b/arch/arm/mach-msm/modem-ssr-8974.c
index fec578f..942eca5 100644
--- a/arch/arm/mach-msm/modem-ssr-8974.c
+++ b/arch/arm/mach-msm/modem-ssr-8974.c
@@ -15,10 +15,14 @@
#include <linux/module.h>
#include <linux/err.h>
+#include <mach/peripheral-loader.h>
#include <mach/subsystem_restart.h>
#include <mach/msm_smsm.h>
+#include "ramdump.h"
+
static int crash_shutdown;
+static int modem_ssr_ignore_errors;
static struct subsys_device *modem_ssr_dev;
#define MAX_SSR_REASON_LEN 81U
@@ -50,6 +54,7 @@
static void restart_modem(void)
{
log_modem_sfr();
+ modem_ssr_ignore_errors = 1;
subsystem_restart("modem");
}
@@ -67,11 +72,21 @@
static int modem_shutdown(const struct subsys_desc *subsys)
{
+ pil_force_shutdown("modem");
+ pil_force_shutdown("mba");
return 0;
}
static int modem_powerup(const struct subsys_desc *subsys)
{
+ /*
+ * At this time, the modem is shutdown. Therefore this function cannot
+ * run concurrently with either the watchdog bite error handler or the
+ * SMSM callback, making it safe to unset the flag below.
+ */
+ modem_ssr_ignore_errors = 0;
+ pil_force_boot("mba");
+ pil_force_boot("modem");
return 0;
}
@@ -81,15 +96,53 @@
smsm_reset_modem(SMSM_RESET);
}
-static int modem_ramdump(int enable,
- const struct subsys_desc *crashed_subsys)
+static struct ramdump_segment modem_segments[] = {
+ {0x08400000, 0x0D100000 - 0x08400000},
+};
+
+static struct ramdump_segment smem_segments[] = {
+ {0x0FA00000, 0x0FC00000 - 0x0FA00000},
+};
+
+static void *modem_ramdump_dev;
+static void *smem_ramdump_dev;
+
+static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
{
- return 0;
+ int ret = 0;
+
+ if (!enable)
+ return ret;
+
+ pil_force_boot("mba");
+
+ ret = do_ramdump(modem_ramdump_dev, modem_segments,
+ ARRAY_SIZE(modem_segments));
+
+ if (ret < 0) {
+ pr_err("Unable to dump modem fw memory (rc = %d).\n",
+ ret);
+ goto out;
+ }
+
+ ret = do_ramdump(smem_ramdump_dev, smem_segments,
+ ARRAY_SIZE(smem_segments));
+
+ if (ret < 0) {
+ pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+ goto out;
+ }
+
+out:
+ pil_force_shutdown("mba");
+ return ret;
}
static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
{
- pr_err("Watchdog bite received from modem software!\n");
+ if (modem_ssr_ignore_errors)
+ return IRQ_HANDLED;
+ pr_err("Watchdog bite received from the modem!\n");
restart_modem();
return IRQ_HANDLED;
}
@@ -133,9 +186,27 @@
goto out;
}
+ modem_ramdump_dev = create_ramdump_device("modem");
+
+ if (!modem_ramdump_dev) {
+ pr_err("%s: Unable to create a modem ramdump device.\n",
+ __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ smem_ramdump_dev = create_ramdump_device("smem-modem");
+
+ if (!smem_ramdump_dev) {
+ pr_err("%s: Unable to create an smem ramdump device.\n",
+ __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
pr_info("%s: modem subsystem restart driver init'ed.\n", __func__);
out:
return ret;
}
-arch_initcall(modem_8974_init);
+module_init(modem_8974_init);
diff --git a/arch/arm/mach-msm/mpm.c b/arch/arm/mach-msm/mpm.c
index 1c39415..5127607 100644
--- a/arch/arm/mach-msm/mpm.c
+++ b/arch/arm/mach-msm/mpm.c
@@ -388,6 +388,7 @@
{
unsigned long *apps_irq_bitmap;
int debug_mask;
+ int i = 0;
if (from_idle) {
apps_irq_bitmap = msm_mpm_enabled_apps_irqs;
@@ -400,15 +401,17 @@
}
if (debug_mask) {
- static char buf[DIV_ROUND_UP(MSM_MPM_NR_APPS_IRQS, 32)*9+1];
+ i = find_first_bit(apps_irq_bitmap, MSM_MPM_NR_APPS_IRQS);
+ while (i < MSM_MPM_NR_APPS_IRQS) {
+ struct irq_desc *desc = i ?
+ irq_to_desc(i) : NULL;
+ pr_info("%s: cannot monitor irq=%d %s\n",
+ __func__, i, desc->name);
+ i = find_next_bit(apps_irq_bitmap,
+ MSM_MPM_NR_APPS_IRQS, i + 1);
+ }
- bitmap_scnprintf(buf, sizeof(buf), apps_irq_bitmap,
- MSM_MPM_NR_APPS_IRQS);
- buf[sizeof(buf) - 1] = '\0';
-
- pr_info("%s: cannot monitor %s", __func__, buf);
}
-
return (bool)__bitmap_empty(apps_irq_bitmap, MSM_MPM_NR_APPS_IRQS);
}
diff --git a/arch/arm/mach-msm/msm-krait-l2-accessors.c b/arch/arm/mach-msm/msm-krait-l2-accessors.c
index 3da155a..2c66ea0 100644
--- a/arch/arm/mach-msm/msm-krait-l2-accessors.c
+++ b/arch/arm/mach-msm/msm-krait-l2-accessors.c
@@ -18,75 +18,12 @@
DEFINE_RAW_SPINLOCK(l2_access_lock);
-#define L2CPMR 0x500
-#define L2CPUCPMR 0x501
-#define L2CPUVRF8 0x708
-#define CPUNDX_MASK (0x7 << 12)
-
-/*
- * For Krait versions found in APQ8064v1.x, save L2CPUVRF8 before
- * L2CPMR or L2CPUCPMR writes and restore it after to work around an
- * issue where L2CPUVRF8 becomes corrupt.
- */
-static bool l2cpuvrf8_needs_fix(u32 reg_addr)
-{
- switch (read_cpuid_id()) {
- case 0x510F06F0: /* KR28M4A10 */
- case 0x510F06F1: /* KR28M4A10B */
- case 0x510F06F2: /* KR28M4A11 */
- break;
- default:
- return false;
- };
-
- switch (reg_addr & ~CPUNDX_MASK) {
- case L2CPMR:
- case L2CPUCPMR:
- return true;
- default:
- return false;
- }
-}
-
-static u32 l2cpuvrf8_fix_save(u32 reg_addr, u32 *l2cpuvrf8_val)
-{
- u32 l2cpuvrf8_addr = L2CPUVRF8 | (reg_addr & CPUNDX_MASK);
-
- mb();
- asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
- "isb\n\t"
- "mrc p15, 3, %[l2cpdr], c15, c0, 7\n\t"
- : [l2cpdr]"=r" (*l2cpuvrf8_val)
- : [l2cpselr]"r" (l2cpuvrf8_addr)
- );
-
- return l2cpuvrf8_addr;
-}
-
-static void l2cpuvrf8_fix_restore(u32 l2cpuvrf8_addr, u32 l2cpuvrf8_val)
-{
- mb();
- asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
- "isb\n\t"
- "mcr p15, 3, %[l2cpdr], c15, c0, 7\n\t"
- "isb\n\t"
- :
- : [l2cpselr]"r" (l2cpuvrf8_addr),
- [l2cpdr]"r" (l2cpuvrf8_val)
- );
-}
-
u32 set_get_l2_indirect_reg(u32 reg_addr, u32 val)
{
unsigned long flags;
- u32 uninitialized_var(l2cpuvrf8_val), l2cpuvrf8_addr = 0;
u32 ret_val;
raw_spin_lock_irqsave(&l2_access_lock, flags);
-
- if (l2cpuvrf8_needs_fix(reg_addr))
- l2cpuvrf8_addr = l2cpuvrf8_fix_save(reg_addr, &l2cpuvrf8_val);
-
mb();
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
"isb\n\t"
@@ -96,10 +33,6 @@
: [l2cpdr_read]"=r" (ret_val)
: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
);
-
- if (l2cpuvrf8_addr)
- l2cpuvrf8_fix_restore(l2cpuvrf8_addr, l2cpuvrf8_val);
-
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
return ret_val;
@@ -109,13 +42,8 @@
void set_l2_indirect_reg(u32 reg_addr, u32 val)
{
unsigned long flags;
- u32 uninitialized_var(l2cpuvrf8_val), l2cpuvrf8_addr = 0;
raw_spin_lock_irqsave(&l2_access_lock, flags);
-
- if (l2cpuvrf8_needs_fix(reg_addr))
- l2cpuvrf8_addr = l2cpuvrf8_fix_save(reg_addr, &l2cpuvrf8_val);
-
mb();
asm volatile ("mcr p15, 3, %[l2cpselr], c15, c0, 6\n\t"
"isb\n\t"
@@ -124,10 +52,6 @@
:
: [l2cpselr]"r" (reg_addr), [l2cpdr]"r" (val)
);
-
- if (l2cpuvrf8_addr)
- l2cpuvrf8_fix_restore(l2cpuvrf8_addr, l2cpuvrf8_val);
-
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
}
EXPORT_SYMBOL(set_l2_indirect_reg);
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 2072cb1..97299a0 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -485,7 +485,7 @@
};
#define M_PRIOLVL_OVERRIDE_ADDR(b, n) \
- (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000220)
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000230)
enum bimc_m_priolvl_override {
M_PRIOLVL_OVERRIDE_RMSK = 0x301,
M_PRIOLVL_OVERRIDE_BMSK = 0x300,
@@ -495,10 +495,10 @@
};
#define M_RD_CMD_OVERRIDE_ADDR(b, n) \
- (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000230)
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000240)
enum bimc_m_read_command_override {
- M_RD_CMD_OVERRIDE_RMSK = 0x37f3f,
- M_RD_CMD_OVERRIDE_AREQPRIO_BMSK = 0x300000,
+ M_RD_CMD_OVERRIDE_RMSK = 0x3071f7f,
+ M_RD_CMD_OVERRIDE_AREQPRIO_BMSK = 0x3000000,
M_RD_CMD_OVERRIDE_AREQPRIO_SHFT = 0x18,
M_RD_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x70000,
M_RD_CMD_OVERRIDE_AMEMTYPE_SHFT = 0x10,
@@ -529,13 +529,15 @@
};
#define M_WR_CMD_OVERRIDE_ADDR(b, n) \
- (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000240)
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000250)
enum bimc_m_write_command_override {
- M_WR_CMD_OVERRIDE_RMSK = 0x37f3f,
- M_WR_CMD_OVERRIDE_AREQPRIO_BMSK = 0x30000,
- M_WR_CMD_OVERRIDE_AREQPRIO_SHFT = 0x10,
- M_WR_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x7000,
- M_WR_CMD_OVERRIDE_AMEMTYPE_SHFT = 0xc,
+ M_WR_CMD_OVERRIDE_RMSK = 0x3071f7f,
+ M_WR_CMD_OVERRIDE_AREQPRIO_BMSK = 0x3000000,
+ M_WR_CMD_OVERRIDE_AREQPRIO_SHFT = 0x18,
+ M_WR_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x70000,
+ M_WR_CMD_OVERRIDE_AMEMTYPE_SHFT = 0x10,
+ M_WR_CMD_OVERRIDE_ATRANSIENT_BMSK = 0x1000,
+ M_WR_CMD_OVERRIDE_ATRANSIENT_SHFT = 0xc,
M_WR_CMD_OVERRIDE_ASHARED_BMSK = 0x800,
M_WR_CMD_OVERRIDE_ASHARED_SHFT = 0xb,
M_WR_CMD_OVERRIDE_AREDIRECT_BMSK = 0x400,
@@ -544,8 +546,10 @@
M_WR_CMD_OVERRIDE_AOOO_SHFT = 0x9,
M_WR_CMD_OVERRIDE_AINNERSHARED_BMSK = 0x100,
M_WR_CMD_OVERRIDE_AINNERSHARED_SHFT = 0x8,
- M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK = 0x20,
- M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT = 0x5,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK = 0x40,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT = 0x6,
+ M_WR_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_BMSK = 0x20,
+ M_WR_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_SHFT = 0x5,
M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_BMSK = 0x10,
M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_SHFT = 0x4,
M_WR_CMD_OVERRIDE_OVERRIDE_ASHARED_BMSK = 0x8,
@@ -1454,7 +1458,7 @@
* boundary in future
*/
wmb();
- set_qos_mode(binfo->base, mas_index, 1, 1, 1);
+ set_qos_mode(binfo->base, mas_index, 0, 1, 1);
break;
case BIMC_QOS_MODE_BYPASS:
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
index 1b8c07e..cfd84eb 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
@@ -641,6 +641,7 @@
.mode = NOC_QOS_MODE_FIXED,
.qport = qports_crypto_c0,
.mas_hw_id = MAS_CRYPTO_CORE0,
+ .hw_sel = MSM_BUS_NOC,
},
{
.id = MSM_BUS_MASTER_CRYPTO_CORE1,
@@ -651,6 +652,7 @@
.mode = NOC_QOS_MODE_FIXED,
.qport = qports_crypto_c1,
.mas_hw_id = MAS_CRYPTO_CORE1,
+ .hw_sel = MSM_BUS_NOC,
},
{
.id = MSM_BUS_MASTER_LPASS_PROC,
@@ -719,6 +721,7 @@
.mas_hw_id = MAS_USB3,
.prio_rd = 2,
.prio_wr = 2,
+ .hw_sel = MSM_BUS_NOC,
},
{
.id = MSM_BUS_SLAVE_AMPSS,
@@ -1046,9 +1049,8 @@
.qport = qports_kmpss,
.ws = 10000,
.mas_hw_id = MAS_APPSS_PROC,
- .prio_lvl = 0,
- .prio_rd = 2,
- .prio_wr = 2,
+ .prio_rd = 1,
+ .prio_wr = 1,
},
{
.id = MSM_BUS_MASTER_AMPSS_M1,
@@ -1061,6 +1063,8 @@
.qport = qports_kmpss,
.ws = 10000,
.mas_hw_id = MAS_APPSS_PROC,
+ .prio_rd = 1,
+ .prio_wr = 1,
},
{
.id = MSM_BUS_MASTER_MSS_PROC,
diff --git a/arch/arm/mach-msm/msm_cpr.c b/arch/arm/mach-msm/msm_cpr.c
index 12f7d96..c00352d 100644
--- a/arch/arm/mach-msm/msm_cpr.c
+++ b/arch/arm/mach-msm/msm_cpr.c
@@ -1,5 +1,4 @@
-/*
- * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -54,6 +53,26 @@
module_param(enable, bool, 0644);
MODULE_PARM_DESC(enable, "CPR Enable");
+static int msm_cpr_debug_mask;
+module_param_named(
+ debug_mask, msm_cpr_debug_mask, int, S_IRUGO | S_IWUSR
+);
+
+enum {
+ /* configuration log */
+ MSM_CPR_DEBUG_CONFIG = BIT(0),
+ /* step up/down interrupt log */
+ MSM_CPR_DEBUG_STEPS = BIT(1),
+ /* cpu frequency notification log */
+ MSM_CPR_DEBUG_FREQ_TRANS = BIT(2),
+};\
+
+#define msm_cpr_debug(mask, message, ...) \
+ do { \
+ if ((mask) & msm_cpr_debug_mask) \
+ pr_info(message, ##__VA_ARGS__); \
+ } while (0)
+
struct msm_cpr {
int curr_osc;
int cpr_mode;
@@ -65,7 +84,9 @@
unsigned int irq;
uint32_t cur_Vmin;
uint32_t cur_Vmax;
+ uint32_t prev_volt_uV;
struct mutex cpr_mutex;
+ spinlock_t cpr_lock;
struct regulator *vreg_cx;
const struct msm_cpr_config *config;
struct notifier_block freq_transition;
@@ -133,17 +154,17 @@
/* Enable the CPR H/W Block */
static void cpr_enable(struct msm_cpr *cpr)
{
- mutex_lock(&cpr->cpr_mutex);
+ spin_lock(&cpr->cpr_lock);
cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, ENABLE_CPR);
- mutex_unlock(&cpr->cpr_mutex);
+ spin_unlock(&cpr->cpr_lock);
}
/* Disable the CPR H/W Block */
static void cpr_disable(struct msm_cpr *cpr)
{
- mutex_lock(&cpr->cpr_mutex);
+ spin_lock(&cpr->cpr_lock);
cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
- mutex_unlock(&cpr->cpr_mutex);
+ spin_unlock(&cpr->cpr_lock);
}
static int32_t cpr_poll_result(struct msm_cpr *cpr)
@@ -154,8 +175,7 @@
rc = readl_poll_timeout(cpr->base + RBCPR_RESULT_0, val, ~val & BUSY_M,
10, 1000);
if (rc)
- pr_info("%s: RBCPR_RESULT_0 read error: %d\n",
- __func__, rc);
+ pr_err("RBCPR_RESULT_0 read error: %d\n", rc);
return rc;
}
@@ -167,8 +187,7 @@
rc = readl_poll_timeout(cpr->base + RBIF_IRQ_STATUS, val, val & 0x1,
10, 1000);
if (rc)
- pr_info("%s: RBCPR_IRQ_STATUS read error: %d\n",
- __func__, rc);
+ pr_err("RBCPR_IRQ_STATUS read error: %d\n", rc);
return rc;
}
@@ -200,15 +219,16 @@
*/
level_uV = chip_data->turbo_Vmax -
(chip_data->tgt_volt_offset * cpr->vp->step_size);
- pr_debug("tgt_volt_uV = %d\n", level_uV);
+ msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+ "tgt_volt_uV = %d\n", level_uV);
/* Call the PMIC specific routine to set the voltage */
rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
if (rc) {
- pr_err("%s: Initial voltage set at %duV failed. %d\n",
- __func__, level_uV, rc);
+ pr_err("Initial voltage set at %duV failed\n", level_uV);
return;
}
+
rc = regulator_enable(cpr->vreg_cx);
if (rc) {
pr_err("failed to enable %s, rc=%d\n", "vdd_cx", rc);
@@ -226,15 +246,13 @@
/* IRQ is already disabled */
rc = cpr_poll_result_done(cpr);
if (rc) {
- pr_err("%s: Quot1: Exiting due to INT_DONE poll timeout\n",
- __func__);
+ pr_err("Quot1: Exiting due to INT_DONE poll timeout\n");
return;
}
rc = cpr_poll_result(cpr);
if (rc) {
- pr_err("%s: Quot1: Exiting due to BUSY poll timeout\n",
- __func__);
+ pr_err("Quot1: Exiting due to BUSY poll timeout\n");
return;
}
@@ -242,14 +260,14 @@
/* Take second CPR measurement at a lower voltage to get QUOT2 */
level_uV -= 4 * cpr->vp->step_size;
- pr_debug("tgt_volt_uV = %d\n", level_uV);
+ msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+ "tgt_volt_uV = %d\n", level_uV);
cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
/* Call the PMIC specific routine to set the voltage */
rc = regulator_set_voltage(cpr->vreg_cx, level_uV, level_uV);
if (rc) {
- pr_err("%s: Voltage set at %duV failed. %d\n",
- __func__, level_uV, rc);
+ pr_err("Voltage set at %duV failed\n", level_uV);
return;
}
@@ -259,15 +277,13 @@
/* cpr_write_reg(cpr, RBIF_CONT_NACK_CMD, 0x1); */
rc = cpr_poll_result_done(cpr);
if (rc) {
- pr_err("%s: Quot2: Exiting due to INT_DONE poll timeout\n",
- __func__);
+ pr_err("Quot2: Exiting due to INT_DONE poll timeout\n");
goto err_poll_result_done;
}
/* IRQ is already disabled */
rc = cpr_poll_result(cpr);
if (rc) {
- pr_err("%s: Quot2: Exiting due to BUSY poll timeout\n",
- __func__);
+ pr_err("Quot2: Exiting due to BUSY poll timeout\n");
goto err_poll_result;
}
quot2 = (cpr_read_reg(cpr, RBCPR_DEBUG1) & QUOT_SLOW_M) >> 12;
@@ -283,8 +299,8 @@
chip_data->step_quot > STEP_QUOT_MAX)
chip_data->step_quot = STEP_QUOT_MAX;
- pr_info("%s: Step Quot is %d\n",
- __func__, chip_data->step_quot);
+ msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+ "Step Quot is %d\n", chip_data->step_quot);
/* Disable the cpr */
cpr_modify_reg(cpr, RBCPR_CTL, LOOP_EN_M, DISABLE_CPR);
@@ -329,27 +345,31 @@
static void
cpr_up_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
{
- int rc, set_volt_uV;
+ int set_volt_uV, rc;
struct msm_cpr_mode *chip_data;
chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
- /**
- * FIXME: Need to handle a potential race condition between
- * freq switch handler and CPR interrupt handler here
- */
/* Set New PMIC voltage */
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "current Vmin=%d Vmax=%d\n", cpr->cur_Vmin, cpr->cur_Vmax);
set_volt_uV = (new_volt < cpr->cur_Vmax ? new_volt
: cpr->cur_Vmax);
- rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
- set_volt_uV);
+
+ if (cpr->prev_volt_uV == set_volt_uV)
+ rc = regulator_sync_voltage(cpr->vreg_cx);
+ else
+ rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
+ set_volt_uV);
if (rc) {
- pr_err("%s: Voltage set at %duV failed. %d\n",
- __func__, set_volt_uV, rc);
+ pr_err("Unable to set_voltage = %d, rc(%d)\n", set_volt_uV, rc);
cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
return;
}
- pr_info("(railway_voltage: %d uV)\n", set_volt_uV);
+
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "(railway_voltage: %d uV)\n", set_volt_uV);
+ cpr->prev_volt_uV = set_volt_uV;
cpr->max_volt_set = (set_volt_uV == cpr->cur_Vmax) ? 1 : 0;
@@ -371,27 +391,29 @@
static void
cpr_dn_event_handler(struct msm_cpr *cpr, uint32_t new_volt)
{
- int rc, set_volt_uV;
+ int set_volt_uV, rc;
struct msm_cpr_mode *chip_data;
chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
- /**
- * FIXME: Need to handle a potential race condition between
- * freq switch handler and CPR interrupt handler here
- */
/* Set New PMIC volt */
set_volt_uV = (new_volt > cpr->cur_Vmin ? new_volt
: cpr->cur_Vmin);
- rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
- set_volt_uV);
+
+ if (cpr->prev_volt_uV == set_volt_uV)
+ rc = regulator_sync_voltage(cpr->vreg_cx);
+ else
+ rc = regulator_set_voltage(cpr->vreg_cx, set_volt_uV,
+ set_volt_uV);
if (rc) {
- pr_err("%s: Voltage at %duV failed %d\n",
- __func__, set_volt_uV, rc);
+ pr_err("Unable to set_voltage = %d, rc(%d)\n", set_volt_uV, rc);
cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
return;
}
- pr_info("(railway_voltage: %d uV)\n", set_volt_uV);
+
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "(railway_voltage: %d uV)\n", set_volt_uV);
+ cpr->prev_volt_uV = set_volt_uV;
cpr->max_volt_set = 0;
@@ -415,7 +437,8 @@
SW_AUTO_CONT_NACK_DN_EN_M,
SW_AUTO_CONT_NACK_DN_EN);
cpr_irq_set(cpr, DOWN_INT, 0);
- pr_debug("%s: DOWN_INT disabled\n", __func__);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "DOWN_INT disabled\n");
}
}
/* Acknowledge the Recommendation */
@@ -429,9 +452,18 @@
chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
error_step = cpr_read_reg(cpr, RBCPR_RESULT_0) >> 2;
- error_step &= 0xF;
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "RBCPR_RESULT_0 17:6=%d\n", (cpr_read_reg(cpr,
+ RBCPR_RESULT_0) >> 6) & 0xFFF);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "RBCPR_RESULT_0 Busy_b19=%d\n", (cpr_read_reg(cpr,
+ RBCPR_RESULT_0) >> 19) & 0x1);
+
+ error_step &= 0xF;
curr_volt = regulator_get_voltage(cpr->vreg_cx);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "Current voltage=%d\n", curr_volt);
if (action == UP) {
/* Clear IRQ, ACK and return if Vdd already at Vmax */
@@ -447,15 +479,29 @@
*/
if (error_step < (cpr->config->up_threshold +
cpr->config->up_margin)) {
- pr_debug("UP_INT error step too small to set\n");
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "UP_INT error step too small to set\n");
cpr_irq_clr_and_nack(cpr, BIT(4) | BIT(0));
return;
}
+ /**
+ * As per chip characterization recommendation, add a step
+ * to up error steps to increase system stability
+ */
+ error_step += 1;
+
/* Calculte new PMIC voltage */
new_volt = curr_volt + (error_step * cpr->vp->step_size);
- pr_debug("UP_INT: new_volt: %d\n", new_volt);
- pr_info("(UP Voltage recommended by CPR: %d uV)\n", new_volt);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "UP_INT: new_volt: %d, error_step=%d\n",
+ new_volt, error_step);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "Current RBCPR_GCNT_TARGET(%d): = 0x%x\n",
+ cpr->curr_osc, readl_relaxed(cpr->base +
+ RBCPR_GCNT_TARGET(cpr->curr_osc)) & TARGET_M);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "(UP Voltage recommended by CPR: %d uV)\n", new_volt);
cpr_up_event_handler(cpr, new_volt);
} else if (action == DOWN) {
@@ -465,15 +511,35 @@
*/
if (error_step < (cpr->config->dn_threshold +
cpr->config->dn_margin)) {
- pr_debug("DOWN_INT error_step too small to set\n");
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "DOWN_INT error_step=%d is too small to set\n",
+ error_step);
cpr_irq_clr_and_nack(cpr, BIT(2) | BIT(0));
return;
}
+ /**
+ * As per chip characterization recommendation, deduct 2 steps
+ * from down error steps to decrease chances of getting closer
+ * to the system level Vmin, thereby improving stability
+ */
+ error_step -= 2;
+
+ /* Keep down step upto two per interrupt to avoid any spike */
+ if (error_step > 2)
+ error_step = 2;
+
/* Calculte new PMIC voltage */
new_volt = curr_volt - (error_step * cpr->vp->step_size);
- pr_debug("DOWN_INT: new_volt: %d\n", new_volt);
- pr_info("(DN Voltage recommended by CPR: %d uV)\n", new_volt);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "DOWN_INT: new_volt: %d, error_step=%d\n",
+ new_volt, error_step);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "Current RBCPR_GCNT_TARGET(%d): = 0x%x\n",
+ cpr->curr_osc, readl_relaxed(cpr->base +
+ RBCPR_GCNT_TARGET(cpr->curr_osc)) & TARGET_M);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "(DN Voltage recommended by CPR: %d uV)\n", new_volt);
cpr_dn_event_handler(cpr, new_volt);
}
}
@@ -488,31 +554,36 @@
/* Following sequence of handling is as per each IRQ's priority */
if (reg_val & BIT(4)) {
- pr_debug(" CPR:IRQ %d occured for UP Flag\n", irq);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "CPR:IRQ %d occured for UP Flag\n", irq);
cpr_set_vdd(cpr, UP);
} else if ((reg_val & BIT(2)) && !(ctl_reg & SW_AUTO_CONT_NACK_DN_EN)) {
- pr_debug(" CPR:IRQ %d occured for Down Flag\n", irq);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "CPR:IRQ %d occured for Down Flag\n", irq);
cpr_set_vdd(cpr, DOWN);
} else if (reg_val & BIT(1)) {
- pr_debug(" CPR:IRQ %d occured for Min Flag\n", irq);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "CPR:IRQ %d occured for Min Flag\n", irq);
cpr_irq_clr_and_nack(cpr, BIT(1) | BIT(0));
} else if (reg_val & BIT(5)) {
- pr_debug(" CPR:IRQ %d occured for MAX Flag\n", irq);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "CPR:IRQ %d occured for MAX Flag\n", irq);
cpr_irq_clr_and_nack(cpr, BIT(5) | BIT(0));
} else if (reg_val & BIT(3)) {
/* SW_AUTO_CONT_ACK_EN is enabled */
- pr_debug(" CPR:IRQ %d occured for Mid Flag\n", irq);
+ msm_cpr_debug(MSM_CPR_DEBUG_STEPS,
+ "CPR:IRQ %d occured for Mid Flag\n", irq);
}
return IRQ_HANDLED;
}
static void cpr_config(struct msm_cpr *cpr)
{
- uint32_t delay_count, cnt = 0, rc, tmp_uV;
+ uint32_t delay_count, cnt = 0, rc;
struct msm_cpr_mode *chip_data;
chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
@@ -543,11 +614,16 @@
* for all the ring oscilators
*/
while (cnt < NUM_OSC) {
+ msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+ "Prog:cnt(%d) gcnt=0x%x quot=0x%x\n", cnt,
+ chip_data->ring_osc_data[cnt].gcnt,
+ chip_data->ring_osc_data[cnt].quot);
cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cnt),
(GCNT_M | TARGET_M),
(chip_data->ring_osc_data[cnt].gcnt << 12 |
chip_data->ring_osc_data[cnt].quot));
- pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cnt,
+ msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+ "RBCPR_GCNT_TARGET(%d): = 0x%x\n", cnt,
readl_relaxed(cpr->base + RBCPR_GCNT_TARGET(cnt)));
cnt++;
}
@@ -555,16 +631,11 @@
/* Configure the step quot */
cpr_2pt_kv_analysis(cpr, chip_data);
- /**
- * Call the PMIC specific routine to set the voltage
- * Set with an extra step since it helps as per
- * characterization data.
- */
- chip_data->calibrated_uV += cpr->vp->step_size;
- tmp_uV = chip_data->calibrated_uV;
- rc = regulator_set_voltage(cpr->vreg_cx, tmp_uV, tmp_uV);
+ /* Call the PMIC specific routine to set the voltage */
+ rc = regulator_set_voltage(cpr->vreg_cx, chip_data->calibrated_uV,
+ chip_data->calibrated_uV);
if (rc)
- pr_err("%s: Voltage set failed %d\n", __func__, rc);
+ pr_err("Voltage set failed %d\n", rc);
/*
* Program the Timer Register for delay between CPR measurements
@@ -575,6 +646,11 @@
cpr->config->delay_us);
cpr_write_reg(cpr, RBCPR_TIMER_INTERVAL, delay_count);
+ /* Use Consecutive Down to avoid any interrupt due to spike */
+ cpr_write_reg(cpr, RBIF_TIMER_ADJUST, (0x2 << RBIF_CONS_DN_SHIFT));
+ msm_cpr_debug(MSM_CPR_DEBUG_CONFIG, "RBIF_TIMER_ADJUST: 0x%x\n",
+ readl_relaxed(cpr->base + RBIF_TIMER_ADJUST));
+
/* Enable the Timer */
cpr_modify_reg(cpr, RBCPR_CTL, TIMER_M, ENABLE_TIMER);
@@ -593,19 +669,23 @@
switch (val) {
case CPUFREQ_PRECHANGE:
- pr_debug("pre freq change notification to cpr\n");
-
+ msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+ "pre freq change notification to cpr\n");
/* Disable Measurement to stop generation of CPR IRQs */
cpr_disable(cpr);
/* Disable routing of IRQ to App */
cpr_irq_set(cpr, INT_MASK & ~MID_INT, 0);
disable_irq(cpr->irq);
cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
- pr_debug("RBCPR_CTL: 0x%x\n",
+
+ msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+ "RBCPR_CTL: 0x%x\n",
readl_relaxed(cpr->base + RBCPR_CTL));
- pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+ msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+ "RBIF_IRQ_STATUS: 0x%x\n",
cpr_read_reg(cpr, RBIF_IRQ_STATUS));
- pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+ msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+ "RBIF_IRQ_EN(0): 0x%x\n",
cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
cpr->prev_mode = cpr->cpr_mode;
@@ -634,12 +714,15 @@
new_freq / 1000);
cpr_modify_reg(cpr, RBCPR_GCNT_TARGET(cpr->curr_osc), TARGET_M,
quot);
- pr_debug("RBCPR_GCNT_TARGET(%d): = 0x%x\n", cpr->curr_osc,
+ msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+ "RBCPR_GCNT_TARGET(%d): = 0x%x\n", cpr->curr_osc,
readl_relaxed(cpr->base +
RBCPR_GCNT_TARGET(cpr->curr_osc)));
- pr_debug("%s: new_freq: %d, set_freq: %d, quot: %d\n", __func__,
+ msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+ "new_freq: %d, quot_freq: %d, quot: %d\n",
freqs->new, new_freq, quot);
- pr_info("%s: PVS Voltage setting is: %d\n", __func__,
+ msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+ "PVS Voltage setting is: %d\n",
regulator_get_voltage(cpr->vreg_cx));
enable_irq(cpr->irq);
@@ -656,18 +739,28 @@
if (ctl_reg & SW_AUTO_CONT_NACK_DN_EN)
cpr_modify_reg(cpr, RBCPR_CTL,
SW_AUTO_CONT_NACK_DN_EN_M, 0);
- pr_debug("RBIF_IRQ_EN(0): 0x%x\n",
+ if (cpr->max_volt_set)
+ cpr->max_volt_set = 0;
+
+ msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+ "RBIF_IRQ_EN(0): 0x%x\n",
cpr_read_reg(cpr, RBIF_IRQ_EN(cpr->config->irq_line)));
- pr_debug("RBCPR_CTL: 0x%x\n",
+ msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+ "RBCPR_CTL: 0x%x\n",
readl_relaxed(cpr->base + RBCPR_CTL));
- pr_debug("RBIF_IRQ_STATUS: 0x%x\n",
+ msm_cpr_debug(MSM_CPR_DEBUG_FREQ_TRANS,
+ "RBIF_IRQ_STATUS: 0x%x\n",
cpr_read_reg(cpr, RBIF_IRQ_STATUS));
+
+ /* Clear all the interrupts */
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+
cpr_enable(cpr);
break;
default:
break;
}
- return 0;
+ return NOTIFY_OK;
}
#ifdef CONFIG_PM
@@ -695,6 +788,9 @@
cpr_write_reg(cpr, RBCPR_CTL,
cpr_save_state.rbcpr_ctl);
+ /* Clear all the interrupts */
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+
enable_irq(cpr->irq);
cpr_enable(cpr);
@@ -711,6 +807,9 @@
cpr_disable(cpr);
disable_irq(cpr->irq);
+ /* Clear all the interrupts */
+ cpr_write_reg(cpr, RBIF_IRQ_CLEAR, ALL_CPR_IRQ);
+
cpr_save_state.rbif_timer_interval =
cpr_read_reg(cpr, RBCPR_TIMER_INTERVAL);
cpr_save_state.rbif_int_en =
@@ -733,12 +832,18 @@
void msm_cpr_pm_resume(void)
{
+ if (!enable)
+ return;
+
msm_cpr_resume(&cpr_pdev->dev);
}
EXPORT_SYMBOL(msm_cpr_pm_resume);
void msm_cpr_pm_suspend(void)
{
+ if (!enable)
+ return;
+
msm_cpr_suspend(&cpr_pdev->dev);
}
EXPORT_SYMBOL(msm_cpr_pm_suspend);
@@ -746,14 +851,26 @@
void msm_cpr_disable(void)
{
- struct msm_cpr *cpr = platform_get_drvdata(cpr_pdev);
+ struct msm_cpr *cpr;
+
+ if (!enable)
+ return;
+
+ cpr = platform_get_drvdata(cpr_pdev);
+
cpr_disable(cpr);
}
EXPORT_SYMBOL(msm_cpr_disable);
void msm_cpr_enable(void)
{
- struct msm_cpr *cpr = platform_get_drvdata(cpr_pdev);
+ struct msm_cpr *cpr;
+
+ if (!enable)
+ return;
+
+ cpr = platform_get_drvdata(cpr_pdev);
+
cpr_enable(cpr);
}
EXPORT_SYMBOL(msm_cpr_enable);
@@ -772,12 +889,15 @@
if (!pdata) {
pr_err("CPR: Platform data is not available\n");
+ enable = false;
return -EIO;
}
cpr = devm_kzalloc(&pdev->dev, sizeof(struct msm_cpr), GFP_KERNEL);
- if (!cpr)
+ if (!cpr) {
+ enable = false;
return -ENOMEM;
+ }
/* Initialize platform_data */
cpr->config = pdata;
@@ -820,7 +940,7 @@
cpr->vp = pdata->vp_data;
- mutex_init(&cpr->cpr_mutex);
+ spin_lock_init(&cpr->cpr_lock);
/* Initialize the Voltage domain for CPR */
cpr->vreg_cx = regulator_get(&pdev->dev, "vddx_cx");
@@ -840,12 +960,15 @@
platform_set_drvdata(pdev, cpr);
chip_data = &cpr->config->cpr_mode_data[cpr->cpr_mode];
- pr_info("CPR Platform Data (upside_steps: %d) (downside_steps: %d) ",
+ msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+ "CPR Platform Data (upside_steps: %d) (downside_steps: %d))",
cpr->config->up_threshold, cpr->config->dn_threshold);
- pr_info("(nominal_voltage: %duV) (turbo_voltage: %duV)\n",
+ msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+ "(nominal_voltage: %duV) (turbo_voltage: %duV)\n",
cpr->config->cpr_mode_data[NORMAL_MODE].calibrated_uV,
cpr->config->cpr_mode_data[TURBO_MODE].calibrated_uV);
- pr_info("(Current corner: TURBO) (gcnt_target: %d) (quot: %d)\n",
+ msm_cpr_debug(MSM_CPR_DEBUG_CONFIG,
+ "(Current corner: TURBO) (gcnt_target: %d) (quot: %d)\n",
chip_data->ring_osc_data[chip_data->ring_osc].gcnt,
chip_data->ring_osc_data[chip_data->ring_osc].quot);
@@ -880,6 +1003,8 @@
cpufreq_register_notifier(&cpr->freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
+ pr_info("MSM CPR driver successfully registered!\n");
+
return res;
err_reg_get:
@@ -887,6 +1012,7 @@
err_ioremap:
iounmap(base);
out:
+ enable = false;
return res;
}
@@ -901,7 +1027,6 @@
regulator_put(cpr->vreg_cx);
free_irq(cpr->irq, cpr);
iounmap(cpr->base);
- mutex_destroy(&cpr->cpr_mutex);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/arch/arm/mach-msm/msm_cpr.h b/arch/arm/mach-msm/msm_cpr.h
index e690c63..005d9b1 100644
--- a/arch/arm/mach-msm/msm_cpr.h
+++ b/arch/arm/mach-msm/msm_cpr.h
@@ -72,6 +72,9 @@
#define SW_AUTO_CONT_ACK_EN BIT(5)
#define SW_AUTO_CONT_NACK_DN_EN BIT(6)
+/* Shift Values */
+#define RBIF_CONS_DN_SHIFT (0x4)
+
/* Test values for RBCPR RUMI Testing */
#define GNT_CNT 0xC0
#define TARGET 0xEFF
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 0c158de..310197e 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/kobject.h>
#include <linux/ktime.h>
@@ -23,167 +22,285 @@
#include <linux/spinlock.h>
#include <linux/stringify.h>
#include <linux/debugfs.h>
+#include <linux/msm_tsens.h>
#include <asm/atomic.h>
#include <asm/page.h>
#include <mach/msm_dcvs.h>
+#include <trace/events/mpdcvs_trace.h>
#define CORE_HANDLE_OFFSET (0xA0)
#define __err(f, ...) pr_err("MSM_DCVS: %s: " f, __func__, __VA_ARGS__)
#define __info(f, ...) pr_info("MSM_DCVS: %s: " f, __func__, __VA_ARGS__)
#define MAX_PENDING (5)
-enum {
- MSM_DCVS_DEBUG_NOTIFIER = BIT(0),
- MSM_DCVS_DEBUG_IDLE_PULSE = BIT(1),
- MSM_DCVS_DEBUG_FREQ_CHANGE = BIT(2),
-};
-
struct core_attribs {
- struct kobj_attribute idle_enabled;
- struct kobj_attribute freq_change_enabled;
- struct kobj_attribute actual_freq;
struct kobj_attribute freq_change_us;
- struct kobj_attribute max_time_us;
-
- struct kobj_attribute slack_time_us;
- struct kobj_attribute scale_slack_time;
- struct kobj_attribute scale_slack_time_pct;
struct kobj_attribute disable_pc_threshold;
- struct kobj_attribute em_window_size;
+ struct kobj_attribute em_win_size_min_us;
+ struct kobj_attribute em_win_size_max_us;
struct kobj_attribute em_max_util_pct;
- struct kobj_attribute ss_window_size;
- struct kobj_attribute ss_util_pct;
+ struct kobj_attribute group_id;
+ struct kobj_attribute max_freq_chg_time_us;
+ struct kobj_attribute slack_mode_dynamic;
+ struct kobj_attribute slack_time_min_us;
+ struct kobj_attribute slack_time_max_us;
+ struct kobj_attribute slack_weight_thresh_pct;
struct kobj_attribute ss_iobusy_conv;
+ struct kobj_attribute ss_win_size_min_us;
+ struct kobj_attribute ss_win_size_max_us;
+ struct kobj_attribute ss_util_pct;
+
+ struct kobj_attribute active_coeff_a;
+ struct kobj_attribute active_coeff_b;
+ struct kobj_attribute active_coeff_c;
+ struct kobj_attribute leakage_coeff_a;
+ struct kobj_attribute leakage_coeff_b;
+ struct kobj_attribute leakage_coeff_c;
+ struct kobj_attribute leakage_coeff_d;
+
+ struct kobj_attribute thermal_poll_ms;
struct attribute_group attrib_group;
};
+enum pending_freq_state {
+ /*
+ * used by the thread to check if pending_freq was updated while it was
+ * setting previous frequency - this is written to and used by the
+ * freq updating thread
+ */
+ NO_OUTSTANDING_FREQ_CHANGE = 0,
+
+ /*
+ * This request is set to indicate that the governor is stopped and no
+ * more frequency change requests are accepted untill it starts again.
+ * This is checked/used by the threads that want to change the freq
+ */
+ STOP_FREQ_CHANGE = -1,
+
+ /*
+ * Any other +ve value means that a freq change was requested and the
+ * thread has not gotten around to update it
+ *
+ * Any other -ve value means that this is the last freq change i.e. a
+ * freq change was requested but the thread has not run yet and
+ * meanwhile the governor was stopped.
+ */
+};
+
struct dcvs_core {
+ spinlock_t idle_state_change_lock;
+ /* 0 when not idle (busy) 1 when idle and -1 when governor starts and
+ * we dont know whether the next call is going to be idle enter or exit
+ */
+ int idle_entered;
+
+ enum msm_dcvs_core_type type;
+ /* this is the number in each type for example cpu 0,1,2 and gpu 0,1 */
+ int type_core_num;
char core_name[CORE_NAME_MAX];
- uint32_t new_freq[MAX_PENDING];
uint32_t actual_freq;
uint32_t freq_change_us;
uint32_t max_time_us; /* core param */
struct msm_dcvs_algo_param algo_param;
- struct msm_dcvs_idle *idle_driver;
- struct msm_dcvs_freq *freq_driver;
+ struct msm_dcvs_energy_curve_coeffs coeffs;
/* private */
- int64_t time_start;
- struct mutex lock;
- spinlock_t cpu_lock;
+ ktime_t time_start;
struct task_struct *task;
struct core_attribs attrib;
- uint32_t handle;
- uint32_t group_id;
- uint32_t freq_pending;
- struct hrtimer timer;
- int32_t timer_disabled;
- /* track if kthread for change_freq is active */
- int32_t change_freq_activated;
+ uint32_t dcvs_core_id;
+ struct msm_dcvs_core_info *info;
+ int sensor;
+ wait_queue_head_t wait_q;
+
+ int (*set_frequency)(int type_core_num, unsigned int freq);
+ unsigned int (*get_frequency)(int type_core_num);
+ int (*idle_enable)(int type_core_num,
+ enum msm_core_control_event event);
+
+ spinlock_t pending_freq_lock;
+ int pending_freq;
+
+ struct hrtimer slack_timer;
+ struct delayed_work temperature_work;
};
-static int msm_dcvs_debug;
static int msm_dcvs_enabled = 1;
module_param_named(enable, msm_dcvs_enabled, int, S_IRUGO | S_IWUSR | S_IWGRP);
-static struct dentry *debugfs_base;
+static struct dentry *debugfs_base;
static struct dcvs_core core_list[CORES_MAX];
-static DEFINE_MUTEX(core_list_lock);
static struct kobject *cores_kobj;
-static struct dcvs_core *core_handles[CORES_MAX];
-/* Change core frequency, called with core mutex locked */
+static void force_stop_slack_timer(struct dcvs_core *core)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags);
+ hrtimer_cancel(&core->slack_timer);
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags);
+}
+
+static void force_start_slack_timer(struct dcvs_core *core, int slack_us)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags);
+
+ /*
+ * only start the timer if governor is not stopped
+ */
+ if (slack_us != 0) {
+ ret = hrtimer_start(&core->slack_timer,
+ ktime_set(0, slack_us * 1000),
+ HRTIMER_MODE_REL_PINNED);
+ if (ret) {
+ pr_err("%s Failed to start timer ret = %d\n",
+ core->core_name, ret);
+ }
+ }
+
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags);
+}
+
+static void stop_slack_timer(struct dcvs_core *core)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags);
+ /* err only for cpu type's GPU's can do idle exit consecutively */
+ if (core->idle_entered == 1 && !(core->dcvs_core_id >= GPU_OFFSET))
+ __err("%s trying to reenter idle", core->core_name);
+ core->idle_entered = 1;
+ hrtimer_cancel(&core->slack_timer);
+ core->idle_entered = 1;
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags);
+}
+
+static void start_slack_timer(struct dcvs_core *core, int slack_us)
+{
+ unsigned long flags1, flags2;
+ int ret;
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags2);
+
+ spin_lock_irqsave(&core->pending_freq_lock, flags1);
+
+ /* err only for cpu type's GPU's can do idle enter consecutively */
+ if (core->idle_entered == 0 && !(core->dcvs_core_id >= GPU_OFFSET))
+ __err("%s trying to reexit idle", core->core_name);
+ core->idle_entered = 0;
+ /*
+ * only start the timer if governor is not stopped
+ */
+ if (slack_us != 0
+ && !(core->pending_freq < NO_OUTSTANDING_FREQ_CHANGE)) {
+ ret = hrtimer_start(&core->slack_timer,
+ ktime_set(0, slack_us * 1000),
+ HRTIMER_MODE_REL_PINNED);
+ if (ret) {
+ pr_err("%s Failed to start timer ret = %d\n",
+ core->core_name, ret);
+ }
+ }
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags1);
+
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags2);
+}
+
+static void restart_slack_timer(struct dcvs_core *core, int slack_us)
+{
+ unsigned long flags1, flags2;
+ int ret;
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags2);
+
+ hrtimer_cancel(&core->slack_timer);
+
+ spin_lock_irqsave(&core->pending_freq_lock, flags1);
+
+ /*
+ * only start the timer if idle is not entered
+ * and governor is not stopped
+ */
+ if (slack_us != 0 && (core->idle_entered != 1)
+ && !(core->pending_freq < NO_OUTSTANDING_FREQ_CHANGE)) {
+ ret = hrtimer_start(&core->slack_timer,
+ ktime_set(0, slack_us * 1000),
+ HRTIMER_MODE_REL_PINNED);
+ if (ret) {
+ pr_err("%s Failed to start timer ret = %d\n",
+ core->core_name, ret);
+ }
+ }
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags1);
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags2);
+}
+
static int __msm_dcvs_change_freq(struct dcvs_core *core)
{
int ret = 0;
unsigned long flags = 0;
- unsigned int requested_freq = 0;
- unsigned int prev_freq = 0;
- int64_t time_start = 0;
- int64_t time_end = 0;
+ int requested_freq = 0;
+ ktime_t time_start;
uint32_t slack_us = 0;
uint32_t ret1 = 0;
- if (!core->freq_driver || !core->freq_driver->set_frequency) {
- /* Core may have unregistered or hotplugged */
- return -ENODEV;
- }
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
repeat:
- spin_lock_irqsave(&core->cpu_lock, flags);
- if (unlikely(!core->freq_pending)) {
- spin_unlock_irqrestore(&core->cpu_lock, flags);
- return ret;
- }
- requested_freq = core->new_freq[core->freq_pending - 1];
- if (unlikely(core->freq_pending > 1) &&
- (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)) {
- int i;
- for (i = 0; i < core->freq_pending - 1; i++) {
- __info("Core %s missing freq %u\n",
- core->core_name, core->new_freq[i]);
- }
- }
+ BUG_ON(!core->pending_freq);
+ if (core->pending_freq == STOP_FREQ_CHANGE)
+ BUG();
+
+ requested_freq = core->pending_freq;
time_start = core->time_start;
- core->time_start = 0;
- core->freq_pending = 0;
- /**
- * Cancel the timers, we dont want the timer firing as we are
- * changing the clock rate. Dont let idle_exit and others setup
- * timers as well.
- */
- hrtimer_cancel(&core->timer);
- core->timer_disabled = 1;
- spin_unlock_irqrestore(&core->cpu_lock, flags);
+ core->time_start = ns_to_ktime(0);
+
+ if (requested_freq < 0) {
+ requested_freq = -1 * requested_freq;
+ core->pending_freq = STOP_FREQ_CHANGE;
+ } else {
+ core->pending_freq = NO_OUTSTANDING_FREQ_CHANGE;
+ }
if (requested_freq == core->actual_freq)
- return ret;
+ goto out;
+
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
/**
* Call the frequency sink driver to change the frequency
* We will need to get back the actual frequency in KHz and
* the record the time taken to change it.
*/
- ret = core->freq_driver->set_frequency(core->freq_driver,
- requested_freq);
- if (ret <= 0) {
+ ret = core->set_frequency(core->type_core_num, requested_freq);
+ if (ret <= 0)
__err("Core %s failed to set freq %u\n",
core->core_name, requested_freq);
/* continue to call TZ to get updated slack timer */
- } else {
- prev_freq = core->actual_freq;
+ else
core->actual_freq = ret;
- }
- time_end = ktime_to_ns(ktime_get());
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
- __info("Core %s Time end %llu Time start: %llu\n",
- core->core_name, time_end, time_start);
- time_end -= time_start;
- do_div(time_end, NSEC_PER_USEC);
- core->freq_change_us = (uint32_t)time_end;
+ core->freq_change_us = (uint32_t)ktime_to_us(
+ ktime_sub(ktime_get(), time_start));
/**
* Disable low power modes if the actual frequency is >
* disable_pc_threshold.
*/
- if (core->actual_freq >
- core->algo_param.disable_pc_threshold) {
- core->idle_driver->enable(core->idle_driver,
+ if (core->actual_freq > core->algo_param.disable_pc_threshold) {
+ core->idle_enable(core->type_core_num,
MSM_DCVS_DISABLE_HIGH_LATENCY_MODES);
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Disabling LPM for %s\n", core->core_name);
- } else if (core->actual_freq <=
- core->algo_param.disable_pc_threshold) {
- core->idle_driver->enable(core->idle_driver,
+ } else if (core->actual_freq <= core->algo_param.disable_pc_threshold) {
+ core->idle_enable(core->type_core_num,
MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Enabling LPM for %s\n", core->core_name);
}
/**
@@ -191,108 +308,165 @@
* to this frequency and that will get us the new slack
* timer
*/
- ret = msm_dcvs_scm_event(core->handle, MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
- core->actual_freq, (uint32_t)time_end, &slack_us, &ret1);
- if (!ret) {
- /* Reset the slack timer */
- if (slack_us) {
- core->timer_disabled = 0;
- ret = hrtimer_start(&core->timer,
- ktime_set(0, slack_us * 1000),
- HRTIMER_MODE_REL_PINNED);
- if (ret)
- __err("Failed to register timer for core %s\n",
- core->core_name);
- }
- } else {
- __err("Error sending core (%s) freq change (%u)\n",
- core->core_name, core->actual_freq);
+ ret = msm_dcvs_scm_event(core->dcvs_core_id,
+ MSM_DCVS_SCM_CLOCK_FREQ_UPDATE,
+ core->actual_freq, core->freq_change_us,
+ &slack_us, &ret1);
+ if (ret) {
+ __err("Error sending core (%s) dcvs_core_id = %d freq change (%u) reqfreq = %d slack_us=%d ret = %d\n",
+ core->core_name, core->dcvs_core_id,
+ core->actual_freq, requested_freq,
+ slack_us, ret);
}
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
- __info("Freq %u requested for core %s (actual %u prev %u) "
- "change time %u us slack time %u us\n",
- requested_freq, core->core_name,
- core->actual_freq, prev_freq,
- core->freq_change_us, slack_us);
+ /* TODO confirm that we get a valid freq from SM even when the above
+ * FREQ_UPDATE fails
+ */
+ restart_slack_timer(core, slack_us);
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
/**
* By the time we are done with freq changes, we could be asked to
* change again. Check before exiting.
*/
- if (core->freq_pending)
+ if (core->pending_freq != NO_OUTSTANDING_FREQ_CHANGE
+ && core->pending_freq != STOP_FREQ_CHANGE) {
goto repeat;
+ }
- core->change_freq_activated = 0;
+out: /* should always be jumped to with the spin_lock held */
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
+
return ret;
}
+static void msm_dcvs_report_temp_work(struct work_struct *work)
+{
+ struct dcvs_core *core = container_of(work,
+ struct dcvs_core,
+ temperature_work.work);
+ struct msm_dcvs_core_info *info = core->info;
+ struct tsens_device tsens_dev;
+ int ret;
+ unsigned long temp = 0;
+ int interval_ms;
+
+ tsens_dev.sensor_num = core->sensor;
+ ret = tsens_get_temp(&tsens_dev, &temp);
+ if (!temp) {
+ tsens_dev.sensor_num = 0;
+ ret = tsens_get_temp(&tsens_dev, &temp);
+ if (!temp)
+ goto out;
+ }
+
+ if (temp == info->power_param.current_temp)
+ goto out;
+ info->power_param.current_temp = temp;
+
+ ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id,
+ &info->power_param,
+ &info->freq_tbl[0], &core->coeffs);
+out:
+ if (info->thermal_poll_ms == 0)
+ interval_ms = 60000;
+ else if (info->thermal_poll_ms < 1000)
+ interval_ms = 1000;
+ else
+ interval_ms = info->thermal_poll_ms;
+
+ schedule_delayed_work(&core->temperature_work,
+ msecs_to_jiffies(interval_ms));
+}
+
static int msm_dcvs_do_freq(void *data)
{
struct dcvs_core *core = (struct dcvs_core *)data;
static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
sched_setscheduler(current, SCHED_FIFO, ¶m);
- set_current_state(TASK_UNINTERRUPTIBLE);
while (!kthread_should_stop()) {
- mutex_lock(&core->lock);
- __msm_dcvs_change_freq(core);
- mutex_unlock(&core->lock);
-
- schedule();
+ wait_event(core->wait_q, !(core->pending_freq == 0 ||
+ core->pending_freq == -1) ||
+ kthread_should_stop());
if (kthread_should_stop())
break;
- set_current_state(TASK_UNINTERRUPTIBLE);
+ __msm_dcvs_change_freq(core);
}
- __set_current_state(TASK_RUNNING);
-
return 0;
}
+/* freq_pending_lock should be held */
+static void request_freq_change(struct dcvs_core *core, int new_freq)
+{
+ if (new_freq == NO_OUTSTANDING_FREQ_CHANGE) {
+ if (core->pending_freq != STOP_FREQ_CHANGE) {
+ __err("%s gov started with earlier pending freq %d\n",
+ core->core_name, core->pending_freq);
+ }
+ core->pending_freq = NO_OUTSTANDING_FREQ_CHANGE;
+ return;
+ }
+
+ if (new_freq == STOP_FREQ_CHANGE) {
+ if (core->pending_freq == NO_OUTSTANDING_FREQ_CHANGE)
+ core->pending_freq = STOP_FREQ_CHANGE;
+ else if (core->pending_freq > 0)
+ core->pending_freq = -1 * core->pending_freq;
+ return;
+ }
+
+ if (core->pending_freq < 0) {
+ /* a value less than 0 means that the governor has stopped
+ * and no more freq changes should be requested
+ */
+ return;
+ }
+
+ if (core->actual_freq != new_freq && core->pending_freq != new_freq) {
+ core->pending_freq = new_freq;
+ core->time_start = ktime_get();
+ wake_up(&core->wait_q);
+ }
+}
+
static int msm_dcvs_update_freq(struct dcvs_core *core,
enum msm_dcvs_scm_event event, uint32_t param0,
- uint32_t *ret1, int *freq_changed)
+ uint32_t *ret1)
{
int ret = 0;
unsigned long flags = 0;
- uint32_t new_freq = 0;
+ uint32_t new_freq = -EINVAL;
- spin_lock_irqsave(&core->cpu_lock, flags);
- ret = msm_dcvs_scm_event(core->handle, event, param0,
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
+
+ ret = msm_dcvs_scm_event(core->dcvs_core_id, event, param0,
core->actual_freq, &new_freq, ret1);
if (ret) {
- __err("Error (%d) sending SCM event %d for core %s\n",
+ if (ret == -13)
+ ret = 0;
+ else
+ __err("Error (%d) sending SCM event %d for core %s\n",
ret, event, core->core_name);
- goto freq_done;
+ goto out;
}
- if ((core->actual_freq != new_freq) &&
- (core->new_freq[core->freq_pending] != new_freq)) {
- if (core->freq_pending >= MAX_PENDING - 1)
- core->freq_pending = MAX_PENDING - 1;
- core->new_freq[core->freq_pending++] = new_freq;
- core->time_start = ktime_to_ns(ktime_get());
-
- /* Schedule the frequency change */
- if (!core->task)
- __err("Uninitialized task for core %s\n",
- core->core_name);
- else {
- if (freq_changed)
- *freq_changed = 1;
- core->change_freq_activated = 1;
- wake_up_process(core->task);
- }
- } else {
- if (freq_changed)
- *freq_changed = 0;
+ if (new_freq == 0) {
+ /*
+ * sometimes TZ gives us a 0 freq back,
+ * do not queue up a request
+ */
+ goto out;
}
-freq_done:
- spin_unlock_irqrestore(&core->cpu_lock, flags);
+
+ request_freq_change(core, new_freq);
+
+out:
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
return ret;
}
@@ -300,19 +474,17 @@
static enum hrtimer_restart msm_dcvs_core_slack_timer(struct hrtimer *timer)
{
int ret = 0;
- struct dcvs_core *core = container_of(timer, struct dcvs_core, timer);
+ struct dcvs_core *core = container_of(timer,
+ struct dcvs_core, slack_timer);
uint32_t ret1;
- uint32_t ret2;
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)
- __info("Slack timer fired for core %s\n", core->core_name);
-
+ trace_printk("dcvs: Slack timer fired for core=%s\n", core->core_name);
/**
* Timer expired, notify TZ
* Dont care about the third arg.
*/
ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_QOS_TIMER_EXPIRED, 0,
- &ret1, &ret2);
+ &ret1);
if (ret)
__err("Timer expired for core %s but failed to notify.\n",
core->core_name);
@@ -333,6 +505,28 @@
return snprintf(buf, PAGE_SIZE, "%d\n", v); \
}
+#define DCVS_PARAM_STORE(_name) \
+static ssize_t msm_dcvs_attr_##_name##_show(struct kobject *kobj,\
+ struct kobj_attribute *attr, char *buf) \
+{ \
+ struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+ return snprintf(buf, PAGE_SIZE, "%d\n", core->info->_name); \
+} \
+static ssize_t msm_dcvs_attr_##_name##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, const char *buf, size_t count) \
+{ \
+ int ret = 0; \
+ uint32_t val = 0; \
+ struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+ ret = kstrtouint(buf, 10, &val); \
+ if (ret) { \
+ __err("Invalid input %s for %s\n", buf, __stringify(_name));\
+ } else { \
+ core->info->_name = val; \
+ } \
+ return count; \
+}
+
#define DCVS_ALGO_PARAM(_name) \
static ssize_t msm_dcvs_attr_##_name##_show(struct kobject *kobj,\
struct kobj_attribute *attr, char *buf) \
@@ -346,14 +540,13 @@
int ret = 0; \
uint32_t val = 0; \
struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
- mutex_lock(&core->lock); \
ret = kstrtouint(buf, 10, &val); \
if (ret) { \
__err("Invalid input %s for %s\n", buf, __stringify(_name));\
} else { \
uint32_t old_val = core->algo_param._name; \
core->algo_param._name = val; \
- ret = msm_dcvs_scm_set_algo_params(core->handle, \
+ ret = msm_dcvs_scm_set_algo_params(core->dcvs_core_id, \
&core->algo_param); \
if (ret) { \
core->algo_param._name = old_val; \
@@ -361,7 +554,37 @@
ret, val, __stringify(_name)); \
} \
} \
- mutex_unlock(&core->lock); \
+ return count; \
+}
+
+#define DCVS_ENERGY_PARAM(_name) \
+static ssize_t msm_dcvs_attr_##_name##_show(struct kobject *kobj,\
+ struct kobj_attribute *attr, char *buf) \
+{ \
+ struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+ return snprintf(buf, PAGE_SIZE, "%d\n", core->coeffs._name); \
+} \
+static ssize_t msm_dcvs_attr_##_name##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, const char *buf, size_t count) \
+{ \
+ int ret = 0; \
+ int32_t val = 0; \
+ struct dcvs_core *core = CORE_FROM_ATTRIBS(attr, _name); \
+ ret = kstrtoint(buf, 10, &val); \
+ if (ret) { \
+ __err("Invalid input %s for %s\n", buf, __stringify(_name));\
+ } else { \
+ int32_t old_val = core->coeffs._name; \
+ core->coeffs._name = val; \
+ ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id, \
+ &core->info->power_param, &core->info->freq_tbl[0], \
+ &core->coeffs); \
+ if (ret) { \
+ core->coeffs._name = old_val; \
+ __err("Error(%d) in setting %d for coeffs param %s\n",\
+ ret, val, __stringify(_name)); \
+ } \
+ } \
return count; \
}
@@ -383,27 +606,38 @@
* Function declarations for different attributes.
* Gets used when setting the attribute show and store parameters.
*/
-DCVS_PARAM_SHOW(idle_enabled, (core->idle_driver != NULL))
-DCVS_PARAM_SHOW(freq_change_enabled, (core->freq_driver != NULL))
-DCVS_PARAM_SHOW(actual_freq, (core->actual_freq))
DCVS_PARAM_SHOW(freq_change_us, (core->freq_change_us))
-DCVS_PARAM_SHOW(max_time_us, (core->max_time_us))
-DCVS_ALGO_PARAM(slack_time_us)
-DCVS_ALGO_PARAM(scale_slack_time)
-DCVS_ALGO_PARAM(scale_slack_time_pct)
DCVS_ALGO_PARAM(disable_pc_threshold)
-DCVS_ALGO_PARAM(em_window_size)
+DCVS_ALGO_PARAM(em_win_size_min_us)
+DCVS_ALGO_PARAM(em_win_size_max_us)
DCVS_ALGO_PARAM(em_max_util_pct)
-DCVS_ALGO_PARAM(ss_window_size)
-DCVS_ALGO_PARAM(ss_util_pct)
+DCVS_ALGO_PARAM(group_id)
+DCVS_ALGO_PARAM(max_freq_chg_time_us)
+DCVS_ALGO_PARAM(slack_mode_dynamic)
+DCVS_ALGO_PARAM(slack_time_min_us)
+DCVS_ALGO_PARAM(slack_time_max_us)
+DCVS_ALGO_PARAM(slack_weight_thresh_pct)
DCVS_ALGO_PARAM(ss_iobusy_conv)
+DCVS_ALGO_PARAM(ss_win_size_min_us)
+DCVS_ALGO_PARAM(ss_win_size_max_us)
+DCVS_ALGO_PARAM(ss_util_pct)
+
+DCVS_ENERGY_PARAM(active_coeff_a)
+DCVS_ENERGY_PARAM(active_coeff_b)
+DCVS_ENERGY_PARAM(active_coeff_c)
+DCVS_ENERGY_PARAM(leakage_coeff_a)
+DCVS_ENERGY_PARAM(leakage_coeff_b)
+DCVS_ENERGY_PARAM(leakage_coeff_c)
+DCVS_ENERGY_PARAM(leakage_coeff_d)
+
+DCVS_PARAM_STORE(thermal_poll_ms)
static int msm_dcvs_setup_core_sysfs(struct dcvs_core *core)
{
int ret = 0;
struct kobject *core_kobj = NULL;
- const int attr_count = 15;
+ const int attr_count = 24;
BUG_ON(!cores_kobj);
@@ -415,23 +649,33 @@
goto done;
}
- DCVS_RO_ATTRIB(0, idle_enabled);
- DCVS_RO_ATTRIB(1, freq_change_enabled);
- DCVS_RO_ATTRIB(2, actual_freq);
- DCVS_RO_ATTRIB(3, freq_change_us);
- DCVS_RO_ATTRIB(4, max_time_us);
+ DCVS_RO_ATTRIB(0, freq_change_us);
- DCVS_RW_ATTRIB(5, slack_time_us);
- DCVS_RW_ATTRIB(6, scale_slack_time);
- DCVS_RW_ATTRIB(7, scale_slack_time_pct);
- DCVS_RW_ATTRIB(8, disable_pc_threshold);
- DCVS_RW_ATTRIB(9, em_window_size);
- DCVS_RW_ATTRIB(10, em_max_util_pct);
- DCVS_RW_ATTRIB(11, ss_window_size);
- DCVS_RW_ATTRIB(12, ss_util_pct);
- DCVS_RW_ATTRIB(13, ss_iobusy_conv);
+ DCVS_RW_ATTRIB(1, disable_pc_threshold);
+ DCVS_RW_ATTRIB(2, em_win_size_min_us);
+ DCVS_RW_ATTRIB(3, em_win_size_max_us);
+ DCVS_RW_ATTRIB(4, em_max_util_pct);
+ DCVS_RW_ATTRIB(5, group_id);
+ DCVS_RW_ATTRIB(6, max_freq_chg_time_us);
+ DCVS_RW_ATTRIB(7, slack_mode_dynamic);
+ DCVS_RW_ATTRIB(8, slack_weight_thresh_pct);
+ DCVS_RW_ATTRIB(9, slack_time_min_us);
+ DCVS_RW_ATTRIB(10, slack_time_max_us);
+ DCVS_RW_ATTRIB(11, ss_iobusy_conv);
+ DCVS_RW_ATTRIB(12, ss_win_size_min_us);
+ DCVS_RW_ATTRIB(13, ss_win_size_max_us);
+ DCVS_RW_ATTRIB(14, ss_util_pct);
- core->attrib.attrib_group.attrs[14] = NULL;
+ DCVS_RW_ATTRIB(15, active_coeff_a);
+ DCVS_RW_ATTRIB(16, active_coeff_b);
+ DCVS_RW_ATTRIB(17, active_coeff_c);
+ DCVS_RW_ATTRIB(18, leakage_coeff_a);
+ DCVS_RW_ATTRIB(19, leakage_coeff_b);
+ DCVS_RW_ATTRIB(20, leakage_coeff_c);
+ DCVS_RW_ATTRIB(21, leakage_coeff_d);
+ DCVS_RW_ATTRIB(22, thermal_poll_ms);
+
+ core->attrib.attrib_group.attrs[23] = NULL;
core_kobj = kobject_create_and_add(core->core_name, cores_kobj);
if (!core_kobj) {
@@ -442,8 +686,6 @@
ret = sysfs_create_group(core_kobj, &core->attrib.attrib_group);
if (ret)
__err("Cannot create core %s attr group\n", core->core_name);
- else if (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER)
- __info("Setting up attributes for core %s\n", core->core_name);
done:
if (ret) {
@@ -454,273 +696,301 @@
return ret;
}
-/* Return the core if found or add to list if @add_to_list is true */
-static struct dcvs_core *msm_dcvs_get_core(const char *name, int add_to_list)
+static int get_core_offset(enum msm_dcvs_core_type type, int num)
+{
+ int offset = -EINVAL;
+
+ switch (type) {
+ case MSM_DCVS_CORE_TYPE_CPU:
+ offset = CPU_OFFSET + num;
+ BUG_ON(offset >= GPU_OFFSET);
+ break;
+ case MSM_DCVS_CORE_TYPE_GPU:
+ offset = GPU_OFFSET + num;
+ BUG_ON(offset >= CORES_MAX);
+ break;
+ default:
+ BUG();
+ }
+
+ return offset;
+}
+
+/* Return the core and initialize non platform data specific numbers in it */
+static struct dcvs_core *msm_dcvs_add_core(enum msm_dcvs_core_type type,
+ int num)
{
struct dcvs_core *core = NULL;
int i;
- int empty = -1;
+ char name[CORE_NAME_MAX];
- if (!name[0] ||
- (strnlen(name, CORE_NAME_MAX - 1) == CORE_NAME_MAX - 1))
- return core;
-
- mutex_lock(&core_list_lock);
- for (i = 0; i < CORES_MAX; i++) {
- core = &core_list[i];
- if ((empty < 0) && !core->core_name[0]) {
- empty = i;
- continue;
- }
- if (!strncmp(name, core->core_name, CORE_NAME_MAX))
- break;
- }
-
- /* Check for core_list full */
- if ((i == CORES_MAX) && (empty < 0)) {
- mutex_unlock(&core_list_lock);
+ i = get_core_offset(type, num);
+ if (i < 0)
return NULL;
- }
- if (i == CORES_MAX && add_to_list) {
- core = &core_list[empty];
- strlcpy(core->core_name, name, CORE_NAME_MAX);
- mutex_init(&core->lock);
- spin_lock_init(&core->cpu_lock);
- core->handle = empty + CORE_HANDLE_OFFSET;
- hrtimer_init(&core->timer,
- CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
- core->timer.function = msm_dcvs_core_slack_timer;
- }
- mutex_unlock(&core_list_lock);
+ if (type == MSM_DCVS_CORE_TYPE_CPU)
+ snprintf(name, CORE_NAME_MAX, "cpu%d", num);
+ else
+ snprintf(name, CORE_NAME_MAX, "gpu%d", num);
+ core = &core_list[i];
+ core->dcvs_core_id = i;
+ strlcpy(core->core_name, name, CORE_NAME_MAX);
+ spin_lock_init(&core->pending_freq_lock);
+ spin_lock_init(&core->idle_state_change_lock);
+ hrtimer_init(&core->slack_timer,
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+ core->slack_timer.function = msm_dcvs_core_slack_timer;
return core;
}
-int msm_dcvs_register_core(const char *core_name, uint32_t group_id,
- struct msm_dcvs_core_info *info)
+/* Return the core if found or add to list if @add_to_list is true */
+static struct dcvs_core *msm_dcvs_get_core(int offset)
+{
+ /* if the handle is still not set bug */
+ BUG_ON(core_list[offset].dcvs_core_id == -1);
+ return &core_list[offset];
+}
+
+
+int msm_dcvs_register_core(
+ enum msm_dcvs_core_type type,
+ int type_core_num,
+ struct msm_dcvs_core_info *info,
+ int (*set_frequency)(int type_core_num, unsigned int freq),
+ unsigned int (*get_frequency)(int type_core_num),
+ int (*idle_enable)(int type_core_num,
+ enum msm_core_control_event event),
+ int sensor)
{
int ret = -EINVAL;
+ int offset;
struct dcvs_core *core = NULL;
+ uint32_t ret1;
+ uint32_t ret2;
- if (!core_name || !core_name[0])
+ offset = get_core_offset(type, type_core_num);
+ if (offset < 0)
return ret;
+ if (core_list[offset].dcvs_core_id != -1)
+ return core_list[offset].dcvs_core_id;
- core = msm_dcvs_get_core(core_name, true);
+ core = msm_dcvs_add_core(type, type_core_num);
if (!core)
return ret;
- mutex_lock(&core->lock);
- if (group_id) {
- /**
- * Create a group for cores, if this core is part of a group
- * if the group_id is 0, the core is not part of a group.
- * If the group_id already exits, it will through an error
- * which we will ignore.
- */
- ret = msm_dcvs_scm_create_group(group_id);
- if (ret == -ENOMEM)
- goto bail;
- }
- core->group_id = group_id;
+ core->type = type;
+ core->type_core_num = type_core_num;
+ core->set_frequency = set_frequency;
+ core->get_frequency = get_frequency;
+ core->idle_enable = idle_enable;
+ core->pending_freq = STOP_FREQ_CHANGE;
- core->max_time_us = info->core_param.max_time_us;
+ core->info = info;
memcpy(&core->algo_param, &info->algo_param,
sizeof(struct msm_dcvs_algo_param));
- ret = msm_dcvs_scm_register_core(core->handle, group_id,
- &info->core_param, info->freq_tbl);
- if (ret)
- goto bail;
+ memcpy(&core->coeffs, &info->energy_coeffs,
+ sizeof(struct msm_dcvs_energy_curve_coeffs));
- ret = msm_dcvs_scm_set_algo_params(core->handle, &info->algo_param);
+ /*
+ * The tz expects cpu0 to represent bit 0 in the mask, however the
+ * dcvs_core_id needs to start from 1, dcvs_core_id = 0 is used to
+ * indicate that this request is not associated with any core.
+ * mpdecision
+ */
+ info->core_param.core_bitmask_id
+ = 1 << (core->dcvs_core_id - CPU_OFFSET);
+ core->sensor = sensor;
+
+ ret = msm_dcvs_scm_register_core(core->dcvs_core_id, &info->core_param);
+ if (ret) {
+ __err("%s: scm register core fail handle = %d ret = %d\n",
+ __func__, core->dcvs_core_id, ret);
+ goto bail;
+ }
+
+ ret = msm_dcvs_scm_set_algo_params(core->dcvs_core_id,
+ &info->algo_param);
+ if (ret) {
+ __err("%s: scm algo params failed ret = %d\n", __func__, ret);
+ goto bail;
+ }
+
+ ret = msm_dcvs_scm_set_power_params(core->dcvs_core_id,
+ &info->power_param,
+ &info->freq_tbl[0], &core->coeffs);
+ if (ret) {
+ __err("%s: scm power params failed ret = %d\n", __func__, ret);
+ goto bail;
+ }
+
+ ret = msm_dcvs_scm_event(core->dcvs_core_id, MSM_DCVS_SCM_CORE_ONLINE,
+ core->actual_freq, 0, &ret1, &ret2);
if (ret)
goto bail;
ret = msm_dcvs_setup_core_sysfs(core);
if (ret) {
__err("Unable to setup core %s sysfs\n", core->core_name);
- core_handles[core->handle - CORE_HANDLE_OFFSET] = NULL;
goto bail;
}
+ core->idle_entered = -1;
+ init_waitqueue_head(&core->wait_q);
+ core->task = kthread_run(msm_dcvs_do_freq, (void *)core,
+ "msm_dcvs/%d", core->dcvs_core_id);
+ ret = core->dcvs_core_id;
-bail:
- mutex_unlock(&core->lock);
+ INIT_DELAYED_WORK(&core->temperature_work, msm_dcvs_report_temp_work);
+ schedule_delayed_work(&core->temperature_work,
+ msecs_to_jiffies(info->thermal_poll_ms));
return ret;
+bail:
+ core->dcvs_core_id = -1;
+ return -EINVAL;
}
EXPORT_SYMBOL(msm_dcvs_register_core);
-int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv)
+void msm_dcvs_update_limits(int dcvs_core_id)
+{
+ struct dcvs_core *core;
+
+ if (dcvs_core_id < CPU_OFFSET || dcvs_core_id > CORES_MAX) {
+ __err("%s invalid dcvs_core_id = %d returning -EINVAL\n",
+ __func__, dcvs_core_id);
+ return;
+ }
+
+ core = msm_dcvs_get_core(dcvs_core_id);
+ core->actual_freq = core->get_frequency(core->type_core_num);
+}
+
+int msm_dcvs_freq_sink_start(int dcvs_core_id)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
uint32_t ret1;
- uint32_t ret2;
+ unsigned long flags;
+ int new_freq;
+ int timer_interval_us;
- if (!drv || !drv->core_name)
- return ret;
+ if (dcvs_core_id < CPU_OFFSET || dcvs_core_id > CORES_MAX) {
+ __err("%s invalid dcvs_core_id = %d returning -EINVAL\n",
+ __func__, dcvs_core_id);
+ return -EINVAL;
+ }
- core = msm_dcvs_get_core(drv->core_name, true);
+ core = msm_dcvs_get_core(dcvs_core_id);
if (!core)
return ret;
- mutex_lock(&core->lock);
- if (core->freq_driver && (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER))
- __info("Frequency notifier for %s being replaced\n",
- core->core_name);
- core->freq_driver = drv;
- core->task = kthread_create(msm_dcvs_do_freq, (void *)core,
- "msm_dcvs/%d", core->handle);
- if (IS_ERR(core->task)) {
- mutex_unlock(&core->lock);
- return -EFAULT;
+ core->actual_freq = core->get_frequency(core->type_core_num);
+
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
+ /* mark that we are ready to accept new frequencies */
+ request_freq_change(core, NO_OUTSTANDING_FREQ_CHANGE);
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
+
+ spin_lock_irqsave(&core->idle_state_change_lock, flags);
+ core->idle_entered = -1;
+ spin_unlock_irqrestore(&core->idle_state_change_lock, flags);
+
+ /* Notify TZ to start receiving idle info for the core */
+ ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 1, &ret1);
+
+ ret = msm_dcvs_scm_event(
+ core->dcvs_core_id, MSM_DCVS_SCM_CORE_ONLINE, core->actual_freq,
+ 0, &new_freq, &timer_interval_us);
+ if (ret)
+ __err("Error (%d) DCVS sending online for %s\n",
+ ret, core->core_name);
+
+ if (new_freq != 0) {
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
+ request_freq_change(core, new_freq);
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
}
+ force_start_slack_timer(core, timer_interval_us);
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Enabling idle pulse for %s\n", core->core_name);
- if (core->idle_driver) {
- core->actual_freq = core->freq_driver->get_frequency(drv);
- /* Notify TZ to start receiving idle info for the core */
- ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_ENABLE_CORE, 1,
- &ret1, &ret2);
- core->idle_driver->enable(core->idle_driver,
- MSM_DCVS_ENABLE_IDLE_PULSE);
- }
-
- mutex_unlock(&core->lock);
-
- return core->handle;
+ core->idle_enable(core->type_core_num, MSM_DCVS_ENABLE_IDLE_PULSE);
+ return 0;
}
-EXPORT_SYMBOL(msm_dcvs_freq_sink_register);
+EXPORT_SYMBOL(msm_dcvs_freq_sink_start);
-int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv)
+int msm_dcvs_freq_sink_stop(int dcvs_core_id)
{
int ret = -EINVAL;
struct dcvs_core *core = NULL;
uint32_t ret1;
- uint32_t ret2;
+ uint32_t freq;
+ unsigned long flags;
- if (!drv || !drv->core_name)
- return ret;
-
- core = msm_dcvs_get_core(drv->core_name, false);
- if (!core)
- return ret;
-
- mutex_lock(&core->lock);
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Disabling idle pulse for %s\n", core->core_name);
- if (core->idle_driver) {
- core->idle_driver->enable(core->idle_driver,
- MSM_DCVS_DISABLE_IDLE_PULSE);
- /* Notify TZ to stop receiving idle info for the core */
- ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_ENABLE_CORE, 0,
- &ret1, &ret2);
- hrtimer_cancel(&core->timer);
- core->idle_driver->enable(core->idle_driver,
- MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Enabling LPM for %s\n", core->core_name);
+ if (dcvs_core_id < 0 || dcvs_core_id > CORES_MAX) {
+ pr_err("%s invalid dcvs_core_id = %d returning -EINVAL\n",
+ __func__, dcvs_core_id);
+ return -EINVAL;
}
- core->freq_pending = 0;
- core->freq_driver = NULL;
- mutex_unlock(&core->lock);
- kthread_stop(core->task);
+
+ core = msm_dcvs_get_core(dcvs_core_id);
+ if (!core) {
+ __err("couldn't find core for coreid = %d\n", dcvs_core_id);
+ return ret;
+ }
+
+ core->idle_enable(core->type_core_num, MSM_DCVS_DISABLE_IDLE_PULSE);
+ /* Notify TZ to stop receiving idle info for the core */
+ ret = msm_dcvs_scm_event(core->dcvs_core_id, MSM_DCVS_SCM_DCVS_ENABLE,
+ 0, core->actual_freq, &freq, &ret1);
+ core->idle_enable(core->type_core_num,
+ MSM_DCVS_ENABLE_HIGH_LATENCY_MODES);
+ spin_lock_irqsave(&core->pending_freq_lock, flags);
+ /* flush out all the pending freq changes */
+ request_freq_change(core, STOP_FREQ_CHANGE);
+ spin_unlock_irqrestore(&core->pending_freq_lock, flags);
+ force_stop_slack_timer(core);
return 0;
}
-EXPORT_SYMBOL(msm_dcvs_freq_sink_unregister);
+EXPORT_SYMBOL(msm_dcvs_freq_sink_stop);
-int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv)
-{
- int ret = -EINVAL;
- struct dcvs_core *core = NULL;
-
- if (!drv || !drv->core_name)
- return ret;
-
- core = msm_dcvs_get_core(drv->core_name, true);
- if (!core)
- return ret;
-
- mutex_lock(&core->lock);
- if (core->idle_driver && (msm_dcvs_debug & MSM_DCVS_DEBUG_NOTIFIER))
- __info("Idle notifier for %s being replaced\n",
- core->core_name);
- core->idle_driver = drv;
- mutex_unlock(&core->lock);
-
- return core->handle;
-}
-EXPORT_SYMBOL(msm_dcvs_idle_source_register);
-
-int msm_dcvs_idle_source_unregister(struct msm_dcvs_idle *drv)
-{
- int ret = -EINVAL;
- struct dcvs_core *core = NULL;
-
- if (!drv || !drv->core_name)
- return ret;
-
- core = msm_dcvs_get_core(drv->core_name, false);
- if (!core)
- return ret;
-
- mutex_lock(&core->lock);
- core->idle_driver = NULL;
- mutex_unlock(&core->lock);
-
- return 0;
-}
-EXPORT_SYMBOL(msm_dcvs_idle_source_unregister);
-
-int msm_dcvs_idle(int handle, enum msm_core_idle_state state, uint32_t iowaited)
+int msm_dcvs_idle(int dcvs_core_id, enum msm_core_idle_state state,
+ uint32_t iowaited)
{
int ret = 0;
struct dcvs_core *core = NULL;
uint32_t timer_interval_us = 0;
uint32_t r0, r1;
- uint32_t freq_changed = 0;
- if (handle >= CORE_HANDLE_OFFSET &&
- (handle - CORE_HANDLE_OFFSET) < CORES_MAX)
- core = &core_list[handle - CORE_HANDLE_OFFSET];
+ if (dcvs_core_id < CPU_OFFSET || dcvs_core_id > CORES_MAX) {
+ pr_err("invalid dcvs_core_id = %d ret -EINVAL\n", dcvs_core_id);
+ return -EINVAL;
+ }
- BUG_ON(!core);
-
- if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
- __info("Core %s idle state %d\n", core->core_name, state);
+ core = msm_dcvs_get_core(dcvs_core_id);
switch (state) {
case MSM_DCVS_IDLE_ENTER:
- hrtimer_cancel(&core->timer);
- ret = msm_dcvs_scm_event(core->handle,
+ stop_slack_timer(core);
+ ret = msm_dcvs_scm_event(core->dcvs_core_id,
MSM_DCVS_SCM_IDLE_ENTER, 0, 0, &r0, &r1);
- if (ret)
+ if (ret < 0 && ret != -13)
__err("Error (%d) sending idle enter for %s\n",
ret, core->core_name);
+ trace_msm_dcvs_idle("idle_enter_exit", core->core_name, 1);
break;
case MSM_DCVS_IDLE_EXIT:
- hrtimer_cancel(&core->timer);
ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_IDLE_EXIT,
- iowaited, &timer_interval_us, &freq_changed);
+ iowaited, &timer_interval_us);
if (ret)
__err("Error (%d) sending idle exit for %s\n",
ret, core->core_name);
- /* only start slack timer if change_freq won't */
- if (freq_changed || core->change_freq_activated)
- break;
- if (timer_interval_us && !core->timer_disabled) {
- ret = hrtimer_start(&core->timer,
- ktime_set(0, timer_interval_us * 1000),
- HRTIMER_MODE_REL_PINNED);
-
- if (ret)
- __err("Failed to register timer for core %s\n",
- core->core_name);
- }
+ start_slack_timer(core, timer_interval_us);
+ trace_msm_dcvs_idle("idle_enter_exit", core->core_name, 0);
+ trace_msm_dcvs_iowait("iowait", core->core_name, iowaited);
+ trace_msm_dcvs_slack_time("slack_timer_dcvs", core->core_name,
+ timer_interval_us);
break;
}
@@ -755,13 +1025,6 @@
goto err;
}
- if (!debugfs_create_u32("debug_mask", S_IRUGO | S_IWUSR,
- debugfs_base, &msm_dcvs_debug)) {
- __err("Cannot create debugfs entry %s\n", "debug_mask");
- ret = -ENOMEM;
- goto err;
- }
-
err:
if (ret) {
kobject_del(cores_kobj);
@@ -776,16 +1039,24 @@
static int __init msm_dcvs_early_init(void)
{
int ret = 0;
+ int i;
if (!msm_dcvs_enabled) {
__info("Not enabled (%d)\n", msm_dcvs_enabled);
return 0;
}
- ret = msm_dcvs_scm_init(10 * 1024);
- if (ret)
- __err("Unable to initialize DCVS err=%d\n", ret);
+ /* Only need about 32kBytes for normal operation */
+ ret = msm_dcvs_scm_init(SZ_32K);
+ if (ret) {
+ __err("Unable to initialize DCVS err=%d\n", ret);
+ goto done;
+ }
+
+ for (i = 0; i < CORES_MAX; i++)
+ core_list[i].dcvs_core_id = -1;
+done:
return ret;
}
postcore_initcall(msm_dcvs_early_init);
diff --git a/arch/arm/mach-msm/msm_dcvs_idle.c b/arch/arm/mach-msm/msm_dcvs_idle.c
deleted file mode 100644
index 179e170..0000000
--- a/arch/arm/mach-msm/msm_dcvs_idle.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/cpu_pm.h>
-#include <linux/platform_device.h>
-#include <linux/pm_qos.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-#include <mach/msm_dcvs.h>
-
-struct cpu_idle_info {
- int cpu;
- int enabled;
- int handle;
- struct msm_dcvs_idle dcvs_notifier;
-};
-
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_idle_info, cpu_idle_info);
-static DEFINE_PER_CPU_SHARED_ALIGNED(u64, iowait_on_cpu);
-static char core_name[NR_CPUS][10];
-static struct pm_qos_request qos_req;
-static uint32_t latency;
-
-static int msm_dcvs_idle_notifier(struct msm_dcvs_idle *self,
- enum msm_core_control_event event)
-{
- struct cpu_idle_info *info = container_of(self,
- struct cpu_idle_info, dcvs_notifier);
-
- switch (event) {
- case MSM_DCVS_ENABLE_IDLE_PULSE:
- info->enabled = true;
- break;
-
- case MSM_DCVS_DISABLE_IDLE_PULSE:
- info->enabled = false;
- break;
-
- case MSM_DCVS_ENABLE_HIGH_LATENCY_MODES:
- pm_qos_update_request(&qos_req, PM_QOS_DEFAULT_VALUE);
- break;
-
- case MSM_DCVS_DISABLE_HIGH_LATENCY_MODES:
- pm_qos_update_request(&qos_req, latency);
- break;
- }
-
- return 0;
-}
-
-static int msm_cpuidle_notifier(struct notifier_block *self, unsigned long cmd,
- void *v)
-{
- struct cpu_idle_info *info =
- &per_cpu(cpu_idle_info, smp_processor_id());
- u64 io_wait_us = 0;
- u64 prev_io_wait_us = 0;
- u64 last_update_time = 0;
- u64 val = 0;
- uint32_t iowaited = 0;
-
- if (!info->enabled)
- return NOTIFY_OK;
-
- switch (cmd) {
- case CPU_PM_ENTER:
- val = get_cpu_iowait_time_us(smp_processor_id(),
- &last_update_time);
- /* val could be -1 when NOHZ is not enabled */
- if (val == (u64)-1)
- val = 0;
- per_cpu(iowait_on_cpu, smp_processor_id()) = val;
- msm_dcvs_idle(info->handle, MSM_DCVS_IDLE_ENTER, 0);
- break;
-
- case CPU_PM_ENTER_FAILED:
- case CPU_PM_EXIT:
- prev_io_wait_us = per_cpu(iowait_on_cpu, smp_processor_id());
- val = get_cpu_iowait_time_us(smp_processor_id(),
- &last_update_time);
- if (val == (u64)-1)
- val = 0;
- io_wait_us = val;
- iowaited = (io_wait_us - prev_io_wait_us);
- msm_dcvs_idle(info->handle, MSM_DCVS_IDLE_EXIT, iowaited);
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block idle_nb = {
- .notifier_call = msm_cpuidle_notifier,
-};
-
-static int msm_dcvs_idle_probe(struct platform_device *pdev)
-{
- int cpu;
- struct cpu_idle_info *info = NULL;
- struct msm_dcvs_idle *inotify = NULL;
-
- for_each_possible_cpu(cpu) {
- info = &per_cpu(cpu_idle_info, cpu);
- info->cpu = cpu;
- inotify = &info->dcvs_notifier;
- snprintf(core_name[cpu], 10, "cpu%d", cpu);
- inotify->core_name = core_name[cpu];
- inotify->enable = msm_dcvs_idle_notifier;
- info->handle = msm_dcvs_idle_source_register(inotify);
- BUG_ON(info->handle < 0);
- }
-
- latency = *((uint32_t *)pdev->dev.platform_data);
- pm_qos_add_request(&qos_req, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
-
- return cpu_pm_register_notifier(&idle_nb);
-}
-
-static int msm_dcvs_idle_remove(struct platform_device *pdev)
-{
- int ret = 0;
- int rc = 0;
- int cpu = 0;
- struct msm_dcvs_idle *inotify = NULL;
- struct cpu_idle_info *info = NULL;
-
- rc = cpu_pm_unregister_notifier(&idle_nb);
-
- for_each_possible_cpu(cpu) {
- info = &per_cpu(cpu_idle_info, cpu);
- inotify = &info->dcvs_notifier;
- ret = msm_dcvs_idle_source_unregister(inotify);
- if (ret) {
- rc = -EFAULT;
- pr_err("Error de-registering core %d idle notifier.\n",
- cpu);
- }
- }
-
- return rc;
-}
-
-static struct platform_driver idle_pdrv = {
- .probe = msm_dcvs_idle_probe,
- .remove = __devexit_p(msm_dcvs_idle_remove),
- .driver = {
- .name = "msm_cpu_idle",
- .owner = THIS_MODULE,
- },
-};
-
-static int msm_dcvs_idle_init(void)
-{
- return platform_driver_register(&idle_pdrv);
-}
-late_initcall(msm_dcvs_idle_init);
diff --git a/arch/arm/mach-msm/msm_dcvs_scm.c b/arch/arm/mach-msm/msm_dcvs_scm.c
index 6095e0813..78d62ac 100644
--- a/arch/arm/mach-msm/msm_dcvs_scm.c
+++ b/arch/arm/mach-msm/msm_dcvs_scm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,18 +20,17 @@
#include <mach/memory.h>
#include <mach/scm.h>
#include <mach/msm_dcvs_scm.h>
+#include <trace/events/mpdcvs_trace.h>
-#define DCVS_CMD_CREATE_GROUP 1
#define DCVS_CMD_REGISTER_CORE 2
#define DCVS_CMD_SET_ALGO_PARAM 3
#define DCVS_CMD_EVENT 4
#define DCVS_CMD_INIT 5
+#define DCVS_CMD_SET_POWER_PARAM 6
struct scm_register_core {
uint32_t core_id;
- uint32_t group_id;
phys_addr_t core_param_phy;
- phys_addr_t freq_phy;
};
struct scm_algo {
@@ -44,6 +43,21 @@
uint32_t size;
};
+struct scm_pwr_param {
+ uint32_t core_id;
+ phys_addr_t pwr_param_phy;
+ phys_addr_t freq_phy;
+ phys_addr_t coeffs_phy;
+};
+
+struct msm_algo_param {
+ enum msm_dcvs_algo_param_type type;
+ union {
+ struct msm_dcvs_algo_param dcvs_param;
+ struct msm_mpd_algo_param mpd_param;
+ } u;
+};
+
int msm_dcvs_scm_init(size_t size)
{
int ret = 0;
@@ -69,49 +83,25 @@
}
EXPORT_SYMBOL(msm_dcvs_scm_init);
-int msm_dcvs_scm_create_group(uint32_t id)
-{
- int ret = 0;
-
- ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_CREATE_GROUP,
- &id, sizeof(uint32_t), NULL, 0);
-
- return ret;
-}
-EXPORT_SYMBOL(msm_dcvs_scm_create_group);
-
-int msm_dcvs_scm_register_core(uint32_t core_id, uint32_t group_id,
- struct msm_dcvs_core_param *param,
- struct msm_dcvs_freq_entry *freq)
+int msm_dcvs_scm_register_core(uint32_t core_id,
+ struct msm_dcvs_core_param *param)
{
int ret = 0;
struct scm_register_core reg_data;
struct msm_dcvs_core_param *p = NULL;
- struct msm_dcvs_freq_entry *f = NULL;
p = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_core_param)), GFP_KERNEL);
if (!p)
return -ENOMEM;
- f = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_freq_entry) *
- param->num_freq), GFP_KERNEL);
- if (!f) {
- kfree(p);
- return -ENOMEM;
- }
-
memcpy(p, param, sizeof(struct msm_dcvs_core_param));
- memcpy(f, freq, sizeof(struct msm_dcvs_freq_entry) * param->num_freq);
reg_data.core_id = core_id;
- reg_data.group_id = group_id;
reg_data.core_param_phy = virt_to_phys(p);
- reg_data.freq_phy = virt_to_phys(f);
ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_REGISTER_CORE,
®_data, sizeof(reg_data), NULL, 0);
- kfree(f);
kfree(p);
return ret;
@@ -123,13 +113,14 @@
{
int ret = 0;
struct scm_algo algo;
- struct msm_dcvs_algo_param *p = NULL;
+ struct msm_algo_param *p = NULL;
- p = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_algo_param)), GFP_KERNEL);
+ p = kzalloc(PAGE_ALIGN(sizeof(struct msm_algo_param)), GFP_KERNEL);
if (!p)
return -ENOMEM;
- memcpy(p, param, sizeof(struct msm_dcvs_algo_param));
+ p->type = MSM_DCVS_ALGO_DCVS_PARAM;
+ memcpy(&p->u.dcvs_param, param, sizeof(struct msm_dcvs_algo_param));
algo.core_id = core_id;
algo.algo_phy = virt_to_phys(p);
@@ -143,6 +134,85 @@
}
EXPORT_SYMBOL(msm_dcvs_scm_set_algo_params);
+int msm_mpd_scm_set_algo_params(struct msm_mpd_algo_param *param)
+{
+ int ret = 0;
+ struct scm_algo algo;
+ struct msm_algo_param *p = NULL;
+
+ p = kzalloc(PAGE_ALIGN(sizeof(struct msm_algo_param)), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ p->type = MSM_DCVS_ALGO_MPD_PARAM;
+ memcpy(&p->u.mpd_param, param, sizeof(struct msm_mpd_algo_param));
+
+ algo.core_id = 0;
+ algo.algo_phy = virt_to_phys(p);
+
+ ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_ALGO_PARAM,
+ &algo, sizeof(algo), NULL, 0);
+
+ kfree(p);
+
+ return ret;
+}
+EXPORT_SYMBOL(msm_mpd_scm_set_algo_params);
+
+int msm_dcvs_scm_set_power_params(uint32_t core_id,
+ struct msm_dcvs_power_params *pwr_param,
+ struct msm_dcvs_freq_entry *freq_entry,
+ struct msm_dcvs_energy_curve_coeffs *coeffs)
+{
+ int ret = 0;
+ struct scm_pwr_param pwr;
+ struct msm_dcvs_power_params *pwrt = NULL;
+ struct msm_dcvs_freq_entry *freqt = NULL;
+ struct msm_dcvs_energy_curve_coeffs *coefft = NULL;
+
+ pwrt = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_power_params)),
+ GFP_KERNEL);
+ if (!pwrt)
+ return -ENOMEM;
+
+ freqt = kzalloc(PAGE_ALIGN(sizeof(struct msm_dcvs_freq_entry)
+ * pwr_param->num_freq),
+ GFP_KERNEL);
+ if (!freqt) {
+ kfree(pwrt);
+ return -ENOMEM;
+ }
+
+ coefft = kzalloc(PAGE_ALIGN(
+ sizeof(struct msm_dcvs_energy_curve_coeffs)),
+ GFP_KERNEL);
+ if (!coefft) {
+ kfree(pwrt);
+ kfree(freqt);
+ return -ENOMEM;
+ }
+
+ memcpy(pwrt, pwr_param, sizeof(struct msm_dcvs_power_params));
+ memcpy(freqt, freq_entry,
+ sizeof(struct msm_dcvs_freq_entry)*pwr_param->num_freq);
+ memcpy(coefft, coeffs, sizeof(struct msm_dcvs_energy_curve_coeffs));
+
+ pwr.core_id = core_id;
+ pwr.pwr_param_phy = virt_to_phys(pwrt);
+ pwr.freq_phy = virt_to_phys(freqt);
+ pwr.coeffs_phy = virt_to_phys(coefft);
+
+ ret = scm_call(SCM_SVC_DCVS, DCVS_CMD_SET_POWER_PARAM,
+ &pwr, sizeof(pwr), NULL, 0);
+
+ kfree(pwrt);
+ kfree(freqt);
+ kfree(coefft);
+
+ return ret;
+}
+EXPORT_SYMBOL(msm_dcvs_scm_set_power_params);
+
int msm_dcvs_scm_event(uint32_t core_id,
enum msm_dcvs_scm_event event_id,
uint32_t param0, uint32_t param1,
@@ -156,6 +226,9 @@
ret = scm_call_atomic4_3(SCM_SVC_DCVS, DCVS_CMD_EVENT,
core_id, event_id, param0, param1, ret0, ret1);
+ trace_msm_dcvs_scm_event(core_id, (int)event_id, param0, param1,
+ *ret0, *ret1);
+
return ret;
}
EXPORT_SYMBOL(msm_dcvs_scm_event);
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 6dde576..c39829b 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -45,7 +45,7 @@
#include "timer.h"
#define DRV_NAME "msm_dsps"
-#define DRV_VERSION "4.02"
+#define DRV_VERSION "4.03"
#define PPSS_TIMER0_32KHZ_REG 0x1004
@@ -771,6 +771,11 @@
{
pr_debug("%s\n", __func__);
disable_irq_nosync(drv->wdog_irq);
+ if (drv->pdata->ppss_wdog_unmasked_int_en_reg) {
+ writel_relaxed(0, (drv->ppss_base+
+ drv->pdata->ppss_wdog_unmasked_int_en_reg));
+ mb(); /* Make sure wdog is disabled before shutting down */
+ }
pil_force_shutdown(drv->pdata->pil_name);
dsps_power_off_handler();
return 0;
@@ -799,6 +804,7 @@
static void dsps_crash_shutdown(const struct subsys_desc *subsys)
{
pr_debug("%s\n", __func__);
+ disable_irq_nosync(drv->wdog_irq);
dsps_crash_shutdown_g = 1;
smsm_change_state(SMSM_DSPS_STATE, SMSM_RESET, SMSM_RESET);
}
diff --git a/arch/arm/mach-msm/msm_mpdecision.c b/arch/arm/mach-msm/msm_mpdecision.c
new file mode 100644
index 0000000..9f6cc11
--- /dev/null
+++ b/arch/arm/mach-msm/msm_mpdecision.c
@@ -0,0 +1,709 @@
+ /* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "mpd %s: " fmt, __func__
+
+#include <linux/cpumask.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/kobject.h>
+#include <linux/ktime.h>
+#include <linux/hrtimer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/cpu.h>
+#include <linux/stringify.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/cpu_pm.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/sched.h>
+#include <linux/rq_stats.h>
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <mach/msm_dcvs.h>
+#include <mach/msm_dcvs_scm.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/mpdcvs_trace.h>
+
+#define DEFAULT_RQ_AVG_POLL_MS (1)
+
+struct mpd_attrib {
+ struct kobj_attribute enabled;
+ struct kobj_attribute rq_avg_poll_ms;
+ struct kobj_attribute iowait_threshold_pct;
+
+ struct kobj_attribute em_win_size_min_us;
+ struct kobj_attribute em_win_size_max_us;
+ struct kobj_attribute em_max_util_pct;
+ struct kobj_attribute mp_em_rounding_point_min;
+ struct kobj_attribute mp_em_rounding_point_max;
+ struct kobj_attribute online_util_pct_min;
+ struct kobj_attribute online_util_pct_max;
+ struct kobj_attribute slack_time_min_us;
+ struct kobj_attribute slack_time_max_us;
+ struct kobj_attribute hp_up_max_ms;
+ struct kobj_attribute hp_up_ms;
+ struct kobj_attribute hp_up_count;
+ struct kobj_attribute hp_dw_max_ms;
+ struct kobj_attribute hp_dw_ms;
+ struct kobj_attribute hp_dw_count;
+ struct attribute_group attrib_group;
+};
+
+struct msm_mpd_scm_data {
+ enum msm_dcvs_scm_event event;
+ int nr;
+};
+
+struct mpdecision {
+ uint32_t enabled;
+ atomic_t algo_cpu_mask;
+ uint32_t rq_avg_poll_ms;
+ uint32_t iowait_threshold_pct;
+ ktime_t next_update;
+ uint32_t slack_us;
+ struct msm_mpd_algo_param mp_param;
+ struct mpd_attrib attrib;
+ struct mutex lock;
+ struct task_struct *task;
+ struct task_struct *hptask;
+ struct hrtimer slack_timer;
+ struct msm_mpd_scm_data data;
+ int hpupdate;
+ wait_queue_head_t wait_q;
+ wait_queue_head_t wait_hpq;
+};
+
+struct hp_latency {
+ int hp_up_max_ms;
+ int hp_up_ms;
+ int hp_up_count;
+ int hp_dw_max_ms;
+ int hp_dw_ms;
+ int hp_dw_count;
+};
+
+static DEFINE_PER_CPU(struct hrtimer, rq_avg_poll_timer);
+static DEFINE_SPINLOCK(rq_avg_lock);
+
+enum {
+ MSM_MPD_DEBUG_NOTIFIER = BIT(0),
+ MSM_MPD_CORE_STATUS = BIT(1),
+ MSM_MPD_SLACK_TIMER = BIT(2),
+};
+
+enum {
+ HPUPDATE_WAITING = 0, /* we are waiting for cpumask update */
+ HPUPDATE_SCHEDULED = 1, /* we are in the process of hotplugging */
+ HPUPDATE_IN_PROGRESS = 2, /* we are in the process of hotplugging */
+};
+
+static int msm_mpd_enabled = 1;
+module_param_named(enabled, msm_mpd_enabled, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static struct dentry *debugfs_base;
+static struct mpdecision msm_mpd;
+
+static struct hp_latency hp_latencies;
+
+static unsigned long last_nr;
+static int num_present_hundreds;
+
+#define RQ_AVG_INSIGNIFICANT_BITS 3
+static bool ok_to_update_tz(int nr, int last_nr)
+{
+ /*
+ * Exclude unnecessary TZ reports if run queue haven't changed much from
+ * the last reported value. The left shift by INSIGNIFICANT_BITS is to
+ * filter out small changes in the run queue average which won't cause
+ * a online cpu mask change. Also if the cpu online count does not match
+ * the count requested by TZ and we are not in the process of bringing
+ * cpus online as indicated by a HPUPDATE_IN_PROGRESS in msm_mpd.hpdata
+ */
+ return
+ (((nr >> RQ_AVG_INSIGNIFICANT_BITS)
+ != (last_nr >> RQ_AVG_INSIGNIFICANT_BITS))
+ || ((hweight32(atomic_read(&msm_mpd.algo_cpu_mask))
+ != num_online_cpus())
+ && (msm_mpd.hpupdate != HPUPDATE_IN_PROGRESS)));
+}
+
+static enum hrtimer_restart msm_mpd_rq_avg_poll_timer(struct hrtimer *timer)
+{
+ int nr, nr_iowait;
+ ktime_t curr_time = ktime_get();
+ unsigned long flags;
+ int cpu = smp_processor_id();
+ enum hrtimer_restart restart = HRTIMER_RESTART;
+
+ spin_lock_irqsave(&rq_avg_lock, flags);
+ /* If running on the wrong cpu, don't restart */
+ if (&per_cpu(rq_avg_poll_timer, cpu) != timer)
+ restart = HRTIMER_NORESTART;
+
+ if (ktime_to_ns(ktime_sub(curr_time, msm_mpd.next_update)) < 0)
+ goto out;
+
+ msm_mpd.next_update = ktime_add_ns(curr_time,
+ (msm_mpd.rq_avg_poll_ms * NSEC_PER_MSEC));
+
+ sched_get_nr_running_avg(&nr, &nr_iowait);
+
+ if ((nr_iowait >= msm_mpd.iowait_threshold_pct) && (nr < last_nr))
+ nr = last_nr;
+
+ if (nr > num_present_hundreds)
+ nr = num_present_hundreds;
+
+ trace_msm_mp_runq("nr_running", nr);
+
+ if (ok_to_update_tz(nr, last_nr)) {
+ hrtimer_try_to_cancel(&msm_mpd.slack_timer);
+ msm_mpd.data.nr = nr;
+ msm_mpd.data.event = MSM_DCVS_SCM_RUNQ_UPDATE;
+ wake_up(&msm_mpd.wait_q);
+ last_nr = nr;
+ }
+
+out:
+ hrtimer_set_expires(timer, msm_mpd.next_update);
+ spin_unlock_irqrestore(&rq_avg_lock, flags);
+ /* set next expiration */
+ return restart;
+}
+
+static void bring_up_cpu(int cpu)
+{
+ int cpu_action_time_ms;
+ int time_taken_ms;
+ int ret, ret1, ret2;
+
+ cpu_action_time_ms = ktime_to_ms(ktime_get());
+ ret = cpu_up(cpu);
+ if (ret) {
+ pr_debug("Error %d online core %d\n", ret, cpu);
+ } else {
+ time_taken_ms = ktime_to_ms(ktime_get()) - cpu_action_time_ms;
+ if (time_taken_ms > hp_latencies.hp_up_max_ms)
+ hp_latencies.hp_up_max_ms = time_taken_ms;
+ hp_latencies.hp_up_ms += time_taken_ms;
+ hp_latencies.hp_up_count++;
+ ret = msm_dcvs_scm_event(
+ CPU_OFFSET + cpu,
+ MSM_DCVS_SCM_CORE_ONLINE,
+ cpufreq_get(cpu),
+ (uint32_t) time_taken_ms * USEC_PER_MSEC,
+ &ret1, &ret2);
+ if (ret)
+ pr_err("Error sending hotplug scm event err=%d\n", ret);
+ }
+}
+
+static void bring_down_cpu(int cpu)
+{
+ int cpu_action_time_ms;
+ int time_taken_ms;
+ int ret, ret1, ret2;
+
+ BUG_ON(cpu == 0);
+ cpu_action_time_ms = ktime_to_ms(ktime_get());
+ ret = cpu_down(cpu);
+ if (ret) {
+ pr_debug("Error %d offline" "core %d\n", ret, cpu);
+ } else {
+ time_taken_ms = ktime_to_ms(ktime_get()) - cpu_action_time_ms;
+ if (time_taken_ms > hp_latencies.hp_dw_max_ms)
+ hp_latencies.hp_dw_max_ms = time_taken_ms;
+ hp_latencies.hp_dw_ms += time_taken_ms;
+ hp_latencies.hp_dw_count++;
+ ret = msm_dcvs_scm_event(
+ CPU_OFFSET + cpu,
+ MSM_DCVS_SCM_CORE_OFFLINE,
+ (uint32_t) time_taken_ms * USEC_PER_MSEC,
+ 0,
+ &ret1, &ret2);
+ if (ret)
+ pr_err("Error sending hotplug scm event err=%d\n", ret);
+ }
+}
+
+static int __ref msm_mpd_update_scm(enum msm_dcvs_scm_event event, int nr)
+{
+ int ret = 0;
+ uint32_t req_cpu_mask = 0;
+ uint32_t slack_us = 0;
+ uint32_t param0 = 0;
+
+ if (event == MSM_DCVS_SCM_RUNQ_UPDATE)
+ param0 = nr;
+
+ ret = msm_dcvs_scm_event(0, event, param0, 0,
+ &req_cpu_mask, &slack_us);
+
+ if (ret) {
+ pr_err("Error (%d) sending event %d, param %d\n", ret, event,
+ param0);
+ return ret;
+ }
+
+ trace_msm_mp_cpusonline("cpu_online_mp", req_cpu_mask);
+ trace_msm_mp_slacktime("slack_time_mp", slack_us);
+ msm_mpd.slack_us = slack_us;
+ atomic_set(&msm_mpd.algo_cpu_mask, req_cpu_mask);
+ msm_mpd.hpupdate = HPUPDATE_SCHEDULED;
+ wake_up(&msm_mpd.wait_hpq);
+
+ /* Start MP Decision slack timer */
+ if (slack_us) {
+ hrtimer_cancel(&msm_mpd.slack_timer);
+ ret = hrtimer_start(&msm_mpd.slack_timer,
+ ktime_set(0, slack_us * NSEC_PER_USEC),
+ HRTIMER_MODE_REL_PINNED);
+ if (ret)
+ pr_err("Failed to register slack timer (%d) %d\n",
+ slack_us, ret);
+ }
+
+ return ret;
+}
+
+static enum hrtimer_restart msm_mpd_slack_timer(struct hrtimer *timer)
+{
+ unsigned long flags;
+
+ trace_printk("mpd:slack_timer_fired!\n");
+
+ spin_lock_irqsave(&rq_avg_lock, flags);
+ if (msm_mpd.data.event == MSM_DCVS_SCM_RUNQ_UPDATE)
+ goto out;
+
+ msm_mpd.data.nr = 0;
+ msm_mpd.data.event = MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED;
+ wake_up(&msm_mpd.wait_q);
+out:
+ spin_unlock_irqrestore(&rq_avg_lock, flags);
+ return HRTIMER_NORESTART;
+}
+
+static int msm_mpd_idle_notifier(struct notifier_block *self,
+ unsigned long cmd, void *v)
+{
+ int cpu = smp_processor_id();
+ unsigned long flags;
+
+ switch (cmd) {
+ case CPU_PM_EXIT:
+ spin_lock_irqsave(&rq_avg_lock, flags);
+ hrtimer_start(&per_cpu(rq_avg_poll_timer, cpu),
+ msm_mpd.next_update,
+ HRTIMER_MODE_ABS_PINNED);
+ spin_unlock_irqrestore(&rq_avg_lock, flags);
+ break;
+ case CPU_PM_ENTER:
+ hrtimer_cancel(&per_cpu(rq_avg_poll_timer, cpu));
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int msm_mpd_hotplug_notifier(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ int cpu = (int)hcpu;
+ unsigned long flags;
+
+ switch (action & (~CPU_TASKS_FROZEN)) {
+ case CPU_STARTING:
+ spin_lock_irqsave(&rq_avg_lock, flags);
+ hrtimer_start(&per_cpu(rq_avg_poll_timer, cpu),
+ msm_mpd.next_update,
+ HRTIMER_MODE_ABS_PINNED);
+ spin_unlock_irqrestore(&rq_avg_lock, flags);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block msm_mpd_idle_nb = {
+ .notifier_call = msm_mpd_idle_notifier,
+};
+
+static struct notifier_block msm_mpd_hotplug_nb = {
+ .notifier_call = msm_mpd_hotplug_notifier,
+};
+
+static int __cpuinit msm_mpd_do_hotplug(void *data)
+{
+ int *event = (int *)data;
+ static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
+ int cpu;
+
+ sched_setscheduler(current, SCHED_FIFO, ¶m);
+
+ while (1) {
+ wait_event(msm_mpd.wait_hpq, *event || kthread_should_stop());
+ if (kthread_should_stop())
+ break;
+
+ msm_mpd.hpupdate = HPUPDATE_IN_PROGRESS;
+ /*
+ * Bring online any offline cores, then offline any online
+ * cores. Whenever a core is off/onlined restart the procedure
+ * in case a new core is desired to be brought online in the
+ * mean time.
+ */
+restart:
+ for_each_possible_cpu(cpu) {
+ if ((atomic_read(&msm_mpd.algo_cpu_mask) & (1 << cpu))
+ && !cpu_online(cpu)) {
+ bring_up_cpu(cpu);
+ if (cpu_online(cpu))
+ goto restart;
+ }
+ }
+
+ for_each_possible_cpu(cpu) {
+ if (!(atomic_read(&msm_mpd.algo_cpu_mask) & (1 << cpu))
+ && cpu_online(cpu)) {
+ bring_down_cpu(cpu);
+ if (!cpu_online(cpu))
+ goto restart;
+ }
+ }
+ msm_mpd.hpupdate = HPUPDATE_WAITING;
+ }
+
+ return 0;
+}
+
+static int msm_mpd_do_update_scm(void *data)
+{
+ struct msm_mpd_scm_data *scm_data = (struct msm_mpd_scm_data *)data;
+ static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
+ unsigned long flags;
+ enum msm_dcvs_scm_event event;
+ int nr;
+
+ sched_setscheduler(current, SCHED_FIFO, ¶m);
+
+ while (1) {
+ wait_event(msm_mpd.wait_q,
+ msm_mpd.data.event == MSM_DCVS_SCM_MPD_QOS_TIMER_EXPIRED
+ || msm_mpd.data.event == MSM_DCVS_SCM_RUNQ_UPDATE
+ || kthread_should_stop());
+
+ if (kthread_should_stop())
+ break;
+
+ spin_lock_irqsave(&rq_avg_lock, flags);
+ event = scm_data->event;
+ nr = scm_data->nr;
+ scm_data->event = 0;
+ scm_data->nr = 0;
+ spin_unlock_irqrestore(&rq_avg_lock, flags);
+
+ msm_mpd_update_scm(event, nr);
+ }
+ return 0;
+}
+
+static int __ref msm_mpd_set_enabled(uint32_t enable)
+{
+ int ret = 0;
+ int ret0 = 0;
+ int ret1 = 0;
+ int cpu;
+ static uint32_t last_enable;
+
+ enable = (enable > 0) ? 1 : 0;
+ if (last_enable == enable)
+ return ret;
+
+ if (enable) {
+ ret = msm_mpd_scm_set_algo_params(&msm_mpd.mp_param);
+ if (ret) {
+ pr_err("Error(%d): msm_mpd_scm_set_algo_params failed\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = msm_dcvs_scm_event(0, MSM_DCVS_SCM_MPD_ENABLE, enable, 0,
+ &ret0, &ret1);
+ if (ret) {
+ pr_err("Error(%d) %s MP Decision\n",
+ ret, (enable ? "enabling" : "disabling"));
+ } else {
+ last_enable = enable;
+ last_nr = 0;
+ }
+ if (enable) {
+ msm_mpd.next_update = ktime_add_ns(ktime_get(),
+ (msm_mpd.rq_avg_poll_ms * NSEC_PER_MSEC));
+ msm_mpd.task = kthread_run(msm_mpd_do_update_scm,
+ &msm_mpd.data, "msm_mpdecision");
+ if (IS_ERR(msm_mpd.task))
+ return -EFAULT;
+
+ msm_mpd.hptask = kthread_run(msm_mpd_do_hotplug,
+ &msm_mpd.hpupdate, "msm_hp");
+ if (IS_ERR(msm_mpd.hptask))
+ return -EFAULT;
+
+ for_each_online_cpu(cpu)
+ hrtimer_start(&per_cpu(rq_avg_poll_timer, cpu),
+ msm_mpd.next_update,
+ HRTIMER_MODE_ABS_PINNED);
+ cpu_pm_register_notifier(&msm_mpd_idle_nb);
+ register_cpu_notifier(&msm_mpd_hotplug_nb);
+ msm_mpd.enabled = 1;
+ } else {
+ for_each_online_cpu(cpu)
+ hrtimer_cancel(&per_cpu(rq_avg_poll_timer, cpu));
+ kthread_stop(msm_mpd.hptask);
+ kthread_stop(msm_mpd.task);
+ cpu_pm_unregister_notifier(&msm_mpd_idle_nb);
+ unregister_cpu_notifier(&msm_mpd_hotplug_nb);
+ msm_mpd.enabled = 0;
+ }
+
+ return ret;
+}
+
+static int msm_mpd_set_rq_avg_poll_ms(uint32_t val)
+{
+ /*
+ * No need to do anything. Just let the timer set its own next poll
+ * interval when it next fires.
+ */
+ msm_mpd.rq_avg_poll_ms = val;
+ return 0;
+}
+
+static int msm_mpd_set_iowait_threshold_pct(uint32_t val)
+{
+ /*
+ * No need to do anything. Just let the timer set its own next poll
+ * interval when it next fires.
+ */
+ msm_mpd.iowait_threshold_pct = val;
+ return 0;
+}
+
+#define MPD_ALGO_PARAM(_name, _param) \
+static ssize_t msm_mpd_attr_##_name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, char *buf) \
+{ \
+ return snprintf(buf, PAGE_SIZE, "%d\n", _param); \
+} \
+static ssize_t msm_mpd_attr_##_name##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, const char *buf, size_t count) \
+{ \
+ int ret = 0; \
+ uint32_t val; \
+ uint32_t old_val; \
+ mutex_lock(&msm_mpd.lock); \
+ ret = kstrtouint(buf, 10, &val); \
+ if (ret) { \
+ pr_err("Invalid input %s for %s %d\n", \
+ buf, __stringify(_name), ret);\
+ return 0; \
+ } \
+ old_val = _param; \
+ _param = val; \
+ ret = msm_mpd_scm_set_algo_params(&msm_mpd.mp_param); \
+ if (ret) { \
+ pr_err("Error %d returned when setting algo param %s to %d\n",\
+ ret, __stringify(_name), val); \
+ _param = old_val; \
+ } \
+ mutex_unlock(&msm_mpd.lock); \
+ return count; \
+}
+
+#define MPD_PARAM(_name, _param) \
+static ssize_t msm_mpd_attr_##_name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, char *buf) \
+{ \
+ return snprintf(buf, PAGE_SIZE, "%d\n", _param); \
+} \
+static ssize_t msm_mpd_attr_##_name##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, const char *buf, size_t count) \
+{ \
+ int ret = 0; \
+ uint32_t val; \
+ uint32_t old_val; \
+ mutex_lock(&msm_mpd.lock); \
+ ret = kstrtouint(buf, 10, &val); \
+ if (ret) { \
+ pr_err("Invalid input %s for %s %d\n", \
+ buf, __stringify(_name), ret);\
+ return 0; \
+ } \
+ old_val = _param; \
+ ret = msm_mpd_set_##_name(val); \
+ if (ret) { \
+ pr_err("Error %d returned when setting algo param %s to %d\n",\
+ ret, __stringify(_name), val); \
+ _param = old_val; \
+ } \
+ mutex_unlock(&msm_mpd.lock); \
+ return count; \
+}
+
+#define MPD_RW_ATTRIB(i, _name) \
+ msm_mpd.attrib._name.attr.name = __stringify(_name); \
+ msm_mpd.attrib._name.attr.mode = S_IRUGO | S_IWUSR; \
+ msm_mpd.attrib._name.show = msm_mpd_attr_##_name##_show; \
+ msm_mpd.attrib._name.store = msm_mpd_attr_##_name##_store; \
+ msm_mpd.attrib.attrib_group.attrs[i] = &msm_mpd.attrib._name.attr;
+
+MPD_PARAM(enabled, msm_mpd.enabled);
+MPD_PARAM(rq_avg_poll_ms, msm_mpd.rq_avg_poll_ms);
+MPD_PARAM(iowait_threshold_pct, msm_mpd.iowait_threshold_pct);
+MPD_ALGO_PARAM(em_win_size_min_us, msm_mpd.mp_param.em_win_size_min_us);
+MPD_ALGO_PARAM(em_win_size_max_us, msm_mpd.mp_param.em_win_size_max_us);
+MPD_ALGO_PARAM(em_max_util_pct, msm_mpd.mp_param.em_max_util_pct);
+MPD_ALGO_PARAM(mp_em_rounding_point_min,
+ msm_mpd.mp_param.mp_em_rounding_point_min);
+MPD_ALGO_PARAM(mp_em_rounding_point_max,
+ msm_mpd.mp_param.mp_em_rounding_point_max);
+MPD_ALGO_PARAM(online_util_pct_min, msm_mpd.mp_param.online_util_pct_min);
+MPD_ALGO_PARAM(online_util_pct_max, msm_mpd.mp_param.online_util_pct_max);
+MPD_ALGO_PARAM(slack_time_min_us, msm_mpd.mp_param.slack_time_min_us);
+MPD_ALGO_PARAM(slack_time_max_us, msm_mpd.mp_param.slack_time_max_us);
+MPD_ALGO_PARAM(hp_up_max_ms, hp_latencies.hp_up_max_ms);
+MPD_ALGO_PARAM(hp_up_ms, hp_latencies.hp_up_ms);
+MPD_ALGO_PARAM(hp_up_count, hp_latencies.hp_up_count);
+MPD_ALGO_PARAM(hp_dw_max_ms, hp_latencies.hp_dw_max_ms);
+MPD_ALGO_PARAM(hp_dw_ms, hp_latencies.hp_dw_ms);
+MPD_ALGO_PARAM(hp_dw_count, hp_latencies.hp_dw_count);
+
+static int __devinit msm_mpd_probe(struct platform_device *pdev)
+{
+ struct kobject *module_kobj = NULL;
+ int ret = 0;
+ const int attr_count = 19;
+ struct msm_mpd_algo_param *param = NULL;
+
+ param = pdev->dev.platform_data;
+
+ module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+ if (!module_kobj) {
+ pr_err("Cannot find kobject for module %s\n", KBUILD_MODNAME);
+ ret = -ENOENT;
+ goto done;
+ }
+
+ msm_mpd.attrib.attrib_group.attrs =
+ kzalloc(attr_count * sizeof(struct attribute *), GFP_KERNEL);
+ if (!msm_mpd.attrib.attrib_group.attrs) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ MPD_RW_ATTRIB(0, enabled);
+ MPD_RW_ATTRIB(1, rq_avg_poll_ms);
+ MPD_RW_ATTRIB(2, iowait_threshold_pct);
+ MPD_RW_ATTRIB(3, em_win_size_min_us);
+ MPD_RW_ATTRIB(4, em_win_size_max_us);
+ MPD_RW_ATTRIB(5, em_max_util_pct);
+ MPD_RW_ATTRIB(6, mp_em_rounding_point_min);
+ MPD_RW_ATTRIB(7, mp_em_rounding_point_max);
+ MPD_RW_ATTRIB(8, online_util_pct_min);
+ MPD_RW_ATTRIB(9, online_util_pct_max);
+ MPD_RW_ATTRIB(10, slack_time_min_us);
+ MPD_RW_ATTRIB(11, slack_time_max_us);
+ MPD_RW_ATTRIB(12, hp_up_max_ms);
+ MPD_RW_ATTRIB(13, hp_up_ms);
+ MPD_RW_ATTRIB(14, hp_up_count);
+ MPD_RW_ATTRIB(15, hp_dw_max_ms);
+ MPD_RW_ATTRIB(16, hp_dw_ms);
+ MPD_RW_ATTRIB(17, hp_dw_count);
+
+ msm_mpd.attrib.attrib_group.attrs[18] = NULL;
+ ret = sysfs_create_group(module_kobj, &msm_mpd.attrib.attrib_group);
+ if (ret)
+ pr_err("Unable to create sysfs objects :%d\n", ret);
+
+ msm_mpd.rq_avg_poll_ms = DEFAULT_RQ_AVG_POLL_MS;
+
+ memcpy(&msm_mpd.mp_param, param, sizeof(struct msm_mpd_algo_param));
+
+ debugfs_base = debugfs_create_dir("msm_mpdecision", NULL);
+ if (!debugfs_base) {
+ pr_err("Cannot create debugfs base msm_mpdecision\n");
+ ret = -ENOENT;
+ goto done;
+ }
+
+done:
+ if (ret && debugfs_base)
+ debugfs_remove(debugfs_base);
+
+ return ret;
+}
+
+static int __devexit msm_mpd_remove(struct platform_device *pdev)
+{
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver msm_mpd_driver = {
+ .probe = msm_mpd_probe,
+ .remove = __devexit_p(msm_mpd_remove),
+ .driver = {
+ .name = "msm_mpdecision",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_mpdecision_init(void)
+{
+ int cpu;
+ if (!msm_mpd_enabled) {
+ pr_info("Not enabled\n");
+ return 0;
+ }
+
+ num_present_hundreds = 100 * num_present_cpus();
+
+ hrtimer_init(&msm_mpd.slack_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL_PINNED);
+ msm_mpd.slack_timer.function = msm_mpd_slack_timer;
+
+ for_each_possible_cpu(cpu) {
+ hrtimer_init(&per_cpu(rq_avg_poll_timer, cpu),
+ CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
+ per_cpu(rq_avg_poll_timer, cpu).function
+ = msm_mpd_rq_avg_poll_timer;
+ }
+ mutex_init(&msm_mpd.lock);
+ init_waitqueue_head(&msm_mpd.wait_q);
+ init_waitqueue_head(&msm_mpd.wait_hpq);
+ return platform_driver_register(&msm_mpd_driver);
+}
+late_initcall(msm_mpdecision_init);
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 2d61504..404b350 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -236,7 +236,7 @@
int needs_workaround = cpu_is_msm8960() || cpu_is_apq8064() ||
cpu_is_msm8930() || cpu_is_msm8930aa() ||
cpu_is_msm9615() || cpu_is_msm8627() ||
- cpu_is_msm8960ab();
+ cpu_is_msm8960ab() || cpu_is_apq8064ab();
if (xo_voter->mode == mode)
return 0;
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 5a85eec..9a85a17 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -856,7 +856,7 @@
/* Interfaces invoked from the scheduler */
int ocmem_memory_off(int id, unsigned long offset, unsigned long len)
{
- return switch_power_state(id, offset, len, REGION_DEFAULT_OFF);
+ return switch_power_state(id, offset, len, REGION_DEFAULT_ON);
}
int ocmem_memory_on(int id, unsigned long offset, unsigned long len)
@@ -866,7 +866,7 @@
int ocmem_memory_retain(int id, unsigned long offset, unsigned long len)
{
- return switch_power_state(id, offset, len, REGION_DEFAULT_RETENTION);
+ return switch_power_state(id, offset, len, REGION_DEFAULT_ON);
}
static int ocmem_power_show_sw_state(struct seq_file *f, void *dummy)
diff --git a/arch/arm/mach-msm/peripheral-loader.h b/arch/arm/mach-msm/peripheral-loader.h
index e3b250b..405b73f 100644
--- a/arch/arm/mach-msm/peripheral-loader.h
+++ b/arch/arm/mach-msm/peripheral-loader.h
@@ -55,7 +55,15 @@
struct pil_device;
+#ifdef CONFIG_MSM_PIL
extern struct pil_device *msm_pil_register(struct pil_desc *desc);
extern void msm_pil_unregister(struct pil_device *pil);
+#else
+static inline struct pil_device *msm_pil_register(struct pil_desc *desc)
+{
+ return NULL;
+}
+static inline void msm_pil_unregister(struct pil_device *pil) { }
+#endif
#endif
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 73248db..bccbce2 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -21,15 +21,22 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/smp.h>
+#include <linux/miscdevice.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
#include <mach/msm_iomap.h>
#include <mach/msm_xo.h>
#include <mach/socinfo.h>
#include <mach/msm_bus_board.h>
#include <mach/msm_bus.h>
+#include <mach/subsystem_restart.h>
+#include <mach/peripheral-loader.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
+#include "smd_private.h"
+#include "ramdump.h"
#define GSS_CSR_AHB_CLK_SEL 0x0
#define GSS_CSR_RESET 0x4
@@ -63,6 +70,14 @@
unsigned long start_addr;
struct clk *xo;
struct pil_device *pil;
+ struct miscdevice misc_dev;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ int crash_shutdown;
+ int irq;
+ void *pil_handle;
+ struct ramdump_device *ramdump_dev;
+ struct ramdump_device *smem_ramdump_dev;
};
static int pil_gss_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -308,11 +323,160 @@
.proxy_unvote = remove_gss_proxy_votes,
};
+#define MAX_SSR_REASON_LEN 81U
+
+static void log_gss_sfr(void)
+{
+ u32 size;
+ char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+ smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+ if (!smem_reason || !size) {
+ pr_err("GSS subsystem failure reason: (unknown, smem_get_entry failed).\n");
+ return;
+ }
+ if (!smem_reason[0]) {
+ pr_err("GSS subsystem failure reason: (unknown, init string found).\n");
+ return;
+ }
+
+ size = min(size, MAX_SSR_REASON_LEN-1);
+ memcpy(reason, smem_reason, size);
+ reason[size] = '\0';
+ pr_err("GSS subsystem failure reason: %s.\n", reason);
+
+ smem_reason[0] = '\0';
+ wmb();
+}
+
+static void restart_gss(struct gss_data *drv)
+{
+ log_gss_sfr();
+ subsystem_restart_dev(drv->subsys);
+}
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+ struct gss_data *drv = data;
+
+ /* Ignore if we're the one that set SMSM_RESET */
+ if (drv->crash_shutdown)
+ return;
+
+ if (new_state & SMSM_RESET) {
+ pr_err("GSS SMSM state changed to SMSM_RESET.\n"
+ "Probable err_fatal on the GSS. "
+ "Calling subsystem restart...\n");
+ restart_gss(drv);
+ }
+}
+
+static int gss_shutdown(const struct subsys_desc *desc)
+{
+ struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+ pil_force_shutdown("gss");
+ disable_irq_nosync(drv->irq);
+
+ return 0;
+}
+
+static int gss_powerup(const struct subsys_desc *desc)
+{
+ struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+ pil_force_boot("gss");
+ enable_irq(drv->irq);
+ return 0;
+}
+
+void gss_crash_shutdown(const struct subsys_desc *desc)
+{
+ struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+ drv->crash_shutdown = 1;
+ smsm_reset_modem(SMSM_RESET);
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment gss_segments[] = {
+ {0x89000000, 0x00D00000}
+};
+
+static struct ramdump_segment smem_segments[] = {
+ {0x80000000, 0x00200000},
+};
+
+static int gss_ramdump(int enable, const struct subsys_desc *desc)
+{
+ int ret;
+ struct gss_data *drv = container_of(desc, struct gss_data, subsys_desc);
+
+ if (enable) {
+ ret = do_ramdump(drv->ramdump_dev, gss_segments,
+ ARRAY_SIZE(gss_segments));
+ if (ret < 0) {
+ pr_err("Unable to dump gss memory\n");
+ return ret;
+ }
+
+ ret = do_ramdump(drv->smem_ramdump_dev, smem_segments,
+ ARRAY_SIZE(smem_segments));
+ if (ret < 0) {
+ pr_err("Unable to dump smem memory (rc = %d).\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct gss_data *drv = dev_id;
+
+ pr_err("Watchdog bite received from GSS!\n");
+ restart_gss(drv);
+
+ return IRQ_HANDLED;
+}
+
+static int gss_open(struct inode *inode, struct file *filp)
+{
+ void *ret;
+ struct miscdevice *c = filp->private_data;
+ struct gss_data *drv = container_of(c, struct gss_data, misc_dev);
+
+ drv->pil_handle = ret = pil_get("gss");
+ if (!ret)
+ pr_debug("%s - pil_get returned NULL\n", __func__);
+
+ return 0;
+}
+
+static int gss_release(struct inode *inode, struct file *filp)
+{
+ struct miscdevice *c = filp->private_data;
+ struct gss_data *drv = container_of(c, struct gss_data, misc_dev);
+
+ pil_put(drv->pil_handle);
+ pr_debug("%s pil_put called on GSS\n", __func__);
+
+ return 0;
+}
+
+const struct file_operations gss_file_ops = {
+ .open = gss_open,
+ .release = gss_release,
+ .owner = THIS_MODULE,
+};
+
static int __devinit pil_gss_probe(struct platform_device *pdev)
{
struct gss_data *drv;
struct resource *res;
struct pil_desc *desc;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -344,6 +508,10 @@
if (IS_ERR(drv->xo))
return PTR_ERR(drv->xo);
+ drv->irq = platform_get_irq(pdev, 0);
+ if (drv->irq < 0)
+ return drv->irq;
+
desc->name = "gss";
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
@@ -363,13 +531,71 @@
if (IS_ERR(drv->pil)) {
return PTR_ERR(drv->pil);
}
+
+ ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+ smsm_state_cb, drv);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "Unable to register SMSM callback\n");
+
+ drv->subsys_desc.name = "gss";
+ drv->subsys_desc.shutdown = gss_shutdown;
+ drv->subsys_desc.powerup = gss_powerup;
+ drv->subsys_desc.ramdump = gss_ramdump;
+ drv->subsys_desc.crash_shutdown = gss_crash_shutdown;
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ drv->misc_dev.minor = MISC_DYNAMIC_MINOR;
+ drv->misc_dev.name = "gss";
+ drv->misc_dev.fops = &gss_file_ops;
+ ret = misc_register(&drv->misc_dev);
+ if (ret)
+ goto err_misc;
+
+ drv->ramdump_dev = create_ramdump_device("gss");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ drv->smem_ramdump_dev = create_ramdump_device("smem-gss");
+ if (!drv->smem_ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_smem;
+ }
+
+ ret = devm_request_irq(&pdev->dev, drv->irq, gss_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, "gss_a5_wdog", drv);
+ if (ret < 0)
+ goto err;
return 0;
+err:
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+err_smem:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ misc_deregister(&drv->misc_dev);
+err_misc:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_gss_remove(struct platform_device *pdev)
{
struct gss_data *drv = platform_get_drvdata(pdev);
+
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+ destroy_ramdump_device(drv->ramdump_dev);
+ misc_deregister(&drv->misc_dev);
+ subsys_unregister(drv->subsys);
msm_pil_unregister(drv->pil);
+
return 0;
}
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
index 5e67d4f..0207f0b 100644
--- a/arch/arm/mach-msm/pil-mba.c
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -172,7 +172,7 @@
return -ENOMEM;
platform_set_drvdata(pdev, drv);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb_base");
if (!res)
return -EINVAL;
drv->reg_base = devm_ioremap(&pdev->dev, res->start,
@@ -180,7 +180,8 @@
if (!drv->reg_base)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "metadata_base");
if (res) {
drv->metadata_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index 8344496..ecb3800 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -19,11 +19,19 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
#include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+#include <mach/peripheral-loader.h>
+#include "modem_notifier.h"
#include "peripheral-loader.h"
#include "scm-pas.h"
+#include "ramdump.h"
#define MARM_BOOT_CONTROL 0x0010
#define MARM_RESET (MSM_CLK_CTL_BASE + 0x2BD4)
@@ -46,12 +54,22 @@
#define PLL_ENA_MARM (MSM_CLK_CTL_BASE + 0x3500)
#define PLL8_STATUS (MSM_CLK_CTL_BASE + 0x3158)
#define CLK_HALT_MSS_SMPSS_MISC_STATE (MSM_CLK_CTL_BASE + 0x2FDC)
+#define MSS_MODEM_RESET (MSM_CLK_CTL_BASE + 0x2C48)
struct modem_data {
void __iomem *base;
+ void __iomem *wdog;
unsigned long start_addr;
struct pil_device *pil;
struct clk *xo;
+ struct notifier_block notifier;
+ int ignore_smsm_ack;
+ int irq;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ struct delayed_work unlock_work;
+ struct work_struct fatal_work;
+ struct ramdump_device *ramdump_dev;
};
static int make_modem_proxy_votes(struct pil_desc *pil)
@@ -161,7 +179,7 @@
return 0;
}
-static int modem_shutdown(struct pil_desc *pil)
+static int modem_pil_shutdown(struct pil_desc *pil)
{
u32 reg;
@@ -203,7 +221,7 @@
static struct pil_reset_ops pil_modem_ops = {
.init_image = modem_init_image,
.auth_and_reset = modem_reset,
- .shutdown = modem_shutdown,
+ .shutdown = modem_pil_shutdown,
.proxy_vote = make_modem_proxy_votes,
.proxy_unvote = remove_modem_proxy_votes,
};
@@ -232,11 +250,166 @@
.proxy_unvote = remove_modem_proxy_votes,
};
+static void modem_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct modem_data *drv;
+
+ /* If modem hasn't already crashed, send SMSM_RESET. */
+ drv = container_of(subsys, struct modem_data, subsys_desc);
+ if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
+ modem_unregister_notifier(&drv->notifier);
+ smsm_reset_modem(SMSM_RESET);
+ }
+
+ /* Wait to allow the modem to clean up caches etc. */
+ mdelay(5);
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct modem_data *drv = dev_id;
+
+ schedule_work(&drv->fatal_work);
+ disable_irq_nosync(drv->irq);
+
+ return IRQ_HANDLED;
+}
+
+static void modem_unlock_timeout(struct work_struct *work)
+{
+ struct modem_data *drv;
+ struct delayed_work *dwork = to_delayed_work(work);
+
+ pr_crit("Timeout waiting for modem to unlock.\n");
+
+ drv = container_of(dwork, struct modem_data, unlock_work);
+ /* The unlock didn't work, clear the reset */
+ writel_relaxed(0x0, MSS_MODEM_RESET);
+ mb();
+
+ subsystem_restart_dev(drv->subsys);
+ enable_irq(drv->irq);
+}
+
+static void modem_fatal_fn(struct work_struct *work)
+{
+ u32 modem_state;
+ u32 panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
+ u32 reset_smsm_states = SMSM_SYSTEM_REBOOT_USR | SMSM_SYSTEM_PWRDWN_USR;
+ struct modem_data *drv;
+
+ drv = container_of(work, struct modem_data, fatal_work);
+
+ pr_err("Watchdog bite received from modem!\n");
+
+ modem_state = smsm_get_state(SMSM_MODEM_STATE);
+ pr_err("Modem SMSM state = 0x%x!\n", modem_state);
+
+ if (modem_state == 0 || modem_state & panic_smsm_states) {
+ subsystem_restart_dev(drv->subsys);
+ enable_irq(drv->irq);
+ } else if (modem_state & reset_smsm_states) {
+ pr_err("User-invoked system reset/powerdown.");
+ kernel_restart(NULL);
+ } else {
+ unsigned long timeout = msecs_to_jiffies(6000);
+
+ pr_err("Modem AHB locked up. Trying to free up modem!\n");
+
+ writel_relaxed(0x3, MSS_MODEM_RESET);
+ /*
+ * If we are still alive (allowing for the 5 second
+ * delayed-panic-reboot), the modem is either still wedged or
+ * SMSM didn't come through. Force panic in that case.
+ */
+ schedule_delayed_work(&drv->unlock_work, timeout);
+ }
+}
+
+static int modem_notif_handler(struct notifier_block *nb, unsigned long code,
+ void *p)
+{
+ struct modem_data *drv = container_of(nb, struct modem_data, notifier);
+
+ if (code == MODEM_NOTIFIER_START_RESET) {
+ if (drv->ignore_smsm_ack) {
+ drv->ignore_smsm_ack = 0;
+ } else {
+ pr_err("Modem error fatal'ed.");
+ subsystem_restart_dev(drv->subsys);
+ }
+ }
+ return NOTIFY_DONE;
+}
+
+static int modem_shutdown(const struct subsys_desc *subsys)
+{
+ struct modem_data *drv;
+
+ drv = container_of(subsys, struct modem_data, subsys_desc);
+ /*
+ * If the modem didn't already crash, setting SMSM_RESET here will help
+ * flush caches etc. The ignore_smsm_ack flag is set to ignore the
+ * SMSM_RESET notification that is generated due to the modem settings
+ * its own SMSM_RESET bit in response to the apps setting the apps
+ * SMSM_RESET bit.
+ */
+ if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
+ drv->ignore_smsm_ack = 1;
+ smsm_reset_modem(SMSM_RESET);
+ }
+
+ /* Disable the modem watchdog to allow clean modem bootup */
+ writel_relaxed(0x0, drv->wdog + 0x8);
+ /*
+ * The write above needs to go through before the modem is powered up
+ * again.
+ */
+ mb();
+ /* Wait here to allow the modem to clean up caches, etc. */
+ msleep(20);
+
+ pil_force_shutdown("modem");
+ disable_irq_nosync(drv->irq);
+
+ return 0;
+}
+
+static int modem_powerup(const struct subsys_desc *subsys)
+{
+ struct modem_data *drv;
+ int ret;
+
+ drv = container_of(subsys, struct modem_data, subsys_desc);
+ ret = pil_force_boot("modem");
+ enable_irq(drv->irq);
+
+ return ret;
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment modem_segments[] = {
+ { 0x42F00000, 0x46000000 - 0x42F00000 },
+};
+
+static int modem_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct modem_data *drv;
+
+ drv = container_of(subsys, struct modem_data, subsys_desc);
+ if (enable)
+ return do_ramdump(drv->ramdump_dev, modem_segments,
+ ARRAY_SIZE(modem_segments));
+ else
+ return 0;
+}
+
static int __devinit pil_modem_driver_probe(struct platform_device *pdev)
{
struct modem_data *drv;
struct resource *res;
struct pil_desc *desc;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -247,6 +420,10 @@
return -ENOMEM;
platform_set_drvdata(pdev, drv);
+ drv->irq = platform_get_irq(pdev, 0);
+ if (drv->irq < 0)
+ return drv->irq;
+
drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!drv->base)
return -ENOMEM;
@@ -259,6 +436,14 @@
if (!desc)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return -EINVAL;
+
+ drv->wdog = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->wdog)
+ return -ENOMEM;
+
desc->name = "modem";
desc->depends_on = "q6";
desc->dev = &pdev->dev;
@@ -273,16 +458,61 @@
dev_info(&pdev->dev, "using non-secure boot\n");
}
drv->pil = msm_pil_register(desc);
- if (IS_ERR(drv->pil)) {
+ if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
+
+ drv->notifier.notifier_call = modem_notif_handler,
+ ret = modem_register_notifier(&drv->notifier);
+ if (ret)
+ goto err_notify;
+
+ drv->subsys_desc.name = "modem";
+ drv->subsys_desc.shutdown = modem_shutdown;
+ drv->subsys_desc.powerup = modem_powerup;
+ drv->subsys_desc.ramdump = modem_ramdump;
+ drv->subsys_desc.crash_shutdown = modem_crash_shutdown;
+
+ INIT_WORK(&drv->fatal_work, modem_fatal_fn);
+ INIT_DELAYED_WORK(&drv->unlock_work, modem_unlock_timeout);
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
}
+
+ drv->ramdump_dev = create_ramdump_device("modem");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ ret = devm_request_irq(&pdev->dev, drv->irq, modem_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, "modem_watchdog", drv);
+ if (ret)
+ goto err_irq;
return 0;
+
+err_irq:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ modem_unregister_notifier(&drv->notifier);
+err_notify:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_modem_driver_exit(struct platform_device *pdev)
{
struct modem_data *drv = platform_get_drvdata(pdev);
+
+ destroy_ramdump_device(drv->ramdump_dev);
+ subsys_unregister(drv->subsys);
+ modem_unregister_notifier(&drv->notifier);
msm_pil_unregister(drv->pil);
+
return 0;
}
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index 01cdb0b..1e39043 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -233,7 +233,7 @@
int ret;
uint32_t regval;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu_base");
if (!res)
return -EINVAL;
@@ -246,14 +246,14 @@
if (!drv->base)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
if (!res)
return -EINVAL;
drv->reset_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
- res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
if (!res)
return -EINVAL;
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index 28b9dee..1a226de 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -19,9 +19,15 @@
#include <linux/elf.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
#include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include "ramdump.h"
#include "peripheral-loader.h"
#include "scm-pas.h"
@@ -60,11 +66,34 @@
#define Q6_STRAP_TCM_BASE (0x28C << 15)
#define Q6_STRAP_TCM_CONFIG 0x28B
+#define SCM_Q6_NMI_CMD 0x1
+
+/**
+ * struct q6v3_data - LPASS driver data
+ * @base: register base
+ * @wk_base: wakeup register base
+ * @wd_base: watchdog register base
+ * @start_addr: address that processor starts running at
+ * @irq: watchdog irq
+ * @pil: peripheral handle
+ * @subsys: subsystem restart handle
+ * @subsys_desc: subsystem restart descriptor
+ * @fatal_wrk: fatal error workqueue
+ * @pll: pll clock handle
+ * @ramdump_dev: ramdump device
+ */
struct q6v3_data {
void __iomem *base;
+ void __iomem *wk_base;
+ void __iomem *wd_base;
unsigned long start_addr;
+ int irq;
struct pil_device *pil;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ struct work_struct fatal_wrk;
struct clk *pll;
+ struct ramdump_device *ramdump_dev;
};
static int pil_q6v3_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -198,11 +227,96 @@
.proxy_unvote = pil_q6v3_remove_proxy_votes,
};
+static void q6_fatal_fn(struct work_struct *work)
+{
+ struct q6v3_data *drv = container_of(work, struct q6v3_data, fatal_wrk);
+
+ pr_err("Watchdog bite received from Q6!\n");
+ subsystem_restart_dev(drv->subsys);
+ enable_irq(drv->irq);
+}
+
+static void send_q6_nmi(struct q6v3_data *drv)
+{
+ /* Send NMI to QDSP6 via an SCM call. */
+ scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
+
+ /* Wakeup the Q6 */
+ writel_relaxed(0x2000, drv->wk_base + 0x1c);
+ /* Q6 requires atleast 100ms to dump caches etc.*/
+ mdelay(100);
+ pr_info("Q6 NMI was sent.\n");
+}
+
+static int lpass_q6_shutdown(const struct subsys_desc *subsys)
+{
+ struct q6v3_data *drv;
+
+ drv = container_of(subsys, struct q6v3_data, subsys_desc);
+ send_q6_nmi(drv);
+ writel_relaxed(0x0, drv->wd_base + 0x24);
+ mb();
+
+ pil_force_shutdown("q6");
+ disable_irq_nosync(drv->irq);
+
+ return 0;
+}
+
+static int lpass_q6_powerup(const struct subsys_desc *subsys)
+{
+ struct q6v3_data *drv;
+ int ret;
+
+ drv = container_of(subsys, struct q6v3_data, subsys_desc);
+ ret = pil_force_boot("q6");
+ enable_irq(drv->irq);
+ return ret;
+}
+
+/* FIXME: Get address, size from PIL */
+static struct ramdump_segment q6_segments[] = {
+ { 0x46700000, 0x47f00000 - 0x46700000 },
+ { 0x28400000, 0x12800 }
+};
+
+static int lpass_q6_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct q6v3_data *drv;
+
+ drv = container_of(subsys, struct q6v3_data, subsys_desc);
+ if (enable)
+ return do_ramdump(drv->ramdump_dev, q6_segments,
+ ARRAY_SIZE(q6_segments));
+ else
+ return 0;
+}
+
+static void lpass_q6_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct q6v3_data *drv;
+
+ drv = container_of(subsys, struct q6v3_data, subsys_desc);
+ send_q6_nmi(drv);
+}
+
+static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
+{
+ int ret;
+ struct q6v3_data *drv = dev_id;
+
+ ret = schedule_work(&drv->fatal_wrk);
+ disable_irq_nosync(drv->irq);
+
+ return IRQ_HANDLED;
+}
+
static int __devinit pil_q6v3_driver_probe(struct platform_device *pdev)
{
struct q6v3_data *drv;
struct resource *res;
struct pil_desc *desc;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -217,14 +331,34 @@
if (!drv->base)
return -ENOMEM;
- desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!drv)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return -EINVAL;
+
+ drv->wk_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->wk_base)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (!res)
+ return -EINVAL;
+
+ drv->wd_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->wd_base)
+ return -ENOMEM;
+
+ drv->irq = platform_get_irq(pdev, 0);
+ if (drv->irq < 0)
+ return drv->irq;
+
drv->pll = devm_clk_get(&pdev->dev, "pll4");
if (IS_ERR(drv->pll))
return PTR_ERR(drv->pll);
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
desc->name = "q6";
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
@@ -239,15 +373,51 @@
}
drv->pil = msm_pil_register(desc);
- if (IS_ERR(drv->pil)) {
+ if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
+
+ drv->subsys_desc.name = "lpass";
+ drv->subsys_desc.shutdown = lpass_q6_shutdown;
+ drv->subsys_desc.powerup = lpass_q6_powerup;
+ drv->subsys_desc.ramdump = lpass_q6_ramdump;
+ drv->subsys_desc.crash_shutdown = lpass_q6_crash_shutdown;
+
+ INIT_WORK(&drv->fatal_wrk, q6_fatal_fn);
+
+ drv->ramdump_dev = create_ramdump_device("lpass");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
}
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ ret = devm_request_irq(&pdev->dev, drv->irq, lpass_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, "lpass_wdog", drv);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to request wdog irq.\n");
+ goto err_irq;
+ }
+
return 0;
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_q6v3_driver_exit(struct platform_device *pdev)
{
struct q6v3_data *drv = platform_get_drvdata(pdev);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->ramdump_dev);
msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
new file mode 100644
index 0000000..a0432550
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.c
@@ -0,0 +1,402 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+
+#include "smd_private.h"
+#include "ramdump.h"
+#include "sysmon.h"
+#include "peripheral-loader.h"
+#include "pil-q6v4.h"
+#include "scm-pas.h"
+
+struct lpass_q6v4 {
+ struct q6v4_data q6;
+ void *riva_notif_hdle;
+ void *modem_notif_hdle;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ int crash_shutdown;
+ void *ramdump_dev;
+ struct work_struct work;
+ int loadable;
+};
+
+static int pil_q6v4_lpass_boot(struct pil_desc *pil)
+{
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
+ int err;
+
+ err = pil_q6v4_power_up(drv);
+ if (err)
+ return err;
+
+ return pil_q6v4_boot(pil);
+}
+
+static int pil_q6v4_lpass_shutdown(struct pil_desc *pil)
+{
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
+ int ret;
+
+ ret = pil_q6v4_shutdown(pil);
+ if (ret)
+ return ret;
+ pil_q6v4_power_down(drv);
+ return 0;
+}
+
+static struct pil_reset_ops pil_q6v4_lpass_ops = {
+ .init_image = pil_q6v4_init_image,
+ .auth_and_reset = pil_q6v4_lpass_boot,
+ .shutdown = pil_q6v4_lpass_shutdown,
+ .proxy_vote = pil_q6v4_make_proxy_votes,
+ .proxy_unvote = pil_q6v4_remove_proxy_votes,
+};
+
+static struct pil_reset_ops pil_q6v4_lpass_ops_trusted = {
+ .init_image = pil_q6v4_init_image_trusted,
+ .auth_and_reset = pil_q6v4_boot_trusted,
+ .shutdown = pil_q6v4_shutdown_trusted,
+ .proxy_vote = pil_q6v4_make_proxy_votes,
+ .proxy_unvote = pil_q6v4_remove_proxy_votes,
+};
+
+static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ int ret;
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("%s: R-Notify: Shutdown started\n", __func__);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
+ SUBSYS_BEFORE_SHUTDOWN);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__, ret);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block rnb = {
+ .notifier_call = riva_notifier_cb,
+};
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *ss_handle)
+{
+ int ret;
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ pr_debug("%s: M-Notify: Shutdown started\n", __func__);
+ ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
+ SUBSYS_BEFORE_SHUTDOWN);
+ if (ret < 0)
+ pr_err("%s: sysmon_send_event error %d", __func__, ret);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block mnb = {
+ .notifier_call = modem_notifier_cb,
+};
+
+static void lpass_log_failure_reason(void)
+{
+ char *reason;
+ char buffer[81];
+ unsigned size;
+
+ reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+ if (!reason) {
+ pr_err("LPASS subsystem failure reason: (unknown, smem_get_entry failed).");
+ return;
+ }
+
+ if (reason[0] == '\0') {
+ pr_err("LPASS subsystem failure reason: (unknown, init value found)");
+ return;
+ }
+
+ size = min(size, sizeof(buffer) - 1);
+ memcpy(buffer, reason, size);
+ buffer[size] = '\0';
+ pr_err("LPASS subsystem failure reason: %s", buffer);
+ memset((void *)reason, 0x0, size);
+ wmb();
+}
+
+static void lpass_fatal_fn(struct work_struct *work)
+{
+ pr_err("Watchdog bite received from lpass Q6!\n");
+ lpass_log_failure_reason();
+ panic("Q6 Resetting the SoC");
+}
+
+static void lpass_smsm_state_cb(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ struct lpass_q6v4 *drv = data;
+
+ /* Ignore if we're the one that set SMSM_RESET */
+ if (drv->crash_shutdown)
+ return;
+
+ if (new_state & SMSM_RESET) {
+ pr_err("%s: LPASS SMSM state changed to SMSM_RESET, new_state = %#x, old_state = %#x\n",
+ __func__, new_state, old_state);
+ lpass_log_failure_reason();
+ panic("Q6 Resetting the SoC");
+ }
+}
+
+#define SCM_Q6_NMI_CMD 0x1
+
+static void send_q6_nmi(void)
+{
+ /* Send NMI to QDSP6 via an SCM call. */
+ uint32_t cmd = 0x1;
+
+ scm_call(SCM_SVC_UTIL, SCM_Q6_NMI_CMD,
+ &cmd, sizeof(cmd), NULL, 0);
+
+ /* Q6 requires worstcase 100ms to dump caches etc.*/
+ mdelay(100);
+ pr_debug("%s: Q6 NMI was sent.\n", __func__);
+}
+
+#define subsys_to_lpass(d) container_of(d, struct lpass_q6v4, subsys_desc)
+
+static int lpass_shutdown(const struct subsys_desc *subsys)
+{
+ struct lpass_q6v4 *drv = subsys_to_lpass(subsys);
+
+ send_q6_nmi();
+ if (drv->loadable)
+ pil_force_shutdown("q6");
+ disable_irq_nosync(drv->q6.wdog_irq);
+
+ return 0;
+}
+
+static int lpass_powerup(const struct subsys_desc *subsys)
+{
+ struct lpass_q6v4 *drv = subsys_to_lpass(subsys);
+ int ret = 0;
+
+ if (drv->loadable)
+ ret = pil_force_boot("q6");
+ enable_irq(drv->q6.wdog_irq);
+
+ return ret;
+}
+
+static struct ramdump_segment segments[] = {
+ {0x8da00000, 0x8f200000 - 0x8da00000},
+ {0x28400000, 0x20000}
+};
+
+static int lpass_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct lpass_q6v4 *drv = subsys_to_lpass(subsys);
+
+ if (!enable)
+ return 0;
+ return do_ramdump(drv->ramdump_dev, segments, ARRAY_SIZE(segments));
+}
+
+static void lpass_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct lpass_q6v4 *drv = subsys_to_lpass(subsys);
+
+ drv->crash_shutdown = 1;
+ send_q6_nmi();
+}
+
+static irqreturn_t lpass_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct lpass_q6v4 *drv = dev_id;
+
+ disable_irq_nosync(drv->q6.wdog_irq);
+ schedule_work(&drv->work);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit pil_q6v4_lpass_driver_probe(struct platform_device *pdev)
+{
+ const struct pil_q6v4_pdata *pdata = pdev->dev.platform_data;
+ struct lpass_q6v4 *drv;
+ struct q6v4_data *q6;
+ struct pil_desc *desc;
+ struct resource *res;
+ int ret;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+ q6 = &drv->q6;
+ desc = &q6->desc;
+
+ q6->wdog_irq = platform_get_irq(pdev, 0);
+ if (q6->wdog_irq < 0)
+ return q6->wdog_irq;
+
+ drv->loadable = !!pdata; /* No pdata = don't use PIL */
+ if (drv->loadable) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+ q6->base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!q6->base)
+ return -ENOMEM;
+
+ q6->vreg = devm_regulator_get(&pdev->dev, "core_vdd");
+ if (IS_ERR(q6->vreg))
+ return PTR_ERR(q6->vreg);
+
+ q6->xo = devm_clk_get(&pdev->dev, "xo");
+ if (IS_ERR(q6->xo))
+ return PTR_ERR(q6->xo);
+
+ desc->name = pdata->name;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ desc->proxy_timeout = 10000;
+ pil_q6v4_init(q6, pdata);
+
+ if (pas_supported(pdata->pas_id) > 0) {
+ desc->ops = &pil_q6v4_lpass_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot\n");
+ } else {
+ desc->ops = &pil_q6v4_lpass_ops;
+ dev_info(&pdev->dev, "using non-secure boot\n");
+ }
+
+ q6->pil = msm_pil_register(desc);
+ if (IS_ERR(q6->pil))
+ return PTR_ERR(q6->pil);
+ }
+
+ drv->subsys_desc.name = "lpass";
+ drv->subsys_desc.shutdown = lpass_shutdown;
+ drv->subsys_desc.powerup = lpass_powerup;
+ drv->subsys_desc.ramdump = lpass_ramdump;
+ drv->subsys_desc.crash_shutdown = lpass_crash_shutdown;
+
+ INIT_WORK(&drv->work, lpass_fatal_fn);
+
+ drv->ramdump_dev = create_ramdump_device("lpass");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ ret = devm_request_irq(&pdev->dev, q6->wdog_irq, lpass_wdog_bite_irq,
+ IRQF_TRIGGER_RISING, dev_name(&pdev->dev), drv);
+ if (ret)
+ goto err_irq;
+
+ ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
+ lpass_smsm_state_cb, drv);
+ if (ret < 0)
+ goto err_smsm;
+
+ drv->riva_notif_hdle = subsys_notif_register_notifier("riva", &rnb);
+ if (IS_ERR(drv->riva_notif_hdle)) {
+ ret = PTR_ERR(drv->riva_notif_hdle);
+ goto err_notif_riva;
+ }
+
+ drv->modem_notif_hdle = subsys_notif_register_notifier("modem", &mnb);
+ if (IS_ERR(drv->modem_notif_hdle)) {
+ ret = PTR_ERR(drv->modem_notif_hdle);
+ goto err_notif_modem;
+ }
+ return 0;
+err_notif_modem:
+ subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+err_notif_riva:
+ smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
+ lpass_smsm_state_cb, drv);
+err_smsm:
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ if (drv->loadable)
+ msm_pil_unregister(q6->pil);
+ return ret;
+}
+
+static int __devexit pil_q6v4_lpass_driver_exit(struct platform_device *pdev)
+{
+ struct lpass_q6v4 *drv = platform_get_drvdata(pdev);
+ subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+ subsys_notif_unregister_notifier(drv->modem_notif_hdle, &mnb);
+ smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
+ lpass_smsm_state_cb, drv);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->ramdump_dev);
+ if (drv->loadable)
+ msm_pil_unregister(drv->q6.pil);
+ return 0;
+}
+
+static struct platform_driver pil_q6v4_lpass_driver = {
+ .probe = pil_q6v4_lpass_driver_probe,
+ .remove = __devexit_p(pil_q6v4_lpass_driver_exit),
+ .driver = {
+ .name = "pil-q6v4-lpass",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_q6v4_lpass_init(void)
+{
+ return platform_driver_register(&pil_q6v4_lpass_driver);
+}
+module_init(pil_q6v4_lpass_init);
+
+static void __exit pil_q6v4_lpass_exit(void)
+{
+ platform_driver_unregister(&pil_q6v4_lpass_driver);
+}
+module_exit(pil_q6v4_lpass_exit);
+
+MODULE_DESCRIPTION("Support for booting QDSP6v4 (Hexagon) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4-mss.c b/arch/arm/mach-msm/pil-q6v4-mss.c
new file mode 100644
index 0000000..61b5536
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v4-mss.c
@@ -0,0 +1,501 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+#include <mach/peripheral-loader.h>
+
+#include "smd_private.h"
+#include "ramdump.h"
+#include "peripheral-loader.h"
+#include "pil-q6v4.h"
+#include "scm-pas.h"
+
+#define MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C70)
+#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
+#define SFAB_MSS_M_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2340)
+#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
+#define MSS_RESET (MSM_CLK_CTL_BASE + 0x2C64)
+
+struct q6v4_modem {
+ struct q6v4_data q6_fw;
+ struct q6v4_data q6_sw;
+ void __iomem *modem_base;
+ void *fw_ramdump_dev;
+ void *sw_ramdump_dev;
+ void *smem_ramdump_dev;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ int crash_shutdown;
+ int loadable;
+};
+
+static DEFINE_MUTEX(pil_q6v4_modem_lock);
+static unsigned pil_q6v4_modem_count;
+
+/* Bring modem subsystem out of reset */
+static void pil_q6v4_init_modem(void __iomem *base, void __iomem *jtag_clk)
+{
+ mutex_lock(&pil_q6v4_modem_lock);
+ if (!pil_q6v4_modem_count) {
+ /* Enable MSS clocks */
+ writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
+ writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
+ writel_relaxed(0x10, MSS_S_HCLK_CTL);
+ writel_relaxed(0x10, MSS_SLP_CLK_CTL);
+ /* Wait for clocks to enable */
+ mb();
+ udelay(10);
+
+ /* De-assert MSS reset */
+ writel_relaxed(0x0, MSS_RESET);
+ mb();
+ udelay(10);
+ /* Enable MSS */
+ writel_relaxed(0x7, base);
+ }
+
+ /* Enable JTAG clocks */
+ /* TODO: Remove if/when Q6 software enables them? */
+ writel_relaxed(0x10, jtag_clk);
+
+ pil_q6v4_modem_count++;
+ mutex_unlock(&pil_q6v4_modem_lock);
+}
+
+/* Put modem subsystem back into reset */
+static void pil_q6v4_shutdown_modem(void)
+{
+ mutex_lock(&pil_q6v4_modem_lock);
+ if (pil_q6v4_modem_count)
+ pil_q6v4_modem_count--;
+ if (pil_q6v4_modem_count == 0)
+ writel_relaxed(0x1, MSS_RESET);
+ mutex_unlock(&pil_q6v4_modem_lock);
+}
+
+static int pil_q6v4_modem_boot(struct pil_desc *pil)
+{
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
+ struct q6v4_modem *mdm = dev_get_drvdata(pil->dev);
+ int err;
+
+ err = pil_q6v4_power_up(drv);
+ if (err)
+ return err;
+
+ pil_q6v4_init_modem(mdm->modem_base, drv->jtag_clk_reg);
+ return pil_q6v4_boot(pil);
+}
+
+static int pil_q6v4_modem_shutdown(struct pil_desc *pil)
+{
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
+ int ret;
+
+ ret = pil_q6v4_shutdown(pil);
+ if (ret)
+ return ret;
+ pil_q6v4_shutdown_modem();
+ pil_q6v4_power_down(drv);
+ return 0;
+}
+
+static struct pil_reset_ops pil_q6v4_modem_ops = {
+ .init_image = pil_q6v4_init_image,
+ .auth_and_reset = pil_q6v4_modem_boot,
+ .shutdown = pil_q6v4_modem_shutdown,
+ .proxy_vote = pil_q6v4_make_proxy_votes,
+ .proxy_unvote = pil_q6v4_remove_proxy_votes,
+};
+
+static struct pil_reset_ops pil_q6v4_modem_ops_trusted = {
+ .init_image = pil_q6v4_init_image_trusted,
+ .auth_and_reset = pil_q6v4_boot_trusted,
+ .shutdown = pil_q6v4_shutdown_trusted,
+ .proxy_vote = pil_q6v4_make_proxy_votes,
+ .proxy_unvote = pil_q6v4_remove_proxy_votes,
+};
+
+static void log_modem_sfr(void)
+{
+ u32 size;
+ char *smem_reason, reason[81];
+
+ smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+ if (!smem_reason || !size) {
+ pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+ return;
+ }
+ if (!smem_reason[0]) {
+ pr_err("modem subsystem failure reason: (unknown, init string found).\n");
+ return;
+ }
+
+ size = min(size, sizeof(reason)-1);
+ memcpy(reason, smem_reason, size);
+ reason[size] = '\0';
+ pr_err("modem subsystem failure reason: %s.\n", reason);
+
+ smem_reason[0] = '\0';
+ wmb();
+}
+
+static void restart_modem(struct q6v4_modem *drv)
+{
+ log_modem_sfr();
+ subsystem_restart_dev(drv->subsys);
+}
+
+#define desc_to_modem(d) container_of(d, struct q6v4_modem, subsys_desc)
+
+static int modem_shutdown(const struct subsys_desc *subsys)
+{
+ struct q6v4_modem *drv = desc_to_modem(subsys);
+
+ /* The watchdogs keep running even after the modem is shutdown */
+ writel_relaxed(0x0, drv->q6_fw.wdog_base + 0x24);
+ writel_relaxed(0x0, drv->q6_sw.wdog_base + 0x24);
+ mb();
+
+ if (drv->loadable) {
+ pil_force_shutdown("modem");
+ pil_force_shutdown("modem_fw");
+ }
+
+ disable_irq_nosync(drv->q6_fw.wdog_irq);
+ disable_irq_nosync(drv->q6_sw.wdog_irq);
+
+ return 0;
+}
+
+static int modem_powerup(const struct subsys_desc *subsys)
+{
+ struct q6v4_modem *drv = desc_to_modem(subsys);
+
+ if (drv->loadable) {
+ pil_force_boot("modem_fw");
+ pil_force_boot("modem");
+ }
+ enable_irq(drv->q6_fw.wdog_irq);
+ enable_irq(drv->q6_sw.wdog_irq);
+ return 0;
+}
+
+void modem_crash_shutdown(const struct subsys_desc *subsys)
+{
+ struct q6v4_modem *drv = desc_to_modem(subsys);
+
+ drv->crash_shutdown = 1;
+ smsm_reset_modem(SMSM_RESET);
+}
+
+static struct ramdump_segment sw_segments[] = {
+ {0x89000000, 0x8D400000 - 0x89000000},
+};
+
+static struct ramdump_segment fw_segments[] = {
+ {0x8D400000, 0x8DA00000 - 0x8D400000},
+};
+
+static struct ramdump_segment smem_segments[] = {
+ {0x80000000, 0x00200000},
+};
+
+static int modem_ramdump(int enable, const struct subsys_desc *subsys)
+{
+ struct q6v4_modem *drv = desc_to_modem(subsys);
+ int ret;
+
+ if (!enable)
+ return 0;
+
+ ret = do_ramdump(drv->sw_ramdump_dev, sw_segments,
+ ARRAY_SIZE(sw_segments));
+ if (ret < 0)
+ return ret;
+
+ ret = do_ramdump(drv->fw_ramdump_dev, fw_segments,
+ ARRAY_SIZE(fw_segments));
+ if (ret < 0)
+ return ret;
+
+ ret = do_ramdump(drv->smem_ramdump_dev, smem_segments,
+ ARRAY_SIZE(smem_segments));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
+{
+ struct q6v4_modem *drv = data;
+
+ /* Ignore if we're the one that set SMSM_RESET */
+ if (drv->crash_shutdown)
+ return;
+
+ if (new_state & SMSM_RESET) {
+ pr_err("Probable fatal error on the modem.\n");
+ restart_modem(drv);
+ }
+}
+
+static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
+{
+ struct q6v4_modem *drv = dev_id;
+ restart_modem(drv);
+ return IRQ_HANDLED;
+}
+
+static int __devinit
+pil_q6v4_proc_init(struct q6v4_data *drv, struct platform_device *pdev, int i)
+{
+ static const char *name[2] = { "fw", "sw" };
+ const struct pil_q6v4_pdata *pdata_p = pdev->dev.platform_data;
+ const struct pil_q6v4_pdata *pdata = pdata_p + i;
+ char reg_name[12];
+ struct pil_desc *desc;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + (i * 2));
+ if (!res)
+ return -EINVAL;
+
+ drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!drv->base)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2 + (i * 2));
+ if (!res)
+ return -EINVAL;
+
+ drv->wdog_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->wdog_base)
+ return -ENOMEM;
+
+ snprintf(reg_name, sizeof(reg_name), "%s_core_vdd", name[i]);
+ drv->vreg = devm_regulator_get(&pdev->dev, reg_name);
+ if (IS_ERR(drv->vreg))
+ return PTR_ERR(drv->vreg);
+
+ drv->xo = devm_clk_get(&pdev->dev, "xo");
+ if (IS_ERR(drv->xo))
+ return PTR_ERR(drv->xo);
+
+ desc = &drv->desc;
+ desc->name = pdata->name;
+ desc->depends_on = pdata->depends;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ desc->proxy_timeout = 10000;
+ pil_q6v4_init(drv, pdata);
+
+ if (pas_supported(pdata->pas_id) > 0) {
+ desc->ops = &pil_q6v4_modem_ops_trusted;
+ dev_info(&pdev->dev, "using secure boot for %s\n", name[i]);
+ } else {
+ desc->ops = &pil_q6v4_modem_ops;
+ dev_info(&pdev->dev, "using non-secure boot for %s\n", name[i]);
+ }
+ return 0;
+}
+
+static int __devinit pil_q6v4_modem_driver_probe(struct platform_device *pdev)
+{
+ struct q6v4_data *drv_fw, *drv_sw;
+ struct q6v4_modem *drv;
+ struct resource *res;
+ struct regulator *pll_supply;
+ int ret;
+ const struct pil_q6v4_pdata *pdata = pdev->dev.platform_data;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+
+ drv_fw = &drv->q6_fw;
+ drv_sw = &drv->q6_sw;
+
+ drv_fw->wdog_irq = platform_get_irq(pdev, 0);
+ if (drv_fw->wdog_irq < 0)
+ return drv_fw->wdog_irq;
+
+ drv_sw->wdog_irq = platform_get_irq(pdev, 1);
+ if (drv_sw->wdog_irq < 0)
+ return drv_sw->wdog_irq;
+
+ drv->loadable = !!pdata; /* No pdata = don't use PIL */
+ if (drv->loadable) {
+ ret = pil_q6v4_proc_init(drv_fw, pdev, 0);
+ if (ret)
+ return ret;
+
+ ret = pil_q6v4_proc_init(drv_sw, pdev, 1);
+ if (ret)
+ return ret;
+
+ pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
+ drv_fw->pll_supply = drv_sw->pll_supply = pll_supply;
+ if (IS_ERR(pll_supply))
+ return PTR_ERR(pll_supply);
+
+ ret = regulator_set_voltage(pll_supply, 1800000, 1800000);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set pll voltage\n");
+ return ret;
+ }
+
+ ret = regulator_set_optimum_mode(pll_supply, 100000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to set pll optimum mode\n");
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ drv->modem_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->modem_base)
+ return -ENOMEM;
+
+ drv_fw->pil = msm_pil_register(&drv_fw->desc);
+ if (IS_ERR(drv_fw->pil))
+ return PTR_ERR(drv_fw->pil);
+
+ drv_sw->pil = msm_pil_register(&drv_sw->desc);
+ if (IS_ERR(drv_sw->pil)) {
+ ret = PTR_ERR(drv_sw->pil);
+ goto err_pil_sw;
+ }
+ }
+
+ drv->subsys_desc.name = "modem";
+ drv->subsys_desc.shutdown = modem_shutdown;
+ drv->subsys_desc.powerup = modem_powerup;
+ drv->subsys_desc.ramdump = modem_ramdump;
+ drv->subsys_desc.crash_shutdown = modem_crash_shutdown;
+
+ drv->fw_ramdump_dev = create_ramdump_device("modem_fw");
+ if (!drv->fw_ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_fw_ramdump;
+ }
+
+ drv->sw_ramdump_dev = create_ramdump_device("modem_sw");
+ if (!drv->sw_ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_sw_ramdump;
+ }
+
+ drv->smem_ramdump_dev = create_ramdump_device("smem-modem");
+ if (!drv->smem_ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_smem_ramdump;
+ }
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ ret = devm_request_irq(&pdev->dev, drv_fw->wdog_irq,
+ modem_wdog_bite_irq, IRQF_TRIGGER_RISING,
+ dev_name(&pdev->dev), drv);
+ if (ret)
+ goto err_irq;
+
+ ret = devm_request_irq(&pdev->dev, drv_sw->wdog_irq,
+ modem_wdog_bite_irq, IRQF_TRIGGER_RISING,
+ dev_name(&pdev->dev), drv);
+ if (ret)
+ goto err_irq;
+
+ ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
+ smsm_state_cb, drv);
+ if (ret)
+ goto err_irq;
+ return 0;
+
+err_irq:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+err_smem_ramdump:
+ destroy_ramdump_device(drv->sw_ramdump_dev);
+err_sw_ramdump:
+ destroy_ramdump_device(drv->fw_ramdump_dev);
+err_fw_ramdump:
+ if (drv->loadable)
+ msm_pil_unregister(drv_sw->pil);
+err_pil_sw:
+ msm_pil_unregister(drv_fw->pil);
+ return ret;
+}
+
+static int __devexit pil_q6v4_modem_driver_exit(struct platform_device *pdev)
+{
+ struct q6v4_modem *drv = platform_get_drvdata(pdev);
+
+ smsm_state_cb_deregister(SMSM_MODEM_STATE, SMSM_RESET,
+ smsm_state_cb, drv);
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->smem_ramdump_dev);
+ destroy_ramdump_device(drv->sw_ramdump_dev);
+ destroy_ramdump_device(drv->fw_ramdump_dev);
+ if (drv->loadable) {
+ msm_pil_unregister(drv->q6_sw.pil);
+ msm_pil_unregister(drv->q6_fw.pil);
+ }
+ return 0;
+}
+
+static struct platform_driver pil_q6v4_modem_driver = {
+ .probe = pil_q6v4_modem_driver_probe,
+ .remove = __devexit_p(pil_q6v4_modem_driver_exit),
+ .driver = {
+ .name = "pil-q6v4-modem",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_q6v4_modem_init(void)
+{
+ return platform_driver_register(&pil_q6v4_modem_driver);
+}
+module_init(pil_q6v4_modem_init);
+
+static void __exit pil_q6v4_modem_exit(void)
+{
+ platform_driver_unregister(&pil_q6v4_modem_driver);
+}
+module_exit(pil_q6v4_modem_exit);
+
+MODULE_DESCRIPTION("Support for booting QDSP6v4 (Hexagon) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index 32cce1d..47033fc 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -22,7 +22,6 @@
#include <linux/clk.h>
#include <mach/msm_bus.h>
-#include <mach/msm_iomap.h>
#include "peripheral-loader.h"
#include "pil-q6v4.h"
@@ -35,12 +34,6 @@
#define QDSP6SS_GFMUX_CTL 0x30
#define QDSP6SS_PWR_CTL 0x38
-#define MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C70)
-#define MSS_SLP_CLK_CTL (MSM_CLK_CTL_BASE + 0x2C60)
-#define SFAB_MSS_M_ACLK_CTL (MSM_CLK_CTL_BASE + 0x2340)
-#define SFAB_MSS_S_HCLK_CTL (MSM_CLK_CTL_BASE + 0x2C00)
-#define MSS_RESET (MSM_CLK_CTL_BASE + 0x2C64)
-
#define Q6SS_SS_ARES BIT(0)
#define Q6SS_CORE_ARES BIT(1)
#define Q6SS_ISDB_ARES BIT(2)
@@ -59,29 +52,19 @@
#define Q6SS_CLK_ENA BIT(1)
#define Q6SS_SRC_SWITCH_CLK_OVR BIT(8)
-struct q6v4_data {
- void __iomem *base;
- void __iomem *modem_base;
- unsigned long start_addr;
- struct regulator *vreg;
- struct regulator *pll_supply;
- bool vreg_enabled;
- struct clk *xo;
- struct pil_device *pil;
-};
-
-static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
+int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
size_t size)
{
const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
- struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
drv->start_addr = ehdr->e_entry;
return 0;
}
+EXPORT_SYMBOL(pil_q6v4_init_image);
-static int pil_q6v4_make_proxy_votes(struct pil_desc *pil)
+int pil_q6v4_make_proxy_votes(struct pil_desc *pil)
{
- const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+ const struct q6v4_data *drv = pil_to_q6v4_data(pil);
int ret;
ret = clk_prepare_enable(drv->xo);
@@ -102,19 +85,21 @@
err:
return ret;
}
+EXPORT_SYMBOL(pil_q6v4_make_proxy_votes);
-static void pil_q6v4_remove_proxy_votes(struct pil_desc *pil)
+void pil_q6v4_remove_proxy_votes(struct pil_desc *pil)
{
- const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
+ const struct q6v4_data *drv = pil_to_q6v4_data(pil);
if (drv->pll_supply)
regulator_disable(drv->pll_supply);
clk_disable_unprepare(drv->xo);
}
+EXPORT_SYMBOL(pil_q6v4_remove_proxy_votes);
-static int pil_q6v4_power_up(struct device *dev)
+int pil_q6v4_power_up(struct q6v4_data *drv)
{
int err;
- struct q6v4_data *drv = dev_get_drvdata(dev);
+ struct device *dev = drv->desc.dev;
err = regulator_set_voltage(drv->vreg, 743750, 743750);
if (err) {
@@ -141,68 +126,27 @@
drv->vreg_enabled = true;
return 0;
}
+EXPORT_SYMBOL(pil_q6v4_power_up);
-static DEFINE_MUTEX(pil_q6v4_modem_lock);
-static unsigned pil_q6v4_modem_count;
-
-/* Bring modem subsystem out of reset */
-static void pil_q6v4_init_modem(void __iomem *base, void __iomem *jtag_clk)
+void pil_q6v4_power_down(struct q6v4_data *drv)
{
- mutex_lock(&pil_q6v4_modem_lock);
- if (!pil_q6v4_modem_count) {
- /* Enable MSS clocks */
- writel_relaxed(0x10, SFAB_MSS_M_ACLK_CTL);
- writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
- writel_relaxed(0x10, MSS_S_HCLK_CTL);
- writel_relaxed(0x10, MSS_SLP_CLK_CTL);
- /* Wait for clocks to enable */
- mb();
- udelay(10);
-
- /* De-assert MSS reset */
- writel_relaxed(0x0, MSS_RESET);
- mb();
- udelay(10);
- /* Enable MSS */
- writel_relaxed(0x7, base);
+ if (drv->vreg_enabled) {
+ regulator_disable(drv->vreg);
+ drv->vreg_enabled = false;
}
-
- /* Enable JTAG clocks */
- /* TODO: Remove if/when Q6 software enables them? */
- writel_relaxed(0x10, jtag_clk);
-
- pil_q6v4_modem_count++;
- mutex_unlock(&pil_q6v4_modem_lock);
}
+EXPORT_SYMBOL(pil_q6v4_power_down);
-/* Put modem subsystem back into reset */
-static void pil_q6v4_shutdown_modem(void)
-{
- mutex_lock(&pil_q6v4_modem_lock);
- if (pil_q6v4_modem_count)
- pil_q6v4_modem_count--;
- if (pil_q6v4_modem_count == 0)
- writel_relaxed(0x1, MSS_RESET);
- mutex_unlock(&pil_q6v4_modem_lock);
-}
-
-static int pil_q6v4_reset(struct pil_desc *pil)
+int pil_q6v4_boot(struct pil_desc *pil)
{
u32 reg, err;
- const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
- const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+ const struct q6v4_data *drv = pil_to_q6v4_data(pil);
- err = pil_q6v4_power_up(pil->dev);
- if (err)
- return err;
/* Enable Q6 ACLK */
- writel_relaxed(0x10, pdata->aclk_reg);
-
- if (drv->modem_base)
- pil_q6v4_init_modem(drv->modem_base, pdata->jtag_clk_reg);
+ writel_relaxed(0x10, drv->aclk_reg);
/* Unhalt bus port */
- err = msm_bus_axi_portunhalt(pdata->bus_port);
+ err = msm_bus_axi_portunhalt(drv->bus_port);
if (err)
dev_err(pil->dev, "Failed to unhalt bus port\n");
@@ -216,8 +160,8 @@
drv->base + QDSP6SS_RST_EVB);
/* Program TCM and AHB address ranges */
- writel_relaxed(pdata->strap_tcm_base, drv->base + QDSP6SS_STRAP_TCM);
- writel_relaxed(pdata->strap_ahb_upper | pdata->strap_ahb_lower,
+ writel_relaxed(drv->strap_tcm_base, drv->base + QDSP6SS_STRAP_TCM);
+ writel_relaxed(drv->strap_ahb_upper | drv->strap_ahb_lower,
drv->base + QDSP6SS_STRAP_AHB);
/* Turn off Q6 core clock */
@@ -257,15 +201,15 @@
return 0;
}
+EXPORT_SYMBOL(pil_q6v4_boot);
-static int pil_q6v4_shutdown(struct pil_desc *pil)
+int pil_q6v4_shutdown(struct pil_desc *pil)
{
u32 reg;
- struct q6v4_data *drv = dev_get_drvdata(pil->dev);
- const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
/* Make sure bus port is halted */
- msm_bus_axi_porthalt(pdata->bus_port);
+ msm_bus_axi_porthalt(drv->bus_port);
/* Turn off Q6 core clock */
writel_relaxed(Q6SS_SRC_SWITCH_CLK_OVR,
@@ -279,188 +223,67 @@
/* Turn off Q6 memories */
writel_relaxed(Q6SS_CLAMP_IO, drv->base + QDSP6SS_PWR_CTL);
- if (drv->modem_base)
- pil_q6v4_shutdown_modem();
-
- if (drv->vreg_enabled) {
- regulator_disable(drv->vreg);
- drv->vreg_enabled = false;
- }
-
return 0;
}
+EXPORT_SYMBOL(pil_q6v4_shutdown);
-static struct pil_reset_ops pil_q6v4_ops = {
- .init_image = pil_q6v4_init_image,
- .auth_and_reset = pil_q6v4_reset,
- .shutdown = pil_q6v4_shutdown,
- .proxy_vote = pil_q6v4_make_proxy_votes,
- .proxy_unvote = pil_q6v4_remove_proxy_votes,
-};
-
-static int pil_q6v4_init_image_trusted(struct pil_desc *pil,
+int pil_q6v4_init_image_trusted(struct pil_desc *pil,
const u8 *metadata, size_t size)
{
- const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
- return pas_init_image(pdata->pas_id, metadata, size);
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
+ return pas_init_image(drv->pas_id, metadata, size);
}
+EXPORT_SYMBOL(pil_q6v4_init_image_trusted);
-static int pil_q6v4_reset_trusted(struct pil_desc *pil)
+int pil_q6v4_boot_trusted(struct pil_desc *pil)
{
- const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
int err;
- err = pil_q6v4_power_up(pil->dev);
+ err = pil_q6v4_power_up(drv);
if (err)
return err;
/* Unhalt bus port */
- err = msm_bus_axi_portunhalt(pdata->bus_port);
+ err = msm_bus_axi_portunhalt(drv->bus_port);
if (err)
dev_err(pil->dev, "Failed to unhalt bus port\n");
- return pas_auth_and_reset(pdata->pas_id);
+ return pas_auth_and_reset(drv->pas_id);
}
+EXPORT_SYMBOL(pil_q6v4_boot_trusted);
-static int pil_q6v4_shutdown_trusted(struct pil_desc *pil)
+int pil_q6v4_shutdown_trusted(struct pil_desc *pil)
{
int ret;
- struct q6v4_data *drv = dev_get_drvdata(pil->dev);
- struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
+ struct q6v4_data *drv = pil_to_q6v4_data(pil);
/* Make sure bus port is halted */
- msm_bus_axi_porthalt(pdata->bus_port);
+ msm_bus_axi_porthalt(drv->bus_port);
- ret = pas_shutdown(pdata->pas_id);
+ ret = pas_shutdown(drv->pas_id);
if (ret)
return ret;
- if (drv->vreg_enabled) {
- regulator_disable(drv->vreg);
- drv->vreg_enabled = false;
- }
+ pil_q6v4_power_down(drv);
return ret;
}
+EXPORT_SYMBOL(pil_q6v4_shutdown_trusted);
-static struct pil_reset_ops pil_q6v4_ops_trusted = {
- .init_image = pil_q6v4_init_image_trusted,
- .auth_and_reset = pil_q6v4_reset_trusted,
- .shutdown = pil_q6v4_shutdown_trusted,
- .proxy_vote = pil_q6v4_make_proxy_votes,
- .proxy_unvote = pil_q6v4_remove_proxy_votes,
-};
-
-static int __devinit pil_q6v4_driver_probe(struct platform_device *pdev)
+void __devinit
+pil_q6v4_init(struct q6v4_data *drv, const struct pil_q6v4_pdata *pdata)
{
- const struct pil_q6v4_pdata *pdata = pdev->dev.platform_data;
- struct q6v4_data *drv;
- struct resource *res;
- struct pil_desc *desc;
- int ret;
+ drv->strap_tcm_base = pdata->strap_tcm_base;
+ drv->strap_ahb_upper = pdata->strap_ahb_upper;
+ drv->strap_ahb_lower = pdata->strap_ahb_lower;
+ drv->aclk_reg = pdata->aclk_reg;
+ drv->jtag_clk_reg = pdata->jtag_clk_reg;
+ drv->pas_id = pdata->pas_id;
+ drv->bus_port = pdata->bus_port;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
-
- drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
- if (!drv)
- return -ENOMEM;
- platform_set_drvdata(pdev, drv);
-
- drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!drv->base)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (res) {
- drv->modem_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!drv->modem_base)
- return -ENOMEM;
- }
-
- desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
- if (!desc)
- return -ENOMEM;
-
- drv->pll_supply = devm_regulator_get(&pdev->dev, "pll_vdd");
- if (IS_ERR(drv->pll_supply)) {
- drv->pll_supply = NULL;
- } else {
- ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
- if (ret) {
- dev_err(&pdev->dev, "failed to set pll voltage\n");
- return ret;
- }
-
- ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to set pll optimum mode\n");
- return ret;
- }
- }
-
- desc->name = pdata->name;
- desc->depends_on = pdata->depends;
- desc->dev = &pdev->dev;
- desc->owner = THIS_MODULE;
- desc->proxy_timeout = 10000;
-
- if (pas_supported(pdata->pas_id) > 0) {
- desc->ops = &pil_q6v4_ops_trusted;
- dev_info(&pdev->dev, "using secure boot\n");
- } else {
- desc->ops = &pil_q6v4_ops;
- dev_info(&pdev->dev, "using non-secure boot\n");
- }
-
- drv->vreg = devm_regulator_get(&pdev->dev, "core_vdd");
- if (IS_ERR(drv->vreg))
- return PTR_ERR(drv->vreg);
-
- ret = regulator_set_optimum_mode(drv->vreg, 100000);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
- return ret;
- }
-
- drv->xo = devm_clk_get(&pdev->dev, "xo");
- if (IS_ERR(drv->xo))
- return PTR_ERR(drv->xo);
-
- drv->pil = msm_pil_register(desc);
- if (IS_ERR(drv->pil))
- return PTR_ERR(drv->pil);
- return 0;
+ regulator_set_optimum_mode(drv->vreg, 100000);
}
-
-static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
-{
- struct q6v4_data *drv = platform_get_drvdata(pdev);
- msm_pil_unregister(drv->pil);
- return 0;
-}
-
-static struct platform_driver pil_q6v4_driver = {
- .probe = pil_q6v4_driver_probe,
- .remove = __devexit_p(pil_q6v4_driver_exit),
- .driver = {
- .name = "pil_qdsp6v4",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init pil_q6v4_init(void)
-{
- return platform_driver_register(&pil_q6v4_driver);
-}
-module_init(pil_q6v4_init);
-
-static void __exit pil_q6v4_exit(void)
-{
- platform_driver_unregister(&pil_q6v4_driver);
-}
-module_exit(pil_q6v4_exit);
+EXPORT_SYMBOL(pil_q6v4_init);
MODULE_DESCRIPTION("Support for booting QDSP6v4 (Hexagon) processors");
MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4.h b/arch/arm/mach-msm/pil-q6v4.h
index b0b97d0..0395bed 100644
--- a/arch/arm/mach-msm/pil-q6v4.h
+++ b/arch/arm/mach-msm/pil-q6v4.h
@@ -12,6 +12,8 @@
#ifndef __MSM_PIL_Q6V4_H
#define __MSM_PIL_Q6V4_H
+#include "peripheral-loader.h"
+
struct pil_q6v4_pdata {
const unsigned long strap_tcm_base;
const unsigned long strap_ahb_upper;
@@ -23,4 +25,52 @@
const unsigned pas_id;
int bus_port;
};
+
+struct clk;
+struct pil_device;
+struct regulator;
+
+/**
+ * struct q6v4_data - Q6 processor
+ */
+struct q6v4_data {
+ void __iomem *base;
+ void __iomem *wdog_base;
+ unsigned long start_addr;
+ unsigned long strap_tcm_base;
+ unsigned long strap_ahb_upper;
+ unsigned long strap_ahb_lower;
+ void __iomem *aclk_reg;
+ void __iomem *jtag_clk_reg;
+ unsigned pas_id;
+ int bus_port;
+ int wdog_irq;
+
+ struct regulator *vreg;
+ struct regulator *pll_supply;
+ bool vreg_enabled;
+ struct clk *xo;
+
+ struct pil_device *pil;
+ struct pil_desc desc;
+};
+
+#define pil_to_q6v4_data(p) container_of(p, struct q6v4_data, desc)
+
+extern int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
+ size_t size);
+extern int pil_q6v4_make_proxy_votes(struct pil_desc *pil);
+extern void pil_q6v4_remove_proxy_votes(struct pil_desc *pil);
+extern int pil_q6v4_power_up(struct q6v4_data *drv);
+extern void pil_q6v4_power_down(struct q6v4_data *drv);
+extern int pil_q6v4_boot(struct pil_desc *pil);
+extern int pil_q6v4_shutdown(struct pil_desc *pil);
+
+extern int pil_q6v4_init_image_trusted(struct pil_desc *pil,
+ const u8 *metadata, size_t size);
+extern int pil_q6v4_boot_trusted(struct pil_desc *pil);
+extern int pil_q6v4_shutdown_trusted(struct pil_desc *pil);
+extern void __devinit
+pil_q6v4_init(struct q6v4_data *drv, const struct pil_q6v4_pdata *p);
+
#endif
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 1fdd342..9ff1234 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -79,7 +79,6 @@
static int pil_mss_enable_clks(struct q6v5_data *drv)
{
int ret;
- void __iomem *mpll1_config_ctl;
ret = clk_prepare_enable(drv->ahb_clk);
if (ret)
@@ -91,12 +90,6 @@
if (ret)
goto err_rom_clk;
- /* TODO: Remove when support for 8974v1.0 HW is dropped. */
- mpll1_config_ctl = ioremap(0xFC981034, 0x4);
- writel_relaxed(0x0300403D, mpll1_config_ctl);
- mb();
- iounmap(mpll1_config_ctl);
-
return 0;
err_rom_clk:
@@ -266,20 +259,21 @@
of_property_read_u32(pdev->dev.of_node, "qcom,pil-self-auth",
&drv->self_auth);
if (drv->self_auth) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "rmb_base");
drv->rmb_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!drv->rmb_base)
return -ENOMEM;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg");
drv->restart_reg = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!drv->restart_reg)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clamp_reg");
drv->io_clamp_reg = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!drv->io_clamp_reg)
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 772031b..f4e8844 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -205,14 +205,14 @@
return ERR_PTR(-ENOMEM);
platform_set_drvdata(pdev, drv);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6_base");
if (!res)
return ERR_PTR(-EINVAL);
drv->reg_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!drv->reg_base)
return ERR_PTR(-ENOMEM);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!drv->axi_halt_base)
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 3040a31..dbb4408 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -20,11 +20,17 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/wcnss_wlan.h>
#include <mach/msm_iomap.h>
+#include <mach/subsystem_restart.h>
+#include <mach/peripheral-loader.h>
#include "peripheral-loader.h"
#include "scm-pas.h"
+#include "ramdump.h"
+#include "smd_private.h"
#define RIVA_PMU_A2XB_CFG 0xB8
#define RIVA_PMU_A2XB_CFG_EN BIT(0)
@@ -82,6 +88,13 @@
struct clk *xo;
struct regulator *pll_supply;
struct pil_device *pil;
+ int irq;
+ int crash;
+ int rst_in_progress;
+ struct subsys_device *subsys;
+ struct subsys_desc subsys_desc;
+ struct delayed_work cancel_work;
+ struct ramdump_device *ramdump_dev;
};
static bool cxo_is_needed(struct riva_data *drv)
@@ -272,6 +285,160 @@
.proxy_unvote = pil_riva_remove_proxy_vote,
};
+static int enable_riva_ssr;
+
+static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_int(val, kp);
+ if (ret)
+ return ret;
+
+ if (enable_riva_ssr)
+ pr_info("Subsystem restart activated for riva.\n");
+
+ return 0;
+}
+module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
+ &enable_riva_ssr, S_IRUGO | S_IWUSR);
+
+static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ struct riva_data *drv = data;
+ char *smem_reset_reason;
+ char buffer[81];
+ unsigned smem_reset_size;
+ unsigned size;
+
+ drv->crash = true;
+ if (!(new_state & SMSM_RESET))
+ return;
+
+ if (drv->rst_in_progress) {
+ pr_err("riva: Ignoring smsm reset req, restart in progress\n");
+ return;
+ }
+
+ pr_err("riva: smsm state changed to smsm reset\n");
+
+ smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
+ &smem_reset_size);
+
+ if (!smem_reset_reason || !smem_reset_size) {
+ pr_err("wcnss subsystem failure reason:\n"
+ "(unknown, smem_get_entry failed)");
+ } else if (!smem_reset_reason[0]) {
+ pr_err("wcnss subsystem failure reason:\n"
+ "(unknown, init string found)");
+ } else {
+ size = smem_reset_size < sizeof(buffer) ? smem_reset_size :
+ (sizeof(buffer) - 1);
+ memcpy(buffer, smem_reset_reason, size);
+ buffer[size] = '\0';
+ pr_err("wcnss subsystem failure reason: %s\n", buffer);
+ memset(smem_reset_reason, 0, smem_reset_size);
+ wmb();
+ }
+
+ drv->rst_in_progress = 1;
+ subsystem_restart_dev(drv->subsys);
+}
+
+static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
+{
+ struct riva_data *drv = dev_id;
+
+ drv->crash = true;
+ if (drv->rst_in_progress) {
+ pr_err("Ignoring riva bite irq, restart in progress\n");
+ return IRQ_HANDLED;
+ }
+ if (!enable_riva_ssr)
+ panic("Watchdog bite received from Riva");
+
+ drv->rst_in_progress = 1;
+ subsystem_restart_dev(drv->subsys);
+
+ return IRQ_HANDLED;
+}
+
+static void riva_post_bootup(struct work_struct *work)
+{
+ struct platform_device *pdev = wcnss_get_platform_device();
+ struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+
+ wcnss_wlan_power(&pdev->dev, pwlanconfig, WCNSS_WLAN_SWITCH_OFF);
+}
+
+static int riva_shutdown(const struct subsys_desc *desc)
+{
+ struct riva_data *drv;
+
+ drv = container_of(desc, struct riva_data, subsys_desc);
+ pil_force_shutdown("wcnss");
+ flush_delayed_work(&drv->cancel_work);
+ wcnss_flush_delayed_boot_votes();
+ disable_irq_nosync(drv->irq);
+
+ return 0;
+}
+
+static int riva_powerup(const struct subsys_desc *desc)
+{
+ struct riva_data *drv;
+ struct platform_device *pdev = wcnss_get_platform_device();
+ struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+ int ret = 0;
+
+ drv = container_of(desc, struct riva_data, subsys_desc);
+ if (pdev && pwlanconfig) {
+ ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
+ WCNSS_WLAN_SWITCH_ON);
+ if (!ret)
+ pil_force_boot("wcnss");
+ }
+ drv->rst_in_progress = 0;
+ enable_irq(drv->irq);
+ schedule_delayed_work(&drv->cancel_work, msecs_to_jiffies(5000));
+
+ return ret;
+}
+
+/*
+ * 7MB RAM segments for Riva SS;
+ * Riva 1.1 0x8f000000 - 0x8f700000
+ * Riva 1.0 0x8f200000 - 0x8f700000
+ */
+static struct ramdump_segment riva_segments[] = {
+ {0x8f000000, 0x8f700000 - 0x8f000000}
+};
+
+static int riva_ramdump(int enable, const struct subsys_desc *desc)
+{
+ struct riva_data *drv;
+
+ drv = container_of(desc, struct riva_data, subsys_desc);
+
+ if (enable)
+ return do_ramdump(drv->ramdump_dev, riva_segments,
+ ARRAY_SIZE(riva_segments));
+ else
+ return 0;
+}
+
+/* Riva crash handler */
+static void riva_crash_shutdown(const struct subsys_desc *desc)
+{
+ struct riva_data *drv;
+
+ drv = container_of(desc, struct riva_data, subsys_desc);
+ pr_err("riva crash shutdown %d\n", drv->crash);
+ if (drv->crash != true)
+ smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
+}
+
static int __devinit pil_riva_probe(struct platform_device *pdev)
{
struct riva_data *drv;
@@ -317,6 +484,10 @@
}
}
+ drv->irq = platform_get_irq(pdev, 0);
+ if (drv->irq < 0)
+ return drv->irq;
+
desc->name = "wcnss";
desc->dev = &pdev->dev;
desc->owner = THIS_MODULE;
@@ -337,13 +508,60 @@
drv->pil = msm_pil_register(desc);
if (IS_ERR(drv->pil))
return PTR_ERR(drv->pil);
+
+ ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
+ smsm_state_cb_hdlr, drv);
+ if (ret < 0)
+ goto err_smsm;
+
+ drv->subsys_desc.name = "wcnss";
+ drv->subsys_desc.shutdown = riva_shutdown;
+ drv->subsys_desc.powerup = riva_powerup;
+ drv->subsys_desc.ramdump = riva_ramdump;
+ drv->subsys_desc.crash_shutdown = riva_crash_shutdown;
+
+ INIT_DELAYED_WORK(&drv->cancel_work, riva_post_bootup);
+
+ drv->ramdump_dev = create_ramdump_device("riva");
+ if (!drv->ramdump_dev) {
+ ret = -ENOMEM;
+ goto err_ramdump;
+ }
+
+ drv->subsys = subsys_register(&drv->subsys_desc);
+ if (IS_ERR(drv->subsys)) {
+ ret = PTR_ERR(drv->subsys);
+ goto err_subsys;
+ }
+
+ ret = devm_request_irq(&pdev->dev, drv->irq, riva_wdog_bite_irq_hdlr,
+ IRQF_TRIGGER_HIGH, "riva_wdog", drv);
+ if (ret < 0)
+ goto err;
+
return 0;
+err:
+ subsys_unregister(drv->subsys);
+err_subsys:
+ destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+ smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
+ smsm_state_cb_hdlr, drv);
+err_smsm:
+ msm_pil_unregister(drv->pil);
+ return ret;
}
static int __devexit pil_riva_remove(struct platform_device *pdev)
{
struct riva_data *drv = platform_get_drvdata(pdev);
+
+ subsys_unregister(drv->subsys);
+ destroy_ramdump_device(drv->ramdump_dev);
+ smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
+ smsm_state_cb_hdlr, drv);
msm_pil_unregister(drv->pil);
+
return 0;
}
diff --git a/arch/arm/mach-msm/pil-venus.c b/arch/arm/mach-msm/pil-venus.c
index 1ccde72..e331296 100644
--- a/arch/arm/mach-msm/pil-venus.c
+++ b/arch/arm/mach-msm/pil-venus.c
@@ -388,7 +388,8 @@
struct pil_desc *desc;
int rc;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "wrapper_base");
if (!res)
return -EINVAL;
@@ -402,7 +403,7 @@
if (!drv->venus_wrapper_base)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vbif_base");
if (!res)
return -EINVAL;
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 700f966..3b31b9f 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -28,19 +28,28 @@
#include <mach/msm_iomap.h>
#include "pm.h"
-#define MSM_CORE1_RESET 0xA8600590
-#define MSM_CORE1_STATUS_MSK 0x02800000
+#define CORE_RESET_BASE 0xA8600590
+#define MSM_CORE_STATUS_MSK 0x02800000
/*
* control for which core is the next to come out of the secondary
* boot "holding pen"
*/
-int pen_release = -1;
+volatile int pen_release = -1;
-static bool cold_boot_done;
+static DEFINE_PER_CPU(bool, cold_boot_done);
+
+struct per_cpu_data {
+ unsigned int reset_off;
+ unsigned int offset;
+ unsigned int ipc_irq;
+ void __iomem *reset_core_base;
+};
static uint32_t *msm8625_boot_vector;
-static void __iomem *reset_core1_base;
+
+
+static struct per_cpu_data cpu_data[CONFIG_NR_CPUS];
/*
* Write pen_release in a way that is guaranteed to be visible to all
@@ -65,7 +74,8 @@
/*
* MP_CORE_IPC will be used to generate interrupt and can be used by either
* of core.
- * To bring core1 out of GDFS we need to raise the SPI using the MP_CORE_IPC.
+ * To bring secondary cores out of GDFS we need to raise the SPI using the
+ * MP_CORE_IPC.
*/
static void raise_clear_spi(unsigned int cpu, bool set)
{
@@ -110,10 +120,10 @@
*/
write_pen_release(-1);
- /* clear the IPC1(SPI-8) pending SPI */
+ /* clear the IPC pending SPI */
if (power_collapsed) {
- raise_clear_spi(1, false);
- clear_pending_spi(MSM8625_INT_ACSR_MP_CORE_IPC1);
+ raise_clear_spi(cpu, false);
+ clear_pending_spi(cpu_data[cpu].ipc_irq);
power_collapsed = 0;
}
@@ -124,7 +134,7 @@
spin_unlock(&boot_lock);
}
-static int __cpuinit msm8625_release_secondary(void)
+static int __cpuinit msm8625_release_secondary(unsigned int cpu)
{
void __iomem *base_ptr;
int value = 0;
@@ -137,33 +147,35 @@
*/
timeout = jiffies + usecs_to_jiffies(20);
while (time_before(jiffies, timeout)) {
- value = __raw_readl(MSM_CFG_CTL_BASE + 0x3c);
- if ((value & MSM_CORE1_STATUS_MSK) ==
- MSM_CORE1_STATUS_MSK)
+ value = __raw_readl(MSM_CFG_CTL_BASE + cpu_data[cpu].offset);
+ if ((value & MSM_CORE_STATUS_MSK) ==
+ MSM_CORE_STATUS_MSK)
break;
udelay(1);
}
if (!value) {
- pr_err("Core 1 cannot be brought out of Reset!!!\n");
+ pr_err("Core %u cannot be brought out of Reset!!!\n", cpu);
return -ENODEV;
}
- base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
+ base_ptr = ioremap_nocache(CORE_RESET_BASE +
+ cpu_data[cpu].reset_off, SZ_4);
if (!base_ptr)
return -ENODEV;
- /* Reset core 1 out of reset */
+
+ /* Reset core out of reset */
__raw_writel(0x0, base_ptr);
mb();
- reset_core1_base = base_ptr;
+ cpu_data[cpu].reset_core_base = base_ptr;
return 0;
}
-void __iomem *core1_reset_base(void)
+void __iomem *core_reset_base(unsigned int cpu)
{
- return reset_core1_base;
+ return cpu_data[cpu].reset_core_base;
}
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -172,12 +184,12 @@
preset_lpj = loops_per_jiffy;
- if (cold_boot_done == false) {
- if (msm8625_release_secondary()) {
- pr_err("Failed to release secondary core\n");
+ if (per_cpu(cold_boot_done, cpu) == false) {
+ if (msm8625_release_secondary(cpu)) {
+ pr_err("Failed to release core %u\n", cpu);
return -ENODEV;
}
- cold_boot_done = true;
+ per_cpu(cold_boot_done, cpu) = true;
}
/*
@@ -200,13 +212,13 @@
* and branch to the address found there.
*
* power_collapsed is the flag which will be updated for Powercollapse.
- * Once we are out of PC, as Core1 will be in the state of GDFS which
- * needs to be brought out by raising an SPI.
+ * Once we are out of PC, as secondary cores will be in the state of
+ * GDFS which needs to be brought out by raising an SPI.
*/
if (power_collapsed) {
- core1_gic_configure_and_raise();
- raise_clear_spi(1, true);
+ gic_configure_and_raise(cpu_data[cpu].ipc_irq, cpu);
+ raise_clear_spi(cpu, true);
} else {
gic_raise_softirq(cpumask_of(cpu), 1);
}
@@ -247,6 +259,34 @@
set_smp_cross_call(gic_raise_softirq);
}
+static void per_cpu_data(unsigned int cpu, unsigned int off,
+ unsigned int off1, unsigned int irq)
+{
+ cpu_data[cpu].reset_off = off;
+ cpu_data[cpu].offset = off1;
+ cpu_data[cpu].ipc_irq = irq;
+}
+
+static void enable_boot_remapper(unsigned long bit, unsigned int off)
+{
+ int value;
+
+ /* Enable boot remapper address */
+ value = __raw_readl(MSM_CFG_CTL_BASE + off);
+ __raw_writel(value | bit, MSM_CFG_CTL_BASE + off) ;
+ mb();
+}
+
+static void remapper_address(unsigned long phys, unsigned int off)
+{
+ /*
+ * Write the address of secondary startup into the
+ * boot remapper register. The secondary CPU branches to this address.
+ */
+ __raw_writel(phys, (MSM_CFG_CTL_BASE + off));
+ mb();
+}
+
static void __init msm8625_boot_vector_init(uint32_t *boot_vector,
unsigned long entry)
{
@@ -260,8 +300,8 @@
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
- int i, value;
- void __iomem *second_ptr;
+ int i, cpu, value;
+ void __iomem *cpu_ptr;
/*
* Initialise the present map, which describes the set of CPUs
@@ -272,25 +312,41 @@
scu_enable(scu_base_addr());
- /*
- * Write the address of secondary startup into the
- * boot remapper register. The secondary CPU branches to this address.
- */
- __raw_writel(MSM8625_SECONDARY_PHYS, (MSM_CFG_CTL_BASE + 0x34));
- mb();
-
- second_ptr = ioremap_nocache(MSM8625_SECONDARY_PHYS, SZ_8);
- if (!second_ptr) {
- pr_err("failed to ioremap for secondary core\n");
+ cpu_ptr = ioremap_nocache(MSM8625_CPU_PHYS, SZ_8);
+ if (!cpu_ptr) {
+ pr_err("failed to ioremap for secondary cores\n");
return;
}
- msm8625_boot_vector_init(second_ptr,
+ msm8625_boot_vector_init(cpu_ptr,
virt_to_phys(msm_secondary_startup));
- iounmap(second_ptr);
- /* Enable boot remapper address: bit 26 for core1 */
- value = __raw_readl(MSM_CFG_CTL_BASE + 0x30);
- __raw_writel(value | (0x4 << 24), MSM_CFG_CTL_BASE + 0x30) ;
- mb();
+ iounmap(cpu_ptr);
+
+ for_each_possible_cpu(cpu) {
+ switch (cpu) {
+ case 0:
+ break;
+ case 1:
+ remapper_address(MSM8625_CPU_PHYS, 0x34);
+ per_cpu_data(cpu, 0x0, 0x3c,
+ MSM8625_INT_ACSR_MP_CORE_IPC1);
+ enable_boot_remapper(BIT(26), 0x30);
+ break;
+ case 2:
+ remapper_address((MSM8625_CPU_PHYS >> 16), 0x4C);
+ per_cpu_data(cpu, 0x8, 0x50,
+ MSM8625_INT_ACSR_MP_CORE_IPC2);
+ enable_boot_remapper(BIT(25), 0x48);
+ break;
+ case 3:
+ value = __raw_readl(MSM_CFG_CTL_BASE + 0x4C);
+ remapper_address(value | MSM8625_CPU_PHYS, 0x4C);
+ per_cpu_data(cpu, 0xC, 0x50,
+ MSM8625_INT_ACSR_MP_CORE_IPC3);
+ enable_boot_remapper(BIT(26), 0x48);
+ break;
+ }
+
+ }
}
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index f6ed1ea..89003cf 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -42,6 +42,19 @@
*/
volatile int pen_release = -1;
+/*
+ * Write pen_release in a way that is guaranteed to be visible to all
+ * observers, irrespective of whether they're taking part in coherency
+ * or not. This is necessary for the hotplug code to work reliably.
+ */
+static void __cpuinit write_pen_release(int val)
+{
+ pen_release = val;
+ smp_wmb();
+ __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+ outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+}
+
static DEFINE_SPINLOCK(boot_lock);
void __cpuinit platform_secondary_init(unsigned int cpu)
@@ -56,6 +69,12 @@
gic_secondary_init(0);
/*
+ * let the primary processor know we're out of the
+ * pen, then head off into the C entry point
+ */
+ write_pen_release(-1);
+
+ /*
* Synchronise with the boot thread.
*/
spin_lock(&boot_lock);
@@ -165,7 +184,8 @@
return krait_release_secondary_sim(0xf9088000, cpu);
if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab())
+ cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab() ||
+ cpu_is_apq8064ab())
return krait_release_secondary(0x02088000, cpu);
if (cpu_is_msm8974())
@@ -176,17 +196,9 @@
}
DEFINE_PER_CPU(int, cold_boot_done);
-static int cold_boot_flags[] = {
- 0,
- SCM_FLAG_COLDBOOT_CPU1,
- SCM_FLAG_COLDBOOT_CPU2,
- SCM_FLAG_COLDBOOT_CPU3,
-};
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
- int ret;
- unsigned int flag = 0;
unsigned long timeout;
pr_debug("Starting secondary CPU %d\n", cpu);
@@ -194,19 +206,8 @@
/* Set preset_lpj to avoid subsequent lpj recalculations */
preset_lpj = loops_per_jiffy;
- if (cpu > 0 && cpu < ARRAY_SIZE(cold_boot_flags))
- flag = cold_boot_flags[cpu];
- else
- __WARN();
-
if (per_cpu(cold_boot_done, cpu) == false) {
- ret = scm_set_boot_addr(virt_to_phys(msm_secondary_startup),
- flag);
- if (ret == 0)
- release_secondary(cpu);
- else
- printk(KERN_DEBUG "Failed to set secondary core boot "
- "address\n");
+ release_secondary(cpu);
per_cpu(cold_boot_done, cpu) = true;
}
@@ -224,9 +225,7 @@
* Note that "pen_release" is the hardware CPU ID, whereas
* "cpu" is Linux's internal ID.
*/
- pen_release = cpu_logical_map(cpu);
- __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
- outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+ write_pen_release(cpu_logical_map(cpu));
/*
* Send the secondary CPU a soft interrupt, thereby causing
@@ -241,8 +240,6 @@
if (pen_release == -1)
break;
- dmac_inv_range((char *)&pen_release,
- (char *)&pen_release + sizeof(pen_release));
udelay(10);
}
@@ -274,6 +271,28 @@
set_smp_cross_call(gic_raise_softirq);
}
+static int cold_boot_flags[] __initdata = {
+ 0,
+ SCM_FLAG_COLDBOOT_CPU1,
+ SCM_FLAG_COLDBOOT_CPU2,
+ SCM_FLAG_COLDBOOT_CPU3,
+};
+
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
+ int cpu, map;
+ unsigned int flags = 0;
+
+ for_each_present_cpu(cpu) {
+ map = cpu_logical_map(cpu);
+ if (map > ARRAY_SIZE(cold_boot_flags)) {
+ set_cpu_present(cpu, false);
+ __WARN();
+ continue;
+ }
+ flags |= cold_boot_flags[map];
+ }
+
+ if (scm_set_boot_addr(virt_to_phys(msm_secondary_startup), flags))
+ pr_warn("Failed to set CPU boot address\n");
}
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 60ee8f0..5c40750 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -30,6 +30,7 @@
#include <mach/system.h>
#include <mach/scm.h>
#include <mach/socinfo.h>
+#include <mach/msm-krait-l2-accessors.h>
#include <asm/cacheflush.h>
#include <asm/hardware/gic.h>
#include <asm/pgtable.h>
@@ -413,10 +414,63 @@
}
EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
+struct reg_data {
+ uint32_t reg;
+ uint32_t val;
+};
-/******************************************************************************
- *
- *****************************************************************************/
+static struct reg_data reg_saved_state[] = {
+ { .reg = 0x4501, },
+ { .reg = 0x5501, },
+ { .reg = 0x6501, },
+ { .reg = 0x7501, },
+ { .reg = 0x0500, },
+};
+
+static unsigned int active_vdd;
+static bool msm_pm_save_cp15;
+static const unsigned int pc_vdd = 0x98;
+
+static void msm_pm_save_cpu_reg(void)
+{
+ int i;
+
+ /* Only on core0 */
+ if (smp_processor_id())
+ return;
+
+ /**
+ * On some targets, L2 PC will turn off may reset the core
+ * configuration for the mux and the default may not make the core
+ * happy when it resumes.
+ * Save the active vdd, and set the core vdd to QSB max vdd, so that
+ * when the core resumes, it is capable of supporting the current QSB
+ * rate. Then restore the active vdd before switching the acpuclk rate.
+ */
+ if (msm_pm_get_l2_flush_flag() == 1) {
+ active_vdd = msm_spm_get_vdd(0);
+ for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
+ reg_saved_state[i].val =
+ get_l2_indirect_reg(reg_saved_state[i].reg);
+ msm_spm_set_vdd(0, pc_vdd);
+ }
+}
+
+static void msm_pm_restore_cpu_reg(void)
+{
+ int i;
+
+ /* Only on core0 */
+ if (smp_processor_id())
+ return;
+
+ if (msm_pm_get_l2_flush_flag() == 1) {
+ for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
+ set_l2_indirect_reg(reg_saved_state[i].reg,
+ reg_saved_state[i].val);
+ msm_spm_set_vdd(0, active_vdd);
+ }
+}
static void *msm_pm_idle_rs_limits;
static bool msm_pm_use_qtimer;
@@ -558,8 +612,14 @@
pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
cpu, __func__, saved_acpuclk_rate);
+ if (msm_pm_save_cp15)
+ msm_pm_save_cpu_reg();
+
collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
+ if (msm_pm_save_cp15)
+ msm_pm_restore_cpu_reg();
+
if (cpu_online(cpu)) {
if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
pr_info("CPU%u: %s: restore clock rate to %lu\n",
@@ -593,9 +653,12 @@
return collapsed;
}
-static void msm_pm_qtimer_available(void)
+static void msm_pm_target_init(void)
{
- if (machine_is_msm8974())
+ if (cpu_is_apq8064())
+ msm_pm_save_cp15 = true;
+
+ if (cpu_is_msm8974())
msm_pm_use_qtimer = true;
}
@@ -718,11 +781,17 @@
switch (mode) {
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+ if (num_online_cpus() > 1) {
+ allow = false;
+ break;
+ }
+ /* fall through */
case MSM_PM_SLEEP_MODE_RETENTION:
if (!allow)
break;
- if (num_online_cpus() > 1) {
+ if (msm_pm_retention_tz_call &&
+ num_online_cpus() > 1) {
allow = false;
break;
}
@@ -1087,7 +1156,7 @@
msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
suspend_set_ops(&msm_pm_ops);
- msm_pm_qtimer_available();
+ msm_pm_target_init();
hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
msm_cpuidle_init();
platform_driver_register(&msm_pc_counter_driver);
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index ed15a0c..7bc4fe0 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -211,7 +211,10 @@
char *key = NULL;
uint32_t val = 0;
int ret = 0;
- int flag = 0;
+ uint32_t vaddr_val;
+
+ pdata.p_addr = 0;
+ vaddr_val = 0;
key = "qcom,mode";
ret = of_property_read_u32(pdev->dev.of_node, key, &val);
@@ -223,24 +226,43 @@
key = "qcom,phy-addr";
ret = of_property_read_u32(pdev->dev.of_node, key, &val);
- if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS)
- goto fail;
- if (!ret) {
+ if (!ret)
pdata.p_addr = val;
- flag++;
- }
+
key = "qcom,virt-addr";
- ret = of_property_read_u32(pdev->dev.of_node, key, &val);
- if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT)
- goto fail;
- if (!ret) {
- pdata.v_addr = (void *)val;
- flag++;
- }
+ ret = of_property_read_u32(pdev->dev.of_node, key, &vaddr_val);
- if (pdata.mode == MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR && (flag != 2)) {
- key = "addresses for boot remap";
+ switch (pdata.mode) {
+ case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
+ if (!pdata.p_addr) {
+ key = "qcom,phy-addr";
+ goto fail;
+ }
+ break;
+ case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
+ if (!vaddr_val)
+ goto fail;
+
+ pdata.v_addr = (void *)vaddr_val;
+ break;
+ case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
+ if (!vaddr_val)
+ goto fail;
+
+ pdata.v_addr = ioremap_nocache(vaddr_val, SZ_8);
+
+ pdata.p_addr = allocate_contiguous_ebi_nomap(SZ_8, SZ_64K);
+ if (!pdata.p_addr) {
+ key = "qcom,phy-addr";
+ goto fail;
+ }
+ break;
+ case MSM_PM_BOOT_CONFIG_TZ:
+ break;
+ default:
+ pr_err("%s: Unsupported boot mode %d",
+ __func__, pdata.mode);
goto fail;
}
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 10c5445..427e39f 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -487,7 +487,7 @@
void __iomem *base_ptr;
unsigned int value = 0;
- base_ptr = core1_reset_base();
+ base_ptr = core_reset_base(1);
if (!base_ptr)
return;
diff --git a/arch/arm/mach-msm/qdsp5/adsp_driver.c b/arch/arm/mach-msm/qdsp5/adsp_driver.c
index 9d261ae..6419bd0 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_driver.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_driver.c
@@ -139,7 +139,7 @@
pr_err("%s: could not get flags for the handle\n", __func__);
goto flag_error;
}
- temp_ptr = ion_map_kernel(region->client, region->handle, ionflag);
+ temp_ptr = ion_map_kernel(region->client, region->handle);
if (IS_ERR_OR_NULL(temp_ptr)) {
pr_err("%s: could not get virtual address\n", __func__);
goto map_error;
@@ -267,7 +267,7 @@
module->name, vaddr, len);
return ret;
}
- if ((region->ion_flag == CACHED) && region->handle) {
+ if ((region->ion_flag == ION_FLAG_CACHED) && region->handle) {
len = ((((len) + 31) & (~31)) + 32);
ret = msm_ion_do_cache_op(region->client, region->handle,
(void *)paddr, len, cmd);
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index ac7cca3..46a80d7 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -1716,7 +1716,7 @@
MM_DBG("allocating mem sz = %d\n", mem_sz);
handle = ion_alloc(client, mem_sz, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1742,7 +1742,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers,freeing instance 0x%08x\n",
(int)audio);
@@ -1758,7 +1758,7 @@
mem_sz = (PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
MM_DBG("allocating mem sz = %d\n", mem_sz);
handle = ion_alloc(client, mem_sz,
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate I/P buffers\n");
rc = -ENOMEM;
@@ -1785,8 +1785,7 @@
goto input_buff_get_flags_error;
}
- audio->map_v_read = ion_map_kernel(client,
- handle, ionflag);
+ audio->map_v_read = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read buffers, freeing instance \
0x%08x\n", (int)audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index 2e64a09..c86c1dd 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -1370,7 +1370,7 @@
MM_DBG("allocating mem sz = %d\n", dma_size);
handle = ion_alloc(client, dma_size, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1398,7 +1398,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_read = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
(int)audio);
@@ -1414,7 +1414,7 @@
MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
handle = ion_alloc(client, BUFFER_SIZE,
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate I/P buffers\n");
rc = -ENOMEM;
@@ -1444,8 +1444,7 @@
goto input_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client,
- handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_ac3.c b/arch/arm/mach-msm/qdsp5/audio_ac3.c
index 63904fb..e453ec5 100644
--- a/arch/arm/mach-msm/qdsp5/audio_ac3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_ac3.c
@@ -1029,7 +1029,7 @@
handle = ion_alloc(audio->client,
(config.buffer_size *
config.buffer_count),
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to alloc I/P buffs\n");
audio->input_buff_handle = NULL;
@@ -1067,8 +1067,7 @@
}
audio->map_v_read = ion_map_kernel(
- audio->client,
- handle, ionflag);
+ audio->client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
ion_free(audio->client, handle);
@@ -1588,7 +1587,7 @@
audio->client = client;
handle = ion_alloc(client, DMASZ, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1614,7 +1613,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers,freeing instance 0x%08x\n",
(int)audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 8aa102a..0792e3f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -981,7 +981,7 @@
handle = ion_alloc(audio->client,
(config.buffer_size *
config.buffer_count),
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to alloc I/P buffs\n");
audio->input_buff_handle = NULL;
@@ -1018,8 +1018,7 @@
break;
}
audio->map_v_read = ion_map_kernel(
- audio->client,
- handle, ionflag);
+ audio->client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read buf\n");
ion_free(audio->client, handle);
@@ -1536,7 +1535,7 @@
audio->client = client;
handle = ion_alloc(client, mem_sz, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1562,7 +1561,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index 4effc8e..0742686 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -1336,7 +1336,7 @@
if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
handle = ion_alloc(client, BUFFER_SIZE,
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate write buffers\n");
rc = -ENOMEM;
@@ -1366,8 +1366,7 @@
goto input_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client,
- handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index 83320f3..7d37cea 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -977,7 +977,7 @@
handle = ion_alloc(audio->client,
(config.buffer_size *
config.buffer_count),
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to alloc I/P buffs\n");
audio->input_buff_handle = NULL;
@@ -1014,8 +1014,7 @@
break;
}
audio->map_v_read = ion_map_kernel(
- audio->client,
- handle, ionflag);
+ audio->client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map mem for read buf\n");
ion_free(audio->client, handle);
@@ -1600,7 +1599,7 @@
audio->client = client;
handle = ion_alloc(client, mem_sz, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
goto output_buff_alloc_error;
@@ -1625,7 +1624,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index c0486db..155b0e1 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -966,7 +966,7 @@
handle = ion_alloc(audio->client,
(config.buffer_size *
config.buffer_count),
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to alloc I/P buffs\n");
audio->input_buff_handle = NULL;
@@ -1003,8 +1003,7 @@
break;
}
audio->map_v_read = ion_map_kernel(
- audio->client,
- handle, ionflag);
+ audio->client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map mem"
" for read buf\n");
@@ -1527,7 +1526,7 @@
audio->client = client;
handle = ion_alloc(client, mem_sz, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1553,7 +1552,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index 9bf0e83..89ad974 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -1310,7 +1310,7 @@
MM_DBG("allocating mem sz = %d\n", dma_size);
handle = ion_alloc(client, dma_size, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1338,7 +1338,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_read = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
(int)audio);
@@ -1353,7 +1353,7 @@
if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
handle = ion_alloc(client, BUFFER_SIZE,
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate I/P buffers\n");
rc = -ENOMEM;
@@ -1383,8 +1383,7 @@
goto input_buff_alloc_error;
}
- audio->map_v_write = ion_map_kernel(client,
- handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index a067b83..8120d7b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -741,7 +741,7 @@
pr_err("%s: could not get flags for the handle\n", __func__);
goto flag_error;
}
- kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag);
+ kvaddr = (unsigned long)ion_map_kernel(audio->client, handle);
if (IS_ERR_OR_NULL((void *)kvaddr)) {
pr_err("%s: could not get virtual address\n", __func__);
goto map_error;
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index cef3d99..b8c64be 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -1095,7 +1095,7 @@
goto flag_error;
}
- temp_ptr = ion_map_kernel(audio->client, handle, ionflag);
+ temp_ptr = ion_map_kernel(audio->client, handle);
if (IS_ERR_OR_NULL(temp_ptr)) {
pr_err("%s: could not get virtual address\n", __func__);
goto map_error;
@@ -1525,7 +1525,7 @@
handle = ion_alloc(audio->client,
(config.buffer_size *
config.buffer_count),
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to alloc I/P buffs\n");
rc = -ENOMEM;
@@ -1558,8 +1558,7 @@
}
audio->map_v_read = ion_map_kernel(
- audio->client,
- handle, ionflag);
+ audio->client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
@@ -2254,7 +2253,7 @@
MM_DBG("memsz = %d\n", mem_sz);
handle = ion_alloc(client, mem_sz, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -2280,7 +2279,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_mvs.c b/arch/arm/mach-msm/qdsp5/audio_mvs.c
index 158dd46..d45043d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mvs.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mvs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -326,6 +326,7 @@
wait_queue_head_t wait;
wait_queue_head_t mode_wait;
+ wait_queue_head_t in_wait;
wait_queue_head_t out_wait;
struct mutex lock;
@@ -1142,6 +1143,7 @@
mutex_unlock(&audio->in_lock);
+ wake_up(&audio->in_wait);
dl_reply.valid_frame_info_ptr = cpu_to_be32(0x00000001);
dl_reply.frame_mode = cpu_to_be32(audio->frame_mode);
@@ -1187,6 +1189,9 @@
rpc_hdr_len);
break;
+ } else if ((rpc_hdr_len == 0) &&
+ (audio->state == AUDIO_MVS_CLOSED)) {
+ break;
} else if (rpc_hdr_len < RPC_COMMON_HDR_SZ) {
continue;
} else {
@@ -1353,8 +1358,11 @@
mutex_lock(&audio->lock);
if (audio->state == AUDIO_MVS_STARTED)
audio_mvs_stop(audio);
- audio_mvs_free_buf(audio);
audio->state = AUDIO_MVS_CLOSED;
+ msm_rpc_read_wakeup(audio->rpc_endpt);
+ msm_rpc_close(audio->rpc_endpt);
+ audio->task = NULL;
+ audio_mvs_free_buf(audio);
mutex_unlock(&audio->lock);
MM_DBG("Release done\n");
@@ -1443,40 +1451,52 @@
MM_DBG("\n");
- mutex_lock(&audio->in_lock);
- if (audio->state == AUDIO_MVS_STARTED) {
- if (count <= sizeof(struct msm_audio_mvs_frame)) {
- if (!list_empty(&audio->free_in_queue)) {
- buf_node =
- list_first_entry(&audio->free_in_queue,
+ rc = wait_event_interruptible_timeout(audio->in_wait,
+ (!list_empty(&audio->free_in_queue) ||
+ audio->state == AUDIO_MVS_STOPPED), 1 * HZ);
+ if (rc > 0) {
+ mutex_lock(&audio->in_lock);
+ if (audio->state == AUDIO_MVS_STARTED) {
+ if (count <= sizeof(struct msm_audio_mvs_frame)) {
+ if (!list_empty(&audio->free_in_queue)) {
+ buf_node = list_first_entry(
+ &audio->free_in_queue,
struct audio_mvs_buf_node,
list);
- list_del(&buf_node->list);
+ list_del(&buf_node->list);
- rc = copy_from_user(&buf_node->frame,
- buf,
- count);
+ rc = copy_from_user(&buf_node->frame,
+ buf,
+ count);
- list_add_tail(&buf_node->list,
- &audio->in_queue);
+ list_add_tail(&buf_node->list,
+ &audio->in_queue);
+ } else {
+ MM_ERR("No free DL buffs\n");
+ }
} else {
- MM_ERR("No free DL buffs\n");
+ MM_ERR("Write count %d > sizeof(frame) %d",
+ count,
+ sizeof(struct msm_audio_mvs_frame));
+
+ rc = -ENOMEM;
}
} else {
- MM_ERR("Write count %d < sizeof(frame) %d",
- count,
- sizeof(struct msm_audio_mvs_frame));
+ MM_ERR("Write performed in invalid state %d\n",
+ audio->state);
- rc = -ENOMEM;
+ rc = -EPERM;
}
+ mutex_unlock(&audio->in_lock);
+ } else if (rc == 0) {
+ MM_ERR("%s: No free DL buffs\n", __func__);
+
+ rc = -ETIMEDOUT;
} else {
- MM_ERR("Write performed in invalid state %d\n",
- audio->state);
+ MM_ERR("%s: write was interrupted\n", __func__);
- rc = -EPERM;
+ rc = -ERESTARTSYS;
}
- mutex_unlock(&audio->in_lock);
-
return rc;
}
@@ -1593,26 +1613,6 @@
MM_DBG("\n");
- memset(&audio_mvs_info, 0, sizeof(audio_mvs_info));
- mutex_init(&audio_mvs_info.lock);
- mutex_init(&audio_mvs_info.in_lock);
- mutex_init(&audio_mvs_info.out_lock);
-
- init_waitqueue_head(&audio_mvs_info.wait);
- init_waitqueue_head(&audio_mvs_info.mode_wait);
- init_waitqueue_head(&audio_mvs_info.out_wait);
-
- INIT_LIST_HEAD(&audio_mvs_info.in_queue);
- INIT_LIST_HEAD(&audio_mvs_info.free_in_queue);
- INIT_LIST_HEAD(&audio_mvs_info.out_queue);
- INIT_LIST_HEAD(&audio_mvs_info.free_out_queue);
-
- wake_lock_init(&audio_mvs_info.suspend_lock,
- WAKE_LOCK_SUSPEND,
- "audio_mvs_suspend");
- pm_qos_add_request(&audio_mvs_info.pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
-
audio_mvs_info.rpc_endpt = msm_rpc_connect_compatible(MVS_PROG,
MVS_VERS_COMP_VER2,
MSM_RPC_UNINTERRUPTIBLE);
@@ -1696,6 +1696,27 @@
};
static int __init audio_mvs_init(void)
{
+ memset(&audio_mvs_info, 0, sizeof(audio_mvs_info));
+ mutex_init(&audio_mvs_info.lock);
+ mutex_init(&audio_mvs_info.in_lock);
+ mutex_init(&audio_mvs_info.out_lock);
+
+ init_waitqueue_head(&audio_mvs_info.wait);
+ init_waitqueue_head(&audio_mvs_info.mode_wait);
+ init_waitqueue_head(&audio_mvs_info.in_wait);
+ init_waitqueue_head(&audio_mvs_info.out_wait);
+
+ INIT_LIST_HEAD(&audio_mvs_info.in_queue);
+ INIT_LIST_HEAD(&audio_mvs_info.free_in_queue);
+ INIT_LIST_HEAD(&audio_mvs_info.out_queue);
+ INIT_LIST_HEAD(&audio_mvs_info.free_out_queue);
+
+ wake_lock_init(&audio_mvs_info.suspend_lock,
+ WAKE_LOCK_SUSPEND,
+ "audio_mvs_suspend");
+ pm_qos_add_request(&audio_mvs_info.pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
return misc_register(&audio_mvs_misc);
}
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 340bcc6..3eb72c8 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -823,7 +823,7 @@
pr_err("%s: could not get flags for the handle\n", __func__);
goto flag_error;
}
- kvaddr = (unsigned long)ion_map_kernel(audio->client, handle, ionflag);
+ kvaddr = (unsigned long)ion_map_kernel(audio->client, handle);
if (IS_ERR_OR_NULL((void *)kvaddr)) {
pr_err("%s: could not get virtual address\n", __func__);
goto map_error;
@@ -1576,7 +1576,7 @@
MM_DBG("memsz = %d\n", mem_sz);
handle = ion_alloc(client, mem_sz, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1602,7 +1602,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 2da1f19..68ffcfef 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -843,7 +843,7 @@
MM_DBG("allocating mem sz = %d\n", DMASZ);
handle = ion_alloc(client, DMASZ, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -871,7 +871,7 @@
goto output_buff_get_flags_error;
}
- audio->data = ion_map_kernel(client, handle, ionflag);
+ audio->data = ion_map_kernel(client, handle);
if (IS_ERR(audio->data)) {
MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
(int)audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index 1a0c333..876c909 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -967,7 +967,7 @@
handle = ion_alloc(audio->client,
(config.buffer_size *
config.buffer_count),
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to alloc I/P buffs\n");
audio->input_buff_handle = NULL;
@@ -1004,8 +1004,7 @@
break;
}
audio->map_v_read = ion_map_kernel(
- audio->client,
- handle, ionflag);
+ audio->client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read buf\n");
ion_free(audio->client, handle);
@@ -1525,7 +1524,7 @@
audio->client = client;
handle = ion_alloc(client, mem_sz, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1551,7 +1550,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index ee079bc..6ca3382 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -1312,7 +1312,7 @@
MM_DBG("allocating mem sz = %d\n", dma_size);
handle = ion_alloc(client, dma_size, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1340,7 +1340,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_read = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
(int)audio);
@@ -1355,7 +1355,7 @@
if (audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) {
MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
handle = ion_alloc(client, BUFFER_SIZE,
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate I/P buffers\n");
rc = -ENOMEM;
@@ -1385,8 +1385,7 @@
goto input_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client,
- handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index 0a77b58..6d520b4 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -1045,7 +1045,7 @@
handle = ion_alloc(audio->client,
(config.buffer_size *
config.buffer_count),
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to alloc I/P buffs\n");
audio->input_buff_handle = NULL;
@@ -1083,8 +1083,7 @@
}
audio->map_v_read = ion_map_kernel(
- audio->client,
- handle, ionflag);
+ audio->client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
ion_free(audio->client, handle);
@@ -1678,7 +1677,7 @@
audio->client = client;
handle = ion_alloc(client, mem_sz, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1704,7 +1703,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index 82fc3f9..a08f3c9 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -1042,7 +1042,7 @@
handle = ion_alloc(audio->client,
(config.buffer_size *
config.buffer_count),
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to alloc I/P buffs\n");
audio->input_buff_handle = NULL;
@@ -1080,8 +1080,7 @@
}
audio->map_v_read = ion_map_kernel(
- audio->client,
- handle, ionflag);
+ audio->client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
ion_free(audio->client, handle);
@@ -1673,7 +1672,7 @@
audio->client = client;
handle = ion_alloc(client, mem_sz, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1699,7 +1698,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
index 733b7a1..e396186 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
@@ -5,6 +5,7 @@
*
* Copyright (C) 2008 HTC Corporation
* Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2012 The Linux Foundation. All rights reserved.
*
* All source code in this file is licensed under the following license except
* where indicated.
@@ -34,7 +35,7 @@
#include <linux/dma-mapping.h>
#include <linux/msm_audio.h>
#include <linux/msm_audio_sbc.h>
-#include <linux/android_pmem.h>
+#include <linux/msm_ion.h>
#include <linux/memory_alloc.h>
#include <mach/iommu.h>
@@ -115,6 +116,8 @@
int stopped; /* set when stopped, cleared on flush */
int abort; /* set when error, like sample rate mismatch */
char *build_id;
+ struct ion_client *client;
+ struct ion_handle *output_buff_handle;
};
static struct audio_a2dp_in the_audio_a2dp_in;
@@ -848,10 +851,11 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- iounmap(audio->msm_map);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
audio->data = NULL;
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
return 0;
}
@@ -861,6 +865,11 @@
struct audio_a2dp_in *audio = &the_audio_a2dp_in;
int rc;
int encid;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
mutex_lock(&audio->lock);
if (audio->opened) {
@@ -868,22 +877,56 @@
goto done;
}
- audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
- if (audio->phys) {
- audio->msm_map = ioremap(audio->phys, DMASZ);
- if (IS_ERR(audio->msm_map)) {
- MM_ERR("could not map the phys address to kernel"
- "space\n");
+ client = msm_ion_client_create(UINT_MAX, "Audio_a2dp_in_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- goto done;
- }
- audio->data = (u8 *)audio->msm_map;
- } else {
- MM_ERR("could not allocate DMA buffers\n");
- rc = -ENOMEM;
- goto done;
+ goto client_create_error;
}
+ audio->client = client;
+
+ MM_DBG("allocating mem sz = %d\n", DMASZ);
+ handle = ion_alloc(client, DMASZ, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto output_buff_get_flags_error;
+ }
+
+ audio->msm_map = ion_map_kernel(client, handle);
+ if (IS_ERR(audio->data)) {
+ MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ audio->data = (char *)audio->msm_map;
+
MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
(int) audio->data, (int) audio->phys);
@@ -953,6 +996,13 @@
mutex_unlock(&audio->lock);
return rc;
evt_error:
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
msm_adsp_put(audio->audrec);
audpreproc_aenc_free(audio->enc_id);
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index 2f03cd0..f1951f7 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -803,7 +803,7 @@
audio->client = client;
handle = ion_alloc(client, DMASZ, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -828,7 +828,7 @@
goto buff_get_flags_error;
}
- audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_read = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
index 1180e8d..6e95dc5 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
@@ -1363,7 +1363,7 @@
MM_DBG("allocating mem sz = %d\n", DMASZ);
handle = ion_alloc(client, DMASZ, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1391,7 +1391,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_read = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
(int)audio);
@@ -1458,7 +1458,7 @@
MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
handle = ion_alloc(client, BUFFER_SIZE,
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate I/P buffers\n");
rc = -ENOMEM;
@@ -1488,8 +1488,7 @@
goto input_buff_alloc_error;
}
- audio->map_v_write = ion_map_kernel(client,
- handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_lpa.c b/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
index 60f43b9..7ec0617 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_lpa.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -27,7 +27,7 @@
#include <linux/delay.h>
#include <linux/earlysuspend.h>
#include <linux/list.h>
-#include <linux/android_pmem.h>
+#include <linux/msm_ion.h>
#include <asm/atomic.h>
#include <asm/ioctls.h>
#include <mach/msm_adsp.h>
@@ -136,9 +136,9 @@
union msm_audio_event_payload payload;
};
-struct audlpa_pmem_region {
+struct audlpa_ion_region {
struct list_head list;
- struct file *file;
+ struct ion_handle *handle;
int fd;
void *vaddr;
unsigned long paddr;
@@ -170,7 +170,7 @@
static void audio_dsp_event(void *private, unsigned id, uint16_t *msg);
static void audlpa_post_event(struct audio *audio, int type,
union msm_audio_event_payload payload);
-static unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up);
static void audlpa_async_send_data(struct audio *audio, unsigned needed,
uint32_t *payload);
@@ -778,7 +778,7 @@
if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE ||
drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
mutex_lock(&audio->lock);
- audlpa_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ audlpa_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
drv_evt->payload.aio_buf.buf_len, 0);
mutex_unlock(&audio->lock);
}
@@ -788,94 +788,118 @@
return rc;
}
-static int audlpa_pmem_check(struct audio *audio,
+static int audlpa_ion_check(struct audio *audio,
void *vaddr, unsigned long len)
{
- struct audlpa_pmem_region *region_elt;
- struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+ struct audlpa_ion_region *region_elt;
+ struct audlpa_ion_region t = {.vaddr = vaddr, .len = len };
- list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
OVERLAPS(region_elt, &t)) {
- MM_ERR("region (vaddr %p len %ld)"
+ MM_ERR("[%p]:region (vaddr %p len %ld)"
" clashes with registered region"
" (vaddr %p paddr %p len %ld)\n",
- vaddr, len,
+ audio, vaddr, len,
region_elt->vaddr,
- (void *)region_elt->paddr,
- region_elt->len);
+ (void *)region_elt->paddr, region_elt->len);
return -EINVAL;
}
}
return 0;
}
-
-static int audlpa_pmem_add(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audlpa_ion_add(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- unsigned long paddr, kvaddr, len;
- struct file *file;
- struct audlpa_pmem_region *region;
+ ion_phys_addr_t paddr;
+ size_t len;
+ unsigned long kvaddr;
+ struct audlpa_ion_region *region;
int rc = -EINVAL;
+ struct ion_handle *handle;
+ unsigned long ionflag;
- MM_DBG("\n"); /* Macro prints the file name and function */
+ MM_ERR("\n"); /* Macro prints the file name and function */
region = kmalloc(sizeof(*region), GFP_KERNEL);
if (!region) {
rc = -ENOMEM;
goto end;
}
-
- if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
- kfree(region);
- goto end;
+ handle = ion_import_dma_buf(audio->client, info->fd);
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_err("%s: could not get handle of the given fd\n", __func__);
+ goto import_error;
}
-
- rc = audlpa_pmem_check(audio, info->vaddr, len);
+ rc = ion_handle_get_flags(audio->client, handle, &ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n", __func__);
+ goto flag_error;
+ }
+ kvaddr = (unsigned long)ion_map_kernel(audio->client, handle);
+ if (IS_ERR_OR_NULL((void *)kvaddr)) {
+ pr_err("%s: could not get virtual address\n", __func__);
+ goto map_error;
+ }
+ rc = ion_phys(audio->client, handle, &paddr, &len);
+ if (rc) {
+ pr_err("%s: could not get physical address\n", __func__);
+ goto ion_error;
+ }
+ rc = audlpa_ion_check(audio, info->vaddr, len);
if (rc < 0) {
- put_pmem_file(file);
- kfree(region);
- goto end;
+ MM_ERR("audpcm_ion_check failed\n");
+ goto ion_error;
}
-
+ region->handle = handle;
region->vaddr = info->vaddr;
region->fd = info->fd;
region->paddr = paddr;
region->kvaddr = kvaddr;
region->len = len;
- region->file = file;
region->ref_cnt = 0;
- MM_DBG("add region paddr %lx vaddr %p, len %lu\n", region->paddr,
- region->vaddr, region->len);
- list_add_tail(®ion->list, &audio->pmem_region_queue);
+ MM_DBG("[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+ audio, region->paddr, region->vaddr,
+ region->len, region->kvaddr);
+ list_add_tail(®ion->list, &audio->ion_region_queue);
+
+ return rc;
+
+ion_error:
+ ion_unmap_kernel(audio->client, handle);
+map_error:
+flag_error:
+ ion_free(audio->client, handle);
+import_error:
+ kfree(region);
end:
return rc;
}
-static int audlpa_pmem_remove(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audlpa_ion_remove(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
struct list_head *ptr, *next;
int rc = -EINVAL;
- MM_DBG("info fd %d vaddr %p\n", info->fd, info->vaddr);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audlpa_ion_region, list);
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audlpa_pmem_region, list);
-
- if ((region->fd == info->fd) &&
+ if (region != NULL && (region->fd == info->fd) &&
(region->vaddr == info->vaddr)) {
if (region->ref_cnt) {
- MM_DBG("region %p in use ref_cnt %d\n",
- region, region->ref_cnt);
+ MM_DBG("%s[%p]:region %p in use ref_cnt %d\n",
+ __func__, audio, region,
+ region->ref_cnt);
break;
}
MM_DBG("remove region fd %d vaddr %p\n",
info->fd, info->vaddr);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
rc = 0;
break;
@@ -885,23 +909,20 @@
return rc;
}
-static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
- unsigned long len, struct audlpa_pmem_region **region)
+static int audlpa_ion_lookup_vaddr(struct audio *audio, void *addr,
+ unsigned long len, struct audlpa_ion_region **region)
{
- struct audlpa_pmem_region *region_elt;
-
+ struct audlpa_ion_region *region_elt;
int match_count = 0;
-
*region = NULL;
/* returns physical address or zero */
- list_for_each_entry(region_elt, &audio->pmem_region_queue,
- list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len) {
/* offset since we could pass vaddr inside a registerd
- * pmem buffer
+ * ion buffer
*/
match_count++;
@@ -911,13 +932,16 @@
}
if (match_count > 1) {
- MM_ERR("multiple hits for vaddr %p, len %ld\n", addr, len);
- list_for_each_entry(region_elt,
- &audio->pmem_region_queue, list) {
+ MM_ERR("%s[%p]:multiple hits for vaddr %p, len %ld\n",
+ __func__, audio, addr, len);
+ list_for_each_entry(region_elt, &audio->ion_region_queue,
+ list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len)
- MM_ERR("\t%p, %ld --> %p\n", region_elt->vaddr,
+ MM_ERR("\t%s[%p]:%p, %ld --> %p\n",
+ __func__, audio,
+ region_elt->vaddr,
region_elt->len,
(void *)region_elt->paddr);
}
@@ -925,17 +949,17 @@
return *region ? 0 : -1;
}
-
-unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
unsigned long paddr;
int ret;
- ret = audlpa_pmem_lookup_vaddr(audio, addr, len, ®ion);
+ ret = audlpa_ion_lookup_vaddr(audio, addr, len, ®ion);
if (ret) {
- MM_ERR("lookup (%p, %ld) failed\n", addr, len);
+ MM_ERR("%s[%p]:lookup (%p, %ld) failed\n",
+ __func__, audio, addr, len);
return 0;
}
if (ref_up)
@@ -969,7 +993,7 @@
buf_node->buf.buf_addr, buf_node->buf.buf_len,
buf_node->buf.data_len);
- buf_node->paddr = audlpa_pmem_fixup(
+ buf_node->paddr = audlpa_ion_fixup(
audio, buf_node->buf.buf_addr,
buf_node->buf.buf_len, 1);
@@ -1269,25 +1293,26 @@
audio->drv_status &= ~ADRV_STATUS_PAUSE;
break;
- case AUDIO_REGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_REGISTER_PMEM\n");
- if (copy_from_user(&info, (void *) arg, sizeof(info)))
+ case AUDIO_REGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_DBG("AUDIO_REGISTER_ION\n");
+ if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audlpa_pmem_add(audio, &info);
+ rc = audlpa_ion_add(audio, &info);
break;
}
- case AUDIO_DEREGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- MM_DBG("AUDIO_DEREGISTER_PMEM\n");
- if (copy_from_user(&info, (void *) arg, sizeof(info)))
+ case AUDIO_DEREGISTER_ION: {
+ struct msm_audio_ion_info info;
+ MM_DBG("AUDIO_DEREGISTER_ION\n");
+ if (copy_from_user(&info, (void *) arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audlpa_pmem_remove(audio, &info);
+ rc = audlpa_ion_remove(audio, &info);
break;
}
+
case AUDIO_ASYNC_WRITE:
if (audio->drv_status & ADRV_STATUS_FSYNC)
rc = -EBUSY;
@@ -1373,15 +1398,16 @@
return audlpa_async_fsync(audio);
}
-static void audlpa_reset_pmem_region(struct audio *audio)
+static void audpcm_reset_ion_region(struct audio *audio)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
struct list_head *ptr, *next;
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audlpa_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audlpa_ion_region, list);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(audio->client, region->handle);
+ ion_free(audio->client, region->handle);
kfree(region);
}
@@ -1399,7 +1425,7 @@
auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
audio_disable(audio);
audlpa_async_flush(audio);
- audlpa_reset_pmem_region(audio);
+ audpcm_reset_ion_region(audio);
msm_adsp_put(audio->audplay);
audpp_adec_free(audio->dec_id);
@@ -1410,13 +1436,12 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audlpa_reset_event_queue(audio);
- iounmap(audio->data);
- free_contiguous_memory_by_paddr(audio->phys);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
if (audio->dentry)
debugfs_remove(audio->dentry);
#endif
+ ion_client_destroy(audio->client);
kfree(audio);
return 0;
}
@@ -1589,7 +1614,7 @@
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->write_wait);
INIT_LIST_HEAD(&audio->out_queue);
- INIT_LIST_HEAD(&audio->pmem_region_queue);
+ INIT_LIST_HEAD(&audio->ion_region_queue);
INIT_LIST_HEAD(&audio->free_event_queue);
INIT_LIST_HEAD(&audio->event_queue);
init_waitqueue_head(&audio->wait);
@@ -1650,13 +1675,19 @@
break;
}
}
+
+ audio->client = msm_ion_client_create(UINT_MAX, "Audio_LPA_Client");
+ if (IS_ERR_OR_NULL(audio->client)) {
+ pr_err("Unable to create ION client\n");
+ goto err;
+ }
+ MM_DBG("Ion client created\n");
+
done:
return rc;
event_err:
msm_adsp_put(audio->audplay);
err:
- iounmap(audio->data);
- free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
MM_INFO("audio instance 0x%08x freeing\n", (int)audio);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_out.c b/arch/arm/mach-msm/qdsp5v2/audio_out.c
index 147ac77..e5c59ba 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_out.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -43,7 +43,7 @@
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/msm_memtypes.h>
#include <mach/cpuidle.h>
-
+#include <linux/msm_ion.h>
#include <mach/htc_pwrsink.h>
#include <mach/debug_mm.h>
@@ -98,6 +98,8 @@
struct pm_qos_request pm_qos_req;
struct audpp_cmd_cfg_object_params_volume vol_pan;
+ struct ion_client *client;
+ struct ion_handle *buff_handle;
};
static void audio_out_listener(u32 evt_id, union auddev_evt_data *evt_payload,
@@ -702,19 +704,53 @@
static int __init audio_init(void)
{
- the_audio.phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
- if (the_audio.phys) {
- the_audio.map_v_write = ioremap(the_audio.phys, DMASZ);
- if (IS_ERR(the_audio.map_v_write)) {
- MM_ERR("could not map physical buffers\n");
- free_contiguous_memory_by_paddr(the_audio.phys);
- return -ENOMEM;
- }
- the_audio.data = the_audio.map_v_write;
- } else {
- MM_ERR("could not allocate physical buffers\n");
- return -ENOMEM;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ int rc;
+ int len = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
+
+ client = msm_ion_client_create(UINT_MAX, "HostPCM");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
+ rc = -ENOMEM;
+ goto client_create_error;
}
+ the_audio.client = client;
+
+ handle = ion_alloc(client, DMASZ, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto buff_alloc_error;
+ }
+ the_audio.buff_handle = handle;
+
+ rc = ion_phys(client, handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ goto buff_get_phys_error;
+ } else
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ the_audio.phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ goto buff_get_flags_error;
+ }
+
+ the_audio.map_v_write = ion_map_kernel(client, handle);
+ if (IS_ERR(the_audio.map_v_write)) {
+ MM_ERR("could not map write buffers\n");
+ rc = -ENOMEM;
+ goto buff_map_error;
+ }
+ the_audio.data = (char *)the_audio.map_v_write;
MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
(int) the_audio.data, (int) the_audio.phys);
mutex_init(&the_audio.lock);
@@ -725,6 +761,15 @@
pm_qos_add_request(&the_audio.pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
return misc_register(&audio_misc);
+buff_map_error:
+buff_get_phys_error:
+buff_get_flags_error:
+ ion_free(client, the_audio.buff_handle);
+buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
+ return rc;
+
}
late_initcall(audio_init);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
index ce67ebb..ff3a696 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -27,7 +27,7 @@
#include <linux/wait.h>
#include <linux/dma-mapping.h>
#include <linux/msm_audio.h>
-#include <linux/android_pmem.h>
+#include <linux/msm_ion.h>
#include <linux/memory_alloc.h>
#include <mach/msm_memtypes.h>
@@ -121,6 +121,8 @@
int abort; /* set when error, like sample rate mismatch */
int dual_mic_config;
char *build_id;
+ struct ion_client *client;
+ struct ion_handle *output_buff_handle;
};
static struct audio_in the_audio_in;
@@ -842,10 +844,11 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- iounmap(audio->map_v_read);
- free_contiguous_memory_by_paddr(audio->phys);
+ ion_unmap_kernel(audio->client, audio->output_buff_handle);
+ ion_free(audio->client, audio->output_buff_handle);
audio->data = NULL;
}
+ ion_client_destroy(audio->client);
mutex_unlock(&audio->lock);
return 0;
}
@@ -855,27 +858,68 @@
struct audio_in *audio = &the_audio_in;
int rc;
int encid;
+ int len = 0;
+ unsigned long ionflag = 0;
+ ion_phys_addr_t addr = 0;
+ struct ion_handle *handle = NULL;
+ struct ion_client *client = NULL;
mutex_lock(&audio->lock);
if (audio->opened) {
rc = -EBUSY;
goto done;
}
- audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
- if (audio->phys) {
- audio->map_v_read = ioremap(audio->phys, DMASZ);
- if (IS_ERR(audio->map_v_read)) {
- MM_ERR("could not map read phys buffers\n");
+
+ client = msm_ion_client_create(UINT_MAX, "Audio_PCM_in_client");
+ if (IS_ERR_OR_NULL(client)) {
+ MM_ERR("Unable to create ION client\n");
rc = -ENOMEM;
- free_contiguous_memory_by_paddr(audio->phys);
- goto done;
- }
- audio->data = audio->map_v_read;
- } else {
- MM_ERR("could not allocate read buffers\n");
- rc = -ENOMEM;
- goto done;
+ goto client_create_error;
}
+ audio->client = client;
+
+ MM_DBG("allocating mem sz = %d\n", DMASZ);
+ handle = ion_alloc(client, DMASZ, SZ_4K,
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(handle)) {
+ MM_ERR("Unable to create allocate O/P buffers\n");
+ rc = -ENOMEM;
+ goto output_buff_alloc_error;
+ }
+
+ audio->output_buff_handle = handle;
+
+ rc = ion_phys(client , handle, &addr, &len);
+ if (rc) {
+ MM_ERR("O/P buffers:Invalid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ rc = -ENOMEM;
+ goto output_buff_get_phys_error;
+ } else {
+ MM_INFO("O/P buffers:valid phy: %x sz: %x\n",
+ (unsigned int) addr, (unsigned int) len);
+ }
+ audio->phys = (int32_t)addr;
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ MM_ERR("could not get flags for the handle\n");
+ rc = -ENOMEM;
+ goto output_buff_get_flags_error;
+ }
+
+ audio->map_v_read = ion_map_kernel(client, handle);
+ if (IS_ERR(audio->data)) {
+ MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
+ (int)audio);
+ rc = -ENOMEM;
+ goto output_buff_map_error;
+ }
+ MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
+ audio->phys, (int)audio->data);
+
+ audio->data = (char *)audio->map_v_read;
+
MM_DBG("Memory addr = 0x%8x phy addr = 0x%8x\n",\
(int) audio->data, (int) audio->phys);
if ((file->f_mode & FMODE_WRITE) &&
@@ -941,6 +985,13 @@
mutex_unlock(&audio->lock);
return rc;
evt_error:
+output_buff_map_error:
+output_buff_get_phys_error:
+output_buff_get_flags_error:
+ ion_free(client, audio->output_buff_handle);
+output_buff_alloc_error:
+ ion_client_destroy(client);
+client_create_error:
msm_adsp_put(audio->audrec);
audpreproc_aenc_free(audio->enc_id);
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index 7fac2ea..8ad738e 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -1368,7 +1368,7 @@
MM_DBG("allocating mem sz = %d\n", DMASZ);
handle = ion_alloc(client, DMASZ, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1396,7 +1396,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_read = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_read = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read buffers,freeing instance 0x%08x\n",
(int)audio);
@@ -1465,7 +1465,7 @@
MM_DBG("allocating BUFFER_SIZE %d\n", BUFFER_SIZE);
handle = ion_alloc(client, BUFFER_SIZE,
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate I/P buffers\n");
rc = -ENOMEM;
@@ -1495,8 +1495,7 @@
goto input_buff_alloc_error;
}
- audio->map_v_write = ion_map_kernel(client,
- handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wma.c b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
index 4ba5821..8562020 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
@@ -1061,7 +1061,7 @@
handle = ion_alloc(audio->client,
(config.buffer_size *
config.buffer_count),
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to alloc I/P buffs\n");
audio->input_buff_handle = NULL;
@@ -1099,8 +1099,7 @@
}
audio->map_v_read = ion_map_kernel(
- audio->client,
- handle, ionflag);
+ audio->client, handle);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
ion_free(audio->client, handle);
@@ -1696,7 +1695,7 @@
audio->client = client;
handle = ion_alloc(client, mem_sz, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
MM_ERR("Unable to create allocate O/P buffers\n");
rc = -ENOMEM;
@@ -1722,7 +1721,7 @@
goto output_buff_get_flags_error;
}
- audio->map_v_write = ion_map_kernel(client, handle, ionflag);
+ audio->map_v_write = ion_map_kernel(client, handle);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.c b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
index 6e6f8e8..49008de 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsprpc.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.c
@@ -73,11 +73,10 @@
int err = 0;
buf->handle = ion_alloc(clnt, buf->size, SZ_4K,
- ION_HEAP(ION_AUDIO_HEAP_ID));
+ ION_HEAP(ION_AUDIO_HEAP_ID), 0);
VERIFY(0 == IS_ERR_OR_NULL(buf->handle));
buf->virt = 0;
- VERIFY(0 != (buf->virt = ion_map_kernel(clnt, buf->handle,
- ION_SET_CACHE(CACHED))));
+ VERIFY(0 != (buf->virt = ion_map_kernel(clnt, buf->handle)));
VERIFY(0 == ion_phys(clnt, buf->handle, &buf->phys, &buf->size));
bail:
if (err && !IS_ERR_OR_NULL(buf->handle))
diff --git a/arch/arm/mach-msm/qdsp6v2/adsprpc.h b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
index 368b8e6..c6c7d23 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsprpc.h
+++ b/arch/arm/mach-msm/qdsp6v2/adsprpc.h
@@ -24,7 +24,7 @@
#include <linux/cdev.h>
#include <linux/list.h>
#include <linux/hash.h>
-#include <linux/ion.h>
+#include <linux/msm_ion.h>
#include <mach/msm_smd.h>
#include <mach/ion.h>
#include "adsprpc_shared.h"
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index 7298fa1..7272f97 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -662,7 +662,7 @@
}
kvptr = ion_map_kernel(acdb_data.ion_client,
- acdb_data.ion_handle, 0);
+ acdb_data.ion_handle);
if (IS_ERR_OR_NULL(kvptr)) {
pr_err("%s: Could not get kernel virt addr!!!\n", __func__);
result = PTR_ERR(kvptr);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
index b5a382e..edf8f77 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -486,7 +486,7 @@
goto flag_error;
}
- temp_ptr = ion_map_kernel(audio->client, handle, ionflag);
+ temp_ptr = ion_map_kernel(audio->client, handle);
if (IS_ERR_OR_NULL(temp_ptr)) {
pr_err("%s: could not get virtual address\n", __func__);
goto map_error;
@@ -707,15 +707,6 @@
case RESET_EVENTS:
reset_device();
break;
- case APR_BASIC_RSP_RESULT:
- switch (payload[0]) {
- case ASM_STREAM_CMD_CLOSE:
- audlpa_unmap_ion_region(audio);
- break;
- default:
- break;
- }
- break;
default:
break;
}
@@ -1136,6 +1127,7 @@
audlpa_async_flush(audio);
audio->wflush = 0;
audio_disable(audio);
+ audlpa_unmap_ion_region(audio);
msm_clear_session_id(audio->ac->session);
auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
q6asm_audio_client_free(audio->ac);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 84a79cd..d6abdda 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -403,7 +403,7 @@
return;
}
-void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
+static void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
{
struct audio_aio_ion_region *region;
struct list_head *ptr, *next;
@@ -436,6 +436,7 @@
audio->drv_ops.out_flush(audio);
audio->drv_ops.in_flush(audio);
audio_aio_disable(audio);
+ audio_aio_unmap_ion_region(audio);
audio_aio_reset_ion_region(audio);
ion_client_destroy(audio->client);
audio->event_abort = 1;
@@ -676,7 +677,7 @@
goto flag_error;
}
- temp_ptr = ion_map_kernel(audio->client, handle, ionflag);
+ temp_ptr = ion_map_kernel(audio->client, handle);
if (IS_ERR_OR_NULL(temp_ptr)) {
pr_err("%s: could not get virtual address\n", __func__);
goto map_error;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index 2b936c5..b2829c3 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -210,7 +210,6 @@
int audio_aio_fsync(struct file *file, loff_t start, loff_t end, int datasync);
void audio_aio_async_out_flush(struct q6audio_aio *audio);
void audio_aio_async_in_flush(struct q6audio_aio *audio);
-void audio_aio_unmap_ion_region(struct q6audio_aio *audio);
#ifdef CONFIG_DEBUG_FS
ssize_t audio_aio_debug_open(struct inode *inode, struct file *file);
ssize_t audio_aio_debug_read(struct file *file, char __user *buf,
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
index c19fd85..63b3064 100644
--- a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
+++ b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
@@ -26,7 +26,7 @@
#include <mach/msm_hdmi_audio.h>
#include <mach/audio_dma_msm8k.h>
#include <sound/dai.h>
-#include "q6core.h"
+#include <mach/qdsp6v2/q6core.h>
#define DMA_ALLOC_BUF_SZ (SZ_4K * 16)
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
index b46e0d3..96f823f 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v1_aio.c
@@ -37,7 +37,6 @@
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
- case APR_BASIC_RSP_RESULT:
audio_aio_cb(opcode, token, payload, audio);
break;
default:
@@ -107,15 +106,6 @@
e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
break;
- case APR_BASIC_RSP_RESULT:
- switch (payload[0]) {
- case ASM_STREAM_CMD_CLOSE:
- audio_aio_unmap_ion_region(audio);
- break;
- default:
- break;
- }
- break;
default:
break;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
index d7de50e..9dd66e1 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6core.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.c
@@ -26,7 +26,7 @@
#include <linux/delay.h>
#include <mach/msm_smd.h>
#include <mach/qdsp6v2/apr.h>
-#include "q6core.h"
+#include <mach/qdsp6v2/q6core.h>
#define TIMEOUT_MS 1000
@@ -79,6 +79,10 @@
bus_bw_resp_received = 1;
wake_up(&bus_bw_req_wait);
break;
+ case ADSP_CMD_SET_DTS_MODEL_ID:
+ pr_debug("ADSP_CMD_SET_DTS_MODEL_ID status[0x%x]\n",
+ payload1[1]);
+ break;
default:
pr_err("Invalid cmd rsp[0x%x][0x%x]\n",
payload1[0], payload1[1]);
@@ -382,6 +386,35 @@
return count;
}
+uint32_t core_set_dts_model_id(uint32_t id_size, uint8_t *id)
+{
+ struct adsp_dts_modelid payload;
+ int rc = 0;
+ pr_debug("core_set_dts_model_id(): Enter\n");
+ core_open();
+ if (core_handle_q) {
+ payload.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ payload.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(uint32_t)+id_size);
+ payload.hdr.src_port = 0;
+ payload.hdr.dest_port = 0;
+ payload.hdr.token = 0;
+ payload.hdr.opcode = ADSP_CMD_SET_DTS_MODEL_ID;
+ payload.model_ID_size = id_size;
+ memcpy(payload.model_ID, id, id_size+1);
+ pr_debug("Send DTS sec opcode=%x modelID = %s, size=%d\n",
+ payload.hdr.opcode, (char *)payload.model_ID,
+ payload.model_ID_size);
+ rc = apr_send_pkt(core_handle_q, (uint32_t *)&payload);
+ if (rc < 0)
+ pr_err("%s: SET_DTS_DTS_MODEL_ID failed op[0x%x]rc[%d]\n",
+ __func__, payload.hdr.opcode, rc);
+ }
+ pr_debug("core_set_dts_model_id(): Exit\n");
+ return rc;
+}
+
static const struct file_operations apr_debug_fops = {
.write = apr_debug_write,
.open = apr_debug_open,
diff --git a/arch/arm/mach-msm/qdsp6v2/q6voice.c b/arch/arm/mach-msm/qdsp6v2/q6voice.c
index 12a02c5..7464ed7 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6voice.c
+++ b/arch/arm/mach-msm/qdsp6v2/q6voice.c
@@ -30,7 +30,7 @@
#include <mach/qdsp6v2/rtac.h>
#include <mach/qdsp6v2/audio_acdb.h>
-#include "q6core.h"
+#include <mach/qdsp6v2/q6core.h>
#define TIMEOUT_MS 3000
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
index 5400ccc..dce3812 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
@@ -515,6 +515,9 @@
case FORMAT_USRAW:
int_format = US_RAW_FORMAT;
break;
+ case FORMAT_USPROX:
+ int_format = US_PROX_FORMAT;
+ break;
default:
pr_err("%s: Invalid format[%d]\n", __func__, ext_format);
break;
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index 1338e86..1fe71bf 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -20,6 +20,7 @@
#define FORMAT_USPS_EPOS 0x00000000
#define FORMAT_USRAW 0x00000001
+#define FORMAT_USPROX 0x00000002
#define INVALID_FORMAT 0xffffffff
#define IN 0x000
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 5883b0c..2189747 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -36,6 +36,7 @@
#include <mach/scm.h>
#include "msm_watchdog.h"
#include "timer.h"
+#include "wdog_debug.h"
#define WDT0_RST 0x38
#define WDT0_EN 0x40
@@ -250,8 +251,11 @@
__raw_writel(5*0x31F3, msm_tmr0_base + WDT0_BARK_TIME);
__raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME);
__raw_writel(1, msm_tmr0_base + WDT0_EN);
- } else
+ } else {
+ /* Needed for 8974: Reset GCC_WDOG_DEBUG register */
+ msm_disable_wdog_debug();
__raw_writel(0, MSM_MPM2_PSHOLD_BASE);
+ }
mdelay(10000);
printk(KERN_ERR "Restarting has failed\n");
diff --git a/arch/arm/mach-msm/rpm-regulator-8960.c b/arch/arm/mach-msm/rpm-regulator-8960.c
index 8fe3571..c5c01c2 100644
--- a/arch/arm/mach-msm/rpm-regulator-8960.c
+++ b/arch/arm/mach-msm/rpm-regulator-8960.c
@@ -325,3 +325,32 @@
{
return &config;
}
+
+struct vreg_config *get_config_8960_pm8917(void)
+{
+ int i;
+
+ /*
+ * PM8917 regulators L24, L25, L26, L27, and L28 require CXO to be ON
+ * while they are enabled. These same regulators on PM8921 do not
+ * require CXO to be ON. Therefore, set the require_cxo flag for these
+ * regulators only when using PM8917.
+ *
+ * Do not apply the workaround to L24 (VDD_MX) because it is always on
+ * and using the TCXO workaround with it would result in additional
+ * latency during every Krait upscaling event.
+ */
+ for (i = 0; i < ARRAY_SIZE(vregs); i++) {
+ switch (vregs[i].id) {
+ case RPM_VREG_ID_PM8921_L25:
+ case RPM_VREG_ID_PM8921_L26:
+ case RPM_VREG_ID_PM8921_L27:
+ case RPM_VREG_ID_PM8921_L28:
+ vregs[i].requires_cxo = true;
+ default:
+ break;
+ }
+ }
+
+ return &config;
+}
diff --git a/arch/arm/mach-msm/rpm-regulator-private.h b/arch/arm/mach-msm/rpm-regulator-private.h
index d55bd73..703335f 100644
--- a/arch/arm/mach-msm/rpm-regulator-private.h
+++ b/arch/arm/mach-msm/rpm-regulator-private.h
@@ -158,11 +158,16 @@
#if defined(CONFIG_MSM_RPM_REGULATOR) && \
(defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_APQ8064))
struct vreg_config *get_config_8960(void);
+struct vreg_config *get_config_8960_pm8917(void);
#else
static inline struct vreg_config *get_config_8960(void)
{
return NULL;
}
+static inline struct vreg_config *get_config_8960_pm8917(void)
+{
+ return NULL;
+}
#endif
#if defined(CONFIG_MSM_RPM_REGULATOR) && defined(CONFIG_ARCH_MSM9615)
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index a8af9e7..d1c61fe 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -112,7 +112,7 @@
PARAM(HEAD_ROOM, 1, 0, 0, 1, "hr", 0, 0x7FFFFFFF, "qcom,init-head-room"),
PARAM(QUIET_MODE, 0, 1, 0, 0, "qm", 0, 2, "qcom,init-quiet-mode"),
PARAM(FREQ_REASON, 0, 1, 0, 1, "resn", 0, 8, "qcom,init-freq-reason"),
- PARAM(CORNER, 0, 1, 0, 0, "corn", 0, 6, "qcom,init-voltage-corner"),
+ PARAM(CORNER, 1, 1, 0, 0, "corn", 0, 6, "qcom,init-voltage-corner"),
PARAM(BYPASS, 1, 0, 0, 0, "bypa", 0, 1, "qcom,init-disallow-bypass"),
};
@@ -1037,6 +1037,19 @@
.enable_time = rpm_vreg_enable_time,
};
+static struct regulator_ops ldo_corner_ops = {
+ .enable = rpm_vreg_enable,
+ .disable = rpm_vreg_disable,
+ .is_enabled = rpm_vreg_is_enabled,
+ .set_voltage = rpm_vreg_set_voltage_corner,
+ .get_voltage = rpm_vreg_get_voltage_corner,
+ .list_voltage = rpm_vreg_list_voltage,
+ .set_mode = rpm_vreg_set_mode,
+ .get_mode = rpm_vreg_get_mode,
+ .get_optimum_mode = rpm_vreg_get_optimum_mode,
+ .enable_time = rpm_vreg_enable_time,
+};
+
static struct regulator_ops smps_ops = {
.enable = rpm_vreg_enable,
.disable = rpm_vreg_disable,
@@ -1194,11 +1207,14 @@
/*
* Switch to voltage corner regulator ops if qcom,use-voltage-corner
- * is specified in the device node (SMPS only).
+ * is specified in the device node (SMPS and LDO only).
*/
- if (of_find_property(node, "qcom,use-voltage-corner", NULL)
- && regulator_type == RPM_REGULATOR_SMD_TYPE_SMPS)
- reg->rdesc.ops = &smps_corner_ops;
+ if (of_property_read_bool(node, "qcom,use-voltage-corner")) {
+ if (regulator_type == RPM_REGULATOR_SMD_TYPE_SMPS)
+ reg->rdesc.ops = &smps_corner_ops;
+ else if (regulator_type == RPM_REGULATOR_SMD_TYPE_LDO)
+ reg->rdesc.ops = &ldo_corner_ops;
+ }
if (regulator_type == RPM_REGULATOR_SMD_TYPE_VS)
reg->rdesc.n_voltages = 0;
@@ -1286,7 +1302,7 @@
}
}
- of_property_read_u32(node, "qcom,system_load", ®->system_load);
+ of_property_read_u32(node, "qcom,system-load", ®->system_load);
rpm_vreg_lock(rpm_vreg);
list_add(®->list, &rpm_vreg->reg_list);
diff --git a/arch/arm/mach-msm/rpm-regulator.c b/arch/arm/mach-msm/rpm-regulator.c
index 424a4fe..01543a2 100644
--- a/arch/arm/mach-msm/rpm-regulator.c
+++ b/arch/arm/mach-msm/rpm-regulator.c
@@ -63,6 +63,7 @@
[RPM_VREG_VERSION_9615] = get_config_9615,
[RPM_VREG_VERSION_8930] = get_config_8930,
[RPM_VREG_VERSION_8930_PM8917] = get_config_8930_pm8917,
+ [RPM_VREG_VERSION_8960_PM8917] = get_config_8960_pm8917,
};
static struct rpm_regulator_consumer_mapping *consumer_map;
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index a9d1ed8..f97eb9a 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -149,8 +149,6 @@
uint32_t id_ack;
};
-static int irq_process;
-
LIST_HEAD(msm_rpm_ack_list);
static void msm_rpm_notify_sleep_chain(struct rpm_message_header *hdr,
@@ -518,20 +516,18 @@
uint32_t msg_id;
int errno;
char buf[MAX_ERR_BUFFER_SIZE] = {0};
- unsigned long flags;
- while (smd_is_pkt_avail(msm_rpm_data.ch_info) && !irq_process) {
- spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
+ if (!spin_trylock(&msm_rpm_data.smd_lock_read))
+ return;
+ while (smd_is_pkt_avail(msm_rpm_data.ch_info)) {
if (msm_rpm_read_smd_data(buf)) {
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read,
- flags);
break;
}
msg_id = msm_rpm_get_msg_id_from_ack(buf);
errno = msm_rpm_get_error_from_ack(buf);
msm_rpm_process_ack(msg_id, errno);
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
}
+ spin_unlock(&msm_rpm_data.smd_lock_read);
}
#define DEBUG_PRINT_BUFFER_SIZE 512
@@ -783,7 +779,14 @@
int msm_rpm_send_request(struct msm_rpm_request *handle)
{
- return msm_rpm_send_data(handle, MSM_RPM_MSG_REQUEST_TYPE, false);
+ int ret;
+ static DEFINE_MUTEX(send_mtx);
+
+ mutex_lock(&send_mtx);
+ ret = msm_rpm_send_data(handle, MSM_RPM_MSG_REQUEST_TYPE, false);
+ mutex_unlock(&send_mtx);
+
+ return ret;
}
EXPORT_SYMBOL(msm_rpm_send_request);
@@ -837,7 +840,6 @@
return 0;
spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags);
- irq_process = true;
elem = msm_rpm_get_entry_from_msg_id(msg_id);
@@ -868,7 +870,6 @@
rc = elem->errno;
msm_rpm_free_list_entry(elem);
wait_ack_cleanup:
- irq_process = false;
spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags);
return rc;
}
@@ -942,7 +943,7 @@
static bool msm_rpm_set_standalone(void)
{
- if (machine_is_msm8974()) {
+ if (machine_is_msm9625()) {
pr_warn("%s(): Running in standalone mode, requests "
"will not be sent to RPM\n", __func__);
standalone = true;
diff --git a/arch/arm/mach-msm/rpm_resources.c b/arch/arm/mach-msm/rpm_resources.c
index 2a835f7..dfed3aa 100644
--- a/arch/arm/mach-msm/rpm_resources.c
+++ b/arch/arm/mach-msm/rpm_resources.c
@@ -945,7 +945,8 @@
irqs_detectable, gpio_detectable))
continue;
- if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
+ if ((MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
+ || (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == sleep_mode))
if (!cpu && msm_rpm_local_request_is_outstanding())
break;
@@ -1131,7 +1132,8 @@
static int __init msm_rpmrs_l2_init(void)
{
if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab()) {
+ cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab() ||
+ cpu_is_apq8064ab()) {
msm_pm_set_l2_flush_flag(0);
diff --git a/arch/arm/mach-msm/rpm_stats.h b/arch/arm/mach-msm/rpm_stats.h
index 918d4fb..a3beaa4 100644
--- a/arch/arm/mach-msm/rpm_stats.h
+++ b/arch/arm/mach-msm/rpm_stats.h
@@ -20,4 +20,19 @@
phys_addr_t phys_addr_base;
u32 phys_size;
};
+
+struct msm_rpm_master_stats_platform_data {
+ phys_addr_t phys_addr_base;
+ u32 phys_size;
+ char **masters;
+ /*
+ * RPM maintains PC stats for each master in MSG RAM,
+ * it allocates 256 bytes for this use.
+ * No of masters differs for different targets.
+ * Based on the number of masters, linux rpm stat
+ * driver reads (32 * nomasters) bytes to display
+ * master stats.
+ */
+ u32 nomasters;
+};
#endif
diff --git a/arch/arm/mach-msm/scm-pas.h b/arch/arm/mach-msm/scm-pas.h
index dd24e20..8da1d75 100644
--- a/arch/arm/mach-msm/scm-pas.h
+++ b/arch/arm/mach-msm/scm-pas.h
@@ -25,8 +25,29 @@
PAS_VIDC,
};
+#ifdef CONFIG_MSM_PIL
extern int pas_init_image(enum pas_id id, const u8 *metadata, size_t size);
extern int pas_auth_and_reset(enum pas_id id);
extern int pas_shutdown(enum pas_id id);
extern int pas_supported(enum pas_id id);
+#else
+static inline int pas_init_image(enum pas_id id, const u8 *metadata,
+ size_t size)
+{
+ return 0;
+}
+static inline int pas_auth_and_reset(enum pas_id id)
+{
+ return 0;
+}
+static inline int pas_shutdown(enum pas_id id)
+{
+ return 0;
+}
+static inline int pas_supported(enum pas_id id)
+{
+ return 0;
+}
+#endif
+
#endif
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index e33f87b..c1e2421 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -35,6 +35,7 @@
#include <linux/wakelock.h>
#include <linux/notifier.h>
#include <linux/sort.h>
+#include <linux/suspend.h>
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
#include <mach/system.h>
@@ -553,6 +554,26 @@
}
}
+static int smsm_pm_notifier(struct notifier_block *nb,
+ unsigned long event, void *unused)
+{
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ smsm_change_state(SMSM_APPS_STATE, SMSM_PROC_AWAKE, 0);
+ break;
+
+ case PM_POST_SUSPEND:
+ smsm_change_state(SMSM_APPS_STATE, 0, SMSM_PROC_AWAKE);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block smsm_pm_nb = {
+ .notifier_call = smsm_pm_notifier,
+ .priority = 0,
+};
+
void smd_diag(void)
{
char *x;
@@ -2545,6 +2566,12 @@
return i;
wmb();
+
+ smsm_pm_notifier(&smsm_pm_nb, PM_POST_SUSPEND, NULL);
+ i = register_pm_notifier(&smsm_pm_nb);
+ if (i)
+ pr_err("%s: power state notif error %d\n", __func__, i);
+
return 0;
}
@@ -3513,9 +3540,10 @@
static struct restart_notifier_block restart_notifiers[] = {
{SMD_MODEM, "modem", .nb.notifier_call = restart_notifier_cb},
{SMD_Q6, "lpass", .nb.notifier_call = restart_notifier_cb},
- {SMD_WCNSS, "riva", .nb.notifier_call = restart_notifier_cb},
+ {SMD_WCNSS, "wcnss", .nb.notifier_call = restart_notifier_cb},
{SMD_DSPS, "dsps", .nb.notifier_call = restart_notifier_cb},
{SMD_MODEM, "gss", .nb.notifier_call = restart_notifier_cb},
+ {SMD_Q6, "adsp", .nb.notifier_call = restart_notifier_cb},
};
static int restart_notifier_cb(struct notifier_block *this,
diff --git a/arch/arm/mach-msm/smd_rpcrouter.c b/arch/arm/mach-msm/smd_rpcrouter.c
index 983d0c1..68c3dd3 100644
--- a/arch/arm/mach-msm/smd_rpcrouter.c
+++ b/arch/arm/mach-msm/smd_rpcrouter.c
@@ -2421,6 +2421,7 @@
{
struct rpcrouter_xprt_info *xprt_info;
struct rpcrouter_xprt_work *xprt_work;
+ unsigned long flags;
/* Workqueue is created in init function which works for all existing
* clients. If this fails in the future, then it will need to be
@@ -2452,11 +2453,13 @@
xprt_info = xprt->priv;
if (xprt_info) {
+ spin_lock_irqsave(&xprt_info->lock, flags);
/* Check read_avail even for OPEN event to handle missed
DATA events while processing the OPEN event*/
if (xprt->read_avail() >= xprt_info->need_len)
wake_lock(&xprt_info->wakelock);
wake_up(&xprt_info->read_wait);
+ spin_unlock_irqrestore(&xprt_info->lock, flags);
}
}
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 86de130..0beb952 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -35,6 +35,8 @@
HW_PLATFORM_LIQUID = 9,
/* Dragonboard platform id is assigned as 10 in CDT */
HW_PLATFORM_DRAGON = 10,
+ HW_PLATFORM_HRD = 13,
+ HW_PLATFORM_DTV = 14,
HW_PLATFORM_INVALID
};
@@ -47,7 +49,9 @@
[HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF",
[HW_PLATFORM_MTP] = "MTP",
[HW_PLATFORM_LIQUID] = "Liquid",
- [HW_PLATFORM_DRAGON] = "Dragon"
+ [HW_PLATFORM_DRAGON] = "Dragon",
+ [HW_PLATFORM_HRD] = "HRD",
+ [HW_PLATFORM_DTV] = "DTV",
};
enum {
@@ -286,6 +290,12 @@
/* 8092 IDs */
[146] = MSM_CPU_8092,
+ /* 8910 IDs */
+ [147] = MSM_CPU_8910,
+
+ /* 8064AB IDs */
+ [153] = MSM_CPU_8064AB,
+
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
considered as unknown CPU. */
@@ -729,6 +739,10 @@
dummy_socinfo.id = 146;
strlcpy(dummy_socinfo.build_id, "mpq8092 - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_msm8910()) {
+ dummy_socinfo.id = 147;
+ strlcpy(dummy_socinfo.build_id, "msm8910 - ",
+ 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-v2.c b/arch/arm/mach-msm/spm-v2.c
index 1eab9bf..f0d3d06 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -179,7 +179,7 @@
}
}
-static inline uint32_t msm_spm_drv_get_sts_curr_pmic_data(
+uint32_t msm_spm_drv_get_sts_curr_pmic_data(
struct msm_spm_driver_data *dev)
{
if (dev->major == SAW2_MAJOR_2) {
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index e81e335..09ee26a 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -141,6 +141,13 @@
int msm_spm_set_vdd(unsigned int cpu, unsigned int vlevel);
/**
+ * msm_spm_get_vdd(): Get core voltage
+ * @cpu: core id
+ * @return: Returns encoded PMIC data.
+ */
+unsigned int msm_spm_get_vdd(unsigned int cpu);
+
+/**
* msm_spm_turn_on_cpu_rail(): Power on cpu rail before turning on core
* @cpu: core id
*/
@@ -239,6 +246,11 @@
return -ENOSYS;
}
+static inline unsigned int msm_spm_get_vdd(unsigned int cpu)
+{
+ return 0;
+}
+
static inline void msm_spm_reinit(void)
{
/* empty */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index b87b0f1..2cbed94 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -75,6 +75,15 @@
}
EXPORT_SYMBOL(msm_spm_set_vdd);
+unsigned int msm_spm_get_vdd(unsigned int cpu)
+{
+ struct msm_spm_device *dev;
+
+ dev = &per_cpu(msm_cpu_spm_device, cpu);
+ return msm_spm_drv_get_sts_curr_pmic_data(&dev->reg_data);
+}
+EXPORT_SYMBOL(msm_spm_get_vdd);
+
static int msm_spm_dev_set_low_power_mode(struct msm_spm_device *dev,
unsigned int mode, bool notify_rpm)
{
@@ -159,7 +168,8 @@
reg = saw_bases[cpu];
if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab()) {
+ cpu_is_apq8064() || cpu_is_msm8627() || cpu_is_msm8960ab() ||
+ cpu_is_apq8064ab()) {
val = 0xA4;
reg += 0x14;
timeout = 512;
diff --git a/arch/arm/mach-msm/spm_driver.h b/arch/arm/mach-msm/spm_driver.h
index f272adb..4cdfd33 100644
--- a/arch/arm/mach-msm/spm_driver.h
+++ b/arch/arm/mach-msm/spm_driver.h
@@ -35,6 +35,8 @@
uint32_t addr);
int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev,
unsigned int vlevel);
+uint32_t msm_spm_drv_get_sts_curr_pmic_data(
+ struct msm_spm_driver_data *dev);
int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
uint8_t *cmd, uint32_t *offset);
void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev);
diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c
index 1305bd1..02ba5ea 100644
--- a/arch/arm/mach-msm/sysmon.c
+++ b/arch/arm/mach-msm/sysmon.c
@@ -159,6 +159,41 @@
}
/**
+ * sysmon_send_shutdown() - send shutdown command to a
+ * subsystem.
+ * @dest_ss: ID of subsystem to send to.
+ *
+ * Returns 0 for success, -EINVAL for an invalid destination, -ENODEV if
+ * the SMD transport channel is not open, -ETIMEDOUT if the destination
+ * subsystem does not respond, and -ENOSYS if the destination subsystem
+ * responds with something unexpected.
+ *
+ * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
+ */
+int sysmon_send_shutdown(enum subsys_id dest_ss)
+{
+ struct sysmon_subsys *ss = &subsys[dest_ss];
+ const char tx_buf[] = "system:shutdown";
+ const char expect[] = "system:ack";
+ size_t prefix_len = ARRAY_SIZE(expect) - 1;
+ int ret;
+
+ if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS)
+ return -EINVAL;
+
+ mutex_lock(&ss->lock);
+ ret = sysmon_send_msg(ss, tx_buf, ARRAY_SIZE(tx_buf));
+ if (ret)
+ goto out;
+
+ if (strncmp(ss->rx_buf, expect, prefix_len))
+ ret = -ENOSYS;
+out:
+ mutex_unlock(&ss->lock);
+ return ret;
+}
+
+/**
* sysmon_get_reason() - Retrieve failure reason from a subsystem.
* @dest_ss: ID of subsystem to query
* @buf: Caller-allocated buffer for the returned NUL-terminated reason
diff --git a/arch/arm/mach-msm/sysmon.h b/arch/arm/mach-msm/sysmon.h
index 77c3329..8c2f6ea 100644
--- a/arch/arm/mach-msm/sysmon.h
+++ b/arch/arm/mach-msm/sysmon.h
@@ -38,6 +38,7 @@
int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
enum subsys_notif_type notif);
int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len);
+int sysmon_send_shutdown(enum subsys_id dest_ss);
#else
static inline int sysmon_send_event(enum subsys_id dest_ss,
const char *event_ss,
@@ -50,6 +51,10 @@
{
return 0;
}
+static inline int sysmon_send_shutdown(enum subsys_id dest_ss)
+{
+ return 0;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 668f4cc..b361d9d 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -966,7 +966,7 @@
if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627() ||
- cpu_is_msm8960ab())
+ cpu_is_msm8960ab() || cpu_is_apq8064ab())
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
if (__get_cpu_var(first_boot)) {
@@ -1064,7 +1064,7 @@
dgt->flags |= MSM_CLOCK_FLAGS_UNSTABLE_COUNT;
} else if (cpu_is_msm8960() || cpu_is_apq8064() || cpu_is_msm8930() ||
cpu_is_msm8930aa() || cpu_is_msm8627() ||
- cpu_is_msm8960ab()) {
+ cpu_is_msm8960ab() || cpu_is_apq8064ab()) {
global_timer_offset = MSM_TMR0_BASE - MSM_TMR_BASE;
dgt->freq = 6750000;
__raw_writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
@@ -1127,7 +1127,7 @@
if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
cpu_is_msm8930() || cpu_is_msm9615() || cpu_is_msm8625() ||
cpu_is_msm8627() || cpu_is_msm8930aa() ||
- cpu_is_msm8960ab()) {
+ cpu_is_msm8960ab() || cpu_is_apq8064ab()) {
clock->percpu_evt = alloc_percpu(struct clock_event_device *);
if (!clock->percpu_evt) {
pr_err("msm_timer_init: memory allocation "
diff --git a/arch/arm/mach-msm/tz_log.c b/arch/arm/mach-msm/tz_log.c
index db797cd..5a7ec69 100644
--- a/arch/arm/mach-msm/tz_log.c
+++ b/arch/arm/mach-msm/tz_log.c
@@ -496,17 +496,23 @@
*/
tzdiag_phy_iobase = readl_relaxed(virt_iobase);
- /*
- * Map the 4KB diagnostic information area
- */
- tzdbg.virt_iobase = devm_ioremap_nocache(&pdev->dev,
- tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
+ if (!pdev->dev.of_node) {
- if (!tzdbg.virt_iobase) {
- dev_err(&pdev->dev,
- "%s: ERROR could not ioremap: start=%p, len=%u\n",
- __func__, (void *) tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
- return -ENXIO;
+ /*
+ * Map the 4KB diagnostic information area
+ */
+ tzdbg.virt_iobase = devm_ioremap_nocache(&pdev->dev,
+ tzdiag_phy_iobase, DEBUG_MAX_RW_BUF);
+
+ if (!tzdbg.virt_iobase) {
+ dev_err(&pdev->dev,
+ "%s: ERROR could not ioremap: start=%p, len=%u\n",
+ __func__, (void *) tzdiag_phy_iobase,
+ DEBUG_MAX_RW_BUF);
+ return -ENXIO;
+ }
+ } else {
+ tzdbg.virt_iobase = virt_iobase;
}
ptr = kzalloc(DEBUG_MAX_RW_BUF, GFP_KERNEL);
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
deleted file mode 100644
index f014df9..0000000
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/wcnss_wlan.h>
-#include <linux/err.h>
-#include <asm/mach-types.h>
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-#include <mach/peripheral-loader.h>
-#include "smd_private.h"
-#include "ramdump.h"
-
-#define MODULE_NAME "wcnss_8960"
-#define MAX_BUF_SIZE 0x51
-
-
-
-static struct delayed_work cancel_vote_work;
-static void *riva_ramdump_dev;
-static int riva_crash;
-static int ss_restart_inprogress;
-static int enable_riva_ssr;
-static struct subsys_device *riva_8960_dev;
-
-static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
- uint32_t new_state)
-{
- char *smem_reset_reason;
- char buffer[MAX_BUF_SIZE];
- unsigned smem_reset_size;
- unsigned size;
-
- riva_crash = true;
-
- pr_err("%s: smsm state changed\n", MODULE_NAME);
-
- if (!(new_state & SMSM_RESET))
- return;
-
- if (ss_restart_inprogress) {
- pr_err("%s: Ignoring smsm reset req, restart in progress\n",
- MODULE_NAME);
- return;
- }
-
- if (!enable_riva_ssr)
- panic(MODULE_NAME ": SMSM reset request received from Riva");
-
- smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
- &smem_reset_size);
-
- if (!smem_reset_reason || !smem_reset_size) {
- pr_err("%s: wcnss subsystem failure reason: %s\n",
- __func__, "(unknown, smem_get_entry failed)");
- } else if (!smem_reset_reason[0]) {
- pr_err("%s: wcnss subsystem failure reason: %s\n",
- __func__, "(unknown, init string found)");
- } else {
- size = smem_reset_size < MAX_BUF_SIZE ? smem_reset_size :
- (MAX_BUF_SIZE - 1);
- memcpy(buffer, smem_reset_reason, size);
- buffer[size] = '\0';
- pr_err("%s: wcnss subsystem failure reason: %s\n",
- __func__, buffer);
- memset(smem_reset_reason, 0, smem_reset_size);
- wmb();
- }
-
- ss_restart_inprogress = true;
- subsystem_restart_dev(riva_8960_dev);
-}
-
-static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
-{
- riva_crash = true;
-
- if (ss_restart_inprogress) {
- pr_err("%s: Ignoring riva bite irq, restart in progress\n",
- MODULE_NAME);
- return IRQ_HANDLED;
- }
-
- if (!enable_riva_ssr)
- panic(MODULE_NAME ": Watchdog bite received from Riva");
-
- ss_restart_inprogress = true;
- subsystem_restart_dev(riva_8960_dev);
-
- return IRQ_HANDLED;
-}
-
-/* SMSM reset Riva */
-static void smsm_riva_reset(void)
-{
- /* per SS reset request bit is not available now,
- * all SS host modules are setting this bit
- * This is still under discussion*/
- smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
-}
-
-static void riva_post_bootup(struct work_struct *work)
-{
- struct platform_device *pdev = wcnss_get_platform_device();
- struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
-
- pr_debug(MODULE_NAME ": Cancel APPS vote for Iris & Riva\n");
-
- wcnss_wlan_power(&pdev->dev, pwlanconfig,
- WCNSS_WLAN_SWITCH_OFF);
-}
-
-/* Subsystem handlers */
-static int riva_shutdown(const struct subsys_desc *subsys)
-{
- pil_force_shutdown("wcnss");
- flush_delayed_work(&cancel_vote_work);
- wcnss_flush_delayed_boot_votes();
- disable_irq_nosync(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
-
- return 0;
-}
-
-static int riva_powerup(const struct subsys_desc *subsys)
-{
- struct platform_device *pdev = wcnss_get_platform_device();
- struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
- int ret = -1;
-
- if (pdev && pwlanconfig)
- ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
- WCNSS_WLAN_SWITCH_ON);
- /* delay PIL operation, this SSR may be happening soon after kernel
- * resumes because of a SMSM RESET by Riva when APPS was suspended.
- * PIL fails to locate the images without this delay */
- if (!ret) {
- msleep(1000);
- pil_force_boot("wcnss");
- }
- ss_restart_inprogress = false;
- enable_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
- schedule_delayed_work(&cancel_vote_work, msecs_to_jiffies(5000));
-
- return ret;
-}
-
-/* 5MB RAM segments for Riva SS */
-static struct ramdump_segment riva_segments[] = {{0x8f200000,
- 0x8f700000 - 0x8f200000} };
-
-static int riva_ramdump(int enable, const struct subsys_desc *subsys)
-{
- pr_debug("%s: enable[%d]\n", MODULE_NAME, enable);
- if (enable)
- return do_ramdump(riva_ramdump_dev,
- riva_segments,
- ARRAY_SIZE(riva_segments));
- else
- return 0;
-}
-
-/* Riva crash handler */
-static void riva_crash_shutdown(const struct subsys_desc *subsys)
-{
- pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
- if (riva_crash != true)
- smsm_riva_reset();
-}
-
-static struct subsys_desc riva_8960 = {
- .name = "riva",
- .shutdown = riva_shutdown,
- .powerup = riva_powerup,
- .ramdump = riva_ramdump,
- .crash_shutdown = riva_crash_shutdown
-};
-
-static int enable_riva_ssr_set(const char *val, struct kernel_param *kp)
-{
- int ret;
-
- ret = param_set_int(val, kp);
- if (ret)
- return ret;
-
- if (enable_riva_ssr)
- pr_info(MODULE_NAME ": Subsystem restart activated for riva.\n");
-
- return 0;
-}
-
-module_param_call(enable_riva_ssr, enable_riva_ssr_set, param_get_int,
- &enable_riva_ssr, S_IRUGO | S_IWUSR);
-
-static int __init riva_restart_init(void)
-{
- riva_8960_dev = subsys_register(&riva_8960);
- if (IS_ERR(riva_8960_dev))
- return PTR_ERR(riva_8960_dev);
- return 0;
-}
-
-static int __init riva_ssr_module_init(void)
-{
- int ret;
-
- if (machine_is_mpq8064_hrd()) {
- pr_err("Riva not supported on this target\n");
- return 0;
- }
-
- ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
- smsm_state_cb_hdlr, 0);
- if (ret < 0) {
- pr_err("%s: Unable to register smsm callback for Riva Reset! %d\n",
- MODULE_NAME, ret);
- goto out;
- }
- ret = request_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
- riva_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
- "riva_wdog", NULL);
-
- if (ret < 0) {
- pr_err("%s: Unable to register for Riva bite interrupt (%d)\n",
- MODULE_NAME, ret);
- goto out;
- }
- ret = riva_restart_init();
- if (ret < 0) {
- pr_err("%s: Unable to register with ssr. (%d)\n",
- MODULE_NAME, ret);
- goto out;
- }
- riva_ramdump_dev = create_ramdump_device("riva");
- if (!riva_ramdump_dev) {
- pr_err("%s: Unable to create ramdump device.\n",
- MODULE_NAME);
- ret = -ENOMEM;
- goto out;
- }
- INIT_DELAYED_WORK(&cancel_vote_work, riva_post_bootup);
-
- pr_info("%s: module initialized\n", MODULE_NAME);
-out:
- return ret;
-}
-
-static void __exit riva_ssr_module_exit(void)
-{
- if (machine_is_mpq8064_hrd())
- return;
- subsys_unregister(riva_8960_dev);
- free_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ, NULL);
-}
-
-module_init(riva_ssr_module_init);
-module_exit(riva_ssr_module_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/wcnss-ssr-8974.c b/arch/arm/mach-msm/wcnss-ssr-8974.c
new file mode 100644
index 0000000..8841b52
--- /dev/null
+++ b/arch/arm/mach-msm/wcnss-ssr-8974.c
@@ -0,0 +1,200 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/wcnss_wlan.h>
+#include <linux/delay.h>
+#include <mach/peripheral-loader.h>
+#include <mach/subsystem_restart.h>
+#include <mach/msm_smsm.h>
+
+#define MODULE_NAME "wcnss_8974"
+#define MAX_SSR_REASON_LEN 0x51
+
+static int ss_restart_inprogress;
+static int wcnss_crash;
+static struct subsys_device *wcnss_ssr_dev;
+static struct delayed_work cancel_vote_work;
+
+#define WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ 181
+
+static void log_wcnss_sfr(void)
+{
+ char *smem_reset_reason;
+ char buffer[MAX_SSR_REASON_LEN];
+ unsigned smem_reset_size;
+ unsigned size;
+
+ smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
+ &smem_reset_size);
+
+ if (!smem_reset_reason || !smem_reset_size) {
+ pr_err("%s: wcnss subsystem failure reason: %s\n",
+ __func__, "(unknown, smem_get_entry failed)");
+ } else if (!smem_reset_reason[0]) {
+ pr_err("%s: wcnss subsystem failure reason: %s\n",
+ __func__, "(unknown, init string found)");
+ } else {
+ size = smem_reset_size < MAX_SSR_REASON_LEN ? smem_reset_size :
+ (MAX_SSR_REASON_LEN - 1);
+ memcpy(buffer, smem_reset_reason, size);
+ buffer[size] = '\0';
+ pr_err("%s: wcnss subsystem failure reason: %s\n",
+ __func__, buffer);
+ memset(smem_reset_reason, 0, smem_reset_size);
+ wmb();
+ }
+}
+
+static void restart_wcnss(void)
+{
+ log_wcnss_sfr();
+ subsystem_restart("wcnss");
+}
+
+static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
+ uint32_t new_state)
+{
+ wcnss_crash = true;
+
+ pr_err("%s: smsm state changed\n", MODULE_NAME);
+
+ if (!(new_state & SMSM_RESET))
+ return;
+
+ if (ss_restart_inprogress) {
+ pr_err("%s: Ignoring smsm reset req, restart in progress\n",
+ MODULE_NAME);
+ return;
+ }
+
+ ss_restart_inprogress = true;
+ restart_wcnss();
+}
+
+
+static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
+{
+ wcnss_crash = true;
+
+ if (ss_restart_inprogress) {
+ pr_err("%s: Ignoring wcnss bite irq, restart in progress\n",
+ MODULE_NAME);
+ return IRQ_HANDLED;
+ }
+
+ ss_restart_inprogress = true;
+ restart_wcnss();
+
+ return IRQ_HANDLED;
+}
+
+static void wcnss_post_bootup(struct work_struct *work)
+{
+ struct platform_device *pdev = wcnss_get_platform_device();
+ struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+
+ pr_debug(MODULE_NAME ": Cancel APPS vote for Iris & Pronto\n");
+
+ wcnss_wlan_power(&pdev->dev, pwlanconfig,
+ WCNSS_WLAN_SWITCH_OFF);
+}
+
+static int wcnss_shutdown(const struct subsys_desc *subsys)
+{
+ pil_force_shutdown("wcnss");
+ flush_delayed_work(&cancel_vote_work);
+ wcnss_flush_delayed_boot_votes();
+ disable_irq_nosync(WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ);
+
+ return 0;
+}
+
+static int wcnss_powerup(const struct subsys_desc *subsys)
+{
+ struct platform_device *pdev = wcnss_get_platform_device();
+ struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
+ int ret = -1;
+
+ if (pdev && pwlanconfig)
+ ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
+ WCNSS_WLAN_SWITCH_ON);
+ if (!ret) {
+ msleep(1000);
+ pil_force_boot("wcnss");
+ }
+ ss_restart_inprogress = false;
+ enable_irq(WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ);
+ schedule_delayed_work(&cancel_vote_work, msecs_to_jiffies(5000));
+
+ return 0;
+}
+
+/* wcnss crash handler */
+static void wcnss_crash_shutdown(const struct subsys_desc *subsys)
+{
+ pr_err("%s: crash shutdown : %d\n", MODULE_NAME, wcnss_crash);
+ if (wcnss_crash != true)
+ smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
+}
+
+static int wcnss_ramdump(int enable,
+ const struct subsys_desc *crashed_subsys)
+{
+ return 0;
+}
+
+static struct subsys_desc wcnss_ssr = {
+ .name = "wcnss",
+ .shutdown = wcnss_shutdown,
+ .powerup = wcnss_powerup,
+ .ramdump = wcnss_ramdump,
+ .crash_shutdown = wcnss_crash_shutdown
+};
+
+static int __init wcnss_ssr_init(void)
+{
+ int ret;
+
+ ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
+ smsm_state_cb_hdlr, 0);
+ if (ret < 0) {
+ pr_err("%s: Unable to register smsm callback for wcnss Reset! %d\n",
+ MODULE_NAME, ret);
+ goto out;
+ }
+ ret = request_irq(WCNSS_APSS_WDOG_BITE_RESET_RDY_IRQ,
+ wcnss_wdog_bite_irq_hdlr, IRQF_TRIGGER_HIGH,
+ "wcnss_wdog", NULL);
+
+ if (ret < 0) {
+ pr_err("%s: Unable to register for wcnss bite interrupt (%d)\n",
+ MODULE_NAME, ret);
+ goto out;
+ }
+ wcnss_ssr_dev = subsys_register(&wcnss_ssr);
+ if (IS_ERR(wcnss_ssr_dev))
+ return PTR_ERR(wcnss_ssr_dev);
+
+ INIT_DELAYED_WORK(&cancel_vote_work, wcnss_post_bootup);
+
+ pr_info("%s: module initialized\n", MODULE_NAME);
+out:
+ return ret;
+}
+
+arch_initcall(wcnss_ssr_init);
diff --git a/arch/arm/mach-msm/wdog_debug.c b/arch/arm/mach-msm/wdog_debug.c
new file mode 100644
index 0000000..08dd9ce
--- /dev/null
+++ b/arch/arm/mach-msm/wdog_debug.c
@@ -0,0 +1,148 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <mach/scm.h>
+#include <linux/slab.h>
+
+#define MODULE_NAME "wdog_debug"
+#define WDOG_DEBUG_EN 17
+#define GCC_WDOG_DEBUG_OFFSET 0x780
+
+struct msm_wdog_debug_data {
+ unsigned int __iomem phys_base;
+ size_t size;
+ void __iomem *base;
+ struct device *dev;
+};
+
+static struct msm_wdog_debug_data *wdog_data;
+
+void msm_disable_wdog_debug(void)
+{
+ unsigned long int value;
+
+ if (wdog_data == NULL)
+ return;
+ value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+ value &= ~BIT(WDOG_DEBUG_EN);
+ writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+}
+EXPORT_SYMBOL(msm_disable_wdog_debug);
+
+void msm_enable_wdog_debug(void)
+{
+ unsigned long int value;
+
+ if (wdog_data == NULL)
+ return;
+ value = readl_relaxed(wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+ value |= BIT(WDOG_DEBUG_EN);
+ writel_relaxed(value, wdog_data->base + GCC_WDOG_DEBUG_OFFSET);
+}
+EXPORT_SYMBOL(msm_enable_wdog_debug);
+
+static int __devexit msm_wdog_debug_remove(struct platform_device *pdev)
+{
+ kfree(wdog_data);
+ wdog_data = NULL;
+ pr_info("MSM wdog_debug Exit - Deactivated\n");
+ return 0;
+}
+
+static int __devinit msm_wdog_debug_dt_to_pdata(struct platform_device *pdev,
+ struct msm_wdog_debug_data *pdata)
+{
+ struct resource *wdog_resource;
+
+ wdog_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!wdog_resource) {
+ dev_err(&pdev->dev, \
+ "%s cannot allocate resource for wdog_debug\n", \
+ __func__);
+ return -ENXIO;
+ }
+ pdata->size = resource_size(wdog_resource);
+ pdata->phys_base = wdog_resource->start;
+ if (unlikely(!(devm_request_region(&pdev->dev, pdata->phys_base,
+ pdata->size, "msm-wdog-debug")))) {
+ dev_err(&pdev->dev, "%s cannot reserve wdog_debug region\n",
+ __func__);
+ return -ENXIO;
+ }
+ pdata->base = devm_ioremap(&pdev->dev, pdata->phys_base,
+ pdata->size);
+ if (!pdata->base) {
+ dev_err(&pdev->dev, "%s cannot map wdog register space\n",
+ __func__);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int __devinit msm_wdog_debug_probe(struct platform_device *pdev)
+{
+ int ret;
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+ wdog_data = kzalloc(sizeof(struct msm_wdog_debug_data), GFP_KERNEL);
+ if (!wdog_data)
+ return -ENOMEM;
+ ret = msm_wdog_debug_dt_to_pdata(pdev, wdog_data);
+ if (ret)
+ goto err;
+ wdog_data->dev = &pdev->dev;
+ platform_set_drvdata(pdev, wdog_data);
+ return 0;
+err:
+ kzfree(wdog_data);
+ wdog_data = NULL;
+ return ret;
+}
+
+static struct of_device_id msm_wdog_debug_match_table[] = {
+ { .compatible = "qcom,msm-wdog-debug" },
+ {}
+};
+
+static struct platform_driver msm_wdog_debug_driver = {
+ .probe = msm_wdog_debug_probe,
+ .remove = msm_wdog_debug_remove,
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = msm_wdog_debug_match_table,
+ },
+};
+
+static int __devinit wdog_debug_init(void)
+{
+ return platform_driver_register(&msm_wdog_debug_driver);
+}
+module_init(wdog_debug_init);
+
+static void __exit wdog_debug_exit(void)
+{
+ platform_driver_unregister(&msm_wdog_debug_driver);
+}
+module_exit(wdog_debug_exit);
+
+MODULE_DESCRIPTION("MSM Driver to disable debug Image");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/wdog_debug.h b/arch/arm/mach-msm/wdog_debug.h
new file mode 100644
index 0000000..920aa89
--- /dev/null
+++ b/arch/arm/mach-msm/wdog_debug.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WDOG_DEBUG_H
+#define __WDOG_DEBUG_H
+
+#ifdef CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL
+void msm_enable_wdog_debug(void);
+void msm_disable_wdog_debug(void);
+#else
+void msm_enable_wdog_debug(void) { }
+void msm_disable_wdog_debug(void) { }
+#endif
+
+#endif
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index cb245ee..e351eb0 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -880,6 +880,16 @@
This option enables optimisations for the PL310 cache
controller.
+config CACHE_PL310_ERP
+ tristate "PL310 CACHE Error Reporting"
+ depends on CACHE_PL310
+ help
+ Say 'Y' here to enable reporting of external L2 cache errors.
+ This feature can be used as a system debugging technique if cache
+ corruption is suspected.
+ Cache error statistics will also be reported in sysfs
+ /sys/devices/platform/pl310_erp/cache_erp
+
config CACHE_TAUROS2
bool "Enable the Tauros2 L2 cache controller"
depends on (ARCH_DOVE || ARCH_MMP || CPU_PJ4)
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 1c415af..6314e94 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -100,6 +100,7 @@
obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
+obj-$(CONFIG_CACHE_PL310_ERP) += cache-pl310-erp.o
obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o
obj-$(CONFIG_CACHE_TAUROS2) += cache-tauros2.o
obj-$(CONFIG_VCM) += vcm.o vcm_alloc.o
diff --git a/arch/arm/mm/cache-pl310-erp.c b/arch/arm/mm/cache-pl310-erp.c
new file mode 100644
index 0000000..ad75143
--- /dev/null
+++ b/arch/arm/mm/cache-pl310-erp.c
@@ -0,0 +1,283 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/cpu.h>
+#include <linux/io.h>
+#include <asm/cputype.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#define MODULE_NAME "pl310_erp"
+
+struct pl310_drv_data {
+ unsigned int irq;
+ unsigned int ecntr;
+ unsigned int parrt;
+ unsigned int parrd;
+ unsigned int errwd;
+ unsigned int errwt;
+ unsigned int errrt;
+ unsigned int errrd;
+ unsigned int slverr;
+ unsigned int decerr;
+ void __iomem *base;
+};
+
+#define ECNTR BIT(0)
+#define PARRT BIT(1)
+#define PARRD BIT(2)
+#define ERRWT BIT(3)
+#define ERRWD BIT(4)
+#define ERRRT BIT(5)
+#define ERRRD BIT(6)
+#define SLVERR BIT(7)
+#define DECERR BIT(8)
+
+static irqreturn_t pl310_erp_irq(int irq, void *dev_id)
+{
+ struct pl310_drv_data *p = platform_get_drvdata(dev_id);
+ uint16_t mask_int_stat, int_clear = 0, error = 0;
+
+ mask_int_stat = readl_relaxed(p->base + L2X0_MASKED_INTR_STAT);
+
+ if (mask_int_stat & ECNTR) {
+ pr_alert("Event Counter1/0 Overflow Increment error\n");
+ p->ecntr++;
+ int_clear = mask_int_stat & ECNTR;
+ }
+
+ if (mask_int_stat & PARRT) {
+ pr_alert("Read parity error on L2 Tag RAM\n");
+ p->parrt++;
+ error = 1;
+ int_clear = mask_int_stat & PARRT;
+ }
+
+ if (mask_int_stat & PARRD) {
+ pr_alert("Read parity error on L2 Tag RAM\n");
+ p->parrd++;
+ error = 1;
+ int_clear = mask_int_stat & PARRD;
+ }
+
+ if (mask_int_stat & ERRWT) {
+ pr_alert("Write error on L2 Tag RAM\n");
+ p->errwt++;
+ int_clear = mask_int_stat & ERRWT;
+ }
+
+ if (mask_int_stat & ERRWD) {
+ pr_alert("Write error on L2 Data RAM\n");
+ p->errwd++;
+ int_clear = mask_int_stat & ERRWD;
+ }
+
+ if (mask_int_stat & ERRRT) {
+ pr_alert("Read error on L2 Tag RAM\n");
+ p->errrt++;
+ int_clear = mask_int_stat & ERRRT;
+ }
+
+ if (mask_int_stat & ERRRD) {
+ pr_alert("Read error on L2 Data RAM\n");
+ p->errrd++;
+ int_clear = mask_int_stat & ERRRD;
+ }
+
+ if (mask_int_stat & DECERR) {
+ pr_alert("L2 master port decode error\n");
+ p->decerr++;
+ int_clear = mask_int_stat & DECERR;
+ }
+
+ if (mask_int_stat & SLVERR) {
+ pr_alert("L2 slave port error\n");
+ p->slverr++;
+ int_clear = mask_int_stat & SLVERR;
+ }
+
+ writel_relaxed(int_clear, p->base + L2X0_INTR_CLEAR);
+
+ /* Make sure the interrupts are cleared */
+ mb();
+
+ /* WARNING will be thrown whenever we receive any L2 interrupt.
+ * Other than parity on tag/data ram, irrespective of the bits
+ * set we will throw a warning.
+ */
+ WARN_ON(!error);
+
+ /* Panic in case we encounter parity error in TAG/DATA Ram */
+ BUG_ON(error);
+
+ return IRQ_HANDLED;
+}
+
+static void pl310_mask_int(struct pl310_drv_data *p, bool enable)
+{
+ uint16_t mask;
+
+ if (enable)
+ mask = 0x1FF;
+ else
+ mask = 0x0;
+
+ writel_relaxed(mask, p->base + L2X0_INTR_MASK);
+
+ /* Make sure Mask is updated */
+ mb();
+
+ pr_debug("Mask interrupt %x\n",
+ readl_relaxed(p->base + L2X0_INTR_MASK));
+}
+
+static int pl310_erp_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct pl310_drv_data *p = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE,
+ "L2CC Interrupt Number:\t\t\t%d\n"\
+ "Event Counter1/0 Overflow Increment:\t%u\n"\
+ "Parity Error on L2 Tag RAM (Read):\t%u\n"\
+ "Parity Error on L2 Data RAM (Read):\t%u\n"\
+ "Error on L2 Tag RAM (Write):\t\t%u\n"\
+ "Error on L2 Data RAM (Write):\t\t%u\n"\
+ "Error on L2 Tag RAM (Read):\t\t%u\n"\
+ "Error on L2 Data RAM (Read):\t\t%u\n"\
+ "SLave Error from L3 Port:\t\t%u\n"\
+ "Decode Error from L3 Port:\t\t%u\n",
+ p->irq, p->ecntr, p->parrt, p->parrd, p->errwt, p->errwd,
+ p->errrt, p->errrd, p->slverr, p->decerr);
+}
+
+static DEVICE_ATTR(cache_erp, 0664, pl310_erp_show, NULL);
+
+static int __init pl310_create_sysfs(struct device *dev)
+{
+ /* create a sysfs entry at
+ * /sys/devices/platform/pl310_erp/cache_erp
+ */
+ return device_create_file(dev, &dev_attr_cache_erp);
+}
+
+static int __devinit pl310_cache_erp_probe(struct platform_device *pdev)
+{
+ struct resource *r;
+ struct pl310_drv_data *drv_data;
+ int ret;
+
+ drv_data = devm_kzalloc(&pdev->dev, sizeof(struct pl310_drv_data),
+ GFP_KERNEL);
+ if (drv_data == NULL) {
+ dev_err(&pdev->dev, "cannot allocate memory\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "No L2 base address\n");
+ ret = -ENODEV;
+ goto error;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
+ "erp")) {
+ ret = -EBUSY;
+ goto error;
+ }
+
+ drv_data->base = devm_ioremap_nocache(&pdev->dev, r->start,
+ resource_size(r));
+ if (!drv_data->base) {
+ dev_err(&pdev->dev, "errored to ioremap 0x%x\n", r->start);
+ ret = -ENOMEM;
+ goto error;
+ }
+ dev_dbg(&pdev->dev, "L2CC base 0x%p\n", drv_data->base);
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "l2_irq");
+ if (!r) {
+ dev_err(&pdev->dev, "No L2 IRQ resource\n");
+ ret = -ENODEV;
+ goto error;
+ }
+
+ drv_data->irq = r->start;
+
+ ret = devm_request_irq(&pdev->dev, drv_data->irq, pl310_erp_irq,
+ IRQF_TRIGGER_RISING, "l2cc_intr", pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "request irq for L2 interrupt failed\n");
+ goto error;
+ }
+
+ platform_set_drvdata(pdev, drv_data);
+
+ pl310_mask_int(drv_data, true);
+
+ ret = pl310_create_sysfs(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to create sysfs entry\n");
+ goto sysfs_err;
+ }
+
+ return 0;
+
+sysfs_err:
+ platform_set_drvdata(pdev, NULL);
+ pl310_mask_int(drv_data, false);
+error:
+ return ret;
+}
+
+static int __devexit pl310_cache_erp_remove(struct platform_device *pdev)
+{
+ struct pl310_drv_data *p = platform_get_drvdata(pdev);
+
+ pl310_mask_int(p, false);
+
+ device_remove_file(&pdev->dev, &dev_attr_cache_erp);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver pl310_cache_erp_driver = {
+ .probe = pl310_cache_erp_probe,
+ .remove = __devexit_p(pl310_cache_erp_remove),
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pl310_cache_erp_init(void)
+{
+ return platform_driver_register(&pl310_cache_erp_driver);
+}
+module_init(pl310_cache_erp_init);
+
+static void __exit pl310_cache_erp_exit(void)
+{
+ platform_driver_unregister(&pl310_cache_erp_driver);
+}
+module_exit(pl310_cache_erp_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PL310 cache error reporting driver");
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 47dab27..ba93e68 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -393,6 +393,16 @@
.size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
/*
+ * Qualcomm Inc. Krait processors.
+ */
+ .type __krait_proc_info, #object
+__krait_proc_info:
+ .long 0x510f0400 @ Required ID value
+ .long 0xff0ffc00 @ Mask for ID
+ __v7_proc __v7_setup, hwcaps = HWCAP_IDIV
+ .size __krait_proc_info, . - __krait_proc_info
+
+ /*
* Match any ARMv7 processor core.
*/
.type __v7_proc_info, #object
diff --git a/drivers/bluetooth/hci_ibs.c b/drivers/bluetooth/hci_ibs.c
index 6253605..acff5a5 100644
--- a/drivers/bluetooth/hci_ibs.c
+++ b/drivers/bluetooth/hci_ibs.c
@@ -254,13 +254,14 @@
struct ibs_struct *ibs = container_of(work, struct ibs_struct,
ws_awake_device);
struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+ unsigned long flags;
BT_DBG(" %p ", hu);
/* Vote for serial clock */
ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
- spin_lock(&ibs->hci_ibs_lock);
+ spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
/* send wake indication to device */
if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
@@ -271,7 +272,8 @@
/* start retransmit timer */
mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
- spin_unlock(&ibs->hci_ibs_lock);
+ spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+
}
static void ibs_wq_awake_rx(struct work_struct *work)
@@ -279,12 +281,14 @@
struct ibs_struct *ibs = container_of(work, struct ibs_struct,
ws_awake_rx);
struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+ unsigned long flags;
BT_DBG(" %p ", hu);
ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
- spin_lock(&ibs->hci_ibs_lock);
+ spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
+
ibs->rx_ibs_state = HCI_IBS_RX_AWAKE;
/* Always acknowledge device wake up,
* sending IBS message doesn't count as TX ON
@@ -294,7 +298,8 @@
ibs->ibs_sent_wacks++; /* debug */
- spin_unlock(&ibs->hci_ibs_lock);
+ spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+
/* actually send the packets */
hci_uart_tx_wakeup(hu);
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index ea75ffd..6ecc970 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -2,4 +2,4 @@
obj-$(CONFIG_DIAG_SDIO_PIPE) += diagfwd_sdio.o
obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_hsic.o
obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_smux.o
-diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o diag_dci.o
+diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o diag_dci.o diag_masks.o diag_debugfs.o
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
new file mode 100644
index 0000000..ed0f08e
--- /dev/null
+++ b/drivers/char/diag/diag_debugfs.c
@@ -0,0 +1,305 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include "diagchar.h"
+#include "diagfwd.h"
+
+#define DEBUG_BUF_SIZE 4096
+static struct dentry *diag_dbgfs_dent;
+static int diag_dbgfs_table_index;
+
+static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char *buf;
+ int ret;
+
+ buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+ if (!buf) {
+ pr_err("diag: %s, Error allocating memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret = scnprintf(buf, DEBUG_BUF_SIZE,
+ "modem ch: 0x%x\n"
+ "lpass ch: 0x%x\n"
+ "riva ch: 0x%x\n"
+ "dci ch: 0x%x\n"
+ "modem cntl_ch: 0x%x\n"
+ "lpass cntl_ch: 0x%x\n"
+ "riva cntl_ch: 0x%x\n"
+ "CPU Tools id: %d\n"
+ "Apps only: %d\n"
+ "Apps master: %d\n"
+ "Check Polling Response: %d\n"
+ "polling_reg_flag: %d\n"
+ "uses device tree: %d\n"
+ "in_busy_1: %d\n"
+ "in_busy_2: %d\n"
+ "in_busy_lpass_1: %d\n"
+ "in_busy_lpass_2: %d\n"
+ "in_busy_wcnss_1: %d\n"
+ "in_busy_wcnss_2: %d\n"
+ "in_busy_dci: %d\n"
+ "logging_mode: %d\n",
+ (unsigned int)driver->ch,
+ (unsigned int)driver->chlpass,
+ (unsigned int)driver->ch_wcnss,
+ (unsigned int)driver->ch_dci,
+ (unsigned int)driver->ch_cntl,
+ (unsigned int)driver->chlpass_cntl,
+ (unsigned int)driver->ch_wcnss_cntl,
+ chk_config_get_id(),
+ chk_apps_only(),
+ chk_apps_master(),
+ chk_polling_response(),
+ driver->polling_reg_flag,
+ driver->use_device_tree,
+ driver->in_busy_1,
+ driver->in_busy_2,
+ driver->in_busy_lpass_1,
+ driver->in_busy_lpass_2,
+ driver->in_busy_wcnss_1,
+ driver->in_busy_wcnss_2,
+ driver->in_busy_dci,
+ driver->logging_mode);
+
+#ifdef CONFIG_DIAG_OVER_USB
+ ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
+ "usb_connected: %d\n",
+ driver->usb_connected);
+#endif
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
+
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t diag_dbgfs_read_workpending(struct file *file,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ char *buf;
+ int ret;
+
+ buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+ if (!buf) {
+ pr_err("diag: %s, Error allocating memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret = scnprintf(buf, DEBUG_BUF_SIZE,
+ "Pending status for work_stucts:\n"
+ "diag_drain_work: %d\n"
+ "diag_read_smd_work: %d\n"
+ "diag_read_smd_cntl_work: %d\n"
+ "diag_read_smd_lpass_work: %d\n"
+ "diag_read_smd_lpass_cntl_work: %d\n"
+ "diag_read_smd_wcnss_work: %d\n"
+ "diag_read_smd_wcnss_cntl_work: %d\n"
+ "diag_modem_mask_update_work: %d\n"
+ "diag_lpass_mask_update_work: %d\n"
+ "diag_wcnss_mask_update_work: %d\n"
+ "diag_read_smd_dci_work: %d\n",
+ work_pending(&(driver->diag_drain_work)),
+ work_pending(&(driver->diag_read_smd_work)),
+ work_pending(&(driver->diag_read_smd_cntl_work)),
+ work_pending(&(driver->diag_read_smd_lpass_work)),
+ work_pending(&(driver->diag_read_smd_lpass_cntl_work)),
+ work_pending(&(driver->diag_read_smd_wcnss_work)),
+ work_pending(&(driver->diag_read_smd_wcnss_cntl_work)),
+ work_pending(&(driver->diag_modem_mask_update_work)),
+ work_pending(&(driver->diag_lpass_mask_update_work)),
+ work_pending(&(driver->diag_wcnss_mask_update_work)),
+ work_pending(&(driver->diag_read_smd_dci_work)));
+
+#ifdef CONFIG_DIAG_OVER_USB
+ ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
+ "diag_proc_hdlc_work: %d\n"
+ "diag_read_work: %d\n",
+ work_pending(&(driver->diag_proc_hdlc_work)),
+ work_pending(&(driver->diag_read_work)));
+#endif
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
+
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char *buf;
+ int ret = 0;
+ int i;
+ int bytes_remaining;
+ int bytes_in_buffer = 0;
+ int bytes_written;
+ int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
+
+ if (diag_dbgfs_table_index >= diag_max_reg) {
+ /* Done. Reset to prepare for future requests */
+ diag_dbgfs_table_index = 0;
+ return 0;
+ }
+
+ buf = kzalloc(sizeof(char) * buf_size, GFP_KERNEL);
+ if (!buf) {
+ pr_err("diag: %s, Error allocating memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ bytes_remaining = buf_size;
+ for (i = diag_dbgfs_table_index; i < diag_max_reg; i++) {
+ /* Do not process empty entries in the table */
+ if (driver->table[i].process_id == 0)
+ continue;
+
+ bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
+ "i: %3d, cmd_code: %4x, subsys_id: %4x, "
+ "client: %2d, cmd_code_lo: %4x, "
+ "cmd_code_hi: %4x, process_id: %5d\n",
+ i,
+ driver->table[i].cmd_code,
+ driver->table[i].subsys_id,
+ driver->table[i].client_id,
+ driver->table[i].cmd_code_lo,
+ driver->table[i].cmd_code_hi,
+ driver->table[i].process_id);
+
+ bytes_in_buffer += bytes_written;
+
+ /* Check if there is room to add another table entry */
+ bytes_remaining = buf_size - bytes_in_buffer;
+ if (bytes_remaining < bytes_written)
+ break;
+ }
+ diag_dbgfs_table_index = i;
+
+ *ppos = 0;
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
+
+ kfree(buf);
+ return ret;
+}
+
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+static ssize_t diag_dbgfs_read_hsic(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char *buf;
+ int ret;
+
+ buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+ if (!buf) {
+ pr_err("diag: %s, Error allocating memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret = scnprintf(buf, DEBUG_BUF_SIZE,
+ "hsic ch: %d\n"
+ "hsic_inited: %d\n"
+ "hsic enabled: %d\n"
+ "hsic_opened: %d\n"
+ "hsic_suspend: %d\n"
+ "in_busy_hsic_read_on_device: %d\n"
+ "in_busy_hsic_write: %d\n"
+ "count_hsic_pool: %d\n"
+ "count_hsic_write_pool: %d\n"
+ "diag_hsic_pool: %x\n"
+ "diag_hsic_write_pool: %x\n"
+ "write_len_mdm: %d\n"
+ "num_hsic_buf_tbl_entries: %d\n"
+ "usb_mdm_connected: %d\n"
+ "diag_read_mdm_work: %d\n"
+ "diag_read_hsic_work: %d\n"
+ "diag_disconnect_work: %d\n"
+ "diag_usb_read_complete_work: %d\n",
+ driver->hsic_ch,
+ driver->hsic_inited,
+ driver->hsic_device_enabled,
+ driver->hsic_device_opened,
+ driver->hsic_suspend,
+ driver->in_busy_hsic_read_on_device,
+ driver->in_busy_hsic_write,
+ driver->count_hsic_pool,
+ driver->count_hsic_write_pool,
+ (unsigned int)driver->diag_hsic_pool,
+ (unsigned int)driver->diag_hsic_write_pool,
+ driver->write_len_mdm,
+ driver->num_hsic_buf_tbl_entries,
+ driver->usb_mdm_connected,
+ work_pending(&(driver->diag_read_mdm_work)),
+ work_pending(&(driver->diag_read_hsic_work)),
+ work_pending(&(driver->diag_disconnect_work)),
+ work_pending(&(driver->diag_usb_read_complete_work)));
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
+
+ kfree(buf);
+ return ret;
+}
+
+const struct file_operations diag_dbgfs_hsic_ops = {
+ .read = diag_dbgfs_read_hsic,
+};
+#endif
+
+const struct file_operations diag_dbgfs_status_ops = {
+ .read = diag_dbgfs_read_status,
+};
+
+const struct file_operations diag_dbgfs_table_ops = {
+ .read = diag_dbgfs_read_table,
+};
+
+const struct file_operations diag_dbgfs_workpending_ops = {
+ .read = diag_dbgfs_read_workpending,
+};
+
+void diag_debugfs_init(void)
+{
+ diag_dbgfs_dent = debugfs_create_dir("diag", 0);
+ if (IS_ERR(diag_dbgfs_dent))
+ return;
+
+ debugfs_create_file("status", 0444, diag_dbgfs_dent, 0,
+ &diag_dbgfs_status_ops);
+
+ debugfs_create_file("table", 0444, diag_dbgfs_dent, 0,
+ &diag_dbgfs_table_ops);
+
+ debugfs_create_file("work_pending", 0444, diag_dbgfs_dent, 0,
+ &diag_dbgfs_workpending_ops);
+
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ debugfs_create_file("hsic", 0444, diag_dbgfs_dent, 0,
+ &diag_dbgfs_hsic_ops);
+#endif
+
+ diag_dbgfs_table_index = 0;
+}
+
+void diag_debugfs_cleanup(void)
+{
+ if (diag_dbgfs_dent) {
+ debugfs_remove_recursive(diag_dbgfs_dent);
+ diag_dbgfs_dent = NULL;
+ }
+}
+#else
+void diag_debugfs_init(void) { }
+void diag_debugfs_cleanup(void) { }
+#endif
diff --git a/drivers/char/diag/diag_debugfs.h b/drivers/char/diag/diag_debugfs.h
new file mode 100644
index 0000000..4bc8b0f
--- /dev/null
+++ b/drivers/char/diag/diag_debugfs.h
@@ -0,0 +1,19 @@
+/* Copyright (c)2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DIAG_DEBUGFS_H
+#define DIAG_DEBUGFS_H
+
+void diag_debugfs_init(void);
+void diag_debugfs_cleanup(void);
+
+#endif
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
new file mode 100644
index 0000000..5316548
--- /dev/null
+++ b/drivers/char/diag/diag_masks.c
@@ -0,0 +1,790 @@
+/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/diagchar.h>
+#include <linux/kmemleak.h>
+#include <linux/workqueue.h>
+#include "diagchar.h"
+#include "diagfwd_cntl.h"
+#include "diag_masks.h"
+
+int diag_event_config;
+int diag_event_num_bytes;
+
+#define ALL_EQUIP_ID 100
+#define ALL_SSID -1
+#define MAX_SSID_PER_RANGE 100
+
+struct mask_info {
+ int equip_id;
+ int num_items;
+ int index;
+};
+
+#define CREATE_MSG_MASK_TBL_ROW(XX) \
+do { \
+ *(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX; \
+ msg_mask_tbl_ptr += 4; \
+ *(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST; \
+ msg_mask_tbl_ptr += 4; \
+ /* mimic the last entry as actual_last while creation */ \
+ *(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST; \
+ msg_mask_tbl_ptr += 4; \
+ /* increment by MAX_SSID_PER_RANGE cells */ \
+ msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int); \
+} while (0)
+
+#define WAIT_FOR_SMD(num_delays, delay_time) \
+do { \
+ int count; \
+ for (count = 0; count < (num_delays); count++) \
+ udelay((delay_time)); \
+} while (0)
+
+static void diag_print_mask_table(void)
+{
+/* Enable this to print mask table when updated */
+#ifdef MASK_DEBUG
+ int first, last, actual_last;
+ uint8_t *ptr = driver->msg_masks;
+ int i = 0;
+ pr_info("diag: F3 message mask table\n");
+ while (*(uint32_t *)(ptr + 4)) {
+ first = *(uint32_t *)ptr;
+ ptr += 4;
+ last = *(uint32_t *)ptr;
+ ptr += 4;
+ actual_last = *(uint32_t *)ptr;
+ ptr += 4;
+ pr_info("diag: SSID %d, %d - %d\n", first, last, actual_last);
+ for (i = 0 ; i <= actual_last - first ; i++)
+ pr_info("diag: MASK:%x\n", *((uint32_t *)ptr + i));
+ ptr += MAX_SSID_PER_RANGE*4;
+ }
+#endif
+}
+
+void diag_create_msg_mask_table(void)
+{
+ uint8_t *msg_mask_tbl_ptr = driver->msg_masks;
+
+ CREATE_MSG_MASK_TBL_ROW(0);
+ CREATE_MSG_MASK_TBL_ROW(1);
+ CREATE_MSG_MASK_TBL_ROW(2);
+ CREATE_MSG_MASK_TBL_ROW(3);
+ CREATE_MSG_MASK_TBL_ROW(4);
+ CREATE_MSG_MASK_TBL_ROW(5);
+ CREATE_MSG_MASK_TBL_ROW(6);
+ CREATE_MSG_MASK_TBL_ROW(7);
+ CREATE_MSG_MASK_TBL_ROW(8);
+ CREATE_MSG_MASK_TBL_ROW(9);
+ CREATE_MSG_MASK_TBL_ROW(10);
+ CREATE_MSG_MASK_TBL_ROW(11);
+ CREATE_MSG_MASK_TBL_ROW(12);
+ CREATE_MSG_MASK_TBL_ROW(13);
+ CREATE_MSG_MASK_TBL_ROW(14);
+ CREATE_MSG_MASK_TBL_ROW(15);
+ CREATE_MSG_MASK_TBL_ROW(16);
+ CREATE_MSG_MASK_TBL_ROW(17);
+ CREATE_MSG_MASK_TBL_ROW(18);
+ CREATE_MSG_MASK_TBL_ROW(19);
+ CREATE_MSG_MASK_TBL_ROW(20);
+ CREATE_MSG_MASK_TBL_ROW(21);
+ CREATE_MSG_MASK_TBL_ROW(22);
+ CREATE_MSG_MASK_TBL_ROW(23);
+}
+
+static void diag_set_msg_mask(int rt_mask)
+{
+ int first_ssid, last_ssid, i;
+ uint8_t *parse_ptr, *ptr = driver->msg_masks;
+
+ mutex_lock(&driver->diagchar_mutex);
+ while (*(uint32_t *)(ptr + 4)) {
+ first_ssid = *(uint32_t *)ptr;
+ ptr += 8; /* increment by 8 to skip 'last' */
+ last_ssid = *(uint32_t *)ptr;
+ ptr += 4;
+ parse_ptr = ptr;
+ pr_debug("diag: updating range %d %d\n", first_ssid, last_ssid);
+ for (i = 0; i < last_ssid - first_ssid + 1; i++) {
+ *(int *)parse_ptr = rt_mask;
+ parse_ptr += 4;
+ }
+ ptr += MAX_SSID_PER_RANGE * 4;
+ }
+ mutex_unlock(&driver->diagchar_mutex);
+}
+
+static void diag_update_msg_mask(int start, int end , uint8_t *buf)
+{
+ int found = 0, first, last, actual_last;
+ uint8_t *actual_last_ptr;
+ uint8_t *ptr = driver->msg_masks;
+ uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
+ uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
+
+ mutex_lock(&driver->diagchar_mutex);
+
+ /* First SSID can be zero : So check that last is non-zero */
+ while (*(uint32_t *)(ptr + 4)) {
+ first = *(uint32_t *)ptr;
+ ptr += 4;
+ last = *(uint32_t *)ptr;
+ ptr += 4;
+ actual_last = *(uint32_t *)ptr;
+ actual_last_ptr = ptr;
+ ptr += 4;
+ if (start >= first && start <= actual_last) {
+ ptr += (start - first)*4;
+ if (end > actual_last) {
+ pr_info("diag: ssid range mismatch\n");
+ actual_last = end;
+ *(uint32_t *)(actual_last_ptr) = end;
+ }
+ if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
+ (((end - start)+1)*4))) {
+ pr_debug("diag: update ssid start %d, end %d\n",
+ start, end);
+ memcpy(ptr, buf , ((end - start)+1)*4);
+ } else
+ pr_alert("diag: Not enough space MSG_MASK\n");
+ found = 1;
+ break;
+ } else {
+ ptr += MAX_SSID_PER_RANGE*4;
+ }
+ }
+ /* Entry was not found - add new table */
+ if (!found) {
+ if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
+ 8 + ((end - start) + 1)*4)) {
+ memcpy(ptr, &(start) , 4);
+ ptr += 4;
+ memcpy(ptr, &(end), 4);
+ ptr += 4;
+ memcpy(ptr, &(end), 4); /* create actual_last entry */
+ ptr += 4;
+ pr_debug("diag: adding NEW ssid start %d, end %d\n",
+ start, end);
+ memcpy(ptr, buf , ((end - start) + 1)*4);
+ } else
+ pr_alert("diag: Not enough buffer space for MSG_MASK\n");
+ }
+ mutex_unlock(&driver->diagchar_mutex);
+ diag_print_mask_table();
+}
+
+void diag_toggle_event_mask(int toggle)
+{
+ uint8_t *ptr = driver->event_masks;
+
+ mutex_lock(&driver->diagchar_mutex);
+ if (toggle)
+ memset(ptr, 0xFF, EVENT_MASK_SIZE);
+ else
+ memset(ptr, 0, EVENT_MASK_SIZE);
+ mutex_unlock(&driver->diagchar_mutex);
+}
+
+
+static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
+{
+ uint8_t *ptr = driver->event_masks;
+ uint8_t *temp = buf + 2;
+
+ mutex_lock(&driver->diagchar_mutex);
+ if (!toggle)
+ memset(ptr, 0 , EVENT_MASK_SIZE);
+ else
+ if (CHK_OVERFLOW(ptr, ptr,
+ ptr+EVENT_MASK_SIZE, num_bytes))
+ memcpy(ptr, temp , num_bytes);
+ else
+ printk(KERN_CRIT "Not enough buffer space for EVENT_MASK\n");
+ mutex_unlock(&driver->diagchar_mutex);
+}
+
+static void diag_disable_log_mask(void)
+{
+ int i = 0;
+ struct mask_info *parse_ptr = (struct mask_info *)(driver->log_masks);
+
+ pr_debug("diag: disable log masks\n");
+ mutex_lock(&driver->diagchar_mutex);
+ for (i = 0; i < MAX_EQUIP_ID; i++) {
+ pr_debug("diag: equip id %d\n", parse_ptr->equip_id);
+ if (!(parse_ptr->equip_id)) /* Reached a null entry */
+ break;
+ memset(driver->log_masks + parse_ptr->index, 0,
+ (parse_ptr->num_items + 7)/8);
+ parse_ptr++;
+ }
+ mutex_unlock(&driver->diagchar_mutex);
+}
+
+int chk_equip_id_and_mask(int equip_id, uint8_t *buf)
+{
+ int i = 0, flag = 0, num_items, offset;
+ unsigned char *ptr_data;
+ struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+
+ pr_debug("diag: received equip id = %d\n", equip_id);
+ /* Check if this is valid equipment ID */
+ for (i = 0; i < MAX_EQUIP_ID; i++) {
+ if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
+ offset = ptr->index;
+ num_items = ptr->num_items;
+ flag = 1;
+ break;
+ }
+ ptr++;
+ }
+ if (!flag)
+ return -EPERM;
+ ptr_data = driver->log_masks + offset;
+ memcpy(buf, ptr_data, (num_items+7)/8);
+ return 0;
+}
+
+static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
+{
+ uint8_t *temp = buf;
+ int i = 0;
+ unsigned char *ptr_data;
+ int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
+ struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+
+ pr_debug("diag: received equip id = %d\n", equip_id);
+ mutex_lock(&driver->diagchar_mutex);
+ /* Check if we already know index of this equipment ID */
+ for (i = 0; i < MAX_EQUIP_ID; i++) {
+ if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
+ offset = ptr->index;
+ break;
+ }
+ if ((ptr->equip_id == 0) && (ptr->index == 0)) {
+ /* Reached a null entry */
+ ptr->equip_id = equip_id;
+ ptr->num_items = num_items;
+ ptr->index = driver->log_masks_length;
+ offset = driver->log_masks_length;
+ driver->log_masks_length += ((num_items+7)/8);
+ break;
+ }
+ ptr++;
+ }
+ ptr_data = driver->log_masks + offset;
+ if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
+ + LOG_MASK_SIZE, (num_items+7)/8))
+ memcpy(ptr_data, temp , (num_items+7)/8);
+ else
+ pr_err("diag: Not enough buffer space for LOG_MASK\n");
+ mutex_unlock(&driver->diagchar_mutex);
+}
+
+void diag_modem_mask_update_fn(struct work_struct *work)
+{
+ diag_send_msg_mask_update(driver->ch_cntl, ALL_SSID,
+ ALL_SSID, MODEM_PROC);
+ diag_send_log_mask_update(driver->ch_cntl, ALL_EQUIP_ID);
+ diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
+}
+
+void diag_lpass_mask_update_fn(struct work_struct *work)
+{
+ diag_send_msg_mask_update(driver->chlpass_cntl, ALL_SSID,
+ ALL_SSID, LPASS_PROC);
+ diag_send_log_mask_update(driver->chlpass_cntl, ALL_EQUIP_ID);
+ diag_send_event_mask_update(driver->chlpass_cntl, diag_event_num_bytes);
+}
+
+void diag_wcnss_mask_update_fn(struct work_struct *work)
+{
+ diag_send_msg_mask_update(driver->ch_wcnss_cntl, ALL_SSID,
+ ALL_SSID, WCNSS_PROC);
+ diag_send_log_mask_update(driver->ch_wcnss_cntl, ALL_EQUIP_ID);
+ diag_send_event_mask_update(driver->ch_wcnss_cntl,
+ diag_event_num_bytes);
+}
+
+void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
+{
+ void *buf = driver->buf_log_mask_update;
+ int header_size = sizeof(struct diag_ctrl_log_mask);
+ struct mask_info *ptr = (struct mask_info *)driver->log_masks;
+ int i, size, wr_size = -ENOMEM, retry_count = 0;
+
+ mutex_lock(&driver->diag_cntl_mutex);
+ for (i = 0; i < MAX_EQUIP_ID; i++) {
+ size = (ptr->num_items+7)/8;
+ /* reached null entry */
+ if ((ptr->equip_id == 0) && (ptr->index == 0))
+ break;
+ driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
+ driver->log_mask->num_items = ptr->num_items;
+ driver->log_mask->data_len = 11 + size;
+ driver->log_mask->stream_id = 1; /* 2, if dual stream */
+ driver->log_mask->status = 3; /* status for valid mask */
+ driver->log_mask->equip_id = ptr->equip_id;
+ driver->log_mask->log_mask_size = size;
+ /* send only desired update, NOT ALL */
+ if (equip_id == ALL_EQUIP_ID || equip_id ==
+ driver->log_mask->equip_id) {
+ memcpy(buf, driver->log_mask, header_size);
+ memcpy(buf+header_size, driver->log_masks+ptr->index,
+ size);
+ if (ch) {
+ while (retry_count < 3) {
+ wr_size = smd_write(ch, buf,
+ header_size + size);
+ if (wr_size == -ENOMEM) {
+ retry_count++;
+ WAIT_FOR_SMD(5, 2000);
+ } else
+ break;
+ }
+ if (wr_size != header_size + size)
+ pr_err("diag: log mask update failed %d, tried %d",
+ wr_size, header_size + size);
+ else
+ pr_debug("diag: updated log equip ID %d,len %d\n",
+ driver->log_mask->equip_id,
+ driver->log_mask->log_mask_size);
+ } else
+ pr_err("diag: ch not valid for log update\n");
+ }
+ ptr++;
+ }
+ mutex_unlock(&driver->diag_cntl_mutex);
+}
+
+void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
+{
+ void *buf = driver->buf_event_mask_update;
+ int header_size = sizeof(struct diag_ctrl_event_mask);
+ int wr_size = -ENOMEM, retry_count = 0;
+
+ mutex_lock(&driver->diag_cntl_mutex);
+ if (num_bytes == 0) {
+ pr_debug("diag: event mask not set yet, so no update\n");
+ mutex_unlock(&driver->diag_cntl_mutex);
+ return;
+ }
+ /* send event mask update */
+ driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
+ driver->event_mask->data_len = 7 + num_bytes;
+ driver->event_mask->stream_id = 1; /* 2, if dual stream */
+ driver->event_mask->status = 3; /* status for valid mask */
+ driver->event_mask->event_config = diag_event_config; /* event config */
+ driver->event_mask->event_mask_size = num_bytes;
+ memcpy(buf, driver->event_mask, header_size);
+ memcpy(buf+header_size, driver->event_masks, num_bytes);
+ if (ch) {
+ while (retry_count < 3) {
+ wr_size = smd_write(ch, buf, header_size + num_bytes);
+ if (wr_size == -ENOMEM) {
+ retry_count++;
+ WAIT_FOR_SMD(5, 2000);
+ } else
+ break;
+ }
+ if (wr_size != header_size + num_bytes)
+ pr_err("diag: error writing event mask %d, tried %d\n",
+ wr_size, header_size + num_bytes);
+ } else
+ pr_err("diag: ch not valid for event update\n");
+ mutex_unlock(&driver->diag_cntl_mutex);
+}
+
+void diag_send_msg_mask_update(smd_channel_t *ch, int updated_ssid_first,
+ int updated_ssid_last, int proc)
+{
+ void *buf = driver->buf_msg_mask_update;
+ int first, last, actual_last, size = -ENOMEM, retry_count = 0;
+ int header_size = sizeof(struct diag_ctrl_msg_mask);
+ uint8_t *ptr = driver->msg_masks;
+
+ mutex_lock(&driver->diag_cntl_mutex);
+ while (*(uint32_t *)(ptr + 4)) {
+ first = *(uint32_t *)ptr;
+ ptr += 4;
+ last = *(uint32_t *)ptr;
+ ptr += 4;
+ actual_last = *(uint32_t *)ptr;
+ ptr += 4;
+ if ((updated_ssid_first >= first && updated_ssid_last <=
+ actual_last) || (updated_ssid_first == ALL_SSID)) {
+ /* send f3 mask update */
+ driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
+ driver->msg_mask->msg_mask_size = actual_last -
+ first + 1;
+ driver->msg_mask->data_len = 11 +
+ 4 * (driver->msg_mask->msg_mask_size);
+ driver->msg_mask->stream_id = 1; /* 2, if dual stream */
+ driver->msg_mask->status = 3; /* status valid mask */
+ driver->msg_mask->msg_mode = 0; /* Legcay mode */
+ driver->msg_mask->ssid_first = first;
+ driver->msg_mask->ssid_last = actual_last;
+ memcpy(buf, driver->msg_mask, header_size);
+ memcpy(buf+header_size, ptr,
+ 4 * (driver->msg_mask->msg_mask_size));
+ if (ch) {
+ while (retry_count < 3) {
+ size = smd_write(ch, buf, header_size +
+ 4*(driver->msg_mask->msg_mask_size));
+ if (size == -ENOMEM) {
+ retry_count++;
+ WAIT_FOR_SMD(5, 2000);
+ } else
+ break;
+ }
+ if (size != header_size +
+ 4*(driver->msg_mask->msg_mask_size))
+ pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
+ proc, size, (header_size +
+ 4*(driver->msg_mask->msg_mask_size)));
+ else
+ pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
+ first, actual_last, proc);
+ } else
+ pr_err("diag: proc %d, ch invalid msg mask update\n",
+ proc);
+ }
+ ptr += MAX_SSID_PER_RANGE*4;
+ }
+ mutex_unlock(&driver->diag_cntl_mutex);
+}
+
+int diag_process_apps_masks(unsigned char *buf, int len)
+{
+ int packet_type = 1;
+ int i;
+ int ssid_first, ssid_last, ssid_range;
+ int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
+ uint8_t *rt_mask_ptr;
+ int equip_id, num_items;
+#if defined(CONFIG_DIAG_OVER_USB)
+ int payload_length;
+#endif
+
+ /* Set log masks */
+ if (*buf == 0x73 && *(int *)(buf+4) == 3) {
+ buf += 8;
+ /* Read Equip ID and pass as first param below*/
+ diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
+ diag_update_userspace_clients(LOG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x73;
+ *(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
+ *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
+ payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
+ for (i = 0; i < payload_length; i++)
+ *(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
+ if (driver->ch_cntl)
+ diag_send_log_mask_update(driver->ch_cntl,
+ *(int *)buf);
+ if (driver->chlpass_cntl)
+ diag_send_log_mask_update(driver->chlpass_cntl,
+ *(int *)buf);
+ if (driver->ch_wcnss_cntl)
+ diag_send_log_mask_update(driver->ch_wcnss_cntl,
+ *(int *)buf);
+ encode_rsp_and_send(12 + payload_length - 1);
+ return 0;
+ }
+#endif
+ } /* Get log masks */
+ else if (*buf == 0x73 && *(int *)(buf+4) == 4) {
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (!(driver->ch) && chk_apps_only()) {
+ equip_id = *(int *)(buf + 8);
+ num_items = *(int *)(buf + 12);
+ driver->apps_rsp_buf[0] = 0x73;
+ driver->apps_rsp_buf[1] = 0x0;
+ driver->apps_rsp_buf[2] = 0x0;
+ driver->apps_rsp_buf[3] = 0x0;
+ *(int *)(driver->apps_rsp_buf + 4) = 0x4;
+ if (!chk_equip_id_and_mask(equip_id,
+ driver->apps_rsp_buf+20))
+ *(int *)(driver->apps_rsp_buf + 8) = 0x0;
+ else
+ *(int *)(driver->apps_rsp_buf + 8) = 0x1;
+ *(int *)(driver->apps_rsp_buf + 12) = equip_id;
+ *(int *)(driver->apps_rsp_buf + 16) = num_items;
+ encode_rsp_and_send(20+(num_items+7)/8-1);
+ return 0;
+ }
+#endif
+ } /* Disable log masks */
+ else if (*buf == 0x73 && *(int *)(buf+4) == 0) {
+ /* Disable mask for each log code */
+ diag_disable_log_mask();
+ diag_update_userspace_clients(LOG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x73;
+ driver->apps_rsp_buf[1] = 0x0;
+ driver->apps_rsp_buf[2] = 0x0;
+ driver->apps_rsp_buf[3] = 0x0;
+ *(int *)(driver->apps_rsp_buf + 4) = 0x0;
+ *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* status */
+ if (driver->ch_cntl)
+ diag_send_log_mask_update(driver->ch_cntl,
+ ALL_EQUIP_ID);
+ if (driver->chlpass_cntl)
+ diag_send_log_mask_update(driver->chlpass_cntl,
+ ALL_EQUIP_ID);
+ if (driver->ch_wcnss_cntl)
+ diag_send_log_mask_update(driver->ch_wcnss_cntl,
+ ALL_EQUIP_ID);
+ encode_rsp_and_send(11);
+ return 0;
+ }
+#endif
+ } /* Get runtime message mask */
+ else if ((*buf == 0x7d) && (*(buf+1) == 0x3)) {
+ ssid_first = *(uint16_t *)(buf + 2);
+ ssid_last = *(uint16_t *)(buf + 4);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (!(driver->ch) && chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x7d;
+ driver->apps_rsp_buf[1] = 0x3;
+ *(uint16_t *)(driver->apps_rsp_buf+2) = ssid_first;
+ *(uint16_t *)(driver->apps_rsp_buf+4) = ssid_last;
+ driver->apps_rsp_buf[6] = 0x1; /* Success Status */
+ driver->apps_rsp_buf[7] = 0x0;
+ rt_mask_ptr = driver->msg_masks;
+ while (*(uint32_t *)(rt_mask_ptr + 4)) {
+ rt_first_ssid = *(uint32_t *)rt_mask_ptr;
+ rt_mask_ptr += 8; /* +8 to skip 'last' */
+ rt_last_ssid = *(uint32_t *)rt_mask_ptr;
+ rt_mask_ptr += 4;
+ if (ssid_first == rt_first_ssid && ssid_last ==
+ rt_last_ssid) {
+ rt_mask_size = 4 * (rt_last_ssid -
+ rt_first_ssid + 1);
+ memcpy(driver->apps_rsp_buf+8,
+ rt_mask_ptr, rt_mask_size);
+ encode_rsp_and_send(8+rt_mask_size-1);
+ return 0;
+ }
+ rt_mask_ptr += MAX_SSID_PER_RANGE*4;
+ }
+ }
+#endif
+ } /* Set runtime message mask */
+ else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
+ ssid_first = *(uint16_t *)(buf + 2);
+ ssid_last = *(uint16_t *)(buf + 4);
+ ssid_range = 4 * (ssid_last - ssid_first + 1);
+ pr_debug("diag: received mask update for ssid_first = %d, ssid_last = %d",
+ ssid_first, ssid_last);
+ diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
+ diag_update_userspace_clients(MSG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (chk_apps_only()) {
+ for (i = 0; i < 8 + ssid_range; i++)
+ *(driver->apps_rsp_buf + i) = *(buf+i);
+ *(driver->apps_rsp_buf + 6) = 0x1;
+ if (driver->ch_cntl)
+ diag_send_msg_mask_update(driver->ch_cntl,
+ ssid_first, ssid_last, MODEM_PROC);
+ if (driver->chlpass_cntl)
+ diag_send_msg_mask_update(driver->chlpass_cntl,
+ ssid_first, ssid_last, LPASS_PROC);
+ if (driver->ch_wcnss_cntl)
+ diag_send_msg_mask_update(driver->ch_wcnss_cntl,
+ ssid_first, ssid_last, WCNSS_PROC);
+ encode_rsp_and_send(8 + ssid_range - 1);
+ return 0;
+ }
+#endif
+ } /* Set ALL runtime message mask */
+ else if ((*buf == 0x7d) && (*(buf+1) == 0x5)) {
+ rt_mask = *(int *)(buf + 4);
+ diag_set_msg_mask(rt_mask);
+ diag_update_userspace_clients(MSG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x7d; /* cmd_code */
+ driver->apps_rsp_buf[1] = 0x5; /* set subcommand */
+ driver->apps_rsp_buf[2] = 1; /* success */
+ driver->apps_rsp_buf[3] = 0; /* rsvd */
+ *(int *)(driver->apps_rsp_buf + 4) = rt_mask;
+ /* send msg mask update to peripheral */
+ if (driver->ch_cntl)
+ diag_send_msg_mask_update(driver->ch_cntl,
+ ALL_SSID, ALL_SSID, MODEM_PROC);
+ if (driver->chlpass_cntl)
+ diag_send_msg_mask_update(driver->chlpass_cntl,
+ ALL_SSID, ALL_SSID, LPASS_PROC);
+ if (driver->ch_wcnss_cntl)
+ diag_send_msg_mask_update(driver->ch_wcnss_cntl,
+ ALL_SSID, ALL_SSID, WCNSS_PROC);
+ encode_rsp_and_send(7);
+ return 0;
+ }
+#endif
+ } else if (*buf == 0x82) { /* event mask change */
+ buf += 4;
+ diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
+ diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
+ diag_update_userspace_clients(EVENT_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x82;
+ driver->apps_rsp_buf[1] = 0x0;
+ *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
+ *(uint16_t *)(driver->apps_rsp_buf + 4) =
+ EVENT_LAST_ID + 1;
+ memcpy(driver->apps_rsp_buf+6, driver->event_masks,
+ EVENT_LAST_ID/8+1);
+ if (driver->ch_cntl)
+ diag_send_event_mask_update(driver->ch_cntl,
+ diag_event_num_bytes);
+ if (driver->chlpass_cntl)
+ diag_send_event_mask_update(
+ driver->chlpass_cntl,
+ diag_event_num_bytes);
+ if (driver->ch_wcnss_cntl)
+ diag_send_event_mask_update(
+ driver->ch_wcnss_cntl, diag_event_num_bytes);
+ encode_rsp_and_send(6 + EVENT_LAST_ID/8);
+ return 0;
+ }
+#endif
+ } else if (*buf == 0x60) {
+ diag_event_config = *(buf+1);
+ diag_toggle_event_mask(*(buf+1));
+ diag_update_userspace_clients(EVENT_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x60;
+ driver->apps_rsp_buf[1] = 0x0;
+ driver->apps_rsp_buf[2] = 0x0;
+ if (driver->ch_cntl)
+ diag_send_event_mask_update(driver->ch_cntl,
+ diag_event_num_bytes);
+ if (driver->chlpass_cntl)
+ diag_send_event_mask_update(
+ driver->chlpass_cntl,
+ diag_event_num_bytes);
+ if (driver->ch_wcnss_cntl)
+ diag_send_event_mask_update(
+ driver->ch_wcnss_cntl, diag_event_num_bytes);
+ encode_rsp_and_send(2);
+ return 0;
+ }
+#endif
+ }
+
+ return packet_type;
+}
+
+void diag_masks_init(void)
+{
+ if (driver->event_mask == NULL) {
+ driver->event_mask = kzalloc(sizeof(
+ struct diag_ctrl_event_mask), GFP_KERNEL);
+ if (driver->event_mask == NULL)
+ goto err;
+ kmemleak_not_leak(driver->event_mask);
+ }
+ if (driver->msg_mask == NULL) {
+ driver->msg_mask = kzalloc(sizeof(
+ struct diag_ctrl_msg_mask), GFP_KERNEL);
+ if (driver->msg_mask == NULL)
+ goto err;
+ kmemleak_not_leak(driver->msg_mask);
+ }
+ if (driver->log_mask == NULL) {
+ driver->log_mask = kzalloc(sizeof(
+ struct diag_ctrl_log_mask), GFP_KERNEL);
+ if (driver->log_mask == NULL)
+ goto err;
+ kmemleak_not_leak(driver->log_mask);
+ }
+
+ if (driver->buf_msg_mask_update == NULL) {
+ driver->buf_msg_mask_update = kzalloc(APPS_BUF_SIZE,
+ GFP_KERNEL);
+ if (driver->buf_msg_mask_update == NULL)
+ goto err;
+ kmemleak_not_leak(driver->buf_msg_mask_update);
+ }
+ if (driver->buf_log_mask_update == NULL) {
+ driver->buf_log_mask_update = kzalloc(APPS_BUF_SIZE,
+ GFP_KERNEL);
+ if (driver->buf_log_mask_update == NULL)
+ goto err;
+ kmemleak_not_leak(driver->buf_log_mask_update);
+ }
+ if (driver->buf_event_mask_update == NULL) {
+ driver->buf_event_mask_update = kzalloc(APPS_BUF_SIZE,
+ GFP_KERNEL);
+ if (driver->buf_event_mask_update == NULL)
+ goto err;
+ kmemleak_not_leak(driver->buf_event_mask_update);
+ }
+ if (driver->msg_masks == NULL) {
+ driver->msg_masks = kzalloc(MSG_MASK_SIZE, GFP_KERNEL);
+ if (driver->msg_masks == NULL)
+ goto err;
+ kmemleak_not_leak(driver->msg_masks);
+ }
+ diag_create_msg_mask_table();
+ diag_event_num_bytes = 0;
+ if (driver->log_masks == NULL) {
+ driver->log_masks = kzalloc(LOG_MASK_SIZE, GFP_KERNEL);
+ if (driver->log_masks == NULL)
+ goto err;
+ kmemleak_not_leak(driver->log_masks);
+ }
+ driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
+ if (driver->event_masks == NULL) {
+ driver->event_masks = kzalloc(EVENT_MASK_SIZE, GFP_KERNEL);
+ if (driver->event_masks == NULL)
+ goto err;
+ kmemleak_not_leak(driver->event_masks);
+ }
+#ifdef CONFIG_DIAG_OVER_USB
+ INIT_WORK(&(driver->diag_modem_mask_update_work),
+ diag_modem_mask_update_fn);
+ INIT_WORK(&(driver->diag_lpass_mask_update_work),
+ diag_lpass_mask_update_fn);
+ INIT_WORK(&(driver->diag_wcnss_mask_update_work),
+ diag_wcnss_mask_update_fn);
+#endif
+ return;
+err:
+ pr_err("diag: Could not initialize diag mask buffers");
+ kfree(driver->event_mask);
+ kfree(driver->log_mask);
+ kfree(driver->msg_mask);
+ kfree(driver->msg_masks);
+ kfree(driver->log_masks);
+ kfree(driver->event_masks);
+}
+
+void diag_masks_exit(void)
+{
+ kfree(driver->event_mask);
+ kfree(driver->log_mask);
+ kfree(driver->msg_mask);
+ kfree(driver->msg_masks);
+ kfree(driver->log_masks);
+ kfree(driver->event_masks);
+}
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
new file mode 100644
index 0000000..bcf5bc2
--- /dev/null
+++ b/drivers/char/diag/diag_masks.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DIAG_MASKS_H
+#define DIAG_MASKS_H
+
+#include "diagfwd.h"
+
+int chk_equip_id_and_mask(int equip_id, uint8_t *buf);
+void diag_send_event_mask_update(smd_channel_t *, int num_bytes);
+void diag_send_msg_mask_update(smd_channel_t *, int ssid_first,
+ int ssid_last, int proc);
+void diag_send_log_mask_update(smd_channel_t *, int);
+int diag_process_apps_masks(unsigned char *buf, int len);
+void diag_masks_init(void);
+void diag_masks_exit(void);
+extern int diag_event_num_bytes;
+#endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 814fe64..5c6cdc6 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -37,6 +37,8 @@
#include "diagfwd_smux.h"
#endif
#include <linux/timer.h>
+#include "diag_debugfs.h"
+#include "diag_masks.h"
MODULE_DESCRIPTION("Diag Char Driver");
MODULE_LICENSE("GPL v2");
@@ -1420,6 +1422,7 @@
INIT_WORK(&(driver->diag_clean_wcnss_reg_work),
diag_clean_wcnss_reg_fn);
diag_debugfs_init();
+ diag_masks_init();
diagfwd_init();
diagfwd_cntl_init();
driver->dci_state = diag_dci_init();
@@ -1457,6 +1460,7 @@
diagchar_cleanup();
diagfwd_exit();
diagfwd_cntl_exit();
+ diag_masks_exit();
diag_sdio_fn(EXIT);
diag_bridge_fn(EXIT);
return -1;
@@ -1470,6 +1474,7 @@
diagmem_exit(driver, POOL_TYPE_ALL);
diagfwd_exit();
diagfwd_cntl_exit();
+ diag_masks_exit();
diag_sdio_fn(EXIT);
diag_bridge_fn(EXIT);
diag_debugfs_cleanup();
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 737edbf..a537bb3 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -39,63 +39,38 @@
#include "diagfwd_sdio.h"
#endif
#include "diag_dci.h"
+#include "diag_masks.h"
#define MODE_CMD 41
#define RESET_ID 2
-#define ALL_EQUIP_ID 100
-#define ALL_SSID -1
-#define MAX_SSID_PER_RANGE 100
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 */
struct diag_master_table entry;
smd_channel_t *ch_temp = NULL, *chlpass_temp = NULL, *ch_wcnss_temp = NULL;
-int diag_event_num_bytes;
-int diag_event_config;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
-struct mask_info {
- int equip_id;
- int num_items;
- int index;
-};
-#define CREATE_MSG_MASK_TBL_ROW(XX) \
-do { \
- *(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX; \
- msg_mask_tbl_ptr += 4; \
- *(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST; \
- msg_mask_tbl_ptr += 4; \
- /* mimic the last entry as actual_last while creation */ \
- *(int *)(msg_mask_tbl_ptr) = MSG_SSID_ ## XX ## _LAST; \
- msg_mask_tbl_ptr += 4; \
- /* increment by MAX_SSID_PER_RANGE cells */ \
- msg_mask_tbl_ptr += MAX_SSID_PER_RANGE * sizeof(int); \
-} while (0)
-
-#define ENCODE_RSP_AND_SEND(buf_length) \
-do { \
- send.state = DIAG_STATE_START; \
- send.pkt = driver->apps_rsp_buf; \
- send.last = (void *)(driver->apps_rsp_buf + buf_length); \
- send.terminate = 1; \
- if (!driver->in_busy_1) { \
- enc.dest = driver->buf_in_1; \
- enc.dest_last = (void *)(driver->buf_in_1 + APPS_BUF_SIZE - 1);\
- diag_hdlc_encode(&send, &enc); \
- driver->write_ptr_1->buf = driver->buf_in_1; \
- driver->write_ptr_1->length = (int)(enc.dest - \
- (void *)(driver->buf_in_1)); \
- driver->in_busy_1 = 1; \
- diag_device_write(driver->buf_in_1, MODEM_DATA, \
- driver->write_ptr_1); \
- memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE); \
- } \
-} while (0)
-
-#define CHK_OVERFLOW(bufStart, start, end, length) \
-((bufStart <= start) && (end - start >= length)) ? 1 : 0
+void encode_rsp_and_send(int buf_length)
+{
+ send.state = DIAG_STATE_START;
+ send.pkt = driver->apps_rsp_buf;
+ send.last = (void *)(driver->apps_rsp_buf + buf_length);
+ send.terminate = 1;
+ if (!driver->in_busy_1) {
+ enc.dest = driver->buf_in_1;
+ enc.dest_last = (void *)(driver->buf_in_1 + APPS_BUF_SIZE - 1);
+ diag_hdlc_encode(&send, &enc);
+ driver->write_ptr_1->buf = driver->buf_in_1;
+ driver->write_ptr_1->length = (int)(enc.dest -
+ (void *)(driver->buf_in_1));
+ driver->in_busy_1 = 1;
+ diag_device_write(driver->buf_in_1, MODEM_DATA,
+ driver->write_ptr_1);
+ memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
+ }
+}
/* Determine if this device uses a device tree */
#ifdef CONFIG_OF
@@ -136,6 +111,7 @@
case MSM_CPU_8960AB:
return AO8960_TOOLS_ID;
case MSM_CPU_8064:
+ case MSM_CPU_8064AB:
return APQ8064_TOOLS_ID;
case MSM_CPU_8930:
case MSM_CPU_8930AA:
@@ -163,6 +139,7 @@
case MSM_CPU_8960:
case MSM_CPU_8960AB:
case MSM_CPU_8064:
+ case MSM_CPU_8064AB:
case MSM_CPU_8930:
case MSM_CPU_8930AA:
case MSM_CPU_8627:
@@ -185,7 +162,7 @@
return 1;
else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
cpu_is_msm9615() || cpu_is_apq8064() || cpu_is_msm8627() ||
- cpu_is_msm8960ab())
+ cpu_is_msm8960ab() || cpu_is_apq8064ab())
return 1;
else
return 0;
@@ -559,248 +536,6 @@
}
}
-static void diag_print_mask_table(void)
-{
-/* Enable this to print mask table when updated */
-#ifdef MASK_DEBUG
- int first, last, actual_last;
- uint8_t *ptr = driver->msg_masks;
- int i = 0;
- pr_info("diag: F3 message mask table\n");
- while (*(uint32_t *)(ptr + 4)) {
- first = *(uint32_t *)ptr;
- ptr += 4;
- last = *(uint32_t *)ptr;
- ptr += 4;
- actual_last = *(uint32_t *)ptr;
- ptr += 4;
- pr_info("diag: SSID %d, %d - %d\n", first, last, actual_last);
- for (i = 0 ; i <= actual_last - first ; i++)
- pr_info("diag: MASK:%x\n", *((uint32_t *)ptr + i));
- ptr += MAX_SSID_PER_RANGE*4;
- }
-#endif
-}
-
-void diag_create_msg_mask_table(void)
-{
- uint8_t *msg_mask_tbl_ptr = driver->msg_masks;
-
- CREATE_MSG_MASK_TBL_ROW(0);
- CREATE_MSG_MASK_TBL_ROW(1);
- CREATE_MSG_MASK_TBL_ROW(2);
- CREATE_MSG_MASK_TBL_ROW(3);
- CREATE_MSG_MASK_TBL_ROW(4);
- CREATE_MSG_MASK_TBL_ROW(5);
- CREATE_MSG_MASK_TBL_ROW(6);
- CREATE_MSG_MASK_TBL_ROW(7);
- CREATE_MSG_MASK_TBL_ROW(8);
- CREATE_MSG_MASK_TBL_ROW(9);
- CREATE_MSG_MASK_TBL_ROW(10);
- CREATE_MSG_MASK_TBL_ROW(11);
- CREATE_MSG_MASK_TBL_ROW(12);
- CREATE_MSG_MASK_TBL_ROW(13);
- CREATE_MSG_MASK_TBL_ROW(14);
- CREATE_MSG_MASK_TBL_ROW(15);
- CREATE_MSG_MASK_TBL_ROW(16);
- CREATE_MSG_MASK_TBL_ROW(17);
- CREATE_MSG_MASK_TBL_ROW(18);
- CREATE_MSG_MASK_TBL_ROW(19);
- CREATE_MSG_MASK_TBL_ROW(20);
- CREATE_MSG_MASK_TBL_ROW(21);
- CREATE_MSG_MASK_TBL_ROW(22);
- CREATE_MSG_MASK_TBL_ROW(23);
-}
-
-static void diag_set_msg_mask(int rt_mask)
-{
- int first_ssid, last_ssid, i;
- uint8_t *parse_ptr, *ptr = driver->msg_masks;
-
- mutex_lock(&driver->diagchar_mutex);
- while (*(uint32_t *)(ptr + 4)) {
- first_ssid = *(uint32_t *)ptr;
- ptr += 8; /* increment by 8 to skip 'last' */
- last_ssid = *(uint32_t *)ptr;
- ptr += 4;
- parse_ptr = ptr;
- pr_debug("diag: updating range %d %d\n", first_ssid, last_ssid);
- for (i = 0; i < last_ssid - first_ssid + 1; i++) {
- *(int *)parse_ptr = rt_mask;
- parse_ptr += 4;
- }
- ptr += MAX_SSID_PER_RANGE * 4;
- }
- mutex_unlock(&driver->diagchar_mutex);
-}
-
-static void diag_update_msg_mask(int start, int end , uint8_t *buf)
-{
- int found = 0, first, last, actual_last;
- uint8_t *actual_last_ptr;
- uint8_t *ptr = driver->msg_masks;
- uint8_t *ptr_buffer_start = &(*(driver->msg_masks));
- uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
-
- mutex_lock(&driver->diagchar_mutex);
-
- /* First SSID can be zero : So check that last is non-zero */
- while (*(uint32_t *)(ptr + 4)) {
- first = *(uint32_t *)ptr;
- ptr += 4;
- last = *(uint32_t *)ptr;
- ptr += 4;
- actual_last = *(uint32_t *)ptr;
- actual_last_ptr = ptr;
- ptr += 4;
- if (start >= first && start <= actual_last) {
- ptr += (start - first)*4;
- if (end > actual_last) {
- pr_info("diag: ssid range mismatch\n");
- actual_last = end;
- *(uint32_t *)(actual_last_ptr) = end;
- }
- if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
- (((end - start)+1)*4))) {
- pr_debug("diag: update ssid start %d, end %d\n",
- start, end);
- memcpy(ptr, buf , ((end - start)+1)*4);
- } else
- pr_alert("diag: Not enough space MSG_MASK\n");
- found = 1;
- break;
- } else {
- ptr += MAX_SSID_PER_RANGE*4;
- }
- }
- /* Entry was not found - add new table */
- if (!found) {
- if (CHK_OVERFLOW(ptr_buffer_start, ptr, ptr_buffer_end,
- 8 + ((end - start) + 1)*4)) {
- memcpy(ptr, &(start) , 4);
- ptr += 4;
- memcpy(ptr, &(end), 4);
- ptr += 4;
- memcpy(ptr, &(end), 4); /* create actual_last entry */
- ptr += 4;
- pr_debug("diag: adding NEW ssid start %d, end %d\n",
- start, end);
- memcpy(ptr, buf , ((end - start) + 1)*4);
- } else
- pr_alert("diag: Not enough buffer space for MSG_MASK\n");
- }
- mutex_unlock(&driver->diagchar_mutex);
- diag_print_mask_table();
-}
-
-void diag_toggle_event_mask(int toggle)
-{
- uint8_t *ptr = driver->event_masks;
-
- mutex_lock(&driver->diagchar_mutex);
- if (toggle)
- memset(ptr, 0xFF, EVENT_MASK_SIZE);
- else
- memset(ptr, 0, EVENT_MASK_SIZE);
- mutex_unlock(&driver->diagchar_mutex);
-}
-
-static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
-{
- uint8_t *ptr = driver->event_masks;
- uint8_t *temp = buf + 2;
-
- mutex_lock(&driver->diagchar_mutex);
- if (!toggle)
- memset(ptr, 0 , EVENT_MASK_SIZE);
- else
- if (CHK_OVERFLOW(ptr, ptr,
- ptr+EVENT_MASK_SIZE, num_bytes))
- memcpy(ptr, temp , num_bytes);
- else
- printk(KERN_CRIT "Not enough buffer space "
- "for EVENT_MASK\n");
- mutex_unlock(&driver->diagchar_mutex);
-}
-
-static void diag_disable_log_mask(void)
-{
- int i = 0;
- struct mask_info *parse_ptr = (struct mask_info *)(driver->log_masks);
-
- pr_debug("diag: disable log masks\n");
- mutex_lock(&driver->diagchar_mutex);
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- pr_debug("diag: equip id %d\n", parse_ptr->equip_id);
- if (!(parse_ptr->equip_id)) /* Reached a null entry */
- break;
- memset(driver->log_masks + parse_ptr->index, 0,
- (parse_ptr->num_items + 7)/8);
- parse_ptr++;
- }
- mutex_unlock(&driver->diagchar_mutex);
-}
-
-int chk_equip_id_and_mask(int equip_id, uint8_t *buf)
-{
- int i = 0, flag = 0, num_items, offset;
- unsigned char *ptr_data;
- struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
-
- pr_debug("diag: received equip id = %d\n", equip_id);
- /* Check if this is valid equipment ID */
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
- offset = ptr->index;
- num_items = ptr->num_items;
- flag = 1;
- break;
- }
- ptr++;
- }
- if (!flag)
- return -EPERM;
- ptr_data = driver->log_masks + offset;
- memcpy(buf, ptr_data, (num_items+7)/8);
- return 0;
-}
-
-static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
-{
- uint8_t *temp = buf;
- int i = 0;
- unsigned char *ptr_data;
- int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
- struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
-
- pr_debug("diag: received equip id = %d\n", equip_id);
- mutex_lock(&driver->diagchar_mutex);
- /* Check if we already know index of this equipment ID */
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
- offset = ptr->index;
- break;
- }
- if ((ptr->equip_id == 0) && (ptr->index == 0)) {
- /* Reached a null entry */
- ptr->equip_id = equip_id;
- ptr->num_items = num_items;
- ptr->index = driver->log_masks_length;
- offset = driver->log_masks_length;
- driver->log_masks_length += ((num_items+7)/8);
- break;
- }
- ptr++;
- }
- ptr_data = driver->log_masks + offset;
- if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
- + LOG_MASK_SIZE, (num_items+7)/8))
- memcpy(ptr_data, temp , (num_items+7)/8);
- else
- pr_err("diag: Not enough buffer space for LOG_MASK\n");
- mutex_unlock(&driver->diagchar_mutex);
-}
-
static void diag_update_pkt_buffer(unsigned char *buf)
{
unsigned char *ptr = driver->pkt_buf;
@@ -869,415 +604,21 @@
}
}
-void diag_modem_mask_update_fn(struct work_struct *work)
-{
- diag_send_msg_mask_update(driver->ch_cntl, ALL_SSID,
- ALL_SSID, MODEM_PROC);
- diag_send_log_mask_update(driver->ch_cntl, ALL_EQUIP_ID);
- diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
-}
-
-void diag_lpass_mask_update_fn(struct work_struct *work)
-{
- diag_send_msg_mask_update(driver->chlpass_cntl, ALL_SSID,
- ALL_SSID, LPASS_PROC);
- diag_send_log_mask_update(driver->chlpass_cntl, ALL_EQUIP_ID);
- diag_send_event_mask_update(driver->chlpass_cntl, diag_event_num_bytes);
-}
-
-void diag_wcnss_mask_update_fn(struct work_struct *work)
-{
- diag_send_msg_mask_update(driver->ch_wcnss_cntl, ALL_SSID,
- ALL_SSID, WCNSS_PROC);
- diag_send_log_mask_update(driver->ch_wcnss_cntl, ALL_EQUIP_ID);
- diag_send_event_mask_update(driver->ch_wcnss_cntl,
- diag_event_num_bytes);
-}
-
-void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
-{
- void *buf = driver->buf_log_mask_update;
- int header_size = sizeof(struct diag_ctrl_log_mask);
- struct mask_info *ptr = (struct mask_info *)driver->log_masks;
- int i, size, wr_size = -ENOMEM, retry_count = 0, timer;
-
- mutex_lock(&driver->diag_cntl_mutex);
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- size = (ptr->num_items+7)/8;
- /* reached null entry */
- if ((ptr->equip_id == 0) && (ptr->index == 0))
- break;
- driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
- driver->log_mask->num_items = ptr->num_items;
- driver->log_mask->data_len = 11 + size;
- driver->log_mask->stream_id = 1; /* 2, if dual stream */
- driver->log_mask->status = 3; /* status for valid mask */
- driver->log_mask->equip_id = ptr->equip_id;
- driver->log_mask->log_mask_size = size;
- /* send only desired update, NOT ALL */
- if (equip_id == ALL_EQUIP_ID || equip_id ==
- driver->log_mask->equip_id) {
- memcpy(buf, driver->log_mask, header_size);
- memcpy(buf+header_size, driver->log_masks+ptr->index,
- size);
- if (ch) {
- while (retry_count < 3) {
- wr_size = smd_write(ch, buf,
- header_size + size);
- if (wr_size == -ENOMEM) {
- retry_count++;
- for (timer = 0; timer < 5;
- timer++)
- udelay(2000);
- } else
- break;
- }
- if (wr_size != header_size + size)
- pr_err("diag: log mask update failed"
- " %d, tried %d", wr_size, header_size + size);
- else
- pr_debug("diag: updated log equip ID %d"
- ",len %d\n", driver->log_mask->equip_id,
- driver->log_mask->log_mask_size);
- } else
- pr_err("diag: ch not valid for log update\n");
- }
- ptr++;
- }
- mutex_unlock(&driver->diag_cntl_mutex);
-}
-
-void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
-{
- void *buf = driver->buf_event_mask_update;
- int header_size = sizeof(struct diag_ctrl_event_mask);
- int wr_size = -ENOMEM, retry_count = 0, timer;
-
- mutex_lock(&driver->diag_cntl_mutex);
- if (num_bytes == 0) {
- pr_debug("diag: event mask not set yet, so no update\n");
- mutex_unlock(&driver->diag_cntl_mutex);
- return;
- }
- /* send event mask update */
- driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
- driver->event_mask->data_len = 7 + num_bytes;
- driver->event_mask->stream_id = 1; /* 2, if dual stream */
- driver->event_mask->status = 3; /* status for valid mask */
- driver->event_mask->event_config = diag_event_config; /* event config */
- driver->event_mask->event_mask_size = num_bytes;
- memcpy(buf, driver->event_mask, header_size);
- memcpy(buf+header_size, driver->event_masks, num_bytes);
- if (ch) {
- while (retry_count < 3) {
- wr_size = smd_write(ch, buf, header_size + num_bytes);
- if (wr_size == -ENOMEM) {
- retry_count++;
- for (timer = 0; timer < 5; timer++)
- udelay(2000);
- } else
- break;
- }
- if (wr_size != header_size + num_bytes)
- pr_err("diag: error writing event mask %d, tried %d\n",
- wr_size, header_size + num_bytes);
- } else
- pr_err("diag: ch not valid for event update\n");
- mutex_unlock(&driver->diag_cntl_mutex);
-}
-
-void diag_send_msg_mask_update(smd_channel_t *ch, int updated_ssid_first,
- int updated_ssid_last, int proc)
-{
- void *buf = driver->buf_msg_mask_update;
- int first, last, actual_last, size = -ENOMEM, retry_count = 0, timer;
- int header_size = sizeof(struct diag_ctrl_msg_mask);
- uint8_t *ptr = driver->msg_masks;
-
- mutex_lock(&driver->diag_cntl_mutex);
- while (*(uint32_t *)(ptr + 4)) {
- first = *(uint32_t *)ptr;
- ptr += 4;
- last = *(uint32_t *)ptr;
- ptr += 4;
- actual_last = *(uint32_t *)ptr;
- ptr += 4;
- if ((updated_ssid_first >= first && updated_ssid_last <=
- actual_last) || (updated_ssid_first == ALL_SSID)) {
- /* send f3 mask update */
- driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
- driver->msg_mask->msg_mask_size = actual_last -
- first + 1;
- driver->msg_mask->data_len = 11 +
- 4 * (driver->msg_mask->msg_mask_size);
- driver->msg_mask->stream_id = 1; /* 2, if dual stream */
- driver->msg_mask->status = 3; /* status valid mask */
- driver->msg_mask->msg_mode = 0; /* Legcay mode */
- driver->msg_mask->ssid_first = first;
- driver->msg_mask->ssid_last = actual_last;
- memcpy(buf, driver->msg_mask, header_size);
- memcpy(buf+header_size, ptr,
- 4 * (driver->msg_mask->msg_mask_size));
- if (ch) {
- while (retry_count < 3) {
- size = smd_write(ch, buf, header_size +
- 4*(driver->msg_mask->msg_mask_size));
- if (size == -ENOMEM) {
- retry_count++;
- for (timer = 0; timer < 5;
- timer++)
- udelay(2000);
- } else
- break;
- }
- if (size != header_size +
- 4*(driver->msg_mask->msg_mask_size))
- pr_err("diag: proc %d, msg mask update "
- "fail %d, tried %d\n", proc, size,
- header_size + 4*(driver->msg_mask->msg_mask_size));
- else
- pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
- first, actual_last, proc);
- } else
- pr_err("diag: proc %d, ch invalid msg mask"
- "update\n", proc);
- }
- ptr += MAX_SSID_PER_RANGE*4;
- }
- mutex_unlock(&driver->diag_cntl_mutex);
-}
-
static int diag_process_apps_pkt(unsigned char *buf, int len)
{
uint16_t subsys_cmd_code;
int subsys_id, ssid_first, ssid_last, ssid_range;
int packet_type = 1, i, cmd_code;
- int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
unsigned char *temp = buf;
- uint8_t *rt_mask_ptr;
- int data_type, equip_id, num_items;
+ int data_type;
#if defined(CONFIG_DIAG_OVER_USB)
- int payload_length;
unsigned char *ptr;
#endif
- /* Set log masks */
- if (*buf == 0x73 && *(int *)(buf+4) == 3) {
- buf += 8;
- /* Read Equip ID and pass as first param below*/
- diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
- diag_update_userspace_clients(LOG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (chk_apps_only()) {
- driver->apps_rsp_buf[0] = 0x73;
- *(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
- *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
- payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
- for (i = 0; i < payload_length; i++)
- *(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
- if (driver->ch_cntl)
- diag_send_log_mask_update(driver->ch_cntl,
- *(int *)buf);
- if (driver->chlpass_cntl)
- diag_send_log_mask_update(driver->chlpass_cntl,
- *(int *)buf);
- if (driver->ch_wcnss_cntl)
- diag_send_log_mask_update(driver->ch_wcnss_cntl,
- *(int *)buf);
- ENCODE_RSP_AND_SEND(12 + payload_length - 1);
- return 0;
- } else
- buf = temp;
-#endif
- } /* Get log masks */
- else if (*buf == 0x73 && *(int *)(buf+4) == 4) {
-#if defined(CONFIG_DIAG_OVER_USB)
- if (!(driver->ch) && chk_apps_only()) {
- equip_id = *(int *)(buf + 8);
- num_items = *(int *)(buf + 12);
- driver->apps_rsp_buf[0] = 0x73;
- driver->apps_rsp_buf[1] = 0x0;
- driver->apps_rsp_buf[2] = 0x0;
- driver->apps_rsp_buf[3] = 0x0;
- *(int *)(driver->apps_rsp_buf + 4) = 0x4;
- if (!chk_equip_id_and_mask(equip_id,
- driver->apps_rsp_buf+20))
- *(int *)(driver->apps_rsp_buf + 8) = 0x0;
- else
- *(int *)(driver->apps_rsp_buf + 8) = 0x1;
- *(int *)(driver->apps_rsp_buf + 12) = equip_id;
- *(int *)(driver->apps_rsp_buf + 16) = num_items;
- ENCODE_RSP_AND_SEND(20+(num_items+7)/8-1);
- return 0;
- } else
- buf = temp;
-#endif
- } /* Disable log masks */
- else if (*buf == 0x73 && *(int *)(buf+4) == 0) {
- /* Disable mask for each log code */
- diag_disable_log_mask();
- diag_update_userspace_clients(LOG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (chk_apps_only()) {
- driver->apps_rsp_buf[0] = 0x73;
- driver->apps_rsp_buf[1] = 0x0;
- driver->apps_rsp_buf[2] = 0x0;
- driver->apps_rsp_buf[3] = 0x0;
- *(int *)(driver->apps_rsp_buf + 4) = 0x0;
- *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* status */
- if (driver->ch_cntl)
- diag_send_log_mask_update(driver->ch_cntl,
- ALL_EQUIP_ID);
- if (driver->chlpass_cntl)
- diag_send_log_mask_update(driver->chlpass_cntl,
- ALL_EQUIP_ID);
- if (driver->ch_wcnss_cntl)
- diag_send_log_mask_update(driver->ch_wcnss_cntl,
- ALL_EQUIP_ID);
- ENCODE_RSP_AND_SEND(11);
- return 0;
- }
-#endif
- } /* Get runtime message mask */
- else if ((*buf == 0x7d) && (*(buf+1) == 0x3)) {
- ssid_first = *(uint16_t *)(buf + 2);
- ssid_last = *(uint16_t *)(buf + 4);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (!(driver->ch) && chk_apps_only()) {
- driver->apps_rsp_buf[0] = 0x7d;
- driver->apps_rsp_buf[1] = 0x3;
- *(uint16_t *)(driver->apps_rsp_buf+2) = ssid_first;
- *(uint16_t *)(driver->apps_rsp_buf+4) = ssid_last;
- driver->apps_rsp_buf[6] = 0x1; /* Success Status */
- driver->apps_rsp_buf[7] = 0x0;
- rt_mask_ptr = driver->msg_masks;
- while (*(uint32_t *)(rt_mask_ptr + 4)) {
- rt_first_ssid = *(uint32_t *)rt_mask_ptr;
- rt_mask_ptr += 8; /* +8 to skip 'last' */
- rt_last_ssid = *(uint32_t *)rt_mask_ptr;
- rt_mask_ptr += 4;
- if (ssid_first == rt_first_ssid && ssid_last ==
- rt_last_ssid) {
- rt_mask_size = 4 * (rt_last_ssid -
- rt_first_ssid + 1);
- memcpy(driver->apps_rsp_buf+8,
- rt_mask_ptr, rt_mask_size);
- ENCODE_RSP_AND_SEND(8+rt_mask_size-1);
- return 0;
- }
- rt_mask_ptr += MAX_SSID_PER_RANGE*4;
- }
- } else
- buf = temp;
-#endif
- } /* Set runtime message mask */
- else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
- ssid_first = *(uint16_t *)(buf + 2);
- ssid_last = *(uint16_t *)(buf + 4);
- ssid_range = 4 * (ssid_last - ssid_first + 1);
- pr_debug("diag: received mask update for ssid_first = %d,"
- " ssid_last = %d", ssid_first, ssid_last);
- diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
- diag_update_userspace_clients(MSG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (chk_apps_only()) {
- for (i = 0; i < 8 + ssid_range; i++)
- *(driver->apps_rsp_buf + i) = *(buf+i);
- *(driver->apps_rsp_buf + 6) = 0x1;
- if (driver->ch_cntl)
- diag_send_msg_mask_update(driver->ch_cntl,
- ssid_first, ssid_last, MODEM_PROC);
- if (driver->chlpass_cntl)
- diag_send_msg_mask_update(driver->chlpass_cntl,
- ssid_first, ssid_last, LPASS_PROC);
- if (driver->ch_wcnss_cntl)
- diag_send_msg_mask_update(driver->ch_wcnss_cntl,
- ssid_first, ssid_last, WCNSS_PROC);
- ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
- return 0;
- } else
- buf = temp;
-#endif
- } /* Set ALL runtime message mask */
- else if ((*buf == 0x7d) && (*(buf+1) == 0x5)) {
- rt_mask = *(int *)(buf + 4);
- diag_set_msg_mask(rt_mask);
- diag_update_userspace_clients(MSG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (chk_apps_only()) {
- driver->apps_rsp_buf[0] = 0x7d; /* cmd_code */
- driver->apps_rsp_buf[1] = 0x5; /* set subcommand */
- driver->apps_rsp_buf[2] = 1; /* success */
- driver->apps_rsp_buf[3] = 0; /* rsvd */
- *(int *)(driver->apps_rsp_buf + 4) = rt_mask;
- /* send msg mask update to peripheral */
- if (driver->ch_cntl)
- diag_send_msg_mask_update(driver->ch_cntl,
- ALL_SSID, ALL_SSID, MODEM_PROC);
- if (driver->chlpass_cntl)
- diag_send_msg_mask_update(driver->chlpass_cntl,
- ALL_SSID, ALL_SSID, LPASS_PROC);
- if (driver->ch_wcnss_cntl)
- diag_send_msg_mask_update(driver->ch_wcnss_cntl,
- ALL_SSID, ALL_SSID, WCNSS_PROC);
- ENCODE_RSP_AND_SEND(7);
- return 0;
- } else
- buf = temp;
-#endif
- } else if (*buf == 0x82) { /* event mask change */
- buf += 4;
- diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
- diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
- diag_update_userspace_clients(EVENT_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (chk_apps_only()) {
- driver->apps_rsp_buf[0] = 0x82;
- driver->apps_rsp_buf[1] = 0x0;
- *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
- *(uint16_t *)(driver->apps_rsp_buf + 4) =
- EVENT_LAST_ID + 1;
- memcpy(driver->apps_rsp_buf+6, driver->event_masks,
- EVENT_LAST_ID/8+1);
- if (driver->ch_cntl)
- diag_send_event_mask_update(driver->ch_cntl,
- diag_event_num_bytes);
- if (driver->chlpass_cntl)
- diag_send_event_mask_update(
- driver->chlpass_cntl,
- diag_event_num_bytes);
- if (driver->ch_wcnss_cntl)
- diag_send_event_mask_update(
- driver->ch_wcnss_cntl, diag_event_num_bytes);
- ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
- return 0;
- } else
- buf = temp;
-#endif
- } else if (*buf == 0x60) {
- diag_event_config = *(buf+1);
- diag_toggle_event_mask(*(buf+1));
- diag_update_userspace_clients(EVENT_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (chk_apps_only()) {
- driver->apps_rsp_buf[0] = 0x60;
- driver->apps_rsp_buf[1] = 0x0;
- driver->apps_rsp_buf[2] = 0x0;
- if (driver->ch_cntl)
- diag_send_event_mask_update(driver->ch_cntl,
- diag_event_num_bytes);
- if (driver->chlpass_cntl)
- diag_send_event_mask_update(
- driver->chlpass_cntl,
- diag_event_num_bytes);
- if (driver->ch_wcnss_cntl)
- diag_send_event_mask_update(
- driver->ch_wcnss_cntl, diag_event_num_bytes);
- ENCODE_RSP_AND_SEND(2);
- return 0;
- }
-#endif
- }
+ /* Check if the command is a supported mask command */
+ if (diag_process_apps_masks(buf, len) == 0)
+ return 0;
+
/* Check for registered clients and forward packet to apropriate proc */
cmd_code = (int)(*(char *)buf);
temp++;
@@ -1334,7 +675,7 @@
for (i = 0; i < 4; i++)
*(driver->apps_rsp_buf+i) = *(buf+i);
*(uint32_t *)(driver->apps_rsp_buf+4) = PKT_SIZE;
- ENCODE_RSP_AND_SEND(7);
+ encode_rsp_and_send(7);
return 0;
}
/* Check for Apps Only & get event mask request */
@@ -1345,7 +686,7 @@
*(uint16_t *)(driver->apps_rsp_buf + 4) = EVENT_LAST_ID + 1;
for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
*(unsigned char *)(driver->apps_rsp_buf + 6 + i) = 0x0;
- ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
+ encode_rsp_and_send(6 + EVENT_LAST_ID/8);
return 0;
}
/* Get log ID range & Check for Apps Only */
@@ -1370,7 +711,7 @@
*(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
*(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
*(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
- ENCODE_RSP_AND_SEND(75);
+ encode_rsp_and_send(75);
return 0;
}
/* Respond to Get SSID Range request message */
@@ -1428,7 +769,7 @@
*(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
*(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
*(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
- ENCODE_RSP_AND_SEND(99);
+ encode_rsp_and_send(99);
return 0;
}
/* Check for Apps Only Respond to Get Subsys Build mask */
@@ -1540,14 +881,14 @@
*(int *)(ptr + i) = msg_bld_masks_22[i/4];
break;
}
- ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
+ encode_rsp_and_send(8 + ssid_range - 1);
return 0;
}
/* Check for download command */
else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
/* send response back */
driver->apps_rsp_buf[0] = *buf;
- ENCODE_RSP_AND_SEND(0);
+ encode_rsp_and_send(0);
msleep(5000);
/* call download API */
msm_set_restart_mode(RESTART_DLOAD);
@@ -1567,7 +908,7 @@
for (i = 0; i < 13; i++)
driver->apps_rsp_buf[i+3] = 0;
- ENCODE_RSP_AND_SEND(15);
+ encode_rsp_and_send(15);
return 0;
}
}
@@ -1578,7 +919,7 @@
for (i = 0; i < 55; i++)
driver->apps_rsp_buf[i] = 0;
- ENCODE_RSP_AND_SEND(54);
+ encode_rsp_and_send(54);
return 0;
}
/* respond to 0x7c command */
@@ -1591,12 +932,12 @@
chk_config_get_id();
*(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
*(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
- ENCODE_RSP_AND_SEND(13);
+ encode_rsp_and_send(13);
return 0;
}
}
#endif
- return packet_type;
+ return packet_type;
}
#ifdef CONFIG_DIAG_OVER_USB
@@ -1611,7 +952,7 @@
driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
for (i = 0; i < index; i++)
driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
- ENCODE_RSP_AND_SEND(index - 3);
+ encode_rsp_and_send(index - 3);
}
#else
static inline void diag_send_error_rsp(int index) {}
@@ -1994,27 +1335,6 @@
driver->use_device_tree = has_device_tree();
mutex_init(&driver->diag_cntl_mutex);
- if (driver->event_mask == NULL) {
- driver->event_mask = kzalloc(sizeof(
- struct diag_ctrl_event_mask), GFP_KERNEL);
- if (driver->event_mask == NULL)
- goto err;
- kmemleak_not_leak(driver->event_mask);
- }
- if (driver->msg_mask == NULL) {
- driver->msg_mask = kzalloc(sizeof(
- struct diag_ctrl_msg_mask), GFP_KERNEL);
- if (driver->msg_mask == NULL)
- goto err;
- kmemleak_not_leak(driver->msg_mask);
- }
- if (driver->log_mask == NULL) {
- driver->log_mask = kzalloc(sizeof(
- struct diag_ctrl_log_mask), GFP_KERNEL);
- if (driver->log_mask == NULL)
- goto err;
- kmemleak_not_leak(driver->log_mask);
- }
if (driver->buf_in_1 == NULL) {
driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
if (driver->buf_in_1 == NULL)
@@ -2051,28 +1371,6 @@
goto err;
kmemleak_not_leak(driver->buf_in_wcnss_2);
}
-
- if (driver->buf_msg_mask_update == NULL) {
- driver->buf_msg_mask_update = kzalloc(APPS_BUF_SIZE,
- GFP_KERNEL);
- if (driver->buf_msg_mask_update == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_msg_mask_update);
- }
- if (driver->buf_log_mask_update == NULL) {
- driver->buf_log_mask_update = kzalloc(APPS_BUF_SIZE,
- GFP_KERNEL);
- if (driver->buf_log_mask_update == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_log_mask_update);
- }
- if (driver->buf_event_mask_update == NULL) {
- driver->buf_event_mask_update = kzalloc(APPS_BUF_SIZE,
- GFP_KERNEL);
- if (driver->buf_event_mask_update == NULL)
- goto err;
- kmemleak_not_leak(driver->buf_event_mask_update);
- }
if (driver->usb_buf_out == NULL &&
(driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
GFP_KERNEL)) == NULL)
@@ -2087,23 +1385,6 @@
if (driver->user_space_data == NULL)
goto err;
kmemleak_not_leak(driver->user_space_data);
- if (driver->msg_masks == NULL
- && (driver->msg_masks = kzalloc(MSG_MASK_SIZE,
- GFP_KERNEL)) == NULL)
- goto err;
- kmemleak_not_leak(driver->msg_masks);
- diag_create_msg_mask_table();
- diag_event_num_bytes = 0;
- if (driver->log_masks == NULL &&
- (driver->log_masks = kzalloc(LOG_MASK_SIZE, GFP_KERNEL)) == NULL)
- goto err;
- kmemleak_not_leak(driver->log_masks);
- driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
- if (driver->event_masks == NULL &&
- (driver->event_masks = kzalloc(EVENT_MASK_SIZE,
- GFP_KERNEL)) == NULL)
- goto err;
- kmemleak_not_leak(driver->event_masks);
if (driver->client_map == NULL &&
(driver->client_map = kzalloc
((driver->num_clients) * sizeof(struct diag_client_map),
@@ -2192,12 +1473,6 @@
#ifdef CONFIG_DIAG_OVER_USB
INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
- INIT_WORK(&(driver->diag_modem_mask_update_work),
- diag_modem_mask_update_fn);
- INIT_WORK(&(driver->diag_lpass_mask_update_work),
- diag_lpass_mask_update_fn);
- INIT_WORK(&(driver->diag_wcnss_mask_update_work),
- diag_wcnss_mask_update_fn);
driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
diag_usb_legacy_notifier);
if (IS_ERR(driver->legacy_ch)) {
@@ -2210,40 +1485,34 @@
return;
err:
- pr_err("diag: Could not initialize diag buffers");
- kfree(driver->event_mask);
- kfree(driver->log_mask);
- kfree(driver->msg_mask);
- kfree(driver->buf_in_1);
- kfree(driver->buf_in_2);
- kfree(driver->buf_in_lpass_1);
- kfree(driver->buf_in_lpass_2);
- kfree(driver->buf_in_wcnss_1);
- kfree(driver->buf_in_wcnss_2);
- kfree(driver->buf_msg_mask_update);
- kfree(driver->buf_log_mask_update);
- kfree(driver->buf_event_mask_update);
- kfree(driver->usb_buf_out);
- kfree(driver->hdlc_buf);
- kfree(driver->msg_masks);
- kfree(driver->log_masks);
- kfree(driver->event_masks);
- kfree(driver->client_map);
- kfree(driver->buf_tbl);
- kfree(driver->data_ready);
- kfree(driver->table);
- kfree(driver->pkt_buf);
- kfree(driver->write_ptr_1);
- kfree(driver->write_ptr_2);
- kfree(driver->write_ptr_lpass_1);
- kfree(driver->write_ptr_lpass_2);
- kfree(driver->write_ptr_wcnss_1);
- kfree(driver->write_ptr_wcnss_2);
- kfree(driver->usb_read_ptr);
- kfree(driver->apps_rsp_buf);
- kfree(driver->user_space_data);
- if (driver->diag_wq)
- destroy_workqueue(driver->diag_wq);
+ pr_err("diag: Could not initialize diag buffers");
+ kfree(driver->buf_in_1);
+ kfree(driver->buf_in_2);
+ kfree(driver->buf_in_lpass_1);
+ kfree(driver->buf_in_lpass_2);
+ kfree(driver->buf_in_wcnss_1);
+ kfree(driver->buf_in_wcnss_2);
+ kfree(driver->buf_msg_mask_update);
+ kfree(driver->buf_log_mask_update);
+ kfree(driver->buf_event_mask_update);
+ kfree(driver->usb_buf_out);
+ kfree(driver->hdlc_buf);
+ kfree(driver->client_map);
+ kfree(driver->buf_tbl);
+ kfree(driver->data_ready);
+ kfree(driver->table);
+ kfree(driver->pkt_buf);
+ kfree(driver->write_ptr_1);
+ kfree(driver->write_ptr_2);
+ kfree(driver->write_ptr_lpass_1);
+ kfree(driver->write_ptr_lpass_2);
+ kfree(driver->write_ptr_wcnss_1);
+ kfree(driver->write_ptr_wcnss_2);
+ kfree(driver->usb_read_ptr);
+ kfree(driver->apps_rsp_buf);
+ kfree(driver->user_space_data);
+ if (driver->diag_wq)
+ destroy_workqueue(driver->diag_wq);
}
void diagfwd_exit(void)
@@ -2262,9 +1531,6 @@
platform_driver_unregister(&msm_smd_ch1_driver);
platform_driver_unregister(&msm_diag_dci_driver);
platform_driver_unregister(&diag_smd_lite_driver);
- kfree(driver->event_mask);
- kfree(driver->log_mask);
- kfree(driver->msg_mask);
kfree(driver->buf_in_1);
kfree(driver->buf_in_2);
kfree(driver->buf_in_lpass_1);
@@ -2276,9 +1542,6 @@
kfree(driver->buf_event_mask_update);
kfree(driver->usb_buf_out);
kfree(driver->hdlc_buf);
- kfree(driver->msg_masks);
- kfree(driver->log_masks);
- kfree(driver->event_masks);
kfree(driver->client_map);
kfree(driver->buf_tbl);
kfree(driver->data_ready);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index cf7fda6..a0631d6 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -16,6 +16,9 @@
#define NO_PROCESS 0
#define NON_APPS_PROC -1
+#define CHK_OVERFLOW(bufStart, start, end, length) \
+ ((((bufStart) <= (start)) && ((end) - (start) >= (length))) ? 1 : 0)
+
void diagfwd_init(void);
void diagfwd_exit(void);
void diag_process_hdlc(void *data, unsigned len);
@@ -31,11 +34,9 @@
int chk_apps_only(void);
int chk_apps_master(void);
int chk_polling_response(void);
-void diag_send_event_mask_update(smd_channel_t *, int num_bytes);
-void diag_send_msg_mask_update(smd_channel_t *, int ssid_first,
- int ssid_last, int proc);
-void diag_send_log_mask_update(smd_channel_t *, int);
+void diag_update_userspace_clients(unsigned int type);
void diag_update_sleeping_process(int process_id, int data_type);
+void encode_rsp_and_send(int buf_length);
/* State for diag forwarding */
#ifdef CONFIG_DIAG_OVER_USB
int diagfwd_connect(void);
@@ -43,6 +44,5 @@
#endif
extern int diag_debug_buf_idx;
extern unsigned char diag_debug_buf[1024];
-extern int diag_event_num_bytes;
extern struct platform_driver msm_diag_dci_driver;
#endif
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 9fc1164..4848a1d 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -17,9 +17,6 @@
#include "diagchar.h"
#include "diagfwd.h"
#include "diagfwd_cntl.h"
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#endif
/* tracks which peripheral is undergoing SSR */
static uint16_t reg_dirty;
#define HDR_SIZ 8
@@ -221,6 +218,8 @@
pr_err("diag: drop reg proc %d\n",
proc_num);
kfree(temp);
+ } else if (type != DIAG_CTRL_MSG_REG) {
+ flag = 1;
}
buf = buf + HDR_SIZ + data_len;
}
@@ -363,291 +362,3 @@
kfree(driver->buf_in_lpass_cntl);
kfree(driver->buf_in_wcnss_cntl);
}
-
-#ifdef CONFIG_DEBUG_FS
-#define DEBUG_BUF_SIZE 4096
-static struct dentry *diag_dbgfs_dent;
-static int diag_dbgfs_table_index;
-
-static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- char *buf;
- int ret;
-
- buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
- if (!buf) {
- pr_err("diag: %s, Error allocating memory\n", __func__);
- return -ENOMEM;
- }
-
- ret = scnprintf(buf, DEBUG_BUF_SIZE,
- "modem ch: 0x%x\n"
- "lpass ch: 0x%x\n"
- "riva ch: 0x%x\n"
- "dci ch: 0x%x\n"
- "modem cntl_ch: 0x%x\n"
- "lpass cntl_ch: 0x%x\n"
- "riva cntl_ch: 0x%x\n"
- "CPU Tools id: %d\n"
- "Apps only: %d\n"
- "Apps master: %d\n"
- "Check Polling Response: %d\n"
- "polling_reg_flag: %d\n"
- "uses device tree: %d\n"
- "in_busy_1: %d\n"
- "in_busy_2: %d\n"
- "in_busy_lpass_1: %d\n"
- "in_busy_lpass_2: %d\n"
- "in_busy_wcnss_1: %d\n"
- "in_busy_wcnss_2: %d\n"
- "in_busy_dci: %d\n"
- "logging_mode: %d\n",
- (unsigned int)driver->ch,
- (unsigned int)driver->chlpass,
- (unsigned int)driver->ch_wcnss,
- (unsigned int)driver->ch_dci,
- (unsigned int)driver->ch_cntl,
- (unsigned int)driver->chlpass_cntl,
- (unsigned int)driver->ch_wcnss_cntl,
- chk_config_get_id(),
- chk_apps_only(),
- chk_apps_master(),
- chk_polling_response(),
- driver->polling_reg_flag,
- driver->use_device_tree,
- driver->in_busy_1,
- driver->in_busy_2,
- driver->in_busy_lpass_1,
- driver->in_busy_lpass_2,
- driver->in_busy_wcnss_1,
- driver->in_busy_wcnss_2,
- driver->in_busy_dci,
- driver->logging_mode);
-
-#ifdef CONFIG_DIAG_OVER_USB
- ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
- "usb_connected: %d\n",
- driver->usb_connected);
-#endif
- ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
-
- kfree(buf);
- return ret;
-}
-
-static ssize_t diag_dbgfs_read_workpending(struct file *file,
- char __user *ubuf, size_t count, loff_t *ppos)
-{
- char *buf;
- int ret;
-
- buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
- if (!buf) {
- pr_err("diag: %s, Error allocating memory\n", __func__);
- return -ENOMEM;
- }
-
- ret = scnprintf(buf, DEBUG_BUF_SIZE,
- "Pending status for work_stucts:\n"
- "diag_drain_work: %d\n"
- "diag_read_smd_work: %d\n"
- "diag_read_smd_cntl_work: %d\n"
- "diag_read_smd_lpass_work: %d\n"
- "diag_read_smd_lpass_cntl_work: %d\n"
- "diag_read_smd_wcnss_work: %d\n"
- "diag_read_smd_wcnss_cntl_work: %d\n"
- "diag_modem_mask_update_work: %d\n"
- "diag_lpass_mask_update_work: %d\n"
- "diag_wcnss_mask_update_work: %d\n"
- "diag_read_smd_dci_work: %d\n",
- work_pending(&(driver->diag_drain_work)),
- work_pending(&(driver->diag_read_smd_work)),
- work_pending(&(driver->diag_read_smd_cntl_work)),
- work_pending(&(driver->diag_read_smd_lpass_work)),
- work_pending(&(driver->diag_read_smd_lpass_cntl_work)),
- work_pending(&(driver->diag_read_smd_wcnss_work)),
- work_pending(&(driver->diag_read_smd_wcnss_cntl_work)),
- work_pending(&(driver->diag_modem_mask_update_work)),
- work_pending(&(driver->diag_lpass_mask_update_work)),
- work_pending(&(driver->diag_wcnss_mask_update_work)),
- work_pending(&(driver->diag_read_smd_dci_work)));
-
-#ifdef CONFIG_DIAG_OVER_USB
- ret += scnprintf(buf+ret, DEBUG_BUF_SIZE,
- "diag_proc_hdlc_work: %d\n"
- "diag_read_work: %d\n",
- work_pending(&(driver->diag_proc_hdlc_work)),
- work_pending(&(driver->diag_read_work)));
-#endif
- ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
-
- kfree(buf);
- return ret;
-}
-
-static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- char *buf;
- int ret = 0;
- int i;
- int bytes_remaining;
- int bytes_in_buffer = 0;
- int bytes_written;
- int buf_size = (DEBUG_BUF_SIZE < count) ? DEBUG_BUF_SIZE : count;
-
- if (diag_dbgfs_table_index >= diag_max_reg) {
- /* Done. Reset to prepare for future requests */
- diag_dbgfs_table_index = 0;
- return 0;
- }
-
- buf = kzalloc(sizeof(char) * buf_size, GFP_KERNEL);
- if (!buf) {
- pr_err("diag: %s, Error allocating memory\n", __func__);
- return -ENOMEM;
- }
-
- bytes_remaining = buf_size;
- for (i = diag_dbgfs_table_index; i < diag_max_reg; i++) {
- /* Do not process empty entries in the table */
- if (driver->table[i].process_id == 0)
- continue;
-
- bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
- "i: %3d, cmd_code: %4x, subsys_id: %4x, "
- "client: %2d, cmd_code_lo: %4x, "
- "cmd_code_hi: %4x, process_id: %5d\n",
- i,
- driver->table[i].cmd_code,
- driver->table[i].subsys_id,
- driver->table[i].client_id,
- driver->table[i].cmd_code_lo,
- driver->table[i].cmd_code_hi,
- driver->table[i].process_id);
-
- bytes_in_buffer += bytes_written;
-
- /* Check if there is room to add another table entry */
- bytes_remaining = buf_size - bytes_in_buffer;
- if (bytes_remaining < bytes_written)
- break;
- }
- diag_dbgfs_table_index = i;
-
- *ppos = 0;
- ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
-
- kfree(buf);
- return ret;
-}
-
-#ifdef CONFIG_DIAG_BRIDGE_CODE
-static ssize_t diag_dbgfs_read_hsic(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- char *buf;
- int ret;
-
- buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
- if (!buf) {
- pr_err("diag: %s, Error allocating memory\n", __func__);
- return -ENOMEM;
- }
-
- ret = scnprintf(buf, DEBUG_BUF_SIZE,
- "hsic ch: %d\n"
- "hsic_inited: %d\n"
- "hsic enabled: %d\n"
- "hsic_opened: %d\n"
- "hsic_suspend: %d\n"
- "in_busy_hsic_read_on_device: %d\n"
- "in_busy_hsic_write: %d\n"
- "count_hsic_pool: %d\n"
- "count_hsic_write_pool: %d\n"
- "diag_hsic_pool: %x\n"
- "diag_hsic_write_pool: %x\n"
- "write_len_mdm: %d\n"
- "num_hsic_buf_tbl_entries: %d\n"
- "usb_mdm_connected: %d\n"
- "diag_read_mdm_work: %d\n"
- "diag_read_hsic_work: %d\n"
- "diag_disconnect_work: %d\n"
- "diag_usb_read_complete_work: %d\n",
- driver->hsic_ch,
- driver->hsic_inited,
- driver->hsic_device_enabled,
- driver->hsic_device_opened,
- driver->hsic_suspend,
- driver->in_busy_hsic_read_on_device,
- driver->in_busy_hsic_write,
- driver->count_hsic_pool,
- driver->count_hsic_write_pool,
- (unsigned int)driver->diag_hsic_pool,
- (unsigned int)driver->diag_hsic_write_pool,
- driver->write_len_mdm,
- driver->num_hsic_buf_tbl_entries,
- driver->usb_mdm_connected,
- work_pending(&(driver->diag_read_mdm_work)),
- work_pending(&(driver->diag_read_hsic_work)),
- work_pending(&(driver->diag_disconnect_work)),
- work_pending(&(driver->diag_usb_read_complete_work)));
-
- ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
-
- kfree(buf);
- return ret;
-}
-
-const struct file_operations diag_dbgfs_hsic_ops = {
- .read = diag_dbgfs_read_hsic,
-};
-#endif
-
-const struct file_operations diag_dbgfs_status_ops = {
- .read = diag_dbgfs_read_status,
-};
-
-const struct file_operations diag_dbgfs_table_ops = {
- .read = diag_dbgfs_read_table,
-};
-
-const struct file_operations diag_dbgfs_workpending_ops = {
- .read = diag_dbgfs_read_workpending,
-};
-
-void diag_debugfs_init(void)
-{
- diag_dbgfs_dent = debugfs_create_dir("diag", 0);
- if (IS_ERR(diag_dbgfs_dent))
- return;
-
- debugfs_create_file("status", 0444, diag_dbgfs_dent, 0,
- &diag_dbgfs_status_ops);
-
- debugfs_create_file("table", 0444, diag_dbgfs_dent, 0,
- &diag_dbgfs_table_ops);
-
- debugfs_create_file("work_pending", 0444, diag_dbgfs_dent, 0,
- &diag_dbgfs_workpending_ops);
-
-#ifdef CONFIG_DIAG_BRIDGE_CODE
- debugfs_create_file("hsic", 0444, diag_dbgfs_dent, 0,
- &diag_dbgfs_hsic_ops);
-#endif
-
- diag_dbgfs_table_index = 0;
-}
-
-void diag_debugfs_cleanup(void)
-{
- if (diag_dbgfs_dent) {
- debugfs_remove_recursive(diag_dbgfs_dent);
- diag_dbgfs_dent = NULL;
- }
-}
-#else
-void diag_debugfs_init(void) { }
-void diag_debugfs_cleanup(void) { }
-#endif
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index e6f5352..8a0ec3f 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -88,7 +88,5 @@
void diag_clean_modem_reg_fn(struct work_struct *);
void diag_clean_lpass_reg_fn(struct work_struct *);
void diag_clean_wcnss_reg_fn(struct work_struct *);
-void diag_debugfs_init(void);
-void diag_debugfs_cleanup(void);
#endif
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index a23fff0..ea4ad4f 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -31,6 +31,16 @@
For production builds, you should probably say 'N' here to avoid
potential power, performance and memory penalty.
+config MSM_QDSS_ETM_PCSAVE_DEFAULT_ENABLE
+ bool "Turn on PC saving by default"
+ depends on MSM_QDSS
+ help
+ Turns on program counter saving on reset by default. Otherwise,
+ PC saving is disabled by default but can be enabled via sysfs.
+
+ For production builds, you should probably say 'N' here to avoid
+ potential power penalty.
+
config CONTROL_TRACE
tristate "Turn on to control tracing"
help
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index a2815de..033e5a0 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_CONTROL_TRACE) += control_trace.o
obj-$(CONFIG_OF) += of_coresight.o
-obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-csr.o coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o
+obj-$(CONFIG_MSM_QDSS) += coresight.o coresight-csr.o coresight-tmc.o coresight-tpiu.o coresight-etb.o coresight-funnel.o coresight-replicator.o coresight-stm.o coresight-etm.o coresight-etm-cp14.o
diff --git a/drivers/coresight/coresight-etm-cp14.c b/drivers/coresight/coresight-etm-cp14.c
new file mode 100644
index 0000000..9a6c13a
--- /dev/null
+++ b/drivers/coresight/coresight-etm-cp14.c
@@ -0,0 +1,510 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/hardware/cp14.h>
+
+static unsigned int etm_read_reg(uint32_t reg)
+{
+ switch (reg) {
+ case 0x0:
+ return etm_read(ETMCR);
+ case 0x1:
+ return etm_read(ETMCCR);
+ case 0x2:
+ return etm_read(ETMTRIGGER);
+ case 0x4:
+ return etm_read(ETMSR);
+ case 0x5:
+ return etm_read(ETMSCR);
+ case 0x6:
+ return etm_read(ETMTSSCR);
+ case 0x8:
+ return etm_read(ETMTEEVR);
+ case 0x9:
+ return etm_read(ETMTECR1);
+ case 0xB:
+ return etm_read(ETMFFLR);
+ case 0x10:
+ return etm_read(ETMACVR0);
+ case 0x11:
+ return etm_read(ETMACVR1);
+ case 0x12:
+ return etm_read(ETMACVR2);
+ case 0x13:
+ return etm_read(ETMACVR3);
+ case 0x14:
+ return etm_read(ETMACVR4);
+ case 0x15:
+ return etm_read(ETMACVR5);
+ case 0x16:
+ return etm_read(ETMACVR6);
+ case 0x17:
+ return etm_read(ETMACVR7);
+ case 0x18:
+ return etm_read(ETMACVR8);
+ case 0x19:
+ return etm_read(ETMACVR9);
+ case 0x1A:
+ return etm_read(ETMACVR10);
+ case 0x1B:
+ return etm_read(ETMACVR11);
+ case 0x1C:
+ return etm_read(ETMACVR12);
+ case 0x1D:
+ return etm_read(ETMACVR13);
+ case 0x1E:
+ return etm_read(ETMACVR14);
+ case 0x1F:
+ return etm_read(ETMACVR15);
+ case 0x20:
+ return etm_read(ETMACTR0);
+ case 0x21:
+ return etm_read(ETMACTR1);
+ case 0x22:
+ return etm_read(ETMACTR2);
+ case 0x23:
+ return etm_read(ETMACTR3);
+ case 0x24:
+ return etm_read(ETMACTR4);
+ case 0x25:
+ return etm_read(ETMACTR5);
+ case 0x26:
+ return etm_read(ETMACTR6);
+ case 0x27:
+ return etm_read(ETMACTR7);
+ case 0x28:
+ return etm_read(ETMACTR8);
+ case 0x29:
+ return etm_read(ETMACTR9);
+ case 0x2A:
+ return etm_read(ETMACTR10);
+ case 0x2B:
+ return etm_read(ETMACTR11);
+ case 0x2C:
+ return etm_read(ETMACTR12);
+ case 0x2D:
+ return etm_read(ETMACTR13);
+ case 0x2E:
+ return etm_read(ETMACTR14);
+ case 0x2F:
+ return etm_read(ETMACTR15);
+ case 0x50:
+ return etm_read(ETMCNTRLDVR0);
+ case 0x51:
+ return etm_read(ETMCNTRLDVR1);
+ case 0x52:
+ return etm_read(ETMCNTRLDVR2);
+ case 0x53:
+ return etm_read(ETMCNTRLDVR3);
+ case 0x54:
+ return etm_read(ETMCNTENR0);
+ case 0x55:
+ return etm_read(ETMCNTENR1);
+ case 0x56:
+ return etm_read(ETMCNTENR2);
+ case 0x57:
+ return etm_read(ETMCNTENR3);
+ case 0x58:
+ return etm_read(ETMCNTRLDEVR0);
+ case 0x59:
+ return etm_read(ETMCNTRLDEVR1);
+ case 0x5A:
+ return etm_read(ETMCNTRLDEVR2);
+ case 0x5B:
+ return etm_read(ETMCNTRLDEVR3);
+ case 0x5C:
+ return etm_read(ETMCNTVR0);
+ case 0x5D:
+ return etm_read(ETMCNTVR1);
+ case 0x5E:
+ return etm_read(ETMCNTVR2);
+ case 0x5F:
+ return etm_read(ETMCNTVR3);
+ case 0x60:
+ return etm_read(ETMSQ12EVR);
+ case 0x61:
+ return etm_read(ETMSQ21EVR);
+ case 0x62:
+ return etm_read(ETMSQ23EVR);
+ case 0x63:
+ return etm_read(ETMSQ31EVR);
+ case 0x64:
+ return etm_read(ETMSQ32EVR);
+ case 0x65:
+ return etm_read(ETMSQ13EVR);
+ case 0x67:
+ return etm_read(ETMSQR);
+ case 0x68:
+ return etm_read(ETMEXTOUTEVR0);
+ case 0x69:
+ return etm_read(ETMEXTOUTEVR1);
+ case 0x6A:
+ return etm_read(ETMEXTOUTEVR2);
+ case 0x6B:
+ return etm_read(ETMEXTOUTEVR3);
+ case 0x6C:
+ return etm_read(ETMCIDCVR0);
+ case 0x6D:
+ return etm_read(ETMCIDCVR1);
+ case 0x6E:
+ return etm_read(ETMCIDCVR2);
+ case 0x6F:
+ return etm_read(ETMCIDCMR);
+ case 0x70:
+ return etm_read(ETMIMPSPEC0);
+ case 0x71:
+ return etm_read(ETMIMPSPEC1);
+ case 0x72:
+ return etm_read(ETMIMPSPEC2);
+ case 0x73:
+ return etm_read(ETMIMPSPEC3);
+ case 0x74:
+ return etm_read(ETMIMPSPEC4);
+ case 0x75:
+ return etm_read(ETMIMPSPEC5);
+ case 0x76:
+ return etm_read(ETMIMPSPEC6);
+ case 0x77:
+ return etm_read(ETMIMPSPEC7);
+ case 0x78:
+ return etm_read(ETMSYNCFR);
+ case 0x79:
+ return etm_read(ETMIDR);
+ case 0x7A:
+ return etm_read(ETMCCER);
+ case 0x7B:
+ return etm_read(ETMEXTINSELR);
+ case 0x7C:
+ return etm_read(ETMTESSEICR);
+ case 0x7D:
+ return etm_read(ETMEIBCR);
+ case 0x7E:
+ return etm_read(ETMTSEVR);
+ case 0x7F:
+ return etm_read(ETMAUXCR);
+ case 0x80:
+ return etm_read(ETMTRACEIDR);
+ case 0x90:
+ return etm_read(ETMVMIDCVR);
+ case 0xC1:
+ return etm_read(ETMOSLSR);
+ case 0xC2:
+ return etm_read(ETMOSSRR);
+ case 0xC4:
+ return etm_read(ETMPDCR);
+ case 0xC5:
+ return etm_read(ETMPDSR);
+ default:
+ WARN(1, "invalid CP14 access to ETM reg: %lx",
+ (unsigned long)reg);
+ return 0;
+ }
+}
+
+static void etm_write_reg(uint32_t val, uint32_t reg)
+{
+ switch (reg) {
+ case 0x0:
+ etm_write(val, ETMCR);
+ return;
+ case 0x2:
+ etm_write(val, ETMTRIGGER);
+ return;
+ case 0x4:
+ etm_write(val, ETMSR);
+ return;
+ case 0x6:
+ etm_write(val, ETMTSSCR);
+ return;
+ case 0x8:
+ etm_write(val, ETMTEEVR);
+ return;
+ case 0x9:
+ etm_write(val, ETMTECR1);
+ return;
+ case 0xB:
+ etm_write(val, ETMFFLR);
+ return;
+ case 0x10:
+ etm_write(val, ETMACVR0);
+ return;
+ case 0x11:
+ etm_write(val, ETMACVR1);
+ return;
+ case 0x12:
+ etm_write(val, ETMACVR2);
+ return;
+ case 0x13:
+ etm_write(val, ETMACVR3);
+ return;
+ case 0x14:
+ etm_write(val, ETMACVR4);
+ return;
+ case 0x15:
+ etm_write(val, ETMACVR5);
+ return;
+ case 0x16:
+ etm_write(val, ETMACVR6);
+ return;
+ case 0x17:
+ etm_write(val, ETMACVR7);
+ return;
+ case 0x18:
+ etm_write(val, ETMACVR8);
+ return;
+ case 0x19:
+ etm_write(val, ETMACVR9);
+ return;
+ case 0x1A:
+ etm_write(val, ETMACVR10);
+ return;
+ case 0x1B:
+ etm_write(val, ETMACVR11);
+ return;
+ case 0x1C:
+ etm_write(val, ETMACVR12);
+ return;
+ case 0x1D:
+ etm_write(val, ETMACVR13);
+ return;
+ case 0x1E:
+ etm_write(val, ETMACVR14);
+ return;
+ case 0x1F:
+ etm_write(val, ETMACVR15);
+ return;
+ case 0x20:
+ etm_write(val, ETMACTR0);
+ return;
+ case 0x21:
+ etm_write(val, ETMACTR1);
+ return;
+ case 0x22:
+ etm_write(val, ETMACTR2);
+ return;
+ case 0x23:
+ etm_write(val, ETMACTR3);
+ return;
+ case 0x24:
+ etm_write(val, ETMACTR4);
+ return;
+ case 0x25:
+ etm_write(val, ETMACTR5);
+ return;
+ case 0x26:
+ etm_write(val, ETMACTR6);
+ return;
+ case 0x27:
+ etm_write(val, ETMACTR7);
+ return;
+ case 0x28:
+ etm_write(val, ETMACTR8);
+ return;
+ case 0x29:
+ etm_write(val, ETMACTR9);
+ return;
+ case 0x2A:
+ etm_write(val, ETMACTR10);
+ return;
+ case 0x2B:
+ etm_write(val, ETMACTR11);
+ return;
+ case 0x2C:
+ etm_write(val, ETMACTR12);
+ return;
+ case 0x2D:
+ etm_write(val, ETMACTR13);
+ return;
+ case 0x2E:
+ etm_write(val, ETMACTR14);
+ return;
+ case 0x2F:
+ etm_write(val, ETMACTR15);
+ return;
+ case 0x50:
+ etm_write(val, ETMCNTRLDVR0);
+ return;
+ case 0x51:
+ etm_write(val, ETMCNTRLDVR1);
+ return;
+ case 0x52:
+ etm_write(val, ETMCNTRLDVR2);
+ return;
+ case 0x53:
+ etm_write(val, ETMCNTRLDVR3);
+ return;
+ case 0x54:
+ etm_write(val, ETMCNTENR0);
+ return;
+ case 0x55:
+ etm_write(val, ETMCNTENR1);
+ return;
+ case 0x56:
+ etm_write(val, ETMCNTENR2);
+ return;
+ case 0x57:
+ etm_write(val, ETMCNTENR3);
+ return;
+ case 0x58:
+ etm_write(val, ETMCNTRLDEVR0);
+ return;
+ case 0x59:
+ etm_write(val, ETMCNTRLDEVR1);
+ return;
+ case 0x5A:
+ etm_write(val, ETMCNTRLDEVR2);
+ return;
+ case 0x5B:
+ etm_write(val, ETMCNTRLDEVR3);
+ return;
+ case 0x5C:
+ etm_write(val, ETMCNTVR0);
+ return;
+ case 0x5D:
+ etm_write(val, ETMCNTVR1);
+ return;
+ case 0x5E:
+ etm_write(val, ETMCNTVR2);
+ return;
+ case 0x5F:
+ etm_write(val, ETMCNTVR3);
+ return;
+ case 0x60:
+ etm_write(val, ETMSQ12EVR);
+ return;
+ case 0x61:
+ etm_write(val, ETMSQ21EVR);
+ return;
+ case 0x62:
+ etm_write(val, ETMSQ23EVR);
+ return;
+ case 0x63:
+ etm_write(val, ETMSQ31EVR);
+ return;
+ case 0x64:
+ etm_write(val, ETMSQ32EVR);
+ return;
+ case 0x65:
+ etm_write(val, ETMSQ13EVR);
+ return;
+ case 0x67:
+ etm_write(val, ETMSQR);
+ return;
+ case 0x68:
+ etm_write(val, ETMEXTOUTEVR0);
+ return;
+ case 0x69:
+ etm_write(val, ETMEXTOUTEVR1);
+ return;
+ case 0x6A:
+ etm_write(val, ETMEXTOUTEVR2);
+ return;
+ case 0x6B:
+ etm_write(val, ETMEXTOUTEVR3);
+ return;
+ case 0x6C:
+ etm_write(val, ETMCIDCVR0);
+ return;
+ case 0x6D:
+ etm_write(val, ETMCIDCVR1);
+ return;
+ case 0x6E:
+ etm_write(val, ETMCIDCVR2);
+ return;
+ case 0x6F:
+ etm_write(val, ETMCIDCMR);
+ return;
+ case 0x70:
+ etm_write(val, ETMIMPSPEC0);
+ return;
+ case 0x71:
+ etm_write(val, ETMIMPSPEC1);
+ return;
+ case 0x72:
+ etm_write(val, ETMIMPSPEC2);
+ return;
+ case 0x73:
+ etm_write(val, ETMIMPSPEC3);
+ return;
+ case 0x74:
+ etm_write(val, ETMIMPSPEC4);
+ return;
+ case 0x75:
+ etm_write(val, ETMIMPSPEC5);
+ return;
+ case 0x76:
+ etm_write(val, ETMIMPSPEC6);
+ return;
+ case 0x77:
+ etm_write(val, ETMIMPSPEC7);
+ return;
+ case 0x78:
+ etm_write(val, ETMSYNCFR);
+ return;
+ case 0x7B:
+ etm_write(val, ETMEXTINSELR);
+ return;
+ case 0x7C:
+ etm_write(val, ETMTESSEICR);
+ return;
+ case 0x7D:
+ etm_write(val, ETMEIBCR);
+ return;
+ case 0x7E:
+ etm_write(val, ETMTSEVR);
+ return;
+ case 0x7F:
+ etm_write(val, ETMAUXCR);
+ return;
+ case 0x80:
+ etm_write(val, ETMTRACEIDR);
+ return;
+ case 0x90:
+ etm_write(val, ETMVMIDCVR);
+ return;
+ case 0xC0:
+ etm_write(val, ETMOSLAR);
+ return;
+ case 0xC2:
+ etm_write(val, ETMOSSRR);
+ return;
+ case 0xC4:
+ etm_write(val, ETMPDCR);
+ return;
+ case 0xC5:
+ etm_write(val, ETMPDSR);
+ return;
+ default:
+ WARN(1, "invalid CP14 access to ETM reg: %lx",
+ (unsigned long)reg);
+ return;
+ }
+}
+
+static inline uint32_t offset_to_reg_num(uint32_t off)
+{
+ return off >> 2;
+}
+
+unsigned int etm_readl_cp14(uint32_t off)
+{
+ uint32_t reg = offset_to_reg_num(off);
+ return etm_read_reg(reg);
+}
+
+void etm_writel_cp14(uint32_t val, uint32_t off)
+{
+ uint32_t reg = offset_to_reg_num(off);
+ etm_write_reg(val, reg);
+}
diff --git a/drivers/coresight/coresight-etm.c b/drivers/coresight/coresight-etm.c
index f4c4d08..50bae55 100644
--- a/drivers/coresight/coresight-etm.c
+++ b/drivers/coresight/coresight-etm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -35,20 +35,45 @@
#include "coresight-priv.h"
-#define etm_writel(drvdata, val, off) \
+#define etm_writel_mm(drvdata, val, off) \
__raw_writel((val), drvdata->base + off)
-#define etm_readl(drvdata, off) \
+#define etm_readl_mm(drvdata, off) \
__raw_readl(drvdata->base + off)
+#define etm_writel(drvdata, val, off) \
+({ \
+ if (cpu_is_krait_v3()) \
+ etm_writel_cp14(val, off); \
+ else \
+ etm_writel_mm(drvdata, val, off); \
+})
+#define etm_readl(drvdata, off) \
+({ \
+ uint32_t val; \
+ if (cpu_is_krait_v3()) \
+ val = etm_readl_cp14(off); \
+ else \
+ val = etm_readl_mm(drvdata, off); \
+ val; \
+})
+
#define ETM_LOCK(drvdata) \
do { \
+ /* recommended by spec to ensure ETM writes are committed prior
+ * to resuming execution
+ */ \
mb(); \
- etm_writel(drvdata, 0x0, CORESIGHT_LAR); \
+ isb(); \
+ etm_writel_mm(drvdata, 0x0, CORESIGHT_LAR); \
} while (0)
#define ETM_UNLOCK(drvdata) \
do { \
- etm_writel(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
+ etm_writel_mm(drvdata, CORESIGHT_UNLOCK, CORESIGHT_LAR); \
+ /* ensure unlock and any pending writes are committed prior to
+ * programming ETM registers
+ */ \
mb(); \
+ isb(); \
} while (0)
/*
@@ -152,6 +177,15 @@
boot_enable, boot_enable, int, S_IRUGO
);
+#ifdef CONFIG_MSM_QDSS_ETM_PCSAVE_DEFAULT_ENABLE
+static int boot_pcsave_enable = 1;
+#else
+static int boot_pcsave_enable;
+#endif
+module_param_named(
+ boot_pcsave_enable, boot_pcsave_enable, int, S_IRUGO
+);
+
struct etm_drvdata {
void __iomem *base;
struct device *dev;
@@ -169,6 +203,7 @@
uint8_t reset;
uint32_t mode;
uint32_t ctrl;
+ uint8_t ctrl_pwrdwn;
uint32_t trigger_event;
uint32_t startstop_ctrl;
uint32_t enable_event;
@@ -195,12 +230,16 @@
uint32_t ctxid_mask;
uint32_t sync_freq;
uint32_t timestamp_event;
+ uint8_t pdcr_pwrup;
+ bool pcsave_impl;
+ bool pcsave_enable;
};
static struct etm_drvdata *etm0drvdata;
-/* ETM clock is derived from the processor clock and gets enabled on a
- * logical OR of below items on Krait (pass2 onwards):
+/*
+ * ETM clock is derived from the processor clock and gets enabled on a
+ * logical OR of below items on Krait (v2 onwards):
* 1.CPMR[ETMCLKEN] is 1
* 2.ETMCR[PD] is 0
* 3.ETMPDCR[PU] is 1
@@ -210,14 +249,17 @@
* 1., 2. and 3. above are permanent enables whereas 4. and 5. are temporary
* enables
*
- * We rely on 5. to be able to access ETMCR and then use 2. above for ETM
- * clock vote in the driver and the save-restore code uses 1. above
+ * We rely on 5. to be able to access ETMCR/ETMPDCR and then use 2./3. above
+ * for ETM clock vote in the driver and the save-restore code uses 1. above
* for its vote
*/
static void etm_set_pwrdwn(struct etm_drvdata *drvdata)
{
uint32_t etmcr;
+ /* ensure pending cp14 accesses complete before setting pwrdwn */
+ mb();
+ isb();
etmcr = etm_readl(drvdata, ETMCR);
etmcr |= BIT(0);
etm_writel(drvdata, etmcr, ETMCR);
@@ -230,6 +272,33 @@
etmcr = etm_readl(drvdata, ETMCR);
etmcr &= ~BIT(0);
etm_writel(drvdata, etmcr, ETMCR);
+ /* ensure pwrup completes before subsequent cp14 accesses */
+ mb();
+ isb();
+}
+
+static void etm_set_pwrup(struct etm_drvdata *drvdata)
+{
+ uint32_t etmpdcr;
+
+ etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
+ etmpdcr |= BIT(3);
+ etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
+ /* ensure pwrup completes before subsequent cp14 accesses */
+ mb();
+ isb();
+}
+
+static void etm_clr_pwrup(struct etm_drvdata *drvdata)
+{
+ uint32_t etmpdcr;
+
+ /* ensure pending cp14 accesses complete before clearing pwrup */
+ mb();
+ isb();
+ etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
+ etmpdcr &= ~BIT(3);
+ etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
}
static void etm_set_prog(struct etm_drvdata *drvdata)
@@ -240,6 +309,10 @@
etmcr = etm_readl(drvdata, ETMCR);
etmcr |= BIT(10);
etm_writel(drvdata, etmcr, ETMCR);
+ /* recommended by spec for cp14 accesses to ensure etmcr write is
+ * complete before polling etmsr
+ */
+ isb();
for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, ETMSR), 1) != 1
&& count > 0; count--)
udelay(1);
@@ -255,6 +328,10 @@
etmcr = etm_readl(drvdata, ETMCR);
etmcr &= ~BIT(10);
etm_writel(drvdata, etmcr, ETMCR);
+ /* recommended by spec for cp14 accesses to ensure etmcr write is
+ * complete before polling etmsr
+ */
+ isb();
for (count = TIMEOUT_US; BVAL(etm_readl(drvdata, ETMSR), 1) != 0
&& count > 0; count--)
udelay(1);
@@ -262,17 +339,94 @@
etm_readl(drvdata, ETMSR));
}
-static void __etm_enable(void *info)
+static void etm_save_pwrdwn(struct etm_drvdata *drvdata)
{
- int i;
+ drvdata->ctrl_pwrdwn = BVAL(etm_readl(drvdata, ETMCR), 0);
+}
+
+static void etm_restore_pwrdwn(struct etm_drvdata *drvdata)
+{
+ uint32_t etmcr;
+
+ etmcr = etm_readl(drvdata, ETMCR);
+ etmcr = (etmcr & ~BIT(0)) | drvdata->ctrl_pwrdwn;
+ etm_writel(drvdata, etmcr, ETMCR);
+}
+
+static void etm_save_pwrup(struct etm_drvdata *drvdata)
+{
+ drvdata->pdcr_pwrup = BVAL(etm_readl_mm(drvdata, ETMPDCR), 3);
+}
+
+static void etm_restore_pwrup(struct etm_drvdata *drvdata)
+{
+ uint32_t etmpdcr;
+
+ etmpdcr = etm_readl_mm(drvdata, ETMPDCR);
+ etmpdcr = (etmpdcr & ~BIT(3)) | (drvdata->pdcr_pwrup << 3);
+ etm_writel_mm(drvdata, etmpdcr, ETMPDCR);
+}
+
+static void etm_enable_pcsave(void *info)
+{
struct etm_drvdata *drvdata = info;
ETM_UNLOCK(drvdata);
- /* Vote for ETM power/clock enable */
+
+ etm_save_pwrup(drvdata);
+ /*
+ * ETMPDCR is only accessible via memory mapped interface and so use
+ * it first to enable power/clock to allow subsequent cp14 accesses.
+ */
+ etm_set_pwrup(drvdata);
+ etm_clr_pwrdwn(drvdata);
+ etm_restore_pwrup(drvdata);
+
+ ETM_LOCK(drvdata);
+}
+
+static void etm_disable_pcsave(void *info)
+{
+ struct etm_drvdata *drvdata = info;
+
+ ETM_UNLOCK(drvdata);
+
+ etm_save_pwrup(drvdata);
+ /*
+ * ETMPDCR is only accessible via memory mapped interface and so use
+ * it first to enable power/clock to allow subsequent cp14 accesses.
+ */
+ etm_set_pwrup(drvdata);
+ etm_set_pwrdwn(drvdata);
+ etm_restore_pwrup(drvdata);
+
+ ETM_LOCK(drvdata);
+}
+
+static void __etm_enable(void *info)
+{
+ int i;
+ uint32_t etmcr;
+ struct etm_drvdata *drvdata = info;
+
+ ETM_UNLOCK(drvdata);
+ /*
+ * Vote for ETM power/clock enable. ETMPDCR is only accessible via
+ * memory mapped interface and so use it first to enable power/clock
+ * to allow subsequent cp14 accesses.
+ */
+ etm_set_pwrup(drvdata);
+ etm_save_pwrdwn(drvdata);
+ /*
+ * Clear power down bit since when this bit is set writes to
+ * certain registers might be ignored.
+ */
etm_clr_pwrdwn(drvdata);
etm_set_prog(drvdata);
- etm_writel(drvdata, drvdata->ctrl | BIT(10), ETMCR);
+ etmcr = etm_readl(drvdata, ETMCR);
+ etmcr &= (BIT(10) | BIT(0));
+ etm_writel(drvdata, drvdata->ctrl | etmcr, ETMCR);
etm_writel(drvdata, drvdata->trigger_event, ETMTRIGGER);
etm_writel(drvdata, drvdata->startstop_ctrl, ETMTSSCR);
etm_writel(drvdata, drvdata->enable_event, ETMTEEVR);
@@ -309,6 +463,7 @@
etm_writel(drvdata, 0x00000000, ETMVMIDCVR);
etm_clr_prog(drvdata);
+ etm_restore_pwrdwn(drvdata);
ETM_LOCK(drvdata);
dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
@@ -346,13 +501,20 @@
struct etm_drvdata *drvdata = info;
ETM_UNLOCK(drvdata);
+ etm_save_pwrdwn(drvdata);
+ /*
+ * Clear power down bit since when this bit is set writes to
+ * certain registers might be ignored.
+ */
+ etm_clr_pwrdwn(drvdata);
etm_set_prog(drvdata);
/* program trace enable to low by using always false event */
etm_writel(drvdata, 0x6F | BIT(14), ETMTEEVR);
+ etm_restore_pwrdwn(drvdata);
/* Vote for ETM power/clock disable */
- etm_set_pwrdwn(drvdata);
+ etm_clr_pwrup(drvdata);
ETM_LOCK(drvdata);
dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
@@ -1307,6 +1469,7 @@
{
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val = drvdata->sync_freq;
+
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1352,6 +1515,60 @@
static DEVICE_ATTR(timestamp_event, S_IRUGO | S_IWUSR, etm_show_timestamp_event,
etm_store_timestamp_event);
+static ssize_t etm_show_pcsave(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ val = drvdata->pcsave_enable;
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static int __etm_store_pcsave(struct etm_drvdata *drvdata, unsigned long val)
+{
+ int ret;
+
+ ret = clk_prepare_enable(drvdata->clk);
+ if (ret)
+ return ret;
+
+ mutex_lock(&drvdata->mutex);
+ if (val) {
+ smp_call_function_single(drvdata->cpu, etm_enable_pcsave,
+ drvdata, 1);
+ drvdata->pcsave_enable = true;
+ } else {
+ smp_call_function_single(drvdata->cpu, etm_disable_pcsave,
+ drvdata, 1);
+ drvdata->pcsave_enable = false;
+ }
+ mutex_unlock(&drvdata->mutex);
+
+ clk_disable_unprepare(drvdata->clk);
+ return 0;
+}
+
+static ssize_t etm_store_pcsave(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+ int ret;
+
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+
+ ret = __etm_store_pcsave(drvdata, val);
+ if (ret)
+ return ret;
+
+ return size;
+}
+static DEVICE_ATTR(pcsave, S_IRUGO | S_IWUSR, etm_show_pcsave,
+ etm_store_pcsave);
+
static struct attribute *etm_attrs[] = {
&dev_attr_nr_addr_cmp.attr,
&dev_attr_nr_cntr.attr,
@@ -1416,16 +1633,32 @@
return true;
}
-static void __devinit etm_init_arch_data(struct etm_drvdata *drvdata)
+static void __devinit etm_prepare_arch(struct etm_drvdata *drvdata)
+{
+ /* Unlock OS lock first to allow memory mapped reads and writes. This
+ * is required for Krait pass1
+ * */
+ etm_os_unlock(NULL);
+ smp_call_function(etm_os_unlock, NULL, 1);
+}
+
+static void __devinit etm_init_arch_data(void *info)
{
uint32_t etmidr;
uint32_t etmccr;
+ struct etm_drvdata *drvdata = info;
- /* Unlock OS lock first to allow memory mapped reads and writes */
- etm_os_unlock(NULL);
- smp_call_function(etm_os_unlock, NULL, 1);
ETM_UNLOCK(drvdata);
- /* Vote for ETM power/clock enable */
+ /*
+ * Vote for ETM power/clock enable. ETMPDCR is only accessible via
+ * memory mapped interface and so use it first to enable power/clock
+ * to allow subsequent cp14 accesses.
+ */
+ etm_set_pwrup(drvdata);
+ /*
+ * Clear power down bit since when this bit is set writes to
+ * certain registers might be ignored.
+ */
etm_clr_pwrdwn(drvdata);
/* Set prog bit. It will be set from reset but this is included to
* ensure it is set
@@ -1443,8 +1676,9 @@
drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
- /* Vote for ETM power/clock disable */
etm_set_pwrdwn(drvdata);
+ /* Vote for ETM power/clock disable */
+ etm_clr_pwrup(drvdata);
ETM_LOCK(drvdata);
}
@@ -1518,12 +1752,6 @@
struct msm_client_dump dump;
struct coresight_desc *desc;
- /* Fail probe for Krait pass3 until supported */
- if (cpu_is_krait_v3()) {
- dev_info(dev, "ETM: failing probe for Krait pass3\n");
- return -EINVAL;
- }
-
if (pdev->dev.of_node) {
pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
if (IS_ERR(pdata))
@@ -1569,7 +1797,9 @@
* ETMs copy it over from ETM0.
*/
if (drvdata->cpu == 0) {
- etm_init_arch_data(drvdata);
+ etm_prepare_arch(drvdata);
+ smp_call_function_single(drvdata->cpu, etm_init_arch_data,
+ drvdata, 1);
etm0drvdata = drvdata;
} else {
etm_copy_arch_data(drvdata);
@@ -1615,11 +1845,24 @@
goto err0;
}
+ if (pdev->dev.of_node)
+ drvdata->pcsave_impl = of_property_read_bool(pdev->dev.of_node,
+ "qcom,pc-save");
+ if (drvdata->pcsave_impl) {
+ ret = device_create_file(&drvdata->csdev->dev,
+ &dev_attr_pcsave);
+ if (ret)
+ dev_err(dev, "ETM pcsave dev node creation failed\n");
+ }
+
dev_info(dev, "ETM initialized\n");
if (boot_enable)
coresight_enable(drvdata->csdev);
+ if (drvdata->pcsave_impl && boot_pcsave_enable)
+ __etm_store_pcsave(drvdata, true);
+
return 0;
err1:
clk_disable_unprepare(drvdata->clk);
@@ -1633,6 +1876,7 @@
{
struct etm_drvdata *drvdata = platform_get_drvdata(pdev);
+ device_remove_file(&drvdata->csdev->dev, &dev_attr_pcsave);
coresight_unregister(drvdata->csdev);
wake_lock_destroy(&drvdata->wake_lock);
mutex_destroy(&drvdata->mutex);
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 2b00242..0cf2b3d 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -39,9 +39,13 @@
#ifdef CONFIG_MSM_QDSS
extern void msm_qdss_csr_enable_bam_to_usb(void);
extern void msm_qdss_csr_disable_bam_to_usb(void);
+extern unsigned int etm_readl_cp14(uint32_t off);
+extern void etm_writel_cp14(uint32_t val, uint32_t off);
#else
static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
+static inline unsigned int etm_readl_cp14(uint32_t off) { return 0; }
+static inline void etm_writel_cp14(uint32_t val, uint32_t off) {}
#endif
#endif
diff --git a/drivers/coresight/coresight-stm.c b/drivers/coresight/coresight-stm.c
index 70b2c43..f6a948b 100644
--- a/drivers/coresight/coresight-stm.c
+++ b/drivers/coresight/coresight-stm.c
@@ -724,6 +724,13 @@
dev_info(drvdata->dev, "STM initialized\n");
+ /*
+ * Enable and disable STM to undo the temporary default STM enable
+ * done by RPM.
+ */
+ coresight_enable(drvdata->csdev);
+ coresight_disable(drvdata->csdev);
+
if (boot_enable)
coresight_enable(drvdata->csdev);
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 0be5882..13f69cd 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -1060,6 +1060,7 @@
goto err0;
}
memset(drvdata->vaddr, 0, drvdata->size);
+ drvdata->buf = drvdata->vaddr;
drvdata->out_mode = TMC_ETR_OUT_MODE_MEM;
ret = tmc_etr_bam_init(pdev, drvdata);
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
index cccb5a7..3974f2e 100644
--- a/drivers/coresight/coresight.c
+++ b/drivers/coresight/coresight.c
@@ -377,8 +377,10 @@
list_for_each_entry(cd, &coresight_devs, dev_link) {
if (cd->id == curr_sink) {
- if (cd->enable && cd->ops->sink_ops->abort)
+ if (cd->enable && cd->ops->sink_ops->abort) {
cd->ops->sink_ops->abort(cd);
+ cd->enable = false;
+ }
}
}
out:
diff --git a/drivers/cpufreq/cpufreq_gov_msm.c b/drivers/cpufreq/cpufreq_gov_msm.c
index 9c49f80..6ddbf4e 100644
--- a/drivers/cpufreq/cpufreq_gov_msm.c
+++ b/drivers/cpufreq/cpufreq_gov_msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,20 +18,114 @@
#include <linux/kobject.h>
#include <linux/cpufreq.h>
#include <linux/platform_device.h>
+#include <linux/cpu_pm.h>
+#include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
#include <mach/msm_dcvs.h>
+struct cpu_idle_info {
+ int enabled;
+ int dcvs_core_id;
+ struct pm_qos_request pm_qos_req;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_idle_info, cpu_idle_info);
+static DEFINE_PER_CPU_SHARED_ALIGNED(u64, iowait_on_cpu);
+static uint32_t latency;
+
+static int msm_dcvs_idle_notifier(int core_num,
+ enum msm_core_control_event event)
+{
+ struct cpu_idle_info *info = &per_cpu(cpu_idle_info, core_num);
+
+ switch (event) {
+ case MSM_DCVS_ENABLE_IDLE_PULSE:
+ info->enabled = true;
+ break;
+
+ case MSM_DCVS_DISABLE_IDLE_PULSE:
+ info->enabled = false;
+ break;
+
+ case MSM_DCVS_ENABLE_HIGH_LATENCY_MODES:
+ pm_qos_update_request(&info->pm_qos_req, PM_QOS_DEFAULT_VALUE);
+ break;
+
+ case MSM_DCVS_DISABLE_HIGH_LATENCY_MODES:
+ pm_qos_update_request(&info->pm_qos_req, latency);
+ break;
+ }
+
+ return 0;
+}
+
+static int msm_cpuidle_notifier(struct notifier_block *self, unsigned long cmd,
+ void *v)
+{
+ struct cpu_idle_info *info =
+ &per_cpu(cpu_idle_info, smp_processor_id());
+ u64 io_wait_us = 0;
+ u64 prev_io_wait_us = 0;
+ u64 last_update_time = 0;
+ u64 val = 0;
+ uint32_t iowaited = 0;
+
+ if (!info->enabled)
+ return NOTIFY_OK;
+
+ switch (cmd) {
+ case CPU_PM_ENTER:
+ val = get_cpu_iowait_time_us(smp_processor_id(),
+ &last_update_time);
+ /* val could be -1 when NOHZ is not enabled */
+ if (val == (u64)-1)
+ val = 0;
+ per_cpu(iowait_on_cpu, smp_processor_id()) = val;
+ msm_dcvs_idle(info->dcvs_core_id, MSM_DCVS_IDLE_ENTER, 0);
+ break;
+
+ case CPU_PM_EXIT:
+ prev_io_wait_us = per_cpu(iowait_on_cpu, smp_processor_id());
+ val = get_cpu_iowait_time_us(smp_processor_id(),
+ &last_update_time);
+ if (val == (u64)-1)
+ val = 0;
+ io_wait_us = val;
+ iowaited = (io_wait_us - prev_io_wait_us);
+ msm_dcvs_idle(info->dcvs_core_id, MSM_DCVS_IDLE_EXIT, iowaited);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block idle_nb = {
+ .notifier_call = msm_cpuidle_notifier,
+};
+
+static void msm_gov_idle_source_init(int cpu, int dcvs_core_id)
+{
+ struct cpu_idle_info *info = NULL;
+
+ info = &per_cpu(cpu_idle_info, cpu);
+ info->dcvs_core_id = dcvs_core_id;
+
+ pm_qos_add_request(&info->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+}
+
struct msm_gov {
- int cpu;
- unsigned int cur_freq;
- unsigned int min_freq;
- unsigned int max_freq;
- struct msm_dcvs_freq gov_notifier;
- struct cpufreq_policy *policy;
+ int cpu;
+ unsigned int cur_freq;
+ unsigned int min_freq;
+ unsigned int max_freq;
+ struct cpufreq_policy *policy;
+ int dcvs_core_id;
};
static DEFINE_PER_CPU_SHARED_ALIGNED(struct mutex, gov_mutex);
static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_gov, msm_gov_info);
-static char core_name[NR_CPUS][10];
static void msm_gov_check_limits(struct cpufreq_policy *policy)
{
@@ -40,7 +134,7 @@
if (policy->max < gov->cur_freq)
__cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_H);
- else if (policy->min > gov->min_freq)
+ else if (policy->min > gov->cur_freq)
__cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_L);
else
@@ -50,14 +144,14 @@
gov->cur_freq = policy->cur;
gov->min_freq = policy->min;
gov->max_freq = policy->max;
+ msm_dcvs_update_limits(gov->dcvs_core_id);
}
-static int msm_dcvs_freq_set(struct msm_dcvs_freq *self,
+static int msm_dcvs_freq_set(int core_num,
unsigned int freq)
{
int ret = -EINVAL;
- struct msm_gov *gov =
- container_of(self, struct msm_gov, gov_notifier);
+ struct msm_gov *gov = &per_cpu(msm_gov_info, core_num);
mutex_lock(&per_cpu(gov_mutex, gov->cpu));
@@ -66,23 +160,30 @@
if (freq > gov->max_freq)
freq = gov->max_freq;
- ret = __cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
- gov->cur_freq = gov->policy->cur;
-
mutex_unlock(&per_cpu(gov_mutex, gov->cpu));
- if (!ret)
- return gov->cur_freq;
+ ret = cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
+
+ if (!ret) {
+ gov->cur_freq = cpufreq_quick_get(gov->cpu);
+ if (freq != gov->cur_freq)
+ pr_err("cpu %d freq %u gov->cur_freq %u didn't match",
+ gov->cpu, freq, gov->cur_freq);
+ }
+ ret = gov->cur_freq;
return ret;
}
-static unsigned int msm_dcvs_freq_get(struct msm_dcvs_freq *self)
+static unsigned int msm_dcvs_freq_get(int core_num)
{
- struct msm_gov *gov =
- container_of(self, struct msm_gov, gov_notifier);
-
- return gov->cur_freq;
+ struct msm_gov *gov = &per_cpu(msm_gov_info, core_num);
+ /*
+ * the rw_sem in cpufreq is always held when this is called.
+ * The policy->cur won't be updated in this case - so it is safe to
+ * access policy->cur
+ */
+ return gov->policy->cur;
}
static int cpufreq_governor_msm(struct cpufreq_policy *policy,
@@ -92,8 +193,6 @@
int ret = 0;
int handle = 0;
struct msm_gov *gov = &per_cpu(msm_gov_info, policy->cpu);
- struct msm_dcvs_freq *dcvs_notifier =
- &(per_cpu(msm_gov_info, cpu).gov_notifier);
switch (event) {
case CPUFREQ_GOV_START:
@@ -103,19 +202,14 @@
mutex_lock(&per_cpu(gov_mutex, cpu));
per_cpu(msm_gov_info, cpu).cpu = cpu;
gov->policy = policy;
- dcvs_notifier->core_name = core_name[cpu];
- dcvs_notifier->set_frequency = msm_dcvs_freq_set;
- dcvs_notifier->get_frequency = msm_dcvs_freq_get;
- handle = msm_dcvs_freq_sink_register(dcvs_notifier);
+ handle = msm_dcvs_freq_sink_start(gov->dcvs_core_id);
BUG_ON(handle < 0);
msm_gov_check_limits(policy);
mutex_unlock(&per_cpu(gov_mutex, cpu));
break;
case CPUFREQ_GOV_STOP:
- mutex_lock(&per_cpu(gov_mutex, cpu));
- msm_dcvs_freq_sink_unregister(dcvs_notifier);
- mutex_unlock(&per_cpu(gov_mutex, cpu));
+ msm_dcvs_freq_sink_stop(gov->dcvs_core_id);
break;
case CPUFREQ_GOV_LIMITS:
@@ -136,21 +230,40 @@
static int __devinit msm_gov_probe(struct platform_device *pdev)
{
- int ret = 0;
int cpu;
- uint32_t group_id = 0x43505530; /* CPU0 */
struct msm_dcvs_core_info *core = NULL;
+ struct msm_dcvs_core_info *core_info = NULL;
+ struct msm_gov_platform_data *pdata = pdev->dev.platform_data;
+ int sensor = 0;
core = pdev->dev.platform_data;
+ core_info = pdata->info;
+ latency = pdata->latency;
for_each_possible_cpu(cpu) {
+ struct msm_gov *gov = &per_cpu(msm_gov_info, cpu);
+
mutex_init(&per_cpu(gov_mutex, cpu));
- snprintf(core_name[cpu], 10, "cpu%d", cpu);
- ret = msm_dcvs_register_core(core_name[cpu], group_id, core);
- if (ret)
+ if (cpu < core->num_cores)
+ sensor = core_info->sensors[cpu];
+ gov->dcvs_core_id = msm_dcvs_register_core(
+ MSM_DCVS_CORE_TYPE_CPU,
+ cpu,
+ core_info,
+ msm_dcvs_freq_set,
+ msm_dcvs_freq_get,
+ msm_dcvs_idle_notifier,
+ sensor);
+ if (gov->dcvs_core_id < 0) {
pr_err("Unable to register core for %d\n", cpu);
+ return -EINVAL;
+ }
+
+ msm_gov_idle_source_init(cpu, gov->dcvs_core_id);
}
+ cpu_pm_register_notifier(&idle_nb);
+
return cpufreq_register_governor(&cpufreq_gov_msm);
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 785ba6c..78161b6 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -869,7 +869,11 @@
static void dbs_input_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
- int i;
+ int i, j;
+ struct cpumask cpus_scheduled;
+ struct cpu_dbs_info_s *dbs_info;
+ cpumask_clear(&cpus_scheduled);
+
if ((dbs_tuners_ins.powersave_bias == POWERSAVE_BIAS_MAXLEVEL) ||
(dbs_tuners_ins.powersave_bias == POWERSAVE_BIAS_MINLEVEL)) {
@@ -878,7 +882,23 @@
}
for_each_online_cpu(i) {
+ dbs_info = &per_cpu(od_cpu_dbs_info, i);
+
+ if (!dbs_info->cur_policy) {
+ pr_err("Dbs policy is NULL\n");
+ continue;
+ }
+
+ for_each_cpu(j, &cpus_scheduled) {
+ if (cpumask_test_cpu(j, dbs_info->cur_policy->cpus))
+ goto skip_schedule;
+ }
+ cpumask_set_cpu(i, &cpus_scheduled);
queue_work_on(i, input_wq, &per_cpu(dbs_refresh_work, i));
+
+ /* This CPU is already running at new frequency */
+skip_schedule:
+ ;
}
}
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 7f760ed..a48e6b2 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -107,24 +107,6 @@
static void ion_iommu_release(struct kref *kref);
-static int ion_validate_buffer_flags(struct ion_buffer *buffer,
- unsigned long flags)
-{
- if (buffer->kmap_cnt || buffer->dmap_cnt || buffer->umap_cnt ||
- buffer->iommu_map_cnt) {
- if (buffer->flags != flags) {
- pr_err("%s: buffer was already mapped with flags %lx,"
- " cannot map with flags %lx\n", __func__,
- buffer->flags, flags);
- return 1;
- }
-
- } else {
- buffer->flags = flags;
- }
- return 0;
-}
-
/* this function should only be called while dev->lock is held */
static void ion_buffer_add(struct ion_device *dev,
struct ion_buffer *buffer)
@@ -232,6 +214,7 @@
buffer->dev = dev;
buffer->size = len;
+ buffer->flags = flags;
table = buffer->heap->ops->map_dma(buffer->heap, buffer);
if (IS_ERR_OR_NULL(table)) {
@@ -412,7 +395,8 @@
}
struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
- size_t align, unsigned int flags)
+ size_t align, unsigned int heap_mask,
+ unsigned int flags)
{
struct rb_node *n;
struct ion_handle *handle;
@@ -443,10 +427,11 @@
if (!((1 << heap->type) & client->heap_mask))
continue;
/* if the caller didn't specify this heap type */
- if (!((1 << heap->id) & flags))
+ if (!((1 << heap->id) & heap_mask))
continue;
/* Do not allow un-secure heap if secure is specified */
- if (secure_allocation && (heap->type != ION_HEAP_TYPE_CP))
+ if (secure_allocation &&
+ (heap->type != (enum ion_heap_type) ION_HEAP_TYPE_CP))
continue;
buffer = ion_buffer_create(heap, dev, len, align, flags);
if (!IS_ERR_OR_NULL(buffer))
@@ -773,8 +758,7 @@
}
EXPORT_SYMBOL(ion_unmap_iommu);
-void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle,
- unsigned long flags)
+void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle)
{
struct ion_buffer *buffer;
void *vaddr;
@@ -796,11 +780,6 @@
return ERR_PTR(-ENODEV);
}
- if (ion_validate_buffer_flags(buffer, flags)) {
- mutex_unlock(&client->lock);
- return ERR_PTR(-EEXIST);
- }
-
mutex_lock(&buffer->lock);
vaddr = ion_handle_kmap_get(handle);
mutex_unlock(&buffer->lock);
@@ -887,7 +866,7 @@
if (type == ION_HEAP_TYPE_SYSTEM_CONTIG ||
type == ION_HEAP_TYPE_CARVEOUT ||
- type == ION_HEAP_TYPE_CP)
+ type == (enum ion_heap_type) ION_HEAP_TYPE_CP)
seq_printf(s, " : %12lx", handle->buffer->priv_phys);
else
seq_printf(s, " : %12s", "N/A");
@@ -1228,36 +1207,6 @@
.kunmap = ion_dma_buf_kunmap,
};
-static int ion_share_set_flags(struct ion_client *client,
- struct ion_handle *handle,
- unsigned long flags)
-{
- struct ion_buffer *buffer;
- bool valid_handle;
- unsigned long ion_flags = ION_SET_CACHE(CACHED);
- if (flags & O_DSYNC)
- ion_flags = ION_SET_CACHE(UNCACHED);
-
- mutex_lock(&client->lock);
- valid_handle = ion_handle_validate(client, handle);
- mutex_unlock(&client->lock);
- if (!valid_handle) {
- WARN(1, "%s: invalid handle passed to set_flags.\n", __func__);
- return -EINVAL;
- }
-
- buffer = handle->buffer;
-
- mutex_lock(&buffer->lock);
- if (ion_validate_buffer_flags(buffer, ion_flags)) {
- mutex_unlock(&buffer->lock);
- return -EEXIST;
- }
- mutex_unlock(&buffer->lock);
- return 0;
-}
-
-
int ion_share_dma_buf(struct ion_client *client, struct ion_handle *handle)
{
struct ion_buffer *buffer;
@@ -1337,7 +1286,7 @@
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
return -EFAULT;
data.handle = ion_alloc(client, data.len, data.align,
- data.flags);
+ data.heap_mask, data.flags);
if (IS_ERR(data.handle))
return PTR_ERR(data.handle);
@@ -1368,14 +1317,9 @@
case ION_IOC_SHARE:
{
struct ion_fd_data data;
- int ret;
if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
return -EFAULT;
- ret = ion_share_set_flags(client, data.handle, filp->f_flags);
- if (ret)
- return ret;
-
data.fd = ion_share_dma_buf(client, data.handle);
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
@@ -1713,7 +1657,7 @@
mutex_lock(&dev->lock);
for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
- if (heap->type != ION_HEAP_TYPE_CP)
+ if (heap->type != (enum ion_heap_type) ION_HEAP_TYPE_CP)
continue;
if (ION_HEAP(heap->id) != heap_id)
continue;
@@ -1741,7 +1685,7 @@
mutex_lock(&dev->lock);
for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
- if (heap->type != ION_HEAP_TYPE_CP)
+ if (heap->type != (enum ion_heap_type) ION_HEAP_TYPE_CP)
continue;
if (ION_HEAP(heap->id) != heap_id)
continue;
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index 9f33859..2070abf 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -930,7 +930,7 @@
cp_heap->kmap_uncached_count = 0;
cp_heap->total_size = heap_data->size;
cp_heap->heap.ops = &cp_heap_ops;
- cp_heap->heap.type = ION_HEAP_TYPE_CP;
+ cp_heap->heap.type = (enum ion_heap_type) ION_HEAP_TYPE_CP;
cp_heap->heap_protected = HEAP_NOT_PROTECTED;
cp_heap->secure_base = cp_heap->base;
cp_heap->secure_size = heap_data->size;
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 165a7bf..4c83d75 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -24,7 +24,7 @@
{
struct ion_heap *heap = NULL;
- switch (heap_data->type) {
+ switch ((int) heap_data->type) {
case ION_HEAP_TYPE_SYSTEM_CONTIG:
heap = ion_system_contig_heap_create(heap_data);
break;
@@ -63,7 +63,7 @@
if (!heap)
return;
- switch (heap->type) {
+ switch ((int) heap->type) {
case ION_HEAP_TYPE_SYSTEM_CONTIG:
ion_system_contig_heap_destroy(heap);
break;
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 4c9be1d..deff514 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -264,7 +264,7 @@
if (!heap->base && heap->extra_data) {
unsigned int align = 0;
- switch (heap->type) {
+ switch ((int) heap->type) {
case ION_HEAP_TYPE_CARVEOUT:
align =
((struct ion_co_heap_pdata *) heap->extra_data)->align;
@@ -346,7 +346,7 @@
{
int ret = 0;
- switch (heap->type) {
+ switch ((int) heap->type) {
case ION_HEAP_TYPE_CP:
{
heap->extra_data = kzalloc(sizeof(struct ion_cp_heap_pdata),
@@ -414,7 +414,7 @@
int ret = of_property_read_u32(node, "qcom,heap-align", &val);
if (!ret) {
- switch (heap->type) {
+ switch ((int) heap->type) {
case ION_HEAP_TYPE_CP:
{
struct ion_cp_heap_pdata *extra =
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 05c7967..2681836 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -65,13 +65,17 @@
#define A3XX_RBBM_INT_CLEAR_CMD 0x061
#define A3XX_RBBM_INT_0_MASK 0x063
#define A3XX_RBBM_INT_0_STATUS 0x064
+#define A3XX_RBBM_PERFCTR_CTL 0x80
#define A3XX_RBBM_GPU_BUSY_MASKED 0x88
+#define A3XX_RBBM_PERFCTR_SP_7_LO 0xE0
+#define A3XX_RBBM_PERFCTR_SP_7_HI 0xE1
#define A3XX_RBBM_RBBM_CTL 0x100
#define A3XX_RBBM_RBBM_CTL 0x100
#define A3XX_RBBM_PERFCTR_PWR_1_LO 0x0EC
#define A3XX_RBBM_PERFCTR_PWR_1_HI 0x0ED
#define A3XX_RBBM_DEBUG_BUS_CTL 0x111
#define A3XX_RBBM_DEBUG_BUS_DATA_STATUS 0x112
+
/* Following two are same as on A2XX, just in a different place */
#define A3XX_CP_PFP_UCODE_ADDR 0x1C9
#define A3XX_CP_PFP_UCODE_DATA 0x1CA
@@ -160,6 +164,7 @@
#define A3XX_VPC_VPC_DEBUG_RAM_READ 0xE62
#define A3XX_UCHE_CACHE_MODE_CONTROL_REG 0xE82
#define A3XX_UCHE_CACHE_INVALIDATE0_REG 0xEA0
+#define A3XX_SP_PERFCOUNTER7_SELECT 0xECB
#define A3XX_GRAS_CL_CLIP_CNTL 0x2040
#define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
#define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048
@@ -526,6 +531,13 @@
#define RBBM_BLOCK_ID_MARB_3 0x2b
/* RBBM_CLOCK_CTL default value */
-#define A3XX_RBBM_CLOCK_CTL_DEFAULT 0xBFFFFFFF
+#define A305_RBBM_CLOCK_CTL_DEFAULT 0xAAAAAAAA
+#define A320_RBBM_CLOCK_CTL_DEFAULT 0xBFFFFFFF
+#define A330_RBBM_CLOCK_CTL_DEFAULT 0xAAAAAAAE
+
+#define A330_RBBM_GPR0_CTL_DEFAULT 0x0AE2B8AE
+
+/* COUNTABLE FOR SP PERFCOUNTER */
+#define SP_FS_FULL_ALU_INSTRUCTIONS 0x0E
#endif
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index cf7f3ce..4eca776 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -127,6 +127,8 @@
REG_CP_IB1_BUFSZ,
REG_CP_IB2_BASE,
REG_CP_IB2_BUFSZ,
+ 0,
+ 0
};
const unsigned int hang_detect_regs_count = ARRAY_SIZE(hang_detect_regs);
@@ -847,15 +849,15 @@
for_each_child_of_node(node, child)
count++;
- info->core_param.num_freq = count;
+ info->power_param.num_freq = count;
- info->freq_tbl = kzalloc(info->core_param.num_freq *
+ info->freq_tbl = kzalloc(info->power_param.num_freq *
sizeof(struct msm_dcvs_freq_entry),
GFP_KERNEL);
if (info->freq_tbl == NULL) {
KGSL_CORE_ERR("kzalloc(%d) failed\n",
- info->core_param.num_freq *
+ info->power_param.num_freq *
sizeof(struct msm_dcvs_freq_entry));
ret = -ENOMEM;
goto err;
@@ -867,7 +869,7 @@
if (adreno_of_read_property(child, "reg", &index))
goto err;
- if (index >= info->core_param.num_freq) {
+ if (index >= info->power_param.num_freq) {
KGSL_CORE_ERR("DCVS freq entry %d is out of range\n",
index);
continue;
@@ -877,43 +879,109 @@
&info->freq_tbl[index].freq))
goto err;
- if (adreno_of_read_property(child, "qcom,idle-energy",
- &info->freq_tbl[index].idle_energy))
- info->freq_tbl[index].idle_energy = 0;
+ if (adreno_of_read_property(child, "qcom,voltage",
+ &info->freq_tbl[index].voltage))
+ info->freq_tbl[index].voltage = 0;
- if (adreno_of_read_property(child, "qcom,active-energy",
- &info->freq_tbl[index].active_energy))
- info->freq_tbl[index].active_energy = 0;
+ if (adreno_of_read_property(child, "qcom,is_trans_level",
+ &info->freq_tbl[index].is_trans_level))
+ info->freq_tbl[index].is_trans_level = 0;
+
+ if (adreno_of_read_property(child, "qcom,active-energy-offset",
+ &info->freq_tbl[index].active_energy_offset))
+ info->freq_tbl[index].active_energy_offset = 0;
+
+ if (adreno_of_read_property(child, "qcom,leakage-energy-offset",
+ &info->freq_tbl[index].leakage_energy_offset))
+ info->freq_tbl[index].leakage_energy_offset = 0;
}
- if (adreno_of_read_property(node, "qcom,core-max-time-us",
- &info->core_param.max_time_us))
+ if (adreno_of_read_property(node, "qcom,num-cores", &info->num_cores))
goto err;
- if (adreno_of_read_property(node, "qcom,algo-slack-time-us",
- &info->algo_param.slack_time_us))
+ info->sensors = kzalloc(info->num_cores *
+ sizeof(int),
+ GFP_KERNEL);
+
+ for (count = 0; count < info->num_cores; count++) {
+ if (adreno_of_read_property(node, "qcom,sensors",
+ &(info->sensors[count])))
+ goto err;
+ }
+
+ if (adreno_of_read_property(node, "qcom,core-core-type",
+ &info->core_param.core_type))
goto err;
if (adreno_of_read_property(node, "qcom,algo-disable-pc-threshold",
&info->algo_param.disable_pc_threshold))
goto err;
-
- if (adreno_of_read_property(node, "qcom,algo-ss-window-size",
- &info->algo_param.ss_window_size))
+ if (adreno_of_read_property(node, "qcom,algo-em-win-size-min-us",
+ &info->algo_param.em_win_size_min_us))
goto err;
-
- if (adreno_of_read_property(node, "qcom,algo-ss-util-pct",
- &info->algo_param.ss_util_pct))
+ if (adreno_of_read_property(node, "qcom,algo-em-win-size-max-us",
+ &info->algo_param.em_win_size_max_us))
goto err;
-
if (adreno_of_read_property(node, "qcom,algo-em-max-util-pct",
&info->algo_param.em_max_util_pct))
goto err;
-
+ if (adreno_of_read_property(node, "qcom,algo-group-id",
+ &info->algo_param.group_id))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,algo-max-freq-chg-time-us",
+ &info->algo_param.max_freq_chg_time_us))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,algo-slack-mode-dynamic",
+ &info->algo_param.slack_mode_dynamic))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,algo-slack-weight-thresh-pct",
+ &info->algo_param.slack_weight_thresh_pct))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,algo-slack-time-min-us",
+ &info->algo_param.slack_time_min_us))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,algo-slack-time-max-us",
+ &info->algo_param.slack_time_max_us))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,algo-ss-win-size-min-us",
+ &info->algo_param.ss_win_size_min_us))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,algo-ss-win-size-max-us",
+ &info->algo_param.ss_win_size_max_us))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,algo-ss-util-pct",
+ &info->algo_param.ss_util_pct))
+ goto err;
if (adreno_of_read_property(node, "qcom,algo-ss-iobusy-conv",
&info->algo_param.ss_iobusy_conv))
goto err;
+ if (adreno_of_read_property(node, "qcom,energy-active-coeff-a",
+ &info->energy_coeffs.active_coeff_a))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,energy-active-coeff-b",
+ &info->energy_coeffs.active_coeff_b))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,energy-active-coeff-c",
+ &info->energy_coeffs.active_coeff_c))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-a",
+ &info->energy_coeffs.leakage_coeff_a))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-b",
+ &info->energy_coeffs.leakage_coeff_b))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-c",
+ &info->energy_coeffs.leakage_coeff_c))
+ goto err;
+ if (adreno_of_read_property(node, "qcom,energy-leakage-coeff-d",
+ &info->energy_coeffs.leakage_coeff_d))
+ goto err;
+
+ if (adreno_of_read_property(node, "qcom,power-current-temp",
+ &info->power_param.current_temp))
+ goto err;
+
return info;
err:
@@ -1039,6 +1107,9 @@
&pdata->nap_allowed))
pdata->nap_allowed = 1;
+ pdata->strtstp_sleepwake = of_property_read_bool(pdev->dev.of_node,
+ "qcom,strtstp-sleepwake");
+
if (adreno_of_read_property(pdev->dev.of_node, "qcom,clk-map",
&pdata->clk_map))
goto err;
@@ -1233,6 +1304,12 @@
*/
hang_detect_regs[0] = adreno_dev->gpudev->reg_rbbm_status;
+ /* Add A3XX specific registers for hang detection */
+ if (adreno_is_a3xx(adreno_dev)) {
+ hang_detect_regs[6] = A3XX_RBBM_PERFCTR_SP_7_LO;
+ hang_detect_regs[7] = A3XX_RBBM_PERFCTR_SP_7_HI;
+ }
+
status = kgsl_mmu_start(device);
if (status)
goto error_clk_off;
@@ -2155,7 +2232,14 @@
if (!adreno_dev->fast_hang_detect)
return 0;
+ if (device->ftbl->isidle(device))
+ return 0;
+
for (i = 0; i < hang_detect_regs_count; i++) {
+
+ if (hang_detect_regs[i] == 0)
+ continue;
+
adreno_regread(device, hang_detect_regs[i],
&curr_reg_val[i]);
if (curr_reg_val[i] != prev_reg_val[i]) {
@@ -2179,12 +2263,15 @@
static uint io_cnt;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+ struct adreno_context *adreno_ctx = context->devctxt;
int retries = 0;
unsigned int ts_issued;
unsigned int context_id = _get_context_id(context);
unsigned int time_elapsed = 0;
unsigned int prev_reg_val[hang_detect_regs_count];
unsigned int wait;
+ unsigned int retry_ts_cmp = 0;
+ unsigned int retry_ts_cmp_msecs = KGSL_SYNCOBJ_SERVER_TIMEOUT;
memset(prev_reg_val, 0, sizeof(prev_reg_val));
@@ -2194,12 +2281,20 @@
if (msecs == KGSL_TIMEOUT_DEFAULT)
msecs = adreno_dev->wait_timeout;
+ /*
+ * With user generated ts, if this check fails perform this check
+ * again after 'retry_ts_cmp_msecs' milliseconds.
+ */
if (timestamp_cmp(timestamp, ts_issued) > 0) {
- KGSL_DRV_ERR(device, "Cannot wait for invalid ts <%d:0x%x>, "
- "last issued ts <%d:0x%x>\n",
- context_id, timestamp, context_id, ts_issued);
- status = -EINVAL;
- goto done;
+ if (!(adreno_ctx->flags & CTXT_FLAGS_USER_GENERATED_TS)) {
+ KGSL_DRV_ERR(device,
+ "Cannot wait for invalid ts <%d:0x%x>, "
+ "last issued ts <%d:0x%x>\n",
+ context_id, timestamp, context_id, ts_issued);
+ status = -EINVAL;
+ goto done;
+ } else
+ retry_ts_cmp = 1;
}
/*
@@ -2269,7 +2364,22 @@
time_elapsed += wait;
wait = KGSL_TIMEOUT_PART;
- retries++;
+ if (!retry_ts_cmp)
+ retries++;
+ else if (time_elapsed >= retry_ts_cmp_msecs) {
+ ts_issued =
+ adreno_dev->ringbuffer.timestamp[context_id];
+ if (timestamp_cmp(timestamp, ts_issued) > 0) {
+ KGSL_DRV_ERR(device,
+ "Cannot wait for user-generated ts <%d:0x%x>, "
+ "not submitted within server timeout period. "
+ "last issued ts <%d:0x%x>\n",
+ context_id, timestamp, context_id, ts_issued);
+ status = -EINVAL;
+ goto done;
+ }
+ retry_ts_cmp = 0;
+ }
} while (!msecs || time_elapsed < msecs);
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 66402fe..fd9a0c3 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -33,7 +33,7 @@
/* Flags to control command packet settings */
#define KGSL_CMD_FLAGS_NONE 0x00000000
#define KGSL_CMD_FLAGS_PMODE 0x00000001
-#define KGSL_CMD_FLAGS_DUMMY_INTR_CMD 0x00000002
+#define KGSL_CMD_FLAGS_INTERNAL_ISSUE 0x00000002
/* Command identifiers */
#define KGSL_CONTEXT_TO_MEM_IDENTIFIER 0x2EADBEEF
@@ -179,6 +179,8 @@
unsigned int value);
int adreno_dump(struct kgsl_device *device, int manual);
+unsigned int adreno_a3xx_rbbm_clock_ctl_default(struct adreno_device
+ *adreno_dev);
struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
unsigned int pt_base,
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 2388fff..8de2c70 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1749,9 +1749,6 @@
if (status & (CP_INT_CNTL__IB1_INT_MASK | CP_INT_CNTL__RB_INT_MASK)) {
queue_work(device->work_queue, &device->ts_expired_ws);
wake_up_interruptible_all(&device->wait_queue);
- atomic_notifier_call_chain(&(device->ts_notifier_list),
- device->id,
- NULL);
}
}
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 7bf928f..4c7534c 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -433,6 +433,19 @@
tmp_ctx.cmd = cmd;
}
+unsigned int adreno_a3xx_rbbm_clock_ctl_default(struct adreno_device
+ *adreno_dev)
+{
+ if (adreno_is_a305(adreno_dev))
+ return A305_RBBM_CLOCK_CTL_DEFAULT;
+ else if (adreno_is_a320(adreno_dev))
+ return A320_RBBM_CLOCK_CTL_DEFAULT;
+ else if (adreno_is_a330(adreno_dev))
+ return A330_RBBM_CLOCK_CTL_DEFAULT;
+
+ BUG_ON(1);
+}
+
/* Copy GMEM contents to system memory shadow. */
static unsigned int *build_gmem2sys_cmds(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt,
@@ -442,7 +455,7 @@
unsigned int *start = cmds;
*cmds++ = cp_type0_packet(A3XX_RBBM_CLOCK_CTL, 1);
- *cmds++ = A3XX_RBBM_CLOCK_CTL_DEFAULT;
+ *cmds++ = adreno_a3xx_rbbm_clock_ctl_default(adreno_dev);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
*cmds++ = CP_REG(A3XX_RB_MODE_CONTROL);
@@ -1238,7 +1251,7 @@
unsigned int *start = cmds;
*cmds++ = cp_type0_packet(A3XX_RBBM_CLOCK_CTL, 1);
- *cmds++ = A3XX_RBBM_CLOCK_CTL_DEFAULT;
+ *cmds++ = adreno_a3xx_rbbm_clock_ctl_default(adreno_dev);
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5);
*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
@@ -2587,9 +2600,6 @@
/* Schedule work to free mem and issue ibs */
queue_work(device->work_queue, &device->ts_expired_ws);
-
- atomic_notifier_call_chain(&device->ts_notifier_list,
- device->id, NULL);
}
#define A3XX_IRQ_CALLBACK(_c) { .func = _c }
@@ -2829,13 +2839,28 @@
/* Enable Clock gating */
adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL,
- A3XX_RBBM_CLOCK_CTL_DEFAULT);
+ adreno_a3xx_rbbm_clock_ctl_default(adreno_dev));
+
+ if (adreno_is_a330(adreno_dev))
+ adreno_regwrite(device, A3XX_RBBM_GPR0_CTL,
+ A330_RBBM_GPR0_CTL_DEFAULT);
/* Set the OCMEM base address for A330 */
if (adreno_is_a330(adreno_dev)) {
adreno_regwrite(device, A3XX_RB_GMEM_BASE_ADDR,
(unsigned int)(adreno_dev->ocmem_base >> 14));
}
+
+ /* Turn on performance counters */
+ adreno_regwrite(device, A3XX_RBBM_PERFCTR_CTL, 0x01);
+
+ /*
+ * Set SP perfcounter 7 to count SP_FS_FULL_ALU_INSTRUCTIONS
+ * we will use this to augment our hang detection
+ */
+
+ adreno_regwrite(device, A3XX_SP_PERFCOUNTER7_SELECT,
+ SP_FS_FULL_ALU_INSTRUCTIONS);
}
/* Defined in adreno_a3xx_snapshot.c */
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index d49fc23..a410445 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -383,7 +383,7 @@
/* Enable Clock gating */
adreno_regwrite(device, A3XX_RBBM_CLOCK_CTL,
- A3XX_RBBM_CLOCK_CTL_DEFAULT);
+ adreno_a3xx_rbbm_clock_ctl_default(adreno_dev));
return snapshot;
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 7cbc7a8..a107a27 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -169,6 +169,14 @@
if (flags & KGSL_CONTEXT_PER_CONTEXT_TS)
drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
+ if (flags & KGSL_CONTEXT_USER_GENERATED_TS) {
+ if (!(flags & KGSL_CONTEXT_PER_CONTEXT_TS)) {
+ ret = -EINVAL;
+ goto err;
+ }
+ drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
+ }
+
ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
if (ret)
goto err;
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 034d6e9..58e4791 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -48,6 +48,8 @@
#define CTXT_FLAGS_GPU_HANG_RECOVERED BIT(12)
/* Context is being destroyed so dont save it */
#define CTXT_FLAGS_BEING_DESTROYED BIT(13)
+/* User mode generated timestamps enabled */
+#define CTXT_FLAGS_USER_GENERATED_TS BIT(14)
struct kgsl_device;
struct adreno_device;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 1ff219b..da9daf7 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -487,11 +487,10 @@
adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
struct adreno_context *context,
unsigned int flags, unsigned int *cmds,
- int sizedwords)
+ int sizedwords, uint32_t timestamp)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(rb->device);
unsigned int *ringcmds;
- unsigned int timestamp;
unsigned int total_sizedwords = sizedwords;
unsigned int i;
unsigned int rcmd_gpu;
@@ -503,22 +502,41 @@
* support, we must use the global timestamp since issueibcmds
* will be returning that one.
*/
- if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
+ if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS)
context_id = context->id;
+ if ((context->flags & CTXT_FLAGS_USER_GENERATED_TS) &&
+ (!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))) {
+ if (timestamp_cmp(rb->timestamp[context_id],
+ timestamp) >= 0) {
+ KGSL_DRV_ERR(rb->device,
+ "Invalid user generated ts <%d:0x%x>, "
+ "less than last issued ts <%d:0x%x>\n",
+ context_id, timestamp, context_id,
+ rb->timestamp[context_id]);
+ return -ERANGE;
+ }
+ }
+
/* reserve space to temporarily turn off protected mode
* error checking if needed
*/
total_sizedwords += flags & KGSL_CMD_FLAGS_PMODE ? 4 : 0;
/* 2 dwords to store the start of command sequence */
total_sizedwords += 2;
- total_sizedwords += context ? 7 : 0;
+ /*
+ * Add CP_COND_EXEC commands to generate CP_INTERRUPT only
+ * for submissions from userspace.
+ */
+ total_sizedwords += (context &&
+ !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) ? 7 : 0;
if (adreno_is_a3xx(adreno_dev))
total_sizedwords += 7;
total_sizedwords += 2; /* scratchpad ts for recovery */
- if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
+ if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS &&
+ !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
total_sizedwords += 3; /* sop timestamp */
total_sizedwords += 4; /* eop timestamp */
total_sizedwords += 3; /* global timestamp without cache
@@ -564,10 +582,13 @@
/* always increment the global timestamp. once. */
rb->timestamp[KGSL_MEMSTORE_GLOBAL]++;
- if (context && !(flags & KGSL_CMD_FLAGS_DUMMY_INTR_CMD)) {
+ /* Do not update context's timestamp for internal submissions */
+ if (context && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
if (context_id == KGSL_MEMSTORE_GLOBAL)
rb->timestamp[context->id] =
rb->timestamp[KGSL_MEMSTORE_GLOBAL];
+ else if (context->flags & CTXT_FLAGS_USER_GENERATED_TS)
+ rb->timestamp[context_id] = timestamp;
else
rb->timestamp[context_id]++;
}
@@ -591,7 +612,8 @@
GSL_RB_WRITE(ringcmds, rcmd_gpu, 0x00);
}
- if (context->flags & CTXT_FLAGS_PER_CONTEXT_TS) {
+ if (context && context->flags & CTXT_FLAGS_PER_CONTEXT_TS
+ && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
/* start-of-pipeline timestamp */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_MEM_WRITE, 2));
@@ -619,11 +641,13 @@
cp_type3_packet(CP_EVENT_WRITE, 3));
GSL_RB_WRITE(ringcmds, rcmd_gpu, CACHE_FLUSH_TS);
GSL_RB_WRITE(ringcmds, rcmd_gpu, (gpuaddr +
- KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)));
- GSL_RB_WRITE(ringcmds, rcmd_gpu, rb->timestamp[context_id]);
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ eoptimestamp)));
+ GSL_RB_WRITE(ringcmds, rcmd_gpu,
+ rb->timestamp[KGSL_MEMSTORE_GLOBAL]);
}
- if (context) {
+ if (context && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
/* Conditional execution based on memory values */
GSL_RB_WRITE(ringcmds, rcmd_gpu,
cp_type3_packet(CP_COND_EXEC, 4));
@@ -675,8 +699,8 @@
device->state & KGSL_STATE_HUNG)
return;
- adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_DUMMY_INTR_CMD,
- cmds, sizedwords);
+ adreno_ringbuffer_addcmds(rb, a_ctxt, KGSL_CMD_FLAGS_INTERNAL_ISSUE,
+ cmds, sizedwords, 0);
}
unsigned int
@@ -692,7 +716,11 @@
if (device->state & KGSL_STATE_HUNG)
return kgsl_readtimestamp(device, KGSL_MEMSTORE_GLOBAL,
KGSL_TIMESTAMP_RETIRED);
- return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds, sizedwords);
+
+ flags |= KGSL_CMD_FLAGS_INTERNAL_ISSUE;
+
+ return adreno_ringbuffer_addcmds(rb, drawctxt, flags, cmds,
+ sizedwords, 0);
}
static bool _parse_ibs(struct kgsl_device_private *dev_priv, uint gpuaddr,
@@ -902,6 +930,7 @@
unsigned int i;
struct adreno_context *drawctxt;
unsigned int start_index = 0;
+ int ret;
if (device->state & KGSL_STATE_HUNG)
return -EBUSY;
@@ -948,9 +977,15 @@
if (unlikely(adreno_dev->ib_check_level >= 1 &&
!_parse_ibs(dev_priv, ibdesc[i].gpuaddr,
ibdesc[i].sizedwords))) {
- kfree(link);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
+
+ if (ibdesc[i].sizedwords == 0) {
+ ret = -EINVAL;
+ goto done;
+ }
+
*cmds++ = CP_HDR_INDIRECT_BUFFER_PFD;
*cmds++ = ibdesc[i].gpuaddr;
*cmds++ = ibdesc[i].sizedwords;
@@ -966,13 +1001,13 @@
adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
*timestamp = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
- drawctxt, 0,
- &link[0], (cmds - link));
+ drawctxt,
+ 0,
+ &link[0], (cmds - link), *timestamp);
KGSL_CMD_INFO(device, "<%d:0x%x> g %08x numibs %d\n",
context->id, *timestamp, (unsigned int)ibdesc, numibs);
- kfree(link);
#ifdef CONFIG_MSM_KGSL_CFF_DUMP
/*
@@ -982,13 +1017,16 @@
*/
adreno_idle(device);
#endif
+
/* If context hung and recovered then return error so that the
* application may handle it */
- if (drawctxt->flags & CTXT_FLAGS_GPU_HANG_RECOVERED)
- return -EDEADLK;
- else
- return 0;
+ ret = (drawctxt->flags & CTXT_FLAGS_GPU_HANG_RECOVERED) ?
+ -EDEADLK : 0;
+
+done:
+ kfree(link);
+ return ret;
}
static int _find_start_of_cmd_seq(struct adreno_ringbuffer *rb,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5904abb..afe384b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -357,7 +357,7 @@
/* MAX - 1, there is one memdesc in memstore for device info */
if (id >= KGSL_MEMSTORE_MAX) {
- KGSL_DRV_ERR(dev_priv->device, "cannot have more than %d "
+ KGSL_DRV_INFO(dev_priv->device, "cannot have more than %d "
"ctxts due to memstore limitation\n",
KGSL_MEMSTORE_MAX);
idr_remove(&dev_priv->device->context_idr, id);
@@ -507,24 +507,6 @@
return ret;
}
-int kgsl_register_ts_notifier(struct kgsl_device *device,
- struct notifier_block *nb)
-{
- BUG_ON(device == NULL);
- return atomic_notifier_chain_register(&device->ts_notifier_list,
- nb);
-}
-EXPORT_SYMBOL(kgsl_register_ts_notifier);
-
-int kgsl_unregister_ts_notifier(struct kgsl_device *device,
- struct notifier_block *nb)
-{
- BUG_ON(device == NULL);
- return atomic_notifier_chain_unregister(&device->ts_notifier_list,
- nb);
-}
-EXPORT_SYMBOL(kgsl_unregister_ts_notifier);
-
int kgsl_check_timestamp(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp)
{
@@ -740,6 +722,7 @@
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);
@@ -762,6 +745,7 @@
goto unlock;
kgsl_process_uninit_sysfs(private);
+ debugfs_remove_recursive(private->debug_root);
list_del(&private->list);
@@ -1080,11 +1064,8 @@
int result;
context = kgsl_find_context(dev_priv, param->context_id);
- if (context == NULL) {
- KGSL_DRV_ERR(dev_priv->device, "invalid context_id %d\n",
- param->context_id);
+ if (context == NULL)
return -EINVAL;
- }
/*
* A reference count is needed here, because waittimestamp may
* block with the device mutex unlocked and userspace could
@@ -1101,6 +1082,7 @@
unsigned int cmd, void *data)
{
int result = 0;
+ int i = 0;
struct kgsl_ringbuffer_issueibcmds *param = data;
struct kgsl_ibdesc *ibdesc;
struct kgsl_context *context;
@@ -1108,17 +1090,11 @@
context = kgsl_find_context(dev_priv, param->drawctxt_id);
if (context == NULL) {
result = -EINVAL;
- KGSL_DRV_ERR(dev_priv->device,
- "invalid context_id %d\n",
- param->drawctxt_id);
goto done;
}
if (param->flags & KGSL_CONTEXT_SUBMIT_IB_LIST) {
if (!param->numibs) {
- KGSL_DRV_ERR(dev_priv->device,
- "Invalid numibs as parameter: %d\n",
- param->numibs);
result = -EINVAL;
goto done;
}
@@ -1129,9 +1105,6 @@
*/
if (param->numibs > 10000) {
- KGSL_DRV_ERR(dev_priv->device,
- "Too many IBs submitted. count: %d max 10000\n",
- param->numibs);
result = -EINVAL;
goto done;
}
@@ -1171,6 +1144,16 @@
param->numibs = 1;
}
+ for (i = 0; i < param->numibs; i++) {
+ if (!kgsl_mmu_gpuaddr_in_range(ibdesc[i].gpuaddr)) {
+ result = -ERANGE;
+ KGSL_DRV_ERR(dev_priv->device,
+ "invalid ib base GPU virtual addr %x\n",
+ ibdesc[i].gpuaddr);
+ goto free_ibdesc;
+ }
+ }
+
result = dev_priv->device->ftbl->issueibcmds(dev_priv,
context,
ibdesc,
@@ -1218,11 +1201,8 @@
struct kgsl_context *context;
context = kgsl_find_context(dev_priv, param->context_id);
- if (context == NULL) {
- KGSL_DRV_ERR(dev_priv->device, "invalid context_id %d\n",
- param->context_id);
+ if (context == NULL)
return -EINVAL;
- }
return _cmdstream_readtimestamp(dev_priv, context,
param->type, ¶m->timestamp);
@@ -1287,11 +1267,8 @@
struct kgsl_context *context;
context = kgsl_find_context(dev_priv, param->context_id);
- if (context == NULL) {
- KGSL_DRV_ERR(dev_priv->device,
- "invalid drawctxt context_id %d\n", param->context_id);
+ if (context == NULL)
return -EINVAL;
- }
return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
context, param->timestamp, param->type);
@@ -1504,6 +1481,8 @@
return -ENOMEM;
memdesc->sglen = sglen;
+ memdesc->sglen_alloc = sglen;
+
sg_init_table(memdesc->sg, sglen);
spin_lock(¤t->mm->page_table_lock);
@@ -1668,11 +1647,16 @@
#endif
static int kgsl_setup_ion(struct kgsl_mem_entry *entry,
- struct kgsl_pagetable *pagetable, int fd)
+ struct kgsl_pagetable *pagetable, void *data)
{
struct ion_handle *handle;
struct scatterlist *s;
struct sg_table *sg_table;
+ struct kgsl_map_user_mem *param = data;
+ int fd = param->fd;
+
+ if (!param->len)
+ return -EINVAL;
if (IS_ERR_OR_NULL(kgsl_ion_client))
return -ENODEV;
@@ -1777,8 +1761,7 @@
entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
break;
case KGSL_USER_MEM_TYPE_ION:
- result = kgsl_setup_ion(entry, private->pagetable,
- param->fd);
+ result = kgsl_setup_ion(entry, private->pagetable, data);
break;
default:
KGSL_CORE_ERR("Invalid memory type: %x\n", memtype);
@@ -1788,6 +1771,13 @@
if (result)
goto error;
+ entry->memdesc.priv |= param->flags & KGSL_MEMTYPE_MASK;
+
+ if (entry->memdesc.size >= SZ_1M)
+ entry->memdesc.priv |= ilog2(SZ_1M) << KGSL_MEMALIGN_SHIFT;
+ else if (entry->memdesc.size >= SZ_64K)
+ entry->memdesc.priv |= ilog2(SZ_64K) << KGSL_MEMALIGN_SHIFT;
+
result = kgsl_mmu_map(private->pagetable,
&entry->memdesc,
GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 416eda9..2861117 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -135,7 +135,8 @@
unsigned int size;
unsigned int priv;
struct scatterlist *sg;
- unsigned int sglen;
+ unsigned int sglen; /* Active entries in the sglist */
+ unsigned int sglen_alloc; /* Allocated entries in the sglist */
struct kgsl_memdesc_ops *ops;
int flags;
};
@@ -182,6 +183,8 @@
struct kgsl_process_private *private, unsigned int gpuaddr,
size_t size);
+void kgsl_get_memory_usage(char *str, size_t len, unsigned int memflags);
+
int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
void *owner);
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 545d2b3..b49c260 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -16,6 +16,7 @@
#include "kgsl.h"
#include "kgsl_device.h"
+#include "kgsl_sharedmem.h"
/*default log levels is error for everything*/
#define KGSL_LOG_LEVEL_DEFAULT 3
@@ -23,6 +24,7 @@
struct dentry *kgsl_debugfs_dir;
static struct dentry *pm_d_debugfs;
+struct dentry *proc_d_debugfs;
static int pm_dump_set(void *data, u64 val)
{
@@ -146,9 +148,90 @@
}
+static const char * const memtype_strings[] = {
+ "gpumem",
+ "pmem",
+ "ashmem",
+ "usermap",
+ "ion",
+};
+
+static const char *memtype_str(int memtype)
+{
+ if (memtype < ARRAY_SIZE(memtype_strings))
+ return memtype_strings[memtype];
+ return "unknown";
+}
+
+static int process_mem_print(struct seq_file *s, void *unused)
+{
+ struct kgsl_mem_entry *entry;
+ struct rb_node *node;
+ struct kgsl_process_private *private = s->private;
+ char flags[4];
+ char usage[16];
+ unsigned int align;
+
+ spin_lock(&private->mem_lock);
+ seq_printf(s, "%8s %8s %5s %10s %16s %5s\n",
+ "gpuaddr", "size", "flags", "type", "usage", "sglen");
+ for (node = rb_first(&private->mem_rb); node; node = rb_next(node)) {
+ struct kgsl_memdesc *m;
+
+ entry = rb_entry(node, struct kgsl_mem_entry, node);
+ m = &entry->memdesc;
+
+ flags[0] = m->priv & KGSL_MEMFLAGS_GLOBAL ? 'g' : '-';
+ flags[1] = m->priv & KGSL_MEMFLAGS_GPUREADONLY ? 'r' : '-';
+
+ align = (m->priv & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
+ if (align >= ilog2(SZ_1M))
+ flags[2] = 'L';
+ else if (align >= ilog2(SZ_64K))
+ flags[2] = 'l';
+ else
+ flags[2] = '-';
+
+ flags[3] = '\0';
+
+ kgsl_get_memory_usage(usage, sizeof(usage), m->priv);
+
+ seq_printf(s, "%08x %8d %5s %10s %16s %5d\n",
+ m->gpuaddr, m->size, flags,
+ memtype_str(entry->memtype), usage, m->sglen);
+ }
+ spin_unlock(&private->mem_lock);
+ return 0;
+}
+
+static int process_mem_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, process_mem_print, inode->i_private);
+}
+
+static const struct file_operations process_mem_fops = {
+ .open = process_mem_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void
+kgsl_process_init_debugfs(struct kgsl_process_private *private)
+{
+ unsigned char name[16];
+
+ snprintf(name, sizeof(name), "%d", private->pid);
+
+ private->debug_root = debugfs_create_dir(name, proc_d_debugfs);
+ debugfs_create_file("mem", 0400, private->debug_root, private,
+ &process_mem_fops);
+}
+
void kgsl_core_debugfs_init(void)
{
kgsl_debugfs_dir = debugfs_create_dir("kgsl", 0);
+ proc_d_debugfs = debugfs_create_dir("proc", kgsl_debugfs_dir);
}
void kgsl_core_debugfs_close(void)
diff --git a/drivers/gpu/msm/kgsl_debugfs.h b/drivers/gpu/msm/kgsl_debugfs.h
index 5e10988..898c4e9 100644
--- a/drivers/gpu/msm/kgsl_debugfs.h
+++ b/drivers/gpu/msm/kgsl_debugfs.h
@@ -15,6 +15,7 @@
#define _KGSL_DEBUGFS_H
struct kgsl_device;
+struct kgsl_process_private;
#ifdef CONFIG_DEBUG_FS
void kgsl_core_debugfs_init(void);
@@ -28,11 +29,16 @@
return kgsl_debugfs_dir;
}
+int kgsl_process_init_debugfs(struct kgsl_process_private *);
#else
static inline void kgsl_core_debugfs_init(void) { }
static inline void kgsl_device_debugfs_init(struct kgsl_device *device) { }
static inline void kgsl_core_debugfs_close(void) { }
static inline struct dentry *kgsl_get_debugfs_dir(void) { return NULL; }
+static inline int kgsl_process_init_debugfs(struct kgsl_process_private *)
+{
+ return 0;
+}
#endif
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2ca3a4f..4394118 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -155,7 +155,6 @@
struct kgsl_pwrctrl pwrctrl;
int open_count;
- struct atomic_notifier_head ts_notifier_list;
struct mutex mutex;
uint32_t state;
uint32_t requested_state;
@@ -210,7 +209,6 @@
.hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
.suspend_gate = COMPLETION_INITIALIZER((_dev).suspend_gate),\
.recovery_gate = COMPLETION_INITIALIZER((_dev).recovery_gate),\
- .ts_notifier_list = ATOMIC_NOTIFIER_INIT((_dev).ts_notifier_list),\
.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
kgsl_idle_check),\
.ts_expired_ws = __WORK_INITIALIZER((_dev).ts_expired_ws,\
@@ -253,6 +251,7 @@
struct kgsl_pagetable *pagetable;
struct list_head list;
struct kobject kobj;
+ struct dentry *debug_root;
struct {
unsigned int cur;
@@ -374,12 +373,6 @@
int kgsl_check_timestamp(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp);
-int kgsl_register_ts_notifier(struct kgsl_device *device,
- struct notifier_block *nb);
-
-int kgsl_unregister_ts_notifier(struct kgsl_device *device,
- struct notifier_block *nb);
-
int kgsl_device_platform_probe(struct kgsl_device *device);
void kgsl_device_platform_remove(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 0e1e100..dbb88ee 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -606,6 +606,7 @@
int ret;
struct gen_pool *pool;
int size;
+ int page_align = ilog2(PAGE_SIZE);
if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
if (memdesc->sglen == 1) {
@@ -630,7 +631,17 @@
/* Allocate from kgsl pool if it exists for global mappings */
pool = _get_pool(pagetable, memdesc->priv);
- memdesc->gpuaddr = gen_pool_alloc(pool, size);
+ /* Allocate aligned virtual addresses for iommu. This allows
+ * more efficient pagetable entries if the physical memory
+ * is also aligned. Don't do this for GPUMMU, because
+ * the address space is so small.
+ */
+ if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype() &&
+ (memdesc->priv & KGSL_MEMALIGN_MASK)) {
+ page_align = (memdesc->priv & KGSL_MEMALIGN_MASK)
+ >> KGSL_MEMALIGN_SHIFT;
+ }
+ memdesc->gpuaddr = gen_pool_alloc_aligned(pool, size, page_align);
if (memdesc->gpuaddr == 0) {
KGSL_CORE_ERR("gen_pool_alloc(%d) failed from pool: %s\n",
size,
@@ -729,7 +740,8 @@
return 0;
gpuaddr = memdesc->gpuaddr;
- memdesc->priv |= KGSL_MEMFLAGS_GLOBAL;
+ memdesc->priv |= KGSL_MEMFLAGS_GLOBAL
+ | (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
result = kgsl_mmu_map(pagetable, memdesc, protflags);
if (result)
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index 879b381..b302bee 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,21 +20,21 @@
#include "kgsl_trace.h"
struct msm_priv {
- struct kgsl_device *device;
- int enabled;
- int handle;
- unsigned int cur_freq;
- struct msm_dcvs_idle idle_source;
- struct msm_dcvs_freq freq_sink;
- struct msm_dcvs_core_info *core_info;
- int gpu_busy;
+ struct kgsl_device *device;
+ int enabled;
+ unsigned int cur_freq;
+ struct msm_dcvs_core_info *core_info;
+ int gpu_busy;
+ int dcvs_core_id;
};
-static int msm_idle_enable(struct msm_dcvs_idle *self,
- enum msm_core_control_event event)
+/* reference to be used in idle and freq callbacks */
+static struct msm_priv *the_msm_priv;
+
+static int msm_idle_enable(int type_core_num,
+ enum msm_core_control_event event)
{
- struct msm_priv *priv = container_of(self, struct msm_priv,
- idle_source);
+ struct msm_priv *priv = the_msm_priv;
switch (event) {
case MSM_DCVS_ENABLE_IDLE_PULSE:
@@ -53,12 +53,10 @@
/* Set the requested frequency if it is within 5MHz (delta) of a
* supported frequency.
*/
-static int msm_set_freq(struct msm_dcvs_freq *self,
- unsigned int freq)
+static int msm_set_freq(int core_num, unsigned int freq)
{
int i, delta = 5000000;
- struct msm_priv *priv = container_of(self, struct msm_priv,
- freq_sink);
+ struct msm_priv *priv = the_msm_priv;
struct kgsl_device *device = priv->device;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
@@ -79,10 +77,10 @@
return priv->cur_freq / 1000;
}
-static unsigned int msm_get_freq(struct msm_dcvs_freq *self)
+static unsigned int msm_get_freq(int core_num)
{
- struct msm_priv *priv = container_of(self, struct msm_priv,
- freq_sink);
+ struct msm_priv *priv = the_msm_priv;
+
/* return current frequency in kHz */
return priv->cur_freq / 1000;
}
@@ -92,7 +90,7 @@
{
struct msm_priv *priv = pwrscale->priv;
if (priv->enabled && !priv->gpu_busy) {
- msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_EXIT, 0);
+ msm_dcvs_idle(priv->dcvs_core_id, MSM_DCVS_IDLE_EXIT, 0);
trace_kgsl_mpdcvs(device, 1);
priv->gpu_busy = 1;
}
@@ -106,7 +104,8 @@
if (priv->enabled && priv->gpu_busy)
if (device->ftbl->isidle(device)) {
- msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+ msm_dcvs_idle(priv->dcvs_core_id,
+ MSM_DCVS_IDLE_ENTER, 0);
trace_kgsl_mpdcvs(device, 0);
priv->gpu_busy = 0;
}
@@ -119,7 +118,7 @@
struct msm_priv *priv = pwrscale->priv;
if (priv->enabled && priv->gpu_busy) {
- msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+ msm_dcvs_idle(priv->dcvs_core_id, MSM_DCVS_IDLE_ENTER, 0);
trace_kgsl_mpdcvs(device, 0);
priv->gpu_busy = 0;
}
@@ -127,13 +126,14 @@
return;
}
-static void msm_remove_io_fraction(struct kgsl_device *device)
+static void msm_set_io_fraction(struct kgsl_device *device,
+ unsigned int value)
{
int i;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
for (i = 0; i < pwr->num_pwrlevels; i++)
- pwr->pwrlevels[i].io_fraction = 100;
+ pwr->pwrlevels[i].io_fraction = value;
}
@@ -154,60 +154,58 @@
{
struct msm_priv *priv;
struct msm_dcvs_freq_entry *tbl;
- int i, ret, low_level;
+ int i, ret = -EINVAL, low_level;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct platform_device *pdev =
container_of(device->parentdev, struct platform_device, dev);
struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
- priv = pwrscale->priv = kzalloc(sizeof(struct msm_priv),
- GFP_KERNEL);
- if (pwrscale->priv == NULL)
- return -ENOMEM;
+ if (the_msm_priv) {
+ priv = pwrscale->priv = the_msm_priv;
+ } else {
+ priv = pwrscale->priv = kzalloc(sizeof(struct msm_priv),
+ GFP_KERNEL);
+ if (pwrscale->priv == NULL)
+ return -ENOMEM;
- priv->core_info = pdata->core_info;
- tbl = priv->core_info->freq_tbl;
- /* Fill in frequency table from low to high, reversing order. */
- low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
- for (i = 0; i <= low_level; i++)
- tbl[i].freq =
- pwr->pwrlevels[low_level - i].gpu_freq / 1000;
- ret = msm_dcvs_register_core(device->name, 0, priv->core_info);
- if (ret) {
- KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
- goto err;
+ priv->core_info = pdata->core_info;
+ tbl = priv->core_info->freq_tbl;
+ /* Fill in frequency table from low to high, reversing order. */
+ low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
+ for (i = 0; i <= low_level; i++)
+ tbl[i].freq =
+ pwr->pwrlevels[low_level - i].gpu_freq / 1000;
+ priv->dcvs_core_id =
+ msm_dcvs_register_core(MSM_DCVS_CORE_TYPE_GPU,
+ 0,
+ priv->core_info,
+ msm_set_freq, msm_get_freq, msm_idle_enable,
+ priv->core_info->sensors[0]);
+ if (priv->dcvs_core_id < 0) {
+ KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
+ goto err;
+ }
+ the_msm_priv = priv;
}
-
priv->device = device;
- priv->idle_source.enable = msm_idle_enable;
- priv->idle_source.core_name = device->name;
- priv->handle = msm_dcvs_idle_source_register(&priv->idle_source);
- if (priv->handle < 0) {
- ret = priv->handle;
- KGSL_PWR_ERR(device, "msm_dcvs_idle_source_register failed\n");
- goto err;
- }
-
- priv->freq_sink.core_name = device->name;
- priv->freq_sink.set_frequency = msm_set_freq;
- priv->freq_sink.get_frequency = msm_get_freq;
- ret = msm_dcvs_freq_sink_register(&priv->freq_sink);
+ ret = msm_dcvs_freq_sink_start(priv->dcvs_core_id);
if (ret >= 0) {
if (device->ftbl->isidle(device)) {
priv->gpu_busy = 0;
- msm_dcvs_idle(priv->handle, MSM_DCVS_IDLE_ENTER, 0);
+ msm_dcvs_idle(priv->dcvs_core_id,
+ MSM_DCVS_IDLE_ENTER, 0);
} else {
priv->gpu_busy = 1;
}
- msm_remove_io_fraction(device);
+ msm_set_io_fraction(device, 0);
return 0;
}
KGSL_PWR_ERR(device, "msm_dcvs_freq_sink_register failed\n");
- msm_dcvs_idle_source_unregister(&priv->idle_source);
err:
- kfree(pwrscale->priv);
+ if (!the_msm_priv)
+ kfree(pwrscale->priv);
pwrscale->priv = NULL;
return ret;
@@ -220,9 +218,7 @@
if (pwrscale->priv == NULL)
return;
- msm_dcvs_idle_source_unregister(&priv->idle_source);
- msm_dcvs_freq_sink_unregister(&priv->freq_sink);
- kfree(pwrscale->priv);
+ msm_dcvs_freq_sink_stop(priv->dcvs_core_id);
pwrscale->priv = NULL;
msm_restore_io_fraction(device);
}
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index c2ce5c7..77617ba 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -317,21 +317,42 @@
struct vm_area_struct *vma,
struct vm_fault *vmf)
{
- unsigned long offset;
- struct page *page;
- int i;
+ int i, pgoff;
+ struct scatterlist *s = memdesc->sg;
+ unsigned int offset;
- offset = (unsigned long) vmf->virtual_address - vma->vm_start;
+ offset = ((unsigned long) vmf->virtual_address - vma->vm_start);
- i = offset >> PAGE_SHIFT;
- page = sg_page(&memdesc->sg[i]);
- if (page == NULL)
+ if (offset >= memdesc->size)
return VM_FAULT_SIGBUS;
- get_page(page);
+ pgoff = offset >> PAGE_SHIFT;
- vmf->page = page;
- return 0;
+ /*
+ * The sglist might be comprised of mixed blocks of memory depending
+ * on how many 64K pages were allocated. This means we have to do math
+ * to find the actual 4K page to map in user space
+ */
+
+ for (i = 0; i < memdesc->sglen; i++) {
+ int npages = s->length >> PAGE_SHIFT;
+
+ if (pgoff < npages) {
+ struct page *page = sg_page(s);
+
+ page = nth_page(page, pgoff);
+
+ get_page(page);
+ vmf->page = page;
+
+ return 0;
+ }
+
+ pgoff -= npages;
+ s = sg_next(s);
+ }
+
+ return VM_FAULT_SIGBUS;
}
static int kgsl_page_alloc_vmflags(struct kgsl_memdesc *memdesc)
@@ -357,7 +378,7 @@
}
if (memdesc->sg)
for_each_sg(memdesc->sg, sg, sglen, i)
- __free_page(sg_page(sg));
+ __free_pages(sg_page(sg), get_order(sg->length));
}
static int kgsl_contiguous_vmflags(struct kgsl_memdesc *memdesc)
@@ -379,23 +400,32 @@
pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
struct page **pages = NULL;
struct scatterlist *sg;
+ int npages = PAGE_ALIGN(memdesc->size) >> PAGE_SHIFT;
int sglen = memdesc->sglen;
- int i;
+ int i, count = 0;
/* Don't map the guard page if it exists */
if (memdesc->flags & KGSL_MEMDESC_GUARD_PAGE)
sglen--;
/* create a list of pages to call vmap */
- pages = vmalloc(sglen * sizeof(struct page *));
+ pages = vmalloc(npages * sizeof(struct page *));
if (!pages) {
KGSL_CORE_ERR("vmalloc(%d) failed\n",
- sglen * sizeof(struct page *));
+ npages * sizeof(struct page *));
return -ENOMEM;
}
- for_each_sg(memdesc->sg, sg, sglen, i)
- pages[i] = sg_page(sg);
- memdesc->hostptr = vmap(pages, sglen,
+
+ for_each_sg(memdesc->sg, sg, sglen, i) {
+ struct page *page = sg_page(sg);
+ int j;
+
+ for (j = 0; j < sg->length >> PAGE_SHIFT; j++)
+ pages[count++] = page++;
+ }
+
+
+ memdesc->hostptr = vmap(pages, count,
VM_IOREMAP, page_prot);
KGSL_STATS_ADD(memdesc->size, kgsl_driver.stats.vmalloc,
kgsl_driver.stats.vmalloc_max);
@@ -503,14 +533,15 @@
static int
_kgsl_sharedmem_page_alloc(struct kgsl_memdesc *memdesc,
struct kgsl_pagetable *pagetable,
- size_t size, unsigned int protflags)
+ size_t size, unsigned int flags, unsigned int protflags)
{
- int i, order, ret = 0;
- int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
+ int pcount = 0, order, ret = 0;
+ int j, len, page_size, sglen_alloc, sglen = 0;
struct page **pages = NULL;
pgprot_t page_prot = pgprot_writecombine(PAGE_KERNEL);
void *ptr;
struct sysinfo si;
+ unsigned int align;
/*
* Get the current memory information to be used in deciding if we
@@ -530,24 +561,36 @@
if (size >= ((si.freeram << PAGE_SHIFT) - SZ_32M))
return -ENOMEM;
+ align = (flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT;
+
+ page_size = (align >= ilog2(SZ_64K) && size >= SZ_64K)
+ ? SZ_64K : PAGE_SIZE;
+
+ /*
+ * There needs to be enough room in the sg structure to be able to
+ * service the allocation entirely with PAGE_SIZE sized chunks
+ */
+
+ sglen_alloc = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
/*
* Add guard page to the end of the allocation when the
* IOMMU is in use.
*/
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
- sglen++;
+ sglen_alloc++;
memdesc->size = size;
memdesc->pagetable = pagetable;
- memdesc->priv = KGSL_MEMFLAGS_CACHED;
+ memdesc->priv |= (flags & KGSL_MEMALIGN_MASK);
memdesc->ops = &kgsl_page_alloc_ops;
- memdesc->sg = kgsl_sg_alloc(sglen);
+ memdesc->sg = kgsl_sg_alloc(sglen_alloc);
if (memdesc->sg == NULL) {
KGSL_CORE_ERR("vmalloc(%d) failed\n",
- sglen * sizeof(struct scatterlist));
+ sglen_alloc * sizeof(struct scatterlist));
ret = -ENOMEM;
goto done;
}
@@ -559,38 +602,52 @@
* two pages; well within the acceptable limits for using kmalloc.
*/
- pages = kmalloc(sglen * sizeof(struct page *), GFP_KERNEL);
+ pages = kmalloc(sglen_alloc * sizeof(struct page *), GFP_KERNEL);
if (pages == NULL) {
KGSL_CORE_ERR("kmalloc (%d) failed\n",
- sglen * sizeof(struct page *));
+ sglen_alloc * sizeof(struct page *));
ret = -ENOMEM;
goto done;
}
kmemleak_not_leak(memdesc->sg);
- memdesc->sglen = sglen;
- sg_init_table(memdesc->sg, sglen);
+ memdesc->sglen_alloc = sglen_alloc;
+ sg_init_table(memdesc->sg, sglen_alloc);
- for (i = 0; i < PAGE_ALIGN(size) / PAGE_SIZE; i++) {
+ len = size;
- /*
- * Don't use GFP_ZERO here because it is faster to memset the
- * range ourselves (see below)
- */
+ while (len > 0) {
+ struct page *page;
+ unsigned int gfp_mask = GFP_KERNEL | __GFP_HIGHMEM |
+ __GFP_NOWARN;
+ int j;
- pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
- if (pages[i] == NULL) {
- ret = -ENOMEM;
- memdesc->sglen = i;
- goto done;
+ /* don't waste space at the end of the allocation*/
+ if (len < page_size)
+ page_size = PAGE_SIZE;
+
+ if (page_size != PAGE_SIZE)
+ gfp_mask |= __GFP_COMP;
+
+ page = alloc_pages(gfp_mask, get_order(page_size));
+
+ if (page == NULL) {
+ if (page_size != PAGE_SIZE) {
+ page_size = PAGE_SIZE;
+ continue;
+ }
}
- sg_set_page(&memdesc->sg[i], pages[i], PAGE_SIZE, 0);
+ for (j = 0; j < page_size >> PAGE_SHIFT; j++)
+ pages[pcount++] = nth_page(page, j);
+
+ sg_set_page(&memdesc->sg[sglen++], page, page_size, 0);
+ len -= page_size;
}
- /* ADd the guard page to the end of the sglist */
+ /* Add the guard page to the end of the sglist */
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU) {
/*
@@ -604,13 +661,14 @@
__GFP_HIGHMEM);
if (kgsl_guard_page != NULL) {
- sg_set_page(&memdesc->sg[sglen - 1], kgsl_guard_page,
+ sg_set_page(&memdesc->sg[sglen++], kgsl_guard_page,
PAGE_SIZE, 0);
memdesc->flags |= KGSL_MEMDESC_GUARD_PAGE;
- } else
- memdesc->sglen--;
+ }
}
+ memdesc->sglen = sglen;
+
/*
* All memory that goes to the user has to be zeroed out before it gets
* exposed to userspace. This means that the memory has to be mapped in
@@ -630,18 +688,16 @@
* path
*/
- ptr = vmap(pages, i, VM_IOREMAP, page_prot);
+ ptr = vmap(pages, pcount, VM_IOREMAP, page_prot);
if (ptr != NULL) {
memset(ptr, 0, memdesc->size);
dmac_flush_range(ptr, ptr + memdesc->size);
vunmap(ptr);
} else {
- int j;
-
/* Very, very, very slow path */
- for (j = 0; j < i; j++) {
+ for (j = 0; j < pcount; j++) {
ptr = kmap_atomic(pages[j]);
memset(ptr, 0, PAGE_SIZE);
dmac_flush_range(ptr, ptr + PAGE_SIZE);
@@ -684,7 +740,7 @@
size = ALIGN(size, PAGE_SIZE * 2);
ret = _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
- GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ 0, GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
if (!ret)
ret = kgsl_page_alloc_map_kernel(memdesc);
if (ret)
@@ -708,7 +764,7 @@
protflags |= GSL_PT_PAGE_WV;
return _kgsl_sharedmem_page_alloc(memdesc, pagetable, size,
- protflags);
+ flags, protflags);
}
EXPORT_SYMBOL(kgsl_sharedmem_page_alloc_user);
@@ -758,7 +814,7 @@
if (memdesc->ops && memdesc->ops->free)
memdesc->ops->free(memdesc);
- kgsl_sg_free(memdesc->sg, memdesc->sglen);
+ kgsl_sg_free(memdesc->sg, memdesc->sglen_alloc);
memset(memdesc, 0, sizeof(*memdesc));
}
@@ -920,3 +976,42 @@
return 0;
}
EXPORT_SYMBOL(kgsl_sharedmem_map_vma);
+
+static const char * const memtype_str[] = {
+ [KGSL_MEMTYPE_OBJECTANY] = "any(0)",
+ [KGSL_MEMTYPE_FRAMEBUFFER] = "framebuffer",
+ [KGSL_MEMTYPE_RENDERBUFFER] = "renderbuffer",
+ [KGSL_MEMTYPE_ARRAYBUFFER] = "arraybuffer",
+ [KGSL_MEMTYPE_ELEMENTARRAYBUFFER] = "elementarraybuffer",
+ [KGSL_MEMTYPE_VERTEXARRAYBUFFER] = "vertexarraybuffer",
+ [KGSL_MEMTYPE_TEXTURE] = "texture",
+ [KGSL_MEMTYPE_SURFACE] = "surface",
+ [KGSL_MEMTYPE_EGL_SURFACE] = "egl_surface",
+ [KGSL_MEMTYPE_GL] = "gl",
+ [KGSL_MEMTYPE_CL] = "cl",
+ [KGSL_MEMTYPE_CL_BUFFER_MAP] = "cl_buffer_map",
+ [KGSL_MEMTYPE_CL_BUFFER_NOMAP] = "cl_buffer_nomap",
+ [KGSL_MEMTYPE_CL_IMAGE_MAP] = "cl_image_map",
+ [KGSL_MEMTYPE_CL_IMAGE_NOMAP] = "cl_image_nomap",
+ [KGSL_MEMTYPE_CL_KERNEL_STACK] = "cl_kernel_stack",
+ [KGSL_MEMTYPE_COMMAND] = "command",
+ [KGSL_MEMTYPE_2D] = "2d",
+ [KGSL_MEMTYPE_EGL_IMAGE] = "egl_image",
+ [KGSL_MEMTYPE_EGL_SHADOW] = "egl_shadow",
+ [KGSL_MEMTYPE_MULTISAMPLE] = "egl_multisample",
+ /* KGSL_MEMTYPE_KERNEL handled below, to avoid huge array */
+};
+
+void kgsl_get_memory_usage(char *name, size_t name_size, unsigned int memflags)
+{
+ unsigned char type;
+
+ type = (memflags & KGSL_MEMTYPE_MASK) >> KGSL_MEMTYPE_SHIFT;
+ if (type == KGSL_MEMTYPE_KERNEL)
+ strlcpy(name, "kernel", name_size);
+ else if (type < ARRAY_SIZE(memtype_str) && memtype_str[type] != NULL)
+ strlcpy(name, memtype_str[type], name_size);
+ else
+ snprintf(name, name_size, "unknown(%3d)", type);
+}
+EXPORT_SYMBOL(kgsl_get_memory_usage);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index de89ac1..5a6c4c2 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -27,8 +27,6 @@
#define KGSL_CACHE_OP_FLUSH 0x02
#define KGSL_CACHE_OP_CLEAN 0x03
-/** Set if the memdesc describes cached memory */
-#define KGSL_MEMFLAGS_CACHED 0x00000001
/** Set if the memdesc is mapped into all pagetables */
#define KGSL_MEMFLAGS_GLOBAL 0x00000002
@@ -136,6 +134,7 @@
{
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
return kgsl_sharedmem_ebimem(memdesc, pagetable, size);
+ memdesc->priv |= (KGSL_MEMTYPE_KERNEL << KGSL_MEMTYPE_SHIFT);
return kgsl_sharedmem_page_alloc(memdesc, pagetable, size);
}
@@ -144,10 +143,17 @@
struct kgsl_pagetable *pagetable,
size_t size, unsigned int flags)
{
+ int ret;
+ unsigned int mask = (KGSL_MEMTYPE_MASK | KGSL_MEMFLAGS_GPUREADONLY);
if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_NONE)
- return kgsl_sharedmem_ebimem_user(memdesc, pagetable, size,
+ ret = kgsl_sharedmem_ebimem_user(memdesc, pagetable, size,
flags);
- return kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size, flags);
+ else
+ ret = kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size,
+ flags);
+ if (ret == 0)
+ memdesc->priv |= flags & mask;
+ return ret;
}
static inline int
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 81ab3fb..81cb34f 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -315,16 +315,22 @@
TP_STRUCT__entry(
__field(unsigned int, gpuaddr)
__field(unsigned int, size)
+ __field(unsigned int, tgid)
+ __array(char, usage, 16)
),
TP_fast_assign(
__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
__entry->size = mem_entry->memdesc.size;
+ __entry->tgid = mem_entry->priv->pid;
+ kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
+ mem_entry->memdesc.priv);
),
TP_printk(
- "gpuaddr=0x%08x size=%d",
- __entry->gpuaddr, __entry->size
+ "gpuaddr=0x%08x size=%d tgid=%d usage=%s",
+ __entry->gpuaddr, __entry->size, __entry->tgid,
+ __entry->usage
)
);
@@ -339,6 +345,8 @@
__field(unsigned int, size)
__field(int, fd)
__field(int, type)
+ __field(unsigned int, tgid)
+ __array(char, usage, 16)
),
TP_fast_assign(
@@ -346,12 +354,16 @@
__entry->size = mem_entry->memdesc.size;
__entry->fd = fd;
__entry->type = mem_entry->memtype;
+ __entry->tgid = mem_entry->priv->pid;
+ kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
+ mem_entry->memdesc.priv);
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d fd=%d",
+ "gpuaddr=0x%08x size=%d type=%d fd=%d tgid=%d usage %s",
__entry->gpuaddr, __entry->size,
- __entry->type, __entry->fd
+ __entry->type, __entry->fd, __entry->tgid,
+ __entry->usage
)
);
@@ -366,17 +378,23 @@
__field(unsigned int, size)
__field(int, type)
__field(int, fd)
+ __field(unsigned int, tgid)
+ __array(char, usage, 16)
),
TP_fast_assign(
__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
__entry->size = mem_entry->memdesc.size;
__entry->type = mem_entry->memtype;
+ __entry->tgid = mem_entry->priv->pid;
+ kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
+ mem_entry->memdesc.priv);
),
TP_printk(
- "gpuaddr=0x%08x size=%d type=%d",
- __entry->gpuaddr, __entry->size, __entry->type
+ "gpuaddr=0x%08x size=%d type=%d tgid=%d usage=%s",
+ __entry->gpuaddr, __entry->size, __entry->type,
+ __entry->tgid, __entry->usage
)
);
@@ -392,6 +410,7 @@
__field(unsigned int, gpuaddr)
__field(unsigned int, size)
__field(int, type)
+ __array(char, usage, 16)
__field(unsigned int, drawctxt_id)
__field(unsigned int, curr_ts)
__field(unsigned int, free_ts)
@@ -401,6 +420,8 @@
__assign_str(device_name, device->name);
__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
__entry->size = mem_entry->memdesc.size;
+ kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
+ mem_entry->memdesc.priv);
__entry->drawctxt_id = id;
__entry->type = mem_entry->memtype;
__entry->curr_ts = curr_ts;
@@ -408,12 +429,13 @@
),
TP_printk(
- "d_name=%s gpuaddr=0x%08x size=%d type=%d ctx=%u"
+ "d_name=%s gpuaddr=0x%08x size=%d type=%d usage=%s ctx=%u"
" curr_ts=0x%x free_ts=0x%x",
__get_str(device_name),
__entry->gpuaddr,
__entry->size,
__entry->type,
+ __entry->usage,
__entry->drawctxt_id,
__entry->curr_ts,
__entry->free_ts
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 8ddc991..712bc60 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -212,10 +212,6 @@
queue_work(device->work_queue, &device->ts_expired_ws);
wake_up_interruptible(&device->wait_queue);
-
- atomic_notifier_call_chain(
- &(device->ts_notifier_list),
- device->id, NULL);
}
}
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 62bfce4..ce1a18e 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -557,6 +557,7 @@
memset(pdata, 0, sizeof *pdata);
pdata->rep = !!of_get_property(node, "autorepeat", NULL);
+ pdata->name = of_get_property(node, "input-name", NULL);
/* First count the subnodes */
pdata->nbuttons = 0;
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 9f64cec..abd66f4 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -104,14 +104,75 @@
static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
+static int pmic8xxx_set_pon1(struct device *dev, u32 debounce_us, bool pull_up)
+{
+ int err;
+ u32 delay;
+ u8 pon_cntl;
+
+ /* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
+ if (debounce_us > USEC_PER_SEC * 2 ||
+ debounce_us < USEC_PER_SEC / 64) {
+ dev_err(dev, "invalid power key trigger delay\n");
+ return -EINVAL;
+ }
+
+ delay = (debounce_us << 6) / USEC_PER_SEC;
+ delay = ilog2(delay);
+
+ err = pm8xxx_readb(dev->parent, PON_CNTL_1, &pon_cntl);
+ if (err < 0) {
+ dev_err(dev, "failed reading PON_CNTL_1 err=%d\n", err);
+ return err;
+ }
+
+ pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
+ pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
+
+ if (pull_up)
+ pon_cntl |= PON_CNTL_PULL_UP;
+ else
+ pon_cntl &= ~PON_CNTL_PULL_UP;
+
+ err = pm8xxx_writeb(dev->parent, PON_CNTL_1, pon_cntl);
+ if (err < 0) {
+ dev_err(dev, "failed writing PON_CNTL_1 err=%d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static ssize_t pmic8xxx_debounce_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+ int err;
+ unsigned long val;
+
+ if (size > 8)
+ return -EINVAL;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ err = pmic8xxx_set_pon1(dev, val, pwrkey->pdata->pull_up);
+ if (err < 0)
+ return err;
+
+ return size;
+}
+
+static DEVICE_ATTR(debounce_us, 0664, NULL, pmic8xxx_debounce_store);
+
static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
{
struct input_dev *pwr;
int key_release_irq = platform_get_irq(pdev, 0);
int key_press_irq = platform_get_irq(pdev, 1);
int err;
- unsigned int delay;
- u8 pon_cntl;
struct pmic8xxx_pwrkey *pwrkey;
const struct pm8xxx_pwrkey_platform_data *pdata =
dev_get_platdata(&pdev->dev);
@@ -121,13 +182,6 @@
return -EINVAL;
}
- /* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
- if (pdata->kpd_trigger_delay_us > USEC_PER_SEC * 2 ||
- pdata->kpd_trigger_delay_us < USEC_PER_SEC / 64) {
- dev_err(&pdev->dev, "invalid power key trigger delay\n");
- return -EINVAL;
- }
-
pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
if (!pwrkey)
return -ENOMEM;
@@ -147,25 +201,10 @@
pwr->phys = "pmic8xxx_pwrkey/input0";
pwr->dev.parent = &pdev->dev;
- delay = (pdata->kpd_trigger_delay_us << 6) / USEC_PER_SEC;
- delay = ilog2(delay);
-
- err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
- if (err < 0) {
- dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
- goto free_input_dev;
- }
-
- pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
- pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
- if (pdata->pull_up)
- pon_cntl |= PON_CNTL_PULL_UP;
- else
- pon_cntl &= ~PON_CNTL_PULL_UP;
-
- err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
- if (err < 0) {
- dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
+ err = pmic8xxx_set_pon1(&pdev->dev,
+ pdata->kpd_trigger_delay_us, pdata->pull_up);
+ if (err) {
+ dev_dbg(&pdev->dev, "Can't set PON CTRL1 register: %d\n", err);
goto free_input_dev;
}
@@ -178,10 +217,22 @@
pwrkey->key_press_irq = key_press_irq;
pwrkey->key_release_irq = key_release_irq;
pwrkey->pwr = pwr;
- pwrkey->press = false;
platform_set_drvdata(pdev, pwrkey);
+ /* check power key status during boot */
+ err = pm8xxx_read_irq_stat(pdev->dev.parent, key_press_irq);
+ if (err < 0) {
+ dev_err(&pdev->dev, "reading irq status failed\n");
+ goto unreg_input_dev;
+ }
+ pwrkey->press = !!err;
+
+ if (pwrkey->press) {
+ input_report_key(pwrkey->pwr, KEY_POWER, 1);
+ input_sync(pwrkey->pwr);
+ }
+
err = request_any_context_irq(key_press_irq, pwrkey_press_irq,
IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
if (err < 0) {
@@ -199,12 +250,22 @@
goto free_press_irq;
}
+ err = device_create_file(&pdev->dev, &dev_attr_debounce_us);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "dev file creation for debounce failed: %d\n",
+ err);
+ goto free_rel_irq;
+ }
+
device_init_wakeup(&pdev->dev, pdata->wakeup);
return 0;
+free_rel_irq:
+ free_irq(key_release_irq, pwrkey);
free_press_irq:
- free_irq(key_press_irq, NULL);
+ free_irq(key_press_irq, pwrkey);
unreg_input_dev:
platform_set_drvdata(pdev, NULL);
input_unregister_device(pwr);
@@ -224,6 +285,7 @@
device_init_wakeup(&pdev->dev, 0);
+ device_remove_file(&pdev->dev, &dev_attr_debounce_us);
free_irq(key_press_irq, pwrkey);
free_irq(key_release_irq, pwrkey);
input_unregister_device(pwrkey->pwr);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index f10f433..f671806 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1389,7 +1389,8 @@
}
data->t9_max_reportid = t9_object->max_reportid;
data->t9_min_reportid = t9_object->max_reportid -
- t9_object->num_report_ids + 1;
+ (t9_object->num_report_ids *
+ (t9_object->instances + 1)) + 1;
if (data->pdata->key_codes) {
t15_object = mxt_get_object(data, MXT_TOUCH_KEYARRAY_T15);
@@ -1398,7 +1399,8 @@
else {
data->t15_max_reportid = t15_object->max_reportid;
data->t15_min_reportid = t15_object->max_reportid -
- t15_object->num_report_ids + 1;
+ (t15_object->num_report_ids *
+ (t15_object->instances + 1)) + 1;
}
}
@@ -1409,7 +1411,8 @@
else {
data->t42_max_reportid = t42_object->max_reportid;
data->t42_min_reportid = t42_object->max_reportid -
- t42_object->num_report_ids + 1;
+ (t42_object->num_report_ids *
+ (t42_object->instances + 1)) + 1;
}
return 0;
@@ -2231,6 +2234,14 @@
}
}
+ /* calibrate */
+ if (data->pdata->need_calibration) {
+ error = mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_CALIBRATE, 1);
+ if (error < 0)
+ dev_dbg(dev, "sending calibration command failed\n");
+ }
+
mutex_unlock(&input_dev->mutex);
return 0;
@@ -2447,6 +2458,9 @@
return -EINVAL;
}
+ /* need calibration during wakeup? */
+ pdata->need_calibration = of_property_read_bool(np,
+ "atmel,need-calibration");
/* config array size */
pdata->config_array_size = 0;
temp = NULL;
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index f867dcb..ec3429b 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -16,7 +16,7 @@
# MSM IOMMU support
config MSM_IOMMU
bool "MSM IOMMU Support"
- depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974
+ depends on ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8974 || ARCH_MPQ8092
select IOMMU_API
help
Support for the IOMMUs found on certain Qualcomm SOCs.
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index c7f6b82..9d88fdd 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -148,9 +148,9 @@
return ret;
}
-static void __reset_iommu(void __iomem *base, int smt_size)
+static void __reset_iommu(void __iomem *base)
{
- int i;
+ int i, smt_size;
SET_ACR(base, 0);
SET_NSACR(base, 0);
@@ -162,6 +162,7 @@
SET_PMCR(base, 0);
SET_SCR1(base, 0);
SET_SSDR_N(base, 0, 0);
+ smt_size = GET_IDR0_NUMSMRG(base);
for (i = 0; i < smt_size; i++)
SET_SMR_VALID(base, i, 0);
@@ -169,9 +170,11 @@
mb();
}
-static void __program_iommu(void __iomem *base, int smt_size)
+static void __program_iommu(void __iomem *base,
+ struct msm_iommu_bfb_settings *bfb_settings)
{
- __reset_iommu(base, smt_size);
+ int i;
+ __reset_iommu(base);
SET_CR0_SMCFCFG(base, 1);
SET_CR0_USFCFG(base, 1);
@@ -181,6 +184,12 @@
SET_CR0_GFIE(base, 1);
SET_CR0_GFRE(base, 1);
SET_CR0_CLIENTPD(base, 0);
+
+ if (bfb_settings)
+ for (i = 0; i < bfb_settings->length; i++)
+ SET_GLOBAL_REG(base, bfb_settings->regs[i],
+ bfb_settings->data[i]);
+
mb(); /* Make sure writes complete before returning */
}
@@ -200,16 +209,28 @@
mb();
}
+static void __release_smg(void __iomem *base, int ctx)
+{
+ int i, smt_size;
+ smt_size = GET_IDR0_NUMSMRG(base);
+
+ /* Invalidate any SMGs associated with this context */
+ for (i = 0; i < smt_size; i++)
+ if (GET_SMR_VALID(base, i) &&
+ GET_S2CR_CBNDX(base, i) == ctx)
+ SET_SMR_VALID(base, i, 0);
+}
+
static void __program_context(void __iomem *base, int ctx, int ncb,
phys_addr_t pgtable, int redirect,
- u32 *sids, int len, int smt_size)
+ u32 *sids, int len)
{
unsigned int prrr, nmrr;
unsigned int pn;
- int i, j, found, num = 0;
+ int i, j, found, num = 0, smt_size;
__reset_context(base, ctx);
-
+ smt_size = GET_IDR0_NUMSMRG(base);
pn = pgtable >> CB_TTBR0_ADDR_SHIFT;
SET_TTBCR(base, ctx, 0);
SET_CB_TTBR0_ADDR(base, ctx, pn);
@@ -416,12 +437,12 @@
}
if (!msm_iommu_ctx_attached(dev->parent))
- __program_iommu(iommu_drvdata->base, iommu_drvdata->nsmr);
+ __program_iommu(iommu_drvdata->base,
+ iommu_drvdata->bfb_settings);
__program_context(iommu_drvdata->base, ctx_drvdata->num,
iommu_drvdata->ncb, __pa(priv->pt.fl_table),
- priv->pt.redirect, ctx_drvdata->sids, ctx_drvdata->nsid,
- iommu_drvdata->nsmr);
+ priv->pt.redirect, ctx_drvdata->sids, ctx_drvdata->nsid);
__disable_clocks(iommu_drvdata);
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
@@ -458,6 +479,8 @@
GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_drvdata->num));
__reset_context(iommu_drvdata->base, ctx_drvdata->num);
+ __release_smg(iommu_drvdata->base, ctx_drvdata->num);
+
__disable_clocks(iommu_drvdata);
regulator_disable(iommu_drvdata->gdsc);
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index e17e1f8..df66a3a 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -467,6 +467,92 @@
return pgprot;
}
+static unsigned long *make_second_level(struct msm_priv *priv,
+ unsigned long *fl_pte)
+{
+ unsigned long *sl;
+ sl = (unsigned long *) __get_free_pages(GFP_KERNEL,
+ get_order(SZ_4K));
+
+ if (!sl) {
+ pr_debug("Could not allocate second level table\n");
+ goto fail;
+ }
+ memset(sl, 0, SZ_4K);
+ clean_pte(sl, sl + NUM_SL_PTE, priv->redirect);
+
+ *fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
+ FL_TYPE_TABLE);
+
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
+fail:
+ return sl;
+}
+
+static int sl_4k(unsigned long *sl_pte, phys_addr_t pa, unsigned int pgprot)
+{
+ int ret = 0;
+
+ if (*sl_pte) {
+ ret = -EBUSY;
+ goto fail;
+ }
+
+ *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_NG | SL_SHARED
+ | SL_TYPE_SMALL | pgprot;
+fail:
+ return ret;
+}
+
+static int sl_64k(unsigned long *sl_pte, phys_addr_t pa, unsigned int pgprot)
+{
+ int ret = 0;
+
+ int i;
+
+ for (i = 0; i < 16; i++)
+ if (*(sl_pte+i)) {
+ ret = -EBUSY;
+ goto fail;
+ }
+
+ for (i = 0; i < 16; i++)
+ *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_NG
+ | SL_SHARED | SL_TYPE_LARGE | pgprot;
+
+fail:
+ return ret;
+}
+
+
+static inline int fl_1m(unsigned long *fl_pte, phys_addr_t pa, int pgprot)
+{
+ if (*fl_pte)
+ return -EBUSY;
+
+ *fl_pte = (pa & 0xFFF00000) | FL_NG | FL_TYPE_SECT | FL_SHARED
+ | pgprot;
+
+ return 0;
+}
+
+
+static inline int fl_16m(unsigned long *fl_pte, phys_addr_t pa, int pgprot)
+{
+ int i;
+ int ret = 0;
+ for (i = 0; i < 16; i++)
+ if (*(fl_pte+i)) {
+ ret = -EBUSY;
+ goto fail;
+ }
+ for (i = 0; i < 16; i++)
+ *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION
+ | FL_TYPE_SECT | FL_SHARED | FL_NG | pgprot;
+fail:
+ return ret;
+}
+
static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
phys_addr_t pa, size_t len, int prot)
{
@@ -514,28 +600,16 @@
fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */
if (len == SZ_16M) {
- int i = 0;
-
- for (i = 0; i < 16; i++)
- if (*(fl_pte+i)) {
- ret = -EBUSY;
- goto fail;
- }
-
- for (i = 0; i < 16; i++)
- *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION
- | FL_TYPE_SECT | FL_SHARED | FL_NG | pgprot;
+ ret = fl_16m(fl_pte, pa, pgprot);
+ if (ret)
+ goto fail;
clean_pte(fl_pte, fl_pte + 16, priv->redirect);
}
if (len == SZ_1M) {
- if (*fl_pte) {
- ret = -EBUSY;
+ ret = fl_1m(fl_pte, pa, pgprot);
+ if (ret)
goto fail;
- }
-
- *fl_pte = (pa & 0xFFF00000) | FL_NG | FL_TYPE_SECT | FL_SHARED
- | pgprot;
clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
@@ -543,22 +617,10 @@
if (len == SZ_4K || len == SZ_64K) {
if (*fl_pte == 0) {
- unsigned long *sl;
- sl = (unsigned long *) __get_free_pages(GFP_KERNEL,
- get_order(SZ_4K));
-
- if (!sl) {
- pr_debug("Could not allocate second level table\n");
+ if (make_second_level(priv, fl_pte) == NULL) {
ret = -ENOMEM;
goto fail;
}
- memset(sl, 0, SZ_4K);
- clean_pte(sl, sl + NUM_SL_PTE, priv->redirect);
-
- *fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
- FL_TYPE_TABLE);
-
- clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
if (!(*fl_pte & FL_TYPE_TABLE)) {
@@ -572,29 +634,17 @@
sl_pte = sl_table + sl_offset;
if (len == SZ_4K) {
- if (*sl_pte) {
- ret = -EBUSY;
+ ret = sl_4k(sl_pte, pa, pgprot);
+ if (ret)
goto fail;
- }
- *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_NG | SL_SHARED
- | SL_TYPE_SMALL | pgprot;
clean_pte(sl_pte, sl_pte + 1, priv->redirect);
}
if (len == SZ_64K) {
- int i;
-
- for (i = 0; i < 16; i++)
- if (*(sl_pte+i)) {
- ret = -EBUSY;
- goto fail;
- }
-
- for (i = 0; i < 16; i++)
- *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_NG
- | SL_SHARED | SL_TYPE_LARGE | pgprot;
-
+ ret = sl_64k(sl_pte, pa, pgprot);
+ if (ret)
+ goto fail;
clean_pte(sl_pte, sl_pte + 16, priv->redirect);
}
@@ -712,22 +762,28 @@
return pa;
}
+static inline int is_fully_aligned(unsigned int va, phys_addr_t pa, size_t len,
+ int align)
+{
+ return IS_ALIGNED(va, align) && IS_ALIGNED(pa, align)
+ && (len >= align);
+}
+
static int msm_iommu_map_range(struct iommu_domain *domain, unsigned int va,
struct scatterlist *sg, unsigned int len,
int prot)
{
unsigned int pa;
unsigned int offset = 0;
- unsigned int pgprot;
unsigned long *fl_table;
unsigned long *fl_pte;
unsigned long fl_offset;
- unsigned long *sl_table;
+ unsigned long *sl_table = NULL;
unsigned long sl_offset, sl_start;
- unsigned int chunk_offset = 0;
- unsigned int chunk_pa;
+ unsigned int chunk_size, chunk_offset = 0;
int ret = 0;
struct msm_priv *priv;
+ unsigned int pgprot4k, pgprot64k, pgprot1m, pgprot16m;
mutex_lock(&msm_iommu_lock);
@@ -736,49 +792,78 @@
priv = domain->priv;
fl_table = priv->pgtable;
- pgprot = __get_pgprot(prot, SZ_4K);
+ pgprot4k = __get_pgprot(prot, SZ_4K);
+ pgprot64k = __get_pgprot(prot, SZ_64K);
+ pgprot1m = __get_pgprot(prot, SZ_1M);
+ pgprot16m = __get_pgprot(prot, SZ_16M);
- if (!pgprot) {
+ if (!pgprot4k || !pgprot64k || !pgprot1m || !pgprot16m) {
ret = -EINVAL;
goto fail;
}
fl_offset = FL_OFFSET(va); /* Upper 12 bits */
fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */
-
- sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
- sl_offset = SL_OFFSET(va);
-
- chunk_pa = get_phys_addr(sg);
- if (chunk_pa == 0) {
- pr_debug("No dma address for sg %p\n", sg);
- ret = -EINVAL;
- goto fail;
- }
+ pa = get_phys_addr(sg);
while (offset < len) {
- /* Set up a 2nd level page table if one doesn't exist */
- if (*fl_pte == 0) {
- sl_table = (unsigned long *)
- __get_free_pages(GFP_KERNEL, get_order(SZ_4K));
+ chunk_size = SZ_4K;
- if (!sl_table) {
- pr_debug("Could not allocate second level table\n");
+ if (is_fully_aligned(va, pa, sg->length - chunk_offset,
+ SZ_16M))
+ chunk_size = SZ_16M;
+ else if (is_fully_aligned(va, pa, sg->length - chunk_offset,
+ SZ_1M))
+ chunk_size = SZ_1M;
+ /* 64k or 4k determined later */
+
+ /* for 1M and 16M, only first level entries are required */
+ if (chunk_size >= SZ_1M) {
+ if (chunk_size == SZ_16M) {
+ ret = fl_16m(fl_pte, pa, pgprot16m);
+ if (ret)
+ goto fail;
+ clean_pte(fl_pte, fl_pte + 16, priv->redirect);
+ fl_pte += 16;
+ } else if (chunk_size == SZ_1M) {
+ ret = fl_1m(fl_pte, pa, pgprot1m);
+ if (ret)
+ goto fail;
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
+ fl_pte++;
+ }
+
+ offset += chunk_size;
+ chunk_offset += chunk_size;
+ va += chunk_size;
+ pa += chunk_size;
+
+ if (chunk_offset >= sg->length && offset < len) {
+ chunk_offset = 0;
+ sg = sg_next(sg);
+ pa = get_phys_addr(sg);
+ if (pa == 0) {
+ pr_debug("No dma address for sg %p\n",
+ sg);
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
+ continue;
+ }
+ /* for 4K or 64K, make sure there is a second level table */
+ if (*fl_pte == 0) {
+ if (!make_second_level(priv, fl_pte)) {
ret = -ENOMEM;
goto fail;
}
-
- memset(sl_table, 0, SZ_4K);
- clean_pte(sl_table, sl_table + NUM_SL_PTE,
- priv->redirect);
-
- *fl_pte = ((((int)__pa(sl_table)) & FL_BASE_MASK) |
- FL_TYPE_TABLE);
- clean_pte(fl_pte, fl_pte + 1, priv->redirect);
- } else
- sl_table = (unsigned long *)
- __va(((*fl_pte) & FL_BASE_MASK));
-
+ }
+ if (!(*fl_pte & FL_TYPE_TABLE)) {
+ ret = -EBUSY;
+ goto fail;
+ }
+ sl_table = __va(((*fl_pte) & FL_BASE_MASK));
+ sl_offset = SL_OFFSET(va);
/* Keep track of initial position so we
* don't clean more than we have to
*/
@@ -786,21 +871,39 @@
/* Build the 2nd level page table */
while (offset < len && sl_offset < NUM_SL_PTE) {
- pa = chunk_pa + chunk_offset;
- sl_table[sl_offset] = (pa & SL_BASE_MASK_SMALL) |
- pgprot | SL_NG | SL_SHARED | SL_TYPE_SMALL;
- sl_offset++;
- offset += SZ_4K;
- chunk_offset += SZ_4K;
+ /* Map a large 64K page if the chunk is large enough and
+ * the pa and va are aligned
+ */
+
+ if (is_fully_aligned(va, pa, sg->length - chunk_offset,
+ SZ_64K))
+ chunk_size = SZ_64K;
+ else
+ chunk_size = SZ_4K;
+
+ if (chunk_size == SZ_4K) {
+ sl_4k(&sl_table[sl_offset], pa, pgprot4k);
+ sl_offset++;
+ } else {
+ BUG_ON(sl_offset + 16 > NUM_SL_PTE);
+ sl_64k(&sl_table[sl_offset], pa, pgprot64k);
+ sl_offset += 16;
+ }
+
+
+ offset += chunk_size;
+ chunk_offset += chunk_size;
+ va += chunk_size;
+ pa += chunk_size;
if (chunk_offset >= sg->length && offset < len) {
chunk_offset = 0;
sg = sg_next(sg);
- chunk_pa = get_phys_addr(sg);
- if (chunk_pa == 0) {
+ pa = get_phys_addr(sg);
+ if (pa == 0) {
pr_debug("No dma address for sg %p\n",
- sg);
+ sg);
ret = -EINVAL;
goto fail;
}
@@ -808,7 +911,7 @@
}
clean_pte(sl_table + sl_start, sl_table + sl_offset,
- priv->redirect);
+ priv->redirect);
fl_pte++;
sl_offset = 0;
@@ -842,45 +945,53 @@
fl_offset = FL_OFFSET(va); /* Upper 12 bits */
fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */
- sl_start = SL_OFFSET(va);
-
while (offset < len) {
- sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
- sl_end = ((len - offset) / SZ_4K) + sl_start;
+ if (*fl_pte & FL_TYPE_TABLE) {
+ sl_start = SL_OFFSET(va);
+ sl_table = __va(((*fl_pte) & FL_BASE_MASK));
+ sl_end = ((len - offset) / SZ_4K) + sl_start;
- if (sl_end > NUM_SL_PTE)
- sl_end = NUM_SL_PTE;
+ if (sl_end > NUM_SL_PTE)
+ sl_end = NUM_SL_PTE;
- memset(sl_table + sl_start, 0, (sl_end - sl_start) * 4);
- clean_pte(sl_table + sl_start, sl_table + sl_end,
- priv->redirect);
+ memset(sl_table + sl_start, 0, (sl_end - sl_start) * 4);
+ clean_pte(sl_table + sl_start, sl_table + sl_end,
+ priv->redirect);
- offset += (sl_end - sl_start) * SZ_4K;
+ offset += (sl_end - sl_start) * SZ_4K;
+ va += (sl_end - sl_start) * SZ_4K;
- /* Unmap and free the 2nd level table if all mappings in it
- * were removed. This saves memory, but the table will need
- * to be re-allocated the next time someone tries to map these
- * VAs.
- */
- used = 0;
+ /* Unmap and free the 2nd level table if all mappings
+ * in it were removed. This saves memory, but the table
+ * will need to be re-allocated the next time someone
+ * tries to map these VAs.
+ */
+ used = 0;
- /* If we just unmapped the whole table, don't bother
- * seeing if there are still used entries left.
- */
- if (sl_end - sl_start != NUM_SL_PTE)
- for (i = 0; i < NUM_SL_PTE; i++)
- if (sl_table[i]) {
- used = 1;
- break;
- }
- if (!used) {
- free_page((unsigned long)sl_table);
+ /* If we just unmapped the whole table, don't bother
+ * seeing if there are still used entries left.
+ */
+ if (sl_end - sl_start != NUM_SL_PTE)
+ for (i = 0; i < NUM_SL_PTE; i++)
+ if (sl_table[i]) {
+ used = 1;
+ break;
+ }
+ if (!used) {
+ free_page((unsigned long)sl_table);
+ *fl_pte = 0;
+
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
+ }
+
+ sl_start = 0;
+ } else {
*fl_pte = 0;
-
clean_pte(fl_pte, fl_pte + 1, priv->redirect);
+ va += SZ_1M;
+ offset += SZ_1M;
+ sl_start = 0;
}
-
- sl_start = 0;
fl_pte++;
}
diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index 8c26f95..68612ba 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.c
@@ -29,29 +29,80 @@
#include <mach/iommu_hw-v2.h>
#include <mach/iommu.h>
+static int msm_iommu_parse_bfb_settings(struct platform_device *pdev,
+ struct msm_iommu_drvdata *drvdata)
+{
+ struct msm_iommu_bfb_settings *bfb_settings;
+ u32 nreg, nval;
+ int ret, i;
+
+ /*
+ * It is not valid for a device to have the qcom,iommu-bfb-regs
+ * property but not the qcom,iommu-bfb-data property, and vice versa.
+ */
+ if (!of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-regs", &nreg)) {
+ if (of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-data",
+ &nval))
+ return -EINVAL;
+ return 0;
+ }
+
+ if (!of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-data", &nval))
+ return -EINVAL;
+
+ if (nreg >= sizeof(bfb_settings->regs))
+ return -EINVAL;
+
+ if (nval >= sizeof(bfb_settings->data))
+ return -EINVAL;
+
+ if (nval != nreg)
+ return -EINVAL;
+
+ bfb_settings = devm_kzalloc(&pdev->dev, sizeof(*bfb_settings),
+ GFP_KERNEL);
+ if (!bfb_settings)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,iommu-bfb-regs",
+ bfb_settings->regs,
+ nreg / sizeof(*bfb_settings->regs));
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,iommu-bfb-data",
+ bfb_settings->data,
+ nval / sizeof(*bfb_settings->data));
+ if (ret)
+ return ret;
+
+ bfb_settings->length = nreg / sizeof(*bfb_settings->regs);
+
+ for (i = 0; i < bfb_settings->length; i++)
+ if (bfb_settings->regs[i] < IMPLDEF_OFFSET ||
+ bfb_settings->regs[i] >= IMPLDEF_OFFSET + IMPLDEF_LENGTH)
+ return -EINVAL;
+
+ drvdata->bfb_settings = bfb_settings;
+ return 0;
+}
+
static int msm_iommu_parse_dt(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata)
{
struct device_node *child;
int ret = 0;
- u32 nsmr;
ret = device_move(&pdev->dev, &msm_iommu_root_dev->dev, DPM_ORDER_NONE);
if (ret)
goto fail;
- ret = of_property_read_u32(pdev->dev.of_node, "qcom,iommu-smt-size",
- &nsmr);
+ ret = msm_iommu_parse_bfb_settings(pdev, drvdata);
if (ret)
goto fail;
- if (nsmr > MAX_NUM_SMR) {
- pr_err("Invalid SMT size: %d\n", nsmr);
- ret = -EINVAL;
- goto fail;
- }
-
- drvdata->nsmr = nsmr;
for_each_child_of_node(pdev->dev.of_node, child) {
drvdata->ncb++;
if (!of_platform_device_create(child, NULL, &pdev->dev))
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index f42fb5e..13493b8 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/leds.h>
#include <linux/err.h>
+#include <linux/spinlock.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/spmi.h>
@@ -163,7 +164,7 @@
int id;
u16 base;
u8 reg;
- struct mutex lock;
+ spinlock_t lock;
struct wled_config_data *wled_cfg;
int max_current;
bool default_on;
@@ -299,7 +300,7 @@
return;
}
- mutex_lock(&led->lock);
+ spin_lock(&led->lock);
led->cdev.brightness = value;
switch (led->id) {
@@ -313,7 +314,7 @@
dev_err(led->cdev.dev, "Invalid LED(%d)\n", led->id);
break;
}
- mutex_unlock(&led->lock);
+ spin_unlock(&led->lock);
}
static int __devinit qpnp_led_set_max_brightness(struct qpnp_led_data *led)
@@ -653,7 +654,7 @@
return -EINVAL;
}
- mutex_init(&led->lock);
+ spin_lock_init(&led->lock);
rc = qpnp_led_initialize(led);
if (rc < 0)
@@ -680,7 +681,6 @@
return 0;
fail_id_check:
- mutex_destroy(&led->lock);
led_classdev_unregister(&led->cdev);
return rc;
}
@@ -689,7 +689,6 @@
{
struct qpnp_led_data *led = dev_get_drvdata(&spmi->dev);
- mutex_destroy(&led->lock);
led_classdev_unregister(&led->cdev);
return 0;
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
index 836ca65..18c3767 100644
--- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -812,7 +812,7 @@
*kernel_mem = NULL;
} else {
*kernel_mem = ion_map_kernel(mpq_demux->ion_client,
- ion_handle, ionflag);
+ ion_handle);
if (*kernel_mem == NULL) {
MPQ_DVB_ERR_PRINT("%s: ion_map_kernel failed\n",
__func__);
@@ -932,7 +932,8 @@
ion_alloc(mpq_demux->ion_client,
actual_buffer_size,
SZ_4K,
- (ION_HEAP(ION_CP_MM_HEAP_ID) | CACHED));
+ ION_HEAP(ION_CP_MM_HEAP_ID),
+ ION_FLAG_CACHED);
if (IS_ERR_OR_NULL(feed_data->payload_buff_handle)) {
ret = PTR_ERR(feed_data->payload_buff_handle);
@@ -948,8 +949,7 @@
payload_buffer =
ion_map_kernel(mpq_demux->ion_client,
- feed_data->payload_buff_handle,
- 0);
+ feed_data->payload_buff_handle);
if (IS_ERR_OR_NULL(payload_buffer)) {
ret = PTR_ERR(payload_buffer);
diff --git a/drivers/media/dvb/mpq/video/mpq_dvb_video.c b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
index 4b3fb0c..bd8c4a4 100644
--- a/drivers/media/dvb/mpq/video/mpq_dvb_video.c
+++ b/drivers/media/dvb/mpq/video/mpq_dvb_video.c
@@ -572,7 +572,7 @@
ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
pmem_fd, kernel_vaddr, buffer_index,
&buff_handle);
- if (ion_flag == CACHED && buff_handle) {
+ if (ion_flag == ION_FLAG_CACHED && buff_handle) {
msm_ion_do_cache_op(
client_ctx->user_ion_client,
buff_handle,
@@ -1133,8 +1133,7 @@
}
vcd_h264_mv_buffer->kernel_virtual_addr =
(u8 *) ion_map_kernel(client_ctx->user_ion_client,
- client_ctx->h264_mv_ion_handle,
- ionflag);
+ client_ctx->h264_mv_ion_handle);
if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
DBG("%s(): get_ION_kernel virtual addr failed\n",
__func__);
@@ -1146,7 +1145,7 @@
VIDEO_DOMAIN, VIDEO_MAIN_POOL,
SZ_4K, 0, (unsigned long *)&iova,
(unsigned long *)&buffer_size,
- UNCACHED, 0);
+ 0, 0);
if (rc) {
DBG("%s():get_ION_kernel physical addr fail\n",
__func__);
@@ -1503,7 +1502,7 @@
kernel_vaddr,
buffer_index,
&buff_handle);
- if (ion_flag == CACHED && buff_handle) {
+ if (ion_flag == ION_FLAG_CACHED && buff_handle) {
msm_ion_do_cache_op(
client_ctx->user_ion_client,
buff_handle,
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index af4c2c9..eb16f2d 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1940,7 +1940,7 @@
}
/* Check for Bahama V2 variant*/
- if (bahama_version == 0x09) {
+ if ((bahama_version == 0x09) || (bahama_version == 0x0a)) {
/* In case of Bahama v2, forcefully enable the
* internal analog and digital voltage controllers
@@ -2179,7 +2179,8 @@
/* Set the index based on the bt status*/
index = bt_status ? 1 : 0;
/* Check for Bahama's existance and Bahama V2 variant*/
- if (bahama_present && (bahama_version == 0x09)) {
+ if (bahama_present
+ && (bahama_version == 0x09 || bahama_version == 0x0a)) {
radio->marimba->mod_id = SLAVE_ID_BAHAMA;
/* actual value itself used as mask*/
retval = marimba_write_bit_mask(radio->marimba,
@@ -4149,7 +4150,7 @@
/* use xfr for interrupt setup */
if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
- || radio->chipID == BAHAMA_2_0) {
+ || radio->chipID == BAHAMA_2_0 || radio->chipID == BAHAMA_2_1) {
FMDBG("Setting interrupts\n");
retval = sync_write_xfr(radio, INT_CTRL, int_ctrl);
/* use register write to setup interrupts */
@@ -4175,7 +4176,8 @@
* registers and it is not valid for MBA 2.1
*/
if ((radio->chipID != MARIMBA_2_1) && (radio->chipID != BAHAMA_1_0)
- && (radio->chipID != BAHAMA_2_0))
+ && (radio->chipID != BAHAMA_2_0)
+ && (radio->chipID != BAHAMA_2_1))
tavarua_handle_interrupts(radio);
return retval;
@@ -4208,7 +4210,7 @@
/* use xfr for interrupt setup */
wait_timeout = 100;
if (radio->chipID == MARIMBA_2_1 || radio->chipID == BAHAMA_1_0
- || radio->chipID == BAHAMA_2_0)
+ || radio->chipID == BAHAMA_2_0 || radio->chipID == BAHAMA_2_1)
retval = sync_write_xfr(radio, INT_CTRL, lpm_buf);
/* use register write to setup interrupts */
else
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index e9b4e2b..be9c43c 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -208,6 +208,15 @@
two mipi lanes, required for msm8625 platform.
Say Y here if this is msm8625 variant platform.
+config IMX135
+ bool "Sensor imx135 (Sony 13MP)"
+ depends on MSM_CAMERA
+ ---help---
+ Support for IMX135 sensor driver.
+ This is a Sony 13MP Bayer Sensor with autofocus and video HDR
+ support.
+ Say Y if the platform uses IMX135 sensor.
+
config VB6801
bool "Sensor vb6801"
depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.c b/drivers/media/video/msm/gemini/msm_gemini_platform.c
index 28d2439..111402b 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.c
@@ -52,7 +52,7 @@
return 0;
rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL,
- SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED, 0);
+ SZ_4K, 0, &paddr, (unsigned long *)&size, 0, 0);
#elif CONFIG_ANDROID_PMEM
unsigned long kvstart;
rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.c b/drivers/media/video/msm/io/msm_camera_i2c.c
index 27ebac5..9e4fcd1 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.c
+++ b/drivers/media/video/msm/io/msm_camera_i2c.c
@@ -376,81 +376,67 @@
{
int i;
int32_t rc = -EFAULT;
- if (client->cci_client) {
- struct msm_camera_cci_ctrl cci_ctrl;
- cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
- cci_ctrl.cci_info = client->cci_client;
- cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = reg_conf_tbl;
- cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
- cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
- cci_ctrl.cfg.cci_i2c_write_cfg.size = size;
- rc = v4l2_subdev_call(client->cci_client->cci_subdev,
- core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
- CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc);
- rc = cci_ctrl.status;
- } else {
- for (i = 0; i < size; i++) {
- enum msm_camera_i2c_data_type dt;
- if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
- rc = msm_camera_i2c_poll(client,
+ for (i = 0; i < size; i++) {
+ enum msm_camera_i2c_data_type dt;
+ if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
+ rc = msm_camera_i2c_poll(client,
+ reg_conf_tbl->reg_addr,
+ reg_conf_tbl->reg_data,
+ reg_conf_tbl->dt);
+ } else {
+ if (reg_conf_tbl->dt == 0)
+ dt = data_type;
+ else
+ dt = reg_conf_tbl->dt;
+ switch (dt) {
+ case MSM_CAMERA_I2C_BYTE_DATA:
+ case MSM_CAMERA_I2C_WORD_DATA:
+ rc = msm_camera_i2c_write(
+ client,
+ reg_conf_tbl->reg_addr,
+ reg_conf_tbl->reg_data, dt);
+ break;
+ case MSM_CAMERA_I2C_SET_BYTE_MASK:
+ rc = msm_camera_i2c_set_mask(client,
reg_conf_tbl->reg_addr,
reg_conf_tbl->reg_data,
- reg_conf_tbl->dt);
- } else {
- if (reg_conf_tbl->dt == 0)
- dt = data_type;
- else
- dt = reg_conf_tbl->dt;
- switch (dt) {
- case MSM_CAMERA_I2C_BYTE_DATA:
- case MSM_CAMERA_I2C_WORD_DATA:
- rc = msm_camera_i2c_write(
- client,
- reg_conf_tbl->reg_addr,
- reg_conf_tbl->reg_data, dt);
- break;
- case MSM_CAMERA_I2C_SET_BYTE_MASK:
- rc = msm_camera_i2c_set_mask(client,
- reg_conf_tbl->reg_addr,
- reg_conf_tbl->reg_data,
- MSM_CAMERA_I2C_BYTE_DATA, 1);
- break;
- case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
- rc = msm_camera_i2c_set_mask(client,
- reg_conf_tbl->reg_addr,
- reg_conf_tbl->reg_data,
- MSM_CAMERA_I2C_BYTE_DATA, 0);
- break;
- case MSM_CAMERA_I2C_SET_WORD_MASK:
- rc = msm_camera_i2c_set_mask(client,
- reg_conf_tbl->reg_addr,
- reg_conf_tbl->reg_data,
- MSM_CAMERA_I2C_WORD_DATA, 1);
- break;
- case MSM_CAMERA_I2C_UNSET_WORD_MASK:
- rc = msm_camera_i2c_set_mask(client,
- reg_conf_tbl->reg_addr,
- reg_conf_tbl->reg_data,
- MSM_CAMERA_I2C_WORD_DATA, 0);
- break;
- case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
- rc = msm_camera_i2c_set_write_mask_data(
- client,
- reg_conf_tbl->reg_addr,
- reg_conf_tbl->reg_data,
- reg_conf_tbl->mask,
- MSM_CAMERA_I2C_BYTE_DATA);
- break;
- default:
- pr_err("%s: Unsupport data type: %d\n",
- __func__, dt);
- break;
- }
- }
- if (rc < 0)
+ MSM_CAMERA_I2C_BYTE_DATA, 1);
break;
- reg_conf_tbl++;
+ case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
+ rc = msm_camera_i2c_set_mask(client,
+ reg_conf_tbl->reg_addr,
+ reg_conf_tbl->reg_data,
+ MSM_CAMERA_I2C_BYTE_DATA, 0);
+ break;
+ case MSM_CAMERA_I2C_SET_WORD_MASK:
+ rc = msm_camera_i2c_set_mask(client,
+ reg_conf_tbl->reg_addr,
+ reg_conf_tbl->reg_data,
+ MSM_CAMERA_I2C_WORD_DATA, 1);
+ break;
+ case MSM_CAMERA_I2C_UNSET_WORD_MASK:
+ rc = msm_camera_i2c_set_mask(client,
+ reg_conf_tbl->reg_addr,
+ reg_conf_tbl->reg_data,
+ MSM_CAMERA_I2C_WORD_DATA, 0);
+ break;
+ case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
+ rc = msm_camera_i2c_set_write_mask_data(
+ client,
+ reg_conf_tbl->reg_addr,
+ reg_conf_tbl->reg_data,
+ reg_conf_tbl->mask,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ break;
+ default:
+ pr_err("%s: Unsupport data type: %d\n",
+ __func__, dt);
+ break;
+ }
}
+ if (rc < 0)
+ break;
+ reg_conf_tbl++;
}
return rc;
}
diff --git a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
index d508c1d..9e7ede4 100644
--- a/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_7x27a_v4l2.c
@@ -145,13 +145,10 @@
case S_PREVIEW:
break;
case S_VIDEO:
- update_axi_qos(MSM_AXI_QOS_RECORDING);
break;
case S_CAPTURE:
- update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
break;
case S_DEFAULT:
- update_axi_qos(PM_QOS_DEFAULT_VALUE);
break;
case S_EXIT:
axi_free(AXI_FLOW_VIEWFINDER_HI);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
index 0370f63..06135ec 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_platform.c
@@ -50,7 +50,7 @@
return 0;
rc = ion_map_iommu(pgmn_dev->jpeg_client, *ionhandle, domain_num, 0,
- SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED,
+ SZ_4K, 0, &paddr, (unsigned long *)&size, 0,
0); JPEG_DBG("%s:%d] addr 0x%x size %ld", __func__, __LINE__,
(uint32_t)paddr, size);
diff --git a/drivers/media/video/msm/mercury/msm_mercury_platform.c b/drivers/media/video/msm/mercury/msm_mercury_platform.c
index e90c63c..3dc7f4b 100644
--- a/drivers/media/video/msm/mercury/msm_mercury_platform.c
+++ b/drivers/media/video/msm/mercury/msm_mercury_platform.c
@@ -58,7 +58,7 @@
rc = ion_map_iommu(mercury_client, *ionhandle, CAMERA_DOMAIN,
GEN_POOL, SZ_4K, 0, &paddr,
- (unsigned long *)&size, UNCACHED, 0);
+ (unsigned long *)&size, 0, 0);
#elif CONFIG_ANDROID_PMEM
unsigned long kvstart;
rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 2d9296c..17303dd 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -210,11 +210,13 @@
int dirty;
int node_type;
struct timeval timestamp;
+ uint32_t frame_id;
};
struct msm_cam_timestamp {
uint8_t present;
struct timeval timestamp;
+ uint32_t frame_id;
};
struct msm_cam_buf_map_info {
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 1e17c5c..77922e2 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -148,6 +148,8 @@
image_mode = MSM_V4L2_EXT_CAPTURE_MODE_RDI1;
else
image_mode = -1;
+ } else if (VFE_MSG_V2X_LIVESHOT_PRIMARY == vfe_msg) {
+ image_mode = MSM_V4L2_EXT_CAPTURE_MODE_V2X_LIVESHOT;
} else
image_mode = -1;
@@ -709,8 +711,12 @@
int rc = -EINVAL;
void __user *argp = (void __user *)arg;
- struct v4l2_subdev *sd = pmctl->vfe_sdev;
-
+ struct v4l2_subdev *sd;
+ if (!pmctl->vfe_sdev) {
+ pr_err("%s vfe subdev is NULL\n", __func__);
+ return -ENXIO;
+ }
+ sd = pmctl->vfe_sdev;
D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
switch (cmd) {
case MSM_CAM_IOCTL_CONFIG_VFE:
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 953f042..2919d23 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -434,7 +434,11 @@
D("%s Copying timestamp as %ld.%ld", __func__,
cam_ts->timestamp.tv_sec, cam_ts->timestamp.tv_usec);
buf->vidbuf.v4l2_buf.timestamp = cam_ts->timestamp;
+ buf->vidbuf.v4l2_buf.sequence = cam_ts->frame_id;
}
+ D("%s Notify user about buffer %d image_mode %d frame_id %d", __func__,
+ buf->vidbuf.v4l2_buf.index, pcam_inst->image_mode,
+ buf->vidbuf.v4l2_buf.sequence);
vb2_buffer_done(&buf->vidbuf, VB2_BUF_STATE_DONE);
return 0;
}
@@ -557,37 +561,53 @@
struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
int idx;
- /* Valid image mode. Search the mctl node first.
- * If mctl node doesnt have the instance, then
- * search in the user's video node */
- if (pmctl->vfe_output_mode == VFE_OUTPUTS_MAIN_AND_THUMB
- || pmctl->vfe_output_mode == VFE_OUTPUTS_THUMB_AND_MAIN
- || pmctl->vfe_output_mode == VFE_OUTPUTS_MAIN_AND_PREVIEW) {
- if (pcam->mctl_node.dev_inst_map[img_mode]
- && is_buffer_queued(pcam, img_mode)) {
- idx = pcam->mctl_node.dev_inst_map[img_mode]->my_index;
- pcam_inst = pcam->mctl_node.dev_inst[idx];
- D("%s Found instance %p in mctl node device\n",
+ /* Valid image mode. Search the mctl node first.
+ * If mctl node doesnt have the instance, then
+ * search in the user's video node */
+ if (pmctl->vfe_output_mode == VFE_OUTPUTS_MAIN_AND_THUMB
+ || pmctl->vfe_output_mode == VFE_OUTPUTS_THUMB_AND_MAIN) {
+ if (pcam->mctl_node.dev_inst_map[img_mode]
+ && is_buffer_queued(pcam, img_mode)) {
+ idx = pcam->mctl_node.dev_inst_map[img_mode]
+ ->my_index;
+ pcam_inst = pcam->mctl_node.dev_inst[idx];
+ D("%s Found instance %p in mctl node device\n",
+ __func__, pcam_inst);
+ } else if (pcam->dev_inst_map[img_mode]) {
+ idx = pcam->dev_inst_map[img_mode]->my_index;
+ pcam_inst = pcam->dev_inst[idx];
+ D("%s Found instance %p in video device\n",
__func__, pcam_inst);
- } else if (pcam->dev_inst_map[img_mode]) {
- idx = pcam->dev_inst_map[img_mode]->my_index;
- pcam_inst = pcam->dev_inst[idx];
- D("%s Found instance %p in video device\n",
+ }
+ } else if (img_mode == MSM_V4L2_EXT_CAPTURE_MODE_V2X_LIVESHOT) {
+ img_mode = MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+ if (pcam->mctl_node.dev_inst_map[img_mode] &&
+ is_buffer_queued(pcam, img_mode)) {
+ idx = pcam->mctl_node.dev_inst_map[img_mode]
+ ->my_index;
+ pcam_inst = pcam->mctl_node.dev_inst[idx];
+ D("%s Found instance %p in mctl node device\n",
+ __func__, pcam_inst);
+ } else if (pcam->dev_inst_map[img_mode]) {
+ idx = pcam->dev_inst_map[img_mode]->my_index;
+ pcam_inst = pcam->dev_inst[idx];
+ D("%s Found instance %p in video device\n",
__func__, pcam_inst);
+ }
+ } else {
+ if (pcam->mctl_node.dev_inst_map[img_mode]) {
+ idx = pcam->mctl_node.dev_inst_map[img_mode]
+ ->my_index;
+ pcam_inst = pcam->mctl_node.dev_inst[idx];
+ D("%s Found instance %p in mctl node device\n",
+ __func__, pcam_inst);
+ } else if (pcam->dev_inst_map[img_mode]) {
+ idx = pcam->dev_inst_map[img_mode]->my_index;
+ pcam_inst = pcam->dev_inst[idx];
+ D("%s Found instance %p in video device\n",
+ __func__, pcam_inst);
+ }
}
- } else {
- if (pcam->mctl_node.dev_inst_map[img_mode]) {
- idx = pcam->mctl_node.dev_inst_map[img_mode]->my_index;
- pcam_inst = pcam->mctl_node.dev_inst[idx];
- D("%s Found instance %p in mctl node device\n",
- __func__, pcam_inst);
- } else if (pcam->dev_inst_map[img_mode]) {
- idx = pcam->dev_inst_map[img_mode]->my_index;
- pcam_inst = pcam->dev_inst[idx];
- D("%s Found instance %p in video device\n",
- __func__, pcam_inst);
- }
- }
return pcam_inst;
}
@@ -805,6 +825,7 @@
__func__, pcam_inst, frame->ch_paddr[0], ret_frame->dirty);
cam_ts.present = 1;
cam_ts.timestamp = ret_frame->timestamp;
+ cam_ts.frame_id = ret_frame->frame_id;
if (ret_frame->dirty)
/* the frame is dirty, not going to disptach to app */
rc = msm_mctl_release_free_buf(pmctl, pcam_inst, frame);
@@ -898,7 +919,7 @@
meta_frame->map[i].handle);
if (ion_map_iommu(client, meta_frame->map[i].handle,
domain_num, 0, SZ_4K,
- 0, &paddr, &len, UNCACHED, 0) < 0) {
+ 0, &paddr, &len, 0, 0) < 0) {
pr_err("%s: cannot map address plane %d", __func__, i);
ion_free(client, meta_frame->map[i].handle);
/* Roll back previous plane mappings, if any */
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index a114b37..7155d4c 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -636,6 +636,9 @@
ret_frame.dirty = dirty;
ret_frame.node_type = 0;
ret_frame.timestamp = frame.timestamp;
+ ret_frame.frame_id = frame.frame_id;
+ D("%s frame_id: %d buffer idx %d\n", __func__,
+ frame.frame_id, frame.buf_idx);
rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, &ret_frame);
return rc;
}
@@ -678,6 +681,7 @@
ret_frame.dirty = 0;
ret_frame.node_type = frame.node_type;
ret_frame.timestamp = frame.timestamp;
+ ret_frame.frame_id = frame.frame_id;
D("%s Frame done id: %d\n", __func__, frame.frame_id);
rc = msm_mctl_buf_done_pp(p_mctl, &buf_handle, &buf, &ret_frame);
return rc;
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index 5136d9d..1875df2 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -136,7 +136,7 @@
if (IS_ERR_OR_NULL(region->handle))
goto out1;
if (ion_map_iommu(client, region->handle, domain_num, 0,
- SZ_4K, 0, &paddr, &len, UNCACHED, 0) < 0)
+ SZ_4K, 0, &paddr, &len, 0, 0) < 0)
goto out2;
#elif CONFIG_ANDROID_PMEM
rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index cd228a1..a70a632 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_OV8825) += ov8825_v4l2.o
obj-$(CONFIG_IMX074) += imx074_v4l2.o
obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
+obj-$(CONFIG_IMX135) += imx135_v4l2.o
obj-$(CONFIG_OV2720) += ov2720.o
obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
diff --git a/drivers/media/video/msm/sensors/imx135_v4l2.c b/drivers/media/video/msm/sensors/imx135_v4l2.c
new file mode 100644
index 0000000..f480923
--- /dev/null
+++ b/drivers/media/video/msm/sensors/imx135_v4l2.c
@@ -0,0 +1,553 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_sensor.h"
+#define SENSOR_NAME "imx135"
+#define PLATFORM_DRIVER_NAME "msm_camera_imx135"
+#define imx135_obj imx135_##obj
+
+DEFINE_MUTEX(imx135_mut);
+static struct msm_sensor_ctrl_t imx135_s_ctrl;
+
+static struct msm_camera_i2c_reg_conf imx135_start_settings[] = {
+ {0x0100, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf imx135_stop_settings[] = {
+ {0x0100, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf imx135_groupon_settings[] = {
+ {0x104, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf imx135_groupoff_settings[] = {
+ {0x104, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf imx135_recommend_settings[] = {
+/* Recommended global settings */
+ {0x0220, 0x01},
+ {0x3008, 0xB0},
+ {0x320A, 0x01},
+ {0x320D, 0x10},
+ {0x3216, 0x2E},
+ {0x3230, 0x0A},
+ {0x3228, 0x05},
+ {0x3229, 0x02},
+ {0x322C, 0x02},
+ {0x3302, 0x10},
+ {0x3390, 0x45},
+ {0x3409, 0x0C},
+ {0x340B, 0xF5},
+ {0x340C, 0x2D},
+ {0x3412, 0x41},
+ {0x3413, 0xAD},
+ {0x3414, 0x1E},
+ {0x3427, 0x04},
+ {0x3480, 0x1E},
+ {0x3484, 0x1E},
+ {0x3488, 0x1E},
+ {0x348C, 0x1E},
+ {0x3490, 0x1E},
+ {0x3494, 0x1E},
+ {0x349C, 0x38},
+ {0x34A3, 0x38},
+ {0x3511, 0x8F},
+ {0x3518, 0x00},
+ {0x3519, 0x94},
+ {0x3833, 0x20},
+ {0x3893, 0x01},
+ {0x38C2, 0x08},
+ {0x3C09, 0x01},
+ {0x4300, 0x00},
+ {0x4316, 0x12},
+ {0x4317, 0x22},
+ {0x431A, 0x00},
+ {0x4324, 0x03},
+ {0x4325, 0x20},
+ {0x4326, 0x03},
+ {0x4327, 0x84},
+ {0x4328, 0x03},
+ {0x4329, 0x20},
+ {0x432A, 0x03},
+ {0x432B, 0x84},
+ {0x4401, 0x3F},
+ {0x4412, 0x3F},
+ {0x4413, 0xFF},
+ {0x4446, 0x3F},
+ {0x4447, 0xFF},
+ {0x4452, 0x00},
+ {0x4453, 0xA0},
+ {0x4454, 0x08},
+ {0x4455, 0x00},
+ {0x4458, 0x18},
+ {0x4459, 0x18},
+ {0x445A, 0x3F},
+ {0x445B, 0x3A},
+ {0x4463, 0x00},
+ {0x4465, 0x00},
+ {0x446E, 0x01},
+/* Image Quality Settings */
+/* Bypass Settings */
+ {0x4203, 0x48},
+/* Defect Correction Recommended Setting */
+ {0x4100, 0xE0},
+ {0x4102, 0x0B},
+/* RGB Filter Recommended Setting */
+ {0x4281, 0x22},
+ {0x4282, 0x82},
+ {0x4284, 0x00},
+ {0x4287, 0x18},
+ {0x4288, 0x00},
+ {0x428B, 0x1E},
+ {0x428C, 0x00},
+ {0x428F, 0x08},
+/* DLC/ADP Recommended Setting */
+ {0x4207, 0x00},
+ {0x4218, 0x02},
+ {0x421B, 0x00},
+ {0x4222, 0x04},
+ {0x4223, 0x44},
+ {0x4224, 0x46},
+ {0x4225, 0xFF},
+ {0x4226, 0x14},
+ {0x4227, 0xF2},
+ {0x4228, 0xFC},
+ {0x4229, 0x60},
+ {0x422A, 0xFA},
+ {0x422B, 0xFE},
+ {0x422C, 0xFE},
+/* Color Artifact Recommended Setting */
+ {0x4243, 0xAA}
+};
+
+/* IMX135 mode 1/2 HV at 24MHz */
+static struct msm_camera_i2c_reg_conf imx135_prev_settings[] = {
+/* Clock Setting */
+ {0x011E, 0x18},
+ {0x011F, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x0B},
+ {0x0305, 0x03},
+ {0x0306, 0x01},
+ {0x0307, 0x5E},
+ {0x0309, 0x05},
+ {0x030B, 0x02},
+ {0x030C, 0x00},
+ {0x030D, 0x71},
+ {0x030E, 0x01},
+ {0x3A06, 0x12},
+/* Mode setting */
+ {0x0101, 0x00},
+ {0x0105, 0x00},
+ {0x0108, 0x03},
+ {0x0109, 0x30},
+ {0x010B, 0x32},
+ {0x0112, 0x0A},
+ {0x0113, 0x0A},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x0390, 0x01}, /* binning_en = 1 */
+ {0x0391, 0x22}, /* binning_type */
+ {0x0392, 0x00}, /* binning_mode = 0 (average) */
+ {0x0401, 0x00},
+ {0x0404, 0x00},
+ {0x0405, 0x10},
+ {0x4083, 0x01},
+/* Size setting*/
+ {0x0340, 0x0A}, /* frame_length_lines = 2680*/
+ {0x0341, 0x78},
+ {0x034C, 0x08},
+ {0x034D, 0x38},
+ {0x034E, 0x06},
+ {0x034F, 0x18},
+ {0x0354, 0x08},
+ {0x0355, 0x38},
+ {0x0356, 0x06},
+ {0x0357, 0x18},
+ {0x3310, 0x08},
+ {0x3311, 0x38},
+ {0x3312, 0x06},
+ {0x3313, 0x18},
+ {0x331C, 0x02},
+ {0x331D, 0xC0},
+ {0x33B0, 0x04},
+ {0x33B1, 0x00},
+ {0x33B3, 0x00},
+ {0x7006, 0x04},
+/* Global Timing Setting */
+ {0x0830, 0x67},
+ {0x0831, 0x27},
+ {0x0832, 0x47},
+ {0x0833, 0x27},
+ {0x0834, 0x27},
+ {0x0835, 0x1F},
+ {0x0836, 0x87},
+ {0x0837, 0x2F},
+ {0x0839, 0x1F},
+ {0x083A, 0x17},
+ {0x083B, 0x02},
+/* Integration Time Setting */
+ {0x0254, 0x00},
+/* Gain Setting */
+ {0x0205, 0x33}
+};
+
+/* IMX135 Mode Fullsize at 24MHz */
+static struct msm_camera_i2c_reg_conf imx135_snap_settings[] = {
+/* Clock Setting */
+ {0x011E, 0x18},
+ {0x011F, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x0B},
+ {0x0305, 0x03},
+ {0x0306, 0x01},
+ {0x0307, 0x5E},
+ {0x0309, 0x05},
+ {0x030B, 0x01},
+ {0x030C, 0x00},
+ {0x030D, 0x60}, /* pll_multiplier = 96 */
+ {0x030E, 0x01},
+ {0x3A06, 0x11},
+/* Mode setting */
+ {0x0101, 0x00},
+ {0x0105, 0x00},
+ {0x0108, 0x03},
+ {0x0109, 0x30},
+ {0x010B, 0x32},
+ {0x0112, 0x0A},
+ {0x0113, 0x0A},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x0390, 0x00},
+ {0x0391, 0x11},
+ {0x0392, 0x00},
+ {0x0401, 0x00},
+ {0x0404, 0x00},
+ {0x0405, 0x10},
+ {0x4083, 0x01},
+/* Size setting */
+ {0x0340, 0x0C},
+ {0x0341, 0x46},
+ {0x034C, 0x10},
+ {0x034D, 0x70},
+ {0x034E, 0x0C},
+ {0x034F, 0x30},
+ {0x0354, 0x10},
+ {0x0355, 0x70},
+ {0x0356, 0x0C},
+ {0x0357, 0x30},
+ {0x3310, 0x10},
+ {0x3311, 0x70},
+ {0x3312, 0x0C},
+ {0x3313, 0x30},
+ {0x331C, 0x06},
+ {0x331D, 0x00},
+ {0x33B0, 0x04},
+ {0x33B1, 0x00},
+ {0x33B3, 0x00},
+ {0x7006, 0x04},
+/* Global Timing Setting */
+ {0x0830, 0x7F},
+ {0x0831, 0x37},
+ {0x0832, 0x5F},
+ {0x0833, 0x37},
+ {0x0834, 0x37},
+ {0x0835, 0x3F},
+ {0x0836, 0xC7},
+ {0x0837, 0x3F},
+ {0x0839, 0x1F},
+ {0x083A, 0x17},
+ {0x083B, 0x02},
+/* Integration Time Setting */
+ {0x0250, 0x0B},
+/* Gain Setting */
+ {0x0205, 0x33}
+};
+
+
+static struct msm_camera_i2c_reg_conf imx135_hdr_settings[] = {
+/* Clock Setting */
+ {0x011E, 0x18},
+ {0x011F, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x0B},
+ {0x0305, 0x03},
+ {0x0306, 0x01},
+ {0x0307, 0x5E},
+ {0x0309, 0x05},
+ {0x030B, 0x02},
+ {0x030C, 0x00},
+ {0x030D, 0x71},
+ {0x030E, 0x01},
+ {0x3A06, 0x12},
+/* Mode setting */
+ {0x0101, 0x00},
+ {0x0105, 0x00},
+ {0x0108, 0x03},
+ {0x0109, 0x30},
+ {0x010B, 0x32},
+ {0x0112, 0x0E},
+ {0x0113, 0x0A},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x0390, 0x00},
+ {0x0391, 0x11},
+ {0x0392, 0x00},
+ {0x0401, 0x00},
+ {0x0404, 0x00},
+ {0x0405, 0x10},
+ {0x4083, 0x01},
+/* Size setting */
+ {0x0340, 0x0C},
+ {0x0341, 0x48},
+ {0x034C, 0x08},
+ {0x034D, 0x38},
+ {0x034E, 0x06},
+ {0x034F, 0x18},
+ {0x0354, 0x08},
+ {0x0355, 0x38},
+ {0x0356, 0x06},
+ {0x0357, 0x18},
+ {0x3310, 0x08},
+ {0x3311, 0x38},
+ {0x3312, 0x06},
+ {0x3313, 0x18},
+ {0x331C, 0x02},
+ {0x331D, 0xA0},
+ {0x33B0, 0x08},
+ {0x33B1, 0x38},
+ {0x33B3, 0x01},
+ {0x7006, 0x04},
+/* Global Timing Setting */
+ {0x0830, 0x67},
+ {0x0831, 0x27},
+ {0x0832, 0x47},
+ {0x0833, 0x27},
+ {0x0834, 0x27},
+ {0x0835, 0x1F},
+ {0x0836, 0x87},
+ {0x0837, 0x2F},
+ {0x0839, 0x1F},
+ {0x083A, 0x17},
+ {0x083B, 0x02},
+/* Integration Time Setting */
+ {0x0250, 0x0B},
+/* Gain Setting */
+ {0x0205, 0x33}
+};
+
+static struct v4l2_subdev_info imx135_subdev_info[] = {
+ {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ },
+ /* more can be supported, to be added later */
+};
+
+static struct msm_camera_i2c_conf_array imx135_init_conf[] = {
+ {&imx135_recommend_settings[0],
+ ARRAY_SIZE(imx135_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+static struct msm_camera_i2c_conf_array imx135_confs[] = {
+ {&imx135_snap_settings[0],
+ ARRAY_SIZE(imx135_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&imx135_prev_settings[0],
+ ARRAY_SIZE(imx135_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&imx135_hdr_settings[0],
+ ARRAY_SIZE(imx135_hdr_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+};
+
+static struct msm_sensor_output_info_t imx135_dimensions[] = {
+ /* RES0 snapshot(FULL SIZE) */
+ {
+ .x_output = 4208,
+ .y_output = 3120,
+ .line_length_pclk = 4572,
+ .frame_length_lines = 3142,
+ .vt_pixel_clk = 307200000,
+ .op_pixel_clk = 307200000,
+ .binning_factor = 1,
+ },
+ /* RES1 4:3 preview(1/2HV QTR SIZE) */
+ {
+ .x_output = 2104,
+ .y_output = 1560,
+ .line_length_pclk = 4572,
+ .frame_length_lines = 2680,
+ .vt_pixel_clk = 361600000,
+ .op_pixel_clk = 180800000,
+ .binning_factor = 1,
+ },
+ /* RES2 4:3 HDR movie mode */
+ {
+ .x_output = 2104,
+ .y_output = 1560,
+ .line_length_pclk = 4572,
+ .frame_length_lines = 3144,
+ .vt_pixel_clk = 361600000,
+ .op_pixel_clk = 180800000,
+ .binning_factor = 1,
+ },
+};
+
+static struct msm_sensor_output_reg_addr_t imx135_reg_addr = {
+ .x_output = 0x34C,
+ .y_output = 0x34E,
+ .line_length_pclk = 0x342,
+ .frame_length_lines = 0x340,
+};
+
+static struct msm_sensor_id_info_t imx135_id_info = {
+ .sensor_id_reg_addr = 0x0000,
+ .sensor_id = 0x0087,
+};
+
+static struct msm_sensor_exp_gain_info_t imx135_exp_gain_info = {
+ .coarse_int_time_addr = 0x202,
+ .global_gain_addr = 0x205,
+ .vert_offset = 4,
+};
+
+static const struct i2c_device_id imx135_i2c_id[] = {
+ {SENSOR_NAME, (kernel_ulong_t)&imx135_s_ctrl},
+ { }
+};
+
+static struct i2c_driver imx135_i2c_driver = {
+ .id_table = imx135_i2c_id,
+ .probe = msm_sensor_i2c_probe,
+ .driver = {
+ .name = SENSOR_NAME,
+ },
+};
+
+static struct msm_camera_i2c_client imx135_sensor_i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+ return i2c_add_driver(&imx135_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops imx135_subdev_core_ops = {
+ .ioctl = msm_sensor_subdev_ioctl,
+ .s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops imx135_subdev_video_ops = {
+ .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops imx135_subdev_ops = {
+ .core = &imx135_subdev_core_ops,
+ .video = &imx135_subdev_video_ops,
+};
+
+int32_t imx135_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t gain, uint32_t line)
+{
+ uint32_t fl_lines;
+ uint8_t offset;
+ fl_lines = s_ctrl->curr_frame_length_lines;
+ fl_lines = (fl_lines * s_ctrl->fps_divider) / Q10;
+ offset = s_ctrl->sensor_exp_gain_info->vert_offset;
+ if (line > (fl_lines - offset))
+ fl_lines = line + offset;
+
+ s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines, fl_lines,
+ MSM_CAMERA_I2C_WORD_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, line,
+ MSM_CAMERA_I2C_WORD_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->global_gain_addr, gain,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+ return 0;
+}
+
+static struct msm_sensor_fn_t imx135_func_tbl = {
+ .sensor_start_stream = msm_sensor_start_stream,
+ .sensor_stop_stream = msm_sensor_stop_stream,
+ .sensor_group_hold_on = msm_sensor_group_hold_on,
+ .sensor_group_hold_off = msm_sensor_group_hold_off,
+ .sensor_set_fps = msm_sensor_set_fps,
+ .sensor_write_exp_gain = imx135_write_exp_gain,
+ .sensor_write_snapshot_exp_gain = imx135_write_exp_gain,
+ .sensor_setting = msm_sensor_setting,
+ .sensor_csi_setting = msm_sensor_setting1,
+ .sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
+ .sensor_mode_init = msm_sensor_mode_init,
+ .sensor_get_output_info = msm_sensor_get_output_info,
+ .sensor_config = msm_sensor_config,
+ .sensor_power_up = msm_sensor_power_up,
+ .sensor_power_down = msm_sensor_power_down,
+ .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines1,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
+};
+
+static struct msm_sensor_reg_t imx135_regs = {
+ .default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+ .start_stream_conf = imx135_start_settings,
+ .start_stream_conf_size = ARRAY_SIZE(imx135_start_settings),
+ .stop_stream_conf = imx135_stop_settings,
+ .stop_stream_conf_size = ARRAY_SIZE(imx135_stop_settings),
+ .group_hold_on_conf = imx135_groupon_settings,
+ .group_hold_on_conf_size = ARRAY_SIZE(imx135_groupon_settings),
+ .group_hold_off_conf = imx135_groupoff_settings,
+ .group_hold_off_conf_size =
+ ARRAY_SIZE(imx135_groupoff_settings),
+ .init_settings = &imx135_init_conf[0],
+ .init_size = ARRAY_SIZE(imx135_init_conf),
+ .mode_settings = &imx135_confs[0],
+ .output_settings = &imx135_dimensions[0],
+ .num_conf = ARRAY_SIZE(imx135_confs),
+};
+
+static struct msm_sensor_ctrl_t imx135_s_ctrl = {
+ .msm_sensor_reg = &imx135_regs,
+ .sensor_i2c_client = &imx135_sensor_i2c_client,
+ .sensor_i2c_addr = 0x20,
+ .sensor_output_reg_addr = &imx135_reg_addr,
+ .sensor_id_info = &imx135_id_info,
+ .sensor_exp_gain_info = &imx135_exp_gain_info,
+ .cam_mode = MSM_SENSOR_MODE_INVALID,
+ .msm_sensor_mutex = &imx135_mut,
+ .sensor_i2c_driver = &imx135_i2c_driver,
+ .sensor_v4l2_subdev_info = imx135_subdev_info,
+ .sensor_v4l2_subdev_info_size = ARRAY_SIZE(imx135_subdev_info),
+ .sensor_v4l2_subdev_ops = &imx135_subdev_ops,
+ .func_tbl = &imx135_func_tbl,
+ .clk_rate = MSM_SENSOR_MCLK_24HZ,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Sony 13MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index f5c9a73..63cf38e 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -1143,18 +1143,6 @@
sensordata->pdata[i].csid_core);
}
- rc = of_property_read_u32_array(of_node, "qcom,is-vpe", val_array,
- count);
- if (rc < 0) {
- pr_err("%s failed %d\n", __func__, __LINE__);
- goto ERROR2;
- }
- for (i = 0; i < count; i++) {
- sensordata->pdata[i].is_vpe = val_array[i];
- CDBG("%s csi_data[%d].is_vpe = %d\n", __func__, i,
- sensordata->pdata[i].is_vpe);
- }
-
pinfo->csi_lane_params = kzalloc(
sizeof(struct msm_camera_csi_lane_params), GFP_KERNEL);
if (!pinfo->csi_lane_params) {
diff --git a/drivers/media/video/msm/sensors/mt9m114_v4l2.c b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
index cba9538..c952f7b 100644
--- a/drivers/media/video/msm/sensors/mt9m114_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1219,11 +1219,52 @@
.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
};
+static const struct of_device_id mt9m114_dt_match[] = {
+ {.compatible = "qcom,mt9m114", .data = &mt9m114_s_ctrl},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, mt9m114_dt_match);
+
+static struct platform_driver mt9m114_platform_driver = {
+ .driver = {
+ .name = "qcom,mt9m114",
+ .owner = THIS_MODULE,
+ .of_match_table = mt9m114_dt_match,
+ },
+};
+
+static int32_t mt9m114_platform_probe(struct platform_device *pdev)
+{
+ int32_t rc = 0;
+ const struct of_device_id *match;
+ match = of_match_device(mt9m114_dt_match, &pdev->dev);
+ rc = msm_sensor_platform_probe(pdev, match->data);
+ return rc;
+}
+
static int __init msm_sensor_init_module(void)
{
+ int32_t rc = 0;
+ rc = platform_driver_probe(&mt9m114_platform_driver,
+ mt9m114_platform_probe);
+ if (!rc)
+ return rc;
return i2c_add_driver(&mt9m114_i2c_driver);
}
+
+static void __exit msm_sensor_exit_module(void)
+{
+ if (mt9m114_s_ctrl.pdev) {
+ msm_sensor_free_sensor_data(&mt9m114_s_ctrl);
+ platform_driver_unregister(&mt9m114_platform_driver);
+ } else {
+ i2c_del_driver(&mt9m114_i2c_driver);
+ }
+ return;
+}
+
static struct v4l2_subdev_core_ops mt9m114_subdev_core_ops = {
.s_ctrl = msm_sensor_v4l2_s_ctrl,
.queryctrl = msm_sensor_v4l2_query_ctrl,
@@ -1286,5 +1327,6 @@
};
module_init(msm_sensor_init_module);
+module_exit(msm_sensor_exit_module);
MODULE_DESCRIPTION("Aptina 1.26MP YUV sensor driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index 6a2372e..0bd625c 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -442,6 +442,43 @@
{0x0B00, 0x00},
};
+static struct msm_camera_i2c_reg_conf s5k3l1yx_19mhz_prev_settings[] = {
+ {0x0501, 0x00}, /* compression_algorithim_L(1d) */
+ {0x0112, 0x0A}, /* CCP_data_format_H */
+ {0x0113, 0x0A}, /* CCP_data_format_L raw8=0808 ,DCPM10 -->8= 0A08 */
+ {0x0306, 0x00}, /* pll_multiplier */
+ {0x0307, 0xCE}, /* pll_multiplier */
+ {0x0202, 0x06}, /* coarse_integration_time */
+ {0x0203, 0x00}, /* coarse_integration_time */
+ {0x0340, 0x09}, /* frame_length_lines */
+ {0x0341, 0x6C}, /* frame_length_lines */
+ {0x0342, 0x11}, /* line_length_pck */
+ {0x0343, 0x80}, /* line_length_pck */
+ {0x0344, 0x00}, /* x_addr_start */
+ {0x0345, 0x18}, /* x_addr_start */
+ {0x0346, 0x00}, /* y_addr_start */
+ {0x0347, 0x00}, /* y_addr_start */
+ {0x0348, 0x0F}, /* x_addr_end */
+ {0x0349, 0x97}, /* x_addr_end */
+ {0x034A, 0x0B}, /* y_addr_end */
+ {0x034B, 0xC7}, /* y_addr_end */
+ {0x034C, 0x07}, /* x_output_size */
+ {0x034D, 0xC0}, /* x_output_size */
+ {0x034E, 0x05}, /* y_output_size */
+ {0x034F, 0xE4}, /* y_output_size */
+ {0x0380, 0x00}, /* x_even_inc */
+ {0x0381, 0x01}, /* x_even_inc */
+ {0x0382, 0x00}, /* x_odd_inc */
+ {0x0383, 0x03}, /* x_odd_inc */
+ {0x0384, 0x00}, /* y_even_inc */
+ {0x0385, 0x01}, /* y_even_inc */
+ {0x0386, 0x00}, /* y_odd_inc */
+ {0x0387, 0x03}, /* y_odd_inc */
+ {0x0900, 0x01}, /* binning_mode */
+ {0x0901, 0x22}, /* binning_type */
+ {0x0902, 0x01}, /* binning_weighting */
+};
+
static struct v4l2_subdev_info s5k3l1yx_subdev_info[] = {
{
.code = V4L2_MBUS_FMT_SBGGR10_1X10,
@@ -471,6 +508,8 @@
MSM_CAMERA_I2C_BYTE_DATA},
{&s5k3l1yx_dpcm_settings[0],
ARRAY_SIZE(s5k3l1yx_dpcm_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&s5k3l1yx_19mhz_prev_settings[0],
+ ARRAY_SIZE(s5k3l1yx_19mhz_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
};
static struct msm_sensor_output_info_t s5k3l1yx_dimensions[] = {
@@ -534,6 +573,16 @@
.op_pixel_clk = 320000000,
.binning_factor = 1,
},
+ /* 30 fps preview with 19.2 input clock*/
+ {
+ .x_output = 1984,
+ .y_output = 1508,
+ .line_length_pclk = 4480,
+ .frame_length_lines = 2412,
+ .vt_pixel_clk = 330000000,
+ .op_pixel_clk = 264000000,
+ .binning_factor = 1,
+ },
};
static struct msm_sensor_output_reg_addr_t s5k3l1yx_reg_addr = {
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 74dd3f2..84aaa69 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -311,7 +311,7 @@
if (command->length > 0) {
command->value =
g_server_dev.server_queue[command->queue_idx].ctrl_data;
- if (command->length > max_control_command_size) {
+ if (command->length > MAX_SERVER_PAYLOAD_LENGTH) {
pr_err("%s: user data %d is too big (max %d)\n",
__func__, command->length,
max_control_command_size);
@@ -476,20 +476,22 @@
struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
{
struct msm_ctrl_cmd ctrlcmd;
- void *temp_data;
+ void *temp_data = NULL;
int rc;
- temp_data = kzalloc(ioctl_ptr->len, GFP_KERNEL);
- if (!temp_data) {
- pr_err("%s could not allocate memory\n", __func__);
- rc = -ENOMEM;
- goto end;
- }
- if (copy_from_user((void *)temp_data,
- (void __user *)ioctl_ptr->ioctl_ptr,
- ioctl_ptr->len)) {
- ERR_COPY_FROM_USER();
- rc = -EFAULT;
- goto copy_from_user_failed;
+ if (ioctl_ptr->len > 0) {
+ temp_data = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+ if (!temp_data) {
+ pr_err("%s could not allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+ if (copy_from_user((void *)temp_data,
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ ioctl_ptr->len)) {
+ ERR_COPY_FROM_USER();
+ rc = -EFAULT;
+ goto copy_from_user_failed;
+ }
}
mutex_lock(&pcam->vid_lock);
@@ -505,6 +507,16 @@
rc = msm_server_control(&g_server_dev, 0, &ctrlcmd);
if (rc < 0)
pr_err("%s: send event failed\n", __func__);
+ else {
+ if (ioctl_ptr->len > 0) {
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+ (void *)temp_data,
+ ioctl_ptr->len)) {
+ ERR_COPY_TO_USER();
+ rc = -EFAULT;
+ }
+ }
+ }
mutex_unlock(&pcam->vid_lock);
kfree(temp_data);
@@ -1519,7 +1531,12 @@
pcam->server_queue_idx = server_q_idx;
queue = &g_server_dev.server_queue[server_q_idx];
queue->ctrl_data = kzalloc(sizeof(uint8_t) *
- max_control_command_size, GFP_KERNEL);
+ MAX_SERVER_PAYLOAD_LENGTH, GFP_KERNEL);
+ if (queue->ctrl_data == NULL) {
+ pr_err("%s: Could not allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto error;
+ }
msm_queue_init(&queue->ctrl_q, "control");
msm_queue_init(&queue->eventData_q, "eventdata");
queue->queue_active = 1;
@@ -2523,7 +2540,11 @@
*p_qidx = server_q_idx;
queue = &g_server_dev.server_queue[server_q_idx];
queue->ctrl_data = kzalloc(sizeof(uint8_t) *
- max_control_command_size, GFP_KERNEL);
+ MAX_SERVER_PAYLOAD_LENGTH, GFP_KERNEL);
+ if (!queue->ctrl_data) {
+ pr_err("%s: Could not find memory\n", __func__);
+ return -ENOMEM;
+ }
msm_queue_init(&queue->ctrl_q, "control");
msm_queue_init(&queue->eventData_q, "eventdata");
queue->queue_active = 1;
diff --git a/drivers/media/video/msm/vfe/msm_vfe32.c b/drivers/media/video/msm/vfe/msm_vfe32.c
index 6e22388..db0db36 100644
--- a/drivers/media/video/msm/vfe/msm_vfe32.c
+++ b/drivers/media/video/msm/vfe/msm_vfe32.c
@@ -587,6 +587,25 @@
atomic_set(&share_ctrl->handle_common_irq, 1);
}
+static void axi_clear_all_interrupts(struct vfe_share_ctrl_t *share_ctrl)
+{
+ atomic_set(&share_ctrl->handle_common_irq, 0);
+ msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+ share_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
+ share_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* clear all pending interrupts*/
+ msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+ share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
+ share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ /* Ensure the write order while writing
+ *to the command register using the barrier */
+ msm_camera_io_w_mb(1,
+ share_ctrl->vfebase + VFE_IRQ_CMD);
+}
+
static void axi_disable_irq(struct vfe_share_ctrl_t *share_ctrl,
uint32_t mode)
{
@@ -632,24 +651,6 @@
msm_camera_io_w(irq_mask, share_ctrl->vfebase +
VFE_IRQ_MASK_0);
}
- /*Dont Disable for concurrent*/
- if (share_ctrl->axi_ref_cnt == 1) {
- atomic_set(&share_ctrl->handle_common_irq, 0);
- msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- share_ctrl->vfebase + VFE_IRQ_MASK_0);
- msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- share_ctrl->vfebase + VFE_IRQ_MASK_1);
-
- /* clear all pending interrupts*/
- msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
- msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
- /* Ensure the write order while writing
- *to the command register using the barrier */
- msm_camera_io_w_mb(1,
- share_ctrl->vfebase + VFE_IRQ_CMD);
- }
}
static void vfe32_stop(struct vfe32_ctrl_type *vfe32_ctrl)
@@ -5554,6 +5555,8 @@
axi_ctrl->share_ctrl->axi_ref_cnt--;
if (axi_ctrl->share_ctrl->axi_ref_cnt > 0)
return;
+
+ axi_clear_all_interrupts(axi_ctrl->share_ctrl);
axi_ctrl->share_ctrl->dual_enabled = 0;
disable_irq(axi_ctrl->vfeirq->start);
tasklet_kill(&axi_ctrl->vfe32_tasklet);
diff --git a/drivers/media/video/msm/vfe/msm_vfe40.c b/drivers/media/video/msm/vfe/msm_vfe40.c
index e958241..9ffa874 100644
--- a/drivers/media/video/msm/vfe/msm_vfe40.c
+++ b/drivers/media/video/msm/vfe/msm_vfe40.c
@@ -4615,19 +4615,19 @@
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS0_STATS_CS);
- if (qcmd->vfeInterruptStatus0 &
+ if (qcmd->vfeInterruptStatus1 &
VFE_IRQ_STATUS1_SYNC_TIMER0)
v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS1_SYNC_TIMER0);
- if (qcmd->vfeInterruptStatus0 &
+ if (qcmd->vfeInterruptStatus1 &
VFE_IRQ_STATUS1_SYNC_TIMER1)
v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
(void *)VFE_IRQ_STATUS1_SYNC_TIMER1);
- if (qcmd->vfeInterruptStatus0 &
+ if (qcmd->vfeInterruptStatus1 &
VFE_IRQ_STATUS1_SYNC_TIMER2)
v4l2_subdev_notify(&vfe40_ctrl->subdev,
NOTIFY_VFE_IRQ,
diff --git a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
index 9deae65..6440b8e 100644
--- a/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/vfe/msm_vfe7x27a_v4l2.c
@@ -836,7 +836,12 @@
kfree(data);
return;
}
- free_buf = vfe2x_check_free_buffer(
+ if (vfe2x_ctrl->liveshot_enabled)
+ free_buf = vfe2x_check_free_buffer(
+ VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_V2X_LIVESHOT_PRIMARY);
+ else
+ free_buf = vfe2x_check_free_buffer(
VFE_MSG_OUTPUT_IRQ,
VFE_MSG_OUTPUT_PRIMARY);
CDBG("free_buf = %x\n",
@@ -1353,12 +1358,14 @@
vfe2x_subdev_notify(id, path);
if (op_mode & SNAPSHOT_MASK_MODE) {
- if (path == VFE_MSG_OUTPUT_PRIMARY)
+ if (path == VFE_MSG_OUTPUT_PRIMARY ||
+ path == VFE_MSG_V2X_LIVESHOT_PRIMARY)
outch = &vfe2x_ctrl->snap;
else if (path == VFE_MSG_OUTPUT_SECONDARY)
outch = &vfe2x_ctrl->thumb;
} else {
- if (path == VFE_MSG_OUTPUT_PRIMARY) {
+ if (path == VFE_MSG_OUTPUT_PRIMARY ||
+ path == VFE_MSG_V2X_LIVESHOT_PRIMARY) {
if (vfe2x_ctrl->zsl_mode)
outch = &vfe2x_ctrl->zsl_prim;
else
@@ -1380,12 +1387,14 @@
vfe2x_subdev_notify(id, path);
CDBG("Opmode = %d\n", op_mode);
if (op_mode & SNAPSHOT_MASK_MODE) {
- if (path == VFE_MSG_OUTPUT_PRIMARY)
+ if (path == VFE_MSG_OUTPUT_PRIMARY ||
+ path == VFE_MSG_V2X_LIVESHOT_PRIMARY)
outch = &vfe2x_ctrl->snap;
else if (path == VFE_MSG_OUTPUT_SECONDARY)
outch = &vfe2x_ctrl->thumb;
} else {
- if (path == VFE_MSG_OUTPUT_PRIMARY) {
+ if (path == VFE_MSG_OUTPUT_PRIMARY ||
+ path == VFE_MSG_V2X_LIVESHOT_PRIMARY) {
if (vfe2x_ctrl->zsl_mode)
outch = &vfe2x_ctrl->zsl_prim;
else
@@ -1413,10 +1422,12 @@
if (op_mode & SNAPSHOT_MASK_MODE) {
if (path == VFE_MSG_OUTPUT_SECONDARY)
ch = &vfe2x_ctrl->thumb;
- else if (path == VFE_MSG_OUTPUT_PRIMARY)
+ else if (path == VFE_MSG_OUTPUT_PRIMARY ||
+ path == VFE_MSG_V2X_LIVESHOT_PRIMARY)
ch = &vfe2x_ctrl->snap;
} else {
- if (path == VFE_MSG_OUTPUT_PRIMARY) {
+ if (path == VFE_MSG_OUTPUT_PRIMARY ||
+ path == VFE_MSG_V2X_LIVESHOT_PRIMARY) {
if (vfe2x_ctrl->zsl_mode)
ch = &vfe2x_ctrl->zsl_prim;
else
diff --git a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
index a813e09..36f8b11 100644
--- a/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
+++ b/drivers/media/video/msm/vfe/msm_vfe_stats_buf.c
@@ -221,7 +221,7 @@
}
if (ion_map_iommu(client, stats_buf->handle,
domain_num, 0, SZ_4K,
- 0, &paddr, &len, UNCACHED, 0) < 0) {
+ 0, &paddr, &len, 0, 0) < 0) {
rc = -EINVAL;
pr_err("%s: cannot map address", __func__);
goto out2;
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 156a721..3dd2193 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -24,7 +24,7 @@
static int get_device_address(struct ion_client *clnt,
struct ion_handle *hndl, int domain_num, int partition_num,
unsigned long align, unsigned long *iova,
- unsigned long *buffer_size, unsigned long flags)
+ unsigned long *buffer_size)
{
int rc;
if (!iova || !buffer_size || !hndl || !clnt) {
@@ -37,7 +37,7 @@
dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
domain_num, partition_num);
rc = ion_map_iommu(clnt, hndl, domain_num, partition_num, align,
- 0, iova, buffer_size, UNCACHED, 0);
+ 0, iova, buffer_size, 0, 0);
if (rc)
dprintk(VIDC_ERR,
"ion_map_iommu failed(%d).domain: %d,partition: %d\n",
@@ -57,7 +57,6 @@
struct msm_smem *mem)
{
struct ion_handle *hndl;
- unsigned long ionflag;
unsigned long iova = 0;
unsigned long buffer_size = 0;
int rc = 0;
@@ -68,16 +67,11 @@
rc = -ENOMEM;
goto fail_import_fd;
}
- rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to get ion flags: %d", rc);
- goto fail_map;
- }
mem->kvaddr = NULL;
mem->domain = domain;
mem->partition_num = partition;
rc = get_device_address(client->clnt, hndl, mem->domain,
- mem->partition_num, 4096, &iova, &buffer_size, ionflag);
+ mem->partition_num, 4096, &iova, &buffer_size);
if (rc) {
dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
goto fail_device_address;
@@ -92,7 +86,6 @@
return rc;
fail_device_address:
ion_unmap_kernel(client->clnt, hndl);
-fail_map:
ion_free(client->clnt, hndl);
fail_import_fd:
return rc;
@@ -106,19 +99,20 @@
unsigned long iova = 0;
unsigned long buffer_size = 0;
unsigned long ionflags = 0;
+ unsigned long heap_mask = 0;
int rc = 0;
if (flags == SMEM_CACHED)
- ionflags |= ION_SET_CACHE(CACHED);
+ ionflags = ION_SET_CACHED(ionflags);
else
- ionflags |= ION_SET_CACHE(UNCACHED);
+ ionflags = ION_SET_UNCACHED(ionflags);
- ionflags = ionflags | ION_HEAP(ION_CP_MM_HEAP_ID);
+ heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
if (align < 4096)
align = 4096;
size = (size + 4095) & (~4095);
dprintk(VIDC_DBG, "domain: %d, partition: %d\n",
domain, partition);
- hndl = ion_alloc(client->clnt, size, align, ionflags);
+ hndl = ion_alloc(client->clnt, size, align, heap_mask, ionflags);
if (IS_ERR_OR_NULL(hndl)) {
dprintk(VIDC_ERR,
"Failed to allocate shared memory = %p, %d, %d, 0x%lx\n",
@@ -131,7 +125,7 @@
mem->domain = domain;
mem->partition_num = partition;
if (map_kernel) {
- mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl);
if (!mem->kvaddr) {
dprintk(VIDC_ERR,
"Failed to map shared mem in kernel\n");
@@ -142,7 +136,7 @@
mem->kvaddr = NULL;
rc = get_device_address(client->clnt, hndl, mem->domain,
- mem->partition_num, align, &iova, &buffer_size, UNCACHED);
+ mem->partition_num, align, &iova, &buffer_size);
if (rc) {
dprintk(VIDC_ERR, "Failed to get device address: %d\n",
rc);
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 7fa4f26..fda03de 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -583,7 +583,7 @@
buffer_info.m.planes[0].reserved[0],
buffer_info.m.planes[0].reserved[1],
buffer_info.m.planes[0].length);
- rc = msm_vidc_release_buf(&v4l2_inst->vidc_inst,
+ rc = msm_vidc_release_buf(v4l2_inst->vidc_inst,
&buffer_info);
if (rc)
dprintk(VIDC_ERR,
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
index ead118d..e7b5caf 100644
--- a/drivers/media/video/msm_vidc/msm_vdec.c
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -281,7 +281,7 @@
int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
{
int rc = 0;
- struct vb2_queue *q;
+ struct buf_queue *q;
q = msm_comm_get_vb2q(inst, i);
if (!q) {
dprintk(VIDC_ERR,
@@ -289,7 +289,9 @@
return -EINVAL;
}
dprintk(VIDC_DBG, "Calling streamon\n");
- rc = vb2_streamon(q, i);
+ mutex_lock(&q->lock);
+ rc = vb2_streamon(&q->vb2_bufq, i);
+ mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
return rc;
@@ -298,7 +300,7 @@
int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
{
int rc = 0;
- struct vb2_queue *q;
+ struct buf_queue *q;
q = msm_comm_get_vb2q(inst, i);
if (!q) {
@@ -307,7 +309,9 @@
return -EINVAL;
}
dprintk(VIDC_DBG, "Calling streamoff\n");
- rc = vb2_streamoff(q, i);
+ mutex_lock(&q->lock);
+ rc = vb2_streamoff(&q->vb2_bufq, i);
+ mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
return rc;
@@ -403,7 +407,7 @@
int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
{
- struct vb2_queue *q = NULL;
+ struct buf_queue *q = NULL;
int rc = 0;
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
@@ -411,14 +415,16 @@
, b->type);
return -EINVAL;
}
- rc = vb2_qbuf(q, b);
+ mutex_lock(&q->lock);
+ rc = vb2_qbuf(&q->vb2_bufq, b);
+ mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
return rc;
}
int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
{
- struct vb2_queue *q = NULL;
+ struct buf_queue *q = NULL;
int rc = 0;
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
@@ -426,7 +432,9 @@
, b->type);
return -EINVAL;
}
- rc = vb2_dqbuf(q, b, true);
+ mutex_lock(&q->lock);
+ rc = vb2_dqbuf(&q->vb2_bufq, b, true);
+ mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_WARN, "Failed to dqbuf, %d\n", rc);
return rc;
@@ -434,7 +442,7 @@
int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
{
- struct vb2_queue *q = NULL;
+ struct buf_queue *q = NULL;
int rc = 0;
if (!inst || !b) {
dprintk(VIDC_ERR,
@@ -448,7 +456,9 @@
return -EINVAL;
}
- rc = vb2_reqbufs(q, b);
+ mutex_lock(&q->lock);
+ rc = vb2_reqbufs(&q->vb2_bufq, b);
+ mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc);
return rc;
@@ -699,7 +709,6 @@
static inline int start_streaming(struct msm_vidc_inst *inst)
{
int rc = 0;
- unsigned long flags;
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
inst->in_reconfig = false;
@@ -727,7 +736,7 @@
goto fail_start;
}
- spin_lock_irqsave(&inst->lock, flags);
+ mutex_lock(&inst->sync_lock);
if (!list_empty(&inst->pendingq)) {
list_for_each_safe(ptr, next, &inst->pendingq) {
temp = list_entry(ptr, struct vb2_buf_entry, list);
@@ -741,7 +750,7 @@
kfree(temp);
}
}
- spin_unlock_irqrestore(&inst->lock, flags);
+ mutex_unlock(&inst->sync_lock);
return rc;
fail_start:
return rc;
@@ -770,11 +779,11 @@
"Streamon called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+ if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
rc = start_streaming(inst);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+ if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
rc = start_streaming(inst);
break;
default:
@@ -797,11 +806,11 @@
dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- if (!inst->vb2_bufq[CAPTURE_PORT].streaming)
+ if (!inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
rc = stop_streaming(inst);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (!inst->vb2_bufq[OUTPUT_PORT].streaming)
+ if (!inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
rc = stop_streaming(inst);
break;
default:
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index c137c08..73a7f8b 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -444,6 +444,17 @@
(1 << L_MODE)
),
},
+ {
+ .id = V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR,
+ .name = "CodecConfig with sync frame",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -615,7 +626,9 @@
}
*num_planes = 1;
spin_lock_irqsave(&inst->lock, flags);
- *num_buffers = inst->buff_req.buffer[0].buffer_count_actual;
+ *num_buffers = inst->buff_req.buffer[0].buffer_count_actual =
+ max(*num_buffers, inst->buff_req.buffer[0].
+ buffer_count_actual);
spin_unlock_irqrestore(&inst->lock, flags);
dprintk(VIDC_DBG, "size = %d, alignment = %d, count = %d\n",
inst->buff_req.buffer[0].buffer_size,
@@ -625,7 +638,6 @@
sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
i, inst->prop.height, inst->prop.width);
}
-
break;
default:
dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
@@ -638,9 +650,9 @@
static inline int start_streaming(struct msm_vidc_inst *inst)
{
int rc = 0;
- unsigned long flags;
struct vb2_buf_entry *temp;
struct list_head *ptr, *next;
+
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -668,7 +680,7 @@
"Failed to move inst: %p to start done state\n", inst);
goto fail_start;
}
- spin_lock_irqsave(&inst->lock, flags);
+ mutex_lock(&inst->sync_lock);
if (!list_empty(&inst->pendingq)) {
list_for_each_safe(ptr, next, &inst->pendingq) {
temp = list_entry(ptr, struct vb2_buf_entry, list);
@@ -682,7 +694,7 @@
kfree(temp);
}
}
- spin_unlock_irqrestore(&inst->lock, flags);
+ mutex_unlock(&inst->sync_lock);
return rc;
fail_start:
return rc;
@@ -700,11 +712,11 @@
dprintk(VIDC_DBG, "Streamon called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+ if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
rc = start_streaming(inst);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+ if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
rc = start_streaming(inst);
break;
default:
@@ -785,6 +797,7 @@
struct hal_intra_refresh intra_refresh;
struct hal_multi_slice_control multi_slice_control;
struct hal_h264_db_control h264_db_control;
+ struct hal_enable enable;
u32 property_id = 0;
u32 property_val = 0;
void *pdata;
@@ -1204,6 +1217,12 @@
h264_db_control.slice_beta_offset = control.value;
pdata = &h264_db_control;
break;
+ case V4L2_CID_QCOM_VIDEO_SYNC_FRAME_SEQ_HDR:
+ property_id =
+ HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
+ enable.enable = control.value;
+ pdata = &enable;
+ break;
default:
break;
}
@@ -1419,7 +1438,7 @@
int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
{
- struct vb2_queue *q = NULL;
+ struct buf_queue *q = NULL;
int rc = 0;
if (!inst || !b) {
dprintk(VIDC_ERR,
@@ -1433,7 +1452,9 @@
return -EINVAL;
}
- rc = vb2_reqbufs(q, b);
+ mutex_lock(&q->lock);
+ rc = vb2_reqbufs(&q->vb2_bufq, b);
+ mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_ERR, "Failed to get reqbufs, %d\n", rc);
return rc;
@@ -1479,7 +1500,7 @@
int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
{
- struct vb2_queue *q = NULL;
+ struct buf_queue *q = NULL;
int rc = 0;
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
@@ -1487,7 +1508,9 @@
"Failed to find buffer queue for type = %d\n", b->type);
return -EINVAL;
}
- rc = vb2_qbuf(q, b);
+ mutex_lock(&q->lock);
+ rc = vb2_qbuf(&q->vb2_bufq, b);
+ mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
return rc;
@@ -1495,7 +1518,7 @@
int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
{
- struct vb2_queue *q = NULL;
+ struct buf_queue *q = NULL;
int rc = 0;
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
@@ -1503,7 +1526,9 @@
"Failed to find buffer queue for type = %d\n", b->type);
return -EINVAL;
}
- rc = vb2_dqbuf(q, b, true);
+ mutex_lock(&q->lock);
+ rc = vb2_dqbuf(&q->vb2_bufq, b, true);
+ mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
return rc;
@@ -1512,7 +1537,7 @@
int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
{
int rc = 0;
- struct vb2_queue *q;
+ struct buf_queue *q;
q = msm_comm_get_vb2q(inst, i);
if (!q) {
dprintk(VIDC_ERR,
@@ -1520,7 +1545,9 @@
return -EINVAL;
}
dprintk(VIDC_DBG, "Calling streamon\n");
- rc = vb2_streamon(q, i);
+ mutex_lock(&q->lock);
+ rc = vb2_streamon(&q->vb2_bufq, i);
+ mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
return rc;
@@ -1529,7 +1556,7 @@
int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
{
int rc = 0;
- struct vb2_queue *q;
+ struct buf_queue *q;
q = msm_comm_get_vb2q(inst, i);
if (!q) {
dprintk(VIDC_ERR,
@@ -1537,7 +1564,9 @@
return -EINVAL;
}
dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i);
- rc = vb2_streamoff(q, i);
+ mutex_lock(&q->lock);
+ rc = vb2_streamoff(&q->vb2_bufq, i);
+ mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
return rc;
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index ec9dac8..8ff7714 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -27,8 +27,8 @@
static int get_poll_flags(void *instance)
{
struct msm_vidc_inst *inst = instance;
- struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
- struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
+ struct vb2_queue *outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+ struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
struct vb2_buffer *out_vb = NULL;
struct vb2_buffer *cap_vb = NULL;
unsigned long flags;
@@ -62,8 +62,8 @@
struct poll_table_struct *wait)
{
struct msm_vidc_inst *inst = instance;
- struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
- struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
+ struct vb2_queue *outq = &inst->bufq[OUTPUT_PORT].vb2_bufq;
+ struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq;
poll_wait(filp, &inst->event_handler.wait, wait);
poll_wait(filp, &capq->done_wq, wait);
@@ -306,9 +306,9 @@
{
struct vb2_queue *q = NULL;
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- q = &inst->vb2_bufq[CAPTURE_PORT];
+ q = &inst->bufq[CAPTURE_PORT].vb2_bufq;
} else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- q = &inst->vb2_bufq[OUTPUT_PORT];
+ q = &inst->bufq[OUTPUT_PORT].vb2_bufq;
} else {
dprintk(VIDC_ERR, "buf_type = %d not recognised\n", type);
return -EINVAL;
@@ -404,6 +404,8 @@
}
mutex_init(&inst->sync_lock);
+ mutex_init(&inst->bufq[CAPTURE_PORT].lock);
+ mutex_init(&inst->bufq[OUTPUT_PORT].lock);
spin_lock_init(&inst->lock);
inst->session_type = session_type;
INIT_LIST_HEAD(&inst->pendingq);
@@ -489,8 +491,10 @@
buf = list_entry(ptr, struct internal_buf,
list);
list_del(&buf->list);
+ spin_unlock_irqrestore(&inst->lock, flags);
msm_smem_free(inst->mem_client, buf->handle);
kfree(buf);
+ spin_lock_irqsave(&inst->lock, flags);
}
}
if (!list_empty(&inst->persistbufs)) {
@@ -498,12 +502,17 @@
buf = list_entry(ptr, struct internal_buf,
list);
list_del(&buf->list);
+ spin_unlock_irqrestore(&inst->lock, flags);
msm_smem_free(inst->mem_client, buf->handle);
kfree(buf);
+ spin_lock_irqsave(&inst->lock, flags);
}
}
- if (inst->extradata_handle)
+ if (inst->extradata_handle) {
+ spin_unlock_irqrestore(&inst->lock, flags);
msm_smem_free(inst->mem_client, inst->extradata_handle);
+ spin_lock_irqsave(&inst->lock, flags);
+ }
spin_unlock_irqrestore(&inst->lock, flags);
msm_smem_delete_client(inst->mem_client);
debugfs_remove_recursive(inst->debugfs_root);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 2aed0b7..a6805af 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -258,13 +258,13 @@
return &fmt[i];
}
-struct vb2_queue *msm_comm_get_vb2q(
+struct buf_queue *msm_comm_get_vb2q(
struct msm_vidc_inst *inst, enum v4l2_buf_type type)
{
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return &inst->vb2_bufq[CAPTURE_PORT];
+ return &inst->bufq[CAPTURE_PORT];
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return &inst->vb2_bufq[OUTPUT_PORT];
+ return &inst->bufq[OUTPUT_PORT];
return NULL;
}
@@ -527,21 +527,25 @@
}
}
-static struct vb2_buffer *get_vb_from_device_addr(struct vb2_queue *q,
+static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq,
u32 dev_addr)
{
struct vb2_buffer *vb = NULL;
+ struct vb2_queue *q = NULL;
int found = 0;
- if (!q) {
+ if (!bufq) {
dprintk(VIDC_ERR, "Invalid parameter\n");
return NULL;
}
+ q = &bufq->vb2_bufq;
+ mutex_lock(&bufq->lock);
list_for_each_entry(vb, &q->queued_list, queued_entry) {
if (vb->v4l2_planes[0].m.userptr == dev_addr) {
found = 1;
break;
}
}
+ mutex_unlock(&bufq->lock);
if (!found) {
dprintk(VIDC_ERR,
"Failed to find the buffer in queued list: %d, %d\n",
@@ -563,7 +567,9 @@
vb = response->clnt_data;
inst = (struct msm_vidc_inst *)response->session_id;
if (vb) {
+ mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->bufq[OUTPUT_PORT].lock);
wake_up(&inst->kernel_event_queue);
}
}
@@ -580,7 +586,7 @@
}
inst = (struct msm_vidc_inst *)response->session_id;
fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
- vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+ vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
(u32)fill_buf_done->packet_buffer1);
if (vb) {
vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
@@ -600,10 +606,8 @@
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
-
- if (!inst->fbd_count)
- vb->v4l2_buf.flags = V4L2_BUF_FLAG_KEYFRAME;
- ++inst->fbd_count;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
switch (fill_buf_done->picture_type) {
case HAL_PICTURE_IDR:
@@ -628,7 +632,9 @@
dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
vb->v4l2_planes[0].bytesused,
vb->v4l2_buf.flags);
+ mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
wake_up(&inst->kernel_event_queue);
} else {
/*
@@ -645,18 +651,19 @@
*/
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS
&& fill_buf_done->filled_len1 == 0) {
- struct vb2_queue *q = &inst->vb2_bufq[CAPTURE_PORT];
+ struct buf_queue *q = &inst->bufq[CAPTURE_PORT];
- if (!list_empty(&q->queued_list)) {
- vb = list_first_entry(&q->queued_list,
+ if (!list_empty(&q->vb2_bufq.queued_list)) {
+ vb = list_first_entry(&q->vb2_bufq.queued_list,
struct vb2_buffer, queued_entry);
vb->v4l2_planes[0].bytesused = 0;
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+ mutex_lock(&q->lock);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(&q->lock);
}
}
-
}
}
@@ -672,7 +679,7 @@
}
inst = (struct msm_vidc_inst *)response->session_id;
fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
- vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+ vb = get_vb_from_device_addr(&inst->bufq[CAPTURE_PORT],
(u32)fill_buf_done->packet_buffer1);
if (vb)
vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
@@ -682,7 +689,9 @@
dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
vb->v4l2_planes[0].bytesused,
vb->v4l2_buf.flags);
+ mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->bufq[CAPTURE_PORT].lock);
}
void handle_cmd_response(enum command_response cmd, void *data)
@@ -1203,7 +1212,6 @@
goto exit;
}
inst->ftb_count = 0;
- inst->fbd_count = 0;
change_inst_state(inst, MSM_VIDC_OPEN);
exit:
return rc;
@@ -1443,7 +1451,6 @@
int rc = 0;
struct vb2_queue *q;
struct msm_vidc_inst *inst;
- unsigned long flags;
struct vb2_buf_entry *entry;
struct vidc_frame_data frame_data;
q = vb->vb2_queue;
@@ -1460,10 +1467,9 @@
goto err_no_mem;
}
entry->vb = vb;
- dprintk(VIDC_DBG, "Queueing buffer in pendingq\n");
- spin_lock_irqsave(&inst->lock, flags);
+ mutex_lock(&inst->sync_lock);
list_add_tail(&entry->list, &inst->pendingq);
- spin_unlock_irqrestore(&inst->lock, flags);
+ mutex_unlock(&inst->sync_lock);
} else {
int64_t time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp);
do_div(time_usec, NSEC_PER_USEC);
@@ -1586,9 +1592,16 @@
buffer_info.align_device_addr = handle->device_addr;
rc = vidc_hal_session_release_buffers(
(void *) inst->session, &buffer_info);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to release scratch buffer: 0x%x, %d",
+ buffer_info.align_device_addr,
+ buffer_info.buffer_size);
list_del(&buf->list);
+ spin_unlock_irqrestore(&inst->lock, flags);
msm_smem_free(inst->mem_client, buf->handle);
kfree(buf);
+ spin_lock_irqsave(&inst->lock, flags);
}
}
spin_unlock_irqrestore(&inst->lock, flags);
@@ -1617,11 +1630,14 @@
(void *) inst->session, &buffer_info);
if (rc)
dprintk(VIDC_WARN,
- "Failed in %s for buffer %ld\n",
- __func__, handle->device_addr);
+ "Failed to release persist buffer 0x%x, %d\n",
+ buffer_info.align_device_addr,
+ buffer_info.buffer_size);
list_del(&buf->list);
+ spin_unlock_irqrestore(&inst->lock, flags);
msm_smem_free(inst->mem_client, buf->handle);
kfree(buf);
+ spin_lock_irqsave(&inst->lock, flags);
}
}
spin_unlock_irqrestore(&inst->lock, flags);
@@ -1633,7 +1649,6 @@
int rc = 0;
struct msm_smem *handle;
struct internal_buf *binfo;
- struct list_head *ptr, *next;
struct vidc_buffer_addr_info buffer_info;
unsigned long flags;
struct hal_buffer_requirements *scratch_buf =
@@ -1643,28 +1658,9 @@
"scratch: num = %d, size = %d\n",
scratch_buf->buffer_count_actual,
scratch_buf->buffer_size);
- spin_lock_irqsave(&inst->lock, flags);
- if (!list_empty(&inst->internalbufs)) {
- list_for_each_safe(ptr, next, &inst->internalbufs) {
- binfo = list_entry(ptr, struct internal_buf,
- list);
- handle = binfo->handle;
- buffer_info.buffer_size = handle->size;
- buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
- buffer_info.num_buffers = 1;
- buffer_info.align_device_addr = handle->device_addr;
- rc = vidc_hal_session_release_buffers(
- (void *) inst->session, &buffer_info);
- if (rc)
- dprintk(VIDC_WARN,
- "Failed in release %s for buffer %ld\n",
- __func__, handle->device_addr);
- list_del(&binfo->list);
- msm_smem_free(inst->mem_client, binfo->handle);
- kfree(binfo);
- }
- }
- spin_unlock_irqrestore(&inst->lock, flags);
+ if (msm_comm_release_scratch_buffers(inst))
+ dprintk(VIDC_WARN, "Failed to release scratch buffers\n");
+
if (scratch_buf->buffer_size) {
for (i = 0; i < scratch_buf->buffer_count_actual;
i++) {
@@ -1779,18 +1775,46 @@
int rc = 0;
bool ip_flush = false;
bool op_flush = false;
+ struct list_head *ptr, *next;
+ struct vb2_buf_entry *temp;
+ struct mutex *lock;
ip_flush = flags & V4L2_QCOM_CMD_FLUSH_OUTPUT;
op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE;
-
if (ip_flush && !op_flush) {
dprintk(VIDC_WARN, "Input only flush not supported\n");
return 0;
}
mutex_lock(&inst->sync_lock);
if (inst->in_reconfig && !ip_flush && op_flush) {
+ if (!list_empty(&inst->pendingq)) {
+ /*Execution can never reach here since port reconfig
+ * wont happen unless pendingq is emptied out
+ * (both pendingq and flush being secured with same
+ * lock). Printing a message here incase this breaks.*/
+ dprintk(VIDC_WARN,
+ "FLUSH BUG: Pending q not empty! It should be empty\n");
+ }
rc = vidc_hal_session_flush(inst->session,
HAL_FLUSH_OUTPUT);
} else {
+ if (!list_empty(&inst->pendingq)) {
+ /*If flush is called after queueing buffers but before
+ * streamon driver should flush the pending queue*/
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ temp =
+ list_entry(ptr, struct vb2_buf_entry, list);
+ if (temp->vb->v4l2_buf.type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ lock = &inst->bufq[CAPTURE_PORT].lock;
+ else
+ lock = &inst->bufq[OUTPUT_PORT].lock;
+ mutex_lock(lock);
+ vb2_buffer_done(temp->vb, VB2_BUF_STATE_DONE);
+ mutex_unlock(lock);
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ }
rc = vidc_hal_session_flush(inst->session,
HAL_FLUSH_ALL);
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
index 1301e5c..0708724 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -23,7 +23,7 @@
const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
-struct vb2_queue *msm_comm_get_vb2q(
+struct buf_queue *msm_comm_get_vb2q(
struct msm_vidc_inst *inst, enum v4l2_buf_type type);
int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.c b/drivers/media/video/msm_vidc/msm_vidc_debug.c
index 7921f84..fa62988 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.c
@@ -104,6 +104,7 @@
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_dir;
}
+ msm_vidc_debug = 0x3;
failed_create_dir:
return dir;
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.h b/drivers/media/video/msm_vidc/msm_vidc_debug.h
index b7928e9..f7aa742 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.h
@@ -18,19 +18,24 @@
#define VIDC_DBG_TAG "msm_vidc: %d: "
+/*To enable messages OR these values and
+* echo the result to debugfs file*/
+
enum vidc_msg_prio {
- VIDC_ERR,
- VIDC_WARN,
- VIDC_INFO,
- VIDC_DBG,
+ VIDC_ERR = 0x0001,
+ VIDC_WARN = 0x0002,
+ VIDC_INFO = 0x0004,
+ VIDC_DBG = 0x0008,
+ VIDC_PROF = 0x0010,
+ VIDC_FW = 0x1000,
};
extern int msm_vidc_debug;
-#define dprintk(level, fmt, arg...) \
- do { \
- if (msm_vidc_debug >= level) \
- printk(KERN_DEBUG VIDC_DBG_TAG fmt, \
- level, ## arg); \
+#define dprintk(__level, __fmt, arg...) \
+ do { \
+ if (msm_vidc_debug & __level) \
+ printk(KERN_DEBUG VIDC_DBG_TAG __fmt,\
+ __level, ## arg); \
} while (0)
struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index 1f2eff8..1ea92fc 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -188,6 +188,11 @@
u32 bitrate;
};
+struct buf_queue {
+ struct vb2_queue vb2_bufq;
+ struct mutex lock;
+};
+
struct msm_vidc_core {
struct list_head list;
struct mutex sync_lock;
@@ -216,7 +221,7 @@
struct session_prop prop;
int state;
const struct msm_vidc_format *fmts[MAX_PORT_NUM];
- struct vb2_queue vb2_bufq[MAX_PORT_NUM];
+ struct buf_queue bufq[MAX_PORT_NUM];
spinlock_t lock;
struct list_head pendingq;
struct list_head internalbufs;
@@ -233,7 +238,6 @@
u32 reconfig_height;
struct dentry *debugfs_root;
u32 ftb_count;
- u32 fbd_count;
struct vb2_buffer *vb2_seq_hdr;
void *priv;
};
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index e610f8e..8ac35d9 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -1170,6 +1170,16 @@
pkt->size += sizeof(u32) * 2;
break;
}
+ case HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER:
+ {
+ struct hfi_enable *hfi;
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER;
+ hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
+ hfi->enable = ((struct hfi_enable *) pdata)->enable;
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
case HAL_CONFIG_VENC_REQUEST_IFRAME:
pkt->rg_property_data[0] =
HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
@@ -1427,6 +1437,7 @@
prop->multi_slice);
break;
}
+ hfi->slice_size = prop->slice_size;
pkt->size += sizeof(u32) + sizeof(struct
hfi_multi_slice_control);
break;
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index c77ae12..879418d 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -137,6 +137,7 @@
HAL_PARAM_VENC_MULTI_SLICE_INFO,
HAL_CONFIG_VENC_TIMESTAMP_SCALE,
HAL_PARAM_VENC_LOW_LATENCY,
+ HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER,
};
enum hal_domain {
@@ -209,7 +210,7 @@
enum hal_mpeg4_profile {
HAL_MPEG4_PROFILE_SIMPLE = 0x00000001,
- HAL_MPEG4_PROFILE_SIMPLESCALABLE = 0x00000002,
+ HAL_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00000002,
HAL_MPEG4_PROFILE_CORE = 0x00000004,
HAL_MPEG4_PROFILE_MAIN = 0x00000008,
HAL_MPEG4_PROFILE_NBIT = 0x00000010,
@@ -223,7 +224,7 @@
HAL_MPEG4_PROFILE_ADVANCEDCODING = 0x00001000,
HAL_MPEG4_PROFILE_ADVANCEDCORE = 0x00002000,
HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
- HAL_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00008000,
+ HAL_MPEG4_PROFILE_SIMPLESCALABLE = 0x00008000,
HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
};
diff --git a/drivers/media/video/msm_wfd/enc-mfc-subdev.c b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
index 5997345..09a5e32 100644
--- a/drivers/media/video/msm_wfd/enc-mfc-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-mfc-subdev.c
@@ -1352,6 +1352,48 @@
err_set_perf_level:
return rc;
}
+
+static long venc_set_avc_delimiter(struct video_client_ctx *client_ctx,
+ __s32 flag)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_avc_delimiter_enable delimiter_flag;
+ if (!client_ctx)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_ENABLE_DELIMITER_FLAG;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_avc_delimiter_enable);
+ delimiter_flag.avc_delimiter_enable_flag = flag;
+ return vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &delimiter_flag);
+}
+
+static long venc_get_avc_delimiter(struct video_client_ctx *client_ctx,
+ __s32 *flag)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_avc_delimiter_enable delimiter_flag;
+ int rc = 0;
+
+ if (!client_ctx || !flag)
+ return -EINVAL;
+
+ vcd_property_hdr.prop_id = VCD_I_ENABLE_DELIMITER_FLAG;
+ vcd_property_hdr.sz =
+ sizeof(struct vcd_property_avc_delimiter_enable);
+ rc = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &delimiter_flag);
+
+ if (rc < 0) {
+ WFD_MSG_ERR("Failed getting property for delimiter");
+ return rc;
+ }
+
+ *flag = delimiter_flag.avc_delimiter_enable_flag;
+ return rc;
+}
+
static long venc_set_header_mode(struct video_client_ctx *client_ctx,
__s32 mode)
{
@@ -1932,7 +1974,7 @@
struct vcd_property_enc_recon_buffer *ctrl = NULL;
unsigned long phy_addr;
int i = 0;
- int flags = 0;
+ int heap_mask = 0;
u32 len;
control.width = inst->width;
control.height = inst->height;
@@ -1945,8 +1987,8 @@
WFD_MSG_ERR("Failed to get recon buf size\n");
goto err;
}
- flags = ION_HEAP(ION_CP_MM_HEAP_ID);
- flags |= inst->secure ? ION_SECURE : ION_HEAP(ION_IOMMU_HEAP_ID);
+ heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
+ heap_mask |= inst->secure ? ION_SECURE : ION_HEAP(ION_IOMMU_HEAP_ID);
if (vcd_get_ion_status()) {
for (i = 0; i < 4; ++i) {
@@ -1957,11 +1999,11 @@
ctrl->user_virtual_addr = (void *)i;
client_ctx->recon_buffer_ion_handle[i]
= ion_alloc(client_ctx->user_ion_client,
- control.size, SZ_8K, flags);
+ control.size, SZ_8K, heap_mask, 0);
ctrl->kernel_virtual_addr = ion_map_kernel(
client_ctx->user_ion_client,
- client_ctx->recon_buffer_ion_handle[i], 0);
+ client_ctx->recon_buffer_ion_handle[i]);
if (IS_ERR_OR_NULL(ctrl->kernel_virtual_addr)) {
WFD_MSG_ERR("ion map kernel failed\n");
@@ -2157,7 +2199,7 @@
if (rc)
WFD_MSG_ERR("Failed to free recon buffer\n");
- if (IS_ERR_OR_NULL(
+ if (!IS_ERR_OR_NULL(
client_ctx->recon_buffer_ion_handle[i])) {
if (!inst->secure) {
ion_unmap_iommu(
@@ -2232,6 +2274,9 @@
case V4L2_CID_MPEG_QCOM_SET_PERF_LEVEL:
rc = venc_set_max_perf_level(client_ctx, ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
+ rc = venc_set_avc_delimiter(client_ctx, ctrl->value);
+ break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
rc = venc_set_entropy_mode(client_ctx, ctrl->value);
break;
@@ -2303,6 +2348,9 @@
case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
rc = venc_get_cyclic_intra_refresh_mb(client_ctx, &ctrl->value);
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER:
+ rc = venc_get_avc_delimiter(client_ctx, &ctrl->value);
+ break;
default:
WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
rc = -ENOTSUPP;
diff --git a/drivers/media/video/msm_wfd/enc-venus-subdev.c b/drivers/media/video/msm_wfd/enc-venus-subdev.c
index 04e42f5..89ad6c7 100644
--- a/drivers/media/video/msm_wfd/enc-venus-subdev.c
+++ b/drivers/media/video/msm_wfd/enc-venus-subdev.c
@@ -617,7 +617,7 @@
}
mregion->kvaddr = ion_map_kernel(venc_ion_client,
- mregion->ion_handle, flags);
+ mregion->ion_handle);
if (IS_ERR_OR_NULL(mregion->kvaddr)) {
WFD_MSG_ERR("Failed to map buffer into kernel\n");
diff --git a/drivers/media/video/msm_wfd/wfd-ioctl.c b/drivers/media/video/msm_wfd/wfd-ioctl.c
index d3c5936..d8080dd 100644
--- a/drivers/media/video/msm_wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm_wfd/wfd-ioctl.c
@@ -91,6 +91,7 @@
u32 out_buf_size;
struct list_head input_mem_list;
struct wfd_stats stats;
+ struct completion stop_mdp_thread;
};
struct wfd_vid_buffer {
@@ -160,7 +161,7 @@
alloc_regions |= secure ? ION_SECURE :
ION_HEAP(ION_IOMMU_HEAP_ID);
handle = ion_alloc(client,
- mregion->size, SZ_4K, alloc_regions);
+ mregion->size, SZ_4K, alloc_regions, 0);
if (IS_ERR_OR_NULL(handle)) {
WFD_MSG_ERR("Failed to allocate input buffer\n");
@@ -168,7 +169,7 @@
goto alloc_fail;
}
- kvaddr = ion_map_kernel(client, handle, secure ? UNCACHED : CACHED);
+ kvaddr = ion_map_kernel(client, handle);
if (IS_ERR_OR_NULL(kvaddr)) {
WFD_MSG_ERR("Failed to get virtual addr\n");
@@ -522,7 +523,7 @@
static int mdp_output_thread(void *data)
{
- int rc = 0;
+ int rc = 0, no_sig_wait = 0;
struct file *filp = (struct file *)data;
struct wfd_inst *inst = filp->private_data;
struct wfd_device *wfd_dev =
@@ -531,6 +532,14 @@
struct mem_region *mregion;
struct vsg_buf_info ibuf_vsg;
while (!kthread_should_stop()) {
+ if (rc) {
+ WFD_MSG_DBG("%s() error in output thread\n", __func__);
+ if (!no_sig_wait) {
+ wait_for_completion(&inst->stop_mdp_thread);
+ no_sig_wait = 1;
+ }
+ continue;
+ }
WFD_MSG_DBG("waiting for mdp output\n");
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev,
core, ioctl, MDP_DQ_BUFFER, (void *)&obuf_mdp);
@@ -540,7 +549,7 @@
WFD_MSG_ERR("MDP reported err %d\n", rc);
WFD_MSG_ERR("Streamoff called\n");
- break;
+ continue;
} else {
wfd_stats_update(&inst->stats,
WFD_STAT_EVENT_MDP_DEQUEUE);
@@ -550,7 +559,7 @@
if (!mregion) {
WFD_MSG_ERR("mdp cookie is null\n");
rc = -EINVAL;
- break;
+ continue;
}
ibuf_vsg.mdp_buf_info = obuf_mdp;
@@ -565,7 +574,7 @@
if (rc) {
WFD_MSG_ERR("Failed to queue frame to vsg\n");
- break;
+ continue;
} else {
wfd_stats_update(&inst->stats,
WFD_STAT_EVENT_VSG_QUEUE);
@@ -599,7 +608,7 @@
WFD_MSG_ERR("Failed to start vsg\n");
goto subdev_start_fail;
}
-
+ init_completion(&inst->stop_mdp_thread);
inst->mdp_task = kthread_run(mdp_output_thread, priv_data,
"mdp_output_thread");
if (IS_ERR(inst->mdp_task)) {
@@ -634,6 +643,7 @@
if (rc)
WFD_MSG_ERR("Failed to stop VSG\n");
+ complete(&inst->stop_mdp_thread);
kthread_stop(inst->mdp_task);
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
ENCODE_FLUSH, (void *)inst->venc_inst);
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index e6cbae3..a160915 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -19,6 +19,8 @@
#include <linux/videodev2.h>
#include <linux/platform_device.h>
#include <linux/memory_alloc.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
#include <mach/board.h>
#include <mach/gpio.h>
@@ -51,13 +53,31 @@
static struct vcap_dev *vcap_ctrl;
-static unsigned debug;
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (debug >= level) \
- printk(KERN_DEBUG "VCAP: " fmt, ## arg); \
- } while (0)
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *vcap_debugfs_base;
+static struct reg_range debug_reg_range[] = {
+ {
+ VCAP_REG_RANGE_1_MIN,
+ VCAP_REG_RANGE_1_MAX,
+ },
+ {
+ VCAP_REG_RANGE_2_MIN,
+ VCAP_REG_RANGE_2_MAX,
+ },
+ {
+ VCAP_REG_RANGE_3_MIN,
+ VCAP_REG_RANGE_3_MAX,
+ },
+ {
+ VCAP_REG_RANGE_4_MIN,
+ VCAP_REG_RANGE_4_MAX,
+ },
+ {
+ VCAP_REG_RANGE_5_MIN,
+ VCAP_REG_RANGE_5_MAX,
+ },
+};
+#endif
int vcap_reg_powerup(struct vcap_dev *dev)
{
@@ -91,7 +111,7 @@
int num_gpios = pdata->num_gpios;
unsigned *gpios = pdata->gpios;
- dprintk(4, "GPIO config start\n");
+ pr_debug("GPIO config start\n");
if (on) {
for (i = 0; i < num_gpios; i++) {
ret = gpio_request(gpios[i], "vcap:vc");
@@ -112,7 +132,7 @@
for (i = 0; i < num_gpios; i++)
gpio_free(gpios[i]);
}
- dprintk(4, "GPIO config exit\n");
+ pr_debug("GPIO config exit\n");
return 0;
gpio_failed:
for (i--; i >= 0; i--)
@@ -151,6 +171,7 @@
pr_err("%s: Failed core set_rate %d\n", __func__, ret);
goto fail_vcap_clk;
}
+ dev->dbg_p.clk_rate = (uint32_t) rate;
dev->vcap_npl_clk = clk_get(ddev, "vcap_npl_clk");
if (IS_ERR(dev->vcap_npl_clk)) {
@@ -198,6 +219,7 @@
dev->vcap_npl_clk = NULL;
fail_vcap_clk:
+ dev->dbg_p.clk_rate = 0;
clk_disable(dev->vcap_clk);
fail_vcap_clk_unprep:
clk_unprepare(dev->vcap_clk);
@@ -228,6 +250,8 @@
clk_put(dev->vcap_clk);
dev->vcap_clk = NULL;
}
+
+ dev->dbg_p.clk_rate = 0;
}
int vcap_get_bus_client_handle(struct vcap_dev *dev)
@@ -244,6 +268,7 @@
unsigned long rate)
{
int rc;
+ pr_debug("Enter %s", __func__);
rc = vcap_reg_powerup(dev);
if (rc < 0)
@@ -259,6 +284,7 @@
goto gpio_failed;
writel_relaxed(0x00030003, VCAP_OFFSET(0xD78));
writel_relaxed(0x00030003, VCAP_OFFSET(0xD7C));
+ pr_debug("Success Exit %s", __func__);
return 0;
gpio_failed:
@@ -274,10 +300,12 @@
int vcap_disable(struct vcap_dev *dev)
{
+ pr_debug("Enter %s", __func__);
config_gpios(0, dev->vcap_pdata);
msm_bus_scale_unregister_client(dev->bus_client_handle);
dev->bus_client_handle = 0;
+ dev->dbg_p.bw_request = 0;
vcap_clk_powerdown(dev);
vcap_reg_powerdown(dev);
return 0;
@@ -311,34 +339,34 @@
struct vb2_buffer *vb;
if (q->fileio) {
- dprintk(1, "%s: file io in progress\n", __func__);
+ pr_debug("%s: file io in progress\n", __func__);
return -EBUSY;
}
if (b->type != q->type) {
- dprintk(1, "%s: invalid buffer type\n", __func__);
+ pr_debug("%s: invalid buffer type\n", __func__);
return -EINVAL;
}
if (b->index >= q->num_buffers) {
- dprintk(1, "%s: buffer index out of range\n", __func__);
+ pr_debug("%s: buffer index out of range\n", __func__);
return -EINVAL;
}
vb = q->bufs[b->index];
if (NULL == vb) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
return -EINVAL;
}
if (b->memory != q->memory) {
- dprintk(1, "%s: invalid memory type\n", __func__);
+ pr_debug("%s: invalid memory type\n", __func__);
return -EINVAL;
}
if (vb->state != VB2_BUF_STATE_DEQUEUED &&
vb->state != VB2_BUF_STATE_PREPARED) {
- dprintk(1, "%s: buffer already in use\n", __func__);
+ pr_err("%s: buffer already in use\n", __func__);
return -EINVAL;
}
@@ -361,17 +389,17 @@
unsigned long flags;
if (q->fileio) {
- dprintk(1, "%s: file io in progress\n", __func__);
+ pr_debug("%s: file io in progress\n", __func__);
return -EBUSY;
}
if (b->type != q->type) {
- dprintk(1, "%s: invalid buffer type\n", __func__);
+ pr_debug("%s: invalid buffer type\n", __func__);
return -EINVAL;
}
if (!q->streaming) {
- dprintk(1, "Streaming off, will not wait for buffers\n");
+ pr_debug("Streaming off, will not wait for buffers\n");
return -EINVAL;
}
@@ -384,13 +412,13 @@
switch (vb->state) {
case VB2_BUF_STATE_DONE:
- dprintk(3, "%s: Returning done buffer\n", __func__);
+ pr_debug("%s: Returning done buffer\n", __func__);
break;
case VB2_BUF_STATE_ERROR:
- dprintk(3, "%s: Ret done buf with err\n", __func__);
+ pr_debug("%s: Ret done buf with err\n", __func__);
break;
default:
- dprintk(1, "%s: Invalid buffer state\n", __func__);
+ pr_debug("%s: Invalid buffer state\n", __func__);
return -EINVAL;
}
@@ -402,7 +430,7 @@
return 0;
}
- dprintk(1, "No buffers to dequeue\n");
+ pr_debug("%s: No buffers to dequeue\n", __func__);
return -EAGAIN;
}
@@ -415,28 +443,28 @@
int rc;
if (q->fileio) {
- dprintk(1, "%s: file io in progress\n", __func__);
+ pr_debug("%s: file io in progress\n", __func__);
return -EBUSY;
}
if (b->type != q->type) {
- dprintk(1, "%s: invalid buffer type\n", __func__);
+ pr_debug("%s: invalid buffer type\n", __func__);
return -EINVAL;
}
if (b->index >= q->num_buffers) {
- dprintk(1, "%s: buffer index out of range\n", __func__);
+ pr_debug("%s: buffer index out of range\n", __func__);
return -EINVAL;
}
vb = q->bufs[b->index];
if (NULL == vb) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
return -EINVAL;
}
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
- dprintk(1, "%s: buffer already in use\n", __func__);
+ pr_debug("%s: buffer already in use\n", __func__);
return -EINVAL;
}
@@ -468,7 +496,7 @@
buf = container_of(vb, struct vcap_buffer, vb);
if (buf->ion_handle == NULL) {
- dprintk(1, "%s: no ION handle to free\n", __func__);
+ pr_debug("%s: no ION handle to free\n", __func__);
return;
}
buf->paddr = 0;
@@ -546,7 +574,7 @@
static int capture_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vcap_client_data *c_data = vb2_get_drv_priv(vq);
- dprintk(2, "VC start streaming\n");
+ pr_debug("VC start streaming\n");
return vc_start_capture(c_data);
}
@@ -643,7 +671,7 @@
static int vp_in_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- dprintk(2, "VP IN start streaming\n");
+ pr_debug("VP IN start streaming\n");
return 0;
}
@@ -652,7 +680,7 @@
struct vcap_client_data *c_data = vb2_get_drv_priv(vq);
struct vb2_buffer *vb;
- dprintk(2, "VP stop streaming\n");
+ pr_debug("VP IN stop streaming\n");
while (!list_empty(&c_data->vp_action.in_active)) {
struct vcap_buffer *buf;
@@ -749,7 +777,7 @@
struct vcap_client_data *c_data = vb2_get_drv_priv(vq);
struct vb2_buffer *vb;
- dprintk(2, "VP out q stop streaming\n");
+ pr_debug("VP OUT q stop streaming\n");
vp_stop_capture(c_data);
while (!list_empty(&c_data->vp_action.out_active)) {
@@ -890,7 +918,7 @@
struct vcap_dev *dev = c_data->dev;
int rc;
- dprintk(3, "In Req Buf %08x\n", (unsigned int)rb->type);
+ pr_debug("VCAP: In Req Buf %08x\n", (unsigned int)rb->type);
c_data->op_mode = determine_mode(c_data);
if (c_data->op_mode == UNKNOWN_VCAP_OP) {
pr_err("VCAP Error: %s: VCAP in unknown mode\n", __func__);
@@ -968,25 +996,25 @@
struct vb2_queue *q;
int rc;
- dprintk(3, "In Q Buf %08x\n", (unsigned int)p->type);
+ pr_debug("VCAP In Q Buf %08x\n", (unsigned int)p->type);
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (c_data->op_mode == VC_AND_VP_VCAP_OP) {
/* If buffer in vp_in_q it will be coming back */
q = &c_data->vp_in_vidq;
if (p->index >= q->num_buffers) {
- dprintk(1, "qbuf: buffer index out of range\n");
+ pr_debug("VCAP qbuf: buffer index out of range\n");
return -EINVAL;
}
vb = q->bufs[p->index];
if (NULL == vb) {
- dprintk(1, "qbuf: buffer is NULL\n");
+ pr_debug("VCAP qbuf: buffer is NULL\n");
return -EINVAL;
}
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
- dprintk(1, "qbuf: buffer already in use\n");
+ pr_debug("VCAP qbuf: buffer already in use\n");
return -EINVAL;
}
rc = get_phys_addr(c_data->dev, &c_data->vc_vidq, p);
@@ -1035,7 +1063,7 @@
struct vcap_client_data *c_data = to_client_data(file->private_data);
int rc;
- dprintk(3, "In DQ Buf %08x\n", (unsigned int)p->type);
+ pr_debug("VCAP In DQ Buf %08x\n", (unsigned int)p->type);
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (c_data->op_mode == VC_AND_VP_VCAP_OP)
@@ -1072,18 +1100,18 @@
int streamon_validate_q(struct vb2_queue *q)
{
if (q->fileio) {
- dprintk(1, "streamon: file io in progress\n");
+ pr_debug("%s: file io in progress\n", __func__);
return -EBUSY;
}
if (q->streaming) {
- dprintk(1, "streamon: already streaming\n");
+ pr_debug("%s: already streaming\n", __func__);
return -EBUSY;
}
if (V4L2_TYPE_IS_OUTPUT(q->type)) {
if (list_empty(&q->queued_list)) {
- dprintk(1, "streamon: no output buffers queued\n");
+ pr_debug("%s: no output buffers queued\n", __func__);
return -EINVAL;
}
}
@@ -1103,10 +1131,11 @@
idx++;
} while (idx < length);
if (idx == length) {
- pr_err("VCAP: Defaulting to highest BW request\n");
+ pr_info("VCAP: Defaulting to highest BW request\n");
idx--;
}
msm_bus_scale_client_update_request(dev->bus_client_handle, idx);
+ dev->dbg_p.bw_request = bus_vectors[idx].vectors[0].ab;
return 0;
}
@@ -1118,7 +1147,7 @@
unsigned long rate;
long rate_rc;
- dprintk(3, "In Stream ON\n");
+ pr_debug("VCAP: In Stream ON\n");
if (determine_mode(c_data) != c_data->op_mode) {
pr_err("VCAP Error: %s: s_fmt called after req_buf", __func__);
return -ENOTRECOVERABLE;
@@ -1160,6 +1189,8 @@
if (rc < 0)
goto free_res;
+ dev->dbg_p.clk_rate = (uint32_t) rate;
+
rate = (c_data->vc_format.hactive_end -
c_data->vc_format.hactive_start);
@@ -1204,6 +1235,8 @@
}
rate = (unsigned long)rate_rc;
rc = clk_set_rate(dev->vcap_clk, rate);
+
+ dev->dbg_p.clk_rate = (uint32_t) rate;
if (rc < 0)
goto free_res;
@@ -1265,6 +1298,9 @@
}
rate = c_data->vc_format.clk_freq / 100 * 102;
+ if ((c_data->vc_format.hactive_end -
+ c_data->vc_format.hactive_start) > 539)
+ rate = 200000000;
rate_rc = clk_round_rate(dev->vcap_clk, rate);
if (rate_rc <= 0) {
pr_err("%s: Failed core rnd_rate\n", __func__);
@@ -1276,6 +1312,8 @@
if (rc < 0)
goto free_res;
+ dev->dbg_p.clk_rate = (uint32_t) rate;
+
rate = (c_data->vc_format.hactive_end -
c_data->vc_format.hactive_start);
@@ -1373,12 +1411,12 @@
int streamoff_validate_q(struct vb2_queue *q)
{
if (q->fileio) {
- dprintk(1, "streamoff: file io in progress\n");
+ pr_debug("%s: file io in progress\n", __func__);
return -EBUSY;
}
if (!q->streaming) {
- dprintk(1, "streamoff: not streaming\n");
+ pr_debug("%s: not streaming\n", __func__);
return -EINVAL;
}
return 0;
@@ -1788,7 +1826,7 @@
struct vb2_queue *q;
unsigned int mask = 0;
- dprintk(1, "Enter slect/poll\n");
+ pr_debug("%s: Enter slect/poll\n", __func__);
switch (c_data->op_mode) {
case VC_VCAP_OP:
@@ -1863,13 +1901,276 @@
return vc_handler(vcap_ctrl);
}
+#ifdef CONFIG_DEBUG_FS
+/* Query VCAP resource usage */
+static ssize_t read_dump_info(struct file *file, char __user *user_buf,
+ size_t len, loff_t *ppos)
+{
+ struct vcap_dev *dev = file->private_data;
+ char str_buf[512];
+ size_t tot_size = 0, size;
+
+ if (dev->vc_client) {
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "VCAP: VC\n");
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vc_resourse = %d\n", dev->vc_resource);
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vc_enabled = %d\n", atomic_read(&dev->vc_enabled));
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vc_client id = %p\n", dev->vc_client);
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vc_queue_count = %d\n",
+ atomic_read(&dev->vc_client->vc_vidq.queued_count));
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vc_total_buffers = %d\n",
+ dev->vc_client->vc_action.tot_buf);
+ tot_size += size;
+ } else {
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "VCAP: VC not in use\n");
+ tot_size += size;
+ }
+ if (dev->vp_client) {
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "VCAP: VP\n");
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vp_resourse = %d\n", dev->vp_resource);
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vp_enabled = %d\n", atomic_read(&dev->vp_enabled));
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vp_client id = %p\n", dev->vp_client);
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vp_in_queue_count = %d\n",
+ atomic_read(
+ &dev->vp_client->vp_in_vidq.queued_count));
+ tot_size += size;
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "vp_out_queue_count = %d\n",
+ atomic_read(
+ &dev->vp_client->vp_out_vidq.queued_count));
+ tot_size += size;
+ } else {
+ size = scnprintf(str_buf + tot_size, sizeof(str_buf) - tot_size,
+ "VCAP: VP not in use\n");
+ tot_size += size;
+ }
+
+ return simple_read_from_buffer(user_buf, len, ppos, str_buf, tot_size);
+}
+
+static const struct file_operations dump_info_fops = {
+ .read = read_dump_info,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
+static int vcap_debug_clk_rate_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ *val = (u64)dev->dbg_p.clk_rate;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clk_rate_fops, vcap_debug_clk_rate_get,
+ NULL, "%llu\n");
+
+static int vcap_debug_bw_req_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ *val = (u64)dev->dbg_p.bw_request;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(bw_req_fops, vcap_debug_bw_req_get,
+ NULL, "%llu\n");
+
+static int vcap_debug_drop_frames_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ struct timeval tv;
+ int drop_count;
+
+ if (!dev->vc_resource)
+ return -EPERM;
+ drop_count = atomic_read(&dev->dbg_p.vc_drop_count);
+ atomic_set(&dev->dbg_p.vc_drop_count, 0);
+
+ do_gettimeofday(&tv);
+ dev->dbg_p.vc_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
+ *val = (u64)drop_count;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(tot_frame_drop_fops, vcap_debug_drop_frames_get,
+ NULL, "%llu\n");
+
+static int vcap_debug_drop_fps_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ struct timeval tv;
+ int drop_count;
+ uint32_t new_ts;
+
+ if (!dev->vc_resource)
+ return -EPERM;
+ drop_count = atomic_read(&dev->dbg_p.vc_drop_count);
+ atomic_set(&dev->dbg_p.vc_drop_count, 0);
+
+ do_gettimeofday(&tv);
+ new_ts = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
+ if ((new_ts - dev->dbg_p.vc_timestamp) / VCAP_USEC &&
+ new_ts > dev->dbg_p.vc_timestamp)
+ drop_count /= ((new_ts - dev->dbg_p.vc_timestamp) / VCAP_USEC);
+ else
+ drop_count = 0;
+
+ dev->dbg_p.vc_timestamp = new_ts;
+ *val = (u64)drop_count;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(drop_fps_fops, vcap_debug_drop_fps_get,
+ NULL, "%llu\n");
+
+static int vcap_debug_vp_lat_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+
+ if (!dev->vp_resource)
+ return -EPERM;
+ *val = (u64)dev->dbg_p.vp_ewma;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(vp_lat_fops, vcap_debug_vp_lat_get,
+ NULL, "%llu\n");
+
+/* Read/Write to VCAP Registers */
+static int vcap_debug_reg_set(void *data, u64 val)
+{
+ struct vcap_dev *dev = data;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(debug_reg_range); i++) {
+ if (val >= debug_reg_range[i].min_val && val <=
+ debug_reg_range[i].max_val)
+ break;
+ }
+ if (i == ARRAY_SIZE(debug_reg_range))
+ return -EINVAL;
+ dev->dbg_p.reg_addr = (uint32_t) val;
+ return 0;
+}
+
+static int vcap_debug_reg_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ *val = (u64)dev->dbg_p.reg_addr;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(vcap_reg_fops, vcap_debug_reg_get,
+ vcap_debug_reg_set, "0x%08llx\n")
+
+static int vcap_debug_reg_rdwr_set(void *data, u64 val)
+{
+ struct vcap_dev *dev = data;
+ u32 reg_val = (u32) val;
+
+ writel_iowmb(reg_val, VCAP_OFFSET(dev->dbg_p.reg_addr));
+ return 0;
+}
+
+static int vcap_debug_reg_rdwr_get(void *data, u64 *val)
+{
+ struct vcap_dev *dev = data;
+ *val = (u64)readl_relaxed(VCAP_OFFSET(dev->dbg_p.reg_addr));
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(vcap_reg_rdwr_fops, vcap_debug_reg_rdwr_get,
+ vcap_debug_reg_rdwr_set, "0x%08llx\n");
+
+static int vcap_debugfs_init(struct vcap_dev *dev)
+{
+ vcap_debugfs_base = debugfs_create_dir("vcap", NULL);
+ if (!vcap_debugfs_base)
+ return -ENOMEM;
+
+ if (!debugfs_create_file("dump_info", S_IRUGO,
+ vcap_debugfs_base, dev, &dump_info_fops))
+ goto error;
+
+ if (!debugfs_create_file("vcap_core_clk_rate", S_IRUGO,
+ vcap_debugfs_base, dev, &clk_rate_fops))
+ goto error;
+
+ if (!debugfs_create_file("vcap_bw_req", S_IRUGO,
+ vcap_debugfs_base, dev, &bw_req_fops))
+ goto error;
+
+ if (!debugfs_create_file("vc_total_frames_drop", S_IRUGO,
+ vcap_debugfs_base, dev, &tot_frame_drop_fops))
+ goto error;
+
+ if (!debugfs_create_file("vc_drop_fps", S_IRUGO,
+ vcap_debugfs_base, dev, &drop_fps_fops))
+ goto error;
+
+ if (!debugfs_create_file("vp_avg_completion_t", S_IRUGO,
+ vcap_debugfs_base, dev, &vp_lat_fops))
+ goto error;
+
+ if (!debugfs_create_file("vcap_reg_addr", S_IRUGO | S_IWUSR,
+ vcap_debugfs_base, dev, &vcap_reg_fops))
+ goto error;
+
+ if (!debugfs_create_file("vcap_reg_val", S_IRUGO | S_IWUSR,
+ vcap_debugfs_base, dev, &vcap_reg_rdwr_fops))
+ goto error;
+ return 0;
+
+error:
+ debugfs_remove_recursive(vcap_debugfs_base);
+ vcap_debugfs_base = NULL;
+ return -ENOMEM;
+}
+
+static void vcap_debugfs_remove(void)
+{
+ if (vcap_debugfs_base) {
+ debugfs_remove_recursive(vcap_debugfs_base);
+ vcap_debugfs_base = NULL;
+ }
+}
+#else
+
+static int vcap_debugfs_init(struct vcap_dev *dev)
+{
+ return 0;
+}
+static void vcap_debugfs_remove(void) {}
+#endif
+
static int __devinit vcap_probe(struct platform_device *pdev)
{
struct vcap_dev *dev;
struct video_device *vfd;
int ret;
- dprintk(1, "Probe started\n");
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
@@ -1946,6 +2247,7 @@
if (ret)
goto unreg_dev;
msm_bus_scale_client_update_request(dev->bus_client_handle, 0);
+ dev->dbg_p.bw_request = 0;
ret = detect_vc(dev);
@@ -1954,8 +2256,10 @@
/* init video device*/
vfd = video_device_alloc();
- if (!vfd)
+ if (!vfd) {
+ ret = -ENOMEM;
goto deinit_vc;
+ }
*vfd = vcap_template;
vfd->v4l2_dev = &dev->v4l2_dev;
@@ -1969,6 +2273,7 @@
dev->vcap_wq = create_workqueue("vcap");
if (!dev->vcap_wq) {
+ ret = -ENOMEM;
pr_err("Could not create workqueue");
goto rel_vdev;
}
@@ -1976,9 +2281,16 @@
dev->ion_client = msm_ion_client_create(-1, "vcap");
if (IS_ERR((void *)dev->ion_client)) {
pr_err("could not get ion client");
+ ret = PTR_ERR(dev->ion_client);
+ dev->ion_client = NULL;
goto rel_vcap_wq;
}
+ atomic_set(&dev->dbg_p.vc_drop_count, 0);
+ ret = vcap_debugfs_init(dev);
+ if (ret < 0)
+ pr_err("VCAP debugfs failed to load");
+
dev->vc_tot_buf = 2;
atomic_set(&dev->vc_enabled, 0);
atomic_set(&dev->vp_enabled, 0);
@@ -1988,7 +2300,6 @@
init_waitqueue_head(&dev->vp_dummy_waitq);
vcap_disable(dev);
- dprintk(1, "Exit probe succesfully");
return 0;
rel_vcap_wq:
destroy_workqueue(dev->vcap_wq);
@@ -2012,6 +2323,7 @@
static int __devexit vcap_remove(struct platform_device *pdev)
{
struct vcap_dev *dev = vcap_ctrl;
+ vcap_debugfs_remove();
ion_client_destroy(dev->ion_client);
flush_workqueue(dev->vcap_wq);
destroy_workqueue(dev->vcap_wq);
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 572c272..3d81161 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -27,14 +27,6 @@
#include <media/vcap_fmt.h>
#include "vcap_vc.h"
-static unsigned debug;
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (debug >= level) \
- printk(KERN_DEBUG "VC: " fmt, ## arg); \
- } while (0)
-
void config_buffer(struct vcap_client_data *c_data,
struct vcap_buffer *buf,
void __iomem *y_addr,
@@ -73,7 +65,7 @@
vb_vc = vp_work->cd->vc_vidq.bufs[p.index];
if (NULL == vb_vc) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
return;
}
@@ -81,7 +73,7 @@
vb_vp = vp_work->cd->vp_in_vidq.bufs[p.index];
if (NULL == vb_vp) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
return;
}
@@ -145,7 +137,7 @@
irq = readl_relaxed(VCAP_VC_INT_STATUS);
- dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
+ pr_debug("%s: irq=0x%08x\n", __func__, irq);
c_data = dev->vc_client;
if (!c_data->streaming) {
@@ -254,6 +246,8 @@
v4l2_event_queue(dev->vfd, &v4l2_evt);
c_data->vc_action.top_field =
!c_data->vc_action.top_field;
+
+ atomic_inc(&dev->dbg_p.vc_drop_count);
continue;
}
buf = list_entry(c_data->vc_action.active.next,
@@ -296,12 +290,13 @@
{
struct vc_action *vc_action = &c_data->vc_action;
struct vcap_dev *dev;
+ struct timeval tv;
unsigned long flags = 0;
int rc, i, counter = 0;
struct vcap_buffer *buf;
dev = c_data->dev;
- dprintk(2, "Start Kickoff\n");
+ pr_debug("Start Kickoff\n");
if (dev->vc_client == NULL) {
pr_err("No active vc client\n");
@@ -344,6 +339,11 @@
c_data->vc_action.vc_ts.tv_usec =
c_data->vc_action.last_ts % VCAP_USEC;
+ atomic_set(&dev->dbg_p.vc_drop_count, 0);
+ do_gettimeofday(&tv);
+ dev->dbg_p.vc_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
rc = 0;
for (i = 0; i < c_data->vc_action.tot_buf; i++)
rc = rc << 1 | 0x2;
@@ -416,7 +416,7 @@
rc = readl_relaxed(VCAP_VC_NPL_CTRL);
writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
- dprintk(2, "%s: Starting VC configuration\n", __func__);
+ pr_debug("%s: Starting VC configuration\n", __func__);
writel_iowmb(0x00000002, VCAP_VC_NPL_CTRL);
writel_iowmb(0x00000004 | vc_format->color_space << 1 |
vc_format->mode << 3 |
@@ -464,7 +464,7 @@
writel_relaxed(0x00006b38, VCAP_VC_IN_CTRL5);
writel_iowmb(0x00000001 , VCAP_OFFSET(0x0d00));
- dprintk(2, "%s: Done VC configuration\n", __func__);
+ pr_debug("%s: Done VC configuration\n", __func__);
return 0;
}
@@ -473,7 +473,7 @@
{
int result;
result = readl_relaxed(VCAP_HARDWARE_VERSION_REG);
- dprintk(1, "Hardware version: %08x\n", result);
+ pr_debug("Hardware version: %08x\n", result);
if (result != VCAP_HARDWARE_VERSION)
return -ENODEV;
INIT_WORK(&dev->vc_to_vp_work.work, mov_buf_to_vp);
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index 4c3ff16..c7de465 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -25,14 +25,6 @@
#include <media/vcap_fmt.h>
#include "vcap_vp.h"
-static unsigned debug;
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (debug >= level) \
- printk(KERN_DEBUG "VP: " fmt, ## arg); \
- } while (0)
-
void config_nr_buffer(struct vcap_client_data *c_data,
struct vcap_buffer *buf)
{
@@ -72,10 +64,10 @@
if (!c_data->streaming)
return -ENOEXEC;
dev = c_data->dev;
- dprintk(2, "Start setup buffers\n");
+ pr_debug("VP: Start setup buffers\n");
if (dev->vp_shutdown) {
- dprintk(1, "%s: VP shutting down, no buf setup\n",
+ pr_debug("%s: VP shutting down, no buf setup\n",
__func__);
return -EPERM;
}
@@ -86,7 +78,7 @@
spin_lock_irqsave(&dev->vp_client->cap_slock, flags);
if (list_empty(&vp_act->in_active)) {
spin_unlock_irqrestore(&dev->vp_client->cap_slock, flags);
- dprintk(1, "%s: VP We have no more input buffers\n",
+ pr_debug("%s: VP We have no more input buffers\n",
__func__);
return -EAGAIN;
}
@@ -94,7 +86,7 @@
if (list_empty(&vp_act->out_active)) {
spin_unlock_irqrestore(&dev->vp_client->cap_slock,
flags);
- dprintk(1, "%s: VP We have no more output buffers\n",
+ pr_debug("%s: VP We have no more output buffers\n",
__func__);
return -EAGAIN;
}
@@ -136,7 +128,7 @@
vb_vc = vp_work->cd->vc_vidq.bufs[p.index];
if (NULL == vb_vc) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
return;
}
@@ -144,7 +136,7 @@
vb_vp = vp_work->cd->vp_in_vidq.bufs[p.index];
if (NULL == vb_vp) {
- dprintk(1, "%s: buffer is NULL\n", __func__);
+ pr_debug("%s: buffer is NULL\n", __func__);
vcvp_qbuf(&vp_work->cd->vp_in_vidq, &p);
return;
}
@@ -158,7 +150,7 @@
/* This call should not fail */
rc = vcvp_qbuf(&vp_work->cd->vc_vidq, &p);
if (rc < 0) {
- dprintk(1, "%s: qbuf to vc failed\n", __func__);
+ pr_err("%s: qbuf to vc failed\n", __func__);
buf_vp->ion_handle = buf_vc->ion_handle;
buf_vp->paddr = buf_vc->paddr;
buf_vc->ion_handle = NULL;
@@ -197,6 +189,7 @@
struct vp_work_t *vp_work = container_of(work, struct vp_work_t, work);
struct vcap_dev *dev;
struct vp_action *vp_act;
+ struct timeval tv;
unsigned long flags = 0;
uint32_t irq;
int rc;
@@ -278,6 +271,11 @@
writel_iowmb(0x00000000 | top_field, VCAP_VP_CTRL);
writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
enable_irq(dev->vpirq->start);
+
+ do_gettimeofday(&tv);
+ dev->dbg_p.vp_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
writel_iowmb(irq, VCAP_VP_INT_CLEAR);
}
@@ -288,6 +286,8 @@
struct v4l2_event v4l2_evt;
uint32_t irq;
int rc;
+ struct timeval tv;
+ uint32_t new_ts;
irq = readl_relaxed(VCAP_VP_INT_STATUS);
if (dev->vp_dummy_event == true) {
@@ -304,7 +304,7 @@
}
if (irq & 0x01000000) {
v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
- VCAP_VC_LINE_ERR_EVENT;
+ VCAP_VP_REG_W_ERR_EVENT;
v4l2_event_queue(dev->vfd, &v4l2_evt);
}
if (irq & 0x00020000) {
@@ -318,7 +318,7 @@
v4l2_event_queue(dev->vfd, &v4l2_evt);
}
- dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
+ pr_debug("%s: irq=0x%08x\n", __func__, irq);
if (!(irq & (VP_PIC_DONE | VP_MODE_CHANGE))) {
writel_relaxed(irq, VCAP_VP_INT_CLEAR);
pr_err("VP IRQ shows some error\n");
@@ -341,6 +341,17 @@
return -EAGAIN;
}
+ do_gettimeofday(&tv);
+ new_ts = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+ if (new_ts > dev->dbg_p.vp_timestamp) {
+ dev->dbg_p.vp_ewma = ((new_ts - dev->dbg_p.vp_timestamp) /
+ 10 + (dev->dbg_p.vp_ewma / 10 * 9));
+ }
+
+ dev->dbg_p.vp_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
INIT_WORK(&dev->vp_work.work, vp_wq_fnc);
dev->vp_work.cd = c_data;
rc = queue_work(dev->vcap_wq, &dev->vp_work.work);
@@ -464,7 +475,7 @@
}
handle = ion_alloc(dev->ion_client, size, SZ_4K,
- ION_HEAP(ION_CP_MM_HEAP_ID));
+ ION_HEAP(ION_CP_MM_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
pr_err("%s: ion_alloc failed\n", __func__);
return -ENOMEM;
@@ -483,7 +494,7 @@
return rc;
}
- vaddr = ion_map_kernel(dev->ion_client, handle, ionflag);
+ vaddr = ion_map_kernel(dev->ion_client, handle);
if (IS_ERR(vaddr)) {
pr_err("%s: Map motion buffer failed\n", __func__);
ion_free(dev->ion_client, handle);
@@ -535,7 +546,7 @@
tot_size = frame_size / 2 * 3;
handle = ion_alloc(dev->ion_client, tot_size, SZ_4K,
- ION_HEAP(ION_CP_MM_HEAP_ID));
+ ION_HEAP(ION_CP_MM_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
pr_err("%s: ion_alloc failed\n", __func__);
return -ENOMEM;
@@ -663,9 +674,9 @@
uint32_t reg;
int rc = 0;
- dprintk(2, "%s: Start VP dummy event\n", __func__);
+ pr_debug("%s: Start VP dummy event\n", __func__);
handle = ion_alloc(dev->ion_client, 0x1200, SZ_4K,
- ION_HEAP(ION_CP_MM_HEAP_ID));
+ ION_HEAP(ION_CP_MM_HEAP_ID), 0);
if (IS_ERR_OR_NULL(handle)) {
pr_err("%s: ion_alloc failed\n", __func__);
return -ENOMEM;
@@ -723,7 +734,7 @@
c_data->vp_out_fmt.height = height;
ion_free(dev->ion_client, handle);
- dprintk(2, "%s: Exit VP dummy event\n", __func__);
+ pr_debug("%s: Exit VP dummy event\n", __func__);
return rc;
}
@@ -731,6 +742,7 @@
{
struct vcap_dev *dev;
struct vp_action *vp_act;
+ struct timeval tv;
unsigned long flags = 0;
unsigned int chroma_fmt = 0;
int size;
@@ -740,7 +752,7 @@
return -ENOEXEC;
dev = c_data->dev;
- dprintk(2, "Start Kickoff\n");
+ pr_debug("Start VP Kickoff\n");
if (dev->vp_client == NULL) {
pr_err("No active vp client\n");
@@ -815,6 +827,11 @@
writel_iowmb(0x00010000 | top_field, VCAP_VP_CTRL);
atomic_set(&c_data->dev->vp_enabled, 1);
enable_irq(dev->vpirq->start);
+
+ do_gettimeofday(&tv);
+ dev->dbg_p.vp_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
return 0;
}
@@ -822,10 +839,11 @@
{
struct vcap_dev *dev;
struct vp_action *vp_act;
+ struct timeval tv;
int rc;
bool top_field = 0;
- dprintk(2, "Start Continue\n");
+ pr_debug("Start VP Continue\n");
dev = c_data->dev;
if (dev->vp_client == NULL) {
@@ -854,5 +872,10 @@
atomic_set(&c_data->dev->vp_enabled, 1);
enable_irq(dev->vpirq->start);
+
+ do_gettimeofday(&tv);
+ dev->dbg_p.vp_timestamp = (uint32_t) (tv.tv_sec * VCAP_USEC +
+ tv.tv_usec);
+
return 0;
}
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index a7d13a8..668cc73 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -1330,14 +1330,11 @@
return -EINVAL;
}
- mutex_lock(&q->q_lock);
ret = __vb2_get_done_vb(q, &vb, nonblocking);
if (ret < 0) {
dprintk(1, "dqbuf: error getting next done buffer\n");
- mutex_unlock(&q->q_lock);
return ret;
}
- mutex_unlock(&q->q_lock);
ret = call_qop(q, buf_finish, vb);
if (ret) {
dprintk(1, "dqbuf: buffer finish failed\n");
@@ -1449,17 +1446,14 @@
/*
* Let driver notice that streaming state has been enabled.
*/
- mutex_lock(&q->q_lock);
ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
if (ret) {
dprintk(1, "streamon: driver refused to start streaming\n");
__vb2_queue_cancel(q);
- mutex_unlock(&q->q_lock);
return ret;
}
q->streaming = 1;
- mutex_unlock(&q->q_lock);
dprintk(3, "Streamon successful\n");
return 0;
}
@@ -1733,7 +1727,6 @@
INIT_LIST_HEAD(&q->queued_list);
INIT_LIST_HEAD(&q->done_list);
spin_lock_init(&q->done_lock);
- mutex_init(&q->q_lock);
init_waitqueue_head(&q->done_wq);
if (q->buf_struct_size == 0)
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index c1a392e2..97bc7c3 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -56,7 +56,7 @@
goto client_failed;
}
mem->ion_handle = ion_alloc(mem->client, mem->size, SZ_4K,
- (0x1 << ION_CP_MM_HEAP_ID | 0x1 << ION_IOMMU_HEAP_ID));
+ (0x1 << ION_CP_MM_HEAP_ID | 0x1 << ION_IOMMU_HEAP_ID), 0);
if (IS_ERR((void *)mem->ion_handle)) {
pr_err("%s Could not allocate\n", __func__);
goto alloc_failed;
@@ -64,7 +64,7 @@
rc = ion_map_iommu(mem->client, mem->ion_handle,
-1, 0, SZ_4K, 0,
(unsigned long *)&phyaddr,
- (unsigned long *)&len, UNCACHED, 0);
+ (unsigned long *)&len, 0, 0);
if (rc < 0) {
pr_err("%s Could not get physical address\n", __func__);
goto phys_failed;
@@ -192,7 +192,7 @@
return PTR_ERR(mem->ion_handle);
}
rc = ion_map_iommu(client, mem->ion_handle, domain_num, 0,
- SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, UNCACHED, 0);
+ SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, 0, 0);
if (rc < 0)
ion_free(client, mem->ion_handle);
#elif CONFIG_ANDROID_PMEM
diff --git a/drivers/mfd/marimba-core.c b/drivers/mfd/marimba-core.c
index 70ec2ec..6a8ea6e 100644
--- a/drivers/mfd/marimba-core.c
+++ b/drivers/mfd/marimba-core.c
@@ -76,12 +76,16 @@
rc = marimba_read_bit_mask(marimba, 0x00, &bahama_version, 1, 0x1F);
if (rc < 0)
return rc;
+ pr_debug("%s: Bahama version: 0x%x\n", __func__, bahama_version);
switch (bahama_version) {
case 0x08: /* varient of bahama v1 */
case 0x10:
case 0x00:
return BAHAMA_VER_1_0;
case 0x09: /* variant of bahama v2 */
+ case 0x0a: /* variant of bahama v2.1 */
+ /* Falling through because initialization */
+ /* and configuration for 2.0 and 2.1 are same */
return BAHAMA_VER_2_0;
default:
return BAHAMA_VER_UNSUPPORTED;
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index 9815f6e..48bc92d 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -33,6 +33,11 @@
#define REG_RTC_BASE 0x11D
#define REG_IRQ_BASE 0x1BB
+#define REG_BATT_ALARM_THRESH 0x023
+#define REG_BATT_ALARM_CTRL1 0x024
+#define REG_BATT_ALARM_CTRL2 0x021
+#define REG_BATT_ALARM_PWM_CTRL 0x020
+
#define REG_SPK_BASE 0x253
#define REG_SPK_REGISTERS 6
@@ -336,6 +341,27 @@
.pdata_size = sizeof(struct pm8xxx_tm_core_data),
};
+static const struct resource batt_alarm_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("pm8921_batt_alarm_irq", PM8038_BATT_ALARM_IRQ),
+};
+
+static struct pm8xxx_batt_alarm_core_data batt_alarm_cdata = {
+ .irq_name = "pm8921_batt_alarm_irq",
+ .reg_addr_threshold = REG_BATT_ALARM_THRESH,
+ .reg_addr_ctrl1 = REG_BATT_ALARM_CTRL1,
+ .reg_addr_ctrl2 = REG_BATT_ALARM_CTRL2,
+ .reg_addr_pwm_ctrl = REG_BATT_ALARM_PWM_CTRL,
+};
+
+static struct mfd_cell batt_alarm_cell __devinitdata = {
+ .name = PM8XXX_BATT_ALARM_DEV_NAME,
+ .id = -1,
+ .resources = batt_alarm_cell_resources,
+ .num_resources = ARRAY_SIZE(batt_alarm_cell_resources),
+ .platform_data = &batt_alarm_cdata,
+ .pdata_size = sizeof(struct pm8xxx_batt_alarm_core_data),
+};
+
static const struct resource ccadc_cell_resources[] __devinitconst = {
SINGLE_IRQ_RESOURCE("PM8921_BMS_CCADC_EOC", PM8921_BMS_CCADC_EOC),
};
@@ -661,6 +687,13 @@
goto bail;
}
+ ret = mfd_add_devices(pmic->dev, 0, &batt_alarm_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add battery alarm subdevice ret=%d\n", ret);
+ goto bail;
+ }
+
if (pdata->ccadc_pdata) {
ccadc_cell.platform_data = pdata->ccadc_pdata;
ccadc_cell.pdata_size =
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 0ea843c..65537e4 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/mfd/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
@@ -257,12 +258,20 @@
u8 byte[4];
struct mfd_cell *dev;
int size;
+ int num_irqs;
} wcd9xxx_codecs[] = {
- {{0x2, 0x0, 0x0, 0x1}, tabla_devs, ARRAY_SIZE(tabla_devs)},
- {{0x1, 0x0, 0x0, 0x1}, tabla1x_devs, ARRAY_SIZE(tabla1x_devs)},
- {{0x0, 0x0, 0x2, 0x1}, taiko_devs, ARRAY_SIZE(taiko_devs)},
- {{0x0, 0x0, 0x0, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
- {{0x1, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
+ {{0x2, 0x0, 0x0, 0x1}, tabla_devs, ARRAY_SIZE(tabla_devs),
+ TABLA_NUM_IRQS},
+ {{0x1, 0x0, 0x0, 0x1}, tabla1x_devs, ARRAY_SIZE(tabla1x_devs),
+ TABLA_NUM_IRQS},
+ {{0x0, 0x0, 0x2, 0x1}, taiko_devs, ARRAY_SIZE(taiko_devs),
+ TAIKO_NUM_IRQS},
+ {{0x0, 0x0, 0x0, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs),
+ SITAR_NUM_IRQS},
+ {{0x1, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs),
+ SITAR_NUM_IRQS},
+ {{0x2, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs),
+ SITAR_NUM_IRQS},
};
static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
@@ -311,21 +320,21 @@
}
}
static int wcd9xxx_check_codec_type(struct wcd9xxx *wcd9xxx,
- struct mfd_cell **wcd9xxx_dev,
- int *wcd9xxx_dev_size)
+ struct mfd_cell **wcd9xxx_dev,
+ int *wcd9xxx_dev_size,
+ int *wcd9xxx_dev_num_irqs)
{
- struct wcd9xx_codec_type *cdc = wcd9xxx_codecs;
- int index;
+ int i;
int ret;
- index = WCD9XXX_A_CHIP_ID_BYTE_0;
- while (index <= WCD9XXX_A_CHIP_ID_BYTE_3) {
- ret = wcd9xxx_reg_read(wcd9xxx, index);
+ i = WCD9XXX_A_CHIP_ID_BYTE_0;
+ while (i <= WCD9XXX_A_CHIP_ID_BYTE_3) {
+ ret = wcd9xxx_reg_read(wcd9xxx, i);
if (ret < 0)
goto exit;
- wcd9xxx->idbyte[index-WCD9XXX_A_CHIP_ID_BYTE_0] = (u8)ret;
+ wcd9xxx->idbyte[i-WCD9XXX_A_CHIP_ID_BYTE_0] = (u8)ret;
pr_debug("%s: wcd9xx read = %x, byte = %x\n", __func__, ret,
- index);
- index++;
+ i);
+ i++;
}
/* Read codec version */
@@ -333,18 +342,20 @@
if (ret < 0)
goto exit;
wcd9xxx->version = (u8)ret & 0x1F;
-
- while (cdc < (cdc + ARRAY_SIZE(wcd9xxx_codecs)) && cdc != NULL) {
- if ((cdc->byte[0] == wcd9xxx->idbyte[0]) &&
- (cdc->byte[1] == wcd9xxx->idbyte[1]) &&
- (cdc->byte[2] == wcd9xxx->idbyte[2]) &&
- (cdc->byte[3] == wcd9xxx->idbyte[3])) {
- pr_info("%s: codec is %s", __func__, cdc->dev->name);
- *wcd9xxx_dev = cdc->dev;
- *wcd9xxx_dev_size = cdc->size;
+ i = 0;
+ while (i < ARRAY_SIZE(wcd9xxx_codecs)) {
+ if ((wcd9xxx_codecs[i].byte[0] == wcd9xxx->idbyte[0]) &&
+ (wcd9xxx_codecs[i].byte[1] == wcd9xxx->idbyte[1]) &&
+ (wcd9xxx_codecs[i].byte[2] == wcd9xxx->idbyte[2]) &&
+ (wcd9xxx_codecs[i].byte[3] == wcd9xxx->idbyte[3])) {
+ pr_info("%s: codec is %s", __func__,
+ wcd9xxx_codecs[i].dev->name);
+ *wcd9xxx_dev = wcd9xxx_codecs[i].dev;
+ *wcd9xxx_dev_size = wcd9xxx_codecs[i].size;
+ *wcd9xxx_dev_num_irqs = wcd9xxx_codecs[i].num_irqs;
break;
}
- cdc++;
+ i++;
}
if (*wcd9xxx_dev == NULL || *wcd9xxx_dev_size == 0)
ret = -ENODEV;
@@ -358,7 +369,7 @@
return ret;
}
-static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx, int irq)
+static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
{
int ret;
struct mfd_cell *wcd9xxx_dev = NULL;
@@ -378,6 +389,11 @@
wcd9xxx_bring_up(wcd9xxx);
+ ret = wcd9xxx_check_codec_type(wcd9xxx, &wcd9xxx_dev, &wcd9xxx_dev_size,
+ &wcd9xxx->num_irqs);
+ if (ret < 0)
+ goto err_irq;
+
if (wcd9xxx->irq != -1) {
ret = wcd9xxx_irq_init(wcd9xxx);
if (ret) {
@@ -385,11 +401,7 @@
goto err;
}
}
- ret = wcd9xxx_check_codec_type(wcd9xxx, &wcd9xxx_dev,
- &wcd9xxx_dev_size);
- if (ret < 0)
- goto err_irq;
ret = mfd_add_devices(wcd9xxx->dev, -1, wcd9xxx_dev, wcd9xxx_dev_size,
NULL, 0);
if (ret != 0) {
@@ -794,10 +806,12 @@
wcd9xxx->read_dev = wcd9xxx_i2c_read;
wcd9xxx->write_dev = wcd9xxx_i2c_write;
- wcd9xxx->irq = pdata->irq;
- wcd9xxx->irq_base = pdata->irq_base;
+ if (!wcd9xxx->dev->of_node) {
+ wcd9xxx->irq = pdata->irq;
+ wcd9xxx->irq_base = pdata->irq_base;
+ }
- ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
+ ret = wcd9xxx_device_init(wcd9xxx);
if (ret) {
pr_err("%s: error, initializing device failed\n", __func__);
goto err_device_init;
@@ -1071,7 +1085,6 @@
pdata->reset_gpio);
goto err;
}
- pdata->irq = -1;
ret = wcd9xxx_dt_parse_slim_interface_dev_info(dev,
&pdata->slimbus_slave_device);
@@ -1162,14 +1175,12 @@
}
wcd9xxx->read_dev = wcd9xxx_slim_read_device;
wcd9xxx->write_dev = wcd9xxx_slim_write_device;
- wcd9xxx->irq = pdata->irq;
- wcd9xxx->irq_base = pdata->irq_base;
wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
-
- if (pdata->num_irqs < TABLA_NUM_IRQS)
- pr_warn("%s: Not enough interrupt lines allocated\n", __func__);
-
wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
+ if (!wcd9xxx->dev->of_node) {
+ wcd9xxx->irq = pdata->irq;
+ wcd9xxx->irq_base = pdata->irq_base;
+ }
ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave);
if (ret) {
@@ -1189,7 +1200,7 @@
wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
- ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
+ ret = wcd9xxx_device_init(wcd9xxx);
if (ret) {
pr_err("%s: error, initializing device failed\n", __func__);
goto err_slim_add;
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 68c4557..103c1a3 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -18,26 +18,32 @@
#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+#include <linux/delay.h>
+#include <linux/irqdomain.h>
#include <linux/interrupt.h>
-
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
#include <mach/cpuidle.h>
#define BYTE_BIT_MASK(nr) (1UL << ((nr) % BITS_PER_BYTE))
#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
-struct wcd9xxx_irq {
- bool level;
-};
+#define WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS 100
-static struct wcd9xxx_irq wcd9xxx_irqs[TABLA_NUM_IRQS] = {
- [0] = { .level = 1},
-/* All other wcd9xxx interrupts are edge triggered */
+#ifdef CONFIG_OF
+struct wcd9xxx_irq_drv_data {
+ struct irq_domain *domain;
+ int irq;
};
+#endif
-static inline int irq_to_wcd9xxx_irq(struct wcd9xxx *wcd9xxx, int irq)
-{
- return irq - wcd9xxx->irq_base;
-}
+static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq);
+static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int irq);
+static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx);
+static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx);
+static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq);
static void wcd9xxx_irq_lock(struct irq_data *data)
{
@@ -56,8 +62,9 @@
*/
if (wcd9xxx->irq_masks_cur[i] != wcd9xxx->irq_masks_cache[i]) {
wcd9xxx->irq_masks_cache[i] = wcd9xxx->irq_masks_cur[i];
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MASK0+i,
- wcd9xxx->irq_masks_cur[i]);
+ wcd9xxx_reg_write(wcd9xxx,
+ WCD9XXX_A_INTR_MASK0 + i,
+ wcd9xxx->irq_masks_cur[i]);
}
}
@@ -67,7 +74,7 @@
static void wcd9xxx_irq_enable(struct irq_data *data)
{
struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
- int wcd9xxx_irq = irq_to_wcd9xxx_irq(wcd9xxx, data->irq);
+ int wcd9xxx_irq = virq_to_phyirq(wcd9xxx, data->irq);
wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
~(BYTE_BIT_MASK(wcd9xxx_irq));
}
@@ -75,9 +82,14 @@
static void wcd9xxx_irq_disable(struct irq_data *data)
{
struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
- int wcd9xxx_irq = irq_to_wcd9xxx_irq(wcd9xxx, data->irq);
+ int wcd9xxx_irq = virq_to_phyirq(wcd9xxx, data->irq);
wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
- |= BYTE_BIT_MASK(wcd9xxx_irq);
+ |= BYTE_BIT_MASK(wcd9xxx_irq);
+}
+
+static void wcd9xxx_irq_mask(struct irq_data *d)
+{
+ /* do nothing but required as linux calls irq_mask without NULL check */
}
static struct irq_chip wcd9xxx_irq_chip = {
@@ -86,6 +98,7 @@
.irq_bus_sync_unlock = wcd9xxx_irq_sync_unlock,
.irq_disable = wcd9xxx_irq_disable,
.irq_enable = wcd9xxx_irq_enable,
+ .irq_mask = wcd9xxx_irq_mask,
};
enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
@@ -106,11 +119,17 @@
{
enum wcd9xxx_pm_state os;
- /* wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
+ /*
+ * wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
* and its subroutines only motly.
* but btn0_lpress_fn is not wcd9xxx_irq_thread's subroutine and
- * it can race with wcd9xxx_irq_thread.
- * so need to embrace wlock_holders with mutex.
+ * It can race with wcd9xxx_irq_thread.
+ * So need to embrace wlock_holders with mutex.
+ *
+ * If system didn't resume, we can simply return false so codec driver's
+ * IRQ handler can return without handling IRQ.
+ * As interrupt line is still active, codec will have another IRQ to
+ * retry shortly.
*/
mutex_lock(&wcd9xxx->pm_lock);
if (wcd9xxx->wlock_holders++ == 0) {
@@ -124,11 +143,11 @@
WCD9XXX_PM_AWAKE)) ==
WCD9XXX_PM_SLEEPABLE ||
(os == WCD9XXX_PM_AWAKE)),
- 5 * HZ)) {
- pr_err("%s: system didn't resume within 5000ms, state %d, "
- "wlock %d\n", __func__, wcd9xxx->pm_state,
- wcd9xxx->wlock_holders);
- WARN_ON(1);
+ msecs_to_jiffies(WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
+ pr_warn("%s: system didn't resume within %dms, s %d, w %d\n",
+ __func__,
+ WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx->pm_state,
+ wcd9xxx->wlock_holders);
wcd9xxx_unlock_sleep(wcd9xxx);
return false;
}
@@ -141,8 +160,14 @@
{
mutex_lock(&wcd9xxx->pm_lock);
if (--wcd9xxx->wlock_holders == 0) {
- wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
- pr_debug("%s: releasing wake lock\n", __func__);
+ pr_debug("%s: releasing wake lock pm_state %d -> %d\n",
+ __func__, wcd9xxx->pm_state, WCD9XXX_PM_SLEEPABLE);
+ /*
+ * if wcd9xxx_lock_sleep failed, pm_state would be still
+ * WCD9XXX_PM_ASLEEP, don't overwrite
+ */
+ if (likely(wcd9xxx->pm_state == WCD9XXX_PM_AWAKE))
+ wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
pm_qos_update_request(&wcd9xxx->pm_qos_req,
PM_QOS_DEFAULT_VALUE);
}
@@ -153,62 +178,72 @@
static void wcd9xxx_irq_dispatch(struct wcd9xxx *wcd9xxx, int irqbit)
{
- if ((irqbit <= TABLA_IRQ_MBHC_INSERTION) &&
- (irqbit >= TABLA_IRQ_MBHC_REMOVAL)) {
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 +
- BIT_BYTE(irqbit), BYTE_BIT_MASK(irqbit));
+ if ((irqbit <= WCD9XXX_IRQ_MBHC_INSERTION) &&
+ (irqbit >= WCD9XXX_IRQ_MBHC_REMOVAL)) {
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
+ BIT_BYTE(irqbit),
+ BYTE_BIT_MASK(irqbit));
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MODE, 0x02);
- handle_nested_irq(wcd9xxx->irq_base + irqbit);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
+ handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
} else {
- handle_nested_irq(wcd9xxx->irq_base + irqbit);
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_CLEAR0 +
- BIT_BYTE(irqbit), BYTE_BIT_MASK(irqbit));
+ handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
+ BIT_BYTE(irqbit),
+ BYTE_BIT_MASK(irqbit));
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MODE, 0x02);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
}
}
+static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
+{
+ return (wcd9xxx->num_irqs / 8) + ((wcd9xxx->num_irqs % 8) ? 1 : 0);
+}
+
static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
{
int ret;
- struct wcd9xxx *wcd9xxx = data;
- u8 status[WCD9XXX_NUM_IRQ_REGS];
int i;
+ struct wcd9xxx *wcd9xxx = data;
+ int num_irq_regs = wcd9xxx_num_irq_regs(wcd9xxx);
+ u8 status[num_irq_regs];
if (unlikely(wcd9xxx_lock_sleep(wcd9xxx) == false)) {
dev_err(wcd9xxx->dev, "Failed to hold suspend\n");
return IRQ_NONE;
}
- ret = wcd9xxx_bulk_read(wcd9xxx, TABLA_A_INTR_STATUS0,
- WCD9XXX_NUM_IRQ_REGS, status);
+ ret = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_INTR_STATUS0,
+ num_irq_regs, status);
if (ret < 0) {
dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
ret);
wcd9xxx_unlock_sleep(wcd9xxx);
return IRQ_NONE;
}
+
/* Apply masking */
- for (i = 0; i < WCD9XXX_NUM_IRQ_REGS; i++)
+ for (i = 0; i < num_irq_regs; i++)
status[i] &= ~wcd9xxx->irq_masks_cur[i];
/* Find out which interrupt was triggered and call that interrupt's
* handler function
*/
- if (status[BIT_BYTE(TABLA_IRQ_SLIMBUS)] &
- BYTE_BIT_MASK(TABLA_IRQ_SLIMBUS))
- wcd9xxx_irq_dispatch(wcd9xxx, TABLA_IRQ_SLIMBUS);
+ if (status[BIT_BYTE(WCD9XXX_IRQ_SLIMBUS)] &
+ BYTE_BIT_MASK(WCD9XXX_IRQ_SLIMBUS))
+ wcd9xxx_irq_dispatch(wcd9xxx, WCD9XXX_IRQ_SLIMBUS);
/* Since codec has only one hardware irq line which is shared by
* codec's different internal interrupts, so it's possible master irq
* handler dispatches multiple nested irq handlers after breaking
* order. Dispatch MBHC interrupts order to follow MBHC state
* machine's order */
- for (i = TABLA_IRQ_MBHC_INSERTION; i >= TABLA_IRQ_MBHC_REMOVAL; i--) {
+ for (i = WCD9XXX_IRQ_MBHC_INSERTION;
+ i >= WCD9XXX_IRQ_MBHC_REMOVAL; i--) {
if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i))
wcd9xxx_irq_dispatch(wcd9xxx, i);
}
- for (i = TABLA_IRQ_BG_PRECHARGE; i < TABLA_NUM_IRQS; i++) {
+ for (i = WCD9XXX_IRQ_BG_PRECHARGE; i < wcd9xxx->num_irqs; i++) {
if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i))
wcd9xxx_irq_dispatch(wcd9xxx, i);
}
@@ -217,59 +252,105 @@
return IRQ_HANDLED;
}
+void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx, int irq, void *data)
+{
+ free_irq(phyirq_to_virq(wcd9xxx, irq), data);
+}
+
+void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ enable_irq(phyirq_to_virq(wcd9xxx, irq));
+}
+
+void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ disable_irq_nosync(phyirq_to_virq(wcd9xxx, irq));
+}
+
+void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq)
+{
+ disable_irq(phyirq_to_virq(wcd9xxx, irq));
+}
+
+static int wcd9xxx_irq_setup_downstream_irq(struct wcd9xxx *wcd9xxx)
+{
+ int irq, virq, ret;
+
+ pr_debug("%s: enter\n", __func__);
+
+ for (irq = 0; irq < wcd9xxx->num_irqs; irq++) {
+ /* Map OF irq */
+ virq = wcd9xxx_map_irq(wcd9xxx, irq);
+ pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
+ if (virq == NO_IRQ) {
+ pr_err("%s, No interrupt specifier for irq %d\n",
+ __func__, irq);
+ return NO_IRQ;
+ }
+
+ ret = irq_set_chip_data(virq, wcd9xxx);
+ if (ret) {
+ pr_err("%s: Failed to configure irq %d (%d)\n",
+ __func__, irq, ret);
+ return ret;
+ }
+
+ if (wcd9xxx->irq_level_high[irq])
+ irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip,
+ handle_level_irq);
+ else
+ irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip,
+ handle_edge_irq);
+
+ irq_set_nested_thread(virq, 1);
+ }
+
+ pr_debug("%s: leave\n", __func__);
+
+ return 0;
+}
+
int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx)
{
- int ret;
- unsigned int i, cur_irq;
+ int i, ret;
+ u8 irq_level[wcd9xxx_num_irq_regs(wcd9xxx)];
mutex_init(&wcd9xxx->irq_lock);
+ wcd9xxx->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx);
if (!wcd9xxx->irq) {
- dev_warn(wcd9xxx->dev,
- "No interrupt specified, no interrupts\n");
- wcd9xxx->irq_base = 0;
- return 0;
+ pr_warn("%s: irq driver is not yet initialized\n", __func__);
+ mutex_destroy(&wcd9xxx->irq_lock);
+ return -EPROBE_DEFER;
+ }
+ pr_debug("%s: probed irq %d\n", __func__, wcd9xxx->irq);
+
+ /* Setup downstream IRQs */
+ ret = wcd9xxx_irq_setup_downstream_irq(wcd9xxx);
+ if (ret) {
+ pr_err("%s: Failed to setup downstream IRQ\n", __func__);
+ wcd9xxx_irq_put_upstream_irq(wcd9xxx);
+ return ret;
}
- if (!wcd9xxx->irq_base) {
- dev_err(wcd9xxx->dev,
- "No interrupt base specified, no interrupts\n");
- return 0;
- }
- /* Mask the individual interrupt sources */
- for (i = 0, cur_irq = wcd9xxx->irq_base; i < TABLA_NUM_IRQS; i++,
- cur_irq++) {
+ /* All other wcd9xxx interrupts are edge triggered */
+ wcd9xxx->irq_level_high[0] = true;
- irq_set_chip_data(cur_irq, wcd9xxx);
-
- if (wcd9xxx_irqs[i].level)
- irq_set_chip_and_handler(cur_irq, &wcd9xxx_irq_chip,
- handle_level_irq);
- else
- irq_set_chip_and_handler(cur_irq, &wcd9xxx_irq_chip,
- handle_edge_irq);
-
- irq_set_nested_thread(cur_irq, 1);
-
- /* ARM needs us to explicitly flag the IRQ as valid
- * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
- set_irq_flags(cur_irq, IRQF_VALID);
-#else
- set_irq_noprobe(cur_irq);
-#endif
-
+ /* mask all the interrupts */
+ memset(irq_level, 0, wcd9xxx_num_irq_regs(wcd9xxx));
+ for (i = 0; i < wcd9xxx->num_irqs; i++) {
wcd9xxx->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
wcd9xxx->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
- wcd9xxx->irq_level[BIT_BYTE(i)] |= wcd9xxx_irqs[i].level <<
- (i % BITS_PER_BYTE);
+ irq_level[BIT_BYTE(i)] |=
+ wcd9xxx->irq_level_high[i] << (i % BITS_PER_BYTE);
}
- for (i = 0; i < WCD9XXX_NUM_IRQ_REGS; i++) {
+
+ for (i = 0; i < wcd9xxx_num_irq_regs(wcd9xxx); i++) {
/* Initialize interrupt mask and level registers */
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_LEVEL0 + i,
- wcd9xxx->irq_level[i]);
- wcd9xxx_reg_write(wcd9xxx, TABLA_A_INTR_MASK0 + i,
- wcd9xxx->irq_masks_cur[i]);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_LEVEL0 + i,
+ irq_level[i]);
+ wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MASK0 + i,
+ wcd9xxx->irq_masks_cur[i]);
}
ret = request_threaded_irq(wcd9xxx->irq, NULL, wcd9xxx_irq_thread,
@@ -294,18 +375,226 @@
free_irq(wcd9xxx->irq, wcd9xxx);
}
- if (ret)
+ if (ret) {
+ pr_err("%s: Failed to init wcd9xxx irq\n", __func__);
+ wcd9xxx_irq_put_upstream_irq(wcd9xxx);
mutex_destroy(&wcd9xxx->irq_lock);
+ }
return ret;
}
+int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq, irq_handler_t handler,
+ const char *name, void *data)
+{
+ int virq;
+
+ virq = phyirq_to_virq(wcd9xxx, irq);
+
+ /*
+ * ARM needs us to explicitly flag the IRQ as valid
+ * and will set them noprobe when we do so.
+ */
+#ifdef CONFIG_ARM
+ set_irq_flags(virq, IRQF_VALID);
+#else
+ set_irq_noprobe(virq);
+#endif
+
+ return request_threaded_irq(virq, NULL, handler, IRQF_TRIGGER_RISING,
+ name, data);
+}
+
void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx)
{
if (wcd9xxx->irq) {
disable_irq_wake(wcd9xxx->irq);
free_irq(wcd9xxx->irq, wcd9xxx);
+ /* Release parent's of node */
+ wcd9xxx_irq_put_upstream_irq(wcd9xxx);
device_init_wakeup(wcd9xxx->dev, 0);
}
mutex_destroy(&wcd9xxx->irq_lock);
}
+
+#ifndef CONFIG_OF
+static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int offset)
+{
+ return wcd9xxx->irq_base + offset;
+}
+
+static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq)
+{
+ return virq - wcd9xxx->irq_base;
+}
+
+static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx)
+{
+ return wcd9xxx->irq;
+}
+
+static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx)
+{
+ /* Do nothing */
+}
+
+static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ return phyirq_to_virq(wcd9xxx, irq);
+}
+#else
+int __init wcd9xxx_irq_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct wcd9xxx_irq_drv_data *data;
+
+ pr_debug("%s: node %s, node parent %s\n", __func__,
+ node->name, node->parent->name);
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /*
+ * wcd9xxx_intc interrupt controller supports N to N irq mapping with
+ * single cell binding with irq numbers(offsets) only.
+ * Use irq_domain_simple_ops that has irq_domain_simple_map and
+ * irq_domain_xlate_onetwocell.
+ */
+ data->domain = irq_domain_add_linear(node, WCD9XXX_MAX_NUM_IRQS,
+ &irq_domain_simple_ops, data);
+ if (!data->domain) {
+ kfree(data);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static struct wcd9xxx_irq_drv_data *
+wcd9xxx_get_irq_drv_d(const struct wcd9xxx *wcd9xxx)
+{
+ struct device_node *pnode;
+ struct irq_domain *domain;
+
+ pnode = of_irq_find_parent(wcd9xxx->dev->of_node);
+ /* Shouldn't happen */
+ if (unlikely(!pnode))
+ return NULL;
+
+ domain = irq_find_host(pnode);
+ return (struct wcd9xxx_irq_drv_data *)domain->host_data;
+}
+
+static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int offset)
+{
+ struct wcd9xxx_irq_drv_data *data;
+
+ data = wcd9xxx_get_irq_drv_d(wcd9xxx);
+ if (!data) {
+ pr_warn("%s: not registered to interrupt controller\n",
+ __func__);
+ return -EINVAL;
+ }
+ return irq_linear_revmap(data->domain, offset);
+}
+
+static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq)
+{
+ struct irq_data *irq_data = irq_get_irq_data(virq);
+ return irq_data->hwirq;
+}
+
+static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx)
+{
+ struct wcd9xxx_irq_drv_data *data;
+
+ /* Hold parent's of node */
+ if (!of_node_get(of_irq_find_parent(wcd9xxx->dev->of_node)))
+ return -EINVAL;
+
+ data = wcd9xxx_get_irq_drv_d(wcd9xxx);
+ if (!data) {
+ pr_err("%s: interrupt controller is not registerd\n", __func__);
+ return 0;
+ }
+
+ rmb();
+ return data->irq;
+}
+
+static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx)
+{
+ /* Hold parent's of node */
+ of_node_put(of_irq_find_parent(wcd9xxx->dev->of_node));
+}
+
+static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq)
+{
+ return of_irq_to_resource(wcd9xxx->dev->of_node, irq, NULL);
+}
+
+static int __devinit wcd9xxx_irq_probe(struct platform_device *pdev)
+{
+ int irq;
+ struct irq_domain *domain;
+ struct wcd9xxx_irq_drv_data *data;
+ int ret = -EINVAL;
+
+ irq = platform_get_irq_byname(pdev, "cdc-int");
+ if (irq < 0) {
+ dev_err(&pdev->dev, "%s: Couldn't find cdc-int node(%d)\n",
+ __func__, irq);
+ return -EINVAL;
+ } else {
+ dev_dbg(&pdev->dev, "%s: virq = %d\n", __func__, irq);
+ domain = irq_find_host(pdev->dev.of_node);
+ data = (struct wcd9xxx_irq_drv_data *)domain->host_data;
+ data->irq = irq;
+ wmb();
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int wcd9xxx_irq_remove(struct platform_device *pdev)
+{
+ struct irq_domain *domain;
+ struct wcd9xxx_irq_drv_data *data;
+
+ domain = irq_find_host(pdev->dev.of_node);
+ data = (struct wcd9xxx_irq_drv_data *)domain->host_data;
+ data->irq = 0;
+ wmb();
+
+ return 0;
+}
+
+static const struct of_device_id of_match[] = {
+ { .compatible = "qcom,wcd9xxx-irq" },
+ { }
+};
+
+static struct platform_driver wcd9xxx_irq_driver = {
+ .probe = wcd9xxx_irq_probe,
+ .remove = wcd9xxx_irq_remove,
+ .driver = {
+ .name = "wcd9xxx_intc",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(of_match),
+ },
+};
+
+static int wcd9xxx_irq_drv_init(void)
+{
+ return platform_driver_register(&wcd9xxx_irq_driver);
+}
+subsys_initcall(wcd9xxx_irq_drv_init);
+
+static void wcd9xxx_irq_drv_exit(void)
+{
+ platform_driver_unregister(&wcd9xxx_irq_driver);
+}
+module_exit(wcd9xxx_irq_drv_exit);
+#endif /* CONFIG_OF */
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index d6d209b..12f896e 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -38,6 +38,7 @@
#include <mach/msm_bus_board.h>
#include <mach/scm.h>
#include <mach/peripheral-loader.h>
+#include <mach/socinfo.h>
#include "qseecom_legacy.h"
#define QSEECOM_DEV "qseecom"
@@ -142,7 +143,6 @@
static DEFINE_MUTEX(pil_access_lock);
static DEFINE_MUTEX(qsee_bw_mutex);
-static DEFINE_MUTEX(qsee_sfpb_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
static int qsee_bw_count;
@@ -180,6 +180,7 @@
int send_resp_flag;
uint32_t qseos_version;
+ struct device *pdev;
};
struct qseecom_client_handle {
@@ -209,9 +210,16 @@
atomic_t ioctl_count;
};
+struct clk *ce_core_clk;
+struct clk *ce_clk;
+struct clk *ce_core_src_clk;
+struct clk *ce_bus_clk;
+
/* Function proto types */
static int qsee_vote_for_clock(int32_t);
static void qsee_disable_clock_vote(int32_t);
+static int __qseecom_init_clk(void);
+static void __qseecom_disable_clk(void);
static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
struct qseecom_register_listener_req *svc)
@@ -254,7 +262,6 @@
struct qseecom_register_listener_req *listener)
{
int ret = 0;
- unsigned int flags = 0;
struct qseecom_register_listener_ireq req;
struct qseecom_command_scm_resp resp;
ion_phys_addr_t pa;
@@ -271,8 +278,7 @@
ret = ion_phys(qseecom.ion_clnt, svc->ihandle, &pa, &svc->sb_length);
/* Populate the structure for sending scm call to load image */
- svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
- svc->ihandle, flags);
+ svc->sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt, svc->ihandle);
svc->sb_phys = pa;
if (qseecom.qseos_version == QSEOS_VERSION_14) {
@@ -494,7 +500,6 @@
{
ion_phys_addr_t pa;
int32_t ret;
- unsigned int flags = 0;
struct qseecom_set_sb_mem_param_req req;
uint32_t len;
@@ -513,8 +518,7 @@
ret = ion_phys(qseecom.ion_clnt, data->client.ihandle, &pa, &len);
/* Populate the structure for sending scm call to load image */
data->client.sb_virt = (char *) ion_map_kernel(qseecom.ion_clnt,
- data->client.ihandle,
- flags);
+ data->client.ihandle);
data->client.sb_phys = pa;
data->client.sb_length = req.sb_len;
data->client.user_virt_sb_base = req.virt_sb_base;
@@ -1202,28 +1206,41 @@
case CLK_DFAB:
mutex_lock(&qsee_bw_mutex);
if (!qsee_bw_count) {
- ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 1);
+ if (qsee_sfpb_bw_count > 0)
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 3);
+ else
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 1);
if (ret)
pr_err("DFAB Bandwidth req failed (%d)\n",
ret);
else
qsee_bw_count++;
+ } else {
+ qsee_bw_count++;
}
mutex_unlock(&qsee_bw_mutex);
break;
case CLK_SFPB:
- mutex_lock(&qsee_sfpb_bw_mutex);
+ mutex_lock(&qsee_bw_mutex);
if (!qsee_sfpb_bw_count) {
- ret = msm_bus_scale_client_update_request(
- qsee_perf_client, 2);
+ if (qsee_bw_count > 0)
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 3);
+ else
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 2);
+
if (ret)
pr_err("SFPB Bandwidth req failed (%d)\n",
ret);
else
qsee_sfpb_bw_count++;
+ } else {
+ qsee_sfpb_bw_count++;
}
- mutex_unlock(&qsee_sfpb_bw_mutex);
+ mutex_unlock(&qsee_bw_mutex);
break;
default:
pr_err("Clock type not defined\n");
@@ -1242,29 +1259,44 @@
switch (clk_type) {
case CLK_DFAB:
mutex_lock(&qsee_bw_mutex);
- if (qsee_bw_count > 0) {
- if (qsee_bw_count-- == 1) {
+ if (qsee_bw_count == 0) {
+ pr_err("Client error.Extra call to disable DFAB clk\n");
+ mutex_unlock(&qsee_bw_mutex);
+ return;
+ }
+
+ if ((qsee_bw_count > 0) && (qsee_bw_count-- == 1)) {
+ if (qsee_sfpb_bw_count > 0)
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 2);
+ else
ret = msm_bus_scale_client_update_request(
qsee_perf_client, 0);
- if (ret)
- pr_err("SFPB Bandwidth req fail (%d)\n",
+ if (ret)
+ pr_err("SFPB Bandwidth req fail (%d)\n",
ret);
- }
}
mutex_unlock(&qsee_bw_mutex);
break;
case CLK_SFPB:
- mutex_lock(&qsee_sfpb_bw_mutex);
- if (qsee_sfpb_bw_count > 0) {
- if (qsee_sfpb_bw_count-- == 1) {
+ mutex_lock(&qsee_bw_mutex);
+ if (qsee_sfpb_bw_count == 0) {
+ pr_err("Client error.Extra call to disable SFPB clk\n");
+ mutex_unlock(&qsee_bw_mutex);
+ return;
+ }
+ if ((qsee_sfpb_bw_count > 0) && (qsee_sfpb_bw_count-- == 1)) {
+ if (qsee_bw_count > 0)
+ ret = msm_bus_scale_client_update_request(
+ qsee_perf_client, 1);
+ else
ret = msm_bus_scale_client_update_request(
qsee_perf_client, 0);
- if (ret)
- pr_err("SFPB Bandwidth req fail (%d)\n",
+ if (ret)
+ pr_err("SFPB Bandwidth req fail (%d)\n",
ret);
- }
}
- mutex_unlock(&qsee_sfpb_bw_mutex);
+ mutex_unlock(&qsee_bw_mutex);
break;
default:
pr_err("Clock type not defined\n");
@@ -1701,7 +1733,6 @@
mutex_unlock(&pil_access_lock);
}
kfree(data);
- qsee_disable_clock_vote(CLK_DFAB);
return ret;
}
@@ -1713,9 +1744,131 @@
.release = qseecom_release
};
+static int __qseecom_init_clk()
+{
+ int rc = 0;
+ struct device *pdev;
+
+ pdev = qseecom.pdev;
+ /* Get CE3 src core clk. */
+ ce_core_src_clk = clk_get(pdev, "core_clk_src");
+ if (!IS_ERR(ce_core_src_clk)) {
+ ce_core_src_clk = ce_core_src_clk;
+
+ /* Set the core src clk @100Mhz */
+ rc = clk_set_rate(ce_core_src_clk, 100000000);
+ if (rc) {
+ clk_put(ce_core_src_clk);
+ pr_err("Unable to set the core src clk @100Mhz.\n");
+ goto err_clk;
+ }
+ } else {
+ pr_warn("Unable to get CE core src clk, set to NULL\n");
+ ce_core_src_clk = NULL;
+ }
+
+ /* Get CE core clk */
+ ce_core_clk = clk_get(pdev, "core_clk");
+ if (IS_ERR(ce_core_clk)) {
+ rc = PTR_ERR(ce_core_clk);
+ pr_err("Unable to get CE core clk\n");
+ if (ce_core_src_clk != NULL)
+ clk_put(ce_core_src_clk);
+ goto err_clk;
+ }
+
+ /* Get CE Interface clk */
+ ce_clk = clk_get(pdev, "iface_clk");
+ if (IS_ERR(ce_clk)) {
+ rc = PTR_ERR(ce_clk);
+ pr_err("Unable to get CE interface clk\n");
+ if (ce_core_src_clk != NULL)
+ clk_put(ce_core_src_clk);
+ clk_put(ce_core_clk);
+ goto err_clk;
+ }
+
+ /* Get CE AXI clk */
+ ce_bus_clk = clk_get(pdev, "bus_clk");
+ if (IS_ERR(ce_bus_clk)) {
+ rc = PTR_ERR(ce_bus_clk);
+ pr_err("Unable to get CE BUS interface clk\n");
+ if (ce_core_src_clk != NULL)
+ clk_put(ce_core_src_clk);
+ clk_put(ce_core_clk);
+ clk_put(ce_clk);
+ goto err_clk;
+ }
+
+ /* Enable CE core clk */
+ rc = clk_prepare_enable(ce_core_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE core clk\n");
+ if (ce_core_src_clk != NULL)
+ clk_put(ce_core_src_clk);
+ clk_put(ce_core_clk);
+ clk_put(ce_clk);
+ goto err_clk;
+ } else {
+ /* Enable CE clk */
+ rc = clk_prepare_enable(ce_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE iface clk\n");
+ clk_disable_unprepare(ce_core_clk);
+ if (ce_core_src_clk != NULL)
+ clk_put(ce_core_src_clk);
+ clk_put(ce_core_clk);
+ clk_put(ce_clk);
+ goto err_clk;
+ } else {
+ /* Enable AXI clk */
+ rc = clk_prepare_enable(ce_bus_clk);
+ if (rc) {
+ pr_err("Unable to enable/prepare CE iface clk\n");
+ clk_disable_unprepare(ce_core_clk);
+ clk_disable_unprepare(ce_clk);
+ if (ce_core_src_clk != NULL)
+ clk_put(ce_core_src_clk);
+ clk_put(ce_core_clk);
+ clk_put(ce_clk);
+ goto err_clk;
+ }
+ }
+ }
+ return rc;
+
+err_clk:
+ if (rc)
+ pr_err("Unable to init CE clks, rc = %d\n", rc);
+ clk_disable_unprepare(ce_clk);
+ clk_disable_unprepare(ce_core_clk);
+ clk_disable_unprepare(ce_bus_clk);
+ if (ce_core_src_clk != NULL)
+ clk_put(ce_core_src_clk);
+ clk_put(ce_clk);
+ clk_put(ce_core_clk);
+ clk_put(ce_bus_clk);
+ return rc;
+}
+
+
+
+static void __qseecom_disable_clk()
+{
+ clk_disable_unprepare(ce_clk);
+ clk_disable_unprepare(ce_core_clk);
+ clk_disable_unprepare(ce_bus_clk);
+ if (ce_core_src_clk != NULL)
+ clk_put(ce_core_src_clk);
+ clk_put(ce_clk);
+ clk_put(ce_core_clk);
+ clk_put(ce_bus_clk);
+}
+
static int __devinit qseecom_probe(struct platform_device *pdev)
{
int rc;
+ int ret;
struct device *class_dev;
char qsee_not_legacy = 0;
struct msm_bus_scale_pdata *qseecom_platform_support;
@@ -1774,6 +1927,8 @@
pil = NULL;
pil_ref_cnt = 0;
}
+
+ qseecom.pdev = class_dev;
/* Create ION msm client */
qseecom.ion_clnt = msm_ion_client_create(0x03, "qseecom-kernel");
if (qseecom.ion_clnt == NULL) {
@@ -1783,17 +1938,23 @@
}
/* register client for bus scaling */
- if (!pdev->dev.of_node) {
+ if (pdev->dev.of_node) {
+ ret = __qseecom_init_clk();
+ if (ret)
+ goto err;
+ qseecom_platform_support = (struct msm_bus_scale_pdata *)
+ msm_bus_cl_get_pdata(pdev);
+ } else {
qseecom_platform_support = (struct msm_bus_scale_pdata *)
pdev->dev.platform_data;
- qsee_perf_client = msm_bus_scale_register_client(
- qseecom_platform_support);
-
- if (!qsee_perf_client)
- pr_err("Unable to register bus client\n");
}
- return 0;
+ qsee_perf_client = msm_bus_scale_register_client(
+ qseecom_platform_support);
+
+ if (!qsee_perf_client)
+ pr_err("Unable to register bus client\n");
+ return 0;
err:
device_destroy(driver_class, qseecom_device_no);
class_destroy:
@@ -1834,6 +1995,9 @@
static void __devexit qseecom_exit(void)
{
+
+ __qseecom_disable_clk();
+
device_destroy(driver_class, qseecom_device_no);
class_destroy(driver_class);
unregister_chrdev_region(qseecom_device_no, 1);
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 15254fb..33f0600 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -80,7 +80,6 @@
config MMC_BLOCK_TEST
tristate "MMC block test"
depends on MMC_BLOCK && IOSCHED_TEST
- default m
help
MMC block test can be used with test iosched to test the MMC block
device.
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 8b9d08b..7387d9a 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -59,6 +59,7 @@
#define INAND_CMD38_ARG_SECTRIM2 0x88
#define MMC_SANITIZE_REQ_TIMEOUT 240000 /* msec */
+
#define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \
(req->cmd_flags & REQ_META)) && \
(rq_data_dir(req) == WRITE))
@@ -119,16 +120,17 @@
unsigned int part_curr;
struct device_attribute force_ro;
struct device_attribute power_ro_lock;
- int area_type;
struct device_attribute num_wr_reqs_to_start_packing;
+ struct device_attribute min_sectors_to_check_bkops_status;
+ int area_type;
};
static DEFINE_MUTEX(open_lock);
enum {
- MMC_PACKED_N_IDX = -1,
- MMC_PACKED_N_ZERO,
- MMC_PACKED_N_SINGLE,
+ MMC_PACKED_N_IDX = -1,
+ MMC_PACKED_N_ZERO,
+ MMC_PACKED_N_SINGLE,
};
module_param(perdev_minors, int, 0444);
@@ -136,8 +138,8 @@
static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
{
- mqrq->packed_cmd = MMC_PACKED_NONE;
- mqrq->packed_num = MMC_PACKED_N_ZERO;
+ mqrq->packed_cmd = MMC_PACKED_NONE;
+ mqrq->packed_num = MMC_PACKED_N_ZERO;
}
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
@@ -305,6 +307,48 @@
return count;
}
+static ssize_t
+min_sectors_to_check_bkops_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ unsigned int min_sectors_to_check_bkops_status;
+ struct mmc_card *card = md->queue.card;
+ int ret;
+
+ if (!card)
+ return -EINVAL;
+
+ min_sectors_to_check_bkops_status =
+ card->bkops_info.min_sectors_to_queue_delayed_work;
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
+ min_sectors_to_check_bkops_status);
+
+ mmc_blk_put(md);
+ return ret;
+}
+
+static ssize_t
+min_sectors_to_check_bkops_status_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ struct mmc_card *card = md->queue.card;
+
+ if (!card)
+ return -EINVAL;
+
+ sscanf(buf, "%d", &value);
+ if (value >= 0)
+ card->bkops_info.min_sectors_to_queue_delayed_work = value;
+
+ mmc_blk_put(md);
+ return count;
+}
+
static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -872,6 +916,9 @@
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
+ if (card->ext_csd.bkops_en)
+ card->bkops_info.sectors_changed += blk_rq_sectors(req);
+
if (mmc_can_discard(card))
arg = MMC_DISCARD_ARG;
else if (mmc_can_trim(card))
@@ -1162,6 +1209,7 @@
int err, check, status;
u8 ext_csd[512];
+ mq_rq->packed_retries--;
check = mmc_blk_err_check(card, areq);
err = get_card_status(card, &status, 0);
if (err) {
@@ -1170,7 +1218,7 @@
return MMC_BLK_ABORT;
}
- if (status & R1_EXP_EVENT) {
+ if (status & R1_EXCEPTION_EVENT) {
err = mmc_send_ext_csd(card, ext_csd);
if (err) {
pr_err("%s: error %d sending ext_csd\n",
@@ -1511,9 +1559,12 @@
if (mmc_req_rel_wr(cur) &&
(md->flags & MMC_BLK_REL_WR) &&
- !en_rel_wr) {
+ !en_rel_wr)
goto no_packed;
- }
+
+ if (mmc_large_sec(card) &&
+ !IS_ALIGNED(blk_rq_sectors(cur), 8))
+ goto no_packed;
max_blk_count = min(card->host->max_blk_count,
card->host->max_req_size >> 9);
@@ -1540,6 +1591,13 @@
break;
}
+ if (mmc_large_sec(card) &&
+ !IS_ALIGNED(blk_rq_sectors(next), 8)) {
+ MMC_BLK_UPDATE_STOP_REASON(stats, LARGE_SEC_ALIGN);
+ put_back = 1;
+ break;
+ }
+
if (next->cmd_flags & REQ_DISCARD ||
next->cmd_flags & REQ_FLUSH) {
MMC_BLK_UPDATE_STOP_REASON(stats, FLUSH_OR_DISCARD);
@@ -1576,8 +1634,12 @@
break;
}
- if (rq_data_dir(next) == WRITE)
+ if (rq_data_dir(next) == WRITE) {
mq->num_of_potential_packed_wr_reqs++;
+ if (card->ext_csd.bkops_en)
+ card->bkops_info.sectors_changed +=
+ blk_rq_sectors(next);
+ }
list_add_tail(&next->queuelist, &mq->mqrq_cur->packed_list);
cur = next;
reqs++;
@@ -1601,6 +1663,7 @@
if (reqs > 0) {
list_add(&req->queuelist, &mq->mqrq_cur->packed_list);
mq->mqrq_cur->packed_num = ++reqs;
+ mq->mqrq_cur->packed_retries = reqs;
return reqs;
}
@@ -1617,7 +1680,7 @@
struct request *req = mqrq->req;
struct request *prq;
struct mmc_blk_data *md = mq->data;
- bool do_rel_wr;
+ bool do_rel_wr, do_data_tag;
u32 *packed_cmd_hdr = mqrq->packed_cmd_hdr;
u8 i = 1;
@@ -1634,9 +1697,15 @@
*/
list_for_each_entry(prq, &mqrq->packed_list, queuelist) {
do_rel_wr = mmc_req_rel_wr(prq) && (md->flags & MMC_BLK_REL_WR);
- /* Argument of CMD23*/
+ do_data_tag = (card->ext_csd.data_tag_unit_size) &&
+ (prq->cmd_flags & REQ_META) &&
+ (rq_data_dir(prq) == WRITE) &&
+ ((brq->data.blocks * brq->data.blksz) >=
+ card->ext_csd.data_tag_unit_size);
+ /* Argument of CMD23 */
packed_cmd_hdr[(i * 2)] =
(do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
+ (do_data_tag ? MMC_CMD23_ARG_TAG_REQ : 0) |
blk_rq_sectors(prq);
/* Argument of CMD18 or CMD25 */
packed_cmd_hdr[((i * 2)) + 1] =
@@ -1665,7 +1734,6 @@
brq->data.blksz = 512;
brq->data.blocks = mqrq->packed_blocks + 1;
brq->data.flags |= MMC_DATA_WRITE;
- brq->data.fault_injected = false;
brq->stop.opcode = MMC_STOP_TRANSMISSION;
brq->stop.arg = 0;
@@ -1717,15 +1785,13 @@
} else
ret = blk_end_request(req, 0, brq->data.bytes_xfered);
} else {
- if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
+ if (mq_rq->packed_cmd == MMC_PACKED_NONE)
ret = blk_end_request(req, 0, brq->data.bytes_xfered);
- }
}
return ret;
}
-static int mmc_blk_end_packed_req(struct mmc_queue *mq,
- struct mmc_queue_req *mq_rq)
+static int mmc_blk_end_packed_req(struct mmc_queue_req *mq_rq)
{
struct request *prq;
int idx = mq_rq->packed_fail_idx, i = 0;
@@ -1753,6 +1819,39 @@
mmc_blk_clear_packed(mq_rq);
return ret;
}
+static void mmc_blk_abort_packed_req(struct mmc_queue_req *mq_rq)
+{
+ struct request *prq;
+
+ while (!list_empty(&mq_rq->packed_list)) {
+ prq = list_entry_rq(mq_rq->packed_list.next);
+ list_del_init(&prq->queuelist);
+ blk_end_request(prq, -EIO, blk_rq_bytes(prq));
+ }
+
+ mmc_blk_clear_packed(mq_rq);
+}
+
+static void mmc_blk_revert_packed_req(struct mmc_queue *mq,
+ struct mmc_queue_req *mq_rq)
+{
+ struct request *prq;
+ struct request_queue *q = mq->queue;
+
+ while (!list_empty(&mq_rq->packed_list)) {
+ prq = list_entry_rq(mq_rq->packed_list.prev);
+ if (prq->queuelist.prev != &mq_rq->packed_list) {
+ list_del_init(&prq->queuelist);
+ spin_lock_irq(q->queue_lock);
+ blk_requeue_request(mq->queue, prq);
+ spin_unlock_irq(q->queue_lock);
+ } else {
+ list_del_init(&prq->queuelist);
+ }
+ }
+
+ mmc_blk_clear_packed(mq_rq);
+}
static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
{
@@ -1762,7 +1861,7 @@
int ret = 1, disable_multi = 0, retry = 0, type;
enum mmc_blk_status status;
struct mmc_queue_req *mq_rq;
- struct request *req, *prq;
+ struct request *req;
struct mmc_async_req *areq;
const u8 packed_num = 2;
u8 reqs = 0;
@@ -1770,8 +1869,11 @@
if (!rqc && !mq->mqrq_prev->req)
return 0;
- if (rqc)
+ if (rqc) {
+ if ((card->ext_csd.bkops_en) && (rq_data_dir(rqc) == WRITE))
+ card->bkops_info.sectors_changed += blk_rq_sectors(rqc);
reqs = mmc_blk_prep_packed_list(mq, rqc);
+ }
do {
if (rqc) {
@@ -1802,7 +1904,7 @@
mmc_blk_reset_success(md, type);
if (mq_rq->packed_cmd != MMC_PACKED_NONE) {
- ret = mmc_blk_end_packed_req(mq, mq_rq);
+ ret = mmc_blk_end_packed_req(mq_rq);
break;
} else {
ret = blk_end_request(req, 0,
@@ -1879,6 +1981,8 @@
mmc_start_req(card->host,
&mq_rq->mmc_active, NULL);
} else {
+ if (!mq_rq->packed_retries)
+ goto cmd_abort;
mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq);
mmc_start_req(card->host,
&mq_rq->mmc_active, NULL);
@@ -1896,12 +2000,7 @@
ret = blk_end_request(req, -EIO,
blk_rq_cur_bytes(req));
} else {
- while (!list_empty(&mq_rq->packed_list)) {
- prq = list_entry_rq(mq_rq->packed_list.next);
- list_del_init(&prq->queuelist);
- blk_end_request(prq, -EIO, blk_rq_bytes(prq));
- }
- mmc_blk_clear_packed(mq_rq);
+ mmc_blk_abort_packed_req(mq_rq);
}
start_new_req:
@@ -1909,22 +2008,9 @@
/*
* If current request is packed, it needs to put back.
*/
- if (mq->mqrq_cur->packed_cmd != MMC_PACKED_NONE) {
- while (!list_empty(&mq->mqrq_cur->packed_list)) {
- prq = list_entry_rq(
- mq->mqrq_cur->packed_list.prev);
- if (prq->queuelist.prev !=
- &mq->mqrq_cur->packed_list) {
- list_del_init(&prq->queuelist);
- spin_lock_irq(mq->queue->queue_lock);
- blk_requeue_request(mq->queue, prq);
- spin_unlock_irq(mq->queue->queue_lock);
- } else {
- list_del_init(&prq->queuelist);
- }
- }
- mmc_blk_clear_packed(mq->mqrq_cur);
- }
+ if (mq->mqrq_cur->packed_cmd != MMC_PACKED_NONE)
+ mmc_blk_revert_packed_req(mq, mq->mqrq_cur);
+
mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
}
@@ -2273,6 +2359,19 @@
if (ret)
goto power_ro_lock_fail;
+ md->min_sectors_to_check_bkops_status.show =
+ min_sectors_to_check_bkops_status_show;
+ md->min_sectors_to_check_bkops_status.store =
+ min_sectors_to_check_bkops_status_store;
+ sysfs_attr_init(&md->min_sectors_to_check_bkops_status.attr);
+ md->min_sectors_to_check_bkops_status.attr.name =
+ "min_sectors_to_check_bkops_status";
+ md->min_sectors_to_check_bkops_status.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(disk_to_dev(md->disk),
+ &md->min_sectors_to_check_bkops_status);
+ if (ret)
+ goto power_ro_lock_fail;
+
return ret;
power_ro_lock_fail:
diff --git a/drivers/mmc/card/mmc_block_test.c b/drivers/mmc/card/mmc_block_test.c
index 871675c..bdda8d5 100644
--- a/drivers/mmc/card/mmc_block_test.c
+++ b/drivers/mmc/card/mmc_block_test.c
@@ -1,5 +1,4 @@
-
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -33,16 +32,11 @@
#define PACKED_HDR_RW_MASK 0x0000FF00
#define PACKED_HDR_NUM_REQS_MASK 0x00FF0000
#define PACKED_HDR_BITS_16_TO_29_SET 0x3FFF0000
-#define SECTOR_SIZE 512
-#define NUM_OF_SECTORS_PER_BIO ((BIO_U32_SIZE * 4) / SECTOR_SIZE)
-#define BIO_TO_SECTOR(x) (x * NUM_OF_SECTORS_PER_BIO)
#define test_pr_debug(fmt, args...) pr_debug("%s: "fmt"\n", MODULE_NAME, args)
#define test_pr_info(fmt, args...) pr_info("%s: "fmt"\n", MODULE_NAME, args)
#define test_pr_err(fmt, args...) pr_err("%s: "fmt"\n", MODULE_NAME, args)
-#define SANITIZE_TEST_TIMEOUT 240000
-
enum is_random {
NON_RANDOM_TEST,
RANDOM_TEST,
@@ -107,8 +101,6 @@
TEST_PACK_MIX_PACKED_NO_PACKED_PACKED,
TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
PACKING_CONTROL_MAX_TESTCASE = TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED,
-
- TEST_WRITE_DISCARD_SANITIZE_READ,
};
enum mmc_block_test_group {
@@ -126,7 +118,6 @@
struct dentry *send_invalid_packed_test;
struct dentry *random_test_seed;
struct dentry *packing_control_test;
- struct dentry *discard_sanitize_test;
};
struct mmc_block_test_data {
@@ -505,8 +496,6 @@
return "\nTest packing control - mix: pack -> no pack -> pack";
case TEST_PACK_MIX_NO_PACKED_PACKED_NO_PACKED:
return "\nTest packing control - mix: no pack->pack->no pack";
- case TEST_WRITE_DISCARD_SANITIZE_READ:
- return "\nTest write, discard, sanitize";
default:
return "Unknown testcase";
}
@@ -1393,63 +1382,6 @@
return 0;
}
-static void pseudo_rnd_sector_and_size(unsigned int *seed,
- unsigned int min_start_sector,
- unsigned int *start_sector,
- unsigned int *num_of_bios)
-{
- unsigned int max_sec = min_start_sector + TEST_MAX_SECTOR_RANGE;
- do {
- *start_sector = pseudo_random_seed(seed,
- 1, max_sec);
- *num_of_bios = pseudo_random_seed(seed,
- 1, TEST_MAX_BIOS_PER_REQ);
- if (!(*num_of_bios))
- *num_of_bios = 1;
- } while ((*start_sector < min_start_sector) ||
- (*start_sector + (*num_of_bios * BIO_U32_SIZE * 4)) > max_sec);
-}
-
-/* sanitize test functions */
-static int prepare_write_discard_sanitize_read(struct test_data *td)
-{
- unsigned int start_sector;
- unsigned int num_of_bios = 0;
- static unsigned int total_bios;
- unsigned int *num_bios_seed;
- int i = 0;
-
- if (mbtd->random_test_seed == 0) {
- mbtd->random_test_seed =
- (unsigned int)(get_jiffies_64() & 0xFFFF);
- test_pr_info("%s: got seed from jiffies %d",
- __func__, mbtd->random_test_seed);
- }
- num_bios_seed = &mbtd->random_test_seed;
-
- do {
- pseudo_rnd_sector_and_size(num_bios_seed, td->start_sector,
- &start_sector, &num_of_bios);
-
- /* DISCARD */
- total_bios += num_of_bios;
- test_pr_info("%s: discard req: id=%d, startSec=%d, NumBios=%d",
- __func__, td->unique_next_req_id, start_sector,
- num_of_bios);
- test_iosched_add_unique_test_req(0, REQ_UNIQUE_DISCARD,
- start_sector, BIO_TO_SECTOR(num_of_bios),
- NULL);
-
- } while (++i < (BLKDEV_MAX_RQ-10));
-
- test_pr_info("%s: total discard bios = %d", __func__, total_bios);
-
- test_pr_info("%s: add sanitize req", __func__);
- test_iosched_add_unique_test_req(0, REQ_UNIQUE_SANITIZE, 0, 0, NULL);
-
- return 0;
-}
-
static bool message_repeat;
static int test_open(struct inode *inode, struct file *file)
{
@@ -1877,49 +1809,6 @@
.read = write_packing_control_test_read,
};
-static ssize_t write_discard_sanitize_test_write(struct file *file,
- const char __user *buf,
- size_t count,
- loff_t *ppos)
-{
- int ret = 0;
- int i = 0;
- int number = -1;
-
- sscanf(buf, "%d", &number);
- if (number <= 0)
- number = 1;
-
- test_pr_info("%s: -- write_discard_sanitize TEST --\n", __func__);
-
- memset(&mbtd->test_info, 0, sizeof(struct test_info));
-
- mbtd->test_group = TEST_GENERAL_GROUP;
-
- mbtd->test_info.data = mbtd;
- mbtd->test_info.prepare_test_fn = prepare_write_discard_sanitize_read;
- mbtd->test_info.get_test_case_str_fn = get_test_case_str;
- mbtd->test_info.timeout_msec = SANITIZE_TEST_TIMEOUT;
-
- for (i = 0 ; i < number ; ++i) {
- test_pr_info("%s: Cycle # %d / %d\n", __func__, i+1, number);
- test_pr_info("%s: ===================", __func__);
-
- mbtd->test_info.testcase = TEST_WRITE_DISCARD_SANITIZE_READ;
- ret = test_iosched_start_test(&mbtd->test_info);
-
- if (ret)
- break;
- }
-
- return count;
-}
-
-const struct file_operations write_discard_sanitize_test_ops = {
- .open = test_open,
- .write = write_discard_sanitize_test_write,
-};
-
static void mmc_block_test_debugfs_cleanup(void)
{
debugfs_remove(mbtd->debug.random_test_seed);
@@ -1927,7 +1816,6 @@
debugfs_remove(mbtd->debug.err_check_test);
debugfs_remove(mbtd->debug.send_invalid_packed_test);
debugfs_remove(mbtd->debug.packing_control_test);
- debugfs_remove(mbtd->debug.discard_sanitize_test);
}
static int mmc_block_test_debugfs_init(void)
@@ -1989,17 +1877,6 @@
if (!mbtd->debug.packing_control_test)
goto err_nomem;
- mbtd->debug.discard_sanitize_test =
- debugfs_create_file("write_discard_sanitize_test",
- S_IRUGO | S_IWUGO,
- tests_root,
- NULL,
- &write_discard_sanitize_test_ops);
- if (!mbtd->debug.discard_sanitize_test) {
- mmc_block_test_debugfs_cleanup();
- return -ENOMEM;
- }
-
return 0;
err_nomem:
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index e1e4408..cc91646 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -59,6 +59,7 @@
struct mmc_queue *mq = d;
struct request_queue *q = mq->queue;
struct request *req;
+ struct mmc_card *card = mq->card;
current->flags |= PF_MEMALLOC;
@@ -74,6 +75,17 @@
spin_unlock_irq(q->queue_lock);
if (req || mq->mqrq_prev->req) {
+ /*
+ * If this is the first request, BKOPs might be in
+ * progress and needs to be stopped before issuing the
+ * request
+ */
+ if (card->ext_csd.bkops_en &&
+ card->bkops_info.started_delayed_bkops) {
+ card->bkops_info.started_delayed_bkops = false;
+ mmc_stop_bkops(card);
+ }
+
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
} else {
@@ -81,6 +93,7 @@
set_current_state(TASK_RUNNING);
break;
}
+ mmc_start_delayed_bkops(card);
up(&mq->thread_sem);
schedule();
down(&mq->thread_sem);
@@ -188,10 +201,11 @@
if (!mq->queue)
return -ENOMEM;
- memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
- memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
INIT_LIST_HEAD(&mqrq_cur->packed_list);
INIT_LIST_HEAD(&mqrq_prev->packed_list);
+
+ memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
+ memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
mq->mqrq_cur = mqrq_cur;
mq->mqrq_prev = mqrq_prev;
mq->queue->queuedata = mq;
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index ec3d6d2..a8c104e 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -40,6 +40,7 @@
u32 packed_cmd_hdr[128];
unsigned int packed_blocks;
enum mmc_packed_cmd packed_cmd;
+ int packed_retries;
int packed_fail_idx;
u8 packed_num;
};
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 478cfac..7e03e5a 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -28,6 +28,7 @@
#include <linux/random.h>
#include <linux/wakelock.h>
#include <linux/pm.h>
+#include <linux/slab.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -43,6 +44,12 @@
#include "sd_ops.h"
#include "sdio_ops.h"
+/*
+ * Background operations can take a long time, depending on the housekeeping
+ * operations the card has to perform.
+ */
+#define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */
+
static struct workqueue_struct *workqueue;
/*
@@ -272,6 +279,220 @@
host->ops->request(host, mrq);
}
+/**
+ * mmc_start_delayed_bkops() - Start a delayed work to check for
+ * the need of non urgent BKOPS
+ *
+ * @card: MMC card to start BKOPS on
+ */
+void mmc_start_delayed_bkops(struct mmc_card *card)
+{
+ if (!card || !card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
+ return;
+
+ if (card->bkops_info.sectors_changed <
+ card->bkops_info.min_sectors_to_queue_delayed_work)
+ return;
+
+ pr_debug("%s: %s: queueing delayed_bkops_work\n",
+ mmc_hostname(card->host), __func__);
+
+ card->bkops_info.sectors_changed = 0;
+
+ /*
+ * cancel_delayed_bkops_work will prevent a race condition between
+ * fetching a request by the mmcqd and the delayed work, in case
+ * it was removed from the queue work but not started yet
+ */
+ card->bkops_info.cancel_delayed_work = false;
+ card->bkops_info.started_delayed_bkops = true;
+ queue_delayed_work(system_nrt_wq, &card->bkops_info.dw,
+ msecs_to_jiffies(
+ card->bkops_info.delay_ms));
+}
+EXPORT_SYMBOL(mmc_start_delayed_bkops);
+
+/**
+ * mmc_start_bkops - start BKOPS for supported cards
+ * @card: MMC card to start BKOPS
+ * @from_exception: A flag to indicate if this function was
+ * called due to an exception raised by the card
+ *
+ * Start background operations whenever requested.
+ * When the urgent BKOPS bit is set in a R1 command response
+ * then background operations should be started immediately.
+*/
+void mmc_start_bkops(struct mmc_card *card, bool from_exception)
+{
+ int err;
+ int timeout;
+ bool use_busy_signal;
+
+ BUG_ON(!card);
+ if (!card->ext_csd.bkops_en)
+ return;
+
+ mmc_claim_host(card->host);
+
+ if ((card->bkops_info.cancel_delayed_work) && !from_exception) {
+ pr_debug("%s: %s: cancel_delayed_work was set, exit\n",
+ mmc_hostname(card->host), __func__);
+ card->bkops_info.cancel_delayed_work = false;
+ goto out;
+ }
+
+ if (mmc_card_doing_bkops(card)) {
+ pr_debug("%s: %s: already doing bkops, exit\n",
+ mmc_hostname(card->host), __func__);
+ goto out;
+ }
+
+ err = mmc_read_bkops_status(card);
+ if (err) {
+ pr_err("%s: Failed to read bkops status: %d\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ if (!card->ext_csd.raw_bkops_status)
+ goto out;
+
+ pr_info("%s: %s: card->ext_csd.raw_bkops_status = 0x%x\n",
+ mmc_hostname(card->host), __func__,
+ card->ext_csd.raw_bkops_status);
+
+ /*
+ * If the function was called due to exception but there is no need
+ * for urgent BKOPS, BKOPs will be performed by the delayed BKOPs
+ * work, before going to suspend
+ */
+ if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 &&
+ from_exception)
+ goto out;
+
+ if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
+ timeout = MMC_BKOPS_MAX_TIMEOUT;
+ use_busy_signal = true;
+ } else {
+ timeout = 0;
+ use_busy_signal = false;
+ }
+
+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal);
+ if (err) {
+ pr_warn("%s: Error %d starting bkops\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /*
+ * For urgent bkops status (LEVEL_2 and more)
+ * bkops executed synchronously, otherwise
+ * the operation is in progress
+ */
+ if (!use_busy_signal) {
+ mmc_card_set_doing_bkops(card);
+ pr_debug("%s: %s: starting the polling thread\n",
+ mmc_hostname(card->host), __func__);
+ queue_work(system_nrt_wq,
+ &card->bkops_info.poll_for_completion);
+ }
+
+out:
+ mmc_release_host(card->host);
+}
+EXPORT_SYMBOL(mmc_start_bkops);
+
+/**
+ * mmc_bkops_completion_polling() - Poll on the card status to
+ * wait for the non-blocking BKOPS completion
+ * @work: The completion polling work
+ *
+ * The on-going reading of the card status will prevent the card
+ * from getting into suspend while it is in the middle of
+ * performing BKOPS.
+ * Since the non blocking BKOPS can be interrupted by a fetched
+ * request we also check IF mmc_card_doing_bkops in each
+ * iteration.
+ */
+void mmc_bkops_completion_polling(struct work_struct *work)
+{
+ struct mmc_card *card = container_of(work, struct mmc_card,
+ bkops_info.poll_for_completion);
+ unsigned long timeout_jiffies = jiffies +
+ msecs_to_jiffies(BKOPS_COMPLETION_POLLING_TIMEOUT_MS);
+ u32 status;
+ int err;
+
+ /*
+ * Wait for the BKOPs to complete. Keep reading the status to prevent
+ * the host from getting into suspend
+ */
+ do {
+ mmc_claim_host(card->host);
+
+ if (!mmc_card_doing_bkops(card))
+ goto out;
+
+ err = mmc_send_status(card, &status);
+ if (err) {
+ pr_err("%s: error %d requesting status\n",
+ mmc_hostname(card->host), err);
+ goto out;
+ }
+
+ /*
+ * Some cards mishandle the status bits, so make sure to check
+ * both the busy indication and the card state.
+ */
+ if ((status & R1_READY_FOR_DATA) &&
+ (R1_CURRENT_STATE(status) != R1_STATE_PRG)) {
+ pr_debug("%s: %s: completed BKOPs, exit polling\n",
+ mmc_hostname(card->host), __func__);
+ mmc_card_clr_doing_bkops(card);
+ card->bkops_info.started_delayed_bkops = false;
+ goto out;
+ }
+
+ mmc_release_host(card->host);
+
+ /*
+ * Sleep before checking the card status again to allow the
+ * card to complete the BKOPs operation
+ */
+ msleep(BKOPS_COMPLETION_POLLING_INTERVAL_MS);
+ } while (time_before(jiffies, timeout_jiffies));
+
+ pr_err("%s: %s: exit polling due to timeout\n",
+ mmc_hostname(card->host), __func__);
+
+ return;
+out:
+ mmc_release_host(card->host);
+}
+
+/**
+ * mmc_start_idle_time_bkops() - check if a non urgent BKOPS is
+ * needed
+ * @work: The idle time BKOPS work
+ */
+void mmc_start_idle_time_bkops(struct work_struct *work)
+{
+ struct mmc_card *card = container_of(work, struct mmc_card,
+ bkops_info.dw.work);
+
+ /*
+ * Prevent a race condition between mmc_stop_bkops and the delayed
+ * BKOPS work in case the delayed work is executed on another CPU
+ */
+ if (card->bkops_info.cancel_delayed_work)
+ return;
+
+ mmc_start_bkops(card, false);
+}
+EXPORT_SYMBOL(mmc_start_idle_time_bkops);
+
static void mmc_wait_done(struct mmc_request *mrq)
{
complete(&mrq->completion);
@@ -381,6 +602,14 @@
if (host->areq) {
mmc_wait_for_req_done(host, host->areq->mrq);
err = host->areq->err_check(host->card, host->areq);
+ /*
+ * Check BKOPS urgency for each R1 response
+ */
+ if (host->card && mmc_card_mmc(host->card) &&
+ ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
+ (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
+ (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT))
+ mmc_start_bkops(host->card, true);
}
if (!err && areq)
@@ -425,7 +654,7 @@
* @card: the MMC card associated with the HPI transfer
*
* Issued High Priority Interrupt, and check for card status
- * util out-of prg-state.
+ * until out-of prg-state.
*/
int mmc_interrupt_hpi(struct mmc_card *card)
{
@@ -507,6 +736,79 @@
EXPORT_SYMBOL(mmc_wait_for_cmd);
/**
+ * mmc_stop_bkops - stop ongoing BKOPS
+ * @card: MMC card to check BKOPS
+ *
+ * Send HPI command to stop ongoing background operations to
+ * allow rapid servicing of foreground operations, e.g. read/
+ * writes. Wait until the card comes out of the programming state
+ * to avoid errors in servicing read/write requests.
+ */
+int mmc_stop_bkops(struct mmc_card *card)
+{
+ int err = 0;
+
+ BUG_ON(!card);
+
+ mmc_claim_host(card->host);
+
+ /*
+ * Notify the delayed work to be cancelled, in case it was already
+ * removed from the queue, but was not started yet
+ */
+ card->bkops_info.cancel_delayed_work = true;
+ if (delayed_work_pending(&card->bkops_info.dw))
+ cancel_delayed_work_sync(&card->bkops_info.dw);
+ if (!mmc_card_doing_bkops(card))
+ goto out;
+
+ err = mmc_interrupt_hpi(card);
+
+ /*
+ * If err is EINVAL, we can't issue an HPI.
+ * It should complete the BKOPS.
+ */
+ if (!err || (err == -EINVAL)) {
+ mmc_card_clr_doing_bkops(card);
+ err = 0;
+ }
+
+out:
+ mmc_release_host(card->host);
+ return err;
+}
+EXPORT_SYMBOL(mmc_stop_bkops);
+
+int mmc_read_bkops_status(struct mmc_card *card)
+{
+ int err;
+ u8 *ext_csd;
+
+ /*
+ * In future work, we should consider storing the entire ext_csd.
+ */
+ ext_csd = kmalloc(512, GFP_KERNEL);
+ if (!ext_csd) {
+ pr_err("%s: could not allocate buffer to receive the ext_csd.\n",
+ mmc_hostname(card->host));
+ return -ENOMEM;
+ }
+
+ mmc_claim_host(card->host);
+ err = mmc_send_ext_csd(card, ext_csd);
+ mmc_release_host(card->host);
+ if (err)
+ goto out;
+
+ card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS];
+ card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
+out:
+ kfree(ext_csd);
+ return err;
+}
+EXPORT_SYMBOL(mmc_read_bkops_status);
+
+/**
* mmc_set_data_timeout - set the timeout for a data command
* @data: data phase for command
* @card: the MMC card associated with the data transfer
@@ -2370,8 +2672,14 @@
err = -EBUSY;
if (!err) {
- if (host->bus_ops->suspend)
+ if (host->bus_ops->suspend) {
+ if (mmc_card_doing_bkops(host->card)) {
+ err = mmc_stop_bkops(host->card);
+ if (err)
+ goto stop_bkops_err;
+ }
err = host->bus_ops->suspend(host);
+ }
if (!(host->card && mmc_card_sdio(host->card)))
mmc_release_host(host);
@@ -2401,6 +2709,10 @@
out:
return err;
+stop_bkops_err:
+ if (!(host->card && mmc_card_sdio(host->card)))
+ mmc_release_host(host);
+ return err;
}
EXPORT_SYMBOL(mmc_suspend_host);
@@ -2463,11 +2775,19 @@
struct mmc_host *host = container_of(
notify_block, struct mmc_host, pm_notify);
unsigned long flags;
-
+ int err = 0;
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
+ if (host->card && mmc_card_mmc(host->card)) {
+ err = mmc_stop_bkops(host->card);
+ if (err) {
+ pr_err("%s: didn't stop bkops\n",
+ mmc_hostname(host));
+ return err;
+ }
+ }
spin_lock_irqsave(&host->lock, flags);
if (mmc_bus_needs_resume(host)) {
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 898e358..4022ccc 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -433,6 +433,14 @@
strlcat(ubuf, temp_buf, cnt);
}
+ if (pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]) {
+ snprintf(temp_buf, TEMP_BUF_SIZE,
+ "%s: %d times: Large sector alignment\n",
+ mmc_hostname(card->host),
+ pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]);
+ strlcat(ubuf, temp_buf, cnt);
+ }
+
spin_unlock(&pack_stats->lock);
kfree(temp_buf);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f87b8cc..ca8b01c 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -463,6 +463,27 @@
}
if (card->ext_csd.rev >= 5) {
+ /* check whether the eMMC card supports BKOPS */
+ if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
+ card->ext_csd.bkops = 1;
+ card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
+ card->ext_csd.raw_bkops_status =
+ ext_csd[EXT_CSD_BKOPS_STATUS];
+ if (!card->ext_csd.bkops_en &&
+ card->host->caps2 & MMC_CAP2_INIT_BKOPS) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BKOPS_EN, 1, 0);
+ if (err)
+ pr_warn("%s: Enabling BKOPS failed\n",
+ mmc_hostname(card->host));
+ else
+ card->ext_csd.bkops_en = 1;
+ }
+ if (!card->ext_csd.bkops_en)
+ pr_info("%s: BKOPS_EN bit is not set\n",
+ mmc_hostname(card->host));
+ }
+
/* check whether the eMMC card supports HPI */
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
card->ext_csd.hpi = 1;
@@ -516,6 +537,7 @@
} else {
card->ext_csd.data_tag_unit_size = 0;
}
+
card->ext_csd.max_packed_writes =
ext_csd[EXT_CSD_MAX_PACKED_WRITES];
card->ext_csd.max_packed_reads =
@@ -1257,9 +1279,10 @@
}
}
- if ((host->caps2 & MMC_CAP2_PACKED_CMD) &&
- (card->ext_csd.max_packed_writes > 0) &&
- (card->ext_csd.max_packed_reads > 0)) {
+ if ((host->caps2 & MMC_CAP2_PACKED_WR &&
+ card->ext_csd.max_packed_writes > 0) ||
+ (host->caps2 & MMC_CAP2_PACKED_RD &&
+ card->ext_csd.max_packed_reads > 0)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_EXP_EVENTS_CTRL,
EXT_CSD_PACKED_EVENT_EN,
@@ -1292,6 +1315,30 @@
if (!card->wr_pack_stats.packing_events)
goto free_card;
}
+
+ if (card->ext_csd.bkops_en) {
+ INIT_DELAYED_WORK(&card->bkops_info.dw,
+ mmc_start_idle_time_bkops);
+ INIT_WORK(&card->bkops_info.poll_for_completion,
+ mmc_bkops_completion_polling);
+
+ /*
+ * Calculate the time to start the BKOPs checking.
+ * The idle time of the host controller should be taken
+ * into account in order to prevent a race condition
+ * before starting BKOPs and going into suspend.
+ * If the host controller didn't set its idle time,
+ * a default value is used.
+ */
+ card->bkops_info.delay_ms = MMC_IDLE_BKOPS_TIME_MS;
+ if (card->bkops_info.host_suspend_tout_ms)
+ card->bkops_info.delay_ms = min(
+ card->bkops_info.delay_ms,
+ card->bkops_info.host_suspend_tout_ms/2);
+
+ card->bkops_info.min_sectors_to_queue_delayed_work =
+ BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK;
+ }
}
if (!oldcard)
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index e18d922..4f46ed1 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -368,18 +368,19 @@
}
/**
- * mmc_switch - modify EXT_CSD register
+ * __mmc_switch - modify EXT_CSD register
* @card: the MMC card associated with the data transfer
* @set: cmd set values
* @index: EXT_CSD register index
* @value: value to program into EXT_CSD register
* @timeout_ms: timeout (ms) for operation performed by register write,
* timeout of zero implies maximum possible timeout
+ * @use_busy_signal: use the busy signal as response type
*
* Modifies the EXT_CSD register for selected card.
*/
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
- unsigned int timeout_ms)
+int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+ unsigned int timeout_ms, bool use_busy_signal)
{
int err;
struct mmc_command cmd = {0};
@@ -393,13 +394,23 @@
(index << 16) |
(value << 8) |
set;
- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.flags = MMC_CMD_AC;
+ if (use_busy_signal)
+ cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
+ else
+ cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
+
+
cmd.cmd_timeout_ms = timeout_ms;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
return err;
+ /* No need to check card status in case of unblocking command */
+ if (!use_busy_signal)
+ return 0;
+
/* Must check status to be sure of no errors */
do {
err = mmc_send_status(card, &status);
@@ -424,6 +435,13 @@
return 0;
}
+EXPORT_SYMBOL_GPL(__mmc_switch);
+
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+ unsigned int timeout_ms)
+{
+ return __mmc_switch(card, set, index, value, timeout_ms, true);
+}
EXPORT_SYMBOL_GPL(mmc_switch);
int mmc_send_status(struct mmc_card *card, u32 *status)
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index c4b41e1..061418f 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -3,7 +3,8 @@
*
* Copyright (C) 2007 Google Inc,
* Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ *
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -79,7 +80,6 @@
#if defined(CONFIG_DEBUG_FS)
static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
static struct dentry *debugfs_dir;
-static struct dentry *debugfs_file;
static int msmsdcc_dbg_init(void);
#endif
@@ -874,6 +874,10 @@
bool ret = true;
u32 xfer_size = data->blksz * data->blocks;
+ if (host->enforce_pio_mode) {
+ ret = false;
+ goto out;
+ }
if (is_sps_mode(host)) {
/*
* BAM Mode: Fall back on PIO if size is less
@@ -892,7 +896,7 @@
/* PIO Mode */
ret = false;
}
-
+ out:
return ret;
}
@@ -1776,6 +1780,7 @@
msmsdcc_irq(int irq, void *dev_id)
{
struct msmsdcc_host *host = dev_id;
+ struct mmc_host *mmc = host->mmc;
u32 status;
int ret = 0;
int timer = 0;
@@ -1817,6 +1822,12 @@
*/
wake_lock(&host->sdio_wlock);
} else {
+ if (!mmc->card || !mmc_card_sdio(mmc->card)) {
+ WARN(1, "%s: SDCC core interrupt received for non-SDIO cards when SDCC clocks are off\n",
+ mmc_hostname(mmc));
+ ret = 1;
+ break;
+ }
spin_unlock(&host->lock);
mmc_signal_sdio_irq(host->mmc);
spin_lock(&host->lock);
@@ -1845,6 +1856,12 @@
#endif
if (status & MCI_SDIOINTROPE) {
+ if (!mmc->card || mmc_card_sdio(mmc->card)) {
+ WARN(1, "%s: SDIO interrupt received for non-SDIO card\n",
+ mmc_hostname(mmc));
+ ret = 1;
+ break;
+ }
if (host->sdcc_suspending)
wake_lock(&host->sdio_suspend_wlock);
spin_unlock(&host->lock);
@@ -2394,7 +2411,8 @@
curr_slot = host->plat->vreg_data;
if (!curr_slot) {
- rc = -EINVAL;
+ pr_debug("%s: vreg info unavailable, assuming the slot is powered by always on domain\n",
+ mmc_hostname(host->mmc));
goto out;
}
@@ -2822,6 +2840,14 @@
msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
msmsdcc_update_io_pad_pwr_switch(host);
msmsdcc_setup_pins(host, false);
+ /*
+ * Reset the mask to prevent hitting any pending interrupts
+ * after powering up the card again.
+ */
+ if (atomic_read(&host->clks_on)) {
+ writel_relaxed(0, host->base + MMCIMASK0);
+ mb();
+ }
break;
case MMC_POWER_UP:
/* writing PWR_UP bit is redundant */
@@ -3463,7 +3489,6 @@
{
struct device *dev = mmc->parent;
struct msmsdcc_host *host = mmc_priv(mmc);
- unsigned long flags;
int rc = 0;
msmsdcc_pm_qos_update_latency(host, 1);
@@ -3497,7 +3522,6 @@
static int msmsdcc_disable(struct mmc_host *mmc)
{
struct msmsdcc_host *host = mmc_priv(mmc);
- unsigned long flags;
int rc = 0;
msmsdcc_pm_qos_update_latency(host, 0);
@@ -4122,25 +4146,35 @@
.hw_reset = msmsdcc_hw_reset,
};
+static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
+{
+ unsigned int gpio_no = host->plat->status_gpio;
+ int status;
+
+ if (!gpio_is_valid(gpio_no))
+ return;
+
+ status = gpio_request(gpio_no, "SD_HW_Detect");
+ if (status)
+ pr_err("%s: %s: gpio_request(%d) failed\n",
+ mmc_hostname(host->mmc), __func__, gpio_no);
+}
+
+static void msmsdcc_disable_status_gpio(struct msmsdcc_host *host)
+{
+ if (gpio_is_valid(host->plat->status_gpio))
+ gpio_free(host->plat->status_gpio);
+}
+
static unsigned int
msmsdcc_slot_status(struct msmsdcc_host *host)
{
int status;
- unsigned int gpio_no = host->plat->status_gpio;
- status = gpio_request(gpio_no, "SD_HW_Detect");
- if (status) {
- pr_err("%s: %s: Failed to request GPIO %d\n",
- mmc_hostname(host->mmc), __func__, gpio_no);
- } else {
- status = gpio_direction_input(gpio_no);
- if (!status) {
- status = gpio_get_value_cansleep(gpio_no);
- if (host->plat->is_status_gpio_active_low)
- status = !status;
- }
- gpio_free(gpio_no);
- }
+ status = gpio_get_value_cansleep(host->plat->status_gpio);
+ if (host->plat->is_status_gpio_active_low)
+ status = !status;
+
return status;
}
@@ -4806,7 +4840,7 @@
struct msmsdcc_host *host = mmc_priv(mmc);
return snprintf(buf, PAGE_SIZE, "%u (Min 5 sec)\n",
- host->idle_tout_ms / 1000);
+ host->idle_tout / 1000);
}
static ssize_t
@@ -4821,7 +4855,7 @@
if (!kstrtou32(buf, 0, &timeout)
&& (timeout > MSM_MMC_DEFAULT_IDLE_TIMEOUT / 1000)) {
spin_lock_irqsave(&host->lock, flags);
- host->idle_tout_ms = timeout * 1000;
+ host->idle_tout = timeout * 1000;
spin_unlock_irqrestore(&host->lock, flags);
}
return count;
@@ -5417,7 +5451,7 @@
struct mmc_platform_data *pdata;
struct device_node *np = dev->of_node;
u32 bus_width = 0, current_limit = 0;
- u32 *clk_table, *sup_voltages;
+ u32 *clk_table = NULL, *sup_voltages = NULL;
int clk_table_len, sup_volt_len, len;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -5806,6 +5840,7 @@
mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
mmc->caps2 |= MMC_CAP2_SANITIZE;
mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
+ mmc->caps2 |= MMC_CAP2_INIT_BKOPS;
if (plat->nonremovable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
@@ -5888,11 +5923,12 @@
plat->wpswitch_gpio = -ENOENT;
if (plat->status || gpio_is_valid(plat->status_gpio)) {
- if (plat->status)
+ if (plat->status) {
host->oldstat = plat->status(mmc_dev(host->mmc));
- else
+ } else {
+ msmsdcc_enable_status_gpio(host);
host->oldstat = msmsdcc_slot_status(host);
-
+ }
host->eject = !host->oldstat;
}
@@ -5947,7 +5983,7 @@
pm_runtime_enable(&(pdev)->dev);
}
#endif
- host->idle_tout_ms = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
+ host->idle_tout = MSM_MMC_DEFAULT_IDLE_TIMEOUT;
setup_timer(&host->req_tout_timer, msmsdcc_req_tout_timer_hdlr,
(unsigned long)host);
@@ -6075,6 +6111,7 @@
if (plat->status_irq)
free_irq(plat->status_irq, host);
+ msmsdcc_disable_status_gpio(host);
sdiowakeup_irq_free:
wake_lock_destroy(&host->sdio_suspend_wlock);
if (plat->sdiowakeup_irq)
@@ -6126,6 +6163,16 @@
return ret;
}
+#ifdef CONFIG_DEBUG_FS
+static void msmsdcc_remove_debugfs(struct msmsdcc_host *host)
+{
+ debugfs_remove_recursive(host->debugfs_host_dir);
+ host->debugfs_host_dir = NULL;
+}
+#else
+static void msmsdcc_remove_debugfs(msmsdcc_host *host) {}
+#endif
+
static int msmsdcc_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = mmc_get_drvdata(pdev);
@@ -6152,6 +6199,8 @@
device_remove_file(&pdev->dev, &host->polling);
device_remove_file(&pdev->dev, &host->idle_timeout);
+ msmsdcc_remove_debugfs(host);
+
del_timer_sync(&host->req_tout_timer);
tasklet_kill(&host->dma_tlet);
tasklet_kill(&host->sps.tlet);
@@ -6159,6 +6208,7 @@
if (plat->status_irq)
free_irq(plat->status_irq, host);
+ msmsdcc_disable_status_gpio(host);
wake_lock_destroy(&host->sdio_suspend_wlock);
if (plat->sdiowakeup_irq) {
@@ -6328,6 +6378,23 @@
}
#endif
+#if CONFIG_DEBUG_FS
+static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
+ const char *func)
+{
+ ktime_t diff;
+
+ if (host->print_pm_stats) {
+ diff = ktime_sub(ktime_get(), start);
+ pr_info("%s: %s: Completed in %llu usec\n", func,
+ mmc_hostname(host->mmc), (u64)ktime_to_us(diff));
+ }
+}
+#else
+static void msmsdcc_print_pm_stats(struct msmsdcc_host *host, ktime_t start,
+ const char *func) {}
+#endif
+
static int
msmsdcc_runtime_suspend(struct device *dev)
{
@@ -6335,6 +6402,7 @@
struct msmsdcc_host *host = mmc_priv(mmc);
int rc = 0;
unsigned long flags;
+ ktime_t start = ktime_get();
if (host->plat->is_sdio_al_client) {
rc = 0;
@@ -6391,6 +6459,7 @@
out:
/* set bus bandwidth to 0 immediately */
msmsdcc_msm_bus_cancel_work_and_set_vote(host, NULL);
+ msmsdcc_print_pm_stats(host, start, __func__);
return rc;
}
@@ -6400,9 +6469,10 @@
struct mmc_host *mmc = dev_get_drvdata(dev);
struct msmsdcc_host *host = mmc_priv(mmc);
unsigned long flags;
+ ktime_t start = ktime_get();
if (host->plat->is_sdio_al_client)
- return 0;
+ goto out;
pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
if (mmc) {
@@ -6437,6 +6507,8 @@
}
host->pending_resume = false;
pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
+out:
+ msmsdcc_print_pm_stats(host, start, __func__);
return 0;
}
@@ -6449,7 +6521,7 @@
return 0;
/* Idle timeout is not configurable for now */
- pm_schedule_suspend(dev, host->idle_tout_ms);
+ pm_schedule_suspend(dev, host->idle_tout);
return -EAGAIN;
}
@@ -6459,17 +6531,21 @@
struct mmc_host *mmc = dev_get_drvdata(dev);
struct msmsdcc_host *host = mmc_priv(mmc);
int rc = 0;
+ ktime_t start = ktime_get();
- if (host->plat->is_sdio_al_client)
- return 0;
-
-
- if (host->plat->status_irq)
+ if (host->plat->is_sdio_al_client) {
+ rc = 0;
+ goto out;
+ }
+ if (host->plat->status_irq) {
disable_irq(host->plat->status_irq);
+ msmsdcc_disable_status_gpio(host);
+ }
if (!pm_runtime_suspended(dev))
rc = msmsdcc_runtime_suspend(dev);
-
+ out:
+ msmsdcc_print_pm_stats(host, start, __func__);
return rc;
}
@@ -6502,10 +6578,12 @@
struct mmc_host *mmc = dev_get_drvdata(dev);
struct msmsdcc_host *host = mmc_priv(mmc);
int rc = 0;
+ ktime_t start = ktime_get();
- if (host->plat->is_sdio_al_client)
- return 0;
-
+ if (host->plat->is_sdio_al_client) {
+ rc = 0;
+ goto out;
+ }
if (mmc->card && mmc_card_sdio(mmc->card))
rc = msmsdcc_runtime_resume(dev);
/*
@@ -6518,10 +6596,12 @@
host->pending_resume = true;
if (host->plat->status_irq) {
+ msmsdcc_enable_status_gpio(host);
msmsdcc_check_status((unsigned long)host);
enable_irq(host->plat->status_irq);
}
-
+out:
+ msmsdcc_print_pm_stats(host, start, __func__);
return rc;
}
@@ -6595,7 +6675,6 @@
platform_driver_unregister(&msmsdcc_driver);
#if defined(CONFIG_DEBUG_FS)
- debugfs_remove(debugfs_file);
debugfs_remove(debugfs_dir);
#endif
}
@@ -6607,59 +6686,128 @@
MODULE_LICENSE("GPL");
#if defined(CONFIG_DEBUG_FS)
-
-static int
-msmsdcc_dbg_state_open(struct inode *inode, struct file *file)
+static int msmsdcc_dbg_idle_tout_get(void *data, u64 *val)
{
- file->private_data = inode->i_private;
+ struct msmsdcc_host *host = data;
+
+ *val = host->idle_tout / 1000L;
return 0;
}
-static ssize_t
-msmsdcc_dbg_state_read(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
+static int msmsdcc_dbg_idle_tout_set(void *data, u64 val)
{
- struct msmsdcc_host *host = (struct msmsdcc_host *) file->private_data;
- char buf[200];
- int max, i;
+ struct msmsdcc_host *host = data;
+ unsigned long flags;
- i = 0;
- max = sizeof(buf) - 1;
+ spin_lock_irqsave(&host->lock, flags);
+ host->idle_tout = (u32)val * 1000;
+ spin_unlock_irqrestore(&host->lock, flags);
- i += scnprintf(buf + i, max - i, "STAT: %p %p %p\n", host->curr.mrq,
- host->curr.cmd, host->curr.data);
- if (host->curr.cmd) {
- struct mmc_command *cmd = host->curr.cmd;
-
- i += scnprintf(buf + i, max - i, "CMD : %.8x %.8x %.8x\n",
- cmd->opcode, cmd->arg, cmd->flags);
- }
- if (host->curr.data) {
- struct mmc_data *data = host->curr.data;
- i += scnprintf(buf + i, max - i,
- "DAT0: %.8x %.8x %.8x %.8x %.8x %.8x\n",
- data->timeout_ns, data->timeout_clks,
- data->blksz, data->blocks, data->error,
- data->flags);
- i += scnprintf(buf + i, max - i, "DAT1: %.8x %.8x %.8x %p\n",
- host->curr.xfer_size, host->curr.xfer_remain,
- host->curr.data_xfered, host->dma.sg);
- }
-
- return simple_read_from_buffer(ubuf, count, ppos, buf, i);
+ return 0;
}
-static const struct file_operations msmsdcc_dbg_state_ops = {
- .read = msmsdcc_dbg_state_read,
- .open = msmsdcc_dbg_state_open,
-};
+DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_idle_tout_ops,
+ msmsdcc_dbg_idle_tout_get,
+ msmsdcc_dbg_idle_tout_set,
+ "%llu\n");
+
+static int msmsdcc_dbg_pio_mode_get(void *data, u64 *val)
+{
+ struct msmsdcc_host *host = data;
+
+ *val = (u64) host->enforce_pio_mode;
+ return 0;
+}
+
+static int msmsdcc_dbg_pio_mode_set(void *data, u64 val)
+{
+ struct msmsdcc_host *host = data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->enforce_pio_mode = !!val;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pio_mode_ops,
+ msmsdcc_dbg_pio_mode_get,
+ msmsdcc_dbg_pio_mode_set,
+ "%llu\n");
+
+static int msmsdcc_dbg_pm_stats_get(void *data, u64 *val)
+{
+ struct msmsdcc_host *host = data;
+
+ *val = !!host->print_pm_stats;
+ return 0;
+}
+
+static int msmsdcc_dbg_pm_stats_set(void *data, u64 val)
+{
+ struct msmsdcc_host *host = data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->print_pm_stats = !!val;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(msmsdcc_dbg_pm_stats_ops,
+ msmsdcc_dbg_pm_stats_get,
+ msmsdcc_dbg_pm_stats_set,
+ "%llu\n");
static void msmsdcc_dbg_createhost(struct msmsdcc_host *host)
{
- if (debugfs_dir) {
- debugfs_file = debugfs_create_file(mmc_hostname(host->mmc),
- 0644, debugfs_dir, host,
- &msmsdcc_dbg_state_ops);
+ int err = 0;
+
+ if (!debugfs_dir)
+ return;
+
+ host->debugfs_host_dir = debugfs_create_dir(
+ mmc_hostname(host->mmc), debugfs_dir);
+ if (IS_ERR(host->debugfs_host_dir)) {
+ err = PTR_ERR(host->debugfs_host_dir);
+ host->debugfs_host_dir = NULL;
+ pr_err("%s: Failed to create debugfs dir for host with err=%d\n",
+ mmc_hostname(host->mmc), err);
+ return;
+ }
+
+ host->debugfs_idle_tout = debugfs_create_file("idle_tout",
+ S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
+ &msmsdcc_dbg_idle_tout_ops);
+
+ if (IS_ERR(host->debugfs_idle_tout)) {
+ err = PTR_ERR(host->debugfs_idle_tout);
+ host->debugfs_idle_tout = NULL;
+ pr_err("%s: Failed to create idle_tout debugfs entry with err=%d\n",
+ mmc_hostname(host->mmc), err);
+ }
+
+ host->debugfs_pio_mode = debugfs_create_file("pio_mode",
+ S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
+ &msmsdcc_dbg_pio_mode_ops);
+
+ if (IS_ERR(host->debugfs_pio_mode)) {
+ err = PTR_ERR(host->debugfs_pio_mode);
+ host->debugfs_pio_mode = NULL;
+ pr_err("%s: Failed to create pio_mode debugfs entry with err=%d\n",
+ mmc_hostname(host->mmc), err);
+ }
+
+ host->debugfs_pm_stats = debugfs_create_file("pm_stats",
+ S_IRUSR | S_IWUSR, host->debugfs_host_dir, host,
+ &msmsdcc_dbg_pm_stats_ops);
+ if (IS_ERR(host->debugfs_pm_stats)) {
+ err = PTR_ERR(host->debugfs_pm_stats);
+ host->debugfs_pm_stats = NULL;
+ pr_err("%s: Failed to create pm_stats debugfs entry with err=%d\n",
+ mmc_hostname(host->mmc), err);
}
}
@@ -6667,7 +6815,7 @@
{
int err;
- debugfs_dir = debugfs_create_dir("msmsdcc", 0);
+ debugfs_dir = debugfs_create_dir("msm_sdcc", 0);
if (IS_ERR(debugfs_dir)) {
err = PTR_ERR(debugfs_dir);
debugfs_dir = NULL;
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 5779491..c66d1a5 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -414,14 +414,20 @@
bool sdio_wakeupirq_disabled;
struct mutex clk_mutex;
bool pending_resume;
- unsigned int idle_tout_ms; /* Timeout in msecs */
+ unsigned int idle_tout; /* Timeout in msecs */
bool pending_dpsm_reset;
+ bool enforce_pio_mode;
+ bool print_pm_stats;
struct msmsdcc_msm_bus_vote msm_bus_vote;
struct device_attribute max_bus_bw;
struct device_attribute polling;
struct device_attribute idle_timeout;
struct device_attribute auto_cmd19_attr;
struct device_attribute auto_cmd21_attr;
+ struct dentry *debugfs_host_dir;
+ struct dentry *debugfs_idle_tout;
+ struct dentry *debugfs_pio_mode;
+ struct dentry *debugfs_pm_stats;
};
#define MSMSDCC_VERSION_STEP_MASK 0x0000FFFF
@@ -483,7 +489,7 @@
if ((step == 0x18) && (minor >= 3))
host->hw_caps |= MSMSDCC_AUTO_CMD21;
- if (version >= 0x2b) /* SDCC v4 2.1.0 and greater */
+ if (step >= 0x2b) /* SDCC v4 2.1.0 and greater */
host->hw_caps |= MSMSDCC_SW_RST | MSMSDCC_AUTO_CMD21;
}
diff --git a/drivers/net/ethernet/msm/msm_rmnet.c b/drivers/net/ethernet/msm/msm_rmnet.c
index 61df241..41ad8af 100644
--- a/drivers/net/ethernet/msm/msm_rmnet.c
+++ b/drivers/net/ethernet/msm/msm_rmnet.c
@@ -501,16 +501,10 @@
static int __rmnet_close(struct net_device *dev)
{
struct rmnet_private *p = netdev_priv(dev);
- int rc;
- unsigned long flags;
- if (p->ch) {
- rc = smd_close(p->ch);
- spin_lock_irqsave(&p->lock, flags);
- p->ch = 0;
- spin_unlock_irqrestore(&p->lock, flags);
- return rc;
- } else
+ if (p->ch)
+ return 0;
+ else
return -EBADF;
}
@@ -529,12 +523,9 @@
static int rmnet_stop(struct net_device *dev)
{
- struct rmnet_private *p = netdev_priv(dev);
-
DBG0("[%s] rmnet_stop()\n", dev->name);
netif_stop_queue(dev);
- tasklet_kill(&p->tsklt);
/* TODO: unload modem safely,
currently, this causes unnecessary unloads */
diff --git a/drivers/net/ethernet/msm/msm_rmnet_smux.c b/drivers/net/ethernet/msm/msm_rmnet_smux.c
index fbb3489..5f29406 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_smux.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_smux.c
@@ -79,6 +79,7 @@
unsigned long timeout_us;
#endif
spinlock_t lock;
+ spinlock_t tx_queue_lock;
struct tasklet_struct tsklt;
/* IOCTL specified mode (protocol, QoS header) */
u32 operation_mode;
@@ -346,12 +347,15 @@
((struct net_device *)(dev))->name, p->stats.tx_packets,
skb->len, skb->mark);
dev_kfree_skb_any(skb);
+
+ spin_lock_irqsave(&p->tx_queue_lock, flags);
if (netif_queue_stopped(dev) &&
msm_smux_is_ch_low(p->ch_id)) {
DBG0("%s: Low WM hit, waking queue=%p\n",
__func__, skb);
netif_wake_queue(dev);
}
+ spin_unlock_irqrestore(&p->tx_queue_lock, flags);
}
void rmnet_smux_notify(void *priv, int event_type, const void *metadata)
@@ -475,14 +479,20 @@
case SMUX_LOW_WM_HIT:
dev = priv;
+ p = netdev_priv(priv);
DBG0("[%s] Low WM hit dev:%s\n", __func__, dev->name);
+ spin_lock_irqsave(&p->tx_queue_lock, flags);
netif_start_queue(dev);
+ spin_unlock_irqrestore(&p->tx_queue_lock, flags);
break;
case SMUX_HIGH_WM_HIT:
dev = priv;
- DBG0("[%s] Low WM hit dev:%s\n", __func__, dev->name);
+ p = netdev_priv(priv);
+ DBG0("[%s] High WM hit dev:%s\n", __func__, dev->name);
+ spin_lock_irqsave(&p->tx_queue_lock, flags);
netif_stop_queue(dev);
+ spin_unlock_irqrestore(&p->tx_queue_lock, flags);
break;
default:
@@ -573,7 +583,6 @@
static int _rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct rmnet_private *p = netdev_priv(dev);
- int smux_ret;
struct QMI_QOS_HDR_S *qmih;
u32 opmode;
unsigned long flags;
@@ -593,21 +602,13 @@
dev->trans_start = jiffies;
- /* if write() succeeds, skb access is unsafe in this process */
- smux_ret = msm_smux_write(p->ch_id, skb, skb->data, skb->len);
-
- if (smux_ret != 0 && smux_ret != -EAGAIN) {
- pr_err("[%s] %s: write returned error %d",
- dev->name, __func__, smux_ret);
- return -EPERM;
- }
-
- return smux_ret;
+ return msm_smux_write(p->ch_id, skb, skb->data, skb->len);
}
static int rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct rmnet_private *p = netdev_priv(dev);
+ unsigned long flags;
int ret = 0;
if (netif_queue_stopped(dev) || (p->device_state == DEVICE_INACTIVE)) {
@@ -616,17 +617,10 @@
return 0;
}
+ spin_lock_irqsave(&p->tx_queue_lock, flags);
ret = _rmnet_xmit(skb, dev);
- if (ret == -EPERM) {
- /* Do not stop the queue here.
- * It will lead to ir-recoverable state.
- */
- ret = NETDEV_TX_BUSY;
- goto exit;
- }
-
- if (msm_smux_is_ch_full(p->ch_id) || (ret == -EAGAIN)) {
+ if (ret == -EAGAIN) {
/*
* EAGAIN means we attempted to overflow the high watermark
* Clearly the queue is not stopped like it should be, so
@@ -636,9 +630,9 @@
*/
netif_stop_queue(dev);
ret = NETDEV_TX_BUSY;
- goto exit;
}
-exit:
+ spin_unlock_irqrestore(&p->tx_queue_lock, flags);
+
return ret;
}
@@ -892,6 +886,7 @@
p->ch_id = n;
p->in_reset = 0;
spin_lock_init(&p->lock);
+ spin_lock_init(&p->tx_queue_lock);
#ifdef CONFIG_MSM_RMNET_DEBUG
p->timeout_us = timeout_us;
p->wakeups_xmit = p->wakeups_rcv = 0;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 1867fe2..6de0a77 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1529,6 +1529,7 @@
spin_lock_irq(&dev->txq.lock);
/* don't autosuspend while transmitting */
if (dev->txq.qlen && PMSG_IS_AUTO(message)) {
+ dev->suspend_count--;
spin_unlock_irq(&dev->txq.lock);
return -EBUSY;
} else {
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index ac0a2fd..2bf857c 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -27,6 +27,7 @@
#include <linux/of_gpio.h>
#include <mach/peripheral-loader.h>
#include <mach/msm_smd.h>
+#include <mach/msm_iomap.h>
#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
#include "wcnss_prealloc.h"
#endif
@@ -159,6 +160,18 @@
static DEVICE_ATTR(wcnss_version, S_IRUSR,
wcnss_version_show, NULL);
+/* interface to reset Riva by sending the reset interrupt */
+void wcnss_reset_intr(void)
+{
+ if (wcnss_hardware_type() == WCNSS_RIVA_HW) {
+ wmb();
+ __raw_writel(1 << 24, MSM_APCS_GCC_BASE + 0x8);
+ } else {
+ pr_err("%s: reset interrupt not supported\n", __func__);
+ }
+}
+EXPORT_SYMBOL(wcnss_reset_intr);
+
static int wcnss_create_sysfs(struct device *dev)
{
int ret;
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 33b12ae..76a758b 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -39,8 +39,10 @@
#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_S1_TIMER_MASK (0xF)
#define QPNP_PON_S2_TIMER_MASK (0x7)
@@ -49,6 +51,7 @@
#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)
@@ -66,6 +69,7 @@
enum pon_type {
PON_KPDPWR,
PON_RESIN,
+ PON_CBLPWR,
};
struct qpnp_pon_config {
@@ -214,6 +218,9 @@
case PON_RESIN:
pon_rt_bit = QPNP_PON_RESIN_N_SET;
break;
+ case PON_CBLPWR:
+ pon_rt_bit = QPNP_PON_CBLPWR_N_SET;
+ break;
default:
return -EINVAL;
}
@@ -253,6 +260,18 @@
return IRQ_HANDLED;
}
+static irqreturn_t qpnp_cblpwr_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+
+ rc = qpnp_pon_input_dispatch(pon, PON_CBLPWR);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to send input event\n");
+
+ return IRQ_HANDLED;
+}
+
static void bark_work_func(struct work_struct *work)
{
int rc;
@@ -351,6 +370,9 @@
case PON_RESIN:
pull_bit = QPNP_PON_RESIN_PULL_UP;
break;
+ case PON_CBLPWR:
+ pull_bit = QPNP_PON_CBLPWR_PULL_UP;
+ break;
default:
return -EINVAL;
}
@@ -489,6 +511,17 @@
}
}
break;
+ case PON_CBLPWR:
+ rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+ qpnp_cblpwr_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "qpnp_cblpwr_status", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+ cfg->state_irq);
+ return rc;
+ }
+ break;
default:
return -EINVAL;
}
@@ -595,6 +628,15 @@
}
}
break;
+ case PON_CBLPWR:
+ cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "cblpwr");
+ if (cfg->state_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get cblpwr irq\n");
+ return rc;
+ }
+ break;
default:
dev_err(&pon->spmi->dev, "PON RESET %d not supported",
cfg->pon_type);
@@ -763,11 +805,13 @@
rc = of_property_read_u32(pon->spmi->dev.of_node,
"qcom,pon-dbc-delay", &delay);
- if (rc && rc != -EINVAL) {
- dev_err(&spmi->dev, "Unable to read debounce delay\n");
- return rc;
+ if (rc) {
+ if (rc != -EINVAL) {
+ dev_err(&spmi->dev, "Unable to read debounce delay\n");
+ return rc;
+ }
} else {
- delay = (delay << 6) / USEC_PER_SEC;
+ delay = (delay << QPNP_PON_DELAY_BIT_SHIFT) / USEC_PER_SEC;
delay = ilog2(delay);
rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
QPNP_PON_DBC_DELAY_MASK, delay);
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 6f9af36..ebe3ad06 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -439,7 +439,7 @@
int i, pwm_size, rc = 0;
int burst_size = SPMI_MAX_BUF_LEN;
int list_len = lut->list_len << 1;
- int offset = lut->lo_index << 2;
+ int offset = lut->lo_index << 1;
pwm_size = QPNP_GET_PWM_SIZE(
chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) &
@@ -856,7 +856,7 @@
return qpnp_lpg_save_and_write(value, mask,
&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
- lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+ lpg_config->base_addr, QPNP_ENABLE_CONTROL, 1, chip);
}
static int qpnp_disable_pwm(struct pwm_device *pwm)
@@ -873,7 +873,7 @@
return qpnp_lpg_save_and_write(value, mask,
&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
- lpg_config->base_addr, QPNP_RAMP_CONTROL, 1, chip);
+ lpg_config->base_addr, QPNP_ENABLE_CONTROL, 1, chip);
}
static int _pwm_config(struct pwm_device *pwm, int duty_us, int period_us)
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 5bbcc84..25febff 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -1828,19 +1828,6 @@
if (virt_addr != NULL)
bam->props.virt_addr = virt_addr;
- if ((bam_props->manage & SPS_BAM_MGR_DEVICE_REMOTE) != 0 &&
- (bam_props->manage & SPS_BAM_MGR_MULTI_EE) != 0 &&
- bam_props->ee == 0) {
- /*
- * BAM global is owned by a remote processor, so force EE index
- * to a non-zero value to insure EE zero globals are not
- * modified.
- */
- SPS_DBG2("sps:Setting EE for BAM %x to non-zero",
- bam_props->phys_addr);
- bam->props.ee = 1;
- }
-
ok = sps_bam_device_init(bam);
mutex_unlock(&bam->lock);
if (ok) {
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 551c0a7..bf78b1c 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -258,6 +258,11 @@
struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
int ret;
+ if (!usb_bam_pdev) {
+ pr_err("%s: usb_bam device not found\n", __func__);
+ return -ENODEV;
+ }
+
if (idx >= CONNECTIONS_NUM) {
pr_err("%s: Invalid connection index\n",
__func__);
@@ -715,12 +720,9 @@
usb_bam_show_enable(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct platform_device *pdev =
- container_of(dev, struct platform_device, dev);
- struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
+ struct msm_usb_bam_platform_data *pdata = dev->platform_data;
- if (!pdev || !pdata)
+ if (!pdata)
return 0;
return scnprintf(buf, PAGE_SIZE, "%s\n",
bam_enable_strings[pdata->usb_active_bam]);
@@ -730,13 +732,15 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct platform_device *pdev = container_of(dev,
- struct platform_device, dev);
- struct msm_usb_bam_platform_data *pdata =
- usb_bam_pdev->dev.platform_data;
+ struct msm_usb_bam_platform_data *pdata = dev->platform_data;
char str[10], *pstr;
int ret, i;
+ if (!pdata) {
+ dev_err(dev, "no usb_bam pdata found\n");
+ return -ENODEV;
+ }
+
strlcpy(str, buf, sizeof(str));
pstr = strim(str);
@@ -745,12 +749,12 @@
pdata->usb_active_bam = i;
}
- dev_dbg(&pdev->dev, "active_bam=%s\n",
+ dev_dbg(dev, "active_bam=%s\n",
bam_enable_strings[pdata->usb_active_bam]);
ret = usb_bam_init();
if (ret) {
- dev_err(&pdev->dev, "failed to initialize usb bam\n");
+ dev_err(dev, "failed to initialize usb bam\n");
return ret;
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 2542845..c474e36 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -395,6 +395,16 @@
help
Say Y here to enable support for pm8921 chip charger subdevice
+config QPNP_CHARGER
+ tristate "QPNP Charger driver"
+ depends on SPMI
+ depends on OF_SPMI
+ help
+ Say Y here to enable the switch mode battery charger
+ and boost device which supports USB detection and charging. The driver
+ also offers relevant information to userspace via the power supply
+ framework.
+
config PM8XXX_CCADC
tristate "PM8XXX battery current adc driver"
depends on MFD_PM8921_CORE
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 9dc1960..3521cfd 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -57,6 +57,7 @@
obj-$(CONFIG_PM8921_BMS) += pm8921-bms.o
obj-$(CONFIG_QPNP_BMS) += qpnp-bms.o
obj-$(CONFIG_PM8921_CHARGER) += pm8921-charger.o
+obj-$(CONFIG_QPNP_CHARGER) += qpnp-charger.o
obj-$(CONFIG_LTC4088_CHARGER) += ltc4088-charger.o
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
obj-$(CONFIG_BATTERY_BCL) += battery_current_limit.o
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index c63c99f..23903df 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,8 +10,8 @@
* GNU General Public License for more details.
*
*/
-#define pr_fmt(fmt) "%s: " fmt, __func__
+#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
@@ -22,6 +22,7 @@
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/ccadc.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
@@ -147,8 +148,9 @@
int ibat_at_cv_ua;
int soc_at_cv;
int prev_chg_soc;
-
struct power_supply *batt_psy;
+ bool low_voltage_wake_lock_held;
+ struct wake_lock low_voltage_wake_lock;
};
/*
@@ -224,7 +226,6 @@
module_param_cb(bms_end_ocv_uv, &bms_ro_param_ops, &bms_end_ocv_uv, 0644);
module_param_cb(bms_end_cc_uah, &bms_ro_param_ops, &bms_end_cc_uah, 0644);
-static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp);
static void readjust_fcc_table(void)
{
struct single_row_lut *temp, *old;
@@ -241,7 +242,7 @@
return;
}
- fcc = interpolate_fcc(the_chip, last_real_fcc_batt_temp);
+ fcc = interpolate_fcc(the_chip->fcc_temp_lut, last_real_fcc_batt_temp);
temp->cols = the_chip->fcc_temp_lut->cols;
for (i = 0; i < the_chip->fcc_temp_lut->cols; i++) {
@@ -583,342 +584,6 @@
return 0;
}
-static int linear_interpolate(int y0, int x0, int y1, int x1, int x)
-{
- if (y0 == y1 || x == x0)
- return y0;
- if (x1 == x0 || x == x1)
- return y1;
-
- return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
-}
-
-static int interpolate_single_lut(struct single_row_lut *lut, int x)
-{
- int i, result;
-
- if (x < lut->x[0]) {
- pr_debug("x %d less than known range return y = %d lut = %pS\n",
- x, lut->y[0], lut);
- return lut->y[0];
- }
- if (x > lut->x[lut->cols - 1]) {
- pr_debug("x %d more than known range return y = %d lut = %pS\n",
- x, lut->y[lut->cols - 1], lut);
- return lut->y[lut->cols - 1];
- }
-
- for (i = 0; i < lut->cols; i++)
- if (x <= lut->x[i])
- break;
- if (x == lut->x[i]) {
- result = lut->y[i];
- } else {
- result = linear_interpolate(
- lut->y[i - 1],
- lut->x[i - 1],
- lut->y[i],
- lut->x[i],
- x);
- }
- return result;
-}
-
-static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp)
-{
- /* batt_temp is in tenths of degC - convert it to degC for lookups */
- batt_temp = batt_temp/10;
- return interpolate_single_lut(chip->fcc_temp_lut, batt_temp);
-}
-
-static int interpolate_fcc_adjusted(struct pm8921_bms_chip *chip, int batt_temp)
-{
- /* batt_temp is in tenths of degC - convert it to degC for lookups */
- batt_temp = batt_temp/10;
- return interpolate_single_lut(chip->adjusted_fcc_temp_lut, batt_temp);
-}
-
-static int interpolate_scalingfactor_fcc(struct pm8921_bms_chip *chip,
- int cycles)
-{
- /*
- * sf table could be null when no battery aging data is available, in
- * that case return 100%
- */
- if (chip->fcc_sf_lut)
- return interpolate_single_lut(chip->fcc_sf_lut, cycles);
- else
- return 100;
-}
-
-static int interpolate_scalingfactor(struct pm8921_bms_chip *chip,
- struct sf_lut *sf_lut,
- int row_entry, int pc)
-{
- int i, scalefactorrow1, scalefactorrow2, scalefactor;
- int rows, cols;
- int row1 = 0;
- int row2 = 0;
-
- /*
- * sf table could be null when no battery aging data is available, in
- * that case return 100%
- */
- if (!sf_lut)
- return 100;
-
- rows = sf_lut->rows;
- cols = sf_lut->cols;
- if (pc > sf_lut->percent[0]) {
- pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
- row1 = 0;
- row2 = 0;
- }
- if (pc < sf_lut->percent[rows - 1]) {
- pr_debug("pc %d less than known pc ranges for sf", pc);
- row1 = rows - 1;
- row2 = rows - 1;
- }
- for (i = 0; i < rows; i++) {
- if (pc == sf_lut->percent[i]) {
- row1 = i;
- row2 = i;
- break;
- }
- if (pc > sf_lut->percent[i]) {
- row1 = i - 1;
- row2 = i;
- break;
- }
- }
-
- if (row_entry < sf_lut->row_entries[0])
- row_entry = sf_lut->row_entries[0];
- if (row_entry > sf_lut->row_entries[cols - 1])
- row_entry = sf_lut->row_entries[cols - 1];
-
- for (i = 0; i < cols; i++)
- if (row_entry <= sf_lut->row_entries[i])
- break;
- if (row_entry == sf_lut->row_entries[i]) {
- scalefactor = linear_interpolate(
- sf_lut->sf[row1][i],
- sf_lut->percent[row1],
- sf_lut->sf[row2][i],
- sf_lut->percent[row2],
- pc);
- return scalefactor;
- }
-
- scalefactorrow1 = linear_interpolate(
- sf_lut->sf[row1][i - 1],
- sf_lut->row_entries[i - 1],
- sf_lut->sf[row1][i],
- sf_lut->row_entries[i],
- row_entry);
-
- scalefactorrow2 = linear_interpolate(
- sf_lut->sf[row2][i - 1],
- sf_lut->row_entries[i - 1],
- sf_lut->sf[row2][i],
- sf_lut->row_entries[i],
- row_entry);
-
- scalefactor = linear_interpolate(
- scalefactorrow1,
- sf_lut->percent[row1],
- scalefactorrow2,
- sf_lut->percent[row2],
- pc);
-
- return scalefactor;
-}
-
-static int is_between(int left, int right, int value)
-{
- if (left >= right && left >= value && value >= right)
- return 1;
- if (left <= right && left <= value && value <= right)
- return 1;
-
- return 0;
-}
-
-/* get ocv given a soc -- reverse lookup */
-static int interpolate_ocv(struct pm8921_bms_chip *chip,
- int batt_temp_degc, int pc)
-{
- int i, ocvrow1, ocvrow2, ocv;
- int rows, cols;
- int row1 = 0;
- int row2 = 0;
-
- rows = chip->pc_temp_ocv_lut->rows;
- cols = chip->pc_temp_ocv_lut->cols;
- if (pc > chip->pc_temp_ocv_lut->percent[0]) {
- pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
- row1 = 0;
- row2 = 0;
- }
- if (pc < chip->pc_temp_ocv_lut->percent[rows - 1]) {
- pr_debug("pc %d less than known pc ranges for sf\n", pc);
- row1 = rows - 1;
- row2 = rows - 1;
- }
- for (i = 0; i < rows; i++) {
- if (pc == chip->pc_temp_ocv_lut->percent[i]) {
- row1 = i;
- row2 = i;
- break;
- }
- if (pc > chip->pc_temp_ocv_lut->percent[i]) {
- row1 = i - 1;
- row2 = i;
- break;
- }
- }
-
- if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0])
- batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
- if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1])
- batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
-
- for (i = 0; i < cols; i++)
- if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[i])
- break;
- if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[i]) {
- ocv = linear_interpolate(
- chip->pc_temp_ocv_lut->ocv[row1][i],
- chip->pc_temp_ocv_lut->percent[row1],
- chip->pc_temp_ocv_lut->ocv[row2][i],
- chip->pc_temp_ocv_lut->percent[row2],
- pc);
- return ocv;
- }
-
- ocvrow1 = linear_interpolate(
- chip->pc_temp_ocv_lut->ocv[row1][i - 1],
- chip->pc_temp_ocv_lut->temp[i - 1],
- chip->pc_temp_ocv_lut->ocv[row1][i],
- chip->pc_temp_ocv_lut->temp[i],
- batt_temp_degc);
-
- ocvrow2 = linear_interpolate(
- chip->pc_temp_ocv_lut->ocv[row2][i - 1],
- chip->pc_temp_ocv_lut->temp[i - 1],
- chip->pc_temp_ocv_lut->ocv[row2][i],
- chip->pc_temp_ocv_lut->temp[i],
- batt_temp_degc);
-
- ocv = linear_interpolate(
- ocvrow1,
- chip->pc_temp_ocv_lut->percent[row1],
- ocvrow2,
- chip->pc_temp_ocv_lut->percent[row2],
- pc);
-
- return ocv;
-}
-
-static int interpolate_pc(struct pm8921_bms_chip *chip,
- int batt_temp_degc, int ocv)
-{
- int i, j, pcj, pcj_minus_one, pc;
- int rows = chip->pc_temp_ocv_lut->rows;
- int cols = chip->pc_temp_ocv_lut->cols;
-
-
- if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0]) {
- pr_debug("batt_temp %d < known temp range\n", batt_temp_degc);
- batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
- }
- if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1]) {
- pr_debug("batt_temp %d > known temp range\n", batt_temp_degc);
- batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
- }
-
- for (j = 0; j < cols; j++)
- if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[j])
- break;
- if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[j]) {
- /* found an exact match for temp in the table */
- if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
- return chip->pc_temp_ocv_lut->percent[0];
- if (ocv <= chip->pc_temp_ocv_lut->ocv[rows - 1][j])
- return chip->pc_temp_ocv_lut->percent[rows - 1];
- for (i = 0; i < rows; i++) {
- if (ocv >= chip->pc_temp_ocv_lut->ocv[i][j]) {
- if (ocv == chip->pc_temp_ocv_lut->ocv[i][j])
- return
- chip->pc_temp_ocv_lut->percent[i];
- pc = linear_interpolate(
- chip->pc_temp_ocv_lut->percent[i],
- chip->pc_temp_ocv_lut->ocv[i][j],
- chip->pc_temp_ocv_lut->percent[i - 1],
- chip->pc_temp_ocv_lut->ocv[i - 1][j],
- ocv);
- return pc;
- }
- }
- }
-
- /*
- * batt_temp_degc is within temperature for
- * column j-1 and j
- */
- if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
- return chip->pc_temp_ocv_lut->percent[0];
- if (ocv <= chip->pc_temp_ocv_lut->ocv[rows - 1][j - 1])
- return chip->pc_temp_ocv_lut->percent[rows - 1];
-
- pcj_minus_one = 0;
- pcj = 0;
- for (i = 0; i < rows-1; i++) {
- if (pcj == 0
- && is_between(chip->pc_temp_ocv_lut->ocv[i][j],
- chip->pc_temp_ocv_lut->ocv[i+1][j], ocv)) {
- pcj = linear_interpolate(
- chip->pc_temp_ocv_lut->percent[i],
- chip->pc_temp_ocv_lut->ocv[i][j],
- chip->pc_temp_ocv_lut->percent[i + 1],
- chip->pc_temp_ocv_lut->ocv[i+1][j],
- ocv);
- }
-
- if (pcj_minus_one == 0
- && is_between(chip->pc_temp_ocv_lut->ocv[i][j-1],
- chip->pc_temp_ocv_lut->ocv[i+1][j-1], ocv)) {
-
- pcj_minus_one = linear_interpolate(
- chip->pc_temp_ocv_lut->percent[i],
- chip->pc_temp_ocv_lut->ocv[i][j-1],
- chip->pc_temp_ocv_lut->percent[i + 1],
- chip->pc_temp_ocv_lut->ocv[i+1][j-1],
- ocv);
- }
-
- if (pcj && pcj_minus_one) {
- pc = linear_interpolate(
- pcj_minus_one,
- chip->pc_temp_ocv_lut->temp[j-1],
- pcj,
- chip->pc_temp_ocv_lut->temp[j],
- batt_temp_degc);
- return pc;
- }
- }
-
- if (pcj)
- return pcj;
-
- if (pcj_minus_one)
- return pcj_minus_one;
-
- pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%",
- ocv, batt_temp_degc);
- return 100;
-}
-
#define BMS_MODE_BIT BIT(6)
#define EN_VBAT_BIT BIT(5)
#define OVERRIDE_MODE_DELAY_MS 20
@@ -975,6 +640,26 @@
raw->last_good_ocv_raw -= MBG_TRANSIENT_ERROR_RAW;
}
+#define SEL_ALT_OREG_BIT BIT(2)
+static int ocv_ir_compensation(struct pm8921_bms_chip *chip, int ocv)
+{
+ int compensated_ocv;
+ int ibatt_ua;
+ int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
+
+ pm_bms_masked_write(chip, BMS_TEST1,
+ SEL_ALT_OREG_BIT, SEL_ALT_OREG_BIT);
+
+ /* since the SEL_ALT_OREG_BIT is set this will give us VSENSE_OCV */
+ pm8921_bms_get_battery_current(&ibatt_ua);
+ compensated_ocv = ocv + div_s64((s64)ibatt_ua * rbatt_mohm, 1000);
+ pr_debug("comp ocv = %d, ocv = %d, ibatt_ua = %d, rbatt_mohm = %d\n",
+ compensated_ocv, ocv, ibatt_ua, rbatt_mohm);
+
+ pm_bms_masked_write(chip, BMS_TEST1, SEL_ALT_OREG_BIT, 0);
+ return compensated_ocv;
+}
+
static int read_soc_params_raw(struct pm8921_bms_chip *chip,
struct pm8921_soc_params *raw)
{
@@ -997,6 +682,8 @@
adjust_pon_ocv_raw(chip, raw);
convert_vbatt_raw_to_uv(chip, usb_chg,
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
+ raw->last_good_ocv_uv = ocv_ir_compensation(chip,
+ raw->last_good_ocv_uv);
chip->last_ocv_uv = raw->last_good_ocv_uv;
pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
@@ -1042,7 +729,7 @@
}
/* Convert the batt_temp to DegC from deciDegC */
batt_temp = batt_temp / 10;
- scalefactor = interpolate_scalingfactor(chip, chip->rbatt_sf_lut,
+ scalefactor = interpolate_scalingfactor(chip->rbatt_sf_lut,
batt_temp, soc_rbatt);
pr_debug("rbatt sf = %d for batt_temp = %d, soc_rbatt = %d\n",
scalefactor, batt_temp, soc_rbatt);
@@ -1069,16 +756,18 @@
int initfcc, result, scalefactor = 0;
if (chip->adjusted_fcc_temp_lut == NULL) {
- initfcc = interpolate_fcc(chip, batt_temp);
+ initfcc = interpolate_fcc(chip->fcc_temp_lut, batt_temp);
- scalefactor = interpolate_scalingfactor_fcc(chip, chargecycles);
+ scalefactor = interpolate_scalingfactor_fcc(chip->fcc_sf_lut,
+ chargecycles);
/* Multiply the initial FCC value by the scale factor. */
result = (initfcc * scalefactor * 1000) / 100;
pr_debug("fcc = %d uAh\n", result);
return result;
} else {
- return 1000 * interpolate_fcc_adjusted(chip, batt_temp);
+ return 1000 * interpolate_fcc(chip->adjusted_fcc_temp_lut,
+ batt_temp);
}
}
@@ -1120,17 +809,18 @@
return 0;
}
-static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv, int batt_temp,
- int chargecycles)
+static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv,
+ int batt_temp, int chargecycles)
{
int pc, scalefactor;
- pc = interpolate_pc(chip, batt_temp / 10, ocv_uv / 1000);
+ pc = interpolate_pc(chip->pc_temp_ocv_lut,
+ batt_temp / 10, ocv_uv / 1000);
pr_debug("pc = %u for ocv = %dmicroVolts batt_temp = %d\n",
pc, ocv_uv, batt_temp);
- scalefactor = interpolate_scalingfactor(chip,
- chip->pc_sf_lut, chargecycles, pc);
+ scalefactor = interpolate_scalingfactor(chip->pc_sf_lut,
+ chargecycles, pc);
pr_debug("scalefactor = %u batt_temp = %d\n", scalefactor, batt_temp);
/* Multiply the initial FCC value by the scale factor. */
@@ -1183,7 +873,8 @@
int uuc_rbatt_uv;
for (i = 0; i <= 100; i++) {
- ocv_mv = interpolate_ocv(chip, batt_temp_degc, i);
+ ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
+ batt_temp_degc, i);
rbatt_mohm = get_rbatt(chip, i, batt_temp);
unusable_uv = (rbatt_mohm * i_ma) + (chip->v_cutoff * 1000);
delta_uv = ocv_mv * 1000 - unusable_uv;
@@ -1239,8 +930,8 @@
new_uuc = (fcc_uah * chip->prev_pc_unusable) / 100;
/* also find update the iavg_ma accordingly */
- new_unusable_mv = interpolate_ocv(chip, batt_temp_degc,
- chip->prev_pc_unusable);
+ new_unusable_mv = interpolate_ocv(chip->pc_temp_ocv_lut,
+ batt_temp_degc, chip->prev_pc_unusable);
if (new_unusable_mv < chip->v_cutoff)
new_unusable_mv = chip->v_cutoff;
@@ -1343,7 +1034,7 @@
* samples with the the shutdown_iavg_ua
*/
if (firsttime && chip->shutdown_iavg_ua != 0) {
- pr_emerg("Using shutdown_iavg_ua = %d in all samples\n",
+ pr_debug("Using shutdown_iavg_ua = %d in all samples\n",
chip->shutdown_iavg_ua);
for (i = 0; i < IAVG_SAMPLES; i++)
iavg_samples[i] = chip->shutdown_iavg_ua;
@@ -1531,11 +1222,11 @@
pc = DIV_ROUND_CLOSEST((int)rc * 100, fcc_uah);
pc = clamp(pc, 0, 100);
- ocv = interpolate_ocv(chip, batt_temp_degc, pc);
+ ocv = interpolate_ocv(chip->pc_temp_ocv_lut, batt_temp_degc, pc);
pr_debug("s_soc = %d, fcc = %d uuc = %d rc = %d, pc = %d, ocv mv = %d\n",
shutdown_soc, fcc_uah, uuc_uah, (int)rc, pc, ocv);
- new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+ new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv);
pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
while (abs(new_pc - pc) > 1) {
@@ -1545,7 +1236,8 @@
delta_mv = -1 * delta_mv;
ocv = ocv + delta_mv;
- new_pc = interpolate_pc(chip, batt_temp_degc, ocv);
+ new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+ batt_temp_degc, ocv);
pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
}
@@ -1650,6 +1342,28 @@
return chip->prev_chg_soc;
}
+static void very_low_voltage_check(struct pm8921_bms_chip *chip,
+ int ibat_ua, int vbat_uv)
+{
+ /*
+ * if battery is very low (v_cutoff voltage + 20mv) hold
+ * a wakelock untill soc = 0%
+ */
+ if (vbat_uv <= (chip->v_cutoff + 20) * 1000
+ && !chip->low_voltage_wake_lock_held) {
+ pr_debug("voltage = %d low holding wakelock\n", vbat_uv);
+ wake_lock(&chip->low_voltage_wake_lock);
+ chip->low_voltage_wake_lock_held = 1;
+ }
+
+ if (vbat_uv > (chip->v_cutoff + 20) * 1000
+ && chip->low_voltage_wake_lock_held) {
+ pr_debug("voltage = %d releasing wakelock\n", vbat_uv);
+ chip->low_voltage_wake_lock_held = 0;
+ wake_unlock(&chip->low_voltage_wake_lock);
+ }
+}
+
static int last_soc_est = -EINVAL;
static int adjust_soc(struct pm8921_bms_chip *chip, int soc,
int batt_temp, int chargecycles,
@@ -1674,6 +1388,7 @@
goto out;
}
+ very_low_voltage_check(chip, ibat_ua, vbat_uv);
delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
@@ -2639,12 +2354,6 @@
return IRQ_HANDLED;
}
-static irqreturn_t pm8921_bms_vsense_avg_handler(int irq, void *data)
-{
- pr_debug("irq = %d triggered", irq);
- return IRQ_HANDLED;
-}
-
struct pm_bms_irq_init_data {
unsigned int irq_id;
char *name;
@@ -2673,8 +2382,6 @@
pm8921_bms_ocv_for_r_handler),
BMS_IRQ(PM8921_BMS_GOOD_OCV, IRQF_TRIGGER_RISING,
pm8921_bms_good_ocv_handler),
- BMS_IRQ(PM8921_BMS_VSENSE_AVG, IRQF_TRIGGER_RISING,
- pm8921_bms_vsense_avg_handler),
};
static void free_irqs(struct pm8921_bms_chip *chip)
@@ -3228,6 +2935,9 @@
goto free_chip;
}
+ wake_lock_init(&chip->low_voltage_wake_lock,
+ WAKE_LOCK_SUSPEND, "pm8921_bms_low");
+
rc = pm8921_bms_hw_init(chip);
if (rc) {
pr_err("couldn't init hardware rc = %d\n", rc);
@@ -3285,12 +2995,33 @@
return 0;
}
+static int pm8921_bms_resume(struct device *dev)
+{
+ int rc, ibat_ua, vbat_uv;
+
+ rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
+ &ibat_ua,
+ &vbat_uv);
+ if (rc < 0) {
+ pr_err("simultaneous vbat ibat failed err = %d\n", rc);
+ return 0;
+ }
+
+ very_low_voltage_check(the_chip, ibat_ua, vbat_uv);
+ return 0;
+}
+
+static const struct dev_pm_ops pm8921_bms_pm_ops = {
+ .resume = pm8921_bms_resume,
+};
+
static struct platform_driver pm8921_bms_driver = {
.probe = pm8921_bms_probe,
.remove = __devexit_p(pm8921_bms_remove),
.driver = {
.name = PM8921_BMS_DEV_NAME,
.owner = THIS_MODULE,
+ .pm = &pm8921_bms_pm_ops,
},
};
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index e4e0004..b4080df 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -27,6 +27,7 @@
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
+#include <linux/mfd/pm8xxx/batt-alarm.h>
#include <mach/msm_xo.h>
#include <mach/msm_hsusb.h>
@@ -115,6 +116,13 @@
int batt_state;
};
+static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
+ unsigned long status, void *unused);
+
+static struct notifier_block alarm_notifier = {
+ .notifier_call = pm8921_battery_gauge_alarm_notify,
+};
+
static struct fsm_state_to_batt_status map[] = {
{FSM_STATE_OFF_0, POWER_SUPPLY_STATUS_UNKNOWN},
{FSM_STATE_BATFETDET_START_12, POWER_SUPPLY_STATUS_UNKNOWN},
@@ -205,6 +213,8 @@
* @max_voltage_mv: the max volts the batt should be charged up to
* @min_voltage_mv: the min battery voltage before turning the FETon
* @uvd_voltage_mv: (PM8917 only) the falling UVD threshold voltage
+ * @alarm_low_mv: the battery alarm voltage low
+ * @alarm_high_mv: the battery alarm voltage high
* @cool_temp_dc: the cool temp threshold in deciCelcius
* @warm_temp_dc: the warm temp threshold in deciCelcius
* @resume_voltage_delta: the voltage delta from vdd max at which the
@@ -225,6 +235,8 @@
unsigned int max_voltage_mv;
unsigned int min_voltage_mv;
unsigned int uvd_voltage_mv;
+ unsigned int alarm_low_mv;
+ unsigned int alarm_high_mv;
int cool_temp_dc;
int warm_temp_dc;
unsigned int temp_check_period;
@@ -250,6 +262,7 @@
bool ext_charge_done;
bool iusb_fine_res;
bool dc_unplug_check;
+ bool disable_hw_clock_switching;
DECLARE_BITMAP(enabled_irqs, PM_CHG_MAX_INTS);
struct work_struct battery_id_valid_work;
int64_t batt_id_min;
@@ -2003,6 +2016,73 @@
return get_prop_batt_temp(the_chip);
}
+static int pm8921_charger_enable_batt_alarm(struct pm8921_chg_chip *chip)
+{
+ int rc = 0;
+
+ rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_enable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+ if (rc) {
+ pr_err("unable to set batt alarm state rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+static int pm8921_charger_configure_batt_alarm(struct pm8921_chg_chip *chip)
+{
+ int rc = 0;
+
+ rc = pm8xxx_batt_alarm_disable(PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+ if (rc) {
+ pr_err("unable to set batt alarm state rc=%d\n", rc);
+ return rc;
+ }
+
+ /*
+ * The batt-alarm driver requires sane values for both min / max,
+ * regardless of whether they're both activated.
+ */
+ rc = pm8xxx_batt_alarm_threshold_set(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR,
+ chip->alarm_low_mv);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_threshold_set(
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR,
+ chip->alarm_high_mv);
+ if (rc) {
+ pr_err("unable to set batt alarm threshold rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_batt_alarm_hold_time_set(
+ PM8XXX_BATT_ALARM_HOLD_TIME_16_MS);
+ if (rc) {
+ pr_err("unable to set batt alarm hold time rc=%d\n", rc);
+ return rc;
+ }
+
+ /* PWM enabled at 2Hz */
+ rc = pm8xxx_batt_alarm_pwm_rate_set(1, 7, 4);
+ if (rc) {
+ pr_err("unable to set batt alarm pwm rate rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_batt_alarm_register_notifier(&alarm_notifier);
+ if (rc) {
+ pr_err("unable to register alarm notifier rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
static void handle_usb_insertion_removal(struct pm8921_chg_chip *chip)
{
int usb_present;
@@ -2138,6 +2218,61 @@
}
}
+static int pm8921_battery_gauge_alarm_notify(struct notifier_block *nb,
+ unsigned long status, void *unused)
+{
+ int rc;
+
+ pr_info("status: %lu\n", status);
+
+ /* Check if called before init */
+
+ switch (status) {
+ case 0:
+ pr_err("spurious interrupt\n");
+ break;
+ /* expected case - trip of low threshold */
+ case 1:
+ if (!the_chip) {
+ pr_err("not initialized\n");
+ return -EINVAL;
+ }
+
+ the_chip->disable_hw_clock_switching = 1;
+
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_enable(
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (rc)
+ pr_err("unable to set alarm state rc=%d\n", rc);
+ break;
+ case 2:
+ if (!the_chip) {
+ pr_err("not initialized\n");
+ return -EINVAL;
+ }
+
+ the_chip->disable_hw_clock_switching = 0;
+
+ rc = pm8xxx_batt_alarm_disable(
+ PM8XXX_BATT_ALARM_UPPER_COMPARATOR);
+ if (!rc)
+ rc = pm8xxx_batt_alarm_enable(
+ PM8XXX_BATT_ALARM_LOWER_COMPARATOR);
+ if (rc)
+ pr_err("unable to set alarm state rc=%d\n", rc);
+
+ pr_err("trip of high threshold\n");
+ break;
+ default:
+ pr_err("error received\n");
+ };
+
+ return 0;
+}
+
static void turn_on_ovp_fet(struct pm8921_chg_chip *chip, u16 ovptestreg)
{
u8 temp;
@@ -2308,12 +2443,6 @@
return IRQ_HANDLED;
}
-static irqreturn_t usbin_ov_irq_handler(int irq, void *data)
-{
- pr_err("USB OverVoltage\n");
- return IRQ_HANDLED;
-}
-
static irqreturn_t batt_inserted_irq_handler(int irq, void *data)
{
struct pm8921_chg_chip *chip = data;
@@ -2358,12 +2487,6 @@
return IRQ_HANDLED;
}
-static irqreturn_t usbin_uv_irq_handler(int irq, void *data)
-{
- pr_err("USB UnderVoltage\n");
- return IRQ_HANDLED;
-}
-
static irqreturn_t vbat_ov_irq_handler(int irq, void *data)
{
pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
@@ -2498,6 +2621,11 @@
pr_debug("USB charger active\n");
pm_chg_iusbmax_get(chip, &usb_ma);
+ if (usb_ma == 500 && !usb_target_ma) {
+ pr_debug("Stopping Unplug Check Worker USB == 500mA\n");
+ disable_input_voltage_regulation(chip);
+ return;
+ }
if (usb_ma <= 100) {
pr_debug(
@@ -3050,6 +3178,18 @@
return;
}
+ /* If the disable hw clock switching
+ * flag was set it can now be unset. Also, re-enable
+ * the battery alarm to set the flag again when needed
+ */
+ if (chip->disable_hw_clock_switching) {
+ /* Unset the hw clock switching flag */
+ chip->disable_hw_clock_switching = 0;
+
+ if (pm8921_charger_enable_batt_alarm(chip))
+ pr_err("couldn't set up batt alarm!\n");
+ }
+
if (end == CHG_FINISHED) {
count++;
} else {
@@ -3309,6 +3449,7 @@
{
unsigned long flags;
int fsm_state;
+ int is_fast_chg;
chip->dc_present = !!is_dc_chg_plugged_in(chip);
chip->usb_present = !!is_usb_chg_plugged_in(chip);
@@ -3325,8 +3466,6 @@
pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
- pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
- pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
@@ -3338,9 +3477,17 @@
if (usb_chg_current) {
/* reissue a vbus draw call */
__pm8921_charger_vbus_draw(usb_chg_current);
- fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
}
spin_unlock_irqrestore(&vbus_lock, flags);
+ /*
+ * The bootloader could have started charging, a fastchg interrupt
+ * might not happen. Check the real time status and if it is fast
+ * charging invoke the handler so that the eoc worker could be
+ * started
+ */
+ is_fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
+ if (is_fast_chg)
+ fastchg_irq_handler(chip->pmic_chg_irq[FASTCHG_IRQ], chip);
fsm_state = pm_chg_get_fsm_state(chip);
if (is_battery_charging(fsm_state)) {
@@ -3374,13 +3521,10 @@
struct pm_chg_irq_init_data chg_irq_data[] = {
CHG_IRQ(USBIN_VALID_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
usbin_valid_irq_handler),
- CHG_IRQ(USBIN_OV_IRQ, IRQF_TRIGGER_RISING, usbin_ov_irq_handler),
CHG_IRQ(BATT_INSERTED_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
batt_inserted_irq_handler),
CHG_IRQ(VBATDET_LOW_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
vbatdet_low_irq_handler),
- CHG_IRQ(USBIN_UV_IRQ, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- usbin_uv_irq_handler),
CHG_IRQ(VBAT_OV_IRQ, IRQF_TRIGGER_RISING, vbat_ov_irq_handler),
CHG_IRQ(CHGWDOG_IRQ, IRQF_TRIGGER_RISING, chgwdog_irq_handler),
CHG_IRQ(VCP_IRQ, IRQF_TRIGGER_RISING, vcp_irq_handler),
@@ -3961,7 +4105,8 @@
rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON, 0);
if (rc)
pr_err("Failed to Force Vref therm off rc=%d\n", rc);
- pm8921_chg_set_hw_clk_switching(chip);
+ if (!(chip->disable_hw_clock_switching))
+ pm8921_chg_set_hw_clk_switching(chip);
return 0;
}
@@ -4044,6 +4189,8 @@
chip->ttrkl_time = pdata->ttrkl_time;
chip->update_time = pdata->update_time;
chip->max_voltage_mv = pdata->max_voltage;
+ chip->alarm_low_mv = pdata->alarm_low_mv;
+ chip->alarm_high_mv = pdata->alarm_high_mv;
chip->min_voltage_mv = pdata->min_voltage;
chip->uvd_voltage_mv = pdata->uvd_thresh_voltage;
chip->resume_voltage_delta = pdata->resume_voltage_delta;
@@ -4149,8 +4296,6 @@
enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[DCIN_VALID_IRQ]);
- enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
- enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
@@ -4166,6 +4311,17 @@
}
}
+ rc = pm8921_charger_configure_batt_alarm(chip);
+ if (rc) {
+ pr_err("Couldn't configure battery alarm! rc=%d\n", rc);
+ goto free_irq;
+ }
+
+ rc = pm8921_charger_enable_batt_alarm(chip);
+ if (rc) {
+ pr_err("Couldn't enable battery alarm! rc=%d\n", rc);
+ goto free_irq;
+ }
create_debugfs_entries(chip);
INIT_WORK(&chip->bms_notify.work, bms_notify);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
new file mode 100644
index 0000000..dda8976
--- /dev/null
+++ b/drivers/power/qpnp-charger.c
@@ -0,0 +1,1259 @@
+/* Copyright (c) 2012 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/spmi.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/radix-tree.h>
+#include <linux/interrupt.h>
+#include <linux/qpnp/qpnp-adc.h>
+#include <linux/power_supply.h>
+#include <linux/bitops.h>
+
+/* Interrupt offsets */
+#define INT_RT_STS(base) (base + 0x10)
+#define INT_SET_TYPE(base) (base + 0x11)
+#define INT_POLARITY_HIGH(base) (base + 0x12)
+#define INT_POLARITY_LOW(base) (base + 0x13)
+#define INT_LATCHED_CLR(base) (base + 0x14)
+#define INT_EN_SET(base) (base + 0x15)
+#define INT_EN_CLR(base) (base + 0x16)
+#define INT_LATCHED_STS(base) (base + 0x18)
+#define INT_PENDING_STS(base) (base + 0x19)
+#define INT_MID_SEL(base) (base + 0x1A)
+#define INT_PRIORITY(base) (base + 0x1B)
+
+/* Peripheral register offsets */
+#define CHGR_CHG_OPTION 0x08
+#define CHGR_ATC_STATUS 0x0A
+#define CHGR_VBAT_STATUS 0x0B
+#define CHGR_IBAT_BMS 0x0C
+#define CHGR_IBAT_STS 0x0D
+#define CHGR_VDD_MAX 0x40
+#define CHGR_VDD_SAFE 0x41
+#define CHGR_VDD_MAX_STEP 0x42
+#define CHGR_IBAT_MAX 0x44
+#define CHGR_IBAT_SAFE 0x45
+#define CHGR_VIN_MIN 0x47
+#define CHGR_VIN_MIN_STEP 0x48
+#define CHGR_CHG_CTRL 0x49
+#define CHGR_CHG_FAILED 0x4A
+#define CHGR_ATC_CTRL 0x4B
+#define CHGR_ATC_FAILED 0x4C
+#define CHGR_VBAT_TRKL 0x50
+#define CHGR_VBAT_WEAK 0x52
+#define CHGR_IBAT_ATC_A 0x54
+#define CHGR_IBAT_ATC_B 0x55
+#define CHGR_IBAT_TERM_CHGR 0x5B
+#define CHGR_IBAT_TERM_BMS 0x5C
+#define CHGR_VBAT_DET 0x5D
+#define CHGR_TTRKL_MAX 0x5F
+#define CHGR_TTRKL_MAX_EN 0x60
+#define CHGR_TCHG_MAX 0x61
+#define CHGR_CHG_WDOG_TIME 0x62
+#define CHGR_CHG_WDOG_DLY 0x63
+#define CHGR_CHG_WDOG_PET 0x64
+#define CHGR_CHG_WDOG_EN 0x65
+#define CHGR_USB_IUSB_MAX 0x44
+#define CHGR_USB_ENUM_T_STOP 0x4E
+#define CHGR_CHG_TEMP_THRESH 0x66
+#define CHGR_BAT_IF_PRES_STATUS 0x08
+#define CHGR_BAT_TEMP_STATUS 0x09
+#define CHGR_BAT_IF_VCP 0x42
+#define CHGR_BAT_IF_BATFET_CTRL1 0x90
+#define CHGR_MISC_BOOT_DONE 0x42
+#define MISC_REVISION2 0x01
+
+/* SMBB peripheral subtype values */
+#define REG_OFFSET_PERP_SUBTYPE 0x05
+#define SMBB_CHGR_SUBTYPE 0x01
+#define SMBB_BUCK_SUBTYPE 0x02
+#define SMBB_BAT_IF_SUBTYPE 0x03
+#define SMBB_USB_CHGPTH_SUBTYPE 0x04
+#define SMBB_DC_CHGPTH_SUBTYPE 0x05
+#define SMBB_BOOST_SUBTYPE 0x06
+#define SMBB_MISC_SUBTYPE 0x07
+
+#define QPNP_CHARGER_DEV_NAME "qcom,qpnp-charger"
+
+/* Interrupt definitions */
+/* smbb_chg_interrupts */
+#define CHG_DONE_IRQ BIT(7)
+#define CHG_FAILED_IRQ BIT(6)
+#define FAST_CHG_ON_IRQ BIT(5)
+#define TRKL_CHG_ON_IRQ BIT(4)
+#define STATE_CHANGE_ON_IR BIT(3)
+#define CHGWDDOG_IRQ BIT(2)
+#define VBAT_DET_HI_IRQ BIT(1)
+#define VBAT_DET_LOW_IRQ BIT(0)
+
+/* smbb_buck_interrupts */
+#define VDD_LOOP_IRQ BIT(6)
+#define IBAT_LOOP_IRQ BIT(5)
+#define ICHG_LOOP_IRQ BIT(4)
+#define VCHG_LOOP_IRQ BIT(3)
+#define OVERTEMP_IRQ BIT(2)
+#define VREF_OV_IRQ BIT(1)
+#define VBAT_OV_IRQ BIT(0)
+
+/* smbb_bat_if_interrupts */
+#define PSI_IRQ BIT(4)
+#define VCP_ON_IRQ BIT(3)
+#define BAT_FET_ON_IRQ BIT(2)
+#define BAT_TEMP_OK_IRQ BIT(1)
+#define BATT_PRES_IRQ BIT(0)
+
+/* smbb_usb_interrupts */
+#define CHG_GONE_IRQ BIT(2)
+#define USBIN_VALID_IRQ BIT(1)
+#define COARSE_DET_USB_IRQ BIT(0)
+
+/* smbb_dc_interrupts */
+#define DCIN_VALID_IRQ BIT(1)
+#define COARSE_DET_DC_IRQ BIT(0)
+
+/* smbb_boost_interrupts */
+#define LIMIT_ERROR_IRQ BIT(1)
+#define BOOST_PWR_OK_IRQ BIT(0)
+
+/* smbb_misc_interrupts */
+#define TFTWDOG_IRQ BIT(0)
+
+/**
+ * struct qpnp_chg_chip - device information
+ * @dev: device pointer to access the parent
+ * @spmi: spmi pointer to access spmi information
+ * @chgr_base: charger peripheral base address
+ * @buck_base: buck peripheral base address
+ * @bat_if_base: battery interface peripheral base address
+ * @usb_chgpth_base: USB charge path peripheral base address
+ * @dc_chgpth_base: DC charge path peripheral base address
+ * @boost_base: boost peripheral base address
+ * @misc_base: misc peripheral base address
+ * @freq_base: freq peripheral base address
+ * @chg_done: indicates that charging is completed
+ * @usb_present: present status of usb
+ * @dc_present: present status of dc
+ * @max_voltage_mv: the max volts the batt should be charged up to
+ * @min_voltage_mv: the min battery voltage before turning the FETon
+ * @term_current: the charging based term current
+ * @revision: PMIC revision
+ * @dc_psy power supply to export information to userspace
+ * @usb_psy power supply to export information to userspace
+ * @bms_psy power supply to export information to userspace
+ * @batt_psy: power supply to export information to userspace
+ *
+ */
+struct qpnp_chg_chip {
+ struct device *dev;
+ struct spmi_device *spmi;
+ u16 chgr_base;
+ u16 buck_base;
+ u16 bat_if_base;
+ u16 usb_chgpth_base;
+ u16 dc_chgpth_base;
+ u16 boost_base;
+ u16 misc_base;
+ u16 freq_base;
+ unsigned int usbin_valid_irq;
+ unsigned int chg_done_irq;
+ unsigned int chg_failed_irq;
+ bool chg_done;
+ bool usb_present;
+ bool dc_present;
+ unsigned int max_bat_chg_current;
+ unsigned int safe_voltage_mv;
+ unsigned int max_voltage_mv;
+ unsigned int min_voltage_mv;
+ unsigned int term_current;
+ unsigned int revision;
+ struct power_supply dc_psy;
+ struct power_supply *usb_psy;
+ struct power_supply *bms_psy;
+ struct power_supply batt_psy;
+};
+
+static struct qpnp_chg_chip *the_chip;
+static int charging_disabled;
+
+static struct of_device_id qpnp_charger_match_table[] = {
+ { .compatible = QPNP_CHARGER_DEV_NAME, },
+ {}
+};
+
+static int
+qpnp_chg_read(struct qpnp_chg_chip *chip, u8 *val,
+ u16 base, int count)
+{
+ int rc;
+ struct spmi_device *spmi = chip->spmi;
+
+ rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, base, val,
+ count);
+ if (rc) {
+ pr_err("SPMI read failed base=0x%02x sid=0x%02x rc=%d\n", base,
+ spmi->sid, rc);
+ return rc;
+ }
+ return 0;
+}
+
+static int
+qpnp_chg_write(struct qpnp_chg_chip *chip, u8 *val,
+ u16 base, int count)
+{
+ int rc;
+ struct spmi_device *spmi = chip->spmi;
+
+ rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, base, val,
+ count);
+ if (rc) {
+ pr_err("write failed base=0x%02x sid=0x%02x rc=%d\n",
+ base, spmi->sid, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int
+qpnp_chg_masked_write(struct qpnp_chg_chip *chip, u16 base,
+ u8 mask, u8 val, int count)
+{
+ int rc;
+ u8 reg;
+
+ rc = qpnp_chg_read(chip, ®, base, count);
+ if (rc) {
+ pr_err("spmi read failed: addr=%03X, rc=%d\n", base, rc);
+ return rc;
+ }
+ pr_debug("addr = 0x%x read 0x%x\n", base, reg);
+
+ reg &= ~mask;
+ reg |= val & mask;
+
+ pr_debug("Writing 0x%x\n", reg);
+
+ rc = qpnp_chg_write(chip, ®, base, count);
+ if (rc) {
+ pr_err("spmi write failed: addr=%03X, rc=%d\n", base, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int
+qpnp_chg_is_usb_chg_plugged_in(struct qpnp_chg_chip *chip)
+{
+ u8 usbin_valid_rt_sts;
+ int rc;
+
+ rc = qpnp_chg_read(chip, &usbin_valid_rt_sts,
+ INT_RT_STS(chip->usb_chgpth_base), 1);
+
+ if (rc) {
+ pr_err("spmi read failed: addr=%03X, rc=%d\n",
+ INT_RT_STS(chip->usb_chgpth_base), rc);
+ return rc;
+ }
+ pr_debug("chgr usb sts 0x%x\n", usbin_valid_rt_sts);
+
+ return (usbin_valid_rt_sts & USBIN_VALID_IRQ) ? 1 : 0;
+}
+
+static int
+qpnp_chg_is_dc_chg_plugged_in(struct qpnp_chg_chip *chip)
+{
+ u8 dcin_valid_rt_sts;
+ int rc;
+
+ rc = qpnp_chg_read(chip, &dcin_valid_rt_sts,
+ INT_RT_STS(chip->dc_chgpth_base), 1);
+ if (rc) {
+ pr_err("spmi read failed: addr=%03X, rc=%d\n",
+ INT_RT_STS(chip->dc_chgpth_base), rc);
+ return rc;
+ }
+
+ return (dcin_valid_rt_sts & DCIN_VALID_IRQ) ? 1 : 0;
+}
+
+#define VCP_IUSBMAX_SETTING_MA 2000
+#define QPNP_CHG_IUSB_MAX_MIN_100 100
+#define QPNP_CHG_IUSB_MAX_MIN_150 150
+#define QPNP_CHG_IUSB_MAX_MIN_MA 200
+#define QPNP_CHG_IUSB_MAX_MAX_MA 2500
+#define QPNP_CHG_IUSB_MAX_STEP_MA 100
+static int
+qpnp_chg_iusbmax_set(struct qpnp_chg_chip *chip, int mA)
+{
+ u8 usb_reg = 0;
+
+ if (mA == QPNP_CHG_IUSB_MAX_MIN_100) {
+ usb_reg = 0x00;
+ pr_debug("current=%d setting %02x\n", mA, usb_reg);
+ return qpnp_chg_write(chip, &usb_reg,
+ chip->usb_chgpth_base + CHGR_USB_IUSB_MAX, 1);
+ } else if (mA == QPNP_CHG_IUSB_MAX_MIN_150) {
+ usb_reg = 0x01;
+ pr_debug("current=%d setting %02x\n", mA, usb_reg);
+ return qpnp_chg_write(chip, &usb_reg,
+ chip->usb_chgpth_base + CHGR_USB_IUSB_MAX, 1);
+ }
+
+ if (mA < QPNP_CHG_IUSB_MAX_MIN_MA
+ || mA > QPNP_CHG_IUSB_MAX_MAX_MA) {
+ pr_err("bad mA=%d asked to set\n", mA);
+ return -EINVAL;
+ }
+
+ /* Hack for VCP issue make sure IUSBMAX setting
+ * is at least 2 A to not brown out device */
+ mA = VCP_IUSBMAX_SETTING_MA;
+
+ usb_reg = mA / QPNP_CHG_IUSB_MAX_STEP_MA;
+
+ pr_debug("current=%d setting 0x%x\n", mA, usb_reg);
+ return qpnp_chg_write(chip, &usb_reg,
+ chip->usb_chgpth_base + CHGR_USB_IUSB_MAX, 1);
+ pr_debug("done\n");
+ return 0;
+}
+
+#define ENUM_T_STOP_BIT BIT(0)
+static irqreturn_t
+qpnp_chg_usb_usbin_valid_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+ int usb_present;
+
+ usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
+ pr_debug("usbin-valid triggered: %d\n", usb_present);
+
+ if (chip->usb_present ^ usb_present) {
+ chip->usb_present = usb_present;
+ power_supply_set_present(chip->usb_psy,
+ chip->usb_present);
+ } else if (!(chip->usb_present && usb_present)) {
+ qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + CHGR_USB_ENUM_T_STOP,
+ ENUM_T_STOP_BIT,
+ ENUM_T_STOP_BIT, 1);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#define CHGR_CHG_FAILED_BIT BIT(7)
+static irqreturn_t
+qpnp_chg_chgr_chg_failed_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+ int rc, usb_present;
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + CHGR_CHG_FAILED,
+ CHGR_CHG_FAILED_BIT,
+ CHGR_CHG_FAILED_BIT, 1);
+ if (rc)
+ pr_err("Failed to write chg_fail clear bit!\n");
+
+ /* Hack: recheck usbin_valid status after chg_fail triggered */
+ usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
+ pr_debug("usb_status: %d\n", usb_present);
+ if (usb_present)
+ qpnp_chg_usb_usbin_valid_irq_handler(chip->usbin_valid_irq,
+ _chip);
+
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+qpnp_chg_chgr_chg_done_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+
+ pr_debug("CHG_DONE IRQ triggered\n");
+ chip->chg_done = true;
+
+ return IRQ_HANDLED;
+}
+
+static enum power_supply_property pm_power_props_mains[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static enum power_supply_property msm_batt_power_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_TEMP,
+};
+
+static char *pm_power_supplied_to[] = {
+ "battery",
+};
+
+#define USB_WALL_THRESHOLD_MA 500
+static int
+qpnp_power_get_property_mains(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct qpnp_chg_chip *chip = container_of(psy, struct qpnp_chg_chip,
+ dc_psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = 0;
+ if (charging_disabled)
+ return 0;
+
+ val->intval = qpnp_chg_is_dc_chg_plugged_in(chip);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int
+get_prop_battery_voltage_now(struct qpnp_chg_chip *chip)
+{
+ int rc = 0;
+ struct qpnp_vadc_result results;
+
+ if (chip->revision > 0) {
+ rc = qpnp_vadc_read(VBAT_SNS, &results);
+ if (rc) {
+ pr_err("Unable to read vbat rc=%d\n", rc);
+ return 0;
+ }
+ return results.physical;
+ } else {
+ pr_err("vbat reading not supported for 1.0 rc=%d\n", rc);
+ return 0;
+ }
+}
+
+#define BATT_PRES_BIT BIT(7)
+static int
+get_prop_batt_present(struct qpnp_chg_chip *chip)
+{
+ u8 batt_present;
+ int rc;
+
+ rc = qpnp_chg_read(chip, &batt_present,
+ chip->bat_if_base + CHGR_BAT_IF_PRES_STATUS, 1);
+ if (rc) {
+ pr_err("Couldn't read battery status read failed rc=%d\n", rc);
+ return 0;
+ };
+ return (batt_present & BATT_PRES_BIT) ? 1 : 0;
+}
+
+#define BATT_TEMP_HOT BIT(6)
+#define BATT_TEMP_OK BIT(7)
+static int
+get_prop_batt_health(struct qpnp_chg_chip *chip)
+{
+ u8 batt_health;
+ int rc;
+
+ rc = qpnp_chg_read(chip, &batt_health,
+ chip->bat_if_base + CHGR_BAT_TEMP_STATUS, 1);
+ if (rc) {
+ pr_err("Couldn't read battery health read failed rc=%d\n", rc);
+ return POWER_SUPPLY_HEALTH_UNKNOWN;
+ };
+
+ if (BATT_TEMP_OK & batt_health)
+ return POWER_SUPPLY_HEALTH_GOOD;
+ if (BATT_TEMP_HOT & batt_health)
+ return POWER_SUPPLY_HEALTH_OVERHEAT;
+ else
+ return POWER_SUPPLY_HEALTH_COLD;
+}
+
+static int
+get_prop_charge_type(struct qpnp_chg_chip *chip)
+{
+ int rc;
+ u8 chgr_sts;
+
+ if (!get_prop_batt_present(chip))
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+
+ 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;
+ }
+
+ if (chgr_sts & TRKL_CHG_ON_IRQ)
+ return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ if (chgr_sts & FAST_CHG_ON_IRQ)
+ return POWER_SUPPLY_CHARGE_TYPE_FAST;
+
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+}
+
+static int
+get_prop_batt_status(struct qpnp_chg_chip *chip)
+{
+ int rc;
+ u8 chgr_sts;
+
+ 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_STATUS_DISCHARGING;
+ }
+
+ pr_debug("chgr sts 0x%x\n", chgr_sts);
+ if (chgr_sts & CHG_DONE_IRQ || chip->chg_done)
+ return POWER_SUPPLY_STATUS_FULL;
+ else
+ chip->chg_done = false;
+
+ if (chgr_sts & TRKL_CHG_ON_IRQ)
+ return POWER_SUPPLY_STATUS_CHARGING;
+ if (chgr_sts & FAST_CHG_ON_IRQ)
+ return POWER_SUPPLY_STATUS_CHARGING;
+
+ return POWER_SUPPLY_STATUS_DISCHARGING;
+}
+
+static int
+get_prop_current_now(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_NOW, &ret);
+ return ret.intval;
+ } else {
+ pr_debug("No BMS supply registered return 0\n");
+ }
+
+ return 0;
+}
+
+static int
+get_prop_full_design(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_CHARGE_FULL_DESIGN, &ret);
+ return ret.intval;
+ } else {
+ pr_debug("No BMS supply registered return 0\n");
+ }
+
+ return 0;
+}
+
+#define DEFAULT_CAPACITY 50
+static int
+get_prop_capacity(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_CAPACITY, &ret);
+ return ret.intval;
+ } else {
+ pr_debug("No BMS supply registered return 50\n");
+ }
+
+ /* return default capacity to avoid userspace
+ * from shutting down unecessarily */
+ return DEFAULT_CAPACITY;
+}
+
+#define DEFAULT_TEMP 25
+#define MAX_TOLERABLE_BATT_TEMP_DDC 680
+static int
+get_prop_batt_temp(struct qpnp_chg_chip *chip)
+{
+ int rc = 0;
+ struct qpnp_vadc_result results;
+
+ if (chip->revision > 0) {
+ rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &results);
+ if (rc) {
+ pr_debug("Unable to read batt temperature rc=%d\n", rc);
+ return 0;
+ }
+ pr_debug("get_bat_temp %d %lld\n",
+ results.adc_code, results.physical);
+ return (int)results.physical;
+ } else {
+ pr_debug("batt temp not supported for PMIC 1.0 rc=%d\n", rc);
+ }
+
+ /* return default temperature to avoid userspace
+ * from shutting down unecessarily */
+ return DEFAULT_TEMP;
+}
+
+static void
+qpnp_batt_external_power_changed(struct power_supply *psy)
+{
+ struct qpnp_chg_chip *chip = container_of(psy, struct qpnp_chg_chip,
+ batt_psy);
+ union power_supply_propval ret = {0,};
+
+ if (!chip->bms_psy)
+ chip->bms_psy = power_supply_get_by_name("bms");
+
+ chip->usb_psy->get_property(chip->usb_psy,
+ POWER_SUPPLY_PROP_ONLINE, &ret);
+
+ if (ret.intval && qpnp_chg_is_usb_chg_plugged_in(chip)) {
+ chip->usb_psy->get_property(chip->usb_psy,
+ POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
+ qpnp_chg_iusbmax_set(chip, ret.intval / 1000);
+ } else {
+ qpnp_chg_iusbmax_set(chip, QPNP_CHG_IUSB_MAX_MIN_MA);
+ }
+
+ pr_debug("end of power supply changed\n");
+ power_supply_changed(&chip->batt_psy);
+}
+
+static int
+qpnp_batt_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct qpnp_chg_chip *chip = container_of(psy, struct qpnp_chg_chip,
+ batt_psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = get_prop_batt_status(chip);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ val->intval = get_prop_charge_type(chip);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = get_prop_batt_health(chip);
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = get_prop_batt_present(chip);
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ val->intval = chip->max_voltage_mv * 1000;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ val->intval = chip->min_voltage_mv * 1000;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = get_prop_battery_voltage_now(chip);
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = get_prop_batt_temp(chip);
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = get_prop_capacity(chip);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = get_prop_current_now(chip);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ val->intval = get_prop_full_design(chip);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#define CHGR_BOOT_DONE BIT(7)
+#define CHGR_CHG_EN BIT(7)
+#define CHGR_ON_BAT_FORCE_BIT BIT(0)
+#define CHGR_BAT_IF_CONST_RDS_EN BIT(7)
+#define CHGR_BAT_IF_VCP_EN BIT(0)
+static int
+qpnp_chg_charge_dis(struct qpnp_chg_chip *chip, int disable)
+{
+ /* This bit forces the charger to run off of the battery rather
+ * than a connected charger */
+ return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
+ CHGR_ON_BAT_FORCE_BIT,
+ disable ? CHGR_ON_BAT_FORCE_BIT : 0, 1);
+}
+
+static int
+qpnp_chg_charge_en(struct qpnp_chg_chip *chip, int enable)
+{
+ return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_CHG_CTRL,
+ CHGR_CHG_EN,
+ enable ? CHGR_CHG_EN : 0, 1);
+}
+
+static int
+qpnp_chg_set_disable_status_param(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct qpnp_chg_chip *chip = the_chip;
+
+ ret = param_set_int(val, kp);
+ if (ret) {
+ pr_err("error setting value %d\n", ret);
+ return ret;
+ }
+ pr_info("factory set disable param to %d\n", charging_disabled);
+ if (chip)
+ qpnp_chg_charge_dis(chip, charging_disabled);
+ return 0;
+}
+module_param_call(disabled, qpnp_chg_set_disable_status_param, param_get_uint,
+ &charging_disabled, 0644);
+
+#define QPNP_CHG_VINMIN_MIN_MV 3400
+#define QPNP_CHG_VINMIN_HIGH_MIN_MV 5600
+#define QPNP_CHG_VINMIN_HIGH_MIN_VAL 0x2B
+#define QPNP_CHG_VINMIN_MAX_MV 9600
+#define QPNP_CHG_VINMIN_STEP_MV 50
+#define QPNP_CHG_VINMIN_STEP_HIGH_MV 200
+#define QPNP_CHG_VINMIN_MASK 0x1F
+static int
+qpnp_chg_vinmin_set(struct qpnp_chg_chip *chip, int voltage)
+{
+ u8 temp;
+
+ if (voltage < QPNP_CHG_VINMIN_MIN_MV
+ || voltage > QPNP_CHG_VINMIN_MAX_MV) {
+ pr_err("bad mV=%d asked to set\n", voltage);
+ return -EINVAL;
+ }
+ if (voltage >= QPNP_CHG_VINMIN_HIGH_MIN_MV) {
+ temp = QPNP_CHG_VINMIN_HIGH_MIN_VAL;
+ temp += (voltage - QPNP_CHG_VINMIN_MIN_MV)
+ / QPNP_CHG_VINMIN_STEP_HIGH_MV;
+ } else {
+ temp = (voltage - QPNP_CHG_VINMIN_MIN_MV)
+ / QPNP_CHG_VINMIN_STEP_MV;
+ }
+
+ pr_debug("voltage=%d setting %02x\n", voltage, temp);
+ return qpnp_chg_masked_write(chip,
+ chip->chgr_base + CHGR_VIN_MIN,
+ QPNP_CHG_VINMIN_MASK, temp, 1);
+}
+
+
+#define QPNP_CHG_ITERM_MIN_MA 100
+#define QPNP_CHG_ITERM_MAX_MA 250
+#define QPNP_CHG_ITERM_STEP_MA 50
+#define QPNP_CHG_ITERM_MASK 0x03
+static int
+qpnp_chg_ibatterm_set(struct qpnp_chg_chip *chip, int term_current)
+{
+ u8 temp;
+
+ if (term_current < QPNP_CHG_ITERM_MIN_MA
+ || term_current > QPNP_CHG_ITERM_MAX_MA) {
+ pr_err("bad mA=%d asked to set\n", term_current);
+ return -EINVAL;
+ }
+
+ temp = (term_current - QPNP_CHG_ITERM_MIN_MA)
+ / QPNP_CHG_ITERM_STEP_MA;
+ return qpnp_chg_masked_write(chip,
+ chip->chgr_base + CHGR_IBAT_TERM_CHGR,
+ QPNP_CHG_ITERM_MASK, temp, 1);
+}
+
+#define QPNP_CHG_IBATMAX_MIN 100
+#define QPNP_CHG_IBATMAX_MAX 3250
+#define QPNP_CHG_I_STEP_MA 50
+#define QPNP_CHG_I_MIN_MA 100
+#define QPNP_CHG_I_MASK 0x3F
+static int
+qpnp_chg_ibatmax_set(struct qpnp_chg_chip *chip, int chg_current)
+{
+ u8 temp;
+
+ if (chg_current < QPNP_CHG_IBATMAX_MIN
+ || chg_current > QPNP_CHG_IBATMAX_MAX) {
+ pr_err("bad mA=%d asked to set\n", chg_current);
+ return -EINVAL;
+ }
+ temp = (chg_current - QPNP_CHG_I_MIN_MA) / QPNP_CHG_I_STEP_MA;
+ return qpnp_chg_masked_write(chip, chip->chgr_base + CHGR_IBAT_MAX,
+ QPNP_CHG_I_MASK, temp, 1);
+}
+
+
+#define QPNP_CHG_V_MIN_MV 3240
+#define QPNP_CHG_V_MAX_MV 4500
+#define QPNP_CHG_V_STEP_MV 10
+static int
+qpnp_chg_vddsafe_set(struct qpnp_chg_chip *chip, int voltage)
+{
+ u8 temp;
+
+ if (voltage < QPNP_CHG_V_MIN_MV
+ || voltage > QPNP_CHG_V_MAX_MV) {
+ pr_err("bad mV=%d asked to set\n", voltage);
+ return -EINVAL;
+ }
+ temp = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
+ pr_debug("voltage=%d setting %02x\n", voltage, temp);
+ return qpnp_chg_write(chip, &temp,
+ chip->chgr_base + CHGR_VDD_SAFE, 1);
+}
+
+#define QPNP_CHG_VDDMAX_MIN 3400
+static int
+qpnp_chg_vddmax_set(struct qpnp_chg_chip *chip, int voltage)
+{
+ u8 temp = 0;
+
+ if (voltage < QPNP_CHG_VDDMAX_MIN
+ || voltage > QPNP_CHG_V_MAX_MV) {
+ pr_err("bad mV=%d asked to set\n", voltage);
+ return -EINVAL;
+ }
+
+ temp = (voltage - QPNP_CHG_V_MIN_MV) / QPNP_CHG_V_STEP_MV;
+
+ pr_debug("voltage=%d setting %02x\n", voltage, temp);
+ return qpnp_chg_write(chip, &temp,
+ chip->chgr_base + CHGR_VDD_MAX, 1);
+}
+
+#define WDOG_EN_BIT BIT(7)
+static int
+qpnp_chg_hwinit(struct qpnp_chg_chip *chip, u8 subtype,
+ struct spmi_resource *spmi_resource)
+{
+ int rc = 0;
+ u8 reg;
+
+ switch (subtype) {
+ case SMBB_CHGR_SUBTYPE:
+ chip->chg_done_irq = spmi_get_irq_byname(chip->spmi,
+ spmi_resource, "chg-done");
+ if (chip->chg_done_irq < 0) {
+ pr_err("Unable to get chg_done irq\n");
+ return -ENXIO;
+ }
+
+ chip->chg_failed_irq = spmi_get_irq_byname(chip->spmi,
+ spmi_resource, "chg-failed");
+ if (chip->chg_failed_irq < 0) {
+ pr_err("Unable to get chg_failed irq\n");
+ return -ENXIO;
+ }
+ rc |= devm_request_irq(chip->dev, chip->chg_done_irq,
+ qpnp_chg_chgr_chg_done_irq_handler,
+ IRQF_TRIGGER_RISING, "chg_done", chip);
+ if (rc < 0) {
+ pr_err("Can't request %d chg_done for chg: %d\n",
+ chip->chg_done_irq, rc);
+ return -ENXIO;
+ }
+ 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 chg: %d\n",
+ chip->chg_failed_irq, rc);
+ return -ENXIO;
+ }
+
+ rc = qpnp_chg_vinmin_set(chip, chip->min_voltage_mv);
+ if (rc) {
+ pr_debug("failed setting min_voltage rc=%d\n", rc);
+ return rc;
+ }
+ rc = qpnp_chg_vddmax_set(chip, chip->max_voltage_mv);
+ if (rc) {
+ pr_debug("failed setting max_voltage rc=%d\n", rc);
+ return rc;
+ }
+ rc = qpnp_chg_vddsafe_set(chip, chip->safe_voltage_mv);
+ if (rc) {
+ pr_debug("failed setting safe_voltage rc=%d\n", rc);
+ return rc;
+ }
+ rc = qpnp_chg_ibatmax_set(chip, chip->max_bat_chg_current);
+ if (rc) {
+ pr_debug("failed setting ibatmax rc=%d\n", rc);
+ return rc;
+ }
+ rc = qpnp_chg_ibatterm_set(chip, chip->term_current);
+ if (rc) {
+ pr_debug("failed setting ibatterm rc=%d\n", rc);
+ return rc;
+ }
+ /* HACK: Disable wdog */
+ rc = qpnp_chg_masked_write(chip, chip->chgr_base + 0x62,
+ 0xFF, 0xA0, 1);
+
+ /* HACK: use analog EOC */
+ rc = qpnp_chg_masked_write(chip, chip->chgr_base +
+ CHGR_IBAT_TERM_CHGR,
+ 0x80, 0x80, 1);
+
+ enable_irq_wake(chip->chg_done_irq);
+ break;
+ case SMBB_BUCK_SUBTYPE:
+ break;
+ case SMBB_BAT_IF_SUBTYPE:
+ /* HACK: Unlock secure access to override temp comparator */
+ rc = qpnp_chg_masked_write(chip,
+ chip->bat_if_base + 0xD0,
+ 0xA5, 0xA5, 1);
+ pr_debug("override hot cold\n");
+ rc = qpnp_chg_masked_write(chip,
+ chip->bat_if_base + 0xE5,
+ 0xFF, 0x28, 1);
+ break;
+ case SMBB_USB_CHGPTH_SUBTYPE:
+ chip->usbin_valid_irq = spmi_get_irq_byname(chip->spmi,
+ spmi_resource, "usbin-valid");
+ if (chip->usbin_valid_irq < 0) {
+ pr_err("Unable to get usbin irq\n");
+ return -ENXIO;
+ }
+ rc = devm_request_irq(chip->dev, chip->usbin_valid_irq,
+ qpnp_chg_usb_usbin_valid_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "chg_usbin_valid", chip);
+ if (rc < 0) {
+ pr_err("Can't request %d usbinvalid for chg: %d\n",
+ chip->usbin_valid_irq, rc);
+ return -ENXIO;
+ }
+
+ enable_irq_wake(chip->usbin_valid_irq);
+ chip->usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
+ if (chip->usb_present) {
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + CHGR_USB_ENUM_T_STOP,
+ ENUM_T_STOP_BIT,
+ ENUM_T_STOP_BIT, 1);
+ if (rc) {
+ pr_err("failed to write enum stop rc=%d\n", rc);
+ return -ENXIO;
+ }
+ }
+ break;
+ case SMBB_DC_CHGPTH_SUBTYPE:
+ break;
+ case SMBB_BOOST_SUBTYPE:
+ break;
+ case SMBB_MISC_SUBTYPE:
+ pr_debug("Setting BOOT_DONE\n");
+ rc = qpnp_chg_masked_write(chip,
+ chip->misc_base + CHGR_MISC_BOOT_DONE,
+ CHGR_BOOT_DONE, CHGR_BOOT_DONE, 1);
+ rc = qpnp_chg_read(chip, ®,
+ chip->misc_base + MISC_REVISION2, 1);
+ if (rc) {
+ pr_err("failed to read revision register rc=%d\n", rc);
+ return rc;
+ }
+
+ chip->revision = reg;
+ break;
+ default:
+ pr_err("Invalid peripheral subtype\n");
+ }
+ return rc;
+}
+
+static int __devinit
+qpnp_charger_probe(struct spmi_device *spmi)
+{
+ u8 subtype;
+ struct qpnp_chg_chip *chip;
+ struct resource *resource;
+ struct spmi_resource *spmi_resource;
+ int rc = 0;
+
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ if (chip == NULL) {
+ pr_err("kzalloc() failed.\n");
+ return -ENOMEM;
+ }
+
+ rc = qpnp_vadc_is_ready();
+ if (rc)
+ goto fail_chg_enable;
+
+ chip->dev = &(spmi->dev);
+ chip->spmi = spmi;
+
+ chip->usb_psy = power_supply_get_by_name("usb");
+ if (!chip->usb_psy) {
+ pr_err("usb supply not found deferring probe\n");
+ rc = -EPROBE_DEFER;
+ goto fail_chg_enable;
+ }
+
+ /* Get the vddmax property */
+ rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vddmax-mv",
+ &chip->max_voltage_mv);
+ if (rc && rc != -EINVAL) {
+ pr_err("Error reading vddmax property %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ /* Get the vinmin property */
+ rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vinmin-mv",
+ &chip->min_voltage_mv);
+ if (rc && rc != -EINVAL) {
+ pr_err("Error reading vddmax property %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ /* Get the vddmax property */
+ rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-vddsafe-mv",
+ &chip->safe_voltage_mv);
+ if (rc && rc != -EINVAL) {
+ pr_err("Error reading vddsave property %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ /* Get the ibatterm property */
+ rc = of_property_read_u32(spmi->dev.of_node,
+ "qcom,chg-ibatterm-ma",
+ &chip->term_current);
+ if (rc && rc != -EINVAL) {
+ pr_err("Error reading ibatterm property %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ /* Get the ibatmax property */
+ rc = of_property_read_u32(spmi->dev.of_node, "qcom,chg-ibatmax-ma",
+ &chip->max_bat_chg_current);
+ if (rc && rc != -EINVAL) {
+ pr_err("Error reading ibatmax property %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ spmi_for_each_container_dev(spmi_resource, spmi) {
+ if (!spmi_resource) {
+ pr_err("qpnp_chg: spmi resource absent\n");
+ rc = -ENXIO;
+ goto fail_chg_enable;
+ }
+
+ resource = spmi_get_resource(spmi, spmi_resource,
+ IORESOURCE_MEM, 0);
+ if (!(resource && resource->start)) {
+ pr_err("node %s IO resource absent!\n",
+ spmi->dev.of_node->full_name);
+ rc = -ENXIO;
+ goto fail_chg_enable;
+ }
+
+ rc = qpnp_chg_read(chip, &subtype,
+ resource->start + REG_OFFSET_PERP_SUBTYPE, 1);
+ if (rc) {
+ pr_err("Peripheral subtype read failed rc=%d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ switch (subtype) {
+ case SMBB_CHGR_SUBTYPE:
+ chip->chgr_base = resource->start;
+ rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+ if (rc) {
+ pr_err("Failed to init subtype 0x%x rc=%d\n",
+ subtype, rc);
+ goto fail_chg_enable;
+ }
+ break;
+ case SMBB_BUCK_SUBTYPE:
+ chip->buck_base = resource->start;
+ rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+ if (rc) {
+ pr_err("Failed to init subtype 0x%x rc=%d\n",
+ subtype, rc);
+ goto fail_chg_enable;
+ }
+ break;
+ case SMBB_BAT_IF_SUBTYPE:
+ chip->bat_if_base = resource->start;
+ rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+ if (rc) {
+ pr_err("Failed to init subtype 0x%x rc=%d\n",
+ subtype, rc);
+ goto fail_chg_enable;
+ }
+ break;
+ case SMBB_USB_CHGPTH_SUBTYPE:
+ chip->usb_chgpth_base = resource->start;
+ rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+ if (rc) {
+ pr_err("Failed to init subtype 0x%x rc=%d\n",
+ subtype, rc);
+ goto fail_chg_enable;
+ }
+ break;
+ case SMBB_DC_CHGPTH_SUBTYPE:
+ chip->dc_chgpth_base = resource->start;
+ rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+ if (rc) {
+ pr_err("Failed to init subtype 0x%x rc=%d\n",
+ subtype, rc);
+ goto fail_chg_enable;
+ }
+ break;
+ case SMBB_BOOST_SUBTYPE:
+ chip->boost_base = resource->start;
+ rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+ if (rc) {
+ pr_err("Failed to init subtype 0x%x rc=%d\n",
+ subtype, rc);
+ goto fail_chg_enable;
+ }
+ break;
+ case SMBB_MISC_SUBTYPE:
+ chip->misc_base = resource->start;
+ rc = qpnp_chg_hwinit(chip, subtype, spmi_resource);
+ if (rc) {
+ pr_err("Failed to init subtype=0x%x rc=%d\n",
+ subtype, rc);
+ goto fail_chg_enable;
+ }
+ break;
+ default:
+ pr_err("Invalid peripheral subtype=0x%x\n", subtype);
+ rc = -EINVAL;
+ goto fail_chg_enable;
+ }
+ }
+ dev_set_drvdata(&spmi->dev, chip);
+ device_init_wakeup(&spmi->dev, 1);
+
+ chip->dc_psy.name = "qpnp-dc";
+ chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+ chip->dc_psy.supplied_to = pm_power_supplied_to;
+ chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+ chip->dc_psy.properties = pm_power_props_mains;
+ chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props_mains);
+ chip->dc_psy.get_property = qpnp_power_get_property_mains;
+
+ chip->batt_psy.name = "battery";
+ chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
+ chip->batt_psy.properties = msm_batt_power_props;
+ chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props);
+ chip->batt_psy.get_property = qpnp_batt_power_get_property;
+ chip->batt_psy.external_power_changed =
+ qpnp_batt_external_power_changed;
+
+ rc = power_supply_register(chip->dev, &chip->dc_psy);
+ if (rc < 0) {
+ pr_err("power_supply_register usb failed rc = %d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ rc = power_supply_register(chip->dev, &chip->batt_psy);
+ if (rc < 0) {
+ pr_err("power_supply_register batt failed rc = %d\n", rc);
+ goto unregister_dc;
+ }
+
+ power_supply_set_present(chip->usb_psy,
+ qpnp_chg_is_usb_chg_plugged_in(chip));
+
+ qpnp_chg_charge_en(chip, 1);
+ the_chip = chip;
+ pr_info("Probe success !\n");
+ return 0;
+
+unregister_dc:
+ power_supply_unregister(&chip->dc_psy);
+fail_chg_enable:
+ kfree(chip);
+ dev_set_drvdata(&spmi->dev, NULL);
+ return rc;
+}
+
+static int __devexit
+qpnp_charger_remove(struct spmi_device *spmi)
+{
+ struct qpnp_chg_chip *chip = dev_get_drvdata(&spmi->dev);
+
+ dev_set_drvdata(&spmi->dev, NULL);
+ kfree(chip);
+
+ return 0;
+}
+
+static struct spmi_driver qpnp_charger_driver = {
+ .probe = qpnp_charger_probe,
+ .remove = __devexit_p(qpnp_charger_remove),
+ .driver = {
+ .name = QPNP_CHARGER_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qpnp_charger_match_table,
+ },
+};
+
+/**
+ * qpnp_chg_init() - register spmi driver for qpnp-chg
+ */
+int __init
+qpnp_chg_init(void)
+{
+ return spmi_driver_register(&qpnp_charger_driver);
+}
+module_init(qpnp_chg_init);
+
+static void __exit
+qpnp_chg_exit(void)
+{
+ spmi_driver_unregister(&qpnp_charger_driver);
+}
+module_exit(qpnp_chg_exit);
+
+
+MODULE_DESCRIPTION("QPNP charger driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_CHARGER_DEV_NAME);
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 45429a1..d099074 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -100,6 +100,7 @@
void __iomem *base;
void __iomem *intr;
int pic_irq;
+ bool allow_wakeup;
spinlock_t lock;
u8 owner;
u8 channel;
@@ -638,10 +639,14 @@
return -ENODEV;
pmic_arb->channel = (u8)prop;
- ret = irq_set_irq_wake(pmic_arb->pic_irq, 1);
- if (unlikely(ret)) {
- pr_err("Unable to set wakeup irq, err=%d\n", ret);
- return -ENODEV;
+ pmic_arb->allow_wakeup = !of_property_read_bool(pdev->dev.of_node,
+ "qcom,not-wakeup");
+ if (pmic_arb->allow_wakeup) {
+ ret = irq_set_irq_wake(pmic_arb->pic_irq, 1);
+ if (unlikely(ret)) {
+ pr_err("Unable to set wakeup irq, err=%d\n", ret);
+ return -ENODEV;
+ }
}
pmic_arb->dev = &pdev->dev;
@@ -685,7 +690,8 @@
spmi_del_controller(&pmic_arb->controller);
err_add_controller:
platform_set_drvdata(pdev, NULL);
- irq_set_irq_wake(pmic_arb->pic_irq, 0);
+ if (pmic_arb->allow_wakeup)
+ irq_set_irq_wake(pmic_arb->pic_irq, 0);
return ret;
}
@@ -693,7 +699,8 @@
{
struct spmi_pmic_arb_dev *pmic_arb = platform_get_drvdata(pdev);
- irq_set_irq_wake(pmic_arb->pic_irq, 0);
+ if (pmic_arb->allow_wakeup)
+ irq_set_irq_wake(pmic_arb->pic_irq, 0);
platform_set_drvdata(pdev, NULL);
spmi_del_controller(&pmic_arb->controller);
return 0;
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index 0c49a89..f60e318 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -907,17 +907,6 @@
return 0;
}
-static int tsens_check_version_support(void)
-{
- int rc = 0;
-
- if (tmdev->hw_type == MSM_8960)
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1)
- rc = -ENODEV;
-
- return rc;
-}
-
static int tsens_calib_sensors(void)
{
int rc = -ENODEV;
@@ -955,13 +944,6 @@
tmdev->tsens_num_sensor = pdata->tsens_num_sensor;
tmdev->hw_type = pdata->hw_type;
- rc = tsens_check_version_support();
- if (rc < 0) {
- kfree(tmdev);
- tmdev = NULL;
- return rc;
- }
-
rc = tsens_calib_sensors();
if (rc < 0) {
kfree(tmdev);
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 7169dc0..77cc1f9 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -10,6 +10,9 @@
* GNU General Public License for more details.
*
*/
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>
@@ -743,8 +746,7 @@
IORESOURCE_MEM, "tsens_physical");
if (!tmdev->res_tsens_mem) {
pr_err("Could not get tsens physical address resource\n");
- rc = -EINVAL;
- goto fail_free_irq;
+ return -EINVAL;
}
tmdev->tsens_len = tmdev->res_tsens_mem->end -
@@ -754,8 +756,7 @@
tmdev->tsens_len, tmdev->res_tsens_mem->name);
if (!res_mem) {
pr_err("Request tsens physical memory region failed\n");
- rc = -EINVAL;
- goto fail_free_irq;
+ return -EINVAL;
}
tmdev->tsens_addr = ioremap(res_mem->start, tmdev->tsens_len);
@@ -805,9 +806,6 @@
if (tmdev->res_tsens_mem)
release_mem_region(tmdev->res_tsens_mem->start,
tmdev->tsens_len);
-fail_free_irq:
- free_irq(tmdev->tsens_irq, tmdev);
-
return rc;
}
@@ -827,8 +825,10 @@
tmdev->pdev = pdev;
rc = tsens_calib_sensors();
- if (rc < 0)
+ if (rc < 0) {
+ pr_err("Calibration failed\n");
goto fail;
+ }
tsens_hw_init();
@@ -848,8 +848,7 @@
if (tmdev->res_tsens_mem)
release_mem_region(tmdev->res_tsens_mem->start,
tmdev->tsens_len);
- free_irq(tmdev->tsens_irq, tmdev);
- kfree(tmdev);
+ tmdev = NULL;
return rc;
}
@@ -930,7 +929,6 @@
tmdev->tsens_len);
free_irq(tmdev->tsens_irq, tmdev);
platform_set_drvdata(pdev, NULL);
- kfree(tmdev);
return 0;
}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 19e1244..a292416 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1357,6 +1357,9 @@
{
struct usb_device *udev = to_usb_device(dev);
+ if (udev->bus->skip_resume && udev->state == USB_STATE_SUSPENDED)
+ return 0;
+
unbind_no_pm_drivers_interfaces(udev);
/* From now on we are sure all drivers support suspend/resume
@@ -1386,6 +1389,15 @@
struct usb_device *udev = to_usb_device(dev);
int status;
+ /*
+ * Some buses would like to keep their devices in suspend
+ * state after system resume. Their resume happen when
+ * a remote wakeup is detected or interface driver start
+ * I/O.
+ */
+ if (udev->bus->skip_resume)
+ return 0;
+
/* For all calls, take the device back to full power and
* tell the PM core in case it was autosuspended previously.
* Unbind the interfaces that will need rebinding later,
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index a3f6e58..b2709d2 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1021,6 +1021,9 @@
dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
request, ep->name, request->length);
+ WARN(!dep->direction && (request->length % ep->desc->wMaxPacketSize),
+ "trying to queue unaligned request (%d)\n", request->length);
+
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_queue(dep, req);
spin_unlock_irqrestore(&dwc->lock, flags);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 46f21a7..0b1a16e 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -52,6 +52,7 @@
#include "f_rmnet_sdio.c"
#include "f_rmnet_smd_sdio.c"
#include "f_rmnet.c"
+#include "f_audio_source.c"
#include "f_mass_storage.c"
#include "u_serial.c"
#include "u_sdio.c"
@@ -71,17 +72,19 @@
#define USB_ETH_RNDIS y
#include "f_rndis.c"
#include "rndis.c"
-#include "u_ether.c"
#include "u_bam_data.c"
#include "f_mbim.c"
#include "f_qc_ecm.c"
#include "f_qc_rndis.c"
+#include "u_ether.c"
#include "u_qc_ether.c"
#ifdef CONFIG_TARGET_CORE
#include "f_tcm.c"
#endif
+#ifdef CONFIG_SND_PCM
#include "u_uac1.c"
#include "f_uac1.c"
+#endif
MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -704,6 +707,7 @@
.init = mbim_function_init,
};
+#ifdef CONFIG_SND_PCM
/* PERIPHERAL AUDIO */
static int audio_function_bind_config(struct android_usb_function *f,
struct usb_configuration *c)
@@ -715,6 +719,7 @@
.name = "audio",
.bind_config = audio_function_bind_config,
};
+#endif
/* DIAG */
@@ -1471,6 +1476,68 @@
.ctrlrequest = accessory_function_ctrlrequest,
};
+static int audio_source_function_init(struct android_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ struct audio_source_config *config;
+
+ config = kzalloc(sizeof(struct audio_source_config), GFP_KERNEL);
+ if (!config)
+ return -ENOMEM;
+ config->card = -1;
+ config->device = -1;
+ f->config = config;
+ return 0;
+}
+
+static void audio_source_function_cleanup(struct android_usb_function *f)
+{
+ kfree(f->config);
+}
+
+static int audio_source_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct audio_source_config *config = f->config;
+
+ return audio_source_bind_config(c, config);
+}
+
+static void audio_source_function_unbind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct audio_source_config *config = f->config;
+
+ config->card = -1;
+ config->device = -1;
+}
+
+static ssize_t audio_source_pcm_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct android_usb_function *f = dev_get_drvdata(dev);
+ struct audio_source_config *config = f->config;
+
+ /* print PCM card and device numbers */
+ return sprintf(buf, "%d %d\n", config->card, config->device);
+}
+
+static DEVICE_ATTR(pcm, S_IRUGO | S_IWUSR, audio_source_pcm_show, NULL);
+
+static struct device_attribute *audio_source_function_attributes[] = {
+ &dev_attr_pcm,
+ NULL
+};
+
+static struct android_usb_function audio_source_function = {
+ .name = "audio_source",
+ .init = audio_source_function_init,
+ .cleanup = audio_source_function_cleanup,
+ .bind_config = audio_source_function_bind_config,
+ .unbind_config = audio_source_function_unbind_config,
+ .attributes = audio_source_function_attributes,
+};
+
static int android_uasp_connect_cb(bool connect)
{
/*
@@ -1520,7 +1587,9 @@
static struct android_usb_function *supported_functions[] = {
&mbim_function,
&ecm_qc_function,
+#ifdef CONFIG_SND_PCM
&audio_function,
+#endif
&rmnet_smd_function,
&rmnet_sdio_function,
&rmnet_smd_sdio_function,
@@ -1537,6 +1606,7 @@
&rndis_qc_function,
&mass_storage_function,
&accessory_function,
+ &audio_source_function,
&uasp_function,
NULL
};
@@ -2131,7 +2201,6 @@
gadget->ep0->driver_data = cdev;
list_for_each_entry(conf, &dev->configs, list_item)
- if (&conf->usb_config == cdev->config)
list_for_each_entry(f,
&conf->enabled_functions,
enabled_list)
@@ -2170,6 +2239,11 @@
unsigned long flags;
composite_disconnect(gadget);
+ /* accessory HID support can be active while the
+ accessory function is not actually enabled,
+ so we need to inform it when we are disconnected.
+ */
+ acc_disconnect();
spin_lock_irqsave(&cdev->lock, flags);
dev->connected = 0;
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index b8b7f68..b3cab7a 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -76,6 +76,8 @@
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define ATDTW_SET_DELAY 100 /* 100msec delay */
+#define EP_PRIME_CHECK_DELAY (jiffies + msecs_to_jiffies(1000))
+#define MAX_PRIME_CHECK_RETRY 3 /*Wait for 3sec for EP prime failure */
/* ctrl register bank access */
static DEFINE_SPINLOCK(udc_lock);
@@ -498,8 +500,6 @@
hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
- while (hw_cread(CAP_ENDPTPRIME, BIT(n)))
- cpu_relax();
if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
return -EAGAIN;
@@ -1006,6 +1006,44 @@
}
/**
+ * dbg_prime_fail: prints a PRIME FAIL event
+ * @addr: endpoint address
+ * @mEp: endpoint structure
+ */
+static void dbg_prime_fail(u8 addr, const char *name,
+ const struct ci13xxx_ep *mEp)
+{
+ char msg[DBG_DATA_MSG];
+ struct ci13xxx_req *req;
+ struct list_head *ptr = NULL;
+
+ if (mEp != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "PRIME fail EP%d%s QH:%08X",
+ mEp->num, mEp->dir ? "IN" : "OUT", mEp->qh.ptr->cap);
+ dbg_print(addr, name, 0, msg);
+ scnprintf(msg, sizeof(msg),
+ "cap:%08X %08X %08X\n",
+ mEp->qh.ptr->curr, mEp->qh.ptr->td.next,
+ mEp->qh.ptr->td.token);
+ dbg_print(addr, "QHEAD", 0, msg);
+
+ list_for_each(ptr, &mEp->qh.queue) {
+ req = list_entry(ptr, struct ci13xxx_req, queue);
+ scnprintf(msg, sizeof(msg),
+ "%08X:%08X:%08X\n",
+ req->dma, req->ptr->next,
+ req->ptr->token);
+ dbg_print(addr, "REQ", 0, msg);
+ scnprintf(msg, sizeof(msg), "%08X:%d\n",
+ req->ptr->page[0],
+ req->req.status);
+ dbg_print(addr, "REQPAGE", 0, msg);
+ }
+ }
+}
+
+/**
* show_events: displays the event buffer
*
* Check "device.h" for details
@@ -1468,12 +1506,14 @@
n = hw_ep_bit(mEp->num, mEp->dir);
pr_info("%s: prime:%08x stat:%08x ep#%d dir:%s"
"dTD_update_fail_count: %lu "
- "mEp->dTD_update_fail_count: %lu\n", __func__,
+ "mEp->dTD_update_fail_count: %lu"
+ "mEp->prime_fail_count: %lu\n", __func__,
hw_cread(CAP_ENDPTPRIME, ~0),
hw_cread(CAP_ENDPTSTAT, ~0),
mEp->num, mEp->dir ? "IN" : "OUT",
udc->dTD_update_fail_count,
- mEp->dTD_update_fail_count);
+ mEp->dTD_update_fail_count,
+ mEp->prime_fail_count);
pr_info("QH: cap:%08x cur:%08x next:%08x token:%08x\n",
mEp->qh.ptr->cap, mEp->qh.ptr->curr,
@@ -1661,6 +1701,57 @@
return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
}
+static void ep_prime_timer_func(unsigned long data)
+{
+ struct ci13xxx_ep *mEp = (struct ci13xxx_ep *)data;
+ struct ci13xxx_req *req;
+ struct list_head *ptr = NULL;
+ int n = hw_ep_bit(mEp->num, mEp->dir);
+ unsigned long flags;
+
+
+ spin_lock_irqsave(mEp->lock, flags);
+ if (!hw_cread(CAP_ENDPTPRIME, BIT(n)))
+ goto out;
+
+ if (list_empty(&mEp->qh.queue))
+ goto out;
+
+ req = list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue);
+
+ mb();
+ if (!(TD_STATUS_ACTIVE & req->ptr->token))
+ goto out;
+
+ mEp->prime_timer_count++;
+ if (mEp->prime_timer_count == MAX_PRIME_CHECK_RETRY) {
+ mEp->prime_timer_count = 0;
+ pr_info("ep%d dir:%s QH:cap:%08x cur:%08x next:%08x tkn:%08x\n",
+ mEp->num, mEp->dir ? "IN" : "OUT",
+ mEp->qh.ptr->cap, mEp->qh.ptr->curr,
+ mEp->qh.ptr->td.next, mEp->qh.ptr->td.token);
+ list_for_each(ptr, &mEp->qh.queue) {
+ req = list_entry(ptr, struct ci13xxx_req, queue);
+ pr_info("\treq:%08xnext:%08xtkn:%08xpage0:%08xsts:%d\n",
+ req->dma, req->ptr->next,
+ req->ptr->token, req->ptr->page[0],
+ req->req.status);
+ }
+ dbg_prime_fail(0xFF, "PRIMEF", mEp);
+ mEp->prime_fail_count++;
+ } else {
+ mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
+ }
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return;
+
+out:
+ mEp->prime_timer_count = 0;
+ spin_unlock_irqrestore(mEp->lock, flags);
+
+}
+
/**
* _hardware_queue: configures a request at hardware level
* @gadget: gadget
@@ -1852,6 +1943,8 @@
ret = hw_ep_prime(mEp->num, mEp->dir,
mEp->type == USB_ENDPOINT_XFER_CONTROL);
+ if (!ret)
+ mod_timer(&mEp->prime_timer, EP_PRIME_CHECK_DELAY);
done:
return ret;
}
@@ -2300,6 +2393,8 @@
if (list_empty(&mEp->qh.queue))
return 0;
+ del_timer(&mEp->prime_timer);
+ mEp->prime_timer_count = 0;
list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
queue) {
dequeue:
@@ -2574,6 +2669,7 @@
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
int retval = 0;
unsigned long flags;
+ unsigned mult = 0;
trace("ep = %p, desc = %p", ep, desc);
@@ -2599,13 +2695,15 @@
mEp->qh.ptr->cap = 0;
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
mEp->qh.ptr->cap |= QH_IOS;
- else if (mEp->type == USB_ENDPOINT_XFER_ISOC) {
+ } else if (mEp->type == USB_ENDPOINT_XFER_ISOC) {
mEp->qh.ptr->cap &= ~QH_MULT;
- mEp->qh.ptr->cap |= BIT(30);
- } else
+ mult = ((mEp->ep.maxpacket >> QH_MULT_SHIFT) + 1) & 0x03;
+ mEp->qh.ptr->cap |= (mult << ffs_nr(QH_MULT));
+ } else {
mEp->qh.ptr->cap |= QH_ZLT;
+ }
mEp->qh.ptr->cap |=
(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
@@ -2647,6 +2745,8 @@
/* only internal SW should disable ctrl endpts */
+ del_timer(&mEp->prime_timer);
+ mEp->prime_timer_count = 0;
direction = mEp->dir;
do {
dbg_event(_usb_addr(mEp), "DISABLE", 0);
@@ -2661,6 +2761,7 @@
mEp->desc = NULL;
mEp->ep.desc = NULL;
+ mEp->ep.maxpacket = USHRT_MAX;
spin_unlock_irqrestore(mEp->lock, flags);
return retval;
@@ -2958,6 +3059,8 @@
spin_lock_irqsave(mEp->lock, flags);
+ del_timer(&mEp->prime_timer);
+ mEp->prime_timer_count = 0;
dbg_event(_usb_addr(mEp), "FFLUSH", 0);
hw_ep_flush(mEp->num, mEp->dir);
@@ -3135,7 +3238,8 @@
mEp->ep.name = mEp->name;
mEp->ep.ops = &usb_ep_ops;
- mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
+ mEp->ep.maxpacket =
+ k ? USHRT_MAX : CTRL_PAYLOAD_MAX;
INIT_LIST_HEAD(&mEp->qh.queue);
spin_unlock_irqrestore(udc->lock, flags);
@@ -3429,6 +3533,8 @@
for (i = 0; i < hw_ep_max; i++) {
struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
INIT_LIST_HEAD(&mEp->ep.ep_list);
+ setup_timer(&mEp->prime_timer, ep_prime_timer_func,
+ (unsigned long) mEp);
}
if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 3162e15..6b3cad8 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -67,6 +67,7 @@
#define QH_MAX_PKT (0x07FFUL << 16)
#define QH_ZLT BIT(29)
#define QH_MULT (0x0003UL << 30)
+#define QH_MULT_SHIFT 11
/* 1 */
u32 curr;
/* 2 - 8 */
@@ -107,6 +108,9 @@
struct device *device;
struct dma_pool *td_pool;
unsigned long dTD_update_fail_count;
+ unsigned long prime_fail_count;
+ int prime_timer_count;
+ struct timer_list prime_timer;
};
struct ci13xxx;
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 108caf9..42a6c43 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -33,6 +33,8 @@
#include <linux/device.h>
#include <linux/miscdevice.h>
+#include <linux/hid.h>
+#include <linux/hiddev.h>
#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb/f_accessory.h>
@@ -40,7 +42,7 @@
#define BULK_BUFFER_SIZE 16384
#define ACC_STRING_SIZE 256
-#define PROTOCOL_VERSION 1
+#define PROTOCOL_VERSION 2
/* String IDs */
#define INTERFACE_STRING_INDEX 0
@@ -49,6 +51,20 @@
#define TX_REQ_MAX 4
#define RX_REQ_MAX 2
+struct acc_hid_dev {
+ struct list_head list;
+ struct hid_device *hid;
+ struct acc_dev *dev;
+ /* accessory defined ID */
+ int id;
+ /* HID report descriptor */
+ u8 *report_desc;
+ /* length of HID report descriptor */
+ int report_desc_len;
+ /* number of bytes of report_desc we have received so far */
+ int report_desc_offset;
+};
+
struct acc_dev {
struct usb_function function;
struct usb_composite_dev *cdev;
@@ -78,6 +94,8 @@
/* set to 1 if we have a pending start request */
int start_requested;
+ int audio_mode;
+
/* synchronize access to our device file */
atomic_t open_excl;
@@ -87,7 +105,21 @@
wait_queue_head_t write_wq;
struct usb_request *rx_req[RX_REQ_MAX];
int rx_done;
- struct delayed_work work;
+
+ /* delayed work for handling ACCESSORY_START */
+ struct delayed_work start_work;
+
+ /* worker for registering and unregistering hid devices */
+ struct work_struct hid_work;
+
+ /* list of active HID devices */
+ struct list_head hid_list;
+
+ /* list of new HID devices to register */
+ struct list_head new_hid_list;
+
+ /* list of dead HID devices to unregister */
+ struct list_head dead_hid_list;
};
static struct usb_interface_descriptor acc_interface_desc = {
@@ -296,6 +328,160 @@
}
}
+static void acc_complete_set_hid_report_desc(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct acc_hid_dev *hid = req->context;
+ struct acc_dev *dev = hid->dev;
+ int length = req->actual;
+
+ if (req->status != 0) {
+ pr_err("acc_complete_set_hid_report_desc, err %d\n",
+ req->status);
+ return;
+ }
+
+ memcpy(hid->report_desc + hid->report_desc_offset, req->buf, length);
+ hid->report_desc_offset += length;
+ if (hid->report_desc_offset == hid->report_desc_len) {
+ /* After we have received the entire report descriptor
+ * we schedule work to initialize the HID device
+ */
+ schedule_work(&dev->hid_work);
+ }
+}
+
+static void acc_complete_send_hid_event(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct acc_hid_dev *hid = req->context;
+ int length = req->actual;
+
+ if (req->status != 0) {
+ pr_err("acc_complete_send_hid_event, err %d\n", req->status);
+ return;
+ }
+
+ hid_report_raw_event(hid->hid, HID_INPUT_REPORT, req->buf, length, 1);
+}
+
+static int acc_hid_parse(struct hid_device *hid)
+{
+ struct acc_hid_dev *hdev = hid->driver_data;
+
+ hid_parse_report(hid, hdev->report_desc, hdev->report_desc_len);
+ return 0;
+}
+
+static int acc_hid_start(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void acc_hid_stop(struct hid_device *hid)
+{
+}
+
+static int acc_hid_open(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void acc_hid_close(struct hid_device *hid)
+{
+}
+
+static struct hid_ll_driver acc_hid_ll_driver = {
+ .parse = acc_hid_parse,
+ .start = acc_hid_start,
+ .stop = acc_hid_stop,
+ .open = acc_hid_open,
+ .close = acc_hid_close,
+};
+
+static struct acc_hid_dev *acc_hid_new(struct acc_dev *dev,
+ int id, int desc_len)
+{
+ struct acc_hid_dev *hdev;
+
+ hdev = kzalloc(sizeof(*hdev), GFP_ATOMIC);
+ if (!hdev)
+ return NULL;
+ hdev->report_desc = kzalloc(desc_len, GFP_ATOMIC);
+ if (!hdev->report_desc) {
+ kfree(hdev);
+ return NULL;
+ }
+ hdev->dev = dev;
+ hdev->id = id;
+ hdev->report_desc_len = desc_len;
+
+ return hdev;
+}
+
+static struct acc_hid_dev *acc_hid_get(struct list_head *list, int id)
+{
+ struct acc_hid_dev *hid;
+
+ list_for_each_entry(hid, list, list) {
+ if (hid->id == id)
+ return hid;
+ }
+ return NULL;
+}
+
+static int acc_register_hid(struct acc_dev *dev, int id, int desc_length)
+{
+ struct acc_hid_dev *hid;
+ unsigned long flags;
+
+ /* report descriptor length must be > 0 */
+ if (desc_length <= 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ /* replace HID if one already exists with this ID */
+ hid = acc_hid_get(&dev->hid_list, id);
+ if (!hid)
+ hid = acc_hid_get(&dev->new_hid_list, id);
+ if (hid)
+ list_move(&hid->list, &dev->dead_hid_list);
+
+ hid = acc_hid_new(dev, id, desc_length);
+ if (!hid) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -ENOMEM;
+ }
+
+ list_add(&hid->list, &dev->new_hid_list);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ /* schedule work to register the HID device */
+ schedule_work(&dev->hid_work);
+ return 0;
+}
+
+static int acc_unregister_hid(struct acc_dev *dev, int id)
+{
+ struct acc_hid_dev *hid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ hid = acc_hid_get(&dev->hid_list, id);
+ if (!hid)
+ hid = acc_hid_get(&dev->new_hid_list, id);
+ if (!hid) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -EINVAL;
+ }
+
+ list_move(&hid->list, &dev->dead_hid_list);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ schedule_work(&dev->hid_work);
+ return 0;
+}
+
static int create_bulk_endpoints(struct acc_dev *dev,
struct usb_endpoint_descriptor *in_desc,
struct usb_endpoint_descriptor *out_desc)
@@ -353,7 +539,7 @@
return 0;
fail:
- printk(KERN_ERR "acc_bind() could not allocate requests\n");
+ pr_err("acc_bind() could not allocate requests\n");
while ((req = req_get(dev, &dev->tx_idle)))
acc_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
@@ -510,6 +696,8 @@
break;
case ACCESSORY_IS_START_REQUESTED:
return dev->start_requested;
+ case ACCESSORY_GET_AUDIO_MODE:
+ return dev->audio_mode;
}
if (!src)
return -EINVAL;
@@ -540,7 +728,7 @@
return 0;
}
-/* file operations for /dev/acc_usb */
+/* file operations for /dev/usb_accessory */
static const struct file_operations acc_fops = {
.owner = THIS_MODULE,
.read = acc_read,
@@ -550,23 +738,47 @@
.release = acc_release,
};
+static int acc_hid_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret)
+ return ret;
+ return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+}
+
static struct miscdevice acc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "usb_accessory",
.fops = &acc_fops,
};
+static const struct hid_device_id acc_hid_table[] = {
+ { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
+ { }
+};
+
+static struct hid_driver acc_hid_driver = {
+ .name = "USB accessory",
+ .id_table = acc_hid_table,
+ .probe = acc_hid_probe,
+};
static int acc_ctrlrequest(struct usb_composite_dev *cdev,
const struct usb_ctrlrequest *ctrl)
{
struct acc_dev *dev = _acc_dev;
int value = -EOPNOTSUPP;
+ struct acc_hid_dev *hid;
+ int offset;
u8 b_requestType = ctrl->bRequestType;
u8 b_request = ctrl->bRequest;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
+ unsigned long flags;
/*
printk(KERN_INFO "acc_ctrlrequest "
@@ -579,20 +791,56 @@
if (b_request == ACCESSORY_START) {
dev->start_requested = 1;
schedule_delayed_work(
- &dev->work, msecs_to_jiffies(10));
+ &dev->start_work, msecs_to_jiffies(10));
value = 0;
} else if (b_request == ACCESSORY_SEND_STRING) {
dev->string_index = w_index;
cdev->gadget->ep0->driver_data = dev;
cdev->req->complete = acc_complete_set_string;
value = w_length;
+ } else if (b_request == ACCESSORY_SET_AUDIO_MODE &&
+ w_index == 0 && w_length == 0) {
+ dev->audio_mode = w_value;
+ value = 0;
+ } else if (b_request == ACCESSORY_REGISTER_HID) {
+ value = acc_register_hid(dev, w_value, w_index);
+ } else if (b_request == ACCESSORY_UNREGISTER_HID) {
+ value = acc_unregister_hid(dev, w_value);
+ } else if (b_request == ACCESSORY_SET_HID_REPORT_DESC) {
+ spin_lock_irqsave(&dev->lock, flags);
+ hid = acc_hid_get(&dev->new_hid_list, w_value);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ if (!hid) {
+ value = -EINVAL;
+ goto err;
+ }
+ offset = w_index;
+ if (offset != hid->report_desc_offset
+ || offset + w_length > hid->report_desc_len) {
+ value = -EINVAL;
+ goto err;
+ }
+ cdev->req->context = hid;
+ cdev->req->complete = acc_complete_set_hid_report_desc;
+ value = w_length;
+ } else if (b_request == ACCESSORY_SEND_HID_EVENT) {
+ spin_lock_irqsave(&dev->lock, flags);
+ hid = acc_hid_get(&dev->hid_list, w_value);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ if (!hid) {
+ value = -EINVAL;
+ goto err;
+ }
+ cdev->req->context = hid;
+ cdev->req->complete = acc_complete_send_hid_event;
+ value = w_length;
}
} else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) {
if (b_request == ACCESSORY_GET_PROTOCOL) {
*((u16 *)cdev->req->buf) = PROTOCOL_VERSION;
value = sizeof(u16);
- /* clear any string left over from a previous session */
+ /* clear strings left over from a previous session */
memset(dev->manufacturer, 0, sizeof(dev->manufacturer));
memset(dev->model, 0, sizeof(dev->model));
memset(dev->description, 0, sizeof(dev->description));
@@ -600,6 +848,7 @@
memset(dev->uri, 0, sizeof(dev->uri));
memset(dev->serial, 0, sizeof(dev->serial));
dev->start_requested = 0;
+ dev->audio_mode = 0;
}
}
@@ -612,6 +861,7 @@
__func__);
}
+err:
if (value == -EOPNOTSUPP)
VDBG(cdev,
"unknown class-specific control req "
@@ -631,6 +881,10 @@
DBG(cdev, "acc_function_bind dev: %p\n", dev);
+ ret = hid_register_driver(&acc_hid_driver);
+ if (ret)
+ return ret;
+
dev->start_requested = 0;
/* allocate interface ID(s) */
@@ -660,6 +914,36 @@
}
static void
+kill_all_hid_devices(struct acc_dev *dev)
+{
+ struct acc_hid_dev *hid;
+ struct list_head *entry, *temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ list_for_each_safe(entry, temp, &dev->hid_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ list_del(&hid->list);
+ list_add(&hid->list, &dev->dead_hid_list);
+ }
+ list_for_each_safe(entry, temp, &dev->new_hid_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ list_del(&hid->list);
+ list_add(&hid->list, &dev->dead_hid_list);
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ schedule_work(&dev->hid_work);
+}
+
+static void
+acc_hid_unbind(struct acc_dev *dev)
+{
+ hid_unregister_driver(&acc_hid_driver);
+ kill_all_hid_devices(dev);
+}
+
+static void
acc_function_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct acc_dev *dev = func_to_dev(f);
@@ -670,14 +954,104 @@
acc_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
acc_request_free(dev->rx_req[i], dev->ep_out);
+
+ acc_hid_unbind(dev);
}
-static void acc_work(struct work_struct *data)
+static void acc_start_work(struct work_struct *data)
{
char *envp[2] = { "ACCESSORY=START", NULL };
kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp);
}
+static int acc_hid_init(struct acc_hid_dev *hdev)
+{
+ struct hid_device *hid;
+ int ret;
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid))
+ return PTR_ERR(hid);
+
+ hid->ll_driver = &acc_hid_ll_driver;
+ hid->dev.parent = acc_device.this_device;
+
+ hid->bus = BUS_USB;
+ hid->vendor = HID_ANY_ID;
+ hid->product = HID_ANY_ID;
+ hid->driver_data = hdev;
+ ret = hid_add_device(hid);
+ if (ret) {
+ pr_err("can't add hid device: %d\n", ret);
+ hid_destroy_device(hid);
+ return ret;
+ }
+
+ hdev->hid = hid;
+ return 0;
+}
+
+static void acc_hid_delete(struct acc_hid_dev *hid)
+{
+ kfree(hid->report_desc);
+ kfree(hid);
+}
+
+static void acc_hid_work(struct work_struct *data)
+{
+ struct acc_dev *dev = _acc_dev;
+ struct list_head *entry, *temp;
+ struct acc_hid_dev *hid;
+ struct list_head new_list, dead_list;
+ unsigned long flags;
+
+ INIT_LIST_HEAD(&new_list);
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* copy hids that are ready for initialization to new_list */
+ list_for_each_safe(entry, temp, &dev->new_hid_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ if (hid->report_desc_offset == hid->report_desc_len)
+ list_move(&hid->list, &new_list);
+ }
+
+ if (list_empty(&dev->dead_hid_list)) {
+ INIT_LIST_HEAD(&dead_list);
+ } else {
+ /* move all of dev->dead_hid_list to dead_list */
+ dead_list.prev = dev->dead_hid_list.prev;
+ dead_list.next = dev->dead_hid_list.next;
+ dead_list.next->prev = &dead_list;
+ dead_list.prev->next = &dead_list;
+ INIT_LIST_HEAD(&dev->dead_hid_list);
+ }
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ /* register new HID devices */
+ list_for_each_safe(entry, temp, &new_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ if (acc_hid_init(hid)) {
+ pr_err("can't add HID device %p\n", hid);
+ acc_hid_delete(hid);
+ } else {
+ spin_lock_irqsave(&dev->lock, flags);
+ list_move(&hid->list, &dev->hid_list);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ }
+ }
+
+ /* remove dead HID devices */
+ list_for_each_safe(entry, temp, &dead_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ list_del(&hid->list);
+ if (hid->hid)
+ hid_destroy_device(hid->hid);
+ acc_hid_delete(hid);
+ }
+}
+
static int acc_function_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
@@ -783,7 +1157,11 @@
init_waitqueue_head(&dev->write_wq);
atomic_set(&dev->open_excl, 0);
INIT_LIST_HEAD(&dev->tx_idle);
- INIT_DELAYED_WORK(&dev->work, acc_work);
+ INIT_LIST_HEAD(&dev->hid_list);
+ INIT_LIST_HEAD(&dev->new_hid_list);
+ INIT_LIST_HEAD(&dev->dead_hid_list);
+ INIT_DELAYED_WORK(&dev->start_work, acc_start_work);
+ INIT_WORK(&dev->hid_work, acc_hid_work);
/* _acc_dev must be set before calling usb_gadget_register_driver */
_acc_dev = dev;
@@ -796,10 +1174,16 @@
err:
kfree(dev);
- printk(KERN_ERR "USB accessory gadget driver failed to initialize\n");
+ pr_err("USB accessory gadget driver failed to initialize\n");
return ret;
}
+static void acc_disconnect(void)
+{
+ /* unregister all HID devices if USB is disconnected */
+ kill_all_hid_devices(_acc_dev);
+}
+
static void acc_cleanup(void)
{
misc_deregister(&acc_device);
diff --git a/drivers/usb/gadget/f_audio_source.c b/drivers/usb/gadget/f_audio_source.c
new file mode 100644
index 0000000..aae941e
--- /dev/null
+++ b/drivers/usb/gadget/f_audio_source.c
@@ -0,0 +1,832 @@
+/*
+ * Gadget Function Driver for USB audio source device
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * 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/device.h>
+#include <linux/usb/audio.h>
+#include <linux/wait.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+
+#define SAMPLE_RATE 44100
+#define FRAMES_PER_MSEC (SAMPLE_RATE / 1000)
+
+#define IN_EP_MAX_PACKET_SIZE 256
+
+/* Number of requests to allocate */
+#define IN_EP_REQ_COUNT 4
+
+#define AUDIO_AC_INTERFACE 0
+#define AUDIO_AS_INTERFACE 1
+#define AUDIO_NUM_INTERFACES 2
+
+/* B.3.1 Standard AC Interface Descriptor */
+static struct usb_interface_descriptor audio_source_ac_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+};
+
+
+#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(AUDIO_NUM_INTERFACES)
+/* 1 input terminal, 1 output terminal and 1 feature unit */
+#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \
+ + UAC_DT_INPUT_TERMINAL_SIZE + UAC_DT_OUTPUT_TERMINAL_SIZE \
+ + UAC_DT_FEATURE_UNIT_SIZE(0))
+/* B.3.2 Class-Specific AC Interface Descriptor */
+static struct uac1_ac_header_descriptor_2 audio_source_ac_header_desc = {
+ .bLength = UAC_DT_AC_HEADER_LENGTH,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_HEADER,
+ .bcdADC = __constant_cpu_to_le16(0x0100),
+ .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
+ .bInCollection = AUDIO_NUM_INTERFACES,
+ .baInterfaceNr = {
+ [0] = AUDIO_AC_INTERFACE,
+ [1] = AUDIO_AS_INTERFACE,
+ }
+};
+
+#define INPUT_TERMINAL_ID 1
+static struct uac_input_terminal_descriptor input_terminal_desc = {
+ .bLength = UAC_DT_INPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_INPUT_TERMINAL,
+ .bTerminalID = INPUT_TERMINAL_ID,
+ .wTerminalType = UAC_INPUT_TERMINAL_MICROPHONE,
+ .bAssocTerminal = 0,
+ .wChannelConfig = 0x3,
+};
+
+DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0);
+
+#define FEATURE_UNIT_ID 2
+static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
+ .bLength = UAC_DT_FEATURE_UNIT_SIZE(0),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_FEATURE_UNIT,
+ .bUnitID = FEATURE_UNIT_ID,
+ .bSourceID = INPUT_TERMINAL_ID,
+ .bControlSize = 2,
+};
+
+#define OUTPUT_TERMINAL_ID 3
+static struct uac1_output_terminal_descriptor output_terminal_desc = {
+ .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
+ .bTerminalID = OUTPUT_TERMINAL_ID,
+ .wTerminalType = UAC_TERMINAL_STREAMING,
+ .bAssocTerminal = FEATURE_UNIT_ID,
+ .bSourceID = FEATURE_UNIT_ID,
+};
+
+/* B.4.1 Standard AS Interface Descriptor */
+static struct usb_interface_descriptor as_interface_alt_0_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+static struct usb_interface_descriptor as_interface_alt_1_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+/* B.4.2 Class-Specific AS Interface Descriptor */
+static struct uac1_as_header_descriptor as_header_desc = {
+ .bLength = UAC_DT_AS_HEADER_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_AS_GENERAL,
+ .bTerminalLink = INPUT_TERMINAL_ID,
+ .bDelay = 1,
+ .wFormatTag = UAC_FORMAT_TYPE_I_PCM,
+};
+
+static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
+ .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_FORMAT_TYPE,
+ .bFormatType = UAC_FORMAT_TYPE_I,
+ .bSubframeSize = 2,
+ .bBitResolution = 16,
+ .bSamFreqType = 1,
+};
+
+/* Standard ISO IN Endpoint Descriptor for highspeed */
+static struct usb_endpoint_descriptor hs_as_in_ep_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_SYNC_SYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = __constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE),
+ .bInterval = 4, /* poll 1 per millisecond */
+};
+
+/* Standard ISO IN Endpoint Descriptor for highspeed */
+static struct usb_endpoint_descriptor fs_as_in_ep_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_SYNC_SYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = __constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE),
+ .bInterval = 1, /* poll 1 per millisecond */
+};
+
+/* Class-specific AS ISO OUT Endpoint Descriptor */
+static struct uac_iso_endpoint_descriptor as_iso_in_desc = {
+ .bLength = UAC_ISO_ENDPOINT_DESC_SIZE,
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = UAC_EP_GENERAL,
+ .bmAttributes = 1,
+ .bLockDelayUnits = 1,
+ .wLockDelay = __constant_cpu_to_le16(1),
+};
+
+static struct usb_descriptor_header *hs_audio_desc[] = {
+ (struct usb_descriptor_header *)&audio_source_ac_interface_desc,
+ (struct usb_descriptor_header *)&audio_source_ac_header_desc,
+
+ (struct usb_descriptor_header *)&input_terminal_desc,
+ (struct usb_descriptor_header *)&output_terminal_desc,
+ (struct usb_descriptor_header *)&feature_unit_desc,
+
+ (struct usb_descriptor_header *)&as_interface_alt_0_desc,
+ (struct usb_descriptor_header *)&as_interface_alt_1_desc,
+ (struct usb_descriptor_header *)&as_header_desc,
+
+ (struct usb_descriptor_header *)&as_type_i_desc,
+
+ (struct usb_descriptor_header *)&hs_as_in_ep_desc,
+ (struct usb_descriptor_header *)&as_iso_in_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *fs_audio_desc[] = {
+ (struct usb_descriptor_header *)&audio_source_ac_interface_desc,
+ (struct usb_descriptor_header *)&audio_source_ac_header_desc,
+
+ (struct usb_descriptor_header *)&input_terminal_desc,
+ (struct usb_descriptor_header *)&output_terminal_desc,
+ (struct usb_descriptor_header *)&feature_unit_desc,
+
+ (struct usb_descriptor_header *)&as_interface_alt_0_desc,
+ (struct usb_descriptor_header *)&as_interface_alt_1_desc,
+ (struct usb_descriptor_header *)&as_header_desc,
+
+ (struct usb_descriptor_header *)&as_type_i_desc,
+
+ (struct usb_descriptor_header *)&fs_as_in_ep_desc,
+ (struct usb_descriptor_header *)&as_iso_in_desc,
+ NULL,
+};
+
+static struct snd_pcm_hardware audio_hw_info = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = SAMPLE_RATE,
+ .rate_max = SAMPLE_RATE,
+
+ .buffer_bytes_max = 1024 * 1024,
+ .period_bytes_min = 64,
+ .period_bytes_max = 512 * 1024,
+ .periods_min = 2,
+ .periods_max = 1024,
+};
+
+/*-------------------------------------------------------------------------*/
+
+struct audio_source_config {
+ int card;
+ int device;
+};
+
+struct audio_dev {
+ struct usb_function func;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ struct snd_pcm_substream *substream;
+
+ struct list_head idle_reqs;
+ struct usb_ep *in_ep;
+
+ spinlock_t lock;
+
+ /* beginning, end and current position in our buffer */
+ void *buffer_start;
+ void *buffer_end;
+ void *buffer_pos;
+
+ /* byte size of a "period" */
+ unsigned int period;
+ /* bytes sent since last call to snd_pcm_period_elapsed */
+ unsigned int period_offset;
+ /* time we started playing */
+ ktime_t start_time;
+ /* number of frames sent since start_time */
+ s64 frames_sent;
+};
+
+static inline struct audio_dev *func_to_audio_source(struct usb_function *f)
+{
+ return container_of(f, struct audio_dev, func);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *audio_request_new(struct usb_ep *ep, int buffer_size)
+{
+ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
+ if (!req)
+ return NULL;
+
+ req->buf = kmalloc(buffer_size, GFP_KERNEL);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ return NULL;
+ }
+ req->length = buffer_size;
+ return req;
+}
+
+static void audio_request_free(struct usb_request *req, struct usb_ep *ep)
+{
+ if (req) {
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+ }
+}
+
+static void audio_req_put(struct audio_dev *audio, struct usb_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ list_add_tail(&req->list, &audio->idle_reqs);
+ spin_unlock_irqrestore(&audio->lock, flags);
+}
+
+static struct usb_request *audio_req_get(struct audio_dev *audio)
+{
+ unsigned long flags;
+ struct usb_request *req;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ if (list_empty(&audio->idle_reqs)) {
+ req = 0;
+ } else {
+ req = list_first_entry(&audio->idle_reqs, struct usb_request,
+ list);
+ list_del(&req->list);
+ }
+ spin_unlock_irqrestore(&audio->lock, flags);
+ return req;
+}
+
+/* send the appropriate number of packets to match our bitrate */
+static void audio_send(struct audio_dev *audio)
+{
+ struct snd_pcm_runtime *runtime;
+ struct usb_request *req;
+ int length, length1, length2, ret;
+ s64 msecs;
+ s64 frames;
+ ktime_t now;
+
+ /* audio->substream will be null if we have been closed */
+ if (!audio->substream)
+ return;
+ /* audio->buffer_pos will be null if we have been stopped */
+ if (!audio->buffer_pos)
+ return;
+
+ runtime = audio->substream->runtime;
+
+ /* compute number of frames to send */
+ now = ktime_get();
+ msecs = ktime_to_ns(now) - ktime_to_ns(audio->start_time);
+ do_div(msecs, 1000000);
+ frames = msecs * SAMPLE_RATE;
+ do_div(frames, 1000);
+
+ /* Readjust our frames_sent if we fall too far behind.
+ * If we get too far behind it is better to drop some frames than
+ * to keep sending data too fast in an attempt to catch up.
+ */
+ if (frames - audio->frames_sent > 10 * FRAMES_PER_MSEC)
+ audio->frames_sent = frames - FRAMES_PER_MSEC;
+
+ frames -= audio->frames_sent;
+
+ /* We need to send something to keep the pipeline going */
+ if (frames <= 0)
+ frames = FRAMES_PER_MSEC;
+
+ while (frames > 0) {
+ req = audio_req_get(audio);
+ if (!req)
+ break;
+
+ length = frames_to_bytes(runtime, frames);
+ if (length > IN_EP_MAX_PACKET_SIZE)
+ length = IN_EP_MAX_PACKET_SIZE;
+
+ if (audio->buffer_pos + length > audio->buffer_end)
+ length1 = audio->buffer_end - audio->buffer_pos;
+ else
+ length1 = length;
+ memcpy(req->buf, audio->buffer_pos, length1);
+ if (length1 < length) {
+ /* Wrap around and copy remaining length
+ * at beginning of buffer.
+ */
+ length2 = length - length1;
+ memcpy(req->buf + length1, audio->buffer_start,
+ length2);
+ audio->buffer_pos = audio->buffer_start + length2;
+ } else {
+ audio->buffer_pos += length1;
+ if (audio->buffer_pos >= audio->buffer_end)
+ audio->buffer_pos = audio->buffer_start;
+ }
+
+ req->length = length;
+ ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC);
+ if (ret < 0) {
+ pr_err("usb_ep_queue failed ret: %d\n", ret);
+ audio_req_put(audio, req);
+ break;
+ }
+
+ frames -= bytes_to_frames(runtime, length);
+ audio->frames_sent += bytes_to_frames(runtime, length);
+ }
+}
+
+static void audio_control_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ /* nothing to do here */
+}
+
+static void audio_data_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct audio_dev *audio = req->context;
+
+ pr_debug("audio_data_complete req->status %d req->actual %d\n",
+ req->status, req->actual);
+
+ audio_req_put(audio, req);
+
+ if (!audio->buffer_start || req->status)
+ return;
+
+ audio->period_offset += req->actual;
+ if (audio->period_offset >= audio->period) {
+ snd_pcm_period_elapsed(audio->substream);
+ audio->period_offset = 0;
+ }
+ audio_send(audio);
+}
+
+static int audio_source_set_endpoint_req(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ int value = -EOPNOTSUPP;
+ u16 ep = le16_to_cpu(ctrl->wIndex);
+ u16 len = le16_to_cpu(ctrl->wLength);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+
+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+ ctrl->bRequest, w_value, len, ep);
+
+ switch (ctrl->bRequest) {
+ case UAC_SET_CUR:
+ case UAC_SET_MIN:
+ case UAC_SET_MAX:
+ case UAC_SET_RES:
+ value = len;
+ break;
+ default:
+ break;
+ }
+
+ return value;
+}
+
+static int audio_source_get_endpoint_req(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ int value = -EOPNOTSUPP;
+ u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
+ u16 len = le16_to_cpu(ctrl->wLength);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u8 *buf = cdev->req->buf;
+
+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+ ctrl->bRequest, w_value, len, ep);
+
+ if (w_value == UAC_EP_CS_ATTR_SAMPLE_RATE << 8) {
+ switch (ctrl->bRequest) {
+ case UAC_GET_CUR:
+ case UAC_GET_MIN:
+ case UAC_GET_MAX:
+ case UAC_GET_RES:
+ /* return our sample rate */
+ buf[0] = (u8)SAMPLE_RATE;
+ buf[1] = (u8)(SAMPLE_RATE >> 8);
+ buf[2] = (u8)(SAMPLE_RATE >> 16);
+ value = 3;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return value;
+}
+
+static int
+audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = cdev->req;
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ /* composite driver infrastructure handles everything; interface
+ * activation uses set_alt().
+ */
+ switch (ctrl->bRequestType) {
+ case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+ value = audio_source_set_endpoint_req(f, ctrl);
+ break;
+
+ case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+ value = audio_source_get_endpoint_req(f, ctrl);
+ break;
+ }
+
+ /* respond with data transfer or status phase? */
+ if (value >= 0) {
+ pr_debug("audio req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ req->zero = 0;
+ req->length = value;
+ req->complete = audio_control_complete;
+ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0)
+ pr_err("audio response on err %d\n", value);
+ }
+
+ /* device either stalls (value < 0) or reports success */
+ return value;
+}
+
+static int audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct audio_dev *audio = func_to_audio_source(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ int ret;
+
+ pr_debug("audio_set_alt intf %d, alt %d\n", intf, alt);
+
+ ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep);
+ if (ret) {
+ audio->in_ep->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ audio->in_ep->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(audio->in_ep);
+ if (ret) {
+ ERROR(cdev, "failed to enable ep %s, result %d\n",
+ audio->in_ep->name, ret);
+ return ret;
+ }
+ return 0;
+}
+
+static void audio_disable(struct usb_function *f)
+{
+ struct audio_dev *audio = func_to_audio_source(f);
+
+ pr_debug("audio_disable\n");
+ usb_ep_disable(audio->in_ep);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void audio_build_desc(struct audio_dev *audio)
+{
+ u8 *sam_freq;
+ int rate;
+
+ /* Set channel numbers */
+ input_terminal_desc.bNrChannels = 2;
+ as_type_i_desc.bNrChannels = 2;
+
+ /* Set sample rates */
+ rate = SAMPLE_RATE;
+ sam_freq = as_type_i_desc.tSamFreq[0];
+ memcpy(sam_freq, &rate, 3);
+}
+
+/* audio function driver setup/binding */
+static int
+audio_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = c->cdev;
+ struct audio_dev *audio = func_to_audio_source(f);
+ int status;
+ struct usb_ep *ep;
+ struct usb_request *req;
+ int i;
+
+ audio_build_desc(audio);
+
+ /* allocate instance-specific interface IDs, and patch descriptors */
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ audio_source_ac_interface_desc.bInterfaceNumber = status;
+
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ as_interface_alt_0_desc.bInterfaceNumber = status;
+ as_interface_alt_1_desc.bInterfaceNumber = status;
+
+ status = -ENODEV;
+
+ /* allocate our endpoint */
+ ep = usb_ep_autoconfig(cdev->gadget, &fs_as_in_ep_desc);
+ if (!ep)
+ goto fail;
+ audio->in_ep = ep;
+ ep->driver_data = audio; /* claim */
+
+ if (gadget_is_dualspeed(c->cdev->gadget))
+ hs_as_in_ep_desc.bEndpointAddress =
+ fs_as_in_ep_desc.bEndpointAddress;
+
+ for (i = 0, status = 0; i < IN_EP_REQ_COUNT && status == 0; i++) {
+ req = audio_request_new(ep, IN_EP_MAX_PACKET_SIZE);
+ if (req) {
+ req->context = audio;
+ req->complete = audio_data_complete;
+ audio_req_put(audio, req);
+ } else
+ status = -ENOMEM;
+ }
+
+fail:
+ return status;
+}
+
+static void
+audio_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct audio_dev *audio = func_to_audio_source(f);
+ struct usb_request *req;
+
+ while ((req = audio_req_get(audio)))
+ audio_request_free(req, audio->in_ep);
+
+ snd_card_free_when_closed(audio->card);
+ audio->card = NULL;
+ audio->pcm = NULL;
+ audio->substream = NULL;
+ audio->in_ep = NULL;
+}
+
+static void audio_pcm_playback_start(struct audio_dev *audio)
+{
+ audio->start_time = ktime_get();
+ audio->frames_sent = 0;
+ audio_send(audio);
+}
+
+static void audio_pcm_playback_stop(struct audio_dev *audio)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ audio->buffer_start = 0;
+ audio->buffer_end = 0;
+ audio->buffer_pos = 0;
+ spin_unlock_irqrestore(&audio->lock, flags);
+}
+
+static int audio_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_dev *audio = substream->private_data;
+
+ runtime->private_data = audio;
+ runtime->hw = audio_hw_info;
+ snd_pcm_limit_hw_rates(runtime);
+ runtime->hw.channels_max = 2;
+
+ audio->substream = substream;
+ return 0;
+}
+
+static int audio_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct audio_dev *audio = substream->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ audio->substream = NULL;
+ spin_unlock_irqrestore(&audio->lock, flags);
+
+ return 0;
+}
+
+static int audio_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int channels = params_channels(params);
+ unsigned int rate = params_rate(params);
+
+ if (rate != SAMPLE_RATE)
+ return -EINVAL;
+ if (channels != 2)
+ return -EINVAL;
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int audio_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int audio_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_dev *audio = runtime->private_data;
+
+ audio->period = snd_pcm_lib_period_bytes(substream);
+ audio->period_offset = 0;
+ audio->buffer_start = runtime->dma_area;
+ audio->buffer_end = audio->buffer_start
+ + snd_pcm_lib_buffer_bytes(substream);
+ audio->buffer_pos = audio->buffer_start;
+
+ return 0;
+}
+
+static snd_pcm_uframes_t audio_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_dev *audio = runtime->private_data;
+ ssize_t bytes = audio->buffer_pos - audio->buffer_start;
+
+ /* return offset of next frame to fill in our buffer */
+ return bytes_to_frames(runtime, bytes);
+}
+
+static int audio_pcm_playback_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct audio_dev *audio = substream->runtime->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ audio_pcm_playback_start(audio);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ audio_pcm_playback_stop(audio);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct audio_dev _audio_dev = {
+ .func = {
+ .name = "audio_source",
+ .bind = audio_bind,
+ .unbind = audio_unbind,
+ .set_alt = audio_set_alt,
+ .setup = audio_setup,
+ .disable = audio_disable,
+ .descriptors = fs_audio_desc,
+ .hs_descriptors = hs_audio_desc,
+ },
+ .lock = __SPIN_LOCK_UNLOCKED(_audio_dev.lock),
+ .idle_reqs = LIST_HEAD_INIT(_audio_dev.idle_reqs),
+};
+
+static struct snd_pcm_ops audio_playback_ops = {
+ .open = audio_pcm_open,
+ .close = audio_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = audio_pcm_hw_params,
+ .hw_free = audio_pcm_hw_free,
+ .prepare = audio_pcm_prepare,
+ .trigger = audio_pcm_playback_trigger,
+ .pointer = audio_pcm_pointer,
+};
+
+int audio_source_bind_config(struct usb_configuration *c,
+ struct audio_source_config *config)
+{
+ struct audio_dev *audio;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ int err;
+
+ config->card = -1;
+ config->device = -1;
+
+ audio = &_audio_dev;
+
+ err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
+ if (err)
+ return err;
+
+ snd_card_set_dev(card, &c->cdev->gadget->dev);
+
+ err = snd_pcm_new(card, "USB audio source", 0, 1, 0, &pcm);
+ if (err)
+ goto pcm_fail;
+ pcm->private_data = audio;
+ pcm->info_flags = 0;
+ audio->pcm = pcm;
+
+ strlcpy(pcm->name, "USB gadget audio", sizeof(pcm->name));
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &audio_playback_ops);
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ NULL, 0, 64 * 1024);
+
+ strlcpy(card->driver, "audio_source", sizeof(card->driver));
+ strlcpy(card->shortname, card->driver, sizeof(card->shortname));
+ strlcpy(card->longname, "USB accessory audio source",
+ sizeof(card->longname));
+
+ err = snd_card_register(card);
+ if (err)
+ goto register_fail;
+
+ err = usb_add_function(c, &audio->func);
+ if (err)
+ goto add_fail;
+
+ config->card = pcm->card->number;
+ config->device = pcm->device;
+ audio->card = card;
+ return 0;
+
+add_fail:
+register_fail:
+pcm_fail:
+ snd_card_free(audio->card);
+ return err;
+}
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 96790c5..ccbc330 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -463,6 +463,10 @@
if (count > MTP_BULK_BUFFER_SIZE)
return -EINVAL;
+ if (!IS_ALIGNED(count, dev->ep_out->maxpacket))
+ DBG(cdev, "%s - count(%d) not multiple of mtu(%d)\n", __func__,
+ count, dev->ep_out->maxpacket);
+
/* we will block until we're online */
DBG(cdev, "mtp_read: waiting for online state\n");
ret = wait_event_interruptible(dev->read_wq,
@@ -484,7 +488,7 @@
requeue_req:
/* queue a request */
req = dev->rx_req[0];
- req->length = count;
+ req->length = MTP_BULK_BUFFER_SIZE;
dev->rx_done = 0;
ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL);
if (ret < 0) {
@@ -751,6 +755,9 @@
count = dev->xfer_file_length;
DBG(cdev, "receive_file_work(%lld)\n", count);
+ if (!IS_ALIGNED(count, dev->ep_out->maxpacket))
+ DBG(cdev, "%s- count(%lld) not multiple of mtu(%d)\n", __func__,
+ count, dev->ep_out->maxpacket);
while (count > 0 || write_req) {
if (count > 0) {
@@ -758,8 +765,9 @@
read_req = dev->rx_req[cur_buf];
cur_buf = (cur_buf + 1) % RX_REQ_MAX;
- read_req->length = (count > MTP_BULK_BUFFER_SIZE
- ? MTP_BULK_BUFFER_SIZE : count);
+ /* some h/w expects size to be aligned to ep's MTU */
+ read_req->length = MTP_BULK_BUFFER_SIZE;
+
dev->rx_done = 0;
ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL);
if (ret < 0) {
@@ -795,6 +803,10 @@
usb_ep_dequeue(dev->ep_out, read_req);
break;
}
+ /* Check if we aligned the size due to MTU constraint */
+ if (count < read_req->length)
+ read_req->actual = (read_req->actual > count ?
+ count : read_req->actual);
/* if xfer_file_length is 0xFFFFFFFF, then we read until
* we get a zero length packet
*/
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 7fedaf6..1c64955 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -403,6 +403,8 @@
static void ecm_qc_notify_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_ecm_qc *ecm = req->context;
+ struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
+ struct usb_cdc_notification *event = req->buf;
switch (req->status) {
case 0:
@@ -584,6 +586,7 @@
static void ecm_qc_disable(struct usb_function *f)
{
struct f_ecm_qc *ecm = func_to_ecm_qc(f);
+ struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
DBG(cdev, "ecm deactivated\n");
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 60b96fe..7a181eb 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -512,8 +512,9 @@
static void rndis_qc_response_complete(struct usb_ep *ep,
struct usb_request *req)
{
- struct f_rndis_qc *rndis = req->context;
+ struct f_rndis_qc *rndis = req->context;
int status = req->status;
+ struct usb_composite_dev *cdev = rndis->port.func.config->cdev;
/* after TX:
* - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
diff --git a/drivers/usb/gadget/f_rmnet_smd.c b/drivers/usb/gadget/f_rmnet_smd.c
index b71f646..5e2c6ed 100644
--- a/drivers/usb/gadget/f_rmnet_smd.c
+++ b/drivers/usb/gadget/f_rmnet_smd.c
@@ -907,13 +907,14 @@
* Register platform driver to be notified in case SMD channels
* later becomes ready to be opened.
*/
- ret = platform_driver_register(&dev->pdrv);
- if (ret)
- ERROR(cdev, "Platform driver %s register failed %d\n",
- dev->pdrv.driver.name, ret);
- else
- dev->is_pdrv_used = 1;
-
+ if (!dev->is_pdrv_used) {
+ ret = platform_driver_register(&dev->pdrv);
+ if (ret)
+ ERROR(cdev, "pdrv %s register failed %d\n",
+ dev->pdrv.driver.name, ret);
+ else
+ dev->is_pdrv_used = 1;
+ }
return;
}
wait_event(dev->smd_ctl.wait, test_bit(CH_OPENED,
diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c
index b385592..8c74381 100644
--- a/drivers/usb/gadget/f_uac1.c
+++ b/drivers/usb/gadget/f_uac1.c
@@ -62,8 +62,6 @@
static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value);
static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
-DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
-DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
#define SPEAKER_INPUT_TERMINAL_ID 3
#define SPEAKER_OUTPUT_TERMINAL_ID 4
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 55fd59e..b408bfd 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -294,15 +294,17 @@
static inline enum chg_type usb_get_chg_type(struct usb_info *ui)
{
- if ((readl(USB_PORTSC) & PORTSC_LS) == PORTSC_LS)
+ if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
return USB_CHG_TYPE__WALLCHARGER;
- else {
+ } else if (ui->pdata->prop_chg) {
if (ui->gadget.speed == USB_SPEED_LOW ||
ui->gadget.speed == USB_SPEED_FULL ||
ui->gadget.speed == USB_SPEED_HIGH)
return USB_CHG_TYPE__SDP;
else
return USB_CHG_TYPE__INVALID;
+ } else {
+ return USB_CHG_TYPE__SDP;
}
}
@@ -332,7 +334,7 @@
if (temp == USB_CHG_TYPE__WALLCHARGER && !ui->proprietary_chg)
return USB_WALLCHARGER_CHG_CURRENT;
- else
+ else if (ui->pdata->prop_chg)
return USB_PROPRIETARY_CHG_CURRENT;
if (suspended || !configured)
@@ -514,6 +516,15 @@
{
struct usb_info *ui = ept->ui;
unsigned cfg = CONFIG_MAX_PKT(ept->ep.maxpacket) | CONFIG_ZLT;
+ const struct usb_endpoint_descriptor *desc = ept->ep.desc;
+ unsigned mult = 0;
+
+ if (desc && ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_ISOC)) {
+ cfg &= ~(CONFIG_MULT);
+ mult = ((ept->ep.maxpacket >> CONFIG_MULT_SHIFT) + 1) & 0x03;
+ cfg |= (mult << (ffs(CONFIG_MULT) - 1));
+ }
/* ep0 out needs interrupt-on-setup */
if (ept->bit == 0)
@@ -2049,6 +2060,54 @@
.write = debug_reprime_ep,
};
+static ssize_t debug_prop_chg_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct usb_info *ui = file->private_data;
+ char kbuf[2];
+
+ memset(kbuf, 0, sizeof(kbuf));
+
+ if (copy_from_user(kbuf, buf, sizeof(kbuf)))
+ return -EFAULT;
+
+ if (!strncmp(kbuf, "1", 1))
+ ui->pdata->prop_chg = 1;
+ else
+ ui->pdata->prop_chg = 0;
+
+ return count;
+}
+
+static ssize_t debug_prop_chg_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct usb_info *ui = file->private_data;
+ char kbuf[2];
+ size_t c = 0;
+
+ memset(kbuf, 0, sizeof(kbuf));
+
+ c = scnprintf(kbuf, sizeof(kbuf), "%d\n", ui->pdata->prop_chg);
+
+ if (copy_to_user(ubuf, kbuf, c))
+ return -EFAULT;
+
+ return simple_read_from_buffer(ubuf, count, ppos, kbuf, c);
+}
+
+static int debug_prop_chg_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+const struct file_operations debug_prop_chg_ops = {
+ .open = debug_prop_chg_open,
+ .read = debug_prop_chg_read,
+ .write = debug_prop_chg_write,
+};
+
static void usb_debugfs_init(struct usb_info *ui)
{
struct dentry *dent;
@@ -2063,6 +2122,8 @@
&debug_wlocks_ops);
debugfs_create_file("prime_fail_countt", 0666, dent, ui,
&prime_fail_ops);
+ debugfs_create_file("proprietary_chg", 0666, dent, ui,
+ &debug_prop_chg_ops);
}
#else
static void usb_debugfs_init(struct usb_info *ui) {}
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 45dfb87..f092329 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -50,7 +50,7 @@
#define BAM_MUX_RX_Q_SIZE 16
#define BAM_MUX_TX_Q_SIZE 200
-#define BAM_MUX_RX_REQ_SIZE (2048 - BAM_MUX_HDR)
+#define BAM_MUX_RX_REQ_SIZE 2048 /* Must be 1KB aligned */
#define DL_INTR_THRESHOLD 20
diff --git a/drivers/usb/gadget/u_data_hsuart.c b/drivers/usb/gadget/u_data_hsuart.c
index 74bb93f..4d88ea5 100644
--- a/drivers/usb/gadget/u_data_hsuart.c
+++ b/drivers/usb/gadget/u_data_hsuart.c
@@ -244,9 +244,7 @@
pr_debug("%s: port:%p tom:%lu pno:%d\n", __func__,
port, port->to_modem, port->port_num);
- spin_unlock_irqrestore(&port->rx_lock, flags);
ret = msm_smux_write(port->ch_id, skb, skb->data, skb->len);
- spin_lock_irqsave(&port->rx_lock, flags);
if (ret < 0) {
if (ret == -EAGAIN) {
/*flow control*/
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index b7f1878..6fe9e58 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -926,6 +926,8 @@
return 0;
}
+#ifdef CONFIG_PM
+
static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
{
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -1135,6 +1137,13 @@
return 0;
}
+#else
+
+#define ehci_hsic_bus_suspend NULL
+#define ehci_hsic_bus_resume NULL
+
+#endif /* CONFIG_PM */
+
static struct hc_driver msm_hsic_driver = {
.description = hcd_name,
.product_desc = "Qualcomm EHCI Host Controller using HSIC",
@@ -1279,6 +1288,7 @@
static irqreturn_t msm_hsic_wakeup_irq(int irq, void *data)
{
struct msm_hsic_hcd *mehci = data;
+ int ret;
mehci->wakeup_int_cnt++;
dbg_log_event(NULL, "Remote Wakeup IRQ", mehci->wakeup_int_cnt);
@@ -1296,8 +1306,17 @@
spin_unlock(&mehci->wakeup_lock);
if (!atomic_read(&mehci->pm_usage_cnt)) {
- atomic_set(&mehci->pm_usage_cnt, 1);
- pm_runtime_get(mehci->dev);
+ ret = pm_runtime_get(mehci->dev);
+ /*
+ * HSIC runtime resume can race with us.
+ * if we are active (ret == 1) or resuming
+ * (ret == -EINPROGRESS), decrement the
+ * PM usage counter before returning.
+ */
+ if ((ret == 1) || (ret == -EINPROGRESS))
+ pm_runtime_put_noidle(mehci->dev);
+ else
+ atomic_set(&mehci->pm_usage_cnt, 1);
}
return IRQ_HANDLED;
@@ -1522,6 +1541,8 @@
return -ENOMEM;
}
+ hcd_to_bus(hcd)->skip_resume = true;
+
hcd->irq = platform_get_irq(pdev, 0);
if (hcd->irq < 0) {
dev_err(&pdev->dev, "Unable to get IRQ resource\n");
@@ -1791,6 +1812,15 @@
if (device_may_wakeup(dev))
disable_irq_wake(hcd->irq);
+ /*
+ * Keep HSIC in Low Power Mode if system is resumed
+ * by any other wakeup source. HSIC is resumed later
+ * when remote wakeup is received or interface driver
+ * start I/O.
+ */
+ if (!atomic_read(&mehci->pm_usage_cnt))
+ return 0;
+
ret = msm_hsic_resume(mehci);
if (ret)
return ret;
diff --git a/drivers/usb/misc/ks_bridge.c b/drivers/usb/misc/ks_bridge.c
index 87f43e1c..61e6891 100644
--- a/drivers/usb/misc/ks_bridge.c
+++ b/drivers/usb/misc/ks_bridge.c
@@ -48,6 +48,7 @@
#define BOOT_BRIDGE_INDEX 0
#define EFS_BRIDGE_INDEX 1
#define MAX_DATA_PKT_SIZE 16384
+#define PENDING_URB_TIMEOUT 10
struct ks_bridge {
char *name;
@@ -58,7 +59,10 @@
struct list_head to_mdm_list;
struct list_head to_ks_list;
wait_queue_head_t ks_wait_q;
+ wait_queue_head_t pending_urb_wait;
struct miscdevice *fs_dev;
+ atomic_t tx_pending_cnt;
+ atomic_t rx_pending_cnt;
/* usb specific */
struct usb_device *udev;
@@ -168,11 +172,10 @@
size_t len;
pkt = list_first_entry(&ksb->to_ks_list, struct data_pkt, list);
- len = min_t(size_t, space, pkt->len);
- pkt->n_read += len;
+ len = min_t(size_t, space, pkt->len - pkt->n_read);
spin_unlock_irqrestore(&ksb->lock, flags);
- ret = copy_to_user(buf + copied, pkt->buf, len);
+ ret = copy_to_user(buf + copied, pkt->buf + pkt->n_read, len);
if (ret) {
pr_err("copy_to_user failed err:%d\n", ret);
ksb_free_data_pkt(pkt);
@@ -180,6 +183,7 @@
return ret;
}
+ pkt->n_read += len;
space -= len;
copied += len;
@@ -207,13 +211,16 @@
dbg_log_event(ksb, "C TX_URB", urb->status, 0);
pr_debug("status:%d", urb->status);
- if (ksb->ifc)
+ if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
usb_autopm_put_interface_async(ksb->ifc);
if (urb->status < 0)
pr_err_ratelimited("urb failed with err:%d", urb->status);
ksb_free_data_pkt(pkt);
+
+ atomic_dec(&ksb->tx_pending_cnt);
+ wake_up(&ksb->pending_urb_wait);
}
static void ksb_tomdm_work(struct work_struct *w)
@@ -252,6 +259,7 @@
dbg_log_event(ksb, "S TX_URB", pkt->len, 0);
+ atomic_inc(&ksb->tx_pending_cnt);
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret) {
pr_err("out urb submission failed");
@@ -259,6 +267,8 @@
usb_free_urb(urb);
ksb_free_data_pkt(pkt);
usb_autopm_put_interface(ksb->ifc);
+ atomic_dec(&ksb->tx_pending_cnt);
+ wake_up(&ksb->pending_urb_wait);
return;
}
@@ -420,8 +430,15 @@
ksb_rx_cb, pkt);
usb_anchor_urb(urb, &ksb->submitted);
- dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
+ if (!test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
+ usb_unanchor_urb(urb);
+ usb_free_urb(urb);
+ ksb_free_data_pkt(pkt);
+ ksb->alloced_read_pkts--;
+ return;
+ }
+ atomic_inc(&ksb->rx_pending_cnt);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret) {
pr_err("in urb submission failed");
@@ -429,9 +446,13 @@
usb_free_urb(urb);
ksb_free_data_pkt(pkt);
ksb->alloced_read_pkts--;
+ atomic_dec(&ksb->rx_pending_cnt);
+ wake_up(&ksb->pending_urb_wait);
return;
}
+ dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
+
usb_free_urb(urb);
}
static void ksb_rx_cb(struct urb *urb)
@@ -454,7 +475,7 @@
urb->status);
ksb_free_data_pkt(pkt);
ksb->alloced_read_pkts--;
- return;
+ goto done;
}
if (urb->actual_length == 0) {
@@ -474,7 +495,9 @@
resubmit_urb:
submit_one_urb(ksb);
-
+done:
+ atomic_dec(&ksb->rx_pending_cnt);
+ wake_up(&ksb->pending_urb_wait);
}
static void ksb_start_rx_work(struct work_struct *w)
@@ -487,6 +510,10 @@
int ret;
for (i = 0; i < NO_RX_REQS; i++) {
+
+ if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
+ return;
+
pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
if (IS_ERR(pkt)) {
pr_err("unable to allocate data pkt");
@@ -516,6 +543,7 @@
dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
+ atomic_inc(&ksb->rx_pending_cnt);
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret) {
pr_err("in urb submission failed");
@@ -524,6 +552,8 @@
ksb_free_data_pkt(pkt);
ksb->alloced_read_pkts--;
usb_autopm_put_interface(ksb->ifc);
+ atomic_dec(&ksb->rx_pending_cnt);
+ wake_up(&ksb->pending_urb_wait);
return;
}
@@ -590,6 +620,8 @@
usb_set_intfdata(ifc, ksb);
set_bit(USB_DEV_CONNECTED, &ksb->flags);
+ atomic_set(&ksb->tx_pending_cnt, 0);
+ atomic_set(&ksb->rx_pending_cnt, 0);
dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
@@ -640,9 +672,16 @@
clear_bit(USB_DEV_CONNECTED, &ksb->flags);
wake_up(&ksb->ks_wait_q);
cancel_work_sync(&ksb->to_mdm_work);
+ cancel_work_sync(&ksb->start_rx_work);
usb_kill_anchored_urbs(&ksb->submitted);
+ wait_event_interruptible_timeout(
+ ksb->pending_urb_wait,
+ !atomic_read(&ksb->tx_pending_cnt) &&
+ !atomic_read(&ksb->rx_pending_cnt),
+ msecs_to_jiffies(PENDING_URB_TIMEOUT));
+
spin_lock_irqsave(&ksb->lock, flags);
while (!list_empty(&ksb->to_ks_list)) {
pkt = list_first_entry(&ksb->to_ks_list,
@@ -741,6 +780,7 @@
INIT_LIST_HEAD(&ksb->to_mdm_list);
INIT_LIST_HEAD(&ksb->to_ks_list);
init_waitqueue_head(&ksb->ks_wait_q);
+ init_waitqueue_head(&ksb->pending_urb_wait);
ksb->wq = create_singlethread_workqueue(ksb->name);
if (!ksb->wq) {
pr_err("unable to allocate workqueue");
diff --git a/drivers/usb/otg/msm72k_otg.c b/drivers/usb/otg/msm72k_otg.c
index f62ae76..ca1b155 100644
--- a/drivers/usb/otg/msm72k_otg.c
+++ b/drivers/usb/otg/msm72k_otg.c
@@ -1229,7 +1229,7 @@
static irqreturn_t msm_otg_irq(int irq, void *data)
{
struct msm_otg *dev = data;
- u32 otgsc, sts, pc, sts_mask;
+ u32 otgsc, sts, pc;
irqreturn_t ret = IRQ_HANDLED;
int work = 0;
enum usb_otg_state state;
@@ -1250,12 +1250,16 @@
otgsc = readl(USB_OTGSC);
sts = readl(USB_USBSTS);
- sts_mask = (otgsc & OTGSC_INTR_MASK) >> 8;
-
- if (!((otgsc & sts_mask) || (sts & STS_PCI))) {
+ /* At times during USB disconnect, hardware generates 1MSIS interrupt
+ * during PHY reset, which leads to irq not handled error as IRQ_NONE
+ * is notified. To workaround this issue, check for all the
+ * OTG_INTR_STS_MASK bits and if set, clear them and notify IRQ_HANDLED.
+ */
+ if (!((otgsc & OTGSC_INTR_STS_MASK) || (sts & STS_PCI))) {
ret = IRQ_NONE;
goto out;
}
+ writel_relaxed(otgsc, USB_OTGSC);
spin_lock_irqsave(&dev->lock, flags);
state = dev->phy.state;
@@ -1277,10 +1281,8 @@
set_bit(A_BUS_REQ, &dev->inputs);
clear_bit(ID, &dev->inputs);
}
- writel(otgsc, USB_OTGSC);
work = 1;
} else if (otgsc & OTGSC_BSVIS) {
- writel(otgsc, USB_OTGSC);
/* BSV interrupt comes when operating as an A-device
* (VBUS on/off).
* But, handle BSV when charger is removed from ACA in ID_A
@@ -1298,7 +1300,6 @@
work = 1;
} else if (otgsc & OTGSC_DPIS) {
pr_debug("DPIS detected\n");
- writel(otgsc, USB_OTGSC);
set_bit(A_SRP_DET, &dev->inputs);
set_bit(A_BUS_REQ, &dev->inputs);
work = 1;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 998978c..f27e0eb 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -52,6 +52,7 @@
#define DRIVER_NAME "msm_otg"
#define ID_TIMER_FREQ (jiffies + msecs_to_jiffies(500))
+#define CHG_RECHECK_DELAY (jiffies + msecs_to_jiffies(2000))
#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */
#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */
@@ -76,6 +77,11 @@
USB_PHY_REG_LPM_OFF,
};
+static char *override_phy_init;
+module_param(override_phy_init, charp, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(override_phy_init,
+ "Override HSUSB PHY Init Settings");
+
static DECLARE_COMPLETION(pmic_vbus_init);
static struct msm_otg *the_msm_otg;
static bool debug_aca_enabled;
@@ -383,12 +389,26 @@
static void ulpi_init(struct msm_otg *motg)
{
struct msm_otg_platform_data *pdata = motg->pdata;
- int *seq = pdata->phy_init_seq;
+ int aseq[10];
+ int *seq = NULL;
+
+ if (override_phy_init) {
+ pr_debug("%s(): HUSB PHY Init:%s\n", __func__,
+ override_phy_init);
+ get_options(override_phy_init, ARRAY_SIZE(aseq), aseq);
+ seq = &aseq[1];
+ } else {
+ seq = pdata->phy_init_seq;
+ }
if (!seq)
return;
while (seq[0] >= 0) {
+ if (override_phy_init)
+ pr_debug("ulpi: write 0x%02x to 0x%02x\n",
+ seq[0], seq[1]);
+
dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
seq[0], seq[1]);
ulpi_write(&motg->phy, seq[0], seq[1]);
@@ -1629,6 +1649,26 @@
return ret;
}
+static void msm_otg_chg_check_timer_func(unsigned long data)
+{
+ struct msm_otg *motg = (struct msm_otg *) data;
+ struct usb_otg *otg = motg->phy.otg;
+
+ if (atomic_read(&motg->in_lpm) ||
+ !test_bit(B_SESS_VLD, &motg->inputs) ||
+ otg->phy->state != OTG_STATE_B_PERIPHERAL ||
+ otg->gadget->speed != USB_SPEED_UNKNOWN) {
+ dev_dbg(otg->phy->dev, "Nothing to do in chg_check_timer\n");
+ return;
+ }
+
+ if ((readl_relaxed(USB_PORTSC) & PORTSC_LS) == PORTSC_LS) {
+ dev_dbg(otg->phy->dev, "DCP is detected as SDP\n");
+ set_bit(B_FALSE_SDP, &motg->inputs);
+ queue_work(system_nrt_wq, &motg->sm_work);
+ }
+}
+
static bool msm_chg_aca_detect(struct msm_otg *motg)
{
struct usb_phy *phy = &motg->phy;
@@ -2001,6 +2041,8 @@
udelay(20);
break;
case SNPS_28NM_INTEGRATED_PHY:
+ /* disable DP and DM pull down resistors */
+ ulpi_write(phy, 0x6, 0xC);
/* Clear charger detecting control bits */
ulpi_write(phy, 0x1F, 0x86);
/* Clear alt interrupt latch and enable bits */
@@ -2080,8 +2122,7 @@
switch (motg->chg_state) {
case USB_CHG_STATE_UNDEFINED:
msm_chg_block_on(motg);
- if (motg->pdata->enable_dcd)
- msm_chg_enable_dcd(motg);
+ msm_chg_enable_dcd(motg);
msm_chg_enable_aca_det(motg);
motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
motg->dcd_retries = 0;
@@ -2108,12 +2149,10 @@
break;
}
}
- if (motg->pdata->enable_dcd)
- is_dcd = msm_chg_check_dcd(motg);
+ is_dcd = msm_chg_check_dcd(motg);
tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES;
if (is_dcd || tmout) {
- if (motg->pdata->enable_dcd)
- msm_chg_disable_dcd(motg);
+ msm_chg_disable_dcd(motg);
msm_chg_enable_primary_det(motg);
delay = MSM_CHG_PRIMARY_DET_TIME;
motg->chg_state = USB_CHG_STATE_DCD_DONE;
@@ -2347,6 +2386,8 @@
msm_otg_start_peripheral(otg, 1);
otg->phy->state =
OTG_STATE_B_PERIPHERAL;
+ mod_timer(&motg->chg_check_timer,
+ CHG_RECHECK_DELAY);
break;
default:
break;
@@ -2367,6 +2408,8 @@
break;
} else {
pr_debug("chg_work cancel");
+ del_timer_sync(&motg->chg_check_timer);
+ clear_bit(B_FALSE_SDP, &motg->inputs);
cancel_delayed_work_sync(&motg->chg_work);
motg->chg_state = USB_CHG_STATE_UNDEFINED;
motg->chg_type = USB_INVALID_CHARGER;
@@ -2404,7 +2447,15 @@
}
break;
case OTG_STATE_B_PERIPHERAL:
- if (!test_bit(ID, &motg->inputs) ||
+ if (test_bit(B_SESS_VLD, &motg->inputs) &&
+ test_bit(B_FALSE_SDP, &motg->inputs)) {
+ pr_debug("B_FALSE_SDP\n");
+ msm_otg_start_peripheral(otg, 0);
+ motg->chg_type = USB_DCP_CHARGER;
+ clear_bit(B_FALSE_SDP, &motg->inputs);
+ otg->phy->state = OTG_STATE_B_IDLE;
+ work = 1;
+ } else if (!test_bit(ID, &motg->inputs) ||
test_bit(ID_A, &motg->inputs) ||
test_bit(ID_B, &motg->inputs) ||
!test_bit(B_SESS_VLD, &motg->inputs)) {
@@ -3709,6 +3760,8 @@
INIT_DELAYED_WORK(&motg->suspend_work, msm_otg_suspend_work);
setup_timer(&motg->id_timer, msm_otg_id_timer_func,
(unsigned long) motg);
+ setup_timer(&motg->chg_check_timer, msm_otg_chg_check_timer_func,
+ (unsigned long) motg);
ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED,
"msm_otg", motg);
if (ret) {
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 54d7090..ed4c25d 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -820,14 +820,6 @@
---help---
Support for DVI mode for MSM HDMI 1080p Panel
-config FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- depends on FB_MSM_HDMI_MSM_PANEL
- bool "Use HDCP mode"
- default y
- ---help---
- Support for HDCP mode for MSM HDMI 1080p Panel
- Choose to enable HDCP
-
config FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
depends on FB_MSM_HDMI_MSM_PANEL
bool "Enable CEC"
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 902e92c..deef4ab 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -60,18 +60,16 @@
struct workqueue_struct *hdmi_work_queue;
struct hdmi_msm_state_type *hdmi_msm_state;
+/* Enable HDCP by default */
+static bool hdcp_feature_on = true;
+
DEFINE_MUTEX(hdmi_msm_state_mutex);
EXPORT_SYMBOL(hdmi_msm_state_mutex);
static DEFINE_MUTEX(hdcp_auth_state_mutex);
static void hdmi_msm_dump_regs(const char *prefix);
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
static void hdmi_msm_hdcp_enable(void);
-#else
-static inline void hdmi_msm_hdcp_enable(void) {}
-#endif
-
static void hdmi_msm_turn_on(void);
static int hdmi_msm_audio_off(void);
static int hdmi_msm_read_edid(void);
@@ -675,7 +673,6 @@
case 0x00D8: return "ACR_48_1";
case 0x00E4: return "AUDIO_INFO0";
case 0x00E8: return "AUDIO_INFO1";
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
case 0x0110: return "HDCP_CTRL";
case 0x0114: return "HDCP_DEBUG_CTRL";
case 0x0118: return "HDCP_INT_CTRL";
@@ -690,7 +687,6 @@
case 0x014C: return "HDCP_RCVPORT_DATA5";
case 0x0150: return "HDCP_RCVPORT_DATA6";
case 0x0168: return "HDCP_RCVPORT_DATA12";
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
case 0x01D0: return "AUDIO_CFG";
case 0x0208: return "USEC_REFTIMER";
case 0x020C: return "DDC_CTRL";
@@ -705,14 +701,10 @@
case 0x0250: return "HPD_INT_STATUS";
case 0x0254: return "HPD_INT_CTRL";
case 0x0258: return "HPD_CTRL";
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
case 0x025C: return "HDCP_ENTROPY_CTRL1";
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
case 0x027C: return "DDC_REF";
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
case 0x0284: return "HDCP_SW_UPPER_AKSV";
case 0x0288: return "HDCP_SW_LOWER_AKSV";
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
case 0x02B4: return "ACTIVE_H";
case 0x02B8: return "ACTIVE_V";
case 0x02BC: return "ACTIVE_V_F2";
@@ -781,7 +773,7 @@
DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n");
kobject_uevent(external_common_state->uevent_kobj, KOBJ_ONLINE);
- if (!external_common_state->present_hdcp) {
+ if (!hdmi_msm_state->hdcp_enable) {
/* Send Audio for HDMI Compliance Cases*/
envp[0] = "HDCP_STATE=PASS";
envp[1] = NULL;
@@ -870,10 +862,13 @@
}
#endif
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
static void hdcp_deauthenticate(void);
static void hdmi_msm_hdcp_reauth_work(struct work_struct *work)
{
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return;
+ }
/* Don't process recursive actions */
mutex_lock(&hdmi_msm_state_mutex);
@@ -891,17 +886,20 @@
* Therefore, as surprising as it may sound do reauth
* only if the device is HDCP-capable
*/
- if (external_common_state->present_hdcp) {
- hdcp_deauthenticate();
- mutex_lock(&hdcp_auth_state_mutex);
- hdmi_msm_state->reauth = TRUE;
- mutex_unlock(&hdcp_auth_state_mutex);
- mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
- }
+ hdcp_deauthenticate();
+ mutex_lock(&hdcp_auth_state_mutex);
+ hdmi_msm_state->reauth = TRUE;
+ mutex_unlock(&hdcp_auth_state_mutex);
+ mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
}
static void hdmi_msm_hdcp_work(struct work_struct *work)
{
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return;
+ }
+
/* Only re-enable if cable still connected */
mutex_lock(&external_common_state_hpd_mutex);
if (external_common_state->hpd_state &&
@@ -922,7 +920,111 @@
hdmi_msm_state->reauth = FALSE;
}
}
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
+
+int hdmi_msm_process_hdcp_interrupts(void)
+{
+ int rc = -1;
+ uint32 hdcp_int_val;
+ char *envp[2];
+
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return -EINVAL;
+ }
+
+ /* HDCP_INT_CTRL[0x0118]
+ * [0] AUTH_SUCCESS_INT [R] HDCP Authentication Success
+ * interrupt status
+ * [1] AUTH_SUCCESS_ACK [W] Acknowledge bit for HDCP
+ * Authentication Success bit - write 1 to clear
+ * [2] AUTH_SUCCESS_MASK [R/W] Mask bit for HDCP Authentication
+ * Success interrupt - set to 1 to enable interrupt */
+ hdcp_int_val = HDMI_INP_ND(0x0118);
+ if ((hdcp_int_val & (1 << 2)) && (hdcp_int_val & (1 << 0))) {
+ /* AUTH_SUCCESS_INT */
+ HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 1)) & ~(1 << 0));
+ DEV_INFO("HDCP: AUTH_SUCCESS_INT received\n");
+ complete_all(&hdmi_msm_state->hdcp_success_done);
+ return 0;
+ }
+
+ /* [4] AUTH_FAIL_INT [R] HDCP Authentication Lost
+ * interrupt Status
+ * [5] AUTH_FAIL_ACK [W] Acknowledge bit for HDCP
+ * Authentication Lost bit - write 1 to clear
+ * [6] AUTH_FAIL_MASK [R/W] Mask bit fo HDCP Authentication
+ * Lost interrupt set to 1 to enable interrupt
+ * [7] AUTH_FAIL_INFO_ACK [W] Acknowledge bit for HDCP
+ * Authentication Failure Info field - write 1 to clear */
+ if ((hdcp_int_val & (1 << 6)) && (hdcp_int_val & (1 << 4))) {
+ /* AUTH_FAIL_INT */
+ /* Clear and Disable */
+ uint32 link_status = HDMI_INP_ND(0x011C);
+ HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 5))
+ & ~((1 << 6) | (1 << 4)));
+ DEV_INFO("HDCP: AUTH_FAIL_INT received, LINK0_STATUS=0x%08x\n",
+ link_status);
+ if (hdmi_msm_state->full_auth_done) {
+ switch_set_state(&external_common_state->sdev, 0);
+ DEV_INFO("Hdmi state switched to %d: %s\n",
+ external_common_state->sdev.state, __func__);
+
+ envp[0] = "HDCP_STATE=FAIL";
+ envp[1] = NULL;
+ DEV_INFO("HDMI HPD:QDSP OFF\n");
+ kobject_uevent_env(external_common_state->uevent_kobj,
+ KOBJ_CHANGE, envp);
+
+ mutex_lock(&hdcp_auth_state_mutex);
+ hdmi_msm_state->full_auth_done = FALSE;
+ mutex_unlock(&hdcp_auth_state_mutex);
+ /* Calling reauth only when authentication
+ * is sucessful or else we always go into
+ * the reauth loop. Also, No need to reauthenticate
+ * if authentication failed because of cable disconnect
+ */
+ if (((link_status & 0xF0) >> 4) != 0x7) {
+ DEV_DBG("Reauthenticate From %s HDCP FAIL INT ",
+ __func__);
+ queue_work(hdmi_work_queue,
+ &hdmi_msm_state->hdcp_reauth_work);
+ } else {
+ DEV_INFO("HDCP: HDMI cable disconnected\n");
+ }
+ }
+
+ /* Clear AUTH_FAIL_INFO as well */
+ HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 7)));
+ return 0;
+ }
+
+ /* [8] DDC_XFER_REQ_INT [R] HDCP DDC Transfer Request
+ * interrupt status
+ * [9] DDC_XFER_REQ_ACK [W] Acknowledge bit for HDCP DDC
+ * Transfer Request bit - write 1 to clear
+ * [10] DDC_XFER_REQ_MASK [R/W] Mask bit for HDCP DDC Transfer
+ * Request interrupt - set to 1 to enable interrupt */
+ if ((hdcp_int_val & (1 << 10)) && (hdcp_int_val & (1 << 8))) {
+ /* DDC_XFER_REQ_INT */
+ HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 9)) & ~(1 << 8));
+ if (!(hdcp_int_val & (1 << 12)))
+ return 0;
+ }
+ /* [12] DDC_XFER_DONE_INT [R] HDCP DDC Transfer done interrupt
+ * status
+ * [13] DDC_XFER_DONE_ACK [W] Acknowledge bit for HDCP DDC
+ * Transfer done bit - write 1 to clear
+ * [14] DDC_XFER_DONE_MASK [R/W] Mask bit for HDCP DDC Transfer
+ * done interrupt - set to 1 to enable interrupt */
+ if ((hdcp_int_val & (1 << 14)) && (hdcp_int_val & (1 << 12))) {
+ /* DDC_XFER_DONE_INT */
+ HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 13)) & ~(1 << 12));
+ DEV_INFO("HDCP: DDC_XFER_DONE received\n");
+ return 0;
+ }
+
+ return rc;
+}
static irqreturn_t hdmi_msm_isr(int irq, void *dev_id)
{
@@ -933,10 +1035,6 @@
#endif
uint32 ddc_int_ctrl;
uint32 audio_int_val;
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- uint32 hdcp_int_val;
- char *envp[2];
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
static uint32 fifo_urun_int_occurred;
static uint32 sample_drop_int_occurred;
const uint32 occurrence_limit = 5;
@@ -1054,96 +1152,8 @@
return IRQ_HANDLED;
}
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- /* HDCP_INT_CTRL[0x0118]
- * [0] AUTH_SUCCESS_INT [R] HDCP Authentication Success
- * interrupt status
- * [1] AUTH_SUCCESS_ACK [W] Acknowledge bit for HDCP
- * Authentication Success bit - write 1 to clear
- * [2] AUTH_SUCCESS_MASK [R/W] Mask bit for HDCP Authentication
- * Success interrupt - set to 1 to enable interrupt */
- hdcp_int_val = HDMI_INP_ND(0x0118);
- if ((hdcp_int_val & (1 << 2)) && (hdcp_int_val & (1 << 0))) {
- /* AUTH_SUCCESS_INT */
- HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 1)) & ~(1 << 0));
- DEV_INFO("HDCP: AUTH_SUCCESS_INT received\n");
- complete_all(&hdmi_msm_state->hdcp_success_done);
+ if (!hdmi_msm_process_hdcp_interrupts())
return IRQ_HANDLED;
- }
- /* [4] AUTH_FAIL_INT [R] HDCP Authentication Lost
- * interrupt Status
- * [5] AUTH_FAIL_ACK [W] Acknowledge bit for HDCP
- * Authentication Lost bit - write 1 to clear
- * [6] AUTH_FAIL_MASK [R/W] Mask bit fo HDCP Authentication
- * Lost interrupt set to 1 to enable interrupt
- * [7] AUTH_FAIL_INFO_ACK [W] Acknowledge bit for HDCP
- * Authentication Failure Info field - write 1 to clear */
- if ((hdcp_int_val & (1 << 6)) && (hdcp_int_val & (1 << 4))) {
- /* AUTH_FAIL_INT */
- /* Clear and Disable */
- uint32 link_status = HDMI_INP_ND(0x011C);
- HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 5))
- & ~((1 << 6) | (1 << 4)));
- DEV_INFO("HDCP: AUTH_FAIL_INT received, LINK0_STATUS=0x%08x\n",
- link_status);
- if (hdmi_msm_state->full_auth_done) {
- switch_set_state(&external_common_state->sdev, 0);
- DEV_INFO("Hdmi state switched to %d: %s\n",
- external_common_state->sdev.state, __func__);
-
- envp[0] = "HDCP_STATE=FAIL";
- envp[1] = NULL;
- DEV_INFO("HDMI HPD:QDSP OFF\n");
- kobject_uevent_env(external_common_state->uevent_kobj,
- KOBJ_CHANGE, envp);
-
- mutex_lock(&hdcp_auth_state_mutex);
- hdmi_msm_state->full_auth_done = FALSE;
- mutex_unlock(&hdcp_auth_state_mutex);
- /* Calling reauth only when authentication
- * is sucessful or else we always go into
- * the reauth loop. Also, No need to reauthenticate
- * if authentication failed because of cable disconnect
- */
- if (((link_status & 0xF0) >> 4) != 0x7) {
- DEV_DBG("Reauthenticate From %s HDCP FAIL INT ",
- __func__);
- queue_work(hdmi_work_queue,
- &hdmi_msm_state->hdcp_reauth_work);
- } else {
- DEV_INFO("HDCP: HDMI cable disconnected\n");
- }
- }
-
- /* Clear AUTH_FAIL_INFO as well */
- HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 7)));
- return IRQ_HANDLED;
- }
- /* [8] DDC_XFER_REQ_INT [R] HDCP DDC Transfer Request
- * interrupt status
- * [9] DDC_XFER_REQ_ACK [W] Acknowledge bit for HDCP DDC
- * Transfer Request bit - write 1 to clear
- * [10] DDC_XFER_REQ_MASK [R/W] Mask bit for HDCP DDC Transfer
- * Request interrupt - set to 1 to enable interrupt */
- if ((hdcp_int_val & (1 << 10)) && (hdcp_int_val & (1 << 8))) {
- /* DDC_XFER_REQ_INT */
- HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 9)) & ~(1 << 8));
- if (!(hdcp_int_val & (1 << 12)))
- return IRQ_HANDLED;
- }
- /* [12] DDC_XFER_DONE_INT [R] HDCP DDC Transfer done interrupt
- * status
- * [13] DDC_XFER_DONE_ACK [W] Acknowledge bit for HDCP DDC
- * Transfer done bit - write 1 to clear
- * [14] DDC_XFER_DONE_MASK [R/W] Mask bit for HDCP DDC Transfer
- * done interrupt - set to 1 to enable interrupt */
- if ((hdcp_int_val & (1 << 14)) && (hdcp_int_val & (1 << 12))) {
- /* DDC_XFER_DONE_INT */
- HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 13)) & ~(1 << 12));
- DEV_INFO("HDCP: DDC_XFER_DONE received\n");
- return IRQ_HANDLED;
- }
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
/* Process CEC Interrupt */
@@ -1302,7 +1312,7 @@
if (external_common_state->hdmi_sink == 0) {
/* HDMI_DVI_SEL */
reg_val |= 0x00000002;
- if (external_common_state->present_hdcp)
+ if (hdmi_msm_state->hdcp_enable)
/* HDMI Encryption */
reg_val |= 0x00000004;
/* HDMI_CTRL */
@@ -1310,7 +1320,7 @@
/* HDMI_DVI_SEL */
reg_val &= ~0x00000002;
} else {
- if (external_common_state->present_hdcp)
+ if (hdmi_msm_state->hdcp_enable)
/* HDMI_Encryption_ON */
reg_val |= 0x00000006;
else
@@ -1390,7 +1400,6 @@
return 0;
}
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
static int hdmi_msm_ddc_write(uint32 dev_addr, uint32 offset,
const uint8 *data_buf, uint32 data_len, const char *what)
{
@@ -1586,7 +1595,6 @@
error:
return status;
}
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
static int hdmi_msm_ddc_read_retry(uint32 dev_addr, uint32 offset,
uint8 *data_buf, uint32 data_len, uint32 request_len, int retry,
@@ -2147,9 +2155,13 @@
return status;
}
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
static void hdcp_auth_info(uint32 auth_info)
{
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return;
+ }
+
switch (auth_info) {
case 0:
DEV_INFO("%s: None", __func__);
@@ -2184,6 +2196,11 @@
static void hdcp_key_state(uint32 key_state)
{
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return;
+ }
+
switch (key_state) {
case 0:
DEV_WARN("%s: No HDCP Keys", __func__);
@@ -2227,6 +2244,11 @@
{
int hdcp_link_status = HDMI_INP(0x011C);
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return;
+ }
+
/* Disable HDCP interrupts */
HDMI_OUTP(0x0118, 0x0);
@@ -2254,6 +2276,11 @@
int failure;
int nack0;
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return;
+ }
+
/*
* Check for any DDC transfer failures
* 0x0128 HDCP_DDC_STATUS
@@ -2364,6 +2391,11 @@
static uint8 buf[0xFF];
memset(buf, 0, sizeof(buf));
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return 0;
+ }
+
if (!is_part1_done) {
is_part1_done = TRUE;
@@ -2651,6 +2683,11 @@
int ret;
uint8 buf[4];
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return 0;
+ }
+
snprintf(what, sizeof(what), "V' H0");
ret = hdmi_msm_ddc_read(0x74, 0x20, buf, 4, 5, what, TRUE);
if (ret) {
@@ -2743,6 +2780,11 @@
boolean ksv_done = FALSE;
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return 0;
+ }
+
memset(buf, 0, sizeof(buf));
memset(kvs_fifo, 0, sizeof(kvs_fifo));
@@ -2935,6 +2977,12 @@
{
int ret = 0;
int poll = 3000;
+
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return 0;
+ }
+
while (poll) {
/* 0x011C HDCP_LINK0_STATUS
[30:28] KEYS_STATE = 3 = "Valid"
@@ -2965,7 +3013,7 @@
uint32 found_repeater = 0x0;
char *envp[2];
- if (!hdmi_msm_has_hdcp()) {
+ if (!hdmi_msm_state->hdcp_enable) {
DEV_INFO("%s: HDCP NOT ENABLED\n", __func__);
return;
}
@@ -3066,7 +3114,6 @@
DEV_INFO("Hdmi state switched to %d: %s\n",
external_common_state->sdev.state, __func__);
}
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
static void hdmi_msm_video_setup(int video_format)
{
@@ -3584,11 +3631,9 @@
{
msm_hdmi_sample_rate = rate;
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- if (hdmi_msm_has_hdcp())
+ if (hdmi_msm_state->hdcp_enable)
hdcp_deauthenticate();
else
-#endif
hdmi_msm_turn_on();
}
EXPORT_SYMBOL(hdmi_msm_audio_sample_rate_reset);
@@ -4158,12 +4203,10 @@
#endif
hdmi_msm_spd_infoframe_packetsetup();
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- if (hdmi_msm_state->reauth) {
+ if (hdmi_msm_state->hdcp_enable && hdmi_msm_state->reauth) {
hdmi_msm_hdcp_enable();
hdmi_msm_state->reauth = FALSE ;
}
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
/* re-initialize CEC if enabled */
@@ -4208,12 +4251,15 @@
}
}
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
static void hdmi_msm_hdcp_timer(unsigned long data)
{
+ if (!hdmi_msm_state->hdcp_enable) {
+ DEV_DBG("%s: HDCP not enabled\n", __func__);
+ return;
+ }
+
queue_work(hdmi_work_queue, &hdmi_msm_state->hdcp_work);
}
-#endif
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
static void hdmi_msm_cec_read_timer_func(unsigned long data)
@@ -4378,12 +4424,14 @@
mutex_unlock(&external_common_state_hpd_mutex);
hdmi_msm_turn_on();
- /* Kick off HDCP Authentication */
- mutex_lock(&hdcp_auth_state_mutex);
- hdmi_msm_state->reauth = FALSE;
- hdmi_msm_state->full_auth_done = FALSE;
- mutex_unlock(&hdcp_auth_state_mutex);
- mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
+ if (hdmi_msm_state->hdcp_enable) {
+ /* Kick off HDCP Authentication */
+ mutex_lock(&hdcp_auth_state_mutex);
+ hdmi_msm_state->reauth = FALSE;
+ hdmi_msm_state->full_auth_done = FALSE;
+ mutex_unlock(&hdcp_auth_state_mutex);
+ mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2);
+ }
} else
mutex_unlock(&external_common_state_hpd_mutex);
@@ -4407,16 +4455,14 @@
external_common_state->sdev.state, __func__);
if (on) {
hdmi_msm_read_edid();
- if (hdmi_msm_has_hdcp())
- hdmi_msm_state->reauth = FALSE ;
+ hdmi_msm_state->reauth = FALSE ;
/* Build EDID table */
hdmi_msm_turn_on();
DEV_INFO("HDMI HPD: CONNECTED: send ONLINE\n");
kobject_uevent(external_common_state->uevent_kobj,
KOBJ_ONLINE);
- hdmi_msm_hdcp_enable();
envp[0] = 0;
- if (!hdmi_msm_has_hdcp()) {
+ if (!hdmi_msm_state->hdcp_enable) {
/* Send Audio for HDMI Compliance Cases*/
envp[0] = "HDCP_STATE=PASS";
envp[1] = NULL;
@@ -4426,6 +4472,8 @@
switch_set_state(&external_common_state->sdev, 1);
DEV_INFO("Hdmi state switched to %d: %s\n",
external_common_state->sdev.state, __func__);
+ } else {
+ hdmi_msm_hdcp_enable();
}
} else {
DEV_INFO("HDMI HPD: DISCONNECTED: send OFFLINE\n");
@@ -4449,7 +4497,6 @@
if (!hdmi_msm_state->hdmi_app_clk)
return -ENODEV;
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
mutex_lock(&hdmi_msm_state_mutex);
if (hdmi_msm_state->hdcp_activating) {
hdmi_msm_state->panel_power_on = FALSE;
@@ -4458,13 +4505,10 @@
return 0;
}
mutex_unlock(&hdmi_msm_state_mutex);
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
DEV_INFO("power: OFF (audio off, Reset Core)\n");
hdmi_msm_audio_off();
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
hdcp_deauthenticate();
-#endif
hdmi_msm_powerdown_phy();
hdmi_msm_state->panel_power_on = FALSE;
@@ -4476,6 +4520,28 @@
return hdmi_msm_state->is_mhl_enabled;
}
+void hdmi_msm_config_hdcp_feature(void)
+{
+ if (hdcp_feature_on && hdmi_msm_has_hdcp()) {
+ init_timer(&hdmi_msm_state->hdcp_timer);
+ hdmi_msm_state->hdcp_timer.function = hdmi_msm_hdcp_timer;
+ hdmi_msm_state->hdcp_timer.data = (uint32)NULL;
+ hdmi_msm_state->hdcp_timer.expires = 0xffffffffL;
+
+ init_completion(&hdmi_msm_state->hdcp_success_done);
+ INIT_WORK(&hdmi_msm_state->hdcp_reauth_work,
+ hdmi_msm_hdcp_reauth_work);
+ INIT_WORK(&hdmi_msm_state->hdcp_work, hdmi_msm_hdcp_work);
+ hdmi_msm_state->hdcp_enable = TRUE;
+ } else {
+ del_timer(&hdmi_msm_state->hdcp_timer);
+ hdmi_msm_state->hdcp_enable = FALSE;
+ }
+ external_common_state->present_hdcp = hdmi_msm_state->hdcp_enable;
+ DEV_INFO("%s: HDCP Feature: %s\n", __func__,
+ hdmi_msm_state->hdcp_enable ? "Enabled" : "Disabled");
+}
+
static int __devinit hdmi_msm_probe(struct platform_device *pdev)
{
int rc;
@@ -4588,15 +4654,6 @@
hdmi_msm_state->hpd_state_timer.expires = 0xffffffffL;
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- init_timer(&hdmi_msm_state->hdcp_timer);
- hdmi_msm_state->hdcp_timer.function =
- hdmi_msm_hdcp_timer;
- hdmi_msm_state->hdcp_timer.data = (uint32)NULL;
-
- hdmi_msm_state->hdcp_timer.expires = 0xffffffffL;
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
-
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
init_timer(&hdmi_msm_state->cec_read_timer);
hdmi_msm_state->cec_read_timer.function =
@@ -4623,22 +4680,7 @@
goto error;
}
- if (hdmi_msm_has_hdcp()) {
- /* Don't Set Encryption in case of non HDCP builds */
- external_common_state->present_hdcp = FALSE;
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- external_common_state->present_hdcp = TRUE;
-#endif
- } else {
- external_common_state->present_hdcp = FALSE;
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- /*
- * If the device is not hdcp capable do
- * not start hdcp timer.
- */
- del_timer(&hdmi_msm_state->hdcp_timer);
-#endif
- }
+ hdmi_msm_config_hdcp_feature();
/* Initialize hdmi node and register with switch driver */
if (hdmi_prim_display)
@@ -4822,11 +4864,6 @@
hdmi_common_init_panel_info(&hdmi_msm_panel_data.panel_info);
init_completion(&hdmi_msm_state->ddc_sw_done);
INIT_WORK(&hdmi_msm_state->hpd_state_work, hdmi_msm_hpd_state_work);
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- init_completion(&hdmi_msm_state->hdcp_success_done);
- INIT_WORK(&hdmi_msm_state->hdcp_reauth_work, hdmi_msm_hdcp_reauth_work);
- INIT_WORK(&hdmi_msm_state->hdcp_work, hdmi_msm_hdcp_work);
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
INIT_WORK(&hdmi_msm_state->cec_latch_detect_work,
@@ -4850,9 +4887,6 @@
" RELEASE"
#endif
" AUDIO EDID HPD HDCP"
-#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
- ":0"
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
" DVI"
#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT
":0"
@@ -4874,6 +4908,36 @@
platform_driver_unregister(&this_driver);
}
+static int set_hdcp_feature_on(const char *val, const struct kernel_param *kp)
+{
+ int rv = param_set_bool(val, kp);
+
+ if (rv)
+ return rv;
+
+ pr_debug("%s: HDCP feature = %d\n", __func__, hdcp_feature_on);
+ if (hdmi_msm_state) {
+ if ((HDMI_INP(0x0250) & 0x2)) {
+ pr_err("%s: Unable to set HDCP feature", __func__);
+ pr_err("%s: HDMI panel is currently turned on",
+ __func__);
+ } else if (hdcp_feature_on != hdmi_msm_state->hdcp_enable) {
+ hdmi_msm_config_hdcp_feature();
+ }
+ }
+
+ return 0;
+}
+
+static struct kernel_param_ops hdcp_feature_on_param_ops = {
+ .set = set_hdcp_feature_on,
+ .get = param_get_bool,
+};
+
+module_param_cb(hdcp, &hdcp_feature_on_param_ops, &hdcp_feature_on,
+ S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(hdcp, "Enable or Disable HDCP");
+
module_init(hdmi_msm_init);
module_exit(hdmi_msm_exit);
diff --git a/drivers/video/msm/hdmi_msm.h b/drivers/video/msm/hdmi_msm.h
index 5d27412..20bd492 100644
--- a/drivers/video/msm/hdmi_msm.h
+++ b/drivers/video/msm/hdmi_msm.h
@@ -64,13 +64,12 @@
struct timer_list hpd_state_timer;
struct completion ddc_sw_done;
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
+ bool hdcp_enable;
boolean hdcp_activating;
boolean reauth ;
struct work_struct hdcp_reauth_work, hdcp_work;
struct completion hdcp_success_done;
struct timer_list hdcp_timer;
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
boolean cec_enabled;
diff --git a/drivers/video/msm/mddi_quickvx.c b/drivers/video/msm/mddi_quickvx.c
index 95e7d41..37c147d 100644
--- a/drivers/video/msm/mddi_quickvx.c
+++ b/drivers/video/msm/mddi_quickvx.c
@@ -263,22 +263,10 @@
int ql_mddi_write(uint32 address, uint32 value)
{
- uint32 regval = 0;
int ret = 0;
ret = mddi_queue_register_write(address, value, TRUE, 0);
- if (!ret) {
- ret = mddi_queue_register_read(address, ®val, TRUE, 0);
- if (regval != value) {
- MDDI_MSG_DEBUG("\nMismatch: ql_mddi_write[0x%x]->0x%x "
- "r0x%x\n", address, value, regval);
- } else {
- MDDI_MSG_DEBUG("\nMatch: ql_mddi_write[0x%x]->0x%x "
- "r0x%x\n", address, value, regval);
- }
- }
-
return ret;
}
@@ -294,8 +282,6 @@
int ql_send_spi_cmd_to_lcd(uint32 index, uint32 cmd)
{
- int retry, ret;
- uint32 readval;
MDDI_MSG_DEBUG("\n %s(): index 0x%x, cmd 0x%x", __func__, index, cmd);
/* do the index phase */
@@ -308,18 +294,6 @@
/* set start */
ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START);
- retry = 0;
-
- do {
- ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval);
-
- if (ret || ++retry > 5) {
- MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry "
- "timeout at index phase, ret = %d", ret);
- return -EIO;
- }
- mddi_wait(1);
- } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0);
/* do the command phase */
/* send 24 bits in the cmd phase */
@@ -331,18 +305,6 @@
/* set start */
ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START);
- retry = 0;
-
- do {
- ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval);
-
- if (ret || ++retry > 5) {
- MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry "
- "timeout at cmd phase, ret = %d", ret);
- return -EIO;
- }
- mddi_wait(1);
- } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0);
return 0;
}
@@ -350,8 +312,6 @@
int ql_send_spi_data_from_lcd(uint32 index, uint32 *value)
{
- int retry, ret;
- uint32 readval;
MDDI_MSG_DEBUG("\n %s(): index 0x%x", __func__, index);
/* do the index phase */
@@ -364,19 +324,6 @@
/* set start */
ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START);
- retry = 0;
-
- do {
- ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval);
-
- if (ret || ++retry > 5) {
- MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry "
- "timeout at index phase, ret = %d", ret);
- return -EIO;
- }
- mddi_wait(1);
- } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0);
-
/* do the command phase */
/* send 8 bits and read 24 bits in the cmd phase, so total 32 bits */
ql_mddi_write(QUICKVX_SPI_TLEN_REG, 31);
@@ -387,29 +334,9 @@
/* set start */
ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START);
- retry = 0;
- do {
- ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval);
+ return 0;
- if (ret || ++retry > 5) {
- MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry "
- "timeout at cmd phase, ret = %d", ret);
- return -EIO;
- }
- mddi_wait(1);
- } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0);
-
- /* value will appear at lower 16 bits */
- ret = ql_mddi_read(QUICKVX_SPI_RX0_REG, value);
-
- if (!ret) {
- *value = *value & 0xffff;
- MDDI_MSG_DEBUG("\n QUICKVX_SPI_RX0_REG value = 0x%x", *value);
- } else
- MDDI_MSG_DEBUG("\n Read QUICKVX_SPI_RX0_REG Failed");
-
- return ret;
}
/* Global Variables */
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index f6d9eb7..946a9d7 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -35,6 +35,7 @@
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
+#include <mach/event_timer.h>
#include <mach/clk.h>
#include "mdp.h"
#include "msm_fb.h"
@@ -183,7 +184,7 @@
base = 0x18000;
break;
case MDP_BLOCK_OVERLAY_2:
- base = (mdp_rev >= MDP_REV_44) ? 0x88000 : 0;
+ base = (mdp_rev >= MDP_REV_43) ? 0x88000 : 0;
break;
default:
break;
@@ -518,7 +519,9 @@
int ret;
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_clk_ctrl(1);
ret = mdp_lut_hw_update(cmap);
+ mdp_clk_ctrl(0);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
if (ret)
@@ -540,9 +543,11 @@
uint32_t out;
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_clk_ctrl(1);
ret = mdp_lut_hw_update(cmap);
if (ret) {
+ mdp_clk_ctrl(0);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
return ret;
}
@@ -550,6 +555,7 @@
/*mask off non LUT select bits*/
out = inpdw(MDP_BASE + 0x90070);
MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out);
+ mdp_clk_ctrl(0);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_lut_i = (mdp_lut_i + 1)%2;
@@ -1066,6 +1072,7 @@
}
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_clk_ctrl(1);
for (i = 0; i < mgmt->num_bins; i++) {
mgmt->c0[i] = inpdw(mdp_hist_base + r_data_offset + (4*i));
mgmt->c1[i] = inpdw(mdp_hist_base + g_data_offset + (4*i));
@@ -1081,6 +1088,7 @@
} else
ret = -ENOMEM;
}
+ mdp_clk_ctrl(0);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
if (!ret)
@@ -1116,6 +1124,7 @@
}
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_clk_ctrl(1);
for (i = 0; i < mgmt->num_bins; i++)
mgmt->c0[i] = inpdw(mdp_hist_base + MDP_HIST_DATA_LUMA_OFF +
(4*i));
@@ -1127,6 +1136,7 @@
} else
ret = -ENOMEM;
}
+ mdp_clk_ctrl(0);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
if (!ret)
@@ -1315,27 +1325,32 @@
}
#endif
-static void send_vsync_work(struct work_struct *work)
-{
- char buf[64];
- char *envp[2];
-
- snprintf(buf, sizeof(buf), "VSYNC=%llu",
- ktime_to_ns(vsync_cntrl.vsync_time));
- envp[0] = buf;
- envp[1] = NULL;
- kobject_uevent_env(&(vsync_cntrl.dev->kobj), KOBJ_CHANGE, envp);
-}
-
#ifdef CONFIG_FB_MSM_MDP303
/* vsync_isr_handler: Called from isr context*/
static void vsync_isr_handler(void)
{
vsync_cntrl.vsync_time = ktime_get();
- schedule_work(&(vsync_cntrl.vsync_work));
}
#endif
+static ssize_t vsync_show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ if (atomic_read(&vsync_cntrl.suspend) > 0 ||
+ atomic_read(&vsync_cntrl.vsync_resume) == 0)
+ return 0;
+
+ INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
+ wait_for_completion(&vsync_cntrl.vsync_wait);
+ ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
+ ktime_to_ns(vsync_cntrl.vsync_time));
+ buf[strlen(buf) + 1] = '\0';
+ return ret;
+}
+
/* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */
int mdp_ppp_pipe_wait(void)
{
@@ -1352,15 +1367,95 @@
if (wait == TRUE) {
ret = wait_for_completion_interruptible_timeout(&mdp_ppp_comp,
5 * HZ);
-
if (!ret)
printk(KERN_ERR "%s: Timed out waiting for the MDP.\n",
- __func__);
+ __func__);
}
return ret;
}
+#define MAX_VSYNC_GAP 4
+#define DEFAULT_FRAME_RATE 60
+
+static u32 mdp_get_panel_framerate(struct msm_fb_data_type *mfd)
+{
+ u32 frame_rate = 0, total_pixel;
+ struct msm_panel_info *panel_info = &mfd->panel_info;
+ if (mfd->dest == DISPLAY_LCD) {
+ if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1)
+ frame_rate = panel_info->lcd.refx100 / (100 * 2);
+ else
+ frame_rate = panel_info->lcd.refx100 / 100;
+ } else {
+ if (panel_info->type == MIPI_VIDEO_PANEL) {
+ frame_rate = panel_info->mipi.frame_rate;
+ } else {
+ total_pixel = (panel_info->lcdc.h_back_porch +
+ panel_info->lcdc.h_front_porch +
+ panel_info->lcdc.h_pulse_width +
+ panel_info->xres) *
+ (panel_info->lcdc.v_back_porch +
+ panel_info->lcdc.v_front_porch +
+ panel_info->lcdc.v_pulse_width +
+ panel_info->yres);
+ if (total_pixel)
+ frame_rate = panel_info->clk_rate /
+ total_pixel;
+ }
+ }
+ if (frame_rate == 0)
+ frame_rate = DEFAULT_FRAME_RATE;
+ return frame_rate;
+}
+
+static int mdp_diff_to_next_vsync(ktime_t cur_time,
+ ktime_t last_vsync, u32 vsync_period)
+{
+ int diff_from_last, diff_to_next;
+ /*
+ * Get interval beween last vsync and current time
+ * Current time = CPU programming MDP for next Vsync
+ */
+ diff_from_last =
+ (ktime_to_us(ktime_sub(cur_time, last_vsync)));
+ diff_from_last /= USEC_PER_MSEC;
+ /*
+ * If the last Vsync occurred too long ago, skip programming
+ * the timer
+ */
+ if (diff_from_last < (vsync_period * MAX_VSYNC_GAP)) {
+ if (diff_from_last > vsync_period)
+ diff_to_next =
+ (diff_from_last - vsync_period) % vsync_period;
+ else
+ diff_to_next = vsync_period - diff_from_last;
+ } else {
+ /* mark it out of range */
+ diff_to_next = vsync_period + 1;
+ }
+ return diff_to_next;
+}
+
+void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync)
+{
+ u32 vsync_period;
+ int diff_to_next;
+ ktime_t cur_time, wakeup_time;
+
+ if (!mfd->cpu_pm_hdl)
+ return;
+ vsync_period = mfd->panel_info.frame_interval;
+ cur_time = ktime_get();
+ diff_to_next = mdp_diff_to_next_vsync(cur_time,
+ pre_vsync,
+ vsync_period);
+ if (diff_to_next > vsync_period)
+ return;
+ wakeup_time = ktime_add_ns(cur_time, diff_to_next * NSEC_PER_MSEC);
+ activate_event_timer(mfd->cpu_pm_hdl, wakeup_time);
+}
+
static DEFINE_SPINLOCK(mdp_lock);
static int mdp_irq_mask;
static int mdp_irq_enabled;
@@ -1782,7 +1877,7 @@
unsigned long flag;
struct mdp_hist_mgmt *mgmt = NULL;
int i, ret;
- int vsync_isr;
+ int vsync_isr, disabled_clocks;
/* Ensure all the register write are complete */
mb();
@@ -1805,19 +1900,25 @@
if (mdp_interrupt & MDP_PRIM_RDPTR) {
spin_lock_irqsave(&mdp_spin_lock, flag);
vsync_isr = vsync_cntrl.vsync_irq_enabled;
- if (!vsync_isr) {
+ disabled_clocks = vsync_cntrl.disabled_clocks;
+ if ((!vsync_isr && !vsync_cntrl.disabled_clocks)
+ || (!vsync_isr && vsync_cntrl.vsync_dma_enabled)) {
mdp_intr_mask &= ~MDP_PRIM_RDPTR;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_disable_irq_nosync(MDP_VSYNC_TERM);
+ vsync_cntrl.disabled_clocks = 1;
+ } else if (vsync_isr) {
+ vsync_isr_handler();
}
+ vsync_cntrl.vsync_dma_enabled = 0;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
- if (vsync_isr) {
- vsync_isr_handler();
- } else {
+ complete(&vsync_cntrl.vsync_comp);
+ if (!vsync_isr && !disabled_clocks)
mdp_pipe_ctrl(MDP_CMD_BLOCK,
MDP_BLOCK_POWER_OFF, TRUE);
- complete(&vsync_cntrl.vsync_wait);
- }
+
+ complete_all(&vsync_cntrl.vsync_wait);
}
/* DMA3 TV-Out Start */
@@ -1870,16 +1971,18 @@
if (!vsync_isr) {
mdp_intr_mask &= ~LCDC_FRAME_START;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_disable_irq_nosync(MDP_VSYNC_TERM);
+ vsync_cntrl.disabled_clocks = 1;
+ } else {
+ vsync_isr_handler();
}
spin_unlock_irqrestore(&mdp_spin_lock, flag);
- if (vsync_isr) {
- vsync_isr_handler();
- } else {
+ if (!vsync_isr)
mdp_pipe_ctrl(MDP_CMD_BLOCK,
MDP_BLOCK_POWER_OFF, TRUE);
- complete(&vsync_cntrl.vsync_wait);
- }
+
+ complete_all(&vsync_cntrl.vsync_wait);
}
/* DMA2 LCD-Out Complete */
@@ -1927,6 +2030,7 @@
spin_unlock_irqrestore(&mdp_spin_lock, flag);
mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF,
TRUE);
+ mdp_disable_irq_nosync(MDP_DMA2_TERM);
complete(&dma->comp);
}
#endif
@@ -1978,6 +2082,7 @@
dma2_data.dmap_busy = FALSE;
dma2_data.waiting = FALSE;
init_completion(&dma2_data.comp);
+ init_completion(&vsync_cntrl.vsync_comp);
init_completion(&dma2_data.dmap_comp);
sema_init(&dma2_data.mutex, 1);
mutex_init(&dma2_data.ov_mutex);
@@ -2009,8 +2114,9 @@
for (i = 0; i < MDP_MAX_BLOCK; i++) {
atomic_set(&mdp_block_power_cnt[i], 0);
}
- INIT_WORK(&(vsync_cntrl.vsync_work), send_vsync_work);
+ vsync_cntrl.disabled_clocks = 1;
init_completion(&vsync_cntrl.vsync_wait);
+ atomic_set(&vsync_cntrl.vsync_resume, 1);
#ifdef MSM_FB_ENABLE_DBGFS
{
struct dentry *root;
@@ -2096,7 +2202,9 @@
pr_debug("%s:+\n", __func__);
mdp_histogram_ctrl_all(FALSE);
-
+ atomic_set(&vsync_cntrl.suspend, 1);
+ atomic_set(&vsync_cntrl.vsync_resume, 0);
+ complete_all(&vsync_cntrl.vsync_wait);
mdp_clk_ctrl(1);
if (mfd->panel.type == MIPI_CMD_PANEL)
mdp4_dsi_cmd_off(pdev);
@@ -2106,6 +2214,8 @@
mfd->panel.type == LCDC_PANEL ||
mfd->panel.type == LVDS_PANEL)
mdp4_lcdc_off(pdev);
+ else if (mfd->panel.type == MDDI_PANEL)
+ mdp4_mddi_off(pdev);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
ret = panel_next_off(pdev);
@@ -2127,7 +2237,16 @@
{
/* empty */
}
+
#endif
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+ &dev_attr_vsync_event.attr,
+ NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+ .attrs = vsync_fs_attrs,
+};
static int mdp_on(struct platform_device *pdev)
{
@@ -2151,16 +2270,35 @@
mfd->panel.type == LCDC_PANEL ||
mfd->panel.type == LVDS_PANEL) {
mdp4_lcdc_on(pdev);
+ } else if (mfd->panel.type == MDDI_PANEL) {
+ mdp_vsync_cfg_regs(mfd, FALSE);
+ mdp4_mddi_on(pdev);
}
mdp_clk_ctrl(0);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
- if ((mdp_rev == MDP_REV_303) &&
- (mfd->panel.type == MIPI_CMD_PANEL))
+ if (mdp_rev == MDP_REV_303 && mfd->panel.type == MIPI_CMD_PANEL) {
+
vsync_cntrl.dev = mfd->fbi->dev;
+ if (!vsync_cntrl.sysfs_created) {
+ ret = sysfs_create_group(&vsync_cntrl.dev->kobj,
+ &vsync_fs_attr_group);
+ if (ret) {
+ pr_err("%s: sysfs creation failed, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD);
+ pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+ vsync_cntrl.sysfs_created = 1;
+ }
+ atomic_set(&vsync_cntrl.suspend, 0);
+ }
+
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
ret = panel_next_on(pdev);
@@ -2383,6 +2521,7 @@
int rc;
resource_size_t size ;
unsigned long flag;
+ u32 frame_rate;
#ifdef CONFIG_FB_MSM_MDP40
int intf, if_no;
#endif
@@ -2391,6 +2530,7 @@
#endif
static int contSplash_update_done;
char *cp;
+ unsigned int mdp_r = 0;
if ((pdev->id == 0) && (pdev->num_resources > 0)) {
mdp_init_pdev = pdev;
@@ -2412,6 +2552,15 @@
}
mdp_rev = mdp_pdata->mdp_rev;
+ if (mdp_rev == MDP_REV_42) {
+ mdp_r = inpdw(MDP_BASE + 0x0);
+ mdp_r = ((mdp_r & 0x30000) >> 16);
+ if (mdp_r == 3) {
+ mdp_rev = MDP_REV_43;
+ mdp_pdata->mdp_rev = MDP_REV_43;
+ }
+ }
+
mdp_iommu_split_domain = mdp_pdata->mdp_iommu_split_domain;
rc = mdp_irq_clk_setup(pdev, mdp_pdata->cont_splash_enabled);
@@ -2434,7 +2583,9 @@
#ifdef CONFIG_FB_MSM_OVERLAY
mdp_hw_cursor_init();
#endif
- mdp_clk_ctrl(0);
+
+ if (!(mdp_pdata->cont_splash_enabled))
+ mdp_clk_ctrl(0);
mdp_resource_initialized = 1;
return 0;
@@ -2560,6 +2711,9 @@
mdp_vsync_resync_workqueue_handler);
mfd->hw_refresh = FALSE;
+ if (mfd->panel.type == MDDI_PANEL)
+ mdp4_mddi_rdptr_init(0);
+
if (mfd->panel.type == EXT_MDDI_PANEL) {
/* 15 fps -> 66 msec */
mfd->refresh_timer_duration = (66 * HZ / 1000);
@@ -2802,6 +2956,7 @@
mdp_clk_ctrl(0);
return -ENODEV;
}
+ mdp4_wfd_init(0);
pdata->on = mdp4_overlay_writeback_on;
pdata->off = mdp4_overlay_writeback_off;
mfd->dma_fnc = mdp4_writeback_overlay;
@@ -2823,6 +2978,11 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
+ frame_rate = mdp_get_panel_framerate(mfd);
+ if (frame_rate) {
+ mfd->panel_info.frame_interval = 1000 / frame_rate;
+ mfd->cpu_pm_hdl = add_event_timer(NULL, (void *)mfd);
+ }
mdp_clk_ctrl(0);
#ifdef CONFIG_MSM_BUS_SCALING
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 371174c..b4a7f79 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -94,10 +94,16 @@
struct vsync {
ktime_t vsync_time;
+ struct completion vsync_comp;
struct device *dev;
struct work_struct vsync_work;
int vsync_irq_enabled;
+ int vsync_dma_enabled;
+ int disabled_clocks;
struct completion vsync_wait;
+ atomic_t suspend;
+ atomic_t vsync_resume;
+ int sysfs_created;
};
extern struct vsync vsync_cntrl;
@@ -790,6 +796,10 @@
{
return 0;
}
+static inline int mdp4_mddi_off(struct platform_device *pdev)
+{
+ return 0;
+}
static inline int mdp4_dsi_cmd_on(struct platform_device *pdev)
{
return 0;
@@ -802,6 +812,19 @@
{
return 0;
}
+static inline int mdp4_mddi_on(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
+
+#ifndef CONFIG_FB_MSM_MDDI
+static inline void mdp4_mddi_rdptr_init(int cndx)
+{
+ /* empty */
+}
+
#endif
void set_cont_splashScreen_status(int);
@@ -901,6 +924,7 @@
int mdp_ppp_v4l2_overlay_play(struct fb_info *info,
unsigned long srcp0_addr, unsigned long srcp0_size,
unsigned long srcp1_addr, unsigned long srcp1_size);
+void mdp_update_pm(struct msm_fb_data_type *mfd, ktime_t pre_vsync);
#ifdef CONFIG_FB_MSM_DTV
void mdp_vid_quant_set(void);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 005e87c..a73b3ad 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -306,10 +306,16 @@
uint32 is_fg; /* control alpha & color key */
uint32 srcp0_addr; /* interleave, luma */
uint32 srcp0_ystride;
+ struct file *srcp0_file;
+ int put0_need;
uint32 srcp1_addr; /* pseudoplanar, chroma plane */
uint32 srcp1_ystride;
+ struct file *srcp1_file;
+ int put1_need;
uint32 srcp2_addr; /* planar color 2*/
uint32 srcp2_ystride;
+ struct file *srcp2_file;
+ int put2_need;
uint32 srcp3_addr; /* alpha/color 3 */
uint32 srcp3_ystride;
uint32 fetch_plane;
@@ -349,7 +355,7 @@
uint32 ov_cnt;
uint32 dmap_cnt;
uint32 dmae_cnt;
- uint32 blt_end;
+ uint32 blt_end; /* used by mddi only */
uint32 blt_ov_koff;
uint32 blt_ov_done;
uint32 blt_dmap_koff;
@@ -387,6 +393,7 @@
ulong intr_dsi_err;
ulong kickoff_ov0;
ulong kickoff_ov1;
+ ulong kickoff_ov2;
ulong kickoff_dmap;
ulong kickoff_dmae;
ulong kickoff_dmas;
@@ -543,12 +550,9 @@
void mdp4_overlay0_done_dsi_cmd(int cndx);
void mdp4_primary_rdptr(void);
void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd);
-int mdp4_overlay_commit(struct fb_info *info, int mixer);
-int mdp4_dsi_video_pipe_commit(void);
-int mdp4_dsi_cmd_pipe_commit(void);
+int mdp4_lcdc_pipe_commit(int cndx, int wait);
+int mdp4_dtv_pipe_commit(int cndx, int wait);
int mdp4_dsi_cmd_update_cnt(int cndx);
-int mdp4_lcdc_pipe_commit(void);
-int mdp4_dtv_pipe_commit(void);
void mdp4_dsi_rdptr_init(int cndx);
void mdp4_dsi_vsync_init(int cndx);
void mdp4_lcdc_vsync_init(int cndx);
@@ -577,6 +581,7 @@
int mdp4_overlay_play_wait(struct fb_info *info,
struct msmfb_overlay_data *req);
int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req);
+int mdp4_overlay_commit(struct fb_info *info, int mixer);
struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(int ptype, int mixer);
void mdp4_overlay_dma_commit(int mixer);
void mdp4_overlay_vsync_commit(struct mdp4_overlay_pipe *pipe);
@@ -592,9 +597,10 @@
int mdp4_overlay_pipe_staged(int mixer);
void mdp4_lcdc_primary_vsyn(void);
void mdp4_overlay0_done_lcdc(int cndx);
-void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma);
+void mdp4_overlay0_done_mddi(int cndx);
void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma);
void mdp4_dmap_done_dsi_cmd(int cndx);
+void mdp4_dmap_done_mddi(int cndx);
void mdp4_dmap_done_dsi_video(int cndx);
void mdp4_dmap_done_lcdc(int cndx);
void mdp4_overlay1_done_dtv(void);
@@ -668,6 +674,12 @@
void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req);
void mdp4_dsi_video_base_swap(int cndx, struct mdp4_overlay_pipe *pipe);
+static inline void mdp4_mddi_blt_start(struct msm_fb_data_type *mfd)
+{
+}
+static inline void mdp4_mddi_blt_stop(struct msm_fb_data_type *mfd)
+{
+}
#ifdef CONFIG_FB_MSM_MDP40
static inline void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
@@ -676,6 +688,8 @@
}
#endif
#else /* CONFIG_FB_MSM_MIPI_DSI */
+void mdp4_mddi_blt_start(struct msm_fb_data_type *mfd);
+void mdp4_mddi_blt_stop(struct msm_fb_data_type *mfd);
int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req);
void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
@@ -683,6 +697,7 @@
int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd);
int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd);
void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd);
+void mdp4_mddi_rdptr_init(int cndx);
static inline int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd)
{
return -ENODEV;
@@ -763,6 +778,8 @@
void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime);
void mdp4_dsi_cmd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
void mdp4_dsi_video_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
+int mdp4_dsi_video_pipe_commit(int cndx, int wait);
+int mdp4_dsi_cmd_pipe_commit(int cndx, int wait);
void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable);
void mdp4_dsi_video_vsync_ctrl(struct fb_info *info, int enable);
#ifdef CONFIG_FB_MSM_MDP303
@@ -770,11 +787,37 @@
{
/* empty */
}
-#else /* CONFIG_FB_MSM_MIPI_DSI */
+#else /* CONFIG_FB_MSM_MDP303 */
void mdp4_dsi_cmd_del_timer(void);
+static inline int mdp4_mddi_on(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline int mdp4_mddi_off(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline void mdp4_mddi_wait4vsync(int cndx, long long *vtime)
+{
+}
+static inline void mdp4_mddi_vsync_ctrl(struct fb_info *info,
+ int enable)
+{
+}
+static inline void mdp4_mddi_pipe_queue(int cndx,
+ struct mdp4_overlay_pipe *pipe)
+{
+}
#endif
#else /* CONFIG_FB_MSM_MIPI_DSI */
+int mdp4_mddi_off(struct platform_device *pdev);
+int mdp4_mddi_on(struct platform_device *pdev);
+void mdp4_mddi_wait4vsync(int cndx, long long *vtime);
+void mdp4_mddi_vsync_ctrl(struct fb_info *info, int enable);
+void mdp4_mddi_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
+void mdp4_overlay_update_mddi(struct msm_fb_data_type *mfd);
+
static inline int mdp4_dsi_cmd_on(struct platform_device *pdev)
{
return 0;
@@ -812,6 +855,14 @@
struct mdp4_overlay_pipe *pipe)
{
}
+static inline int mdp4_dsi_video_pipe_commit(int cndx, int wait)
+{
+ return 0;
+}
+static inline int mdp4_dsi_cmd_pipe_commit(int cndx, int wait)
+{
+ return 0;
+}
static inline void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info,
int enable)
{
@@ -870,7 +921,7 @@
int mdp4_overlay_writeback_on(struct platform_device *pdev);
int mdp4_overlay_writeback_off(struct platform_device *pdev);
void mdp4_writeback_overlay(struct msm_fb_data_type *mfd);
-void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma);
+void mdp4_overlay2_done_wfd(struct mdp_dma_data *dma);
int mdp4_writeback_start(struct fb_info *info);
int mdp4_writeback_stop(struct fb_info *info);
@@ -920,19 +971,17 @@
u32 mdp4_get_mixer_num(u32 panel_type);
#ifndef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
-static inline void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd)
+static inline void mdp4_wfd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe)
{
/* empty */
}
-static inline void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
+static inline void mdp4_wfd_init(int cndx)
{
/* empty */
}
#else
-void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd);
-void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe);
+void mdp4_wfd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe);
+void mdp4_wfd_init(int cndx);
#endif
#endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 18cf817..ab27267 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -191,6 +191,19 @@
if (pipe == NULL)
return;
+ if (pipe->flags & MDP_MEMORY_ID_TYPE_FB) {
+ if (pipe->put0_need)
+ fput_light(pipe->srcp0_file, pipe->put0_need);
+ if (pipe->put1_need)
+ fput_light(pipe->srcp1_file, pipe->put1_need);
+ if (pipe->put2_need)
+ fput_light(pipe->srcp2_file, pipe->put2_need);
+
+ pr_debug("%s: ndx=%d flags=%x put=%d\n", __func__,
+ pipe->pipe_ndx, pipe->flags, pipe->put0_need);
+ return;
+ }
+
mutex_lock(&iommu_mutex);
mixer = pipe->mixer_num;
iom = &pipe->iommu;
@@ -735,37 +748,53 @@
*luma_off = 0;
*chroma_off = 0;
- if (pipe->src_x && (pipe->frame_format ==
+ if ((pipe->src_x || pipe->src_y) && (pipe->frame_format ==
MDP4_FRAME_FORMAT_LINEAR)) {
- src_xy = (pipe->src_y << 16) | pipe->src_x;
- src_xy &= 0xffff0000;
+ src_xy = 0;
outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */
switch (pipe->src_format) {
case MDP_Y_CR_CB_H2V2:
case MDP_Y_CR_CB_GH2V2:
case MDP_Y_CB_CR_H2V2:
- *luma_off = pipe->src_x;
- *chroma_off = pipe->src_x/2;
+ *luma_off = pipe->src_x +
+ (pipe->src_y * pipe->srcp0_ystride);
+ *chroma_off = pipe->src_x / 2 +
+ ((pipe->src_y / 2) * pipe->srcp1_ystride);
break;
case MDP_Y_CBCR_H2V2_TILE:
case MDP_Y_CRCB_H2V2_TILE:
case MDP_Y_CBCR_H2V2:
case MDP_Y_CRCB_H2V2:
+ *luma_off = pipe->src_x +
+ (pipe->src_y * pipe->srcp0_ystride);
+ *chroma_off = pipe->src_x +
+ ((pipe->src_y / 2) * pipe->srcp1_ystride);
+ break;
+
case MDP_Y_CRCB_H1V1:
case MDP_Y_CBCR_H1V1:
+ *luma_off = pipe->src_x +
+ (pipe->src_y * pipe->srcp0_ystride);
+ *chroma_off = pipe->src_x +
+ ((pipe->src_y * 2) * pipe->srcp1_ystride);
+ break;
+
case MDP_Y_CRCB_H2V1:
case MDP_Y_CBCR_H2V1:
case MDP_Y_CRCB_H1V2:
- *luma_off = pipe->src_x;
- *chroma_off = pipe->src_x;
+ *luma_off = pipe->src_x +
+ (pipe->src_y * pipe->srcp0_ystride);
+ *chroma_off = pipe->src_x +
+ (pipe->src_y * pipe->srcp1_ystride);
break;
case MDP_YCRYCB_H2V1:
if (pipe->src_x & 0x1)
pipe->src_x += 1;
- *luma_off += pipe->src_x * 2;
+ *luma_off += pipe->src_x * 2 +
+ ((pipe->src_y * 2) * pipe->srcp0_ystride);
break;
case MDP_ARGB_8888:
@@ -778,7 +807,8 @@
case MDP_RGB_888:
case MDP_YCBCR_H1V1:
case MDP_YCRCB_H1V1:
- *luma_off = pipe->src_x * pipe->bpp;
+ *luma_off = (pipe->src_x * pipe->bpp) +
+ (pipe->src_y * pipe->srcp0_ystride);
break;
default:
@@ -1619,6 +1649,8 @@
data |= stage;
}
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_clk_ctrl(1);
mdp4_mixer_blend_setup(mixer);
off = 0;
@@ -1638,7 +1670,6 @@
mixer, data, ctrl->flush[mixer], current->pid);
}
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
local_irq_save(flags);
if (off)
outpdw(MDP_BASE + off, data);
@@ -1649,6 +1680,7 @@
}
local_irq_restore(flags);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_clk_ctrl(0);
}
@@ -1927,7 +1959,7 @@
struct mdp4_overlay_pipe *d_pipe;
struct mdp4_overlay_pipe *s_pipe;
struct blend_cfg *blend;
- int i, off, ptype, alpha_drop = 0;
+ int i, off, alpha_drop = 0;
int d_alpha, s_alpha;
unsigned char *overlay_base;
uint32 c0, c1, c2, base_premulti;
@@ -1957,7 +1989,8 @@
if (s_pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
((s_pipe->op_mode & MDP4_OP_SCALEY_EN) ||
(s_pipe->op_mode & MDP4_OP_SCALEX_EN)) &&
- !(s_pipe->op_mode & MDP4_OP_SCALEY_PIXEL_RPT))
+ !(s_pipe->op_mode & (MDP4_OP_SCALEX_PIXEL_RPT |
+ MDP4_OP_SCALEY_PIXEL_RPT)))
alpha_drop = 1;
d_pipe = mdp4_background_layer(mixer, s_pipe);
@@ -1973,7 +2006,8 @@
blend->bg_alpha = 0x0ff - s_pipe->alpha;
blend->fg_alpha = s_pipe->alpha;
blend->co3_sel = 1; /* use fg alpha */
-
+ pr_debug("%s: bg alpha %d, fg alpha %d\n",
+ __func__, blend->bg_alpha, blend->fg_alpha);
if (s_pipe->is_fg) {
if (s_pipe->alpha == 0xff) {
blend->solidfill = 1;
@@ -1989,30 +2023,21 @@
MDP4_BLEND_FG_ALPHA_FG_PIXEL;
else
blend->fg_alpha = 0xff;
+ blend->op |= MDP4_BLEND_BG_INV_ALPHA;
} else
blend->op = MDP4_BLEND_BG_ALPHA_FG_CONST;
-
- blend->op |= MDP4_BLEND_BG_INV_ALPHA;
} else if (d_alpha) {
- ptype = mdp4_overlay_format2type(s_pipe->src_format);
- if (ptype == OVERLAY_TYPE_VIDEO) {
- blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL |
- MDP4_BLEND_FG_INV_ALPHA);
- if ((!(s_pipe->flags & MDP_BLEND_FG_PREMULT)) &&
- ((i != MDP4_MIXER_STAGE0) ||
- (!base_premulti)))
- blend->op |=
- MDP4_BLEND_BG_ALPHA_BG_PIXEL;
- else
- blend->fg_alpha = 0xff;
+ blend->op = (MDP4_BLEND_FG_ALPHA_BG_PIXEL |
+ MDP4_BLEND_FG_INV_ALPHA);
+ if ((!(d_pipe->flags & MDP_BLEND_FG_PREMULT)) &&
+ ((i != MDP4_MIXER_STAGE0) ||
+ (!base_premulti)))
+ blend->op |=
+ MDP4_BLEND_BG_ALPHA_BG_PIXEL;
+ else
+ blend->fg_alpha = 0xff;
- blend->co3_sel = 0; /* use bg alpha */
- } else {
- /* s_pipe is rgb without alpha */
- blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
- MDP4_BLEND_BG_ALPHA_BG_CONST);
- blend->bg_alpha = 0;
- }
+ blend->co3_sel = 0; /* use bg alpha */
}
if (s_pipe->transp != MDP_TRANSP_NOP) {
@@ -2314,6 +2339,18 @@
return -ERANGE;
}
+ if (mdp_rev <= MDP_REV_41) {
+ if ((mdp4_overlay_format2type(req->src.format) ==
+ OVERLAY_TYPE_RGB) &&
+ !(req->flags & MDP_OV_PIPE_SHARE) &&
+ ((req->src_rect.w > req->dst_rect.w) ||
+ (req->src_rect.h > req->dst_rect.h))) {
+ mdp4_stat.err_size++;
+ pr_err("%s: downscale on RGB pipe!\n", __func__);
+ return -EINVAL;
+ }
+ }
+
if (mdp_hw_revision == MDP4_REVISION_V1) {
/* non integer down saceling ratio smaller than 1/4
* is not supportted
@@ -2832,6 +2869,8 @@
mdp4_dsi_video_blt_start(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_cmd_blt_start(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_blt_start(mfd);
pr_info("%s mixer0 start blt [%d] from %d to %d.\n",
__func__,
flag,
@@ -2880,6 +2919,8 @@
mdp4_dsi_video_blt_stop(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_cmd_blt_stop(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_blt_stop(mfd);
pr_info("%s mixer0 stop blt [%d] from %d to %d.\n",
__func__,
flag,
@@ -2924,14 +2965,13 @@
if (file == NULL)
return -EINVAL;
+ pipe->flags |= MDP_MEMORY_ID_TYPE_FB;
if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
if (get_fb_phys_info(start, len, fb_num,
DISPLAY_SUBSYSTEM_ID)) {
ret = -1;
} else {
- pr_warn("%s: mdp4_overlay play with FB memory\n",
- __func__);
*srcp_file = file;
*p_need = put_needed;
}
@@ -3145,20 +3185,14 @@
else {
/* mixer 0 */
ctrl->mixer0_played = 0;
- if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
- if (mfd->panel_power_on)
- mdp4_mddi_blt_dmap_busy_wait(mfd);
- }
+
}
mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_down(pipe, 0);
if (pipe->mixer_num == MDP4_MIXER0) {
- if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
- if (mfd->panel_power_on)
- mdp4_mddi_overlay_restore();
- }
+
} else { /* mixer1, DTV, ATV */
if (ctrl->panel_mode & MDP4_PANEL_DTV)
mdp4_overlay_dtv_unset(mfd, pipe);
@@ -3182,6 +3216,8 @@
mdp4_dsi_cmd_wait4vsync(0, vtime);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
mdp4_lcdc_wait4vsync(0, vtime);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_wait4vsync(0, vtime);
} else if (hdmi_prim_display || info->node == 1) {
mdp4_dtv_wait4vsync(0, vtime);
}
@@ -3205,6 +3241,8 @@
mdp4_dsi_cmd_vsync_ctrl(info, cmd);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
mdp4_lcdc_vsync_ctrl(info, cmd);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_vsync_ctrl(info, cmd);
} else if (hdmi_prim_display || info->node == 1)
mdp4_dtv_vsync_ctrl(info, cmd);
@@ -3289,11 +3327,8 @@
struct mdp4_overlay_pipe *pipe;
ulong start, addr;
ulong len = 0;
- struct file *srcp0_file = NULL;
- struct file *srcp1_file = NULL, *srcp2_file = NULL;
struct ion_handle *srcp0_ihdl = NULL;
struct ion_handle *srcp1_ihdl = NULL, *srcp2_ihdl = NULL;
- int ps0_need, p_need;
uint32_t overlay_version = 0;
int ret = 0;
@@ -3318,8 +3353,8 @@
mutex_lock(&mfd->dma->ov_mutex);
img = &req->data;
- get_img(img, info, pipe, 0, &start, &len, &srcp0_file,
- &ps0_need, &srcp0_ihdl);
+ get_img(img, info, pipe, 0, &start, &len, &pipe->srcp0_file,
+ &pipe->put0_need, &srcp0_ihdl);
if (len == 0) {
pr_err("%s: pmem Error\n", __func__);
ret = -1;
@@ -3341,8 +3376,9 @@
if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) {
if (overlay_version > 0) {
img = &req->plane1_data;
- get_img(img, info, pipe, 1, &start, &len, &srcp1_file,
- &p_need, &srcp1_ihdl);
+ get_img(img, info, pipe, 1, &start, &len,
+ &pipe->srcp1_file, &pipe->put1_need,
+ &srcp1_ihdl);
if (len == 0) {
pr_err("%s: Error to get plane1\n", __func__);
ret = -EINVAL;
@@ -3373,8 +3409,9 @@
} else if (pipe->fetch_plane == OVERLAY_PLANE_PLANAR) {
if (overlay_version > 0) {
img = &req->plane1_data;
- get_img(img, info, pipe, 1, &start, &len, &srcp1_file,
- &p_need, &srcp1_ihdl);
+ get_img(img, info, pipe, 1, &start, &len,
+ &pipe->srcp1_file, &pipe->put1_need,
+ &srcp1_ihdl);
if (len == 0) {
pr_err("%s: Error to get plane1\n", __func__);
ret = -EINVAL;
@@ -3383,8 +3420,9 @@
pipe->srcp1_addr = start + img->offset;
img = &req->plane2_data;
- get_img(img, info, pipe, 2, &start, &len, &srcp2_file,
- &p_need, &srcp2_ihdl);
+ get_img(img, info, pipe, 2, &start, &len,
+ &pipe->srcp2_file, &pipe->put2_need,
+ &srcp2_ihdl);
if (len == 0) {
pr_err("%s: Error to get plane2\n", __func__);
ret = -EINVAL;
@@ -3425,77 +3463,79 @@
mdp4_overlay_mdp_perf_req(mfd, ctrl->plist);
- if (pipe->mixer_num == MDP4_MIXER2 ||
- ctrl->panel_mode & MDP4_PANEL_MDDI)
- goto mddi;
-
if (pipe->mixer_num == MDP4_MIXER0) {
if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
/* cndx = 0 */
mdp4_dsi_cmd_pipe_queue(0, pipe);
- }
- if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
+ } else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
/* cndx = 0 */
mdp4_dsi_video_pipe_queue(0, pipe);
} else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
/* cndx = 0 */
mdp4_lcdc_pipe_queue(0, pipe);
}
+ if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
+ /* cndx = 0 */
+ mdp4_mddi_pipe_queue(0, pipe);
+ }
} else if (pipe->mixer_num == MDP4_MIXER1) {
if (ctrl->panel_mode & MDP4_PANEL_DTV)
mdp4_dtv_pipe_queue(0, pipe);/* cndx = 0 */
+ } else if (pipe->mixer_num == MDP4_MIXER2) {
+ ctrl->mixer2_played++;
+ if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK)
+ mdp4_wfd_pipe_queue(0, pipe);/* cndx = 0 */
}
mutex_unlock(&mfd->dma->ov_mutex);
return ret;
-mddi:
- if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
- mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
- } else {
- mdp4_overlay_rgb_setup(pipe); /* rgb pipe */
- }
-
- mdp4_mixer_stage_up(pipe, 0);
-
- if (pipe->mixer_num == MDP4_MIXER2) {
- ctrl->mixer2_played++;
- if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
- mdp4_writeback_dma_busy_wait(mfd);
- mdp4_writeback_kickoff_video(mfd, pipe);
- }
- } else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
- if (pipe->flags & MDP_OV_PLAY_NOWAIT) {
- mdp4_stat.overlay_play[pipe->mixer_num]++;
- mutex_unlock(&mfd->dma->ov_mutex);
- goto end;
- }
- mdp4_mixer_stage_commit(pipe->mixer_num);
- mdp4_mddi_dma_busy_wait(mfd);
- mdp4_mddi_kickoff_video(mfd, pipe);
- }
-
- if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
- mdp4_iommu_unmap(pipe);
- mdp4_stat.overlay_play[pipe->mixer_num]++;
-
end:
mutex_unlock(&mfd->dma->ov_mutex);
-#ifdef CONFIG_ANDROID_PMEM
- if (srcp0_file)
- put_pmem_file(srcp0_file);
- if (srcp1_file)
- put_pmem_file(srcp1_file);
- if (srcp2_file)
- put_pmem_file(srcp2_file);
-#endif
- /* only source may use frame buffer */
- if (img->flags & MDP_MEMORY_ID_TYPE_FB)
- fput_light(srcp0_file, ps0_need);
return ret;
}
+int mdp4_overlay_commit(struct fb_info *info, int mixer)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ if (mfd == NULL)
+ return -ENODEV;
+
+ if (!mfd->panel_power_on) /* suspended */
+ return -EINVAL;
+
+ if (mixer >= MDP4_MIXER_MAX)
+ return -EPERM;
+
+ mutex_lock(&mfd->dma->ov_mutex);
+
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
+
+ if (mixer == MDP4_MIXER0) {
+ if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
+ /* cndx = 0 */
+ mdp4_dsi_cmd_pipe_commit(0, 1);
+ } else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
+ /* cndx = 0 */
+ mdp4_dsi_video_pipe_commit(0, 1);
+ } else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
+ /* cndx = 0 */
+ mdp4_lcdc_pipe_commit(0, 1);
+ }
+ } else if (mixer == MDP4_MIXER1) {
+ if (ctrl->panel_mode & MDP4_PANEL_DTV)
+ mdp4_dtv_pipe_commit(0, 1);
+ }
+
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
+
+ mutex_unlock(&mfd->dma->ov_mutex);
+
+ return 0;
+}
+
struct msm_iommu_ctx {
char *name;
int domain;
diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c
index e67b244..90c3da9 100644
--- a/drivers/video/msm/mdp4_overlay_atv.c
+++ b/drivers/video/msm/mdp4_overlay_atv.c
@@ -184,6 +184,8 @@
} else {
pipe->srcp0_addr = (uint32)(buf + buf_offset);
}
+ mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
+
mdp4_overlay_mdp_perf_req(pipe, mfd);
mdp4_overlay_mdp_perf_upd(mfd, 1);
mdp4_overlay_rgb_setup(pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 3320d11..ecdd567 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -39,7 +39,7 @@
static int vsync_start_y_adjust = 4;
#define MAX_CONTROLLER 1
-#define VSYNC_EXPIRE_TICK 8
+#define VSYNC_EXPIRE_TICK 4
static struct vsycn_ctrl {
struct device *dev;
@@ -54,11 +54,12 @@
uint32 rdptr_intr_tot;
uint32 rdptr_sirq_tot;
atomic_t suspend;
+ atomic_t vsync_resume;
int wait_vsync_cnt;
int blt_change;
int blt_free;
int blt_end;
- int uevent;
+ int sysfs_created;
struct mutex update_lock;
struct completion ov_comp;
struct completion dmap_comp;
@@ -72,7 +73,6 @@
int clk_control;
int new_update;
ktime_t vsync_time;
- struct work_struct vsync_work;
struct work_struct clk_work;
} vsync_ctrl_db[MAX_CONTROLLER];
@@ -250,7 +250,7 @@
static void mdp4_dsi_cmd_blt_ov_update(struct mdp4_overlay_pipe *pipe);
-int mdp4_dsi_cmd_pipe_commit(void)
+int mdp4_dsi_cmd_pipe_commit(int cndx, int wait)
{
int i, undx;
int mixer = 0;
@@ -377,6 +377,12 @@
mdp4_stat.overlay_commit[pipe->mixer_num]++;
+ if (wait) {
+ long long tick;
+
+ mdp4_dsi_cmd_wait4vsync(cndx, &tick);
+ }
+
return cnt;
}
@@ -384,7 +390,6 @@
void mdp4_dsi_cmd_vsync_ctrl(struct fb_info *info, int enable)
{
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct vsycn_ctrl *vctrl;
unsigned long flags;
int clk_set_on = 0;
@@ -415,24 +420,23 @@
spin_lock_irqsave(&vctrl->spin_lock, flags);
vctrl->clk_control = 0;
vctrl->expire_tick = 0;
- vctrl->uevent = 1;
vctrl->new_update = 1;
if (clk_set_on) {
vsync_irq_enable(INTR_PRIMARY_RDPTR,
MDP_PRIM_RDPTR_TERM);
}
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
-
- mdp4_overlay_update_dsi_cmd(mfd);
} else {
spin_lock_irqsave(&vctrl->spin_lock, flags);
vctrl->clk_control = 1;
- vctrl->uevent = 0;
if (vctrl->clk_enabled)
vctrl->expire_tick = VSYNC_EXPIRE_TICK;
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
}
mutex_unlock(&vctrl->update_lock);
+
+ if (vctrl->vsync_enabled && atomic_read(&vctrl->suspend) == 0)
+ atomic_set(&vctrl->vsync_resume, 1);
}
void mdp4_dsi_cmd_wait4vsync(int cndx, long long *vtime)
@@ -515,13 +519,9 @@
vctrl->vsync_time = ktime_get();
spin_lock(&vctrl->spin_lock);
- if (vctrl->uevent)
- schedule_work(&vctrl->vsync_work);
- if (vctrl->wait_vsync_cnt) {
- complete(&vctrl->vsync_comp);
- vctrl->wait_vsync_cnt = 0;
- }
+ complete_all(&vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt = 0;
if (vctrl->expire_tick) {
vctrl->expire_tick--;
@@ -539,6 +539,8 @@
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
+ if (pipe == NULL)
+ return;
/* blt enabled */
spin_lock(&vctrl->spin_lock);
@@ -578,6 +580,8 @@
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
+ if (pipe == NULL)
+ return;
spin_lock(&vctrl->spin_lock);
vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
@@ -636,21 +640,35 @@
mutex_unlock(&vctrl->update_lock);
}
-static void send_vsync_work(struct work_struct *work)
+static ssize_t vsync_show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct vsycn_ctrl *vctrl =
- container_of(work, typeof(*vctrl), vsync_work);
- char buf[64];
- char *envp[2];
+ int cndx;
+ struct vsycn_ctrl *vctrl;
+ ssize_t ret = 0;
+ unsigned long flags;
- snprintf(buf, sizeof(buf), "VSYNC=%llu",
+ cndx = 0;
+ vctrl = &vsync_ctrl_db[0];
+
+ if (atomic_read(&vctrl->suspend) > 0 ||
+ atomic_read(&vctrl->vsync_resume) == 0)
+ return 0;
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (vctrl->wait_vsync_cnt == 0)
+ INIT_COMPLETION(vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt++;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ wait_for_completion(&vctrl->vsync_comp);
+
+ ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
ktime_to_ns(vctrl->vsync_time));
- envp[0] = buf;
- envp[1] = NULL;
- kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp);
+ buf[strlen(buf) + 1] = '\0';
+ return ret;
}
-
void mdp4_dsi_rdptr_init(int cndx)
{
struct vsycn_ctrl *vctrl;
@@ -671,7 +689,7 @@
init_completion(&vctrl->dmap_comp);
init_completion(&vctrl->vsync_comp);
spin_lock_init(&vctrl->spin_lock);
- INIT_WORK(&vctrl->vsync_work, send_vsync_work);
+ atomic_set(&vctrl->vsync_resume, 1);
INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
}
@@ -952,6 +970,14 @@
mdp4_dsi_cmd_do_blt(mfd, req->enable);
}
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+ &dev_attr_vsync_event.attr,
+ NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+ .attrs = vsync_fs_attrs,
+};
int mdp4_dsi_cmd_on(struct platform_device *pdev)
{
int ret = 0;
@@ -976,6 +1002,19 @@
atomic_set(&vctrl->suspend, 0);
pr_debug("%s-:\n", __func__);
+ if (!vctrl->sysfs_created) {
+ ret = sysfs_create_group(&vctrl->dev->kobj,
+ &vsync_fs_attr_group);
+ if (ret) {
+ pr_err("%s: sysfs group creation failed, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
+ pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+ vctrl->sysfs_created = 1;
+ }
return ret;
}
@@ -987,6 +1026,8 @@
struct msm_fb_data_type *mfd;
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
+ struct vsync_update *vp;
+ int undx;
pr_debug("%s+:\n", __func__);
@@ -1000,6 +1041,9 @@
}
atomic_set(&vctrl->suspend, 1);
+ atomic_set(&vctrl->vsync_resume, 0);
+
+ complete_all(&vctrl->vsync_comp);
/* sanity check, free pipes besides base layer */
mdp4_overlay_unset_mixer(pipe->mixer_num);
@@ -1016,11 +1060,20 @@
mdp_clk_ctrl(0);
}
+ undx = vctrl->update_ndx;
+ vp = &vctrl->vlist[undx];
+ if (vp->update_cnt) {
+ /*
+ * pipe's iommu will be freed at next overlay play
+ * and iommu_drop statistic will be increased by one
+ */
+ vp->update_cnt = 0; /* empty queue */
+ }
+
vctrl->clk_enabled = 0;
vctrl->vsync_enabled = 0;
vctrl->clk_control = 0;
vctrl->expire_tick = 0;
- vctrl->uevent = 0;
vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
@@ -1068,7 +1121,7 @@
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
unsigned long flags;
- long long xx;
+ long long tick;
vctrl = &vsync_ctrl_db[cndx];
@@ -1109,10 +1162,10 @@
mdp4_overlay_mdp_perf_upd(mfd, 1);
mutex_lock(&mfd->dma->ov_mutex);
- mdp4_dsi_cmd_pipe_commit();
+ mdp4_dsi_cmd_pipe_commit(cndx, 0);
mutex_unlock(&mfd->dma->ov_mutex);
- mdp4_dsi_cmd_wait4vsync(0, &xx);
+ mdp4_dsi_cmd_wait4vsync(cndx, &tick);
mdp4_overlay_mdp_perf_upd(mfd, 0);
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 2d21929..6aa101f 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -52,10 +52,11 @@
int ov_koff;
int ov_done;
atomic_t suspend;
+ atomic_t vsync_resume;
int wait_vsync_cnt;
int blt_change;
int blt_free;
- int fake_vsync;
+ int sysfs_created;
struct mutex update_lock;
struct completion ov_comp;
struct completion dmap_comp;
@@ -66,7 +67,6 @@
struct vsync_update vlist[2];
int vsync_irq_enabled;
ktime_t vsync_time;
- struct work_struct vsync_work;
} vsync_ctrl_db[MAX_CONTROLLER];
static void vsync_irq_enable(int intr, int term)
@@ -147,7 +147,7 @@
static void mdp4_dsi_video_wait4dmap(int cndx);
static void mdp4_dsi_video_wait4ov(int cndx);
-int mdp4_dsi_video_pipe_commit(void)
+int mdp4_dsi_video_pipe_commit(int cndx, int wait)
{
int i, undx;
@@ -159,7 +159,7 @@
unsigned long flags;
int cnt = 0;
- vctrl = &vsync_ctrl_db[0];
+ vctrl = &vsync_ctrl_db[cndx];
mutex_lock(&vctrl->update_lock);
undx = vctrl->update_ndx;
@@ -253,6 +253,13 @@
mdp4_stat.overlay_commit[pipe->mixer_num]++;
+ if (wait) {
+ if (pipe->ov_blt_addr)
+ mdp4_dsi_video_wait4ov(cndx);
+ else
+ mdp4_dsi_video_wait4dmap(cndx);
+ }
+
return cnt;
}
@@ -263,11 +270,6 @@
vctrl = &vsync_ctrl_db[cndx];
- if (vctrl->fake_vsync) {
- vctrl->fake_vsync = 0;
- schedule_work(&vctrl->vsync_work);
- }
-
if (vctrl->vsync_irq_enabled == enable)
return;
@@ -279,6 +281,9 @@
vsync_irq_enable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
else
vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+
+ if (vctrl->vsync_irq_enabled && atomic_read(&vctrl->suspend) == 0)
+ atomic_set(&vctrl->vsync_resume, 1);
}
void mdp4_dsi_video_wait4vsync(int cndx, long long *vtime)
@@ -350,7 +355,6 @@
vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
mdp4_dsi_video_wait4dmap(cndx);
- vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
}
@@ -371,18 +375,32 @@
wait_for_completion(&vctrl->ov_comp);
}
-static void send_vsync_work(struct work_struct *work)
+static ssize_t vsync_show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct vsycn_ctrl *vctrl =
- container_of(work, typeof(*vctrl), vsync_work);
- char buf[64];
- char *envp[2];
+ int cndx;
+ struct vsycn_ctrl *vctrl;
+ ssize_t ret = 0;
+ unsigned long flags;
- snprintf(buf, sizeof(buf), "VSYNC=%llu",
+ cndx = 0;
+ vctrl = &vsync_ctrl_db[0];
+
+ if (atomic_read(&vctrl->suspend) > 0 ||
+ atomic_read(&vctrl->vsync_resume) == 0)
+ return 0;
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (vctrl->wait_vsync_cnt == 0)
+ INIT_COMPLETION(vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt++;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ wait_for_completion(&vctrl->vsync_comp);
+
+ ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
ktime_to_ns(vctrl->vsync_time));
- envp[0] = buf;
- envp[1] = NULL;
- kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp);
+ buf[strlen(buf) + 1] = '\0';
+ return ret;
}
void mdp4_dsi_vsync_init(int cndx)
@@ -407,8 +425,8 @@
init_completion(&vctrl->dmap_comp);
init_completion(&vctrl->ov_comp);
atomic_set(&vctrl->suspend, 0);
+ atomic_set(&vctrl->vsync_resume, 1);
spin_lock_init(&vctrl->spin_lock);
- INIT_WORK(&vctrl->vsync_work, send_vsync_work);
}
void mdp4_dsi_video_base_swap(int cndx, struct mdp4_overlay_pipe *pipe)
@@ -424,6 +442,16 @@
vctrl->base_pipe = pipe;
}
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+
+static struct attribute *vsync_fs_attrs[] = {
+ &dev_attr_vsync_event.attr,
+ NULL,
+};
+
+static struct attribute_group vsync_fs_attr_group = {
+ .attrs = vsync_fs_attrs,
+};
int mdp4_dsi_video_on(struct platform_device *pdev)
{
int dsi_width;
@@ -478,7 +506,6 @@
vctrl->mfd = mfd;
vctrl->dev = mfd->fbi->dev;
- vctrl->fake_vsync = 1;
/* mdp clock on */
mdp_clk_ctrl(1);
@@ -522,6 +549,9 @@
mdp4_dsi_video_wait4dmap_done(0);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
mipi_dsi_controller_cfg(0);
+ /* Clks are enabled in probe.
+ Disabling clocks now */
+ mdp_clk_ctrl(0);
}
pipe->src_height = fbi->var.yres;
@@ -634,6 +664,21 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_histogram_ctrl_all(TRUE);
+
+ if (!vctrl->sysfs_created) {
+ ret = sysfs_create_group(&vctrl->dev->kobj,
+ &vsync_fs_attr_group);
+ if (ret) {
+ pr_err("%s: sysfs group creation failed, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
+ pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+ vctrl->sysfs_created = 1;
+ }
+
return ret;
}
@@ -644,17 +689,21 @@
struct msm_fb_data_type *mfd;
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
+ struct vsync_update *vp;
unsigned long flags;
- int need_wait = 0;
+ int undx, need_wait = 0;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
atomic_set(&vctrl->suspend, 1);
+ atomic_set(&vctrl->vsync_resume, 0);
msleep(20); /* >= 17 ms */
+ complete_all(&vctrl->vsync_comp);
+
if (pipe->ov_blt_addr) {
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (vctrl->ov_koff != vctrl->ov_done)
@@ -670,6 +719,21 @@
dsi_video_enabled = 0;
+ if (vctrl->vsync_irq_enabled) {
+ vctrl->vsync_irq_enabled = 0;
+ vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+ }
+
+ undx = vctrl->update_ndx;
+ vp = &vctrl->vlist[undx];
+ if (vp->update_cnt) {
+ /*
+ * pipe's iommu will be freed at next overlay play
+ * and iommu_drop statistic will be increased by one
+ */
+ vp->update_cnt = 0; /* empty queue */
+ }
+
if (pipe) {
/* sanity check, free pipes besides base layer */
mdp4_overlay_unset_mixer(pipe->mixer_num);
@@ -691,8 +755,6 @@
}
}
- vctrl->fake_vsync = 1;
-
/* mdp clock off */
mdp_clk_ctrl(0);
mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -857,7 +919,6 @@
vctrl = &vsync_ctrl_db[cndx];
pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
vctrl->vsync_time = ktime_get();
- schedule_work(&vctrl->vsync_work);
spin_lock(&vctrl->spin_lock);
if (vctrl->wait_vsync_cnt) {
@@ -881,6 +942,8 @@
}
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
+ if (pipe == NULL)
+ return;
spin_lock(&vctrl->spin_lock);
vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
@@ -916,6 +979,8 @@
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
+ if (pipe == NULL)
+ return;
spin_lock(&vctrl->spin_lock);
vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
@@ -1028,16 +1093,17 @@
mdp4_dsi_video_pipe_queue(0, pipe);
}
+ mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
mdp4_overlay_mdp_perf_upd(mfd, 1);
mutex_lock(&mfd->dma->ov_mutex);
- mdp4_dsi_video_pipe_commit();
+ mdp4_dsi_video_pipe_commit(cndx, 0);
mutex_unlock(&mfd->dma->ov_mutex);
if (pipe->ov_blt_addr)
- mdp4_dsi_video_wait4ov(0);
+ mdp4_dsi_video_wait4ov(cndx);
else
- mdp4_dsi_video_wait4dmap(0);
+ mdp4_dsi_video_wait4dmap(cndx);
mdp4_overlay_mdp_perf_upd(mfd, 0);
}
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index f01543b..21e5d1d 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -29,6 +29,7 @@
#include "mdp.h"
#include "msm_fb.h"
+#include "hdmi_msm.h"
#include "mdp4.h"
#define DTV_BASE 0xD0000
@@ -70,10 +71,11 @@
int update_ndx;
int dmae_intr_cnt;
atomic_t suspend;
+ atomic_t vsync_resume;
int dmae_wait_cnt;
int wait_vsync_cnt;
int blt_change;
- int fake_vsync;
+ int sysfs_created;
struct mutex update_lock;
struct completion ov_comp;
struct completion dmae_comp;
@@ -83,7 +85,6 @@
struct vsync_update vlist[2];
int vsync_irq_enabled;
ktime_t vsync_time;
- struct work_struct vsync_work;
} vsync_ctrl_db[MAX_CONTROLLER];
static void vsync_irq_enable(int intr, int term)
@@ -164,7 +165,7 @@
static void mdp4_dtv_blt_ov_update(struct mdp4_overlay_pipe *pipe);
static void mdp4_dtv_wait4dmae(int cndx);
-int mdp4_dtv_pipe_commit(void)
+int mdp4_dtv_pipe_commit(int cndx, int wait)
{
int i, undx;
@@ -176,7 +177,7 @@
unsigned long flags;
int cnt = 0;
- vctrl = &vsync_ctrl_db[0];
+ vctrl = &vsync_ctrl_db[cndx];
mutex_lock(&vctrl->update_lock);
undx = vctrl->update_ndx;
vp = &vctrl->vlist[undx];
@@ -235,6 +236,9 @@
spin_unlock_irqrestore(&vctrl->spin_lock, flags);
mdp4_stat.overlay_commit[pipe->mixer_num]++;
+ if (wait)
+ mdp4_dtv_wait4dmae(cndx);
+
return cnt;
}
@@ -245,10 +249,8 @@
vctrl = &vsync_ctrl_db[cndx];
- if (vctrl->fake_vsync) {
- vctrl->fake_vsync = 0;
- schedule_work(&vctrl->vsync_work);
- }
+ if (!external_common_state->hpd_state)
+ complete_all(&vctrl->vsync_comp);
if (vctrl->vsync_irq_enabled == enable)
return;
@@ -261,6 +263,9 @@
vsync_irq_enable(INTR_EXTERNAL_VSYNC, MDP_EXTER_VSYNC_TERM);
else
vsync_irq_disable(INTR_EXTERNAL_VSYNC, MDP_EXTER_VSYNC_TERM);
+
+ if (vctrl->vsync_irq_enabled && atomic_read(&vctrl->suspend) == 0)
+ atomic_set(&vctrl->vsync_resume, 1);
}
void mdp4_dtv_wait4vsync(int cndx, long long *vtime)
@@ -310,20 +315,34 @@
wait_for_completion(&vctrl->dmae_comp);
}
-static void send_vsync_work(struct work_struct *work)
+static ssize_t vsync_show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct vsycn_ctrl *vctrl =
- container_of(work, typeof(*vctrl), vsync_work);
- char buf[64];
- char *envp[2];
+ int cndx;
+ struct vsycn_ctrl *vctrl;
+ ssize_t ret = 0;
+ unsigned long flags;
- snprintf(buf, sizeof(buf), "VSYNC=%llu",
+ cndx = 0;
+ vctrl = &vsync_ctrl_db[0];
+
+ if (atomic_read(&vctrl->suspend) > 0 ||
+ !external_common_state->hpd_state ||
+ atomic_read(&vctrl->vsync_resume) == 0)
+ return 0;
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (vctrl->wait_vsync_cnt == 0)
+ INIT_COMPLETION(vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt++;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ wait_for_completion(&vctrl->vsync_comp);
+
+ ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
ktime_to_ns(vctrl->vsync_time));
- envp[0] = buf;
- envp[1] = NULL;
- kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp);
+ buf[strlen(buf) + 1] = '\0';
+ return ret;
}
-
void mdp4_dtv_vsync_init(int cndx)
{
struct vsycn_ctrl *vctrl;
@@ -346,8 +365,8 @@
init_completion(&vctrl->ov_comp);
init_completion(&vctrl->dmae_comp);
atomic_set(&vctrl->suspend, 0);
+ atomic_set(&vctrl->vsync_resume, 1);
spin_lock_init(&vctrl->spin_lock);
- INIT_WORK(&vctrl->vsync_work, send_vsync_work);
}
static int mdp4_dtv_start(struct msm_fb_data_type *mfd)
@@ -506,6 +525,15 @@
return 0;
}
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+ &dev_attr_vsync_event.attr,
+ NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+ .attrs = vsync_fs_attrs,
+};
+
int mdp4_dtv_on(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
@@ -524,7 +552,6 @@
return -EINVAL;
vctrl->dev = mfd->fbi->dev;
- vctrl->fake_vsync = 1;
mdp_footswitch_ctrl(TRUE);
/* Mdp clock enable */
@@ -547,6 +574,19 @@
atomic_set(&vctrl->suspend, 0);
+ if (!vctrl->sysfs_created) {
+ ret = sysfs_create_group(&vctrl->dev->kobj,
+ &vsync_fs_attr_group);
+ if (ret) {
+ pr_err("%s: sysfs group creation failed, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
+ pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+ vctrl->sysfs_created = 1;
+ }
pr_info("%s:\n", __func__);
return ret;
@@ -557,17 +597,24 @@
struct msm_fb_data_type *mfd;
int ret = 0;
int cndx = 0;
+ int undx;
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
+ struct vsync_update *vp;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
vctrl = &vsync_ctrl_db[cndx];
atomic_set(&vctrl->suspend, 1);
+ atomic_set(&vctrl->vsync_resume, 0);
- while (vctrl->wait_vsync_cnt)
- msleep(20); /* >= 17 ms */
+ if (vctrl->vsync_irq_enabled) {
+ while (vctrl->wait_vsync_cnt)
+ msleep(20); /* >= 17 ms */
+ }
+
+ complete_all(&vctrl->vsync_comp);
pipe = vctrl->base_pipe;
if (pipe != NULL) {
@@ -594,9 +641,23 @@
mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV);
+ if (vctrl->vsync_irq_enabled) {
+ vctrl->vsync_irq_enabled = 0;
+ vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+ }
+
+ undx = vctrl->update_ndx;
+ vp = &vctrl->vlist[undx];
+ if (vp->update_cnt) {
+ /*
+ * pipe's iommu will be freed at next overlay play
+ * and iommu_drop statistic will be increased by one
+ */
+ vp->update_cnt = 0; /* empty queue */
+ }
+
ret = panel_next_off(pdev);
mdp_footswitch_ctrl(FALSE);
- vctrl->fake_vsync = 1;
/* Mdp clock disable */
mdp_clk_ctrl(0);
@@ -795,7 +856,6 @@
vctrl = &vsync_ctrl_db[cndx];
pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
vctrl->vsync_time = ktime_get();
- schedule_work(&vctrl->vsync_work);
spin_lock(&vctrl->spin_lock);
if (vctrl->wait_vsync_cnt) {
@@ -822,6 +882,8 @@
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
+ if (pipe == NULL)
+ return;
pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
spin_lock(&vctrl->spin_lock);
@@ -862,6 +924,8 @@
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
+ if (pipe == NULL)
+ return;
spin_lock(&vctrl->spin_lock);
if (pipe->ov_blt_addr == 0) {
@@ -1011,10 +1075,11 @@
pipe->srcp0_addr = (uint32)mfd->ibuf.buf;
mdp4_dtv_pipe_queue(0, pipe);
}
+ mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
mutex_lock(&mfd->dma->ov_mutex);
mdp4_overlay_mdp_perf_upd(mfd, 1);
- mdp4_dtv_pipe_commit();
+ mdp4_dtv_pipe_commit(cndx, 0);
mdp4_overlay_mdp_perf_upd(mfd, 0);
mutex_unlock(&mfd->dma->ov_mutex);
}
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index bc8ded5..1f5136f 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -53,10 +53,11 @@
int ov_koff;
int ov_done;
atomic_t suspend;
+ atomic_t vsync_resume;
int wait_vsync_cnt;
int blt_change;
int blt_free;
- int fake_vsync;
+ int sysfs_created;
struct mutex update_lock;
struct completion ov_comp;
struct completion dmap_comp;
@@ -67,7 +68,6 @@
struct vsync_update vlist[2];
int vsync_irq_enabled;
ktime_t vsync_time;
- struct work_struct vsync_work;
} vsync_ctrl_db[MAX_CONTROLLER];
@@ -152,7 +152,7 @@
static void mdp4_lcdc_wait4dmap(int cndx);
static void mdp4_lcdc_wait4ov(int cndx);
-int mdp4_lcdc_pipe_commit(void)
+int mdp4_lcdc_pipe_commit(int cndx, int wait)
{
int i, undx;
@@ -164,7 +164,7 @@
unsigned long flags;
int cnt = 0;
- vctrl = &vsync_ctrl_db[0];
+ vctrl = &vsync_ctrl_db[cndx];
mutex_lock(&vctrl->update_lock);
undx = vctrl->update_ndx;
@@ -257,6 +257,13 @@
mdp4_stat.overlay_commit[pipe->mixer_num]++;
+ if (wait) {
+ if (pipe->ov_blt_addr)
+ mdp4_lcdc_wait4ov(cndx);
+ else
+ mdp4_lcdc_wait4dmap(cndx);
+ }
+
return cnt;
}
@@ -267,11 +274,6 @@
vctrl = &vsync_ctrl_db[cndx];
- if (vctrl->fake_vsync) {
- vctrl->fake_vsync = 0;
- schedule_work(&vctrl->vsync_work);
- }
-
if (vctrl->vsync_irq_enabled == enable)
return;
@@ -283,6 +285,9 @@
vsync_irq_enable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
else
vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+
+ if (vctrl->vsync_irq_enabled && atomic_read(&vctrl->suspend) == 0)
+ atomic_set(&vctrl->vsync_resume, 1);
}
void mdp4_lcdc_wait4vsync(int cndx, long long *vtime)
@@ -354,18 +359,32 @@
wait_for_completion(&vctrl->ov_comp);
}
-static void send_vsync_work(struct work_struct *work)
+static ssize_t vsync_show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct vsycn_ctrl *vctrl =
- container_of(work, typeof(*vctrl), vsync_work);
- char buf[64];
- char *envp[2];
+ int cndx;
+ struct vsycn_ctrl *vctrl;
+ ssize_t ret = 0;
+ unsigned long flags;
- snprintf(buf, sizeof(buf), "VSYNC=%llu",
- ktime_to_ns(vctrl->vsync_time));
- envp[0] = buf;
- envp[1] = NULL;
- kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp);
+ cndx = 0;
+ vctrl = &vsync_ctrl_db[0];
+
+ if (atomic_read(&vctrl->suspend) > 0 ||
+ atomic_read(&vctrl->vsync_resume) == 0)
+ return 0;
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (vctrl->wait_vsync_cnt == 0)
+ INIT_COMPLETION(vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt++;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ wait_for_completion(&vctrl->vsync_comp);
+
+ ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
+ ktime_to_ns(vctrl->vsync_time));
+ buf[strlen(buf) + 1] = '\0';
+ return ret;
}
void mdp4_lcdc_vsync_init(int cndx)
@@ -390,8 +409,8 @@
init_completion(&vctrl->dmap_comp);
init_completion(&vctrl->ov_comp);
atomic_set(&vctrl->suspend, 0);
+ atomic_set(&vctrl->vsync_resume, 1);
spin_lock_init(&vctrl->spin_lock);
- INIT_WORK(&vctrl->vsync_work, send_vsync_work);
}
void mdp4_lcdc_base_swap(int cndx, struct mdp4_overlay_pipe *pipe)
@@ -407,6 +426,15 @@
vctrl->base_pipe = pipe;
}
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+ &dev_attr_vsync_event.attr,
+ NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+ .attrs = vsync_fs_attrs,
+};
+
int mdp4_lcdc_on(struct platform_device *pdev)
{
int lcdc_width;
@@ -461,7 +489,6 @@
vctrl->mfd = mfd;
vctrl->dev = mfd->fbi->dev;
- vctrl->fake_vsync = 1;
/* mdp clock on */
mdp_clk_ctrl(1);
@@ -621,6 +648,21 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_histogram_ctrl_all(TRUE);
+
+ if (!vctrl->sysfs_created) {
+ ret = sysfs_create_group(&vctrl->dev->kobj,
+ &vsync_fs_attr_group);
+ if (ret) {
+ pr_err("%s: sysfs group creation failed, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ kobject_uevent(&vctrl->dev->kobj, KOBJ_ADD);
+ pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+ vctrl->sysfs_created = 1;
+ }
+
return ret;
}
@@ -631,17 +673,21 @@
struct msm_fb_data_type *mfd;
struct vsycn_ctrl *vctrl;
struct mdp4_overlay_pipe *pipe;
+ struct vsync_update *vp;
unsigned long flags;
- int need_wait = 0;
+ int undx, need_wait = 0;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
atomic_set(&vctrl->suspend, 1);
+ atomic_set(&vctrl->vsync_resume, 0);
msleep(20); /* >= 17 ms */
+ complete_all(&vctrl->vsync_comp);
+
if (pipe->ov_blt_addr) {
spin_lock_irqsave(&vctrl->spin_lock, flags);
if (vctrl->ov_koff != vctrl->ov_done)
@@ -657,6 +703,21 @@
lcdc_enabled = 0;
+ if (vctrl->vsync_irq_enabled) {
+ vctrl->vsync_irq_enabled = 0;
+ vsync_irq_disable(INTR_PRIMARY_VSYNC, MDP_PRIM_VSYNC_TERM);
+ }
+
+ undx = vctrl->update_ndx;
+ vp = &vctrl->vlist[undx];
+ if (vp->update_cnt) {
+ /*
+ * pipe's iommu will be freed at next overlay play
+ * and iommu_drop statistic will be increased by one
+ */
+ vp->update_cnt = 0; /* empty queue */
+ }
+
if (pipe) {
/* sanity check, free pipes besides base layer */
mdp4_overlay_unset_mixer(pipe->mixer_num);
@@ -678,8 +739,6 @@
}
}
- vctrl->fake_vsync = 1;
-
/* MDP clock disable */
mdp_clk_ctrl(0);
mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
@@ -746,7 +805,6 @@
vctrl = &vsync_ctrl_db[cndx];
pr_debug("%s: cpu=%d\n", __func__, smp_processor_id());
vctrl->vsync_time = ktime_get();
- schedule_work(&vctrl->vsync_work);
spin_lock(&vctrl->spin_lock);
if (vctrl->wait_vsync_cnt) {
@@ -771,6 +829,8 @@
}
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
+ if (pipe == NULL)
+ return;
spin_lock(&vctrl->spin_lock);
vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
@@ -809,6 +869,8 @@
vctrl = &vsync_ctrl_db[cndx];
pipe = vctrl->base_pipe;
+ if (pipe == NULL)
+ return;
spin_lock(&vctrl->spin_lock);
vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
@@ -917,17 +979,18 @@
mdp4_lcdc_pipe_queue(0, pipe);
}
+ mdp_update_pm(mfd, vsync_ctrl_db[0].vsync_time);
mdp4_overlay_mdp_perf_upd(mfd, 1);
mutex_lock(&mfd->dma->ov_mutex);
- mdp4_lcdc_pipe_commit();
+ mdp4_lcdc_pipe_commit(cndx, 0);
mutex_unlock(&mfd->dma->ov_mutex);
if (pipe->ov_blt_addr)
- mdp4_lcdc_wait4ov(0);
+ mdp4_lcdc_wait4ov(cndx);
else
- mdp4_lcdc_wait4dmap(0);
+ mdp4_lcdc_wait4dmap(cndx);
mdp4_overlay_mdp_perf_upd(mfd, 0);
}
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index be4a89a..ca84eca 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, 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,38 +17,680 @@
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/hrtimer.h>
#include <linux/delay.h>
-#include <mach/hardware.h>
#include <linux/io.h>
-
-#include <asm/system.h>
-#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
-
#include <linux/fb.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
-static struct mdp4_overlay_pipe *mddi_pipe;
-static struct msm_fb_data_type *mddi_mfd;
-static int busy_wait_cnt;
+static int mddi_state;
+
+#define TOUT_PERIOD HZ /* 1 second */
+#define MS_100 (HZ/10) /* 100 ms */
static int vsync_start_y_adjust = 4;
-static int dmap_vsync_enable;
+#define MAX_CONTROLLER 1
+#define VSYNC_EXPIRE_TICK 8
-void mdp_dmap_vsync_set(int enable)
+static struct vsycn_ctrl {
+ struct device *dev;
+ int inited;
+ int update_ndx;
+ int expire_tick;
+ int blt_wait;
+ u32 ov_koff;
+ u32 ov_done;
+ u32 dmap_koff;
+ u32 dmap_done;
+ uint32 rdptr_intr_tot;
+ uint32 rdptr_sirq_tot;
+ atomic_t suspend;
+ int wait_vsync_cnt;
+ int blt_change;
+ int blt_free;
+ int blt_end;
+ int uevent;
+ struct mutex update_lock;
+ struct completion ov_comp;
+ struct completion dmap_comp;
+ struct completion vsync_comp;
+ spinlock_t spin_lock;
+ struct msm_fb_data_type *mfd;
+ struct mdp4_overlay_pipe *base_pipe;
+ struct vsync_update vlist[2];
+ int vsync_enabled;
+ int clk_enabled;
+ int clk_control;
+ int new_update;
+ ktime_t vsync_time;
+ struct work_struct vsync_work;
+ struct work_struct clk_work;
+} vsync_ctrl_db[MAX_CONTROLLER];
+
+static void vsync_irq_enable(int intr, int term)
{
- dmap_vsync_enable = enable;
+ unsigned long flag;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ /* no need to clear other interrupts for comamnd mode */
+ mdp_intr_mask |= intr;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_enable_irq(term);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
}
-int mdp_dmap_vsync_get(void)
+static void vsync_irq_disable(int intr, int term)
{
- return dmap_vsync_enable;
+ unsigned long flag;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ /* no need to clrear other interrupts for comamnd mode */
+ mdp_intr_mask &= ~intr;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_disable_irq_nosync(term);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+}
+
+static void mdp4_mddi_blt_ov_update(struct mdp4_overlay_pipe *pipe)
+{
+ uint32 off, addr;
+ int bpp;
+ char *overlay_base;
+
+ if (pipe->ov_blt_addr == 0)
+ return;
+
+ bpp = 3; /* overlay ouput is RGB888 */
+ off = 0;
+ if (pipe->ov_cnt & 0x01)
+ off = pipe->src_height * pipe->src_width * bpp;
+ addr = pipe->ov_blt_addr + off;
+ /* overlay 0 */
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
+ outpdw(overlay_base + 0x000c, addr);
+ outpdw(overlay_base + 0x001c, addr);
+}
+
+static void mdp4_mddi_blt_dmap_update(struct mdp4_overlay_pipe *pipe)
+{
+ uint32 off, addr;
+ int bpp;
+
+ if (pipe->ov_blt_addr == 0)
+ return;
+
+ bpp = 3; /* overlay ouput is RGB888 */
+ off = 0;
+ if (pipe->dmap_cnt & 0x01)
+ off = pipe->src_height * pipe->src_width * bpp;
+ addr = pipe->dma_blt_addr + off;
+
+ /* dmap */
+ MDP_OUTP(MDP_BASE + 0x90008, addr);
+}
+
+static void mdp4_mddi_wait4dmap(int cndx);
+static void mdp4_mddi_wait4ov(int cndx);
+
+static void mdp4_mddi_do_blt(struct msm_fb_data_type *mfd, int enable)
+{
+ unsigned long flags;
+ int cndx = 0;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ int need_wait;
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+
+ mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+
+ if (mfd->ov0_wb_buf->write_addr == 0) {
+ pr_err("%s: no blt_base assigned\n", __func__);
+ return;
+ }
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (enable && pipe->ov_blt_addr == 0) {
+ vctrl->blt_change++;
+ if (vctrl->dmap_koff != vctrl->dmap_done) {
+ INIT_COMPLETION(vctrl->dmap_comp);
+ need_wait = 1;
+ }
+ } else if (enable == 0 && pipe->ov_blt_addr) {
+ vctrl->blt_change++;
+ if (vctrl->ov_koff != vctrl->dmap_done) {
+ INIT_COMPLETION(vctrl->dmap_comp);
+ need_wait = 1;
+ }
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ if (need_wait)
+ mdp4_mddi_wait4dmap(0);
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (enable && pipe->ov_blt_addr == 0) {
+ pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr;
+ pipe->dma_blt_addr = mfd->ov0_wb_buf->read_addr;
+ pipe->ov_cnt = 0;
+ pipe->dmap_cnt = 0;
+ vctrl->ov_koff = vctrl->dmap_koff;
+ vctrl->ov_done = vctrl->dmap_done;
+ vctrl->blt_free = 0;
+ vctrl->blt_wait = 0;
+ vctrl->blt_end = 0;
+ mdp4_stat.blt_mddi++;
+ } else if (enable == 0 && pipe->ov_blt_addr) {
+ pipe->ov_blt_addr = 0;
+ pipe->dma_blt_addr = 0;
+ vctrl->blt_end = 1;
+ vctrl->blt_free = 4; /* 4 commits to free wb buf */
+ }
+
+ pr_debug("%s: changed=%d enable=%d ov_blt_addr=%x\n", __func__,
+ vctrl->blt_change, enable, (int)pipe->ov_blt_addr);
+
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+}
+
+/*
+ * mdp4_mddi_do_update:
+ * called from thread context
+ */
+void mdp4_mddi_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe)
+{
+ struct vsycn_ctrl *vctrl;
+ struct vsync_update *vp;
+ struct mdp4_overlay_pipe *pp;
+ int undx;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ mutex_lock(&vctrl->update_lock);
+ undx = vctrl->update_ndx;
+ vp = &vctrl->vlist[undx];
+
+ pp = &vp->plist[pipe->pipe_ndx - 1]; /* ndx start form 1 */
+
+ pr_debug("%s: vndx=%d pipe_ndx=%d expire=%x pid=%d\n", __func__,
+ undx, pipe->pipe_ndx, vctrl->expire_tick, current->pid);
+
+ *pp = *pipe; /* clone it */
+ vp->update_cnt++;
+
+ mutex_unlock(&vctrl->update_lock);
+ mdp4_stat.overlay_play[pipe->mixer_num]++;
+}
+
+static void mdp4_mddi_blt_ov_update(struct mdp4_overlay_pipe *pipe);
+
+int mdp4_mddi_pipe_commit(void)
+{
+ int i, undx;
+ int mixer = 0;
+ struct vsycn_ctrl *vctrl;
+ struct vsync_update *vp;
+ struct mdp4_overlay_pipe *pipe;
+ struct mdp4_overlay_pipe *real_pipe;
+ unsigned long flags;
+ int need_dmap_wait = 0;
+ int need_ov_wait = 0;
+ int cnt = 0;
+
+ vctrl = &vsync_ctrl_db[0];
+
+ mutex_lock(&vctrl->update_lock);
+ undx = vctrl->update_ndx;
+ vp = &vctrl->vlist[undx];
+ pipe = vctrl->base_pipe;
+ mixer = pipe->mixer_num;
+
+ if (vp->update_cnt == 0) {
+ mutex_unlock(&vctrl->update_lock);
+ return cnt;
+ }
+
+ vctrl->update_ndx++;
+ vctrl->update_ndx &= 0x01;
+ vp->update_cnt = 0; /* reset */
+ if (vctrl->blt_free) {
+ vctrl->blt_free--;
+ if (vctrl->blt_free == 0)
+ mdp4_free_writeback_buf(vctrl->mfd, mixer);
+ }
+ mutex_unlock(&vctrl->update_lock);
+
+ /* free previous committed iommu back to pool */
+ mdp4_overlay_iommu_unmap_freelist(mixer);
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (pipe->ov_blt_addr) {
+ /* Blt */
+ if (vctrl->blt_wait)
+ need_dmap_wait = 1;
+ if (vctrl->ov_koff != vctrl->ov_done) {
+ INIT_COMPLETION(vctrl->ov_comp);
+ need_ov_wait = 1;
+ }
+ } else {
+ /* direct out */
+ if (vctrl->dmap_koff != vctrl->dmap_done) {
+ INIT_COMPLETION(vctrl->dmap_comp);
+ pr_debug("%s: wait, ok=%d od=%d dk=%d dd=%d cpu=%d\n",
+ __func__, vctrl->ov_koff, vctrl->ov_done,
+ vctrl->dmap_koff, vctrl->dmap_done, smp_processor_id());
+ need_dmap_wait = 1;
+ }
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ if (need_dmap_wait) {
+ pr_debug("%s: wait4dmap\n", __func__);
+ mdp4_mddi_wait4dmap(0);
+ }
+
+ if (need_ov_wait) {
+ pr_debug("%s: wait4ov\n", __func__);
+ mdp4_mddi_wait4ov(0);
+ }
+
+ if (pipe->ov_blt_addr) {
+ if (vctrl->blt_end) {
+ vctrl->blt_end = 0;
+ pipe->ov_blt_addr = 0;
+ pipe->dma_blt_addr = 0;
+ }
+ }
+
+ if (vctrl->blt_change) {
+ mdp4_overlayproc_cfg(pipe);
+ mdp4_overlay_dmap_xy(pipe);
+ vctrl->blt_change = 0;
+ }
+
+ pipe = vp->plist;
+ for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
+ if (pipe->pipe_used) {
+ cnt++;
+ real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+ if (real_pipe && real_pipe->pipe_used) {
+ /* pipe not unset */
+ mdp4_overlay_vsync_commit(pipe);
+ }
+ /* free previous iommu to freelist
+ * which will be freed at next
+ * pipe_commit
+ */
+ mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
+ pipe->pipe_used = 0; /* clear */
+ }
+ }
+
+ mdp4_mixer_stage_commit(mixer);
+
+ pipe = vctrl->base_pipe;
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (pipe->ov_blt_addr) {
+ mdp4_mddi_blt_ov_update(pipe);
+ pipe->ov_cnt++;
+ vctrl->ov_koff++;
+ vsync_irq_enable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
+ } else {
+ vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+ vctrl->dmap_koff++;
+ }
+ pr_debug("%s: kickoff\n", __func__);
+ /* kickoff overlay engine */
+ mdp4_stat.kickoff_ov0++;
+ outpdw(MDP_BASE + 0x0004, 0);
+ mb(); /* make sure kickoff ececuted */
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ mdp4_stat.overlay_commit[pipe->mixer_num]++;
+
+ return cnt;
+}
+
+void mdp4_mddi_vsync_ctrl(struct fb_info *info, int enable)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct vsycn_ctrl *vctrl;
+ unsigned long flags;
+ int clk_set_on = 0;
+ int cndx = 0;
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ pr_debug("%s: clk_enabled=%d vsycn_enabeld=%d req=%d\n", __func__,
+ vctrl->clk_enabled, vctrl->vsync_enabled, enable);
+
+ mutex_lock(&vctrl->update_lock);
+
+ if (vctrl->vsync_enabled == enable) {
+ mutex_unlock(&vctrl->update_lock);
+ return;
+ }
+
+ vctrl->vsync_enabled = enable;
+
+ if (enable) {
+ if (vctrl->clk_enabled == 0) {
+ pr_debug("%s: SET_CLK_ON\n", __func__);
+ mdp_clk_ctrl(1);
+ vctrl->clk_enabled = 1;
+ clk_set_on = 1;
+ }
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vctrl->clk_control = 0;
+ vctrl->expire_tick = 0;
+ vctrl->uevent = 1;
+ vctrl->new_update = 1;
+ if (clk_set_on) {
+ vsync_irq_enable(INTR_PRIMARY_RDPTR,
+ MDP_PRIM_RDPTR_TERM);
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ mdp4_overlay_update_mddi(mfd);
+ } else {
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vctrl->clk_control = 1;
+ vctrl->uevent = 0;
+ if (vctrl->clk_enabled)
+ vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ }
+ mutex_unlock(&vctrl->update_lock);
+}
+
+void mdp4_mddi_wait4vsync(int cndx, long long *vtime)
+{
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ unsigned long flags;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+
+ if (atomic_read(&vctrl->suspend) > 0) {
+ *vtime = -1;
+ return;
+ }
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (vctrl->wait_vsync_cnt == 0)
+ INIT_COMPLETION(vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt++;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ wait_for_completion(&vctrl->vsync_comp);
+ mdp4_stat.wait4vsync0++;
+
+ *vtime = ktime_to_ns(vctrl->vsync_time);
+}
+
+static void mdp4_mddi_wait4dmap(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ wait_for_completion(&vctrl->dmap_comp);
+}
+
+static void mdp4_mddi_wait4ov(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ wait_for_completion(&vctrl->ov_comp);
+}
+
+/*
+ * primary_rdptr_isr:
+ * called from interrupt context
+ */
+static void primary_rdptr_isr(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pr_debug("%s: ISR, cpu=%d\n", __func__, smp_processor_id());
+ vctrl->rdptr_intr_tot++;
+ vctrl->vsync_time = ktime_get();
+
+ spin_lock(&vctrl->spin_lock);
+
+ if (vctrl->uevent)
+ schedule_work(&vctrl->vsync_work);
+
+ if (vctrl->wait_vsync_cnt) {
+ complete(&vctrl->vsync_comp);
+ vctrl->wait_vsync_cnt = 0;
+ }
+
+ if (vctrl->expire_tick) {
+ vctrl->expire_tick--;
+ if (vctrl->expire_tick == 0)
+ schedule_work(&vctrl->clk_work);
+ }
+ spin_unlock(&vctrl->spin_lock);
+}
+
+void mdp4_dmap_done_mddi(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ int diff;
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+
+ /* blt enabled */
+ spin_lock(&vctrl->spin_lock);
+ vsync_irq_disable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+ vctrl->dmap_done++;
+ diff = vctrl->ov_done - vctrl->dmap_done;
+ pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n",
+ __func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff,
+ vctrl->dmap_done, smp_processor_id());
+ complete_all(&vctrl->dmap_comp);
+ if (diff <= 0) {
+ if (vctrl->blt_wait)
+ vctrl->blt_wait = 0;
+ spin_unlock(&vctrl->spin_lock);
+ return;
+ }
+
+ /* kick dmap */
+ mdp4_mddi_blt_dmap_update(pipe);
+ pipe->dmap_cnt++;
+ mdp4_stat.kickoff_dmap++;
+ vctrl->dmap_koff++;
+ vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+ outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */
+ mb(); /* make sure kickoff executed */
+ spin_unlock(&vctrl->spin_lock);
+}
+
+/*
+ * mdp4_overlay0_done_mddi: called from isr
+ */
+void mdp4_overlay0_done_mddi(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ int diff;
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+
+ spin_lock(&vctrl->spin_lock);
+ vsync_irq_disable(INTR_OVERLAY0_DONE, MDP_OVERLAY0_TERM);
+ vctrl->ov_done++;
+ complete_all(&vctrl->ov_comp);
+ diff = vctrl->ov_done - vctrl->dmap_done;
+
+ pr_debug("%s: ov_koff=%d ov_done=%d dmap_koff=%d dmap_done=%d cpu=%d\n",
+ __func__, vctrl->ov_koff, vctrl->ov_done, vctrl->dmap_koff,
+ vctrl->dmap_done, smp_processor_id());
+
+ if (pipe->ov_blt_addr == 0) {
+ /* blt disabled */
+ spin_unlock(&vctrl->spin_lock);
+ return;
+ }
+
+ if (diff > 1) {
+ /*
+ * two overlay_done and none dmap_done yet
+ * let dmap_done kickoff dmap
+ * and put pipe_commit to wait
+ */
+ vctrl->blt_wait = 1;
+ pr_debug("%s: blt_wait set\n", __func__);
+ spin_unlock(&vctrl->spin_lock);
+ return;
+ }
+ mdp4_mddi_blt_dmap_update(pipe);
+ pipe->dmap_cnt++;
+ mdp4_stat.kickoff_dmap++;
+ vctrl->dmap_koff++;
+ vsync_irq_enable(INTR_DMA_P_DONE, MDP_DMAP_TERM);
+ outpdw(MDP_BASE + 0x000c, 0); /* kickoff dmap engine */
+ mb(); /* make sure kickoff executed */
+ spin_unlock(&vctrl->spin_lock);
+}
+
+static void clk_ctrl_work(struct work_struct *work)
+{
+ struct vsycn_ctrl *vctrl =
+ container_of(work, typeof(*vctrl), clk_work);
+ unsigned long flags;
+
+ mutex_lock(&vctrl->update_lock);
+ if (vctrl->clk_control && vctrl->clk_enabled) {
+ pr_debug("%s: SET_CLK_OFF\n", __func__);
+ mdp_clk_ctrl(0);
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
+ vctrl->clk_enabled = 0;
+ vctrl->clk_control = 0;
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+ }
+ mutex_unlock(&vctrl->update_lock);
+}
+
+static void send_vsync_work(struct work_struct *work)
+{
+ struct vsycn_ctrl *vctrl =
+ container_of(work, typeof(*vctrl), vsync_work);
+ char buf[64];
+ char *envp[2];
+
+ snprintf(buf, sizeof(buf), "VSYNC=%llu",
+ ktime_to_ns(vctrl->vsync_time));
+ envp[0] = buf;
+ envp[1] = NULL;
+ kobject_uevent_env(&vctrl->dev->kobj, KOBJ_CHANGE, envp);
+}
+
+
+void mdp4_mddi_rdptr_init(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+ if (vctrl->inited)
+ return;
+
+ vctrl->inited = 1;
+ vctrl->update_ndx = 0;
+ mutex_init(&vctrl->update_lock);
+ init_completion(&vctrl->ov_comp);
+ init_completion(&vctrl->dmap_comp);
+ init_completion(&vctrl->vsync_comp);
+ spin_lock_init(&vctrl->spin_lock);
+ INIT_WORK(&vctrl->vsync_work, send_vsync_work);
+ INIT_WORK(&vctrl->clk_work, clk_ctrl_work);
+}
+
+void mdp4_primary_rdptr(void)
+{
+ primary_rdptr_isr(0);
+}
+
+void mdp4_overlay_mddi_state_set(int state)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mddi_state = state;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+}
+
+int mdp4_overlay_mddi_state_get(void)
+{
+ return mddi_state;
+}
+
+static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp)
+{
+ /*
+ * The adreno GPU hardware requires that the pitch be aligned to
+ * 32 pixels for color buffers, so for the cases where the GPU
+ * is writing directly to fb0, the framebuffer pitch
+ * also needs to be 32 pixel aligned
+ */
+
+ if (fb_index == 0)
+ return ALIGN(xres, 32) * bpp;
+ else
+ return xres * bpp;
}
void mdp4_mddi_vsync_enable(struct msm_fb_data_type *mfd,
@@ -61,13 +703,6 @@
if ((mfd->use_mdp_vsync) && (mfd->ibuf.vsync_enable) &&
(mfd->panel_info.lcd.vsync_enable)) {
- if (mdp_hw_revision < MDP4_REVISION_V2_1) {
- /* need dmas dmap switch */
- if (which == 0 && dmap_vsync_enable == 0 &&
- mfd->panel_info.lcd.rev < 2) /* dma_p */
- return;
- }
-
if (vsync_start_y_adjust <= pipe->dst_y)
start_y = pipe->dst_y - vsync_start_y_adjust;
else
@@ -88,633 +723,337 @@
}
}
-#define WHOLESCREEN
+void mdp4_mddi_base_swap(int cndx, struct mdp4_overlay_pipe *pipe)
+{
+ struct vsycn_ctrl *vctrl;
-void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd)
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+ vctrl->base_pipe = pipe;
+}
+
+static void mdp4_overlay_setup_pipe_addr(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
{
MDPIBUF *iBuf = &mfd->ibuf;
+ struct fb_info *fbi;
+ int bpp;
uint8 *src;
+
+ /* whole screen for base layer */
+ src = (uint8 *) iBuf->buf;
+ fbi = mfd->fbi;
+
+ if (pipe->is_3d) {
+ bpp = fbi->var.bits_per_pixel / 8;
+ pipe->src_height = pipe->src_height_3d;
+ pipe->src_width = pipe->src_width_3d;
+ pipe->src_h = pipe->src_height_3d;
+ pipe->src_w = pipe->src_width_3d;
+ pipe->dst_h = pipe->src_height_3d;
+ pipe->dst_w = pipe->src_width_3d;
+ pipe->srcp0_ystride = msm_fb_line_length(0,
+ pipe->src_width, bpp);
+ } else {
+ /* 2D */
+ pipe->src_height = fbi->var.yres;
+ pipe->src_width = fbi->var.xres;
+ pipe->src_h = fbi->var.yres;
+ pipe->src_w = fbi->var.xres;
+ pipe->dst_h = fbi->var.yres;
+ pipe->dst_w = fbi->var.xres;
+ pipe->srcp0_ystride = fbi->fix.line_length;
+ }
+ pipe->src_y = 0;
+ pipe->src_x = 0;
+ pipe->dst_y = 0;
+ pipe->dst_x = 0;
+ pipe->srcp0_addr = (uint32)src;
+}
+
+void mdp4_overlay_update_mddi(struct msm_fb_data_type *mfd)
+{
int ptype;
uint32 mddi_ld_param;
uint16 mddi_vdo_packet_reg;
struct mdp4_overlay_pipe *pipe;
+ uint32 data;
int ret;
+ int cndx = 0;
+ struct vsycn_ctrl *vctrl;
if (mfd->key != MFD_KEY)
return;
- mddi_mfd = mfd; /* keep it */
+ vctrl = &vsync_ctrl_db[cndx];
- /* MDP cmd block enable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-
- if (mddi_pipe == NULL) {
+ if (vctrl->base_pipe == NULL) {
ptype = mdp4_overlay_format2type(mfd->fb_imgType);
+
if (ptype < 0)
- printk(KERN_INFO "%s: format2type failed\n", __func__);
+ pr_err("%s: format2type failed\n", __func__);
+
pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0);
- if (pipe == NULL)
- printk(KERN_INFO "%s: pipe_alloc failed\n", __func__);
+ if (pipe == NULL) {
+ pr_err("%s: pipe_alloc failed\n", __func__);
+ return;
+ }
pipe->pipe_used++;
+ pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
pipe->mixer_num = MDP4_MIXER0;
pipe->src_format = mfd->fb_imgType;
mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_MDDI);
ret = mdp4_overlay_format2pipe(pipe);
if (ret < 0)
- printk(KERN_INFO "%s: format2type failed\n", __func__);
+ pr_err("%s: format2type failed\n", __func__);
- mddi_pipe = pipe; /* keep it */
- mddi_ld_param = 0;
- mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
-
- if (mdp_hw_revision == MDP4_REVISION_V2_1) {
- uint32 data;
-
- data = inpdw(MDP_BASE + 0x0028);
- data &= ~0x0300; /* bit 8, 9, MASTER4 */
- if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */
- data |= 0x0200;
- else
- data |= 0x0100;
-
- MDP_OUTP(MDP_BASE + 0x00028, data);
- }
-
- if (mfd->panel_info.type == MDDI_PANEL) {
- if (mfd->panel_info.pdest == DISPLAY_1)
- mddi_ld_param = 0;
- else
- mddi_ld_param = 1;
- } else {
- mddi_ld_param = 2;
- }
-
- MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
-
- if (mfd->panel_info.bpp == 24)
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg);
- else if (mfd->panel_info.bpp == 16)
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg);
- else
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
-
- MDP_OUTP(MDP_BASE + 0x00098, 0x01);
+ vctrl->base_pipe = pipe; /* keep it */
mdp4_init_writeback_buf(mfd, MDP4_MIXER0);
pipe->ov_blt_addr = 0;
pipe->dma_blt_addr = 0;
} else {
- pipe = mddi_pipe;
+ pipe = vctrl->base_pipe;
}
- /* 0 for dma_p, client_id = 0 */
- MDP_OUTP(MDP_BASE + 0x00090, 0);
+ MDP_OUTP(MDP_BASE + 0x021c, 10); /* read pointer */
+ mddi_ld_param = 0;
+ mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
- src = (uint8 *) iBuf->buf;
+ if (mdp_hw_revision == MDP4_REVISION_V2_1) {
+ data = inpdw(MDP_BASE + 0x0028);
+ data &= ~0x0300; /* bit 8, 9, MASTER4 */
+ if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */
+ data |= 0x0200;
+ else
+ data |= 0x0100;
-#ifdef WHOLESCREEN
-
- {
- struct fb_info *fbi;
-
- fbi = mfd->fbi;
- pipe->src_height = fbi->var.yres;
- pipe->src_width = fbi->var.xres;
- pipe->src_h = fbi->var.yres;
- pipe->src_w = fbi->var.xres;
- pipe->src_y = 0;
- pipe->src_x = 0;
- pipe->dst_h = fbi->var.yres;
- pipe->dst_w = fbi->var.xres;
- pipe->dst_y = 0;
- pipe->dst_x = 0;
- pipe->srcp0_addr = (uint32)src;
- pipe->srcp0_ystride = fbi->fix.line_length;
+ MDP_OUTP(MDP_BASE + 0x00028, data);
}
-#else
- if (mdp4_overlay_active(MDP4_MIXER0)) {
- struct fb_info *fbi;
-
- fbi = mfd->fbi;
- pipe->src_height = fbi->var.yres;
- pipe->src_width = fbi->var.xres;
- pipe->src_h = fbi->var.yres;
- pipe->src_w = fbi->var.xres;
- pipe->src_y = 0;
- pipe->src_x = 0;
- pipe->dst_h = fbi->var.yres;
- pipe->dst_w = fbi->var.xres;
- pipe->dst_y = 0;
- pipe->dst_x = 0;
- pipe->srcp0_addr = (uint32) src;
- pipe->srcp0_ystride = fbi->fix.line_length;
+ if (mfd->panel_info.type == MDDI_PANEL) {
+ if (mfd->panel_info.pdest == DISPLAY_1)
+ mddi_ld_param = 0;
+ else
+ mddi_ld_param = 1;
} else {
- /* starting input address */
- src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width)
- * iBuf->bpp;
-
- pipe->src_height = iBuf->dma_h;
- pipe->src_width = iBuf->dma_w;
- pipe->src_h = iBuf->dma_h;
- pipe->src_w = iBuf->dma_w;
- pipe->src_y = 0;
- pipe->src_x = 0;
- pipe->dst_h = iBuf->dma_h;
- pipe->dst_w = iBuf->dma_w;
- pipe->dst_y = iBuf->dma_y;
- pipe->dst_x = iBuf->dma_x;
- pipe->srcp0_addr = (uint32) src;
- pipe->srcp0_ystride = iBuf->ibuf_width * iBuf->bpp;
+ mddi_ld_param = 2;
}
-#endif
- pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
+ MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
+
+ if (mfd->panel_info.bpp == 24)
+ MDP_OUTP(MDP_BASE + 0x00094,
+ (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg);
+ else if (mfd->panel_info.bpp == 16)
+ MDP_OUTP(MDP_BASE + 0x00094,
+ (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg);
+ else
+ MDP_OUTP(MDP_BASE + 0x00094,
+ (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
+
+ MDP_OUTP(MDP_BASE + 0x00098, 0x01);
+
+
+ mdp4_overlay_setup_pipe_addr(mfd, pipe);
mdp4_overlay_rgb_setup(pipe);
- mdp4_mixer_stage_up(pipe, 1);
+ mdp4_overlay_reg_flush(pipe, 1);
+
+ mdp4_mixer_stage_up(pipe, 0);
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmap_xy(pipe);
mdp4_overlay_dmap_cfg(mfd, 0);
+
mdp4_mixer_stage_commit(pipe->mixer_num);
- mdp4_mddi_vsync_enable(mfd, pipe, 0);
- /* MDP cmd block disable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ wmb();
}
-int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd)
+void mdp4_mddi_blt_start(struct msm_fb_data_type *mfd)
{
- unsigned long flag;
-
- pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n",
- __func__, mddi_pipe->blt_end,
- (int)mddi_pipe->ov_blt_addr, current->pid);
-
- mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
-
- if (mfd->ov0_wb_buf->write_addr == 0) {
- pr_info("%s: no blt_base assigned\n", __func__);
- return -EBUSY;
- }
-
- if (mddi_pipe->ov_blt_addr == 0) {
- mdp4_mddi_dma_busy_wait(mfd);
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mddi_pipe->blt_end = 0;
- mddi_pipe->blt_cnt = 0;
- mddi_pipe->ov_cnt = 0;
- mddi_pipe->dmap_cnt = 0;
- mddi_pipe->ov_blt_addr = mfd->ov0_wb_buf->write_addr;
- mddi_pipe->dma_blt_addr = mfd->ov0_wb_buf->write_addr;
- mdp4_stat.blt_mddi++;
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- return 0;
+ mdp4_mddi_do_blt(mfd, 1);
}
- return -EBUSY;
-}
-
-int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+void mdp4_mddi_blt_stop(struct msm_fb_data_type *mfd)
{
- unsigned long flag;
-
- pr_debug("%s: blt_end=%d blt_addr=%x\n",
- __func__, mddi_pipe->blt_end, (int)mddi_pipe->ov_blt_addr);
-
- if ((mddi_pipe->blt_end == 0) && mddi_pipe->ov_blt_addr) {
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mddi_pipe->blt_end = 1; /* mark as end */
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- return 0;
- }
-
- return -EBUSY;
-}
-
-int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
- struct msmfb_overlay_blt *req)
-{
- req->offset = 0;
- req->width = mddi_pipe->src_width;
- req->height = mddi_pipe->src_height;
- req->bpp = mddi_pipe->bpp;
-
- return sizeof(*req);
+ mdp4_mddi_do_blt(mfd, 0);
}
void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req)
{
- if (req->enable)
- mdp4_mddi_overlay_blt_start(mfd);
- else if (req->enable == 0)
- mdp4_mddi_overlay_blt_stop(mfd);
-
+ mdp4_mddi_do_blt(mfd, req->enable);
}
-void mdp4_blt_xy_update(struct mdp4_overlay_pipe *pipe)
+int mdp4_mddi_on(struct platform_device *pdev)
{
- uint32 off, addr, addr2;
- int bpp;
- char *overlay_base;
+ int ret = 0;
+ int cndx = 0;
+ struct msm_fb_data_type *mfd;
+ struct vsycn_ctrl *vctrl;
- if (pipe->ov_blt_addr == 0)
- return;
+ pr_debug("%s+:\n", __func__);
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
-#ifdef BLT_RGB565
- bpp = 2; /* overlay ouput is RGB565 */
-#else
- bpp = 3; /* overlay ouput is RGB888 */
-#endif
- off = 0;
- if (pipe->dmap_cnt & 0x01)
- off = pipe->src_height * pipe->src_width * bpp;
+ vctrl = &vsync_ctrl_db[cndx];
+ vctrl->mfd = mfd;
+ vctrl->dev = mfd->fbi->dev;
- addr = pipe->ov_blt_addr + off;
+ mdp_clk_ctrl(1);
+ mdp4_overlay_update_mddi(mfd);
+ mdp_clk_ctrl(0);
- /* dmap */
- MDP_OUTP(MDP_BASE + 0x90008, addr);
+ mdp4_iommu_attach();
- off = 0;
- if (pipe->ov_cnt & 0x01)
- off = pipe->src_height * pipe->src_width * bpp;
- addr2 = pipe->ov_blt_addr + off;
- /* overlay 0 */
- overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
- outpdw(overlay_base + 0x000c, addr2);
- outpdw(overlay_base + 0x001c, addr2);
+ atomic_set(&vctrl->suspend, 0);
+ pr_debug("%s-:\n", __func__);
+
+ return ret;
}
-void mdp4_primary_rdptr(void)
+int mdp4_mddi_off(struct platform_device *pdev)
{
-}
+ int ret = 0;
+ int cndx = 0;
+ struct msm_fb_data_type *mfd;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
-/*
- * mdp4_dmap_done_mddi: called from isr
- */
-void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma)
-{
- int diff;
+ pr_debug("%s+:\n", __func__);
- mddi_pipe->dmap_cnt++;
- diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
- pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
- __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- if (diff <= 0) {
- spin_lock(&mdp_spin_lock);
- dma->dmap_busy = FALSE;
- complete(&dma->dmap_comp);
- spin_unlock(&mdp_spin_lock);
-
- if (mddi_pipe->blt_end) {
- mddi_pipe->blt_end = 0;
- mddi_pipe->ov_blt_addr = 0;
- mddi_pipe->dma_blt_addr = 0;
- pr_debug("%s: END, ov_cnt=%d dmap_cnt=%d\n", __func__,
- mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
- mdp_intr_mask &= ~INTR_DMA_P_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- }
-
- mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
- mdp_disable_irq_nosync(MDP_DMA2_TERM); /* disable intr */
- return;
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+ if (pipe == NULL) {
+ pr_err("%s: NO base pipe\n", __func__);
+ return ret;
}
- spin_lock(&mdp_spin_lock);
- dma->busy = FALSE;
- spin_unlock(&mdp_spin_lock);
- complete(&dma->comp);
- if (busy_wait_cnt)
- busy_wait_cnt--;
+ atomic_set(&vctrl->suspend, 1);
- pr_debug("%s: kickoff dmap\n", __func__);
+ /* sanity check, free pipes besides base layer */
+ mdp4_overlay_unset_mixer(pipe->mixer_num);
+ mdp4_mixer_stage_down(pipe, 1);
+ mdp4_overlay_pipe_free(pipe);
+ vctrl->base_pipe = NULL;
- mdp4_blt_xy_update(mddi_pipe);
- /* kick off dmap */
- outpdw(MDP_BASE + 0x000c, 0x0);
- mdp4_stat.kickoff_dmap++;
- mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
-}
-
-/*
- * mdp4_overlay0_done_mddi: called from isr
- */
-void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma)
-{
- int diff;
-
- if (mddi_pipe->ov_blt_addr == 0) {
- mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
- spin_lock(&mdp_spin_lock);
- dma->busy = FALSE;
- spin_unlock(&mdp_spin_lock);
- complete(&dma->comp);
-
- if (busy_wait_cnt)
- busy_wait_cnt--;
- mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
-
- return;
+ if (vctrl->clk_enabled) {
+ /*
+ * in case of suspend, vsycn_ctrl off is not
+ * received from frame work which left clock on
+ * then, clock need to be turned off here
+ */
+ mdp_clk_ctrl(0);
}
- /* blt enabled */
- if (mddi_pipe->blt_end == 0)
- mddi_pipe->ov_cnt++;
+ vctrl->clk_enabled = 0;
+ vctrl->vsync_enabled = 0;
+ vctrl->clk_control = 0;
+ vctrl->expire_tick = 0;
+ vctrl->uevent = 0;
- pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
- __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+ vsync_irq_disable(INTR_PRIMARY_RDPTR, MDP_PRIM_RDPTR_TERM);
- if (mddi_pipe->blt_cnt == 0) {
- /* first kickoff since blt enabled */
- mdp_intr_mask |= INTR_DMA_P_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- }
+ pr_debug("%s-:\n", __func__);
- mddi_pipe->blt_cnt++;
-
- diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
- if (diff >= 2) {
- mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
- return;
- }
-
- spin_lock(&mdp_spin_lock);
- dma->busy = FALSE;
- dma->dmap_busy = TRUE;
- spin_unlock(&mdp_spin_lock);
- complete(&dma->comp);
-
- if (busy_wait_cnt)
- busy_wait_cnt--;
-
- pr_debug("%s: kickoff dmap\n", __func__);
-
- mdp4_blt_xy_update(mddi_pipe);
- mdp_enable_irq(MDP_DMA2_TERM); /* enable intr */
- /* kick off dmap */
- outpdw(MDP_BASE + 0x000c, 0x0);
- mdp4_stat.kickoff_dmap++;
- mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
-}
-
-void mdp4_mddi_overlay_restore(void)
-{
- if (mddi_mfd == NULL)
- return;
-
- pr_debug("%s: resotre, pid=%d\n", __func__, current->pid);
-
- if (mddi_mfd->panel_power_on == 0)
- return;
- if (mddi_mfd && mddi_pipe) {
- mdp4_mddi_dma_busy_wait(mddi_mfd);
- mdp4_overlay_update_lcd(mddi_mfd);
-
- if (mddi_pipe->ov_blt_addr)
- mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
- mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe);
- mddi_mfd->dma_update_flag = 1;
- }
- if (mdp_hw_revision < MDP4_REVISION_V2_1) /* need dmas dmap switch */
- mdp4_mddi_overlay_dmas_restore();
-}
-
-void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd)
-{
- unsigned long flag;
- int need_wait = 0;
-
- spin_lock_irqsave(&mdp_spin_lock, flag);
- if (mfd->dma->dmap_busy == TRUE) {
- INIT_COMPLETION(mfd->dma->dmap_comp);
- need_wait++;
- }
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-
- if (need_wait) {
- /* wait until DMA finishes the current job */
- wait_for_completion(&mfd->dma->dmap_comp);
- }
-}
-
-/*
- * mdp4_mddi_cmd_dma_busy_wait: check mddi link activity
- * mddi link is a shared resource and it can only be used
- * while it is in idle state.
- * ov_mutex need to be acquired before call this function.
- */
-void mdp4_mddi_dma_busy_wait(struct msm_fb_data_type *mfd)
-{
- unsigned long flag;
- int need_wait = 0;
-
- pr_debug("%s: START, pid=%d\n", __func__, current->pid);
- spin_lock_irqsave(&mdp_spin_lock, flag);
- if (mfd->dma->busy == TRUE) {
- if (busy_wait_cnt == 0)
- INIT_COMPLETION(mfd->dma->comp);
- busy_wait_cnt++;
- need_wait++;
- }
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-
-
- if (need_wait) {
- /* wait until DMA finishes the current job */
- pr_debug("%s: PENDING, pid=%d\n", __func__, current->pid);
- wait_for_completion(&mfd->dma->comp);
- }
- pr_debug("%s: DONE, pid=%d\n", __func__, current->pid);
-}
-
-void mdp4_mddi_kickoff_video(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
/*
- * a video kickoff may happen before UI kickoff after
- * blt enabled. mdp4_overlay_update_lcd() need
- * to be called before kickoff.
- * vice versa for blt disabled.
+ * footswitch off
+ * this will casue all mdp register
+ * to be reset to default
+ * after footswitch on later
*/
- if (mddi_pipe->ov_blt_addr && mddi_pipe->blt_cnt == 0)
- mdp4_overlay_update_lcd(mfd); /* first time */
- else if (mddi_pipe->ov_blt_addr == 0 && mddi_pipe->blt_cnt) {
- mdp4_overlay_update_lcd(mfd); /* last time */
- mddi_pipe->blt_cnt = 0;
- }
- pr_debug("%s: blt_addr=%d blt_cnt=%d\n",
- __func__, (int)mddi_pipe->ov_blt_addr, mddi_pipe->blt_cnt);
-
- if (mddi_pipe->ov_blt_addr)
- mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
- mdp4_mddi_overlay_kickoff(mfd, pipe);
+ return ret;
}
-void mdp4_mddi_kickoff_ui(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
+void mdp_mddi_overlay_suspend(struct msm_fb_data_type *mfd)
{
- pr_debug("%s: pid=%d\n", __func__, current->pid);
- mdp4_mddi_overlay_kickoff(mfd, pipe);
-}
+ int cndx = 0;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+ /* dis-engage rgb0 from mixer0 */
+ if (pipe) {
+ if (mfd->ref_cnt == 0) {
+ /* adb stop */
+ if (pipe->pipe_type == OVERLAY_TYPE_BF)
+ mdp4_overlay_borderfill_stage_down(pipe);
-void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- unsigned long flag;
-
- mdp_enable_irq(MDP_OVERLAY0_TERM);
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mfd->dma->busy = TRUE;
- if (mddi_pipe->ov_blt_addr)
- mfd->dma->dmap_busy = TRUE;
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- /* start OVERLAY pipe */
- mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
- mdp4_stat.kickoff_ov0++;
-}
-
-void mdp4_dma_s_update_lcd(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- MDPIBUF *iBuf = &mfd->ibuf;
- uint32 outBpp = iBuf->bpp;
- uint16 mddi_vdo_packet_reg;
- uint32 dma_s_cfg_reg;
-
- dma_s_cfg_reg = 0;
-
- if (mfd->fb_imgType == MDP_RGBA_8888)
- dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR; /* on purpose */
- else if (mfd->fb_imgType == MDP_BGR_565)
- dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR;
- else
- dma_s_cfg_reg |= DMA_PACK_PATTERN_RGB;
-
- if (outBpp == 4)
- dma_s_cfg_reg |= (1 << 26); /* xRGB8888 */
- else if (outBpp == 2)
- dma_s_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
-
- dma_s_cfg_reg |= DMA_DITHER_EN;
-
- /* MDP cmd block enable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- /* PIXELSIZE */
- MDP_OUTP(MDP_BASE + 0xa0004, (pipe->dst_h << 16 | pipe->dst_w));
- MDP_OUTP(MDP_BASE + 0xa0008, pipe->srcp0_addr); /* ibuf address */
- MDP_OUTP(MDP_BASE + 0xa000c, pipe->srcp0_ystride);/* ystride */
-
- if (mfd->panel_info.bpp == 24) {
- dma_s_cfg_reg |= DMA_DSTC0G_8BITS | /* 666 18BPP */
- DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS;
- } else if (mfd->panel_info.bpp == 18) {
- dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */
- DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
- } else {
- dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */
- DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
- }
-
- MDP_OUTP(MDP_BASE + 0xa0010, (pipe->dst_y << 16) | pipe->dst_x);
-
- /* 1 for dma_s, client_id = 0 */
- MDP_OUTP(MDP_BASE + 0x00090, 1);
-
- mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
-
- if (mfd->panel_info.bpp == 24)
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg);
- else if (mfd->panel_info.bpp == 16)
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg);
- else
- MDP_OUTP(MDP_BASE + 0x00094,
- (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
-
- MDP_OUTP(MDP_BASE + 0x00098, 0x01);
-
- MDP_OUTP(MDP_BASE + 0xa0000, dma_s_cfg_reg);
-
- mdp4_mddi_vsync_enable(mfd, pipe, 1);
-
- /* MDP cmd block disable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-}
-
-void mdp4_mddi_dma_s_kickoff(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- mdp_enable_irq(MDP_DMA_S_TERM);
-
- if (mddi_pipe->ov_blt_addr == 0)
- mfd->dma->busy = TRUE;
-
- mfd->ibuf_flushed = TRUE;
- /* start dma_s pipe */
- mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd);
- mdp4_stat.kickoff_dmas++;
-
- /* wait until DMA finishes the current job */
- wait_for_completion(&mfd->dma->comp);
- mdp_disable_irq(MDP_DMA_S_TERM);
-}
-
-void mdp4_mddi_overlay_dmas_restore(void)
-{
- /* mutex held by caller */
- if (mddi_mfd && mddi_pipe) {
- mdp4_mddi_dma_busy_wait(mddi_mfd);
- mdp4_dma_s_update_lcd(mddi_mfd, mddi_pipe);
- mdp4_mddi_dma_s_kickoff(mddi_mfd, mddi_pipe);
- mddi_mfd->dma_update_flag = 1;
+ /* pipe == rgb1 */
+ mdp4_overlay_unset_mixer(pipe->mixer_num);
+ vctrl->base_pipe = NULL;
+ } else {
+ mdp4_mixer_stage_down(pipe, 1);
+ mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 1);
+ }
}
}
void mdp4_mddi_overlay(struct msm_fb_data_type *mfd)
{
- mutex_lock(&mfd->dma->ov_mutex);
+ int cndx = 0;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ unsigned long flags;
+ long long xx;
- if (mfd && mfd->panel_power_on) {
- mdp4_mddi_dma_busy_wait(mfd);
+ vctrl = &vsync_ctrl_db[cndx];
- if (mddi_pipe && mddi_pipe->ov_blt_addr)
- mdp4_mddi_blt_dmap_busy_wait(mfd);
- mdp4_overlay_mdp_perf_upd(mfd, 0);
- mdp4_overlay_update_lcd(mfd);
+ if (!mfd->panel_power_on)
+ return;
- mdp4_overlay_mdp_perf_upd(mfd, 1);
- if (mdp_hw_revision < MDP4_REVISION_V2_1) {
- /* dmas dmap switch */
- if (mdp4_overlay_mixer_play(mddi_pipe->mixer_num)
- == 0) {
- mdp4_dma_s_update_lcd(mfd, mddi_pipe);
- mdp4_mddi_dma_s_kickoff(mfd, mddi_pipe);
- } else
- mdp4_mddi_kickoff_ui(mfd, mddi_pipe);
- } else /* no dams dmap switch */
- mdp4_mddi_kickoff_ui(mfd, mddi_pipe);
-
- /* signal if pan function is waiting for the update completion */
- if (mfd->pan_waiting) {
- mfd->pan_waiting = FALSE;
- complete(&mfd->pan_comp);
- }
+ pipe = vctrl->base_pipe;
+ if (pipe == NULL) {
+ pr_err("%s: NO base pipe\n", __func__);
+ return;
}
+
+ mutex_lock(&vctrl->update_lock);
+ if (!vctrl->clk_enabled) {
+ pr_err("%s: mdp clocks disabled\n", __func__);
+ mutex_unlock(&vctrl->update_lock);
+ return;
+
+ }
+ mutex_unlock(&vctrl->update_lock);
+
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ if (vctrl->expire_tick) {
+ /*
+ * in the middle of shutting clocks down
+ * delay to allow pan display to go through
+ */
+ vctrl->expire_tick = VSYNC_EXPIRE_TICK;
+ }
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE) {
+ mdp4_mddi_vsync_enable(mfd, pipe, 0);
+ mdp4_overlay_setup_pipe_addr(mfd, pipe);
+ mdp4_mddi_pipe_queue(0, pipe);
+ }
+
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
+
+ mutex_lock(&mfd->dma->ov_mutex);
+ mdp4_mddi_pipe_commit();
mutex_unlock(&mfd->dma->ov_mutex);
+ mdp4_mddi_wait4vsync(0, &xx);
+
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
}
int mdp4_mddi_overlay_cursor(struct fb_info *info, struct fb_cursor *cursor)
@@ -722,7 +1061,6 @@
struct msm_fb_data_type *mfd = info->par;
mutex_lock(&mfd->dma->ov_mutex);
if (mfd && mfd->panel_power_on) {
- mdp4_mddi_dma_busy_wait(mfd);
mdp_hw_cursor_update(info, cursor);
}
mutex_unlock(&mfd->dma->ov_mutex);
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index ee7e9ce..18c6635 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -45,9 +45,49 @@
WITH_CLIENT
};
-static struct mdp4_overlay_pipe *writeback_pipe;
-static struct msm_fb_data_type *writeback_mfd;
-static int busy_wait_cnt;
+#define MAX_CONTROLLER 1
+#define VSYNC_EXPIRE_TICK 0
+
+static struct vsycn_ctrl {
+ struct device *dev;
+ int inited;
+ int update_ndx;
+ u32 ov_koff;
+ u32 ov_done;
+ atomic_t suspend;
+ struct mutex update_lock;
+ struct completion ov_comp;
+ spinlock_t spin_lock;
+ struct msm_fb_data_type *mfd;
+ struct mdp4_overlay_pipe *base_pipe;
+ struct vsync_update vlist[2];
+} vsync_ctrl_db[MAX_CONTROLLER];
+
+static void vsync_irq_enable(int intr, int term)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ /* no need to clrear other interrupts for comamnd mode */
+ mdp_intr_mask |= intr;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_enable_irq(term);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+}
+
+static void vsync_irq_disable(int intr, int term)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ /* no need to clrear other interrupts for comamnd mode */
+ mdp_intr_mask &= ~intr;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_disable_irq_nosync(term);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+}
+
+static int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd);
int mdp4_overlay_writeback_on(struct platform_device *pdev)
{
@@ -58,6 +98,8 @@
int bpp;
int ret;
uint32 data;
+ struct vsycn_ctrl *vctrl;
+ int cndx = 0;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
@@ -67,7 +109,9 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- writeback_mfd = mfd; /* keep it */
+ vctrl = &vsync_ctrl_db[cndx];
+ vctrl->mfd = mfd;
+ vctrl->dev = mfd->fbi->dev;
fbi = mfd->fbi;
@@ -77,12 +121,14 @@
fbi->var.yoffset * fbi->fix.line_length;
/* MDP cmd block enable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_clk_ctrl(1);
- if (writeback_pipe == NULL) {
+ if (vctrl->base_pipe == NULL) {
pipe = mdp4_overlay_pipe_alloc(OVERLAY_TYPE_BF, MDP4_MIXER2);
- if (pipe == NULL)
+ if (pipe == NULL) {
pr_info("%s: pipe_alloc failed\n", __func__);
+ return -EIO;
+ }
pipe->pipe_used++;
pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
pipe->mixer_num = MDP4_MIXER2;
@@ -92,11 +138,12 @@
if (ret < 0)
pr_info("%s: format2type failed\n", __func__);
- writeback_pipe = pipe; /* keep it */
+ vctrl->base_pipe = pipe; /* keep it */
} else {
- pipe = writeback_pipe;
+ pipe = vctrl->base_pipe;
}
+
ret = panel_next_on(pdev);
/* MDP_LAYERMIXER_WB_MUX_SEL to use mixer1 axi for mixer2 writeback */
@@ -113,46 +160,68 @@
MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008,
(0x0 & 0xFFF)); /* 12-bit R */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_clk_ctrl(0);
return ret;
}
int mdp4_overlay_writeback_off(struct platform_device *pdev)
{
- int ret;
- struct msm_fb_data_type *mfd =
- (struct msm_fb_data_type *)platform_get_drvdata(pdev);
- if (mfd && writeback_pipe) {
- mdp4_writeback_dma_busy_wait(mfd);
- mdp4_overlay_pipe_free(writeback_pipe);
- mdp4_overlay_panel_mode_unset(writeback_pipe->mixer_num,
- MDP4_PANEL_WRITEBACK);
- writeback_pipe = NULL;
+ int cndx = 0;
+ struct msm_fb_data_type *mfd;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ int ret = 0;
+
+ pr_debug("%s+:\n", __func__);
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+ if (pipe == NULL) {
+ pr_err("%s: NO base pipe\n", __func__);
+ return ret;
}
+
+ /* sanity check, free pipes besides base layer */
+ mdp4_overlay_unset_mixer(pipe->mixer_num);
+ mdp4_mixer_stage_down(pipe, 1);
+ mdp4_overlay_pipe_free(pipe);
+ vctrl->base_pipe = NULL;
+
ret = panel_next_off(pdev);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ mdp_clk_ctrl(1);
/* MDP_LAYERMIXER_WB_MUX_SEL to restore to default cfg*/
outpdw(MDP_BASE + 0x100F4, 0x0);
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_clk_ctrl(0);
+ pr_debug("%s-:\n", __func__);
return ret;
}
-int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd)
+
+static int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd)
{
struct fb_info *fbi;
uint8 *buf;
unsigned int buf_offset;
struct mdp4_overlay_pipe *pipe;
int bpp;
+ int cndx = 0;
+ struct vsycn_ctrl *vctrl;
if (mfd->key != MFD_KEY)
return -ENODEV;
- if (!writeback_pipe)
- return -EINVAL;
fbi = mfd->fbi;
- pipe = writeback_pipe;
+ vctrl = &vsync_ctrl_db[cndx];
+
+ pipe = vctrl->base_pipe;
+ if (!pipe) {
+ pr_err("%s: no base layer pipe\n", __func__);
+ return -EINVAL;
+ }
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
@@ -160,7 +229,7 @@
fbi->var.yoffset * fbi->fix.line_length;
/* MDP cmd block enable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_clk_ctrl(1);
pipe->src_height = fbi->var.yres;
pipe->src_width = fbi->var.xres;
@@ -184,142 +253,190 @@
mdp4_mixer_stage_up(pipe, 0);
mdp4_overlayproc_cfg(pipe);
- mdp4_mixer_stage_commit(pipe->mixer_num);
/* MDP cmd block disable */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_clk_ctrl(0);
wmb();
return 0;
}
-void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd)
+
+/*
+ * mdp4_wfd_piep_queue:
+ * called from thread context
+ */
+void mdp4_wfd_pipe_queue(int cndx, struct mdp4_overlay_pipe *pipe)
{
- unsigned long flag;
- int need_wait = 0;
+ struct vsycn_ctrl *vctrl;
+ struct vsync_update *vp;
+ struct mdp4_overlay_pipe *pp;
+ int undx;
- spin_lock_irqsave(&mdp_spin_lock, flag);
- if (mfd->dma->busy == TRUE) {
- if (busy_wait_cnt == 0)
- INIT_COMPLETION(mfd->dma->comp);
- busy_wait_cnt = 1;
- need_wait++;
- }
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
-
- if (need_wait) {
- /* wait until DMA finishes the current job */
- pr_debug("%s: pending pid=%d\n",
- __func__, current->pid);
- wait_for_completion(&mfd->dma->comp);
- }
-}
-
-void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma)
-{
- spin_lock(&mdp_spin_lock);
- dma->busy = FALSE;
- if (busy_wait_cnt)
- busy_wait_cnt = 0;
- mdp_disable_irq_nosync(MDP_OVERLAY2_TERM);
- spin_unlock(&mdp_spin_lock);
- complete_all(&dma->comp);
- pr_debug("%s ovdone interrupt\n", __func__);
-
-}
-void mdp4_writeback_overlay_kickoff(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- unsigned long flag;
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mdp_enable_irq(MDP_OVERLAY2_TERM);
-
- mfd->dma->busy = TRUE;
- outp32(MDP_INTR_CLEAR, INTR_OVERLAY2_DONE);
- mdp_intr_mask |= INTR_OVERLAY2_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
-
- wmb(); /* make sure all registers updated */
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- /* start OVERLAY pipe */
- mdp_pipe_kickoff(MDP_OVERLAY2_TERM, mfd);
- wmb();
- pr_debug("%s: before ov done interrupt\n", __func__);
-}
-void mdp4_writeback_dma_stop(struct msm_fb_data_type *mfd)
-{
- /* mutex holded by caller */
- if (mfd && writeback_pipe) {
- mdp4_writeback_dma_busy_wait(mfd);
- mdp4_overlay_writeback_update(mfd);
-
- mdp4_writeback_overlay_kickoff(mfd, writeback_pipe);
- }
-}
-
-void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- struct msmfb_writeback_data_list *node = NULL;
- mutex_lock(&mfd->unregister_mutex);
- mutex_lock(&mfd->writeback_mutex);
- if (!list_empty(&mfd->writeback_free_queue)
- && mfd->writeback_state != WB_STOPING
- && mfd->writeback_state != WB_STOP) {
- node = list_first_entry(&mfd->writeback_free_queue,
- struct msmfb_writeback_data_list, active_entry);
- }
- if (node) {
- list_del(&(node->active_entry));
- node->state = IN_BUSY_QUEUE;
- mfd->writeback_active_cnt++;
- }
- mutex_unlock(&mfd->writeback_mutex);
-
- writeback_pipe->ov_blt_addr = (ulong) (node ? node->addr : NULL);
-
- /* free previous iommu at freelist back to pool */
- mdp4_overlay_iommu_unmap_freelist(writeback_pipe->mixer_num);
-
- if (!writeback_pipe->ov_blt_addr) {
- pr_err("%s: no writeback buffer 0x%x, %p\n", __func__,
- (unsigned int)writeback_pipe->ov_blt_addr, node);
- mutex_unlock(&mfd->unregister_mutex);
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
return;
}
- if (writeback_pipe->blt_cnt == 0)
- mdp4_overlay_writeback_update(mfd);
+ vctrl = &vsync_ctrl_db[cndx];
- pr_debug("%s: pid=%d\n", __func__, current->pid);
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
- mdp4_mixer_stage_commit(pipe->mixer_num);
+ mutex_lock(&vctrl->update_lock);
+ undx = vctrl->update_ndx;
+ vp = &vctrl->vlist[undx];
- mdp4_writeback_overlay_kickoff(mfd, pipe);
- mdp4_writeback_dma_busy_wait(mfd);
+ pp = &vp->plist[pipe->pipe_ndx - 1]; /* ndx start form 1 */
- /* move current committed iommu to freelist */
- mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
+ pr_debug("%s: vndx=%d pipe_ndx=%d pid=%d\n", __func__,
+ undx, pipe->pipe_ndx, current->pid);
- mutex_lock(&mfd->writeback_mutex);
- list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
- mutex_unlock(&mfd->writeback_mutex);
- mfd->writeback_active_cnt--;
- mutex_unlock(&mfd->unregister_mutex);
- wake_up(&mfd->wait_q);
+ *pp = *pipe; /* clone it */
+ vp->update_cnt++;
+
+ mutex_unlock(&vctrl->update_lock);
+ mdp4_stat.overlay_play[pipe->mixer_num]++;
}
-void mdp4_writeback_kickoff_ui(struct msm_fb_data_type *mfd,
- struct mdp4_overlay_pipe *pipe)
-{
- mdp4_mixer_stage_commit(pipe->mixer_num);
+static void mdp4_wfd_wait4ov(int cndx);
- pr_debug("%s: pid=%d\n", __func__, current->pid);
- mdp4_writeback_overlay_kickoff(mfd, pipe);
+int mdp4_wfd_pipe_commit(void)
+{
+ int i, undx;
+ int mixer = 0;
+ struct vsycn_ctrl *vctrl;
+ struct vsync_update *vp;
+ struct mdp4_overlay_pipe *pipe;
+ struct mdp4_overlay_pipe *real_pipe;
+ unsigned long flags;
+ int cnt = 0;
+
+ vctrl = &vsync_ctrl_db[0];
+
+ mutex_lock(&vctrl->update_lock);
+ undx = vctrl->update_ndx;
+ vp = &vctrl->vlist[undx];
+ pipe = vctrl->base_pipe;
+ mixer = pipe->mixer_num;
+
+ if (vp->update_cnt == 0) {
+ mutex_unlock(&vctrl->update_lock);
+ return cnt;
+ }
+
+ vctrl->update_ndx++;
+ vctrl->update_ndx &= 0x01;
+ vp->update_cnt = 0; /* reset */
+ mutex_unlock(&vctrl->update_lock);
+
+ /* free previous committed iommu back to pool */
+ mdp4_overlay_iommu_unmap_freelist(mixer);
+
+ pipe = vp->plist;
+ for (i = 0; i < OVERLAY_PIPE_MAX; i++, pipe++) {
+ if (pipe->pipe_used) {
+ cnt++;
+ real_pipe = mdp4_overlay_ndx2pipe(pipe->pipe_ndx);
+ if (real_pipe && real_pipe->pipe_used) {
+ /* pipe not unset */
+ mdp4_overlay_vsync_commit(pipe);
+ }
+ /* free previous iommu to freelist
+ * which will be freed at next
+ * pipe_commit
+ */
+ mdp4_overlay_iommu_pipe_free(pipe->pipe_ndx, 0);
+ pipe->pipe_used = 0; /* clear */
+ }
+ }
+
+ mdp4_mixer_stage_commit(mixer);
+
+ pipe = vctrl->base_pipe;
+ spin_lock_irqsave(&vctrl->spin_lock, flags);
+ vctrl->ov_koff++;
+ INIT_COMPLETION(vctrl->ov_comp);
+ vsync_irq_enable(INTR_OVERLAY2_DONE, MDP_OVERLAY2_TERM);
+ pr_debug("%s: kickoff\n", __func__);
+ /* kickoff overlay engine */
+ mdp4_stat.kickoff_ov2++;
+ outpdw(MDP_BASE + 0x00D0, 0);
+ mb(); /* make sure kickoff executed */
+ spin_unlock_irqrestore(&vctrl->spin_lock, flags);
+
+ mdp4_stat.overlay_commit[pipe->mixer_num]++;
+
+ return cnt;
+}
+
+void mdp4_wfd_init(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+ if (vctrl->inited)
+ return;
+
+ vctrl->inited = 1;
+ vctrl->update_ndx = 0;
+ mutex_init(&vctrl->update_lock);
+ init_completion(&vctrl->ov_comp);
+ spin_lock_init(&vctrl->spin_lock);
+}
+
+static void mdp4_wfd_wait4ov(int cndx)
+{
+ struct vsycn_ctrl *vctrl;
+
+ if (cndx >= MAX_CONTROLLER) {
+ pr_err("%s: out or range: cndx=%d\n", __func__, cndx);
+ return;
+ }
+
+ vctrl = &vsync_ctrl_db[cndx];
+
+ if (atomic_read(&vctrl->suspend) > 0)
+ return;
+
+ wait_for_completion(&vctrl->ov_comp);
+}
+
+
+void mdp4_overlay2_done_wfd(struct mdp_dma_data *dma)
+{
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+ int cndx = 0;
+
+ vctrl = &vsync_ctrl_db[cndx];
+ pipe = vctrl->base_pipe;
+
+ spin_lock(&vctrl->spin_lock);
+ vsync_irq_disable(INTR_OVERLAY2_DONE, MDP_OVERLAY2_TERM);
+ vctrl->ov_done++;
+ complete(&vctrl->ov_comp);
+
+ pr_debug("%s ovdone interrupt\n", __func__);
+ spin_unlock(&vctrl->spin_lock);
}
void mdp4_writeback_overlay(struct msm_fb_data_type *mfd)
{
- int ret = 0;
struct msmfb_writeback_data_list *node = NULL;
+ struct vsycn_ctrl *vctrl;
+ struct mdp4_overlay_pipe *pipe;
+
+ if (mfd && !mfd->panel_power_on)
+ return;
+
+ pr_debug("%s:+ mfd=%x\n", __func__, (int)mfd);
+
+ vctrl = &vsync_ctrl_db[0];
+ pipe = vctrl->base_pipe;
mutex_lock(&mfd->unregister_mutex);
mutex_lock(&mfd->writeback_mutex);
@@ -336,44 +453,36 @@
}
mutex_unlock(&mfd->writeback_mutex);
- writeback_pipe->ov_blt_addr = (ulong) (node ? node->addr : NULL);
+ pipe->ov_blt_addr = (ulong) (node ? node->addr : NULL);
+
+ if (!pipe->ov_blt_addr) {
+ pr_err("%s: no writeback buffer 0x%x, %p\n", __func__,
+ (unsigned int)pipe->ov_blt_addr, node);
+ mutex_unlock(&mfd->unregister_mutex);
+ return;
+ }
mutex_lock(&mfd->dma->ov_mutex);
- pr_debug("%s in writeback\n", __func__);
- if (writeback_pipe && !writeback_pipe->ov_blt_addr) {
+ if (pipe && !pipe->ov_blt_addr) {
pr_err("%s: no writeback buffer 0x%x\n", __func__,
- (unsigned int)writeback_pipe->ov_blt_addr);
- ret = mdp4_overlay_writeback_update(mfd);
- if (ret)
- pr_err("%s: update failed writeback pipe NULL\n",
- __func__);
+ (unsigned int)pipe->ov_blt_addr);
goto fail_no_blt_addr;
}
- if (mfd && mfd->panel_power_on) {
- pr_debug("%s in before busy wait\n", __func__);
- mdp4_writeback_dma_busy_wait(mfd);
+ if (pipe->pipe_type == OVERLAY_TYPE_RGB)
+ mdp4_wfd_pipe_queue(0, pipe);
- pr_debug("%s in before update\n", __func__);
- ret = mdp4_overlay_writeback_update(mfd);
- if (ret) {
- pr_err("%s: update failed writeback pipe NULL\n",
- __func__);
- goto fail_no_blt_addr;
- }
+ mdp4_overlay_mdp_perf_upd(mfd, 1);
- pr_debug("%s: in writeback pan display 0x%x\n", __func__,
- (unsigned int)writeback_pipe->ov_blt_addr);
- mdp4_writeback_kickoff_ui(mfd, writeback_pipe);
- mdp4_iommu_unmap(writeback_pipe);
+ mdp_clk_ctrl(1);
+ mdp4_overlay_writeback_update(mfd);
- /* signal if pan function is waiting for the
- * update completion */
- if (mfd->pan_waiting) {
- mfd->pan_waiting = FALSE;
- complete(&mfd->pan_comp);
- }
- }
+ mdp4_wfd_pipe_commit();
+
+ mdp4_overlay_mdp_perf_upd(mfd, 0);
+
+ mdp4_wfd_wait4ov(0);
+ mdp_clk_ctrl(0);
mutex_lock(&mfd->writeback_mutex);
list_add_tail(&node->active_entry, &mfd->writeback_busy_queue);
@@ -385,7 +494,9 @@
mdp4_overlay_resource_release();*/
mutex_unlock(&mfd->dma->ov_mutex);
mutex_unlock(&mfd->unregister_mutex);
+ pr_debug("%s:-\n", __func__);
}
+
static int mdp4_overlay_writeback_register_buffer(
struct msm_fb_data_type *mfd, struct msmfb_writeback_data_list *node)
{
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index b35acfb..516722e 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -110,21 +110,22 @@
.csc_data = {
(0),
{
- 0x0200, 0x0000, 0x0000,
- 0x0000, 0x0200, 0x0000,
- 0x0000, 0x0000, 0x0200,
+ 0x0083, 0x0102, 0x0032,
+ 0x1fb5, 0x1f6c, 0x00e1,
+ 0x00e1, 0x1f45, 0x1fdc,
},
{
0x0, 0x0, 0x0,
},
{
- 0, 0, 0,
+ 0x0010, 0x0080, 0x0080,
},
{
0, 0xff, 0, 0xff, 0, 0xff,
},
{
- 0, 0xff, 0, 0xff, 0, 0xff,
+ 0x0010, 0x00eb, 0x0010,
+ 0x00f0, 0x0010, 0x00f0,
},
},
},
@@ -133,21 +134,22 @@
.csc_data = {
(0),
{
- 0x0200, 0x0000, 0x0000,
- 0x0000, 0x0200, 0x0000,
- 0x0000, 0x0000, 0x0200,
+ 0x0083, 0x0102, 0x0032,
+ 0x1fb5, 0x1f6c, 0x00e1,
+ 0x00e1, 0x1f45, 0x1fdc,
},
{
0x0, 0x0, 0x0,
},
{
- 0, 0, 0,
+ 0x0010, 0x0080, 0x0080,
},
{
0, 0xff, 0, 0xff, 0, 0xff,
},
{
- 0, 0xff, 0, 0xff, 0, 0xff,
+ 0x0010, 0x00eb, 0x0010,
+ 0x00f0, 0x0010, 0x00f0,
},
},
},
@@ -176,7 +178,6 @@
},
};
-
unsigned is_mdp4_hw_reset(void)
{
unsigned hw_reset = 0;
@@ -556,7 +557,7 @@
mdp4_dmap_done_dsi_cmd(0);
#else
else { /* MDDI */
- mdp4_dma_p_done_mddi(dma);
+ mdp4_dmap_done_mddi(0);
mdp_pipe_ctrl(MDP_DMA2_BLOCK,
MDP_BLOCK_POWER_OFF, TRUE);
complete(&dma->comp);
@@ -607,7 +608,7 @@
mdp4_overlay0_done_dsi_cmd(0);
#else
if (panel & MDP4_PANEL_MDDI)
- mdp4_overlay0_done_mddi(dma);
+ mdp4_overlay0_done_mddi(0);
#endif
}
mdp_hw_cursor_done();
@@ -634,14 +635,8 @@
if (isr & INTR_OVERLAY2_DONE) {
mdp4_stat.intr_overlay2++;
/* disable DTV interrupt */
- dma = &dma_wb_data;
- spin_lock(&mdp_spin_lock);
- mdp_intr_mask &= ~INTR_OVERLAY2_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- dma->waiting = FALSE;
- spin_unlock(&mdp_spin_lock);
if (panel & MDP4_PANEL_WRITEBACK)
- mdp4_overlay1_done_writeback(dma);
+ mdp4_overlay2_done_wfd(&dma_wb_data);
}
#endif
#endif /* OVERLAY */
@@ -2138,7 +2133,7 @@
base = 0x1A000;
break;
case MDP_BLOCK_OVERLAY_2:
- base = (mdp_rev >= MDP_REV_44) ? 0x8A000 : 0x0;
+ base = (mdp_rev >= MDP_REV_43) ? 0x8A000 : 0x0;
break;
case MDP_BLOCK_VG_1:
base = 0x24000;
@@ -2309,7 +2304,7 @@
pr_info("%s:%d ion based allocation mfd->mem_hid 0x%x\n",
__func__, __LINE__, mfd->mem_hid);
buf->ihdl = ion_alloc(mfd->iclient, buffer_size, SZ_4K,
- mfd->mem_hid);
+ mfd->mem_hid, 0);
if (!IS_ERR_OR_NULL(buf->ihdl)) {
if (mdp_iommu_split_domain) {
if (ion_map_iommu(mfd->iclient, buf->ihdl,
@@ -2658,7 +2653,7 @@
break;
case MDP_BLOCK_OVERLAY_2:
- valid = (mdp_rev >= MDP_REV_44) ? 1 : 0;
+ valid = (mdp_rev >= MDP_REV_43) ? 1 : 0;
break;
default:
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 0fad0a7..54f5ef5 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -719,84 +719,6 @@
.write = pmdh_reg_write,
};
-
-
-#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDDI)
-static int vsync_reg_open(struct inode *inode, struct file *file)
-{
- /* non-seekable */
- file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
- return 0;
-}
-
-static int vsync_reg_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static ssize_t vsync_reg_write(
- struct file *file,
- const char __user *buff,
- size_t count,
- loff_t *ppos)
-{
- uint32 enable;
- int cnt;
-
- if (count >= sizeof(debug_buf))
- return -EFAULT;
-
- if (copy_from_user(debug_buf, buff, count))
- return -EFAULT;
-
- debug_buf[count] = 0; /* end of string */
-
- cnt = sscanf(debug_buf, "%x", &enable);
-
- mdp_dmap_vsync_set(enable);
-
- return count;
-}
-
-static ssize_t vsync_reg_read(
- struct file *file,
- char __user *buff,
- size_t count,
- loff_t *ppos)
-{
- char *bp;
- int len = 0;
- int tot = 0;
- int dlen;
-
- if (*ppos)
- return 0; /* the end */
-
- bp = debug_buf;
- dlen = sizeof(debug_buf);
- len = snprintf(bp, dlen, "%x\n", mdp_dmap_vsync_get());
- tot += len;
- bp += len;
- *bp = 0;
- tot++;
-
- if (copy_to_user(buff, debug_buf, tot))
- return -EFAULT;
-
- *ppos += tot; /* increase offset */
-
- return tot;
-}
-
-
-static const struct file_operations vsync_fops = {
- .open = vsync_reg_open,
- .release = vsync_reg_release,
- .read = vsync_reg_read,
- .write = vsync_reg_write,
-};
-#endif
-
static ssize_t emdh_reg_write(
struct file *file,
const char __user *buff,
@@ -1342,15 +1264,6 @@
return -1;
}
-#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDDI)
- if (debugfs_create_file("vsync", 0644, dent, 0, &vsync_fops)
- == NULL) {
- printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n",
- __FILE__, __LINE__);
- return -1;
- }
-#endif
-
dent = debugfs_create_dir("emdh", NULL);
if (IS_ERR(dent)) {
diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c
index 4b76e72..4d4b05f 100644
--- a/drivers/video/msm/mdp_dma.c
+++ b/drivers/video/msm/mdp_dma.c
@@ -482,10 +482,22 @@
#endif
{
unsigned long flag;
+ static int first_vsync;
+ int need_wait = 0;
down(&mfd->dma->mutex);
- if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
+ if ((mfd) && (mfd->panel_power_on)) {
down(&mfd->sem);
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ if (mfd->dma->busy == TRUE)
+ need_wait++;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ if (need_wait)
+ wait_for_completion_killable(&mfd->dma->comp);
+
+ /* schedule DMA to start */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mfd->ibuf_flushed = TRUE;
mdp_dma2_update_lcd(mfd);
@@ -493,15 +505,31 @@
mdp_enable_irq(MDP_DMA2_TERM);
mfd->dma->busy = TRUE;
INIT_COMPLETION(mfd->dma->comp);
-
+ INIT_COMPLETION(vsync_cntrl.vsync_comp);
+ if (!vsync_cntrl.vsync_irq_enabled &&
+ vsync_cntrl.disabled_clocks) {
+ MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
+ outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
+ mdp_intr_mask |= MDP_PRIM_RDPTR;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ mdp_enable_irq(MDP_VSYNC_TERM);
+ vsync_cntrl.vsync_dma_enabled = 1;
+ }
spin_unlock_irqrestore(&mdp_spin_lock, flag);
/* schedule DMA to start */
mdp_dma_schedule(mfd, MDP_DMA2_TERM);
up(&mfd->sem);
- /* wait until DMA finishes the current job */
- wait_for_completion_killable(&mfd->dma->comp);
- mdp_disable_irq(MDP_DMA2_TERM);
+ /* wait until Vsync finishes the current job */
+ if (first_vsync) {
+ if (!wait_for_completion_killable_timeout
+ (&vsync_cntrl.vsync_comp, HZ/10))
+ pr_err("Timedout DMA %s %d", __func__,
+ __LINE__);
+ } else {
+ first_vsync = 1;
+ }
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
/* signal if pan function is waiting for the update completion */
if (mfd->pan_waiting) {
@@ -515,28 +543,37 @@
void mdp_dma_vsync_ctrl(int enable)
{
unsigned long flag;
+ int disabled_clocks;
if (vsync_cntrl.vsync_irq_enabled == enable)
return;
spin_lock_irqsave(&mdp_spin_lock, flag);
if (!enable)
INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
vsync_cntrl.vsync_irq_enabled = enable;
+ disabled_clocks = vsync_cntrl.disabled_clocks;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
- if (enable) {
+ if (enable && disabled_clocks)
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ if (enable && vsync_cntrl.disabled_clocks &&
+ !vsync_cntrl.vsync_dma_enabled) {
MDP_OUTP(MDP_BASE + 0x021c, 0x10); /* read pointer */
- spin_lock_irqsave(&mdp_spin_lock, flag);
outp32(MDP_INTR_CLEAR, MDP_PRIM_RDPTR);
mdp_intr_mask |= MDP_PRIM_RDPTR;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
mdp_enable_irq(MDP_VSYNC_TERM);
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- } else {
- wait_for_completion(&vsync_cntrl.vsync_wait);
- mdp_disable_irq(MDP_VSYNC_TERM);
+ vsync_cntrl.disabled_clocks = 0;
+ } else if (enable && vsync_cntrl.disabled_clocks) {
+ vsync_cntrl.disabled_clocks = 0;
}
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ if (vsync_cntrl.vsync_irq_enabled &&
+ atomic_read(&vsync_cntrl.suspend) == 0)
+ atomic_set(&vsync_cntrl.vsync_resume, 1);
}
void mdp_lcd_update_workqueue_handler(struct work_struct *work)
diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c
index a1f2b65..e2fb8ba 100644
--- a/drivers/video/msm/mdp_dma_dsi_video.c
+++ b/drivers/video/msm/mdp_dma_dsi_video.c
@@ -34,6 +34,33 @@
static int first_pixel_start_x;
static int first_pixel_start_y;
+static ssize_t vsync_show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
+ if (atomic_read(&vsync_cntrl.suspend) > 0 ||
+ atomic_read(&vsync_cntrl.vsync_resume) == 0)
+ return 0;
+
+ wait_for_completion(&vsync_cntrl.vsync_wait);
+ ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
+ ktime_to_ns(vsync_cntrl.vsync_time));
+ buf[strlen(buf) + 1] = '\0';
+ return ret;
+}
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+ &dev_attr_vsync_event.attr,
+ NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+ .attrs = vsync_fs_attrs,
+};
+
int mdp_dsi_video_on(struct platform_device *pdev)
{
int dsi_width;
@@ -88,6 +115,7 @@
var = &fbi->var;
vsync_cntrl.dev = mfd->fbi->dev;
+ atomic_set(&vsync_cntrl.suspend, 0);
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
@@ -226,6 +254,20 @@
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ if (!vsync_cntrl.sysfs_created) {
+ ret = sysfs_create_group(&vsync_cntrl.dev->kobj,
+ &vsync_fs_attr_group);
+ if (ret) {
+ pr_err("%s: sysfs creation failed, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD);
+ pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+ vsync_cntrl.sysfs_created = 1;
+ }
+
return ret;
}
@@ -241,6 +283,10 @@
mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
ret = panel_next_off(pdev);
+
+ atomic_set(&vsync_cntrl.suspend, 1);
+ atomic_set(&vsync_cntrl.vsync_resume, 0);
+ complete_all(&vsync_cntrl.vsync_wait);
/* delay to make sure the last frame finishes */
msleep(20);
@@ -250,16 +296,21 @@
void mdp_dma_video_vsync_ctrl(int enable)
{
unsigned long flag;
+ int disabled_clocks;
if (vsync_cntrl.vsync_irq_enabled == enable)
return;
spin_lock_irqsave(&mdp_spin_lock, flag);
if (!enable)
INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
vsync_cntrl.vsync_irq_enabled = enable;
+ if (!enable)
+ vsync_cntrl.disabled_clocks = 0;
+ disabled_clocks = vsync_cntrl.disabled_clocks;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
- if (enable) {
+ if (enable && disabled_clocks) {
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
spin_lock_irqsave(&mdp_spin_lock, flag);
outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
@@ -267,10 +318,10 @@
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
mdp_enable_irq(MDP_VSYNC_TERM);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
- } else {
- wait_for_completion(&vsync_cntrl.vsync_wait);
- mdp_disable_irq(MDP_VSYNC_TERM);
}
+ if (vsync_cntrl.vsync_irq_enabled &&
+ atomic_read(&vsync_cntrl.suspend) == 0)
+ atomic_set(&vsync_cntrl.vsync_resume, 1);
}
void mdp_dsi_video_update(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c
index 10d60ab..fbfe35f 100644
--- a/drivers/video/msm/mdp_dma_lcdc.c
+++ b/drivers/video/msm/mdp_dma_lcdc.c
@@ -51,6 +51,33 @@
int first_pixel_start_x;
int first_pixel_start_y;
+static ssize_t vsync_show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ if (atomic_read(&vsync_cntrl.suspend) > 0 ||
+ atomic_read(&vsync_cntrl.vsync_resume) == 0)
+ return 0;
+
+ INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
+ wait_for_completion(&vsync_cntrl.vsync_wait);
+ ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu",
+ ktime_to_ns(vsync_cntrl.vsync_time));
+ buf[strlen(buf) + 1] = '\0';
+ return ret;
+}
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static struct attribute *vsync_fs_attrs[] = {
+ &dev_attr_vsync_event.attr,
+ NULL,
+};
+static struct attribute_group vsync_fs_attr_group = {
+ .attrs = vsync_fs_attrs,
+};
+
int mdp_lcdc_on(struct platform_device *pdev)
{
int lcdc_width;
@@ -106,6 +133,7 @@
fbi = mfd->fbi;
var = &fbi->var;
vsync_cntrl.dev = mfd->fbi->dev;
+ atomic_set(&vsync_cntrl.suspend, 0);
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
@@ -292,6 +320,20 @@
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ if (!vsync_cntrl.sysfs_created) {
+ ret = sysfs_create_group(&vsync_cntrl.dev->kobj,
+ &vsync_fs_attr_group);
+ if (ret) {
+ pr_err("%s: sysfs creation failed, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ kobject_uevent(&vsync_cntrl.dev->kobj, KOBJ_ADD);
+ pr_debug("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
+ vsync_cntrl.sysfs_created = 1;
+ }
+
return ret;
}
@@ -321,6 +363,9 @@
ret = panel_next_off(pdev);
up(&mfd->dma->mutex);
+ atomic_set(&vsync_cntrl.suspend, 1);
+ atomic_set(&vsync_cntrl.vsync_resume, 0);
+ complete_all(&vsync_cntrl.vsync_wait);
/* delay to make sure the last frame finishes */
msleep(16);
@@ -331,16 +376,21 @@
void mdp_dma_lcdc_vsync_ctrl(int enable)
{
unsigned long flag;
+ int disabled_clocks;
if (vsync_cntrl.vsync_irq_enabled == enable)
return;
spin_lock_irqsave(&mdp_spin_lock, flag);
if (!enable)
INIT_COMPLETION(vsync_cntrl.vsync_wait);
+
vsync_cntrl.vsync_irq_enabled = enable;
+ if (!enable)
+ vsync_cntrl.disabled_clocks = 0;
+ disabled_clocks = vsync_cntrl.disabled_clocks;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
- if (enable) {
+ if (enable && disabled_clocks) {
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
spin_lock_irqsave(&mdp_spin_lock, flag);
outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
@@ -348,10 +398,11 @@
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
mdp_enable_irq(MDP_VSYNC_TERM);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
- } else {
- wait_for_completion(&vsync_cntrl.vsync_wait);
- mdp_disable_irq(MDP_VSYNC_TERM);
}
+
+ if (vsync_cntrl.vsync_irq_enabled &&
+ atomic_read(&vsync_cntrl.suspend) == 0)
+ atomic_set(&vsync_cntrl.vsync_resume, 1);
}
void mdp_lcdc_update(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 6f42565..3c60c2b 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -15,6 +15,7 @@
#define MDSS_H
#include <linux/msm_ion.h>
+#include <linux/earlysuspend.h>
#include <linux/msm_mdp.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@@ -23,8 +24,6 @@
#define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_res->mdp_base + addr)
#define MDSS_REG_READ(addr) readl_relaxed(mdss_res->mdp_base + addr)
-extern spinlock_t dsi_clk_lock;
-
enum mdss_mdp_clk_type {
MDSS_CLK_AHB,
MDSS_CLK_AXI,
@@ -53,6 +52,7 @@
u32 irq_buzy;
u32 mdp_irq_mask;
+ u32 mdp_hist_irq_mask;
u32 suspend;
u32 timeout;
@@ -74,6 +74,8 @@
struct ion_client *iclient;
int iommu_domain;
int iommu_attached;
+
+ struct early_suspend early_suspend;
};
extern struct mdss_data_type *mdss_res;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index e409a0b..8f4f4d5 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -199,11 +199,7 @@
{
int ret = 0;
- spin_lock_bh(&dsi_clk_lock);
mdss_dsi_clk_disable(pdata);
-
- spin_unlock_bh(&dsi_clk_lock);
-
mdss_dsi_unprepare_clocks();
/* disable DSI controller */
@@ -250,11 +246,7 @@
mdss_dsi_phy_init(pdata);
mdss_dsi_prepare_clocks();
-
- spin_lock_bh(&dsi_clk_lock);
-
mdss_dsi_clk_enable(pdata);
- spin_unlock_bh(&dsi_clk_lock);
clk_rate = pdata->panel_info.clk_rate;
clk_rate = min(clk_rate, pdata->panel_info.clk_max);
@@ -311,6 +303,7 @@
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data);
}
+ mdss_dsi_sw_reset(pdata);
mdss_dsi_host_init(mipi, pdata);
if (mipi->force_clk_lane_hs) {
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 5d0d578..125644e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -32,8 +32,6 @@
static spinlock_t dsi_mdp_lock;
static int dsi_mdp_busy;
-spinlock_t dsi_clk_lock;
-
struct mdss_hw mdss_dsi_hw = {
.hw_ndx = MDSS_HW_DSI0,
.ptr = NULL,
@@ -45,7 +43,6 @@
init_completion(&dsi_dma_comp);
spin_lock_init(&dsi_irq_lock);
spin_lock_init(&dsi_mdp_lock);
- spin_lock_init(&dsi_clk_lock);
}
void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
@@ -816,6 +813,7 @@
void mdss_dsi_sw_reset(struct mdss_panel_data *pdata)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ u32 dsi_ctrl;
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
@@ -824,6 +822,16 @@
return;
}
+ dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
+ dsi_ctrl &= ~0x01;
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl);
+ wmb();
+
+ /* turn esc, byte, dsi, pclk, sclk, hclk on */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x11c,
+ 0x23f); /* DSI_CLK_CTRL */
+ wmb();
+
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 0x01);
wmb();
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x118, 0x00);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index b247e4d..fd52e1c 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -106,8 +106,6 @@
pr_debug("%s:%d, debug info (mode) : %d\n", __func__, __LINE__,
mipi->mode);
- mdss_dsi_sw_reset(pdata);
-
if (mipi->mode == DSI_VIDEO_MODE) {
mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf, dsi_panel_on_cmds,
num_of_on_cmds);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 3bef9b3..9f29887 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -42,6 +42,9 @@
#include <linux/vmalloc.h>
#include <mach/board.h>
+#include <mach/memory.h>
+#include <mach/msm_memtypes.h>
+#include <mach/iommu_domains.h>
#include "mdss_fb.h"
#include "mdss_mdp.h"
@@ -316,6 +319,9 @@
mfd->op_enable);
if (ret)
pr_warn("can't turn on display!\n");
+
+ if (mfd->vsync_pending)
+ mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
}
return ret;
@@ -593,37 +599,17 @@
size *= mfd->fb_page;
if (mfd->index == 0) {
- struct ion_client *iclient = mdss_get_ionclient();
-
- if (iclient) {
- mfd->ihdl = ion_alloc(iclient, size, SZ_4K,
- ION_HEAP(ION_CP_MM_HEAP_ID) |
- ION_HEAP(ION_SF_HEAP_ID));
- if (IS_ERR_OR_NULL(mfd->ihdl)) {
- pr_err("unable to alloc fbmem from ion (%p)\n",
- mfd->ihdl);
- return -ENOMEM;
- }
-
- virt = ion_map_kernel(iclient, mfd->ihdl, 0);
- ion_phys(iclient, mfd->ihdl, &phys, &size);
-
- if (is_mdss_iommu_attached()) {
- ion_map_iommu(iclient, mfd->ihdl,
- mdss_get_iommu_domain(),
- 0, SZ_4K, 0, &mfd->iova,
- (unsigned long *) &size,
- 0, 0);
- }
- } else {
- virt = dma_alloc_coherent(NULL, size,
- (dma_addr_t *) &phys, GFP_KERNEL);
- if (!virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
- return -ENOMEM;
- }
+ virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+ if (!virt) {
+ pr_err("unable to alloc fbmem size=%u\n", size);
+ return -ENOMEM;
}
-
+ phys = memory_pool_node_paddr(virt);
+ if (is_mdss_iommu_attached()) {
+ msm_iommu_map_contig_buffer(phys,
+ mdss_get_iommu_domain(), 0, size, SZ_4K, 0,
+ &(mfd->iova));
+ }
pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
size, virt, phys, mfd->index);
} else {
@@ -943,7 +929,6 @@
struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- u32 len;
if (var->rotate != FB_ROTATE_UR)
return -EINVAL;
@@ -1022,9 +1007,12 @@
if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
return -EINVAL;
- len = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
- if (len > info->fix.smem_len)
- return -EINVAL;
+ if (info->fix.smem_start) {
+ u32 len = var->xres_virtual * var->yres_virtual *
+ (var->bits_per_pixel / 8);
+ if (len > info->fix.smem_len)
+ return -EINVAL;
+ }
if ((var->xres == 0) || (var->yres == 0))
return -EINVAL;
@@ -1148,6 +1136,46 @@
ret = mdss_mdp_pa_config(&mdp_pp.data.pa_cfg_data,
©back);
break;
+
+ case mdp_op_pcc_cfg:
+ ret = mdss_mdp_pcc_config(&mdp_pp.data.pcc_cfg_data,
+ ©back);
+ break;
+
+ case mdp_op_lut_cfg:
+ switch (mdp_pp.data.lut_cfg_data.lut_type) {
+ case mdp_lut_igc:
+ ret = mdss_mdp_igc_lut_config(
+ (struct mdp_igc_lut_data *)
+ &mdp_pp.data.lut_cfg_data.data,
+ ©back);
+ break;
+
+ case mdp_lut_pgc:
+ ret = mdss_mdp_argc_config(
+ &mdp_pp.data.lut_cfg_data.data.pgc_lut_data,
+ ©back);
+ break;
+
+ case mdp_lut_hist:
+ ret = mdss_mdp_hist_lut_config(
+ (struct mdp_hist_lut_data *)
+ &mdp_pp.data.lut_cfg_data.data, ©back);
+ break;
+
+ default:
+ ret = -ENOTSUPP;
+ break;
+ }
+ break;
+ case mdp_op_dither_cfg:
+ ret = mdss_mdp_dither_config(&mdp_pp.data.dither_cfg_data,
+ ©back);
+ break;
+ case mdp_op_gamut_cfg:
+ ret = mdss_mdp_gamut_config(&mdp_pp.data.gamut_cfg_data,
+ ©back);
+ break;
default:
pr_err("Unsupported request to MDP_PP IOCTL.\n");
ret = -EINVAL;
@@ -1163,6 +1191,9 @@
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
void __user *argp = (void __user *)arg;
+ struct mdp_histogram_data hist;
+ struct mdp_histogram_start_req hist_req;
+ u32 block, hist_data_addr = 0;
struct mdp_page_protection fb_page_protection;
int ret = -ENOSYS;
@@ -1175,6 +1206,43 @@
ret = mdss_fb_set_lut(info, argp);
break;
+ case MSMFB_HISTOGRAM:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+
+ ret = copy_from_user(&hist, argp, sizeof(hist));
+ if (ret)
+ return ret;
+
+ ret = mdss_mdp_hist_collect(info, &hist, &hist_data_addr);
+ if ((ret == 0) && hist_data_addr) {
+ ret = copy_to_user(hist.c0, (u32 *)hist_data_addr,
+ sizeof(u32) * hist.bin_cnt);
+ if (ret == 0)
+ ret = copy_to_user(argp, &hist,
+ sizeof(hist));
+ }
+ break;
+
+ case MSMFB_HISTOGRAM_START:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+
+ ret = copy_from_user(&hist_req, argp, sizeof(hist_req));
+ if (ret)
+ return ret;
+
+ ret = mdss_mdp_histogram_start(&hist_req);
+ break;
+
+ case MSMFB_HISTOGRAM_STOP:
+ ret = copy_from_user(&block, argp, sizeof(int));
+ if (ret)
+ return ret;
+
+ ret = mdss_mdp_histogram_stop(block);
+ break;
+
case MSMFB_GET_PAGE_PROTECTION:
fb_page_protection.page_protection =
mfd->mdp_fb_page_protection;
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index a10e5e4..25c39f6 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -56,6 +56,7 @@
int op_enable;
u32 fb_imgType;
u32 dst_format;
+ int vsync_pending;
int hw_refresh;
@@ -95,6 +96,8 @@
struct mdss_mdp_ctl *ctl;
struct mdss_mdp_wb *wb;
struct list_head overlay_list;
+ struct list_head pipes_used;
+ struct list_head pipes_cleanup;
};
int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index f720a2f..8db38d6 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -358,34 +358,25 @@
DEV_DBG("EDID: reading block(%d) with block-size=%d\n",
block, block_size);
for (i = 0; i < 0x80; i += block_size) {
- /*Read EDID twice with 32bit alighnment too */
- if (block < 2) {
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0xA0;
- ddc_data.offset = block*0x80 + i;
- ddc_data.data_buf = edid_buf+i;
- ddc_data.data_len = block_size;
- ddc_data.retry = 1;
- ddc_data.what = "EDID";
- ddc_data.no_align = false;
+ memset(&ddc_data, 0, sizeof(ddc_data));
+ ddc_data.dev_addr = 0xA0;
+ ddc_data.offset = block*0x80 + i;
+ ddc_data.data_buf = edid_buf+i;
+ ddc_data.data_len = block_size;
+ ddc_data.request_len = block_size;
+ ddc_data.retry = 1;
+ ddc_data.what = "EDID";
+ ddc_data.no_align = false;
+ /*Read EDID twice with 32bit alighnment too */
+ if (block < 2)
status = hdmi_ddc_read(
edid_ctrl->init_data.ddc_ctrl,
&ddc_data);
- } else {
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0xA0;
- ddc_data.offset = block*0x80 + i;
- ddc_data.data_buf = edid_buf+i;
- ddc_data.data_len = block_size;
- ddc_data.request_len = block_size;
- ddc_data.retry = 1;
- ddc_data.what = "EDID";
-
+ else
status = hdmi_ddc_read_seg(
edid_ctrl->init_data.ddc_ctrl,
&ddc_data);
- }
if (status)
break;
}
@@ -413,7 +404,7 @@
}
print_len = 0x80;
- for (ndx = 0; ndx < print_len; ndx += 16)
+ for (ndx = 0; ndx < print_len; ndx += 4)
DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x\n",
ndx, ndx+3,
b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3]);
@@ -1392,7 +1383,7 @@
{
struct hdmi_edid_ctrl *edid_ctrl = NULL;
- if (!init_data || !init_data->base ||
+ if (!init_data || !init_data->io ||
!init_data->mutex || !init_data->sysfs_kobj ||
!init_data->ddc_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.h b/drivers/video/msm/mdss/mdss_hdmi_edid.h
index d10ae49..5c51e7e 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.h
@@ -16,7 +16,7 @@
#include "mdss_hdmi_util.h"
struct hdmi_edid_init_data {
- void __iomem *base;
+ struct dss_io_data *io;
struct mutex *mutex;
struct kobject *sysfs_kobj;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 9278029..7f41221 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -12,7 +12,6 @@
*/
#include <linux/bitops.h>
-#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -20,7 +19,7 @@
#include <linux/of_gpio.h>
#include <linux/types.h>
-/* #define DEBUG */
+#define REG_DUMP 0
#include "mdss_fb.h"
#include "mdss_hdmi_tx.h"
@@ -91,19 +90,19 @@
0x07, 0x07, 0x07, 0x07, 0x02, 0x02, 0x02} /*12*/
};
-static const char *hdmi_tx_clk_name(u32 clk)
+const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
{
- switch (clk) {
- case HDMI_TX_AHB_CLK: return "hdmi_ahb_clk";
- case HDMI_TX_APP_CLK: return "hdmi_app_clk";
- case HDMI_TX_EXTP_CLK: return "hdmi_extp_clk";
- default: return "???";
+ switch (module) {
+ case HDMI_TX_HPD_PM: return "HDMI_TX_HPD_PM";
+ case HDMI_TX_CORE_PM: return "HDMI_TX_CORE_PM";
+ case HDMI_TX_CEC_PM: return "HDMI_TX_CEC_PM";
+ default: return "???";
}
-} /* hdmi_tx_clk_name */
+} /* hdmi_tx_pm_name */
-static const char *hdmi_tx_io_name(u32 io)
+static const char *hdmi_tx_io_name(u32 type)
{
- switch (io) {
+ switch (type) {
case HDMI_TX_CORE_IO: return "core_physical";
case HDMI_TX_PHY_IO: return "phy_physical";
case HDMI_TX_QFPROM_IO: return "qfprom_physical";
@@ -190,75 +189,6 @@
return ret;
} /* hdmi_tx_sysfs_rda_connected */
-static ssize_t hdmi_tx_sysfs_rda_fake_hpd(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- ssize_t ret;
- struct hdmi_tx_ctrl *hdmi_ctrl =
- hdmi_tx_get_drvdata_from_sysfs_dev(dev);
-
- if (!hdmi_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
- return -EINVAL;
- }
-
- mutex_lock(&hdmi_ctrl->mutex);
- ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_state);
- DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_state);
- mutex_unlock(&hdmi_ctrl->mutex);
-
- return ret;
-} /* hdmi_tx_sysfs_rda_fake_hpd */
-
-static ssize_t hdmi_tx_sysfs_wta_fake_hpd(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int fake_hpd, rc = 0;
- ssize_t ret = strnlen(buf, PAGE_SIZE);
- struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-
- DEV_DBG("%s:\n", __func__);
- hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
-
- if (!hdmi_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
- return -EINVAL;
- }
-
- rc = kstrtoint(buf, 10, &fake_hpd);
- if (rc) {
- DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
- return rc;
- }
-
- mutex_lock(&hdmi_ctrl->mutex);
- DEV_INFO("%s: fake_hpd=%d\n", __func__, fake_hpd);
- if (fake_hpd) {
- hdmi_ctrl->hpd_state = true;
-
- /* todo: Remove this once HPD line is available in HW */
- DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
- if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE))
- DEV_ERR("%s: failed sending online event\n", __func__);
- switch_set_state(&hdmi_ctrl->sdev, 1);
- DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
- hdmi_ctrl->sdev.state);
- } else {
- hdmi_ctrl->hpd_state = false;
-
- /* todo: Remove this once HPD line is available in HW */
- DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
- if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE))
- DEV_ERR("%s: failed sending online event\n", __func__);
- switch_set_state(&hdmi_ctrl->sdev, 0);
- DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
- hdmi_ctrl->sdev.state);
- }
- mutex_unlock(&hdmi_ctrl->mutex);
-
- return ret;
-} /* hdmi_tx_sysfs_wta_fake_hpd */
-
static ssize_t hdmi_tx_sysfs_rda_hpd(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -298,16 +228,13 @@
return rc;
}
- /* todo: Remove this once HPD line is available in HW */
- if (0) {
- if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
- rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
- } else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
- rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
- } else {
- rc = -EPERM;
- ret = rc;
- }
+ if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+ } else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+ } else {
+ rc = -EPERM;
+ ret = rc;
}
if (!rc) {
@@ -325,13 +252,10 @@
static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
hdmi_tx_sysfs_wta_hpd);
-static DEVICE_ATTR(fake_hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_fake_hpd,
- hdmi_tx_sysfs_wta_fake_hpd);
static struct attribute *hdmi_tx_fs_attrs[] = {
&dev_attr_connected.attr,
&dev_attr_hpd.attr,
- &dev_attr_fake_hpd.attr,
NULL,
};
static struct attribute_group hdmi_tx_fs_attrs_group = {
@@ -385,7 +309,7 @@
return -EINVAL;
}
- edid_init_data.base = hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base;
+ edid_init_data.io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
edid_init_data.mutex = &hdmi_ctrl->mutex;
edid_init_data.sysfs_kobj = hdmi_ctrl->kobj;
edid_init_data.ddc_ctrl = &hdmi_ctrl->ddc_ctrl;
@@ -405,14 +329,14 @@
static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- return HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
- HDMI_CTRL) & BIT(0);
+ struct dss_io_data *io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ return DSS_REG_R_ND(io, HDMI_CTRL) & BIT(0);
} /* hdmi_tx_is_controller_on */
static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- return !(HDMI_REG_R_ND(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
- HDMI_CTRL) & BIT(1));
+ struct dss_io_data *io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ return !(DSS_REG_R_ND(io, HDMI_CTRL) & BIT(1));
} /* hdmi_tx_is_dvi_mode */
static int hdmi_tx_init_panel_info(uint32_t resolution,
@@ -473,44 +397,6 @@
hdmi_set_supported_mode(HDMI_VFRMT_1920x1080p60_16_9);
} /* hdmi_tx_setup_video_mode_lut */
-static inline struct clk *hdmi_tx_get_clk(struct hdmi_tx_platform_data *pdata,
- u32 clk_idx)
-{
- if (!pdata || clk_idx > HDMI_TX_MAX_CLK) {
- DEV_ERR("%s: invalid input\n", __func__);
- return NULL;
- }
-
- return pdata->clk[clk_idx];
-} /* hdmi_tx_get_clk */
-
-static int hdmi_tx_clk_set_rate(struct hdmi_tx_platform_data *pdata,
- u32 clk_idx, unsigned long clk_rate)
-{
- int rc = 0;
- struct clk *clk = NULL;
-
- if (!pdata) {
- DEV_ERR("%s: invalid input\n", __func__);
- return -EINVAL;
- }
-
- clk = hdmi_tx_get_clk(pdata, clk_idx);
- if (clk) {
- rc = clk_set_rate(clk, clk_rate);
- if (IS_ERR_VALUE(rc))
- DEV_ERR("%s: failed rc=%d\n", __func__, rc);
- else
- DEV_DBG("%s: name='%s' rate=%lu\n", __func__,
- hdmi_tx_clk_name(clk_idx), clk_rate);
- } else {
- DEV_ERR("%s: FAILED: invalid clk_idx=%d\n", __func__, clk_idx);
- rc = -EINVAL;
- }
-
- return rc;
-} /* hdmi_tx_clk_set_rate */
-
static int hdmi_tx_read_sink_info(struct hdmi_tx_ctrl *hdmi_ctrl)
{
int status;
@@ -551,9 +437,14 @@
}
io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: Core io is not initialized\n", __func__);
+ return;
+ }
+
DEV_DBG("%s: Got HPD interrupt\n", __func__);
- hpd_state = (HDMI_REG_R(io->base, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+ hpd_state = (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
mutex_lock(&hdmi_ctrl->mutex);
if ((hdmi_ctrl->hpd_prev_state != hdmi_ctrl->hpd_state) ||
(hdmi_ctrl->hpd_state != hpd_state)) {
@@ -605,22 +496,62 @@
}
/* Set IRQ for HPD */
- HDMI_REG_W(io->base, HDMI_HPD_INT_CTRL, 4 | (hpd_state ? 0 : 2));
+ DSS_REG_W(io, HDMI_HPD_INT_CTRL, 4 | (hpd_state ? 0 : 2));
} /* hdmi_tx_hpd_state_work */
-static int hdmi_tx_check_capability(void __iomem *base)
+static void hdmi_tx_hpd_int_work(struct work_struct *work)
+{
+ u32 hpd_int_status;
+ u32 hpd_int_ctrl;
+ u32 cable_detected;
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+ struct dss_io_data *io = NULL;
+
+ hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_int_work);
+ if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
+ DEV_DBG("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: Core io is not initialized\n", __func__);
+ return;
+ }
+
+ /* Process HPD Interrupt */
+ hpd_int_status = DSS_REG_R(io, HDMI_HPD_INT_STATUS);
+ hpd_int_ctrl = DSS_REG_R(io, HDMI_HPD_INT_CTRL);
+
+ DSS_REG_W(io, HDMI_HPD_INT_CTRL, BIT(2));
+
+ cable_detected = hpd_int_status & BIT(1);
+ mutex_lock(&hdmi_ctrl->mutex);
+ hdmi_ctrl->hpd_cable_chg_detected = true;
+ hdmi_ctrl->hpd_prev_state = cable_detected ? 0 : 1;
+ hdmi_ctrl->hpd_stable = 0;
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+
+ DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
+ hpd_int_status);
+} /* hdmi_tx_hpd_int_work */
+
+static int hdmi_tx_check_capability(struct dss_io_data *io)
{
u32 hdmi_disabled, hdcp_disabled;
- if (!base) {
+ if (!io) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
- /* QFPROM_RAW_FEAT_CONFIG_ROW0_LSB */
- hdcp_disabled = HDMI_REG_R_ND(base, 0x000000F8) & BIT(31);
- /* QFPROM_RAW_FEAT_CONFIG_ROW0_MSB */
- hdmi_disabled = HDMI_REG_R_ND(base, 0x000000FC) & BIT(0);
+ hdcp_disabled = DSS_REG_R_ND(io,
+ QFPROM_RAW_FEAT_CONFIG_ROW0_LSB) & BIT(31);
+
+ hdmi_disabled = DSS_REG_R_ND(io,
+ QFPROM_RAW_FEAT_CONFIG_ROW0_MSB) & BIT(0);
DEV_DBG("%s: Features <HDMI:%s, HDCP:%s>\n", __func__,
hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON");
@@ -710,25 +641,9 @@
goto end;
}
- /*
- * extpclk is driven by hdmi phy pll. This phy pll programming requires
- * hdmi_ahb_clk. So enable it and then disable.
- */
- rc = clk_prepare_enable(pdata->clk[HDMI_TX_AHB_CLK]);
- if (rc) {
- DEV_ERR("%s: failed to enable '%s' clk\n", __func__,
- hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
- goto end;
- }
- rc = hdmi_tx_clk_set_rate(pdata, HDMI_TX_EXTP_CLK,
- timing->pixel_freq * 1000);
- if (rc) {
- DEV_ERR("%s: FAILED: '%s' clk set rate\n", __func__,
- hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
- clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
- goto end;
- }
- clk_disable_unprepare(pdata->clk[HDMI_TX_AHB_CLK]);
+ /* todo: find a better way */
+ hdmi_ctrl->pdata.power_data[HDMI_TX_CORE_PM].clk_config[0].rate =
+ timing->pixel_freq * 1000;
hdmi_ctrl->video_resolution = format;
hdmi_edid_set_video_resolution(
@@ -772,35 +687,35 @@
timing->back_porch_h + timing->pulse_width_h - 1;
total_v = timing->active_v + timing->front_porch_v +
timing->back_porch_v + timing->pulse_width_v - 1;
- HDMI_REG_W(io->base, HDMI_TOTAL,
+ DSS_REG_W(io, HDMI_TOTAL,
((total_v << 16) & 0x0FFF0000) |
((total_h << 0) & 0x00000FFF));
start_h = timing->back_porch_h + timing->pulse_width_h;
end_h = (total_h + 1) - timing->front_porch_h;
- HDMI_REG_W(io->base, HDMI_ACTIVE_H,
+ DSS_REG_W(io, HDMI_ACTIVE_H,
((end_h << 16) & 0x0FFF0000) |
((start_h << 0) & 0x00000FFF));
start_v = timing->back_porch_v + timing->pulse_width_v - 1;
end_v = total_v - timing->front_porch_v;
- HDMI_REG_W(io->base, HDMI_ACTIVE_V,
+ DSS_REG_W(io, HDMI_ACTIVE_V,
((end_v << 16) & 0x0FFF0000) |
((start_v << 0) & 0x00000FFF));
if (timing->interlaced) {
- HDMI_REG_W(io->base, HDMI_V_TOTAL_F2,
+ DSS_REG_W(io, HDMI_V_TOTAL_F2,
((total_v + 1) << 0) & 0x00000FFF);
- HDMI_REG_W(io->base, HDMI_ACTIVE_V_F2,
+ DSS_REG_W(io, HDMI_ACTIVE_V_F2,
(((start_v + 1) << 0) & 0x00000FFF) |
(((end_v + 1) << 16) & 0x0FFF0000));
} else {
- HDMI_REG_W(io->base, HDMI_V_TOTAL_F2, 0);
- HDMI_REG_W(io->base, HDMI_ACTIVE_V_F2, 0);
+ DSS_REG_W(io, HDMI_V_TOTAL_F2, 0);
+ DSS_REG_W(io, HDMI_ACTIVE_V_F2, 0);
}
- HDMI_REG_W(io->base, HDMI_FRAME_CTRL,
+ DSS_REG_W(io, HDMI_FRAME_CTRL,
((timing->interlaced << 31) & 0x80000000) |
((timing->active_low_h << 29) & 0x20000000) |
((timing->active_low_v << 28) & 0x10000000));
@@ -929,28 +844,28 @@
regVal = regVal << 8 | avi_iframe[4];
regVal = regVal << 8 | avi_iframe[3];
regVal = regVal << 8 | checksum;
- HDMI_REG_W(io->base, HDMI_AVI_INFO0, regVal);
+ DSS_REG_W(io, HDMI_AVI_INFO0, regVal);
regVal = avi_iframe[9];
regVal = regVal << 8 | avi_iframe[8];
regVal = regVal << 8 | avi_iframe[7];
regVal = regVal << 8 | avi_iframe[6];
- HDMI_REG_W(io->base, HDMI_AVI_INFO1, regVal);
+ DSS_REG_W(io, HDMI_AVI_INFO1, regVal);
regVal = avi_iframe[13];
regVal = regVal << 8 | avi_iframe[12];
regVal = regVal << 8 | avi_iframe[11];
regVal = regVal << 8 | avi_iframe[10];
- HDMI_REG_W(io->base, HDMI_AVI_INFO2, regVal);
+ DSS_REG_W(io, HDMI_AVI_INFO2, regVal);
regVal = avi_iframe[1];
regVal = regVal << 16 | avi_iframe[15];
regVal = regVal << 8 | avi_iframe[14];
- HDMI_REG_W(io->base, HDMI_AVI_INFO3, regVal);
+ DSS_REG_W(io, HDMI_AVI_INFO3, regVal);
/* 0x3 for AVI InfFrame enable (every frame) */
- HDMI_REG_W(io->base, HDMI_INFOFRAME_CTRL0,
- HDMI_REG_R(io->base, HDMI_INFOFRAME_CTRL0) |
+ DSS_REG_W(io, HDMI_INFOFRAME_CTRL0,
+ DSS_REG_R(io, HDMI_INFOFRAME_CTRL0) |
0x00000003L);
} /* hdmi_tx_set_avi_infoframe */
@@ -986,14 +901,14 @@
* 0x19 Length of Source Product Description InfoFrame
*/
packet_header = 0x83 | (0x01 << 8) | (0x19 << 16);
- HDMI_REG_W(io->base, HDMI_GENERIC1_HDR, packet_header);
+ DSS_REG_W(io, HDMI_GENERIC1_HDR, packet_header);
check_sum += IFRAME_CHECKSUM_32(packet_header);
packet_payload = (vendor_name[3] & 0x7f)
| ((vendor_name[4] & 0x7f) << 8)
| ((vendor_name[5] & 0x7f) << 16)
| ((vendor_name[6] & 0x7f) << 24);
- HDMI_REG_W(io->base, HDMI_GENERIC1_1, packet_payload);
+ DSS_REG_W(io, HDMI_GENERIC1_1, packet_payload);
check_sum += IFRAME_CHECKSUM_32(packet_payload);
/* Product Description (7-bit ASCII code) */
@@ -1001,28 +916,28 @@
| ((product_description[0] & 0x7f) << 8)
| ((product_description[1] & 0x7f) << 16)
| ((product_description[2] & 0x7f) << 24);
- HDMI_REG_W(io->base, HDMI_GENERIC1_2, packet_payload);
+ DSS_REG_W(io, HDMI_GENERIC1_2, packet_payload);
check_sum += IFRAME_CHECKSUM_32(packet_payload);
packet_payload = (product_description[3] & 0x7f)
| ((product_description[4] & 0x7f) << 8)
| ((product_description[5] & 0x7f) << 16)
| ((product_description[6] & 0x7f) << 24);
- HDMI_REG_W(io->base, HDMI_GENERIC1_3, packet_payload);
+ DSS_REG_W(io, HDMI_GENERIC1_3, packet_payload);
check_sum += IFRAME_CHECKSUM_32(packet_payload);
packet_payload = (product_description[7] & 0x7f)
| ((product_description[8] & 0x7f) << 8)
| ((product_description[9] & 0x7f) << 16)
| ((product_description[10] & 0x7f) << 24);
- HDMI_REG_W(io->base, HDMI_GENERIC1_4, packet_payload);
+ DSS_REG_W(io, HDMI_GENERIC1_4, packet_payload);
check_sum += IFRAME_CHECKSUM_32(packet_payload);
packet_payload = (product_description[11] & 0x7f)
| ((product_description[12] & 0x7f) << 8)
| ((product_description[13] & 0x7f) << 16)
| ((product_description[14] & 0x7f) << 24);
- HDMI_REG_W(io->base, HDMI_GENERIC1_5, packet_payload);
+ DSS_REG_W(io, HDMI_GENERIC1_5, packet_payload);
check_sum += IFRAME_CHECKSUM_32(packet_payload);
/*
@@ -1039,7 +954,7 @@
* 09h PC general
*/
packet_payload = (product_description[15] & 0x7f) | 0x00 << 8;
- HDMI_REG_W(io->base, HDMI_GENERIC1_6, packet_payload);
+ DSS_REG_W(io, HDMI_GENERIC1_6, packet_payload);
check_sum += IFRAME_CHECKSUM_32(packet_payload);
/* Vendor Name (7bit ASCII code) */
@@ -1048,7 +963,7 @@
| ((vendor_name[2] & 0x7f) << 24);
check_sum += IFRAME_CHECKSUM_32(packet_payload);
packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff);
- HDMI_REG_W(io->base, HDMI_GENERIC1_0, packet_payload);
+ DSS_REG_W(io, HDMI_GENERIC1_0, packet_payload);
/*
* GENERIC1_LINE | GENERIC1_CONT | GENERIC1_SEND
@@ -1056,9 +971,9 @@
* Enable this packet to transmit every frame
* Enable HDMI TX engine to transmit Generic packet 1
*/
- packet_control = HDMI_REG_R_ND(io->base, HDMI_GEN_PKT_CTRL);
+ packet_control = DSS_REG_R_ND(io, HDMI_GEN_PKT_CTRL);
packet_control |= ((0x1 << 24) | (1 << 5) | (1 << 4));
- HDMI_REG_W(io->base, HDMI_GEN_PKT_CTRL, packet_control);
+ DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control);
} /* hdmi_tx_set_spd_infoframe */
/* todo: revisit when new HPD debouncing logic is avialble */
@@ -1075,11 +990,17 @@
static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
{
u32 reg_val = 0;
+ struct dss_io_data *io = NULL;
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
return;
}
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: Core io is not initialized\n", __func__);
+ return;
+ }
if (power_on) {
/* ENABLE */
@@ -1101,77 +1022,12 @@
reg_val = BIT(1);
}
- HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base, HDMI_CTRL,
- reg_val);
+ DSS_REG_W(io, HDMI_CTRL, reg_val);
DEV_DBG("HDMI Core: %s, HDMI_CTRL=0x%08x\n",
power_on ? "Enable" : "Disable", reg_val);
} /* hdmi_tx_set_mode */
-static int hdmi_tx_clk_update(struct hdmi_tx_platform_data *pdata, u32 clk_idx,
- u32 enable)
-{
- int rc = 0;
- struct clk *clk = hdmi_tx_get_clk(pdata, clk_idx);
-
- if (clk) {
- DEV_DBG("%s: clk=%d en=%d\n", __func__, clk_idx, enable);
- if (enable) {
- rc = clk_prepare_enable(clk);
- if (rc)
- DEV_ERR("%s: clk=%d enable failed\n",
- __func__, clk_idx);
- } else {
- clk_disable_unprepare(clk);
- }
- } else {
- DEV_ERR("%s: FAILED: invalid input for clk='%s'\n", __func__,
- hdmi_tx_clk_name(clk_idx));
- rc = -EINVAL;
- }
-
- return rc;
-} /* hdmi_tx_clk_update */
-
-/* Note: Before accessing extpclk, always make sure that hdmi_ahb_clk is on */
-static int hdmi_tx_clk_ctrl_update(struct hdmi_tx_platform_data *pdata, int on)
-{
- int rc = 0;
- DEV_DBG("%s: HDMI Clk: %s\n", __func__, on ? "Enable" : "Disable");
-
- rc = hdmi_tx_clk_update(pdata, HDMI_TX_APP_CLK, on);
- if (on && rc) {
- DEV_ERR("%s: '%s' on failed\n", __func__,
- hdmi_tx_clk_name(HDMI_TX_APP_CLK));
- goto fail_hdmi_app_clk;
- }
- if (on) {
- rc = hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, on);
- if (rc) {
- DEV_ERR("%s: '%s' on failed\n", __func__,
- hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
- goto fail_hdmi_ahb_clk;
- }
- rc = hdmi_tx_clk_update(pdata, HDMI_TX_EXTP_CLK, on);
- if (rc) {
- DEV_ERR("%s: '%s' on failed\n", __func__,
- hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
- goto fail_hdmi_extp_clk;
- }
- } else {
- hdmi_tx_clk_update(pdata, HDMI_TX_EXTP_CLK, on);
- hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, on);
- }
- return rc;
-
-fail_hdmi_extp_clk:
- hdmi_tx_clk_update(pdata, HDMI_TX_AHB_CLK, 0);
-fail_hdmi_ahb_clk:
- hdmi_tx_clk_update(pdata, HDMI_TX_APP_CLK, 0);
-fail_hdmi_app_clk:
- return rc;
-} /* hdmi_tx_clk_ctrl_update */
-
static int hdmi_tx_config_power(struct hdmi_tx_ctrl *hdmi_ctrl,
enum hdmi_tx_power_module_type module, int config)
{
@@ -1191,17 +1047,33 @@
goto exit;
}
- if (config)
+ if (config) {
rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
power_data->vreg_config, power_data->num_vreg, 1);
- else
+ if (rc) {
+ DEV_ERR("%s: Failed to config %s vreg. Err=%d\n",
+ __func__, hdmi_tx_pm_name(module), rc);
+ goto exit;
+ }
+
+ rc = msm_dss_get_clk(&hdmi_ctrl->pdev->dev,
+ power_data->clk_config, power_data->num_clk);
+ if (rc) {
+ DEV_ERR("%s: Failed to get %s clk. Err=%d\n",
+ __func__, hdmi_tx_pm_name(module), rc);
+
+ msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
+ power_data->vreg_config, power_data->num_vreg, 0);
+ }
+ } else {
+ msm_dss_put_clk(power_data->clk_config, power_data->num_clk);
+
rc = msm_dss_config_vreg(&hdmi_ctrl->pdev->dev,
power_data->vreg_config, power_data->num_vreg, 0);
-
- if (rc)
- DEV_ERR("%s: Failed to %s %s vreg. Error=%d\n",
- __func__, config ? "config" : "deconfig",
- hdmi_pm_name(module), rc);
+ if (rc)
+ DEV_ERR("%s: Fail to deconfig %s vreg. Err=%d\n",
+ __func__, hdmi_tx_pm_name(module), rc);
+ }
exit:
return rc;
@@ -1231,18 +1103,36 @@
power_data->num_vreg, 1);
if (rc) {
DEV_ERR("%s: Failed to enable %s vreg. Error=%d\n",
- __func__, hdmi_pm_name(module), rc);
+ __func__, hdmi_tx_pm_name(module), rc);
goto error;
}
rc = msm_dss_enable_gpio(power_data->gpio_config,
- power_data->num_gpio, enable);
+ power_data->num_gpio, 1);
if (rc) {
DEV_ERR("%s: Failed to enable %s gpio. Error=%d\n",
- __func__, hdmi_pm_name(module), rc);
+ __func__, hdmi_tx_pm_name(module), rc);
goto disable_vreg;
}
+
+ rc = msm_dss_clk_set_rate(power_data->clk_config,
+ power_data->num_clk);
+ if (rc) {
+ DEV_ERR("%s: failed to set clks rate for %s. err=%d\n",
+ __func__, hdmi_tx_pm_name(module), rc);
+ goto disable_gpio;
+ }
+
+ rc = msm_dss_enable_clk(power_data->clk_config,
+ power_data->num_clk, 1);
+ if (rc) {
+ DEV_ERR("%s: Failed to enable clks for %s. Error=%d\n",
+ __func__, hdmi_tx_pm_name(module), rc);
+ goto disable_gpio;
+ }
} else {
+ msm_dss_enable_clk(power_data->clk_config,
+ power_data->num_clk, 0);
msm_dss_enable_gpio(power_data->gpio_config,
power_data->num_gpio, 0);
msm_dss_enable_vreg(power_data->vreg_config,
@@ -1251,6 +1141,8 @@
return rc;
+disable_gpio:
+ msm_dss_enable_gpio(power_data->gpio_config, power_data->num_gpio, 0);
disable_vreg:
msm_dss_enable_vreg(power_data->vreg_config, power_data->num_vreg, 0);
error:
@@ -1281,7 +1173,7 @@
if (rc) {
DEV_ERR("%s: core hdmi_msm_enable_power failed rc = %d\n",
__func__, rc);
- goto error;
+ goto disable_hpd_power;
}
rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 1);
if (rc) {
@@ -1293,7 +1185,8 @@
return rc;
disable_core_power:
hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
-error:
+disable_hpd_power:
+ hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
return rc;
} /* hdmi_tx_core_on */
@@ -1311,36 +1204,34 @@
io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
if (!io->base) {
- DEV_ERR("%s: io not inititalized\n", __func__);
+ DEV_ERR("%s: core io not inititalized\n", __func__);
return;
}
- val = HDMI_REG_R_ND(io->base, HDMI_PHY_CTRL);
+ val = DSS_REG_R_ND(io, HDMI_PHY_CTRL);
phy_reset_polarity = val >> 3 & 0x1;
pll_reset_polarity = val >> 1 & 0x1;
if (phy_reset_polarity == 0)
- HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET);
+ DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET);
else
- HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val & (~SW_RESET));
+ DSS_REG_W_ND(io, HDMI_PHY_CTRL, val & (~SW_RESET));
if (pll_reset_polarity == 0)
- HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET_PLL);
+ DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET_PLL);
else
- HDMI_REG_W_ND(io->base,
- HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
+ DSS_REG_W_ND(io, HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
if (phy_reset_polarity == 0)
- HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val & (~SW_RESET));
+ DSS_REG_W_ND(io, HDMI_PHY_CTRL, val & (~SW_RESET));
else
- HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET);
+ DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET);
if (pll_reset_polarity == 0)
- HDMI_REG_W_ND(io->base,
- HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
+ DSS_REG_W_ND(io, HDMI_PHY_CTRL, val & (~SW_RESET_PLL));
else
- HDMI_REG_W_ND(io->base, HDMI_PHY_CTRL, val | SW_RESET_PLL);
+ DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET_PLL);
} /* hdmi_tx_phy_reset */
static void hdmi_tx_init_phy(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -1354,55 +1245,58 @@
io = &hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO];
if (!io->base) {
- DEV_ERR("%s: Core io is not initialized\n", __func__);
+ DEV_ERR("%s: phy io is not initialized\n", __func__);
return;
}
- HDMI_REG_W_ND(io->base, HDMI_PHY_ANA_CFG0, 0x1B);
- HDMI_REG_W_ND(io->base, HDMI_PHY_ANA_CFG1, 0xF2);
- HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_CFG0, 0x0);
- HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN0, 0x0);
- HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN1, 0x0);
- HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN2, 0x0);
- HDMI_REG_W_ND(io->base, HDMI_PHY_BIST_PATN3, 0x0);
+ DSS_REG_W_ND(io, HDMI_PHY_ANA_CFG0, 0x1B);
+ DSS_REG_W_ND(io, HDMI_PHY_ANA_CFG1, 0xF2);
+ DSS_REG_W_ND(io, HDMI_PHY_BIST_CFG0, 0x0);
+ DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN0, 0x0);
+ DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN1, 0x0);
+ DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN2, 0x0);
+ DSS_REG_W_ND(io, HDMI_PHY_BIST_PATN3, 0x0);
- HDMI_REG_W_ND(io->base, HDMI_PHY_PD_CTRL1, 0x20);
+ DSS_REG_W_ND(io, HDMI_PHY_PD_CTRL1, 0x20);
} /* hdmi_tx_init_phy */
static void hdmi_tx_powerdown_phy(struct hdmi_tx_ctrl *hdmi_ctrl)
{
+ struct dss_io_data *io = NULL;
+
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
return;
}
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO];
+ if (!io->base) {
+ DEV_ERR("%s: phy io is not initialized\n", __func__);
+ return;
+ }
- HDMI_REG_W_ND(hdmi_ctrl->pdata.io[HDMI_TX_PHY_IO].base,
- HDMI_PHY_PD_CTRL0, 0x7F);
+ DSS_REG_W_ND(io, HDMI_PHY_PD_CTRL0, 0x7F);
} /* hdmi_tx_powerdown_phy */
static int hdmi_tx_start(struct hdmi_tx_ctrl *hdmi_ctrl)
{
int rc = 0;
+ struct dss_io_data *io = NULL;
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: core io is not initialized\n", __func__);
+ return -EINVAL;
+ }
+
/* todo: Audio */
hdmi_tx_set_mode(hdmi_ctrl, false);
- mutex_lock(&hdmi_ctrl->mutex);
- rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 1);
- if (rc) {
- DEV_ERR("%s: hdmi_tx_clk_enable failed.\n", __func__);
- mutex_unlock(&hdmi_ctrl->mutex);
- return rc;
- }
- mutex_unlock(&hdmi_ctrl->mutex);
-
hdmi_tx_init_phy(hdmi_ctrl);
- HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
- HDMI_USEC_REFTIMER, 0x0001001B);
+ DSS_REG_W(io, HDMI_USEC_REFTIMER, 0x0001001B);
hdmi_tx_set_mode(hdmi_ctrl, true);
@@ -1413,8 +1307,7 @@
hdmi_tx_set_spd_infoframe(hdmi_ctrl);
/* Set IRQ for HPD */
- HDMI_REG_W(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
- HDMI_HPD_INT_CTRL, 4 | (hdmi_ctrl->hpd_state ? 0 : 2));
+ DSS_REG_W(io, HDMI_HPD_INT_CTRL, 4 | (hdmi_ctrl->hpd_state ? 0 : 2));
/* todo: HDCP/CEC */
@@ -1437,12 +1330,6 @@
/* todo: Audio */
hdmi_tx_powerdown_phy(hdmi_ctrl);
hdmi_ctrl->panel_power_on = false;
-
- mutex_lock(&hdmi_ctrl->mutex);
- if (hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 0))
- DEV_ERR("%s: hdmi_tx_clk_disable failed.\n", __func__);
- mutex_unlock(&hdmi_ctrl->mutex);
-
hdmi_tx_core_off(hdmi_ctrl);
return 0;
@@ -1451,6 +1338,7 @@
static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
{
int rc = 0;
+ struct dss_io_data *io = NULL;
struct hdmi_tx_ctrl *hdmi_ctrl =
hdmi_tx_get_drvdata_from_panel_data(panel_data);
@@ -1458,11 +1346,10 @@
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
-
- rc = hdmi_tx_core_on(hdmi_ctrl);
- if (rc) {
- DEV_ERR("%s: hdmi_msm_core_on failed\n", __func__);
- return rc;
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: core io is not initialized\n", __func__);
+ return -EINVAL;
}
DEV_INFO("power: ON (%dx%d %ld)\n", hdmi_ctrl->xres, hdmi_ctrl->yres,
@@ -1471,7 +1358,12 @@
rc = hdmi_tx_set_video_fmt(hdmi_ctrl);
if (rc) {
DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc);
- hdmi_tx_core_off(hdmi_ctrl);
+ return rc;
+ }
+
+ rc = hdmi_tx_core_on(hdmi_ctrl);
+ if (rc) {
+ DEV_ERR("%s: hdmi_msm_core_on failed\n", __func__);
return rc;
}
@@ -1494,8 +1386,7 @@
mutex_unlock(&hdmi_ctrl->mutex);
}
- hdmi_reg_dump(hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].base,
- hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].len, "HDMI-ON: ");
+ dss_reg_dump(io->base, io->len, "HDMI-ON: ", REG_DUMP);
DEV_INFO("%s: HDMI=%s DVI= %s\n", __func__,
hdmi_tx_is_controller_on(hdmi_ctrl) ? "ON" : "OFF" ,
@@ -1524,13 +1415,6 @@
hdmi_tx_set_mode(hdmi_ctrl, false);
- mutex_lock(&hdmi_ctrl->mutex);
- rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, 0);
- if (rc)
- DEV_INFO("%s: Failed to disable clock. Error=%d\n",
- __func__, rc);
- mutex_unlock(&hdmi_ctrl->mutex);
-
rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
if (rc)
DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
@@ -1552,7 +1436,7 @@
io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
if (!io->base) {
- DEV_ERR("%s: io not inititalized\n", __func__);
+ DEV_ERR("%s: core io not inititalized\n", __func__);
return -EINVAL;
}
@@ -1566,31 +1450,21 @@
return rc;
}
- mutex_lock(&hdmi_ctrl->mutex);
- rc = hdmi_tx_clk_ctrl_update(&hdmi_ctrl->pdata, true);
- if (rc) {
- DEV_ERR("%s: Failed to enable clocks. rc=%d\n",
- __func__, rc);
- mutex_unlock(&hdmi_ctrl->mutex);
- goto disable_hpd_power;
- }
- mutex_unlock(&hdmi_ctrl->mutex);
-
- hdmi_reg_dump(io->base, io->len, "HDMI-INIT: ");
+ dss_reg_dump(io->base, io->len, "HDMI-INIT: ", REG_DUMP);
hdmi_tx_set_mode(hdmi_ctrl, false);
hdmi_tx_phy_reset(hdmi_ctrl);
hdmi_tx_set_mode(hdmi_ctrl, true);
- HDMI_REG_W(io->base, HDMI_USEC_REFTIMER, 0x0001001B);
+ DSS_REG_W(io, HDMI_USEC_REFTIMER, 0x0001001B);
/* set timeout to 4.1ms (max) for hardware debounce */
- reg_val = HDMI_REG_R(io->base, HDMI_HPD_CTRL) | 0x1FFF;
+ reg_val = DSS_REG_R(io, HDMI_HPD_CTRL) | 0x1FFF;
/* Toggle HPD circuit to trigger HPD sense */
- HDMI_REG_W(io->base, HDMI_HPD_CTRL,
+ DSS_REG_W(io, HDMI_HPD_CTRL,
~(1 << 28) & reg_val);
- HDMI_REG_W(io->base, HDMI_HPD_CTRL, (1 << 28) | reg_val);
+ DSS_REG_W(io, HDMI_HPD_CTRL, (1 << 28) | reg_val);
hdmi_ctrl->hpd_initialized = true;
@@ -1607,11 +1481,6 @@
mutex_unlock(&hdmi_ctrl->mutex);
mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
- return 0;
-
-disable_hpd_power:
- hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, false);
-
return rc;
} /* hdmi_tx_hpd_on */
@@ -1629,7 +1498,6 @@
rc = hdmi_tx_hpd_on(hdmi_ctrl);
} else {
hdmi_tx_hpd_off(hdmi_ctrl);
- /* Set HDMI switch node to 0 on HPD feature disable */
switch_set_state(&hdmi_ctrl->sdev, 0);
DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
hdmi_ctrl->sdev.state);
@@ -1640,8 +1508,6 @@
static irqreturn_t hdmi_tx_isr(int irq, void *data)
{
- u32 hpd_int_status;
- u32 hpd_int_ctrl;
struct dss_io_data *io = NULL;
struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
@@ -1652,108 +1518,26 @@
io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
if (!io->base) {
- DEV_WARN("%s: io not initialized, ISR ignored\n", __func__);
+ DEV_WARN("%s: core io not initialized, ISR ignored\n",
+ __func__);
return IRQ_HANDLED;
}
- /* Process HPD Interrupt */
- hpd_int_status = HDMI_REG_R(io->base, HDMI_HPD_INT_STATUS);
- hpd_int_ctrl = HDMI_REG_R(io->base, HDMI_HPD_INT_CTRL);
- if ((hpd_int_ctrl & BIT(2)) && (hpd_int_status & BIT(0))) {
- u32 cable_detected = hpd_int_status & BIT(1);
-
+ if (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(0)) {
/*
- * Clear all interrupts, timer will turn IRQ back on
- * Leaving the bit[2] on, else core goes off
- * on getting HPD during power off.
+ * Turn off HPD irq and clear all interrupts,
+ * worker will turn IRQ back on
*/
- HDMI_REG_W(io->base, HDMI_HPD_INT_CTRL, BIT(2) | BIT(0));
-
- DEV_DBG("%s: HPD IRQ, Ctrl=%04x, State=%04x\n", __func__,
- hpd_int_ctrl, hpd_int_status);
-
- mutex_lock(&hdmi_ctrl->mutex);
- hdmi_ctrl->hpd_cable_chg_detected = true;
- hdmi_ctrl->hpd_prev_state = cable_detected ? 0 : 1;
- hdmi_ctrl->hpd_stable = 0;
- mutex_unlock(&hdmi_ctrl->mutex);
-
- mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
-
- return IRQ_HANDLED;
+ DSS_REG_W(io, HDMI_HPD_INT_CTRL, ~BIT(2) | BIT(0));
+ queue_work(hdmi_ctrl->workq, &hdmi_ctrl->hpd_int_work);
}
- if (!hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl))
- return IRQ_HANDLED;
-
- DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
- hpd_int_status);
+ if (hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl) < 0)
+ DEV_ERR("%s: hdmi_ddc_isr failed\n", __func__);
return IRQ_HANDLED;
} /* hdmi_tx_isr */
-static void hdmi_tx_clk_deinit(struct hdmi_tx_platform_data *pdata)
-{
- int i;
- if (!pdata) {
- DEV_ERR("%s: invalid input\n", __func__);
- return;
- }
-
- for (i = HDMI_TX_MAX_CLK - 1; i >= 0; i--) {
- if (pdata->clk[i])
- clk_put(pdata->clk[i]);
- pdata->clk[i] = NULL;
- }
-} /* hdmi_tx_clk_deinit */
-
-static int hdmi_tx_clk_init(struct platform_device *pdev,
- struct hdmi_tx_platform_data *pdata)
-{
- int rc = 0;
- struct device *dev = NULL;
- struct clk *clk = NULL;
-
- if (!pdev || !pdata) {
- DEV_ERR("%s: invalid input\n", __func__);
- return -EINVAL;
- }
- dev = &pdev->dev;
-
- clk = clk_get(dev, "iface_clk");
- rc = IS_ERR(clk);
- if (rc) {
- DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
- hdmi_tx_clk_name(HDMI_TX_AHB_CLK));
- goto error;
- }
- pdata->clk[HDMI_TX_AHB_CLK] = clk;
-
- clk = clk_get(dev, "core_clk");
- rc = IS_ERR(clk);
- if (rc) {
- DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
- hdmi_tx_clk_name(HDMI_TX_APP_CLK));
- goto error;
- }
- pdata->clk[HDMI_TX_APP_CLK] = clk;
-
- clk = clk_get(dev, "extp_clk");
- rc = IS_ERR(clk);
- if (rc) {
- DEV_ERR("%s: ERROR: '%s' clk not found\n", __func__,
- hdmi_tx_clk_name(HDMI_TX_EXTP_CLK));
- goto error;
- }
- pdata->clk[HDMI_TX_EXTP_CLK] = clk;
-
- return rc;
-
-error:
- hdmi_tx_clk_deinit(pdata);
- return rc;
-} /* hdmi_tx_clk_init */
-
static void hdmi_tx_dev_deinit(struct hdmi_tx_ctrl *hdmi_ctrl)
{
if (!hdmi_ctrl) {
@@ -1785,7 +1569,7 @@
pdata = &hdmi_ctrl->pdata;
- rc = hdmi_tx_check_capability(pdata->io[HDMI_TX_QFPROM_IO].base);
+ rc = hdmi_tx_check_capability(&pdata->io[HDMI_TX_QFPROM_IO]);
if (rc) {
DEV_ERR("%s: no HDMI device\n", __func__);
goto fail_no_hdmi;
@@ -1802,11 +1586,11 @@
goto fail_create_workq;
}
- /* todo: May be move this ? */
- hdmi_ctrl->ddc_ctrl.base = pdata->io[HDMI_TX_CORE_IO].base;
+ hdmi_ctrl->ddc_ctrl.io = &pdata->io[HDMI_TX_CORE_IO];
init_completion(&hdmi_ctrl->ddc_ctrl.ddc_sw_done);
INIT_WORK(&hdmi_ctrl->hpd_state_work, hdmi_tx_hpd_state_work);
+ INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
init_timer(&hdmi_ctrl->hpd_state_timer);
hdmi_ctrl->hpd_state_timer.function = hdmi_tx_hpd_state_timer;
hdmi_ctrl->hpd_state_timer.data = (u32)hdmi_ctrl;
@@ -1868,23 +1652,16 @@
return;
}
- /* CLK */
- hdmi_tx_clk_deinit(&hdmi_ctrl->pdata);
-
- /* VREG */
+ /* VREG & CLK */
for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--) {
if (hdmi_tx_config_power(hdmi_ctrl, i, 0))
DEV_ERR("%s: '%s' power deconfig fail\n",
- __func__, hdmi_pm_name(i));
+ __func__, hdmi_tx_pm_name(i));
}
/* IO */
- for (i = HDMI_TX_MAX_IO - 1; i >= 0; i--) {
- if (hdmi_ctrl->pdata.io[i].base)
- iounmap(hdmi_ctrl->pdata.io[i].base);
- hdmi_ctrl->pdata.io[i].base = NULL;
- hdmi_ctrl->pdata.io[i].len = 0;
- }
+ for (i = HDMI_TX_MAX_IO - 1; i >= 0; i--)
+ msm_dss_iounmap(&hdmi_ctrl->pdata.io[i]);
} /* hdmi_tx_deinit_resource */
static int hdmi_tx_init_resource(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -1913,23 +1690,16 @@
pdata->io[i].len);
}
- /* VREG */
+ /* VREG & CLK */
for (i = 0; i < HDMI_TX_MAX_PM; i++) {
rc = hdmi_tx_config_power(hdmi_ctrl, i, 1);
if (rc) {
DEV_ERR("%s: '%s' power config failed.rc=%d\n",
- __func__, hdmi_pm_name(i), rc);
+ __func__, hdmi_tx_pm_name(i), rc);
goto error;
}
}
- /* CLK */
- rc = hdmi_tx_clk_init(hdmi_ctrl->pdev, pdata);
- if (rc) {
- DEV_ERR("%s: FAILED: clk init. rc=%d\n", __func__, rc);
- goto error;
- }
-
return rc;
error:
@@ -1937,6 +1707,98 @@
return rc;
} /* hdmi_tx_init_resource */
+static void hdmi_tx_put_dt_clk_data(struct device *dev,
+ struct dss_module_power *module_power)
+{
+ if (!module_power) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (module_power->clk_config) {
+ devm_kfree(dev, module_power->clk_config);
+ module_power->clk_config = NULL;
+ }
+ module_power->num_clk = 0;
+} /* hdmi_tx_put_dt_clk_data */
+
+/* todo: once clk are moved to device tree then change this implementation */
+static int hdmi_tx_get_dt_clk_data(struct device *dev,
+ struct dss_module_power *mp, u32 module_type)
+{
+ int rc = 0;
+
+ if (!dev || !mp) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ DEV_DBG("%s: module: '%s'\n", __func__, hdmi_tx_pm_name(module_type));
+
+ switch (module_type) {
+ case HDMI_TX_HPD_PM:
+ mp->num_clk = 2;
+ mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
+ mp->num_clk, GFP_KERNEL);
+ if (!mp->clk_config) {
+ DEV_ERR("%s: can't alloc '%s' clk mem\n", __func__,
+ hdmi_tx_pm_name(module_type));
+ goto error;
+ }
+
+ snprintf(mp->clk_config[0].clk_name, 32, "%s", "iface_clk");
+ mp->clk_config[0].type = DSS_CLK_AHB;
+ mp->clk_config[0].rate = 0;
+
+ snprintf(mp->clk_config[1].clk_name, 32, "%s", "core_clk");
+ mp->clk_config[1].type = DSS_CLK_OTHER;
+ mp->clk_config[1].rate = 19200000;
+ break;
+
+ case HDMI_TX_CORE_PM:
+ mp->num_clk = 2;
+ mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
+ mp->num_clk, GFP_KERNEL);
+ if (!mp->clk_config) {
+ DEV_ERR("%s: can't alloc '%s' clk mem\n", __func__,
+ hdmi_tx_pm_name(module_type));
+ goto error;
+ }
+
+ snprintf(mp->clk_config[0].clk_name, 32, "%s", "extp_clk");
+ mp->clk_config[0].type = DSS_CLK_PCLK;
+ /* This rate will be overwritten when core is powered on */
+ mp->clk_config[0].rate = 148500000;
+
+ snprintf(mp->clk_config[1].clk_name, 32, "%s", "alt_iface_clk");
+ mp->clk_config[1].type = DSS_CLK_AHB;
+ mp->clk_config[1].rate = 0;
+ break;
+
+ case HDMI_TX_CEC_PM:
+ mp->num_clk = 0;
+ DEV_DBG("%s: no clk\n", __func__);
+ break;
+
+ default:
+ DEV_ERR("%s: invalid module type=%d\n", __func__,
+ module_type);
+ return -EINVAL;
+ }
+
+ return rc;
+
+error:
+ if (mp->clk_config) {
+ devm_kfree(dev, mp->clk_config);
+ mp->clk_config = NULL;
+ }
+ mp->num_clk = 0;
+
+ return rc;
+} /* hdmi_tx_get_dt_clk_data */
+
static void hdmi_tx_put_dt_vreg_data(struct device *dev,
struct dss_module_power *module_power)
{
@@ -1985,7 +1847,7 @@
return -EINVAL;
}
- DEV_DBG("%s: module: '%s'\n", __func__, hdmi_pm_name(module_type));
+ DEV_DBG("%s: module: '%s'\n", __func__, hdmi_tx_pm_name(module_type));
of_node = dev->of_node;
@@ -2025,7 +1887,7 @@
mod_vreg_total, GFP_KERNEL);
if (!mp->vreg_config) {
DEV_ERR("%s: can't alloc '%s' vreg mem\n", __func__,
- hdmi_pm_name(module_type));
+ hdmi_tx_pm_name(module_type));
goto error;
}
} else {
@@ -2070,7 +1932,7 @@
prop_name, val_array, dt_vreg_total);
if (rc) {
DEV_ERR("%s: error read '%s' vreg type. rc=%d\n",
- __func__, hdmi_pm_name(module_type), rc);
+ __func__, hdmi_tx_pm_name(module_type), rc);
goto error;
}
mp->vreg_config[j].type = val_array[i];
@@ -2085,7 +1947,7 @@
dt_vreg_total);
if (rc) {
DEV_ERR("%s: error read '%s' min volt. rc=%d\n",
- __func__, hdmi_pm_name(module_type), rc);
+ __func__, hdmi_tx_pm_name(module_type), rc);
goto error;
}
mp->vreg_config[j].min_voltage = val_array[i];
@@ -2100,7 +1962,7 @@
dt_vreg_total);
if (rc) {
DEV_ERR("%s: error read '%s' max volt. rc=%d\n",
- __func__, hdmi_pm_name(module_type), rc);
+ __func__, hdmi_tx_pm_name(module_type), rc);
goto error;
}
mp->vreg_config[j].max_voltage = val_array[i];
@@ -2115,7 +1977,7 @@
dt_vreg_total);
if (rc) {
DEV_ERR("%s: error read '%s' min volt. rc=%d\n",
- __func__, hdmi_pm_name(module_type), rc);
+ __func__, hdmi_tx_pm_name(module_type), rc);
goto error;
}
mp->vreg_config[j].optimum_voltage = val_array[i];
@@ -2136,8 +1998,12 @@
return rc;
error:
- for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
- hdmi_tx_put_dt_vreg_data(dev, mp);
+ if (mp->vreg_config) {
+ devm_kfree(dev, mp->vreg_config);
+ mp->vreg_config = NULL;
+ }
+ mp->num_vreg = 0;
+
if (val_array)
devm_kfree(dev, val_array);
return rc;
@@ -2191,7 +2057,7 @@
return -EINVAL;
}
- DEV_DBG("%s: module: '%s'\n", __func__, hdmi_pm_name(module_type));
+ DEV_DBG("%s: module: '%s'\n", __func__, hdmi_tx_pm_name(module_type));
of_node = dev->of_node;
@@ -2227,7 +2093,7 @@
mod_gpio_total, GFP_KERNEL);
if (!mp->gpio_config) {
DEV_ERR("%s: can't alloc '%s' gpio mem\n", __func__,
- hdmi_pm_name(module_type));
+ hdmi_tx_pm_name(module_type));
goto error;
}
} else {
@@ -2268,8 +2134,11 @@
return rc;
error:
- for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
- hdmi_tx_put_dt_gpio_data(dev, mp);
+ if (mp->gpio_config) {
+ devm_kfree(dev, mp->gpio_config);
+ mp->gpio_config = NULL;
+ }
+ mp->num_gpio = 0;
return rc;
} /* hdmi_tx_get_dt_gpio_data */
@@ -2284,6 +2153,9 @@
}
for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
+ hdmi_tx_put_dt_clk_data(dev, &pdata->power_data[i]);
+
+ for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
hdmi_tx_put_dt_vreg_data(dev, &pdata->power_data[i]);
for (i = HDMI_TX_MAX_PM - 1; i >= 0; i--)
@@ -2317,7 +2189,7 @@
&pdata->power_data[i], i);
if (rc) {
DEV_ERR("%s: '%s' get_dt_gpio_data failed.rc=%d\n",
- __func__, hdmi_pm_name(i), rc);
+ __func__, hdmi_tx_pm_name(i), rc);
goto error;
}
}
@@ -2328,7 +2200,18 @@
&pdata->power_data[i], i);
if (rc) {
DEV_ERR("%s: '%s' get_dt_vreg_data failed.rc=%d\n",
- __func__, hdmi_pm_name(i), rc);
+ __func__, hdmi_tx_pm_name(i), rc);
+ goto error;
+ }
+ }
+
+ /* CLK */
+ for (i = 0; i < HDMI_TX_MAX_PM; i++) {
+ rc = hdmi_tx_get_dt_clk_data(&pdev->dev,
+ &pdata->power_data[i], i);
+ if (rc) {
+ DEV_ERR("%s: '%s' get_dt_clk_data failed.rc=%d\n",
+ __func__, hdmi_tx_pm_name(i), rc);
goto error;
}
}
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 7e37d28..94e0fda 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -15,14 +15,6 @@
#include <linux/switch.h>
#include "mdss_hdmi_util.h"
-#include "mdss_io_util.h"
-
-enum hdmi_tx_clk_type {
- HDMI_TX_AHB_CLK,
- HDMI_TX_APP_CLK,
- HDMI_TX_EXTP_CLK,
- HDMI_TX_MAX_CLK
-};
enum hdmi_tx_io_type {
HDMI_TX_CORE_IO,
@@ -42,9 +34,6 @@
/* Data filled from device tree nodes */
struct dss_io_data io[HDMI_TX_MAX_IO];
struct dss_module_power power_data[HDMI_TX_MAX_PM];
-
- /* clk and regulator handles */
- struct clk *clk[HDMI_TX_MAX_CLK];
};
struct hdmi_tx_ctrl {
@@ -67,6 +56,7 @@
u32 hpd_state;
u32 hpd_feature_on;
struct work_struct hpd_state_work;
+ struct work_struct hpd_int_work;
struct timer_list hpd_state_timer;
unsigned long pixel_clk;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.c b/drivers/video/msm/mdss/mdss_hdmi_util.c
index 3ba9f89..e7ea8c9 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.c
@@ -15,226 +15,6 @@
#include <mach/board.h>
#include "mdss_hdmi_util.h"
-const char *hdmi_reg_name(u32 offset)
-{
- switch (offset) {
- case 0x00000000: return "HDMI_CTRL";
- case 0x00000010: return "HDMI_TEST_PATTERN";
- case 0x00000014: return "HDMI_RANDOM_PATTERN";
- case 0x00000018: return "HDMI_PKT_BLK_CTRL";
- case 0x0000001C: return "HDMI_STATUS";
- case 0x00000020: return "HDMI_AUDIO_PKT_CTRL";
- case 0x00000024: return "HDMI_ACR_PKT_CTRL";
- case 0x00000028: return "HDMI_VBI_PKT_CTRL";
- case 0x0000002C: return "HDMI_INFOFRAME_CTRL0";
- case 0x00000030: return "HDMI_INFOFRAME_CTRL1";
- case 0x00000034: return "HDMI_GEN_PKT_CTRL";
- case 0x0000003C: return "HDMI_ACP";
- case 0x00000040: return "HDMI_GC";
- case 0x00000044: return "HDMI_AUDIO_PKT_CTRL2";
- case 0x00000048: return "HDMI_ISRC1_0";
- case 0x0000004C: return "HDMI_ISRC1_1";
- case 0x00000050: return "HDMI_ISRC1_2";
- case 0x00000054: return "HDMI_ISRC1_3";
- case 0x00000058: return "HDMI_ISRC1_4";
- case 0x0000005C: return "HDMI_ISRC2_0";
- case 0x00000060: return "HDMI_ISRC2_1";
- case 0x00000064: return "HDMI_ISRC2_2";
- case 0x00000068: return "HDMI_ISRC2_3";
- case 0x0000006C: return "HDMI_AVI_INFO0";
- case 0x00000070: return "HDMI_AVI_INFO1";
- case 0x00000074: return "HDMI_AVI_INFO2";
- case 0x00000078: return "HDMI_AVI_INFO3";
- case 0x0000007C: return "HDMI_MPEG_INFO0";
- case 0x00000080: return "HDMI_MPEG_INFO1";
- case 0x00000084: return "HDMI_GENERIC0_HDR";
- case 0x00000088: return "HDMI_GENERIC0_0";
- case 0x0000008C: return "HDMI_GENERIC0_1";
- case 0x00000090: return "HDMI_GENERIC0_2";
- case 0x00000094: return "HDMI_GENERIC0_3";
- case 0x00000098: return "HDMI_GENERIC0_4";
- case 0x0000009C: return "HDMI_GENERIC0_5";
- case 0x000000A0: return "HDMI_GENERIC0_6";
- case 0x000000A4: return "HDMI_GENERIC1_HDR";
- case 0x000000A8: return "HDMI_GENERIC1_0";
- case 0x000000AC: return "HDMI_GENERIC1_1";
- case 0x000000B0: return "HDMI_GENERIC1_2";
- case 0x000000B4: return "HDMI_GENERIC1_3";
- case 0x000000B8: return "HDMI_GENERIC1_4";
- case 0x000000BC: return "HDMI_GENERIC1_5";
- case 0x000000C0: return "HDMI_GENERIC1_6";
- case 0x000000C4: return "HDMI_ACR_32_0";
- case 0x000000C8: return "HDMI_ACR_32_1";
- case 0x000000CC: return "HDMI_ACR_44_0";
- case 0x000000D0: return "HDMI_ACR_44_1";
- case 0x000000D4: return "HDMI_ACR_48_0";
- case 0x000000D8: return "HDMI_ACR_48_1";
- case 0x000000DC: return "HDMI_ACR_STATUS_0";
- case 0x000000E0: return "HDMI_ACR_STATUS_1";
- case 0x000000E4: return "HDMI_AUDIO_INFO0";
- case 0x000000E8: return "HDMI_AUDIO_INFO1";
- case 0x000000EC: return "HDMI_CS_60958_0";
- case 0x000000F0: return "HDMI_CS_60958_1";
- case 0x000000F8: return "HDMI_RAMP_CTRL0";
- case 0x000000FC: return "HDMI_RAMP_CTRL1";
- case 0x00000100: return "HDMI_RAMP_CTRL2";
- case 0x00000104: return "HDMI_RAMP_CTRL3";
- case 0x00000108: return "HDMI_CS_60958_2";
- case 0x00000110: return "HDMI_HDCP_CTRL";
- case 0x00000114: return "HDMI_HDCP_DEBUG_CTRL";
- case 0x00000118: return "HDMI_HDCP_INT_CTRL";
- case 0x0000011C: return "HDMI_HDCP_LINK0_STATUS";
- case 0x00000120: return "HDMI_HDCP_DDC_CTRL_0";
- case 0x00000124: return "HDMI_HDCP_DDC_CTRL_1";
- case 0x00000128: return "HDMI_HDCP_DDC_STATUS";
- case 0x0000012C: return "HDMI_HDCP_ENTROPY_CTRL0";
- case 0x00000130: return "HDMI_HDCP_RESET";
- case 0x00000134: return "HDMI_HDCP_RCVPORT_DATA0";
- case 0x00000138: return "HDMI_HDCP_RCVPORT_DATA1";
- case 0x0000013C: return "HDMI_HDCP_RCVPORT_DATA2_0";
- case 0x00000140: return "HDMI_HDCP_RCVPORT_DATA2_1";
- case 0x00000144: return "HDMI_HDCP_RCVPORT_DATA3";
- case 0x00000148: return "HDMI_HDCP_RCVPORT_DATA4";
- case 0x0000014C: return "HDMI_HDCP_RCVPORT_DATA5";
- case 0x00000150: return "HDMI_HDCP_RCVPORT_DATA6";
- case 0x00000154: return "HDMI_HDCP_RCVPORT_DATA7";
- case 0x00000158: return "HDMI_HDCP_RCVPORT_DATA8";
- case 0x0000015C: return "HDMI_HDCP_RCVPORT_DATA9";
- case 0x00000160: return "HDMI_HDCP_RCVPORT_DATA10";
- case 0x00000164: return "HDMI_HDCP_RCVPORT_DATA11";
- case 0x00000168: return "HDMI_HDCP_RCVPORT_DATA12";
- case 0x0000016C: return "HDMI_VENSPEC_INFO0";
- case 0x00000170: return "HDMI_VENSPEC_INFO1";
- case 0x00000174: return "HDMI_VENSPEC_INFO2";
- case 0x00000178: return "HDMI_VENSPEC_INFO3";
- case 0x0000017C: return "HDMI_VENSPEC_INFO4";
- case 0x00000180: return "HDMI_VENSPEC_INFO5";
- case 0x00000184: return "HDMI_VENSPEC_INFO6";
- case 0x00000194: return "HDMI_HDCP_DEBUG";
- case 0x0000019C: return "HDMI_TMDS_CTRL_CHAR";
- case 0x000001A4: return "HDMI_TMDS_CTRL_SEL";
- case 0x000001A8: return "HDMI_TMDS_SYNCCHAR01";
- case 0x000001AC: return "HDMI_TMDS_SYNCCHAR23";
- case 0x000001B4: return "HDMI_TMDS_DEBUG";
- case 0x000001B8: return "HDMI_TMDS_CTL_BITS";
- case 0x000001BC: return "HDMI_TMDS_DCBAL_CTRL";
- case 0x000001C0: return "HDMI_TMDS_DCBAL_CHAR";
- case 0x000001C8: return "HDMI_TMDS_CTL01_GEN";
- case 0x000001CC: return "HDMI_TMDS_CTL23_GEN";
- case 0x000001D0: return "HDMI_AUDIO_CFG";
- case 0x00000204: return "HDMI_DEBUG";
- case 0x00000208: return "HDMI_USEC_REFTIMER";
- case 0x0000020C: return "HDMI_DDC_CTRL";
- case 0x00000210: return "HDMI_DDC_ARBITRATION";
- case 0x00000214: return "HDMI_DDC_INT_CTRL";
- case 0x00000218: return "HDMI_DDC_SW_STATUS";
- case 0x0000021C: return "HDMI_DDC_HW_STATUS";
- case 0x00000220: return "HDMI_DDC_SPEED";
- case 0x00000224: return "HDMI_DDC_SETUP";
- case 0x00000228: return "HDMI_DDC_TRANS0";
- case 0x0000022C: return "HDMI_DDC_TRANS1";
- case 0x00000230: return "HDMI_DDC_TRANS2";
- case 0x00000234: return "HDMI_DDC_TRANS3";
- case 0x00000238: return "HDMI_DDC_DATA";
- case 0x0000023C: return "HDMI_HDCP_SHA_CTRL";
- case 0x00000240: return "HDMI_HDCP_SHA_STATUS";
- case 0x00000244: return "HDMI_HDCP_SHA_DATA";
- case 0x00000248: return "HDMI_HDCP_SHA_DBG_M0_0";
- case 0x0000024C: return "HDMI_HDCP_SHA_DBG_M0_1";
- case 0x00000250: return "HDMI_HPD_INT_STATUS";
- case 0x00000254: return "HDMI_HPD_INT_CTRL";
- case 0x00000258: return "HDMI_HPD_CTRL";
- case 0x0000025C: return "HDMI_HDCP_ENTROPY_CTRL1";
- case 0x00000260: return "HDMI_HDCP_SW_UPPER_AN";
- case 0x00000264: return "HDMI_HDCP_SW_LOWER_AN";
- case 0x00000268: return "HDMI_CRC_CTRL";
- case 0x0000026C: return "HDMI_VID_CRC";
- case 0x00000270: return "HDMI_AUD_CRC";
- case 0x00000274: return "HDMI_VBI_CRC";
- case 0x0000027C: return "HDMI_DDC_REF";
- case 0x00000284: return "HDMI_HDCP_SW_UPPER_AKSV";
- case 0x00000288: return "HDMI_HDCP_SW_LOWER_AKSV";
- case 0x0000028C: return "HDMI_CEC_CTRL";
- case 0x00000290: return "HDMI_CEC_WR_DATA";
- case 0x00000294: return "HDMI_CEC_RETRANSMIT";
- case 0x00000298: return "HDMI_CEC_STATUS";
- case 0x0000029C: return "HDMI_CEC_INT";
- case 0x000002A0: return "HDMI_CEC_ADDR";
- case 0x000002A4: return "HDMI_CEC_TIME";
- case 0x000002A8: return "HDMI_CEC_REFTIMER";
- case 0x000002AC: return "HDMI_CEC_RD_DATA";
- case 0x000002B0: return "HDMI_CEC_RD_FILTER";
- case 0x000002B4: return "HDMI_ACTIVE_H";
- case 0x000002B8: return "HDMI_ACTIVE_V";
- case 0x000002BC: return "HDMI_ACTIVE_V_F2";
- case 0x000002C0: return "HDMI_TOTAL";
- case 0x000002C4: return "HDMI_V_TOTAL_F2";
- case 0x000002C8: return "HDMI_FRAME_CTRL";
- case 0x000002CC: return "HDMI_AUD_INT";
- case 0x000002D0: return "HDMI_DEBUG_BUS_CTRL";
- case 0x000002D4: return "HDMI_PHY_CTRL";
- case 0x000002DC: return "HDMI_CEC_WR_RANGE";
- case 0x000002E0: return "HDMI_CEC_RD_RANGE";
- case 0x000002E4: return "HDMI_VERSION";
- case 0x000002F4: return "HDMI_BIST_ENABLE";
- case 0x000002F8: return "HDMI_TIMING_ENGINE_EN";
- case 0x000002FC: return "HDMI_INTF_CONFIG";
- case 0x00000300: return "HDMI_HSYNC_CTL";
- case 0x00000304: return "HDMI_VSYNC_PERIOD_F0";
- case 0x00000308: return "HDMI_VSYNC_PERIOD_F1";
- case 0x0000030C: return "HDMI_VSYNC_PULSE_WIDTH_F0";
- case 0x00000310: return "HDMI_VSYNC_PULSE_WIDTH_F1";
- case 0x00000314: return "HDMI_DISPLAY_V_START_F0";
- case 0x00000318: return "HDMI_DISPLAY_V_START_F1";
- case 0x0000031C: return "HDMI_DISPLAY_V_END_F0";
- case 0x00000320: return "HDMI_DISPLAY_V_END_F1";
- case 0x00000324: return "HDMI_ACTIVE_V_START_F0";
- case 0x00000328: return "HDMI_ACTIVE_V_START_F1";
- case 0x0000032C: return "HDMI_ACTIVE_V_END_F0";
- case 0x00000330: return "HDMI_ACTIVE_V_END_F1";
- case 0x00000334: return "HDMI_DISPLAY_HCTL";
- case 0x00000338: return "HDMI_ACTIVE_HCTL";
- case 0x0000033C: return "HDMI_HSYNC_SKEW";
- case 0x00000340: return "HDMI_POLARITY_CTL";
- case 0x00000344: return "HDMI_TPG_MAIN_CONTROL";
- case 0x00000348: return "HDMI_TPG_VIDEO_CONFIG";
- case 0x0000034C: return "HDMI_TPG_COMPONENT_LIMITS";
- case 0x00000350: return "HDMI_TPG_RECTANGLE";
- case 0x00000354: return "HDMI_TPG_INITIAL_VALUE";
- case 0x00000358: return "HDMI_TPG_BLK_WHT_PATTERN_FRAMES";
- case 0x0000035C: return "HDMI_TPG_RGB_MAPPING";
- default: return "???";
- }
-} /* hdmi_reg_name */
-
-void hdmi_reg_w(void __iomem *addr, u32 offset, u32 value, u32 debug)
-{
- u32 in_val;
-
- writel_relaxed(value, addr+offset);
- if (debug && PORT_DEBUG) {
- in_val = readl_relaxed(addr+offset);
- DEV_DBG("HDMI[%04x] => %08x [%08x] %s\n", offset, value,
- in_val, hdmi_reg_name(offset));
- }
-} /* hdmi_reg_w */
-
-u32 hdmi_reg_r(void __iomem *addr, u32 offset, u32 debug)
-{
- u32 value = readl_relaxed(addr+offset);
- if (debug && PORT_DEBUG)
- DEV_DBG("HDMI[%04x] <= %08x %s\n", offset, value,
- hdmi_reg_name(offset));
- return value;
-} /* hdmi_reg_r */
-
-void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix)
-{
- if (REG_DUMP)
- print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4,
- (void *)base, length, false);
-} /* hdmi_reg_dump */
-
static struct hdmi_disp_mode_timing_type
hdmi_supported_video_mode_lut[HDMI_VFRMT_MAX] = {
HDMI_SETTINGS_640x480p60_4_3,
@@ -505,7 +285,7 @@
{
u32 reg_val, time_out_count;
- if (!ddc_ctrl || !ddc_ctrl->base) {
+ if (!ddc_ctrl || !ddc_ctrl->io) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
@@ -515,9 +295,9 @@
do {
--time_out_count;
/* Clear and Enable DDC interrupt */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL,
BIT(2) | BIT(1));
- reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+ reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
} while ((reg_val & BIT(0)) && time_out_count);
if (!time_out_count) {
@@ -535,7 +315,7 @@
int status = 0;
int log_retry_fail;
- if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+ if (!ddc_ctrl || !ddc_ctrl->io || !ddc_data) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
@@ -565,7 +345,7 @@
* INDEX = 0x0 (initial offset into buffer)
* INDEX_WRITE = 0x1 (setting initial offset)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
BIT(31) | (ddc_data->dev_addr << 8));
/*
@@ -576,7 +356,7 @@
* INDEX = 0x0
* INDEX_WRITE = 0x0 (auto-increment by hardware)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->offset << 8);
/*
* 3. Write to HDMI_I2C_DATA with the following fields set in order to
@@ -586,7 +366,7 @@
* INDEX = 0x0
* INDEX_WRITE = 0x0 (auto-increment by hardware)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
(ddc_data->dev_addr | BIT(0)) << 8);
/* Data setup is complete, now setup the transaction characteristics */
@@ -599,7 +379,7 @@
* STOP0 = 0x0 (do NOT insert STOP bit)
* CNT0 = 0x1 (single byte transaction excluding address)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
/*
* 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
@@ -609,7 +389,7 @@
* STOP1 = 0x1 (insert STOP bit)
* CNT1 = data_len (it's 128 (0x80) for a blk read)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS1,
BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16));
/* Trigger the I2C transfer */
@@ -624,11 +404,11 @@
* GO = 0x1 (kicks off hardware)
*/
INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(20));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(20));
time_out_count = wait_for_completion_interruptible_timeout(
&ddc_ctrl->ddc_sw_done, HZ/2);
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, BIT(1));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, BIT(1));
if (!time_out_count) {
if (ddc_data->retry-- > 0) {
DEV_INFO("%s: failed timout, retry=%d\n", __func__,
@@ -637,26 +417,26 @@
}
status = -ETIMEDOUT;
DEV_ERR("%s: timedout(7), Int Ctrl=%08x\n", __func__,
- HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+ DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL));
DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
__func__,
- HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
- HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+ DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS),
+ DSS_REG_R(ddc_ctrl->io, HDMI_DDC_HW_STATUS));
goto error;
}
/* Read DDC status */
- reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+ reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS);
reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
/* Check if any NACK occurred */
if (reg_val) {
/* SW_STATUS_RESET */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(3));
if (ddc_data->retry == 1)
/* SOFT_RESET */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(1));
if (ddc_data->retry-- > 0) {
DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d\n",
@@ -687,13 +467,13 @@
* INDEX_WRITE = 0x1 (explicitly define offset)
*/
/* Write this data to DDC buffer */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
BIT(0) | (3 << 16) | BIT(31));
/* Discard first byte */
- HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+ DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_DATA);
for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
- reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+ reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_DATA);
ddc_data->data_buf[ndx] = (u8)((reg_val & 0x0000FF00) >> 8);
}
@@ -705,46 +485,44 @@
void hdmi_ddc_config(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
{
- if (!ddc_ctrl || !ddc_ctrl->base) {
+ if (!ddc_ctrl || !ddc_ctrl->io) {
DEV_ERR("%s: invalid input\n", __func__);
return;
}
/* Configure Pre-Scale multiplier & Threshold */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_SPEED, (10 << 16) | (2 << 0));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_SPEED, (10 << 16) | (2 << 0));
/*
* Setting 31:24 bits : Time units to wait before timeout
* when clock is being stalled by external sink device
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_SETUP, 0xFF000000);
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_SETUP, 0xFF000000);
/* Enable reference timer to 27 micro-seconds */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_REF, (1 << 16) | (27 << 0));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_REF, (1 << 16) | (27 << 0));
} /* hdmi_ddc_config */
int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
{
- int rc = -1;
u32 ddc_int_ctrl;
- if (!ddc_ctrl || !ddc_ctrl->base) {
+ if (!ddc_ctrl || !ddc_ctrl->io) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
- ddc_int_ctrl = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
+ ddc_int_ctrl = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
if ((ddc_int_ctrl & BIT(2)) && (ddc_int_ctrl & BIT(0))) {
/* SW_DONE INT occured, clr it */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL,
ddc_int_ctrl | BIT(1));
complete(&ddc_ctrl->ddc_sw_done);
- return 0;
}
DEV_DBG("%s: ddc_int_ctrl=%04x\n", __func__, ddc_int_ctrl);
- return rc;
+ return 0;
} /* hdmi_ddc_isr */
int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
@@ -779,7 +557,7 @@
int log_retry_fail;
int seg_addr = 0x60, seg_num = 0x01;
- if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+ if (!ddc_ctrl || !ddc_ctrl->io || !ddc_data) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
@@ -808,7 +586,7 @@
* INDEX = 0x0 (initial offset into buffer)
* INDEX_WRITE = 0x1 (setting initial offset)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, BIT(31) | (seg_addr << 8));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, BIT(31) | (seg_addr << 8));
/*
* 2. Write to HDMI_I2C_DATA with the following fields set in order to
@@ -818,7 +596,7 @@
* INDEX = 0x0
* INDEX_WRITE = 0x0 (auto-increment by hardware)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, seg_num << 8);
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, seg_num << 8);
/*
* 3. Write to HDMI_I2C_DATA with the following fields set in order to
@@ -828,9 +606,9 @@
* INDEX = 0x0
* INDEX_WRITE = 0x0 (auto-increment by hardware)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->dev_addr << 8);
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->dev_addr << 8);
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->offset << 8);
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
(ddc_data->dev_addr | BIT(0)) << 8);
/* Data setup is complete, now setup the transaction characteristics */
@@ -843,7 +621,7 @@
* STOP0 = 0x0 (do NOT insert STOP bit)
* CNT0 = 0x1 (single byte transaction excluding address)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
/*
* 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
@@ -853,7 +631,7 @@
* STOP1 = 0x1 (insert STOP bit)
* CNT1 = data_len (it's 128 (0x80) for a blk read)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1, BIT(12) | BIT(16));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS1, BIT(12) | BIT(16));
/*
* 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
@@ -863,7 +641,7 @@
* STOP1 = 0x1 (insert STOP bit)
* CNT1 = data_len (it's 128 (0x80) for a blk read)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS2,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS2,
BIT(0) | BIT(12) | BIT(13) | (ddc_data->request_len << 16));
/* Trigger the I2C transfer */
@@ -877,13 +655,13 @@
* GO = 0x1 (kicks off hardware)
*/
INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(21));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(21));
time_out_count = wait_for_completion_interruptible_timeout(
&ddc_ctrl->ddc_sw_done, HZ/2);
- reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
+ reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
if (!time_out_count) {
if (ddc_data->retry-- > 0) {
DEV_INFO("%s: failed timout, retry=%d\n", __func__,
@@ -892,25 +670,25 @@
}
status = -ETIMEDOUT;
DEV_ERR("%s: timedout(7), Int Ctrl=%08x\n", __func__,
- HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+ DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL));
DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
__func__,
- HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
- HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+ DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS),
+ DSS_REG_R(ddc_ctrl->io, HDMI_DDC_HW_STATUS));
goto error;
}
/* Read DDC status */
- reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+ reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS);
reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
/* Check if any NACK occurred */
if (reg_val) {
/* SW_STATUS_RESET */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(3));
if (ddc_data->retry == 1)
/* SOFT_RESET */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(1));
if (ddc_data->retry-- > 0) {
DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d\n",
__func__, ddc_data->what, reg_val,
@@ -940,14 +718,14 @@
* INDEX_WRITE = 0x1 (explicitly define offset)
*/
/* Write this data to DDC buffer */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
BIT(0) | (5 << 16) | BIT(31));
/* Discard first byte */
- HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+ DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_DATA);
for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
- reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_DATA);
+ reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_DATA);
ddc_data->data_buf[ndx] = (u8) ((reg_val & 0x0000FF00) >> 8);
}
@@ -964,7 +742,7 @@
int status = 0, retry = 10;
u32 time_out_count;
- if (!ddc_ctrl || !ddc_ctrl->base || !ddc_data) {
+ if (!ddc_ctrl || !ddc_ctrl->io || !ddc_data) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
@@ -991,7 +769,7 @@
* INDEX = 0x0 (initial offset into buffer)
* INDEX_WRITE = 0x1 (setting initial offset)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
BIT(31) | (ddc_data->dev_addr << 8));
/*
@@ -1002,7 +780,7 @@
* INDEX = 0x0
* INDEX_WRITE = 0x0 (auto-increment by hardware)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA, ddc_data->offset << 8);
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA, ddc_data->offset << 8);
/*
* 3. Write to HDMI_I2C_DATA with the following fields set in order to
@@ -1013,7 +791,7 @@
* INDEX_WRITE = 0x0 (auto-increment by hardware)
*/
for (ndx = 0; ndx < ddc_data->data_len; ++ndx)
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_DATA,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_DATA,
((u32)ddc_data->data_buf[ndx]) << 8);
/* Data setup is complete, now setup the transaction characteristics */
@@ -1026,7 +804,7 @@
* STOP0 = 0x0 (do NOT insert STOP bit)
* CNT0 = 0x1 (single byte transaction excluding address)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS0, BIT(12) | BIT(16));
/*
* 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in
@@ -1038,7 +816,7 @@
* Byte count for second transition (excluding the first
* Byte which is usually the address)
*/
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_TRANS1,
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_TRANS1,
BIT(13) | ((ddc_data->data_len-1) << 16));
/* Trigger the I2C transfer */
@@ -1051,13 +829,13 @@
* GO = 0x1 (kicks off hardware)
*/
INIT_COMPLETION(ddc_ctrl->ddc_sw_done);
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(0) | BIT(20));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(0) | BIT(20));
time_out_count = wait_for_completion_interruptible_timeout(
&ddc_ctrl->ddc_sw_done, HZ/2);
- reg_val = HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL);
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
+ reg_val = DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL);
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL, reg_val & (~BIT(2)));
if (!time_out_count) {
if (retry-- > 0) {
DEV_INFO("%s[%s]: failed timout, retry=%d\n", __func__,
@@ -1067,26 +845,26 @@
status = -ETIMEDOUT;
DEV_ERR("%s[%s]: timedout, Int Ctrl=%08x\n",
__func__, ddc_data->what,
- HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_INT_CTRL));
+ DSS_REG_R(ddc_ctrl->io, HDMI_DDC_INT_CTRL));
DEV_ERR("%s: DDC SW Status=%08x, HW Status=%08x\n",
__func__,
- HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_SW_STATUS),
- HDMI_REG_R(ddc_ctrl->base, HDMI_DDC_HW_STATUS));
+ DSS_REG_R(ddc_ctrl->io, HDMI_DDC_SW_STATUS),
+ DSS_REG_R(ddc_ctrl->io, HDMI_DDC_HW_STATUS));
goto error;
}
/* Read DDC status */
- reg_val = HDMI_REG_R_ND(ddc_ctrl->base, HDMI_DDC_SW_STATUS);
+ reg_val = DSS_REG_R_ND(ddc_ctrl->io, HDMI_DDC_SW_STATUS);
reg_val &= 0x00001000 | 0x00002000 | 0x00004000 | 0x00008000;
/* Check if any NACK occurred */
if (reg_val) {
if (retry > 1)
/* SW_STATUS_RESET */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(3));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(3));
else
/* SOFT_RESET */
- HDMI_REG_W_ND(ddc_ctrl->base, HDMI_DDC_CTRL, BIT(1));
+ DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_CTRL, BIT(1));
if (retry-- > 0) {
DEV_DBG("%s[%s]: failed NACK=%08x, retry=%d\n",
diff --git a/drivers/video/msm/mdss/mdss_hdmi_util.h b/drivers/video/msm/mdss/mdss_hdmi_util.h
index 47515ba..852a93c 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_util.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_util.h
@@ -12,26 +12,7 @@
#ifndef __HDMI_UTIL_H__
#define __HDMI_UTIL_H__
-
-#define DEV_INFO(fmt, args...) pr_info(fmt, ##args)
-#define DEV_WARN(fmt, args...) pr_warn(fmt, ##args)
-#define DEV_ERR(fmt, args...) pr_err(fmt, ##args)
-
-#ifdef DEBUG
-#define DEV_DBG(fmt, args...) pr_err(fmt, ##args)
-#else
-#define DEV_DBG(args...) (void)0
-#endif
-
-#define PORT_DEBUG 0
-#define REG_DUMP 0
-void hdmi_reg_w(void __iomem *addr, u32 offset, u32 value, u32 debug);
-u32 hdmi_reg_r(void __iomem *addr, u32 offset, u32 debug);
-
-#define HDMI_REG_W_ND(addr, offset, val) hdmi_reg_w(addr, offset, val, false)
-#define HDMI_REG_W(addr, offset, val) hdmi_reg_w(addr, offset, val, true)
-#define HDMI_REG_R_ND(addr, offset) hdmi_reg_r(addr, offset, false)
-#define HDMI_REG_R(addr, offset) hdmi_reg_r(addr, offset, true)
+#include "mdss_io_util.h"
/* HDMI_TX Registers */
#define HDMI_CTRL (0x00000000)
@@ -220,7 +201,7 @@
#define HDMI_TPG_BLK_WHT_PATTERN_FRAMES (0x00000358)
#define HDMI_TPG_RGB_MAPPING (0x0000035C)
-/* HDMI PHY Registers, use them with PHY base and _ND macro */
+/* HDMI PHY Registers */
#define HDMI_PHY_ANA_CFG0 (0x00000000)
#define HDMI_PHY_ANA_CFG1 (0x00000004)
#define HDMI_PHY_PD_CTRL0 (0x00000010)
@@ -231,6 +212,10 @@
#define HDMI_PHY_BIST_PATN2 (0x00000044)
#define HDMI_PHY_BIST_PATN3 (0x00000048)
+/* QFPROM Registers for HDMI/HDCP */
+#define QFPROM_RAW_FEAT_CONFIG_ROW0_LSB (0x000000F8)
+#define QFPROM_RAW_FEAT_CONFIG_ROW0_MSB (0x000000FC)
+
/* all video formats defined by EIA CEA 861D */
#define HDMI_VFRMT_640x480p60_4_3 0
#define HDMI_VFRMT_720x480p60_4_3 1
@@ -397,7 +382,7 @@
};
struct hdmi_tx_ddc_ctrl {
- void __iomem *base;
+ struct dss_io_data *io;
struct completion ddc_sw_done;
};
@@ -412,9 +397,6 @@
int retry;
};
-void hdmi_reg_dump(void __iomem *base, u32 length, const char *prefix);
-const char *hdmi_reg_name(u32 offset);
-
const struct hdmi_disp_mode_timing_type *hdmi_get_supported_mode(u32 mode);
void hdmi_set_supported_mode(u32 mode);
const char *hdmi_get_video_fmt_2string(u32 format);
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index 65d08d3..5778525 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -10,10 +10,65 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include "mdss_io_util.h"
+void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug)
+{
+ u32 in_val;
+
+ if (!io || !io->base) {
+ DEV_ERR("%pS->%s: invalid input\n",
+ __builtin_return_address(0), __func__);
+ return;
+ }
+
+ if (offset > io->len) {
+ DEV_ERR("%pS->%s: offset out of range\n",
+ __builtin_return_address(0), __func__);
+ return;
+ }
+
+ writel_relaxed(value, io->base + offset);
+ if (debug) {
+ in_val = readl_relaxed(io->base + offset);
+ DEV_DBG("[%08x] => %08x [%08x]\n", (u32)(io->base + offset),
+ value, in_val);
+ }
+} /* dss_reg_w */
+
+u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug)
+{
+ u32 value;
+ if (!io || !io->base) {
+ DEV_ERR("%pS->%s: invalid input\n",
+ __builtin_return_address(0), __func__);
+ return -EINVAL;
+ }
+
+ if (offset > io->len) {
+ DEV_ERR("%pS->%s: offset out of range\n",
+ __builtin_return_address(0), __func__);
+ return -EINVAL;
+ }
+
+ value = readl_relaxed(io->base + offset);
+ if (debug)
+ DEV_DBG("[%08x] <= %08x\n", (u32)(io->base + offset), value);
+
+ return value;
+} /* dss_reg_r */
+
+void dss_reg_dump(void __iomem *base, u32 length, const char *prefix,
+ u32 debug)
+{
+ if (debug)
+ print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4,
+ (void *)base, length, false);
+} /* dss_reg_dump */
+
static struct resource *msm_dss_get_res_byname(struct platform_device *pdev,
unsigned int type, const char *name)
{
@@ -21,11 +76,10 @@
res = platform_get_resource_byname(pdev, type, name);
if (!res)
- pr_err("%s: '%s' resource not found\n", __func__, name);
+ DEV_ERR("%s: '%s' resource not found\n", __func__, name);
return res;
-}
-
+} /* msm_dss_get_res_byname */
int msm_dss_ioremap_byname(struct platform_device *pdev,
struct dss_io_data *io_data, const char *name)
@@ -33,32 +87,49 @@
struct resource *res = NULL;
if (!pdev || !io_data) {
- pr_err("%s: invalid input\n", __func__);
+ DEV_ERR("%pS->%s: invalid input\n",
+ __builtin_return_address(0), __func__);
return -EINVAL;
}
res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name);
if (!res) {
- pr_err("%s: '%s' msm_dss_get_res_byname failed\n",
- __func__, name);
+ DEV_ERR("%pS->%s: '%s' msm_dss_get_res_byname failed\n",
+ __builtin_return_address(0), __func__, name);
return -ENODEV;
}
io_data->len = resource_size(res);
io_data->base = ioremap(res->start, io_data->len);
if (!io_data->base) {
- pr_err("%s: '%s' ioremap failed\n", __func__, name);
+ DEV_ERR("%pS->%s: '%s' ioremap failed\n",
+ __builtin_return_address(0), __func__, name);
return -EIO;
}
return 0;
-}
+} /* msm_dss_ioremap_byname */
+
+void msm_dss_iounmap(struct dss_io_data *io_data)
+{
+ if (!io_data) {
+ DEV_ERR("%pS->%s: invalid input\n",
+ __builtin_return_address(0), __func__);
+ return;
+ }
+
+ if (io_data->base) {
+ iounmap(io_data->base);
+ io_data->base = NULL;
+ }
+ io_data->len = 0;
+} /* msm_dss_iounmap */
int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
int num_vreg, int config)
{
int i = 0, rc = 0;
- struct dss_vreg *curr_vreg;
+ struct dss_vreg *curr_vreg = NULL;
if (config) {
for (i = 0; i < num_vreg; i++) {
@@ -67,8 +138,8 @@
curr_vreg->vreg_name);
rc = IS_ERR(curr_vreg->vreg);
if (rc) {
- pr_err("%s: %s get failed. rc=%d\n",
- __func__,
+ DEV_ERR("%pS->%s: %s get failed. rc=%d\n",
+ __builtin_return_address(0), __func__,
curr_vreg->vreg_name, rc);
curr_vreg->vreg = NULL;
goto vreg_get_fail;
@@ -79,7 +150,8 @@
curr_vreg->min_voltage,
curr_vreg->max_voltage);
if (rc < 0) {
- pr_err("%s: %s set voltage failed\n",
+ DEV_ERR("%pS->%s: %s set vltg fail\n",
+ __builtin_return_address(0),
__func__,
curr_vreg->vreg_name);
goto vreg_set_voltage_fail;
@@ -89,8 +161,9 @@
curr_vreg->vreg,
curr_vreg->optimum_voltage);
if (rc < 0) {
- pr_err(
- "%s: %s set opt mode failed\n",
+ DEV_ERR(
+ "%pS->%s: %s set opt m fail\n",
+ __builtin_return_address(0),
__func__,
curr_vreg->vreg_name);
goto vreg_set_opt_mode_fail;
@@ -144,14 +217,16 @@
for (i = 0; i < num_vreg; i++) {
rc = IS_ERR(in_vreg[i].vreg);
if (rc) {
- pr_err("%s: %s regulator error. rc=%d\n",
- __func__, in_vreg[i].vreg_name, rc);
+ DEV_ERR("%pS->%s: %s regulator error. rc=%d\n",
+ __builtin_return_address(0), __func__,
+ in_vreg[i].vreg_name, rc);
goto disable_vreg;
}
rc = regulator_enable(in_vreg[i].vreg);
if (rc < 0) {
- pr_err("%s: %s enable failed\n",
- __func__, in_vreg[i].vreg_name);
+ DEV_ERR("%pS->%s: %s enable failed\n",
+ __builtin_return_address(0), __func__,
+ in_vreg[i].vreg_name);
goto disable_vreg;
}
}
@@ -176,8 +251,9 @@
rc = gpio_request(in_gpio[i].gpio,
in_gpio[i].gpio_name);
if (rc < 0) {
- pr_err("%s: %s enable failed\n",
- __func__, in_gpio[i].gpio_name);
+ DEV_ERR("%pS->%s: %s enable failed\n",
+ __builtin_return_address(0), __func__,
+ in_gpio[i].gpio_name);
goto disable_gpio;
}
}
@@ -192,3 +268,117 @@
gpio_free(in_gpio[i].gpio);
return rc;
} /* msm_dss_enable_gpio */
+
+void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk)
+{
+ int i;
+
+ for (i = num_clk - 1; i >= 0; i--) {
+ if (clk_arry[i].clk)
+ clk_put(clk_arry[i].clk);
+ clk_arry[i].clk = NULL;
+ }
+} /* msm_dss_put_clk */
+
+int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk)
+{
+ int i, rc = 0;
+
+ for (i = 0; i < num_clk; i++) {
+ clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
+ rc = IS_ERR(clk_arry[i].clk);
+ if (rc) {
+ DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n",
+ __builtin_return_address(0), __func__,
+ clk_arry[i].clk_name, rc);
+ goto error;
+ }
+ }
+
+ return rc;
+
+error:
+ msm_dss_put_clk(clk_arry, num_clk);
+
+ return rc;
+} /* msm_dss_get_clk */
+
+int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk)
+{
+ int i, rc = 0;
+
+ for (i = 0; i < num_clk; i++) {
+ if (clk_arry[i].clk) {
+ if (DSS_CLK_AHB != clk_arry[i].type) {
+ DEV_DBG("%pS->%s: '%s' rate %ld\n",
+ __builtin_return_address(0), __func__,
+ clk_arry[i].clk_name,
+ clk_arry[i].rate);
+ rc = clk_set_rate(clk_arry[i].clk,
+ clk_arry[i].rate);
+ if (rc) {
+ DEV_ERR("%pS->%s: %s failed. rc=%d\n",
+ __builtin_return_address(0),
+ __func__,
+ clk_arry[i].clk_name, rc);
+ break;
+ }
+ }
+ } else {
+ DEV_ERR("%pS->%s: '%s' is not available\n",
+ __builtin_return_address(0), __func__,
+ clk_arry[i].clk_name);
+ rc = -EPERM;
+ break;
+ }
+ }
+
+ return rc;
+} /* msm_dss_clk_set_rate */
+
+int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable)
+{
+ int i, rc = 0;
+
+ if (enable) {
+ for (i = 0; i < num_clk; i++) {
+ DEV_DBG("%pS->%s: enable '%s'\n",
+ __builtin_return_address(0), __func__,
+ clk_arry[i].clk_name);
+ if (clk_arry[i].clk) {
+ rc = clk_prepare_enable(clk_arry[i].clk);
+ if (rc)
+ DEV_ERR("%pS->%s: %s en fail. rc=%d\n",
+ __builtin_return_address(0),
+ __func__,
+ clk_arry[i].clk_name, rc);
+ } else {
+ DEV_ERR("%pS->%s: '%s' is not available\n",
+ __builtin_return_address(0), __func__,
+ clk_arry[i].clk_name);
+ rc = -EPERM;
+ }
+
+ if (rc) {
+ msm_dss_enable_clk(&clk_arry[i],
+ i, false);
+ break;
+ }
+ }
+ } else {
+ for (i = num_clk - 1; i >= 0; i--) {
+ DEV_DBG("%pS->%s: disable '%s'\n",
+ __builtin_return_address(0), __func__,
+ clk_arry[i].clk_name);
+
+ if (clk_arry[i].clk)
+ clk_disable_unprepare(clk_arry[i].clk);
+ else
+ DEV_ERR("%pS->%s: '%s' is not available\n",
+ __builtin_return_address(0), __func__,
+ clk_arry[i].clk_name);
+ }
+ }
+
+ return rc;
+} /* msm_dss_enable_clk */
diff --git a/drivers/video/msm/mdss/mdss_io_util.h b/drivers/video/msm/mdss/mdss_io_util.h
index 9671414..51e9e54 100644
--- a/drivers/video/msm/mdss/mdss_io_util.h
+++ b/drivers/video/msm/mdss/mdss_io_util.h
@@ -17,11 +17,29 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#ifdef DEBUG
+#define DEV_DBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define DEV_DBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+#define DEV_INFO(fmt, args...) pr_info(fmt, ##args)
+#define DEV_WARN(fmt, args...) pr_warn(fmt, ##args)
+#define DEV_ERR(fmt, args...) pr_err(fmt, ##args)
+
struct dss_io_data {
u32 len;
void __iomem *base;
};
+void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug);
+u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug);
+void dss_reg_dump(void __iomem *base, u32 len, const char *prefix, u32 debug);
+
+#define DSS_REG_W_ND(io, offset, val) dss_reg_w(io, offset, val, false)
+#define DSS_REG_W(io, offset, val) dss_reg_w(io, offset, val, true)
+#define DSS_REG_R_ND(io, offset) dss_reg_r(io, offset, false)
+#define DSS_REG_R(io, offset) dss_reg_r(io, offset, true)
+
enum dss_vreg_type {
DSS_REG_LDO,
DSS_REG_VS,
@@ -41,19 +59,42 @@
char gpio_name[32];
};
+enum dss_clk_type {
+ DSS_CLK_AHB, /* no set rate. rate controlled through rpm */
+ DSS_CLK_PCLK,
+ DSS_CLK_OTHER,
+};
+
+struct dss_clk {
+ struct clk *clk; /* clk handle */
+ char clk_name[32];
+ enum dss_clk_type type;
+ unsigned long rate;
+};
+
struct dss_module_power {
unsigned num_vreg;
struct dss_vreg *vreg_config;
unsigned num_gpio;
struct dss_gpio *gpio_config;
+ unsigned num_clk;
+ struct dss_clk *clk_config;
};
int msm_dss_ioremap_byname(struct platform_device *pdev,
struct dss_io_data *io_data, const char *name);
+void msm_dss_iounmap(struct dss_io_data *io_data);
+
int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable);
int msm_dss_gpio_enable(struct dss_gpio *in_gpio, int num_gpio, int enable);
+
int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg,
int num_vreg, int config);
int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable);
+int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk);
+void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk);
+int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk);
+int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable);
+
#endif /* __MDSS_IO_UTIL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 63df84c..0f6cfe9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -128,6 +128,8 @@
static DEFINE_SPINLOCK(mdss_lock);
struct mdss_hw *mdss_irq_handlers[MDSS_MAX_HW_BLK];
+static int mdss_mdp_register_early_suspend(struct mdss_data_type *mdata);
+
static inline int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr)
{
struct mdss_hw *hw;
@@ -216,8 +218,9 @@
spin_lock_irqsave(&mdss_lock, irq_flags);
if (!(mdss_res->irq_mask & ndx_bit)) {
- pr_warn("MDSS HW ndx=%d is NOT set, mask=%x\n",
- hw->hw_ndx, mdss_res->mdp_irq_mask);
+ pr_warn("MDSS HW ndx=%d is NOT set, mask=%x, hist mask=%x\n",
+ hw->hw_ndx, mdss_res->mdp_irq_mask,
+ mdss_res->mdp_hist_irq_mask);
} else {
mdss_irq_handlers[hw->hw_ndx] = NULL;
mdss_res->irq_mask &= ~ndx_bit;
@@ -244,8 +247,9 @@
spin_lock(&mdss_lock);
if (!(mdss_res->irq_mask & ndx_bit)) {
- pr_warn("MDSS HW ndx=%d is NOT set, mask=%x\n",
- hw->hw_ndx, mdss_res->mdp_irq_mask);
+ pr_warn("MDSS HW ndx=%d is NOT set, mask=%x, hist mask=%x\n",
+ hw->hw_ndx, mdss_res->mdp_irq_mask,
+ mdss_res->mdp_hist_irq_mask);
} else {
mdss_irq_handlers[hw->hw_ndx] = NULL;
mdss_res->irq_mask &= ~ndx_bit;
@@ -357,6 +361,29 @@
return ret;
}
+int mdss_mdp_hist_irq_enable(u32 irq)
+{
+ unsigned long irq_flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&mdp_lock, irq_flags);
+ if (mdss_res->mdp_hist_irq_mask & irq) {
+ pr_warn("MDSS MDP Hist IRQ-0x%x is already set, mask=%x\n",
+ irq, mdss_res->mdp_hist_irq_mask);
+ ret = -EBUSY;
+ } else {
+ pr_debug("MDP IRQ mask old=%x new=%x\n",
+ mdss_res->mdp_hist_irq_mask, irq);
+ mdss_res->mdp_hist_irq_mask |= irq;
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_CLEAR, irq);
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_EN,
+ mdss_res->mdp_hist_irq_mask);
+ mdss_enable_irq(&mdss_mdp_hw);
+ }
+ spin_unlock_irqrestore(&mdp_lock, irq_flags);
+
+ return ret;
+}
void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num)
{
@@ -374,7 +401,27 @@
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
mdss_res->mdp_irq_mask);
- if (mdss_res->mdp_irq_mask == 0)
+ if ((mdss_res->mdp_irq_mask == 0) &&
+ (mdss_res->mdp_hist_irq_mask == 0))
+ mdss_disable_irq(&mdss_mdp_hw);
+ }
+ spin_unlock_irqrestore(&mdp_lock, irq_flags);
+}
+
+void mdss_mdp_hist_irq_disable(u32 irq)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&mdp_lock, irq_flags);
+ if (!(mdss_res->mdp_hist_irq_mask & irq)) {
+ pr_warn("MDSS MDP IRQ-%x is NOT set, mask=%x\n",
+ irq, mdss_res->mdp_hist_irq_mask);
+ } else {
+ mdss_res->mdp_hist_irq_mask &= ~irq;
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_EN,
+ mdss_res->mdp_hist_irq_mask);
+ if ((mdss_res->mdp_irq_mask == 0) &&
+ (mdss_res->mdp_hist_irq_mask == 0))
mdss_disable_irq(&mdss_mdp_hw);
}
spin_unlock_irqrestore(&mdp_lock, irq_flags);
@@ -394,7 +441,8 @@
mdss_res->mdp_irq_mask &= ~irq;
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
mdss_res->mdp_irq_mask);
- if (mdss_res->mdp_irq_mask == 0)
+ if ((mdss_res->mdp_irq_mask == 0) &&
+ (mdss_res->mdp_hist_irq_mask == 0))
mdss_disable_irq_nosync(&mdss_mdp_hw);
}
spin_unlock(&mdp_lock);
@@ -852,6 +900,16 @@
goto probe_done;
}
rc = mdss_mdp_bus_scale_register(mdata);
+ if (rc) {
+ pr_err("unable to register bus scaling\n");
+ goto probe_done;
+ }
+
+ rc = mdss_mdp_register_early_suspend(mdata);
+ if (rc) {
+ pr_err("unable to register early suspend\n");
+ goto probe_done;
+ }
probe_done:
if (IS_ERR_VALUE(rc)) {
mdss_res = NULL;
@@ -861,88 +919,154 @@
return rc;
}
-void mdss_mdp_footswitch_ctrl(int on)
+static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
{
mutex_lock(&mdp_suspend_mutex);
- if (!mdss_res->suspend || mdss_res->eintf_ena || !mdss_res->fs) {
+ if (!mdata->suspend || mdata->eintf_ena || !mdata->fs) {
mutex_unlock(&mdp_suspend_mutex);
return;
}
- if (on && !mdss_res->fs_ena) {
+ if (on && !mdata->fs_ena) {
pr_debug("Enable MDP FS\n");
- regulator_enable(mdss_res->fs);
+ regulator_enable(mdata->fs);
mdss_iommu_attach();
- mdss_res->fs_ena = true;
- } else if (!on && mdss_res->fs_ena) {
+ mdata->fs_ena = true;
+ } else if (!on && mdata->fs_ena) {
pr_debug("Disable MDP FS\n");
mdss_iommu_dettach();
- regulator_disable(mdss_res->fs);
- mdss_res->fs_ena = false;
+ regulator_disable(mdata->fs);
+ mdata->fs_ena = false;
}
mutex_unlock(&mdp_suspend_mutex);
}
-#ifdef CONFIG_PM
-static void mdss_mdp_suspend_sub(void)
-{
- cancel_delayed_work(&mdss_res->clk_ctrl_worker);
-
- flush_workqueue(mdss_res->clk_ctrl_wq);
-
- mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
-
- mutex_lock(&mdp_suspend_mutex);
- mdss_res->suspend = true;
- mutex_unlock(&mdp_suspend_mutex);
-}
-
-static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
+static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
{
int ret;
- pr_debug("display suspend");
ret = mdss_fb_suspend_all();
if (IS_ERR_VALUE(ret)) {
pr_err("Unable to suspend all fb panels (%d)\n", ret);
return ret;
}
- mdss_mdp_suspend_sub();
- if (mdss_res->clk_ena) {
+
+ cancel_delayed_work(&mdata->clk_ctrl_worker);
+
+ flush_workqueue(mdata->clk_ctrl_wq);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_MASTER_OFF, false);
+
+ mutex_lock(&mdp_suspend_mutex);
+ mdata->suspend = true;
+ mutex_unlock(&mdp_suspend_mutex);
+
+ if (mdata->clk_ena) {
pr_err("MDP suspend failed\n");
return -EBUSY;
}
- mdss_mdp_footswitch_ctrl(false);
+ mdss_mdp_footswitch_ctrl(mdata, false);
+
+ pr_debug("suspend done\n");
return 0;
}
-static int mdss_mdp_resume(struct platform_device *pdev)
+static inline int mdss_mdp_resume_sub(struct mdss_data_type *mdata)
{
- struct mdss_data_type *mdata = platform_get_drvdata(pdev);
int ret = 0;
- if (!mdata)
- return -ENODEV;
-
- pr_debug("resume display");
-
- mdss_mdp_footswitch_ctrl(true);
+ mdss_mdp_footswitch_ctrl(mdata, true);
mutex_lock(&mdp_suspend_mutex);
- mdss_res->suspend = false;
+ mdata->suspend = false;
mutex_unlock(&mdp_suspend_mutex);
mdss_hw_init(mdata);
ret = mdss_fb_resume_all();
if (IS_ERR_VALUE(ret))
pr_err("Unable to resume all fb panels (%d)\n", ret);
+ pr_debug("resume done\n");
+
return ret;
}
+
+#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
+static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+
+ if (!mdata)
+ return -ENODEV;
+
+ pr_debug("display suspend\n");
+
+ return mdss_mdp_suspend_sub(mdata);
+}
+
+static int mdss_mdp_resume(struct platform_device *pdev)
+{
+ struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+
+ if (!mdata)
+ return -ENODEV;
+
+ pr_debug("display resume\n");
+
+ return mdss_mdp_resume_sub(mdata);
+}
#else
#define mdss_mdp_suspend NULL
#define mdss_mdp_resume NULL
#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void mdss_mdp_early_suspend(struct early_suspend *h)
+{
+ struct mdss_data_type *mdata;
+ mdata = container_of(h, struct mdss_data_type, early_suspend);
+
+ pr_debug("display early suspend\n");
+
+ mdss_mdp_suspend_sub(mdata);
+}
+
+static void mdss_mdp_late_resume(struct early_suspend *h)
+{
+ struct mdss_data_type *mdata;
+ mdata = container_of(h, struct mdss_data_type, early_suspend);
+
+ pr_debug("display early resume\n");
+
+ mdss_mdp_resume_sub(mdata);
+}
+
+static int mdss_mdp_register_early_suspend(struct mdss_data_type *mdata)
+{
+ mdata->early_suspend.suspend = mdss_mdp_early_suspend;
+ mdata->early_suspend.resume = mdss_mdp_late_resume;
+ mdata->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
+ register_early_suspend(&mdata->early_suspend);
+
+ return 0;
+}
+
+static int mdss_mdp_remove_early_suspend(struct mdss_data_type *mdata)
+{
+ unregister_early_suspend(&mdata->early_suspend);
+
+ return 0;
+}
+#else
+static int mdss_mdp_register_early_suspend(struct mdss_data_type *mdata)
+{
+ return 0;
+}
+static int mdss_mdp_remove_early_suspend(struct mdss_data_type *mdata)
+{
+ return 0;
+}
+#endif
+
static int mdss_mdp_remove(struct platform_device *pdev)
{
struct mdss_data_type *mdata = platform_get_drvdata(pdev);
@@ -951,13 +1075,16 @@
pm_runtime_disable(&pdev->dev);
mdss_mdp_pp_term(&pdev->dev);
mdss_mdp_bus_scale_unregister(mdata);
+ mdss_mdp_remove_early_suspend(mdata);
return 0;
}
static const struct of_device_id mdss_mdp_dt_match[] = {
{ .compatible = "qcom,mdss_mdp",},
+ {}
};
MODULE_DEVICE_TABLE(of, mdss_mdp_dt_match);
+EXPORT_COMPAT("qcom,mdss_mdp");
static struct platform_driver mdss_mdp_driver = {
.probe = mdss_mdp_probe,
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 610c132..33028cb 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -29,7 +29,7 @@
#define MDP_CLK_DEFAULT_RATE 37500000
#define PHASE_STEP_SHIFT 21
#define MAX_MIXER_WIDTH 2048
-#define MAX_MIXER_HEIGHT 2048
+#define MAX_MIXER_HEIGHT 2400
#define MAX_IMG_WIDTH 0x3FFF
#define MAX_IMG_HEIGHT 0x3FFF
#define MIN_DST_W 10
@@ -241,7 +241,10 @@
unsigned long smp[MAX_PLANES];
struct mdss_mdp_data buffers[2];
- struct list_head list;
+ struct list_head used_list;
+ struct list_head cleanup_list;
+
+ struct mdp_overlay_pp_params pp_cfg;
};
struct mdss_mdp_writeback_arg {
@@ -250,6 +253,7 @@
void *priv_data;
};
+#define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
u32 reg, u32 val)
{
@@ -266,6 +270,8 @@
irqreturn_t mdss_mdp_isr(int irq, void *ptr);
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num);
+int mdss_mdp_hist_irq_enable(u32 irq);
+void mdss_mdp_hist_irq_disable(u32 irq);
void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num);
int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
void (*fnc_ptr)(void *), void *arg);
@@ -275,10 +281,10 @@
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
int mdss_mdp_vsync_clk_enable(int enable);
void mdss_mdp_clk_ctrl(int enable, int isr);
-void mdss_mdp_footswitch_ctrl(int on);
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd);
+int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en);
int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
@@ -295,7 +301,24 @@
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
int mdss_mdp_csc_setup(u32 block, u32 blk_idx, u32 tbl_idx, u32 csc_type);
+int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
+ struct mdp_csc_cfg *data);
+
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
+
+int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback);
+int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback);
+int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback);
+int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
+int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
+
+int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req);
+int mdss_mdp_histogram_stop(u32 block);
+int mdss_mdp_hist_collect(struct fb_info *info,
+ struct mdp_histogram_data *hist, u32 *hist_data_addr);
+void mdss_mdp_hist_intr_done(u32 isr);
+
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index f72ff8d..d21a095 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -90,18 +90,34 @@
*bus_ib_quota = 0;
*clk_rate = 0;
- if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
- struct mdss_panel_info *pinfo = &mixer->ctl->mfd->panel_info;
- v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
- pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width);
- v_active = pinfo->yres;
- } else if (mixer->rotator_mode) {
+ if (mixer->rotator_mode) {
pipe = mixer->stage_pipe[0]; /* rotator pipe */
v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
v_active = v_total;
} else {
- v_total = mixer->height;
- v_active = v_total;
+ int is_writeback = false;
+ if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+ struct mdss_panel_info *pinfo;
+ pinfo = &mixer->ctl->mfd->panel_info;
+ v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
+ pinfo->lcdc.v_front_porch +
+ pinfo->lcdc.v_pulse_width);
+ v_active = pinfo->yres;
+
+ if (pinfo->type == WRITEBACK_PANEL)
+ is_writeback = true;
+ } else {
+ v_total = mixer->height;
+ v_active = v_total;
+
+ is_writeback = true;
+ }
+ *clk_rate = mixer->width * v_total * fps;
+ if (is_writeback) {
+ /* perf for bus writeback */
+ *bus_ab_quota = fps * mixer->width * mixer->height * 3;
+ *bus_ib_quota = *bus_ab_quota;
+ }
}
for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
@@ -118,7 +134,7 @@
if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
quota = (quota / v_active) * v_total;
- else
+ else if (mixer->rotator_mode)
quota *= 2; /* bus read + write */
rate = pipe->dst.w;
@@ -344,6 +360,8 @@
mdss_mdp_mixer_free(mixer);
mdss_mdp_ctl_free(ctl);
+ mdss_mdp_ctl_perf_commit(MDSS_MDP_PERF_UPDATE_ALL);
+
return 0;
}
@@ -351,6 +369,7 @@
{
struct mdss_mdp_ctl *ctl;
u32 width, height;
+ int ret = 0;
if (!mfd)
return -ENODEV;
@@ -363,43 +382,54 @@
return -EINVAL;
}
- ctl = mdss_mdp_ctl_alloc();
-
- if (!ctl) {
- pr_err("unable to allocate ctl\n");
- return -ENOMEM;
+ if (!mfd->ctl) {
+ ctl = mdss_mdp_ctl_alloc();
+ if (!ctl) {
+ pr_err("unable to allocate ctl\n");
+ return -ENOMEM;
+ }
+ ctl->mfd = mfd;
+ mfd->ctl = ctl;
+ } else {
+ ctl = mfd->ctl;
}
- ctl->mfd = mfd;
ctl->width = width;
ctl->height = height;
ctl->dst_format = mfd->panel_info.out_format;
- ctl->mixer_left = mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
if (!ctl->mixer_left) {
- pr_err("unable to allocate layer mixer\n");
- mdss_mdp_ctl_free(ctl);
- return -ENOMEM;
+ ctl->mixer_left =
+ mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
+ if (!ctl->mixer_left) {
+ pr_err("unable to allocate layer mixer\n");
+ ret = -ENOMEM;
+ goto ctl_init_fail;
+ }
}
- ctl->mixer_left->width = MIN(width, MAX_MIXER_WIDTH);
+ if (width > MAX_MIXER_WIDTH)
+ width /= 2;
+
+ ctl->mixer_left->width = width;
ctl->mixer_left->height = height;
ctl->mixer_left->ctl = ctl;
- width -= ctl->mixer_left->width;
-
- if (width) {
- ctl->mixer_right =
- mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
- if (!ctl->mixer_right) {
- pr_err("unable to allocate layer mixer\n");
- mdss_mdp_mixer_free(ctl->mixer_left);
- mdss_mdp_ctl_free(ctl);
- return -ENOMEM;
+ if (width < ctl->width) {
+ if (ctl->mixer_right == NULL) {
+ ctl->mixer_right =
+ mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
+ if (!ctl->mixer_right) {
+ pr_err("unable to allocate right mixer\n");
+ ret = -ENOMEM;
+ goto ctl_init_fail;
+ }
}
ctl->mixer_right->width = width;
ctl->mixer_right->height = height;
ctl->mixer_right->ctl = ctl;
+ } else if (ctl->mixer_right) {
+ mdss_mdp_mixer_free(ctl->mixer_right);
}
switch (mfd->panel_info.type) {
@@ -431,9 +461,8 @@
break;
default:
pr_err("unsupported panel type (%d)\n", mfd->panel_info.type);
- mdss_mdp_ctl_free(ctl);
- return -EINVAL;
-
+ ret = -EINVAL;
+ goto ctl_init_fail;
}
ctl->opmode |= (ctl->intf_num << 4);
@@ -443,9 +472,17 @@
MDSS_MDP_CTL_OP_PACK_3D_H_ROW_INT;
}
- mfd->ctl = ctl;
+ctl_init_fail:
+ if (IS_ERR_VALUE(ret)) {
+ if (ctl->mixer_left)
+ mdss_mdp_mixer_free(ctl->mixer_left);
+ if (ctl->mixer_right)
+ mdss_mdp_mixer_free(ctl->mixer_right);
+ mdss_mdp_ctl_free(ctl);
+ mfd->ctl = NULL;
+ }
- return 0;
+ return ret;
}
static int mdss_mdp_ctl_destroy(struct msm_fb_data_type *mfd)
@@ -486,12 +523,11 @@
return -ENODEV;
}
- if (!mfd->ctl) {
- if (mdss_mdp_ctl_init(mfd)) {
- pr_err("unable to initialize ctl\n");
- return -ENODEV;
- }
+ if (mdss_mdp_ctl_init(mfd)) {
+ pr_err("unable to initialize ctl\n");
+ return -ENODEV;
}
+
ctl = mfd->ctl;
if (ctl->power_on) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 0139afd..651d595 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -74,6 +74,11 @@
MDSS_MDP_IRQ_INTF_VSYNC = 25,
};
+#define MDSS_MDP_REG_IGC_VIG_BASE 0x300
+#define MDSS_MDP_REG_IGC_RGB_BASE 0x310
+#define MDSS_MDP_REG_IGC_DMA_BASE 0x320
+#define MDSS_MDP_REG_IGC_DSPP_BASE 0x400
+
enum mdss_mdp_ctl_index {
MDSS_MDP_CTL0,
MDSS_MDP_CTL1,
@@ -189,6 +194,9 @@
#define MDSS_MDP_REG_VIG_CSC_0_BASE 0x280
#define MDSS_MDP_REG_VIG_CSC_1_BASE 0x320
+#define MDSS_MDP_REG_VIG_HIST_CTL_BASE 0x2C4
+#define MDSS_MDP_REG_VIG_HIST_LUT_BASE 0x2F0
+
#define MDSS_MDP_SCALE_FILTER_NEAREST 0x0
#define MDSS_MDP_SCALE_FILTER_BIL 0x1
#define MDSS_MDP_SCALE_FILTER_PCMN 0x2
@@ -260,6 +268,8 @@
#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0 0x108
#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1 0x10C
+#define MDSS_MDP_REG_LM_GC_LUT_BASE 0x110
+
#define MDSS_MDP_LM_BORDER_COLOR (1 << 24)
#define MDSS_MDP_LM_CURSOR_OUT (1 << 25)
#define MDSS_MDP_BLEND_FG_ALPHA_FG_CONST (0 << 0)
@@ -323,7 +333,12 @@
#define MDSS_MDP_REG_DSPP_OFFSET(pipe) (0x4600 + ((pipe) * 0x400))
#define MDSS_MDP_REG_DSPP_OP_MODE 0x000
+#define MDSS_MDP_REG_DSPP_PCC_BASE 0x030
+#define MDSS_MDP_REG_DSPP_DITHER_DEPTH 0x150
+#define MDSS_MDP_REG_DSPP_HIST_CTL_BASE 0x210
+#define MDSS_MDP_REG_DSPP_HIST_LUT_BASE 0x230
#define MDSS_MDP_REG_DSPP_PA_BASE 0x238
+#define MDSS_MDP_REG_DSPP_GAMUT_BASE 0x2DC
enum mdss_mpd_intf_index {
MDSS_MDP_NO_INTF,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index fed7d21..3c7c362 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -183,7 +183,7 @@
if (mutex_lock_interruptible(&ctx->vsync_lock))
return -EINTR;
- if (!ctx->timegen_en) {
+ if (vsync_handler && !ctx->timegen_en) {
ctx->vsync_time = ktime_get();
schedule_work(&ctx->vsync_work);
}
@@ -213,6 +213,9 @@
return -ENODEV;
}
+ if (ctx->vsync_handler)
+ mdss_mdp_video_set_vsync_handler(ctl, NULL);
+
if (ctx->timegen_en) {
off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index e8e8163..452ebdc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -282,7 +282,7 @@
}
mutex_lock(&mfd->lock);
- list_add(&pipe->list, &mfd->overlay_list);
+ list_add(&pipe->used_list, &mfd->pipes_used);
mutex_unlock(&mfd->lock);
pipe->mixer = mixer;
pipe->mfd = mfd;
@@ -316,6 +316,15 @@
pipe->req_data = *req;
+ if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
+ if (pipe->num <= MDSS_MDP_SSPP_VIG2)
+ memcpy(&pipe->pp_cfg, &req->overlay_pp_cfg,
+ sizeof(struct mdp_overlay_pp_params));
+ else
+ pr_debug("%s: RGB Pipes don't support CSC/QSEED\n",
+ __func__);
+ }
+
pipe->params_changed++;
req->id = pipe->ndx;
@@ -386,24 +395,31 @@
static int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
{
- int ret;
+ struct mdss_mdp_pipe *pipe, *tmp;
+ struct msm_fb_data_type *mfd = ctl->mfd;
+ int i, ret;
- if (ctl->mfd->kickoff_fnc)
- ret = ctl->mfd->kickoff_fnc(ctl);
+ if (mfd->kickoff_fnc)
+ ret = mfd->kickoff_fnc(ctl);
else
ret = mdss_mdp_display_commit(ctl, NULL);
if (IS_ERR_VALUE(ret))
return ret;
- pr_debug("freeing previous buffers\n");
+ mutex_lock(&mfd->lock);
+ list_for_each_entry_safe(pipe, tmp, &mfd->pipes_cleanup, cleanup_list) {
+ list_del(&pipe->cleanup_list);
+ for (i = 0; i < ARRAY_SIZE(pipe->buffers); i++)
+ mdss_mdp_overlay_free_buf(&pipe->buffers[i]);
- mutex_lock(&ctl->mfd->lock);
- if (!list_empty(&ctl->mfd->overlay_list)) {
- struct mdss_mdp_pipe *pipe;
+ mdss_mdp_pipe_destroy(pipe);
+ }
+
+ if (!list_empty(&mfd->pipes_used)) {
struct mdss_mdp_data *data;
int buf_ndx;
- list_for_each_entry(pipe, &ctl->mfd->overlay_list, list) {
+ list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
buf_ndx = (pipe->play_cnt - 1) & 1; /* prev buffer */
data = &pipe->buffers[buf_ndx];
@@ -414,9 +430,7 @@
}
}
}
- mutex_unlock(&ctl->mfd->lock);
-
- pr_debug("done freeing previous buffers\n");
+ mutex_unlock(&mfd->lock);
return ret;
}
@@ -424,8 +438,7 @@
static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
{
struct mdss_mdp_pipe *pipe;
- struct mdss_mdp_pipe *cleanup_pipes[MDSS_MDP_MAX_SSPP];
- int i, ret = 0, clean_cnt = 0;
+ int i, ret = 0;
u32 pipe_ndx, unset_ndx = 0;
if (!mfd || !mfd->ctl)
@@ -451,28 +464,15 @@
if (pipe_ndx & ndx) {
unset_ndx |= pipe_ndx;
pipe = mdss_mdp_pipe_get_locked(pipe_ndx);
- if (pipe) {
- mutex_lock(&mfd->lock);
- list_del(&pipe->list);
- mutex_unlock(&mfd->lock);
- mdss_mdp_mixer_pipe_unstage(pipe);
- cleanup_pipes[clean_cnt++] = pipe;
- } else {
+ if (!pipe) {
pr_warn("unknown pipe ndx=%x\n", pipe_ndx);
+ continue;
}
- }
- }
-
- if (clean_cnt) {
- int j;
- ret = mdss_mdp_overlay_kickoff(mfd->ctl);
-
- for (i = 0; i < clean_cnt; i++) {
- pipe = cleanup_pipes[i];
- for (j = 0; j < ARRAY_SIZE(pipe->buffers); j++)
- mdss_mdp_overlay_free_buf(&pipe->buffers[i]);
-
- mdss_mdp_pipe_destroy(pipe);
+ mutex_lock(&mfd->lock);
+ list_del(&pipe->used_list);
+ list_add(&pipe->cleanup_list, &mfd->pipes_cleanup);
+ mutex_unlock(&mfd->lock);
+ mdss_mdp_mixer_pipe_unstage(pipe);
}
}
@@ -486,8 +486,8 @@
int cnt = 0;
mutex_lock(&mfd->lock);
- if (!list_empty(&mfd->overlay_list)) {
- list_for_each_entry(pipe, &mfd->overlay_list, list) {
+ if (!list_empty(&mfd->pipes_used)) {
+ list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
if (pipe->ndx & MDSS_MDP_ROT_SESSION_MASK) {
struct mdss_mdp_rotator_session *rot;
rot = mdss_mdp_rotator_session_get(pipe->ndx);
@@ -504,6 +504,7 @@
if (unset_ndx) {
pr_debug("%d pipes need cleanup (%x)\n", cnt, unset_ndx);
mdss_mdp_overlay_unset(mfd, unset_ndx);
+ mdss_mdp_overlay_kickoff(mfd->ctl);
}
return 0;
@@ -594,7 +595,7 @@
ctl = pipe->mixer->ctl;
mdss_mdp_pipe_unlock(pipe);
- if (ret == 0 && !(pipe->flags & MDP_OV_PLAY_NOWAIT))
+ if ((ret == 0) && (mfd->panel_info.type == WRITEBACK_PANEL))
ret = mdss_mdp_overlay_kickoff(ctl);
return ret;
@@ -626,8 +627,15 @@
if (pipe == NULL) {
struct mdp_overlay req;
struct fb_info *fbi = mfd->fbi;
+ struct mdss_mdp_mixer *mixer;
int ret, bpp;
+ mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_LEFT);
+ if (!mixer) {
+ pr_err("unable to retrieve mixer\n");
+ return -ENODEV;
+ }
+
memset(&req, 0, sizeof(req));
bpp = fbi->var.bits_per_pixel / 8;
@@ -636,20 +644,22 @@
req.src.height = fbi->var.yres;
req.src.width = fbi->fix.line_length / bpp;
if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
- if (req.src.width <= MAX_MIXER_WIDTH)
- return -ENODEV;
+ if (req.src.width <= mixer->width) {
+ pr_warn("right fb pipe not needed\n");
+ return -EINVAL;
+ }
req.flags |= MDSS_MDP_RIGHT_MIXER;
- req.src_rect.x = MAX_MIXER_WIDTH;
- req.src_rect.w = fbi->var.xres - MAX_MIXER_WIDTH;
+ req.src_rect.x = mixer->width;
+ req.src_rect.w = fbi->var.xres - mixer->width;
} else {
req.src_rect.x = 0;
- req.src_rect.w = MIN(fbi->var.xres, MAX_MIXER_WIDTH);
+ req.src_rect.w = MIN(fbi->var.xres, mixer->width);
}
req.src_rect.y = 0;
req.src_rect.h = req.src.height;
- req.dst_rect.x = req.src_rect.x;
+ req.dst_rect.x = 0;
req.dst_rect.y = 0;
req.dst_rect.w = req.src_rect.w;
req.dst_rect.h = req.src_rect.h;
@@ -685,7 +695,7 @@
fbi = mfd->fbi;
if (fbi->fix.smem_len == 0) {
- pr_warn("fb memory not allocated\n");
+ mdss_mdp_overlay_kickoff(mfd->ctl);
return;
}
@@ -765,7 +775,7 @@
pr_debug("sent vsync on ctl=%d ts=%llu\n", ctl->num, ktime_to_ns(t));
}
-static int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
+int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
{
struct mdss_mdp_ctl *ctl = mfd->ctl;
int rc;
@@ -777,6 +787,11 @@
pr_debug("vsync en=%d\n", en);
+ if (!ctl->power_on) {
+ mfd->vsync_pending = en;
+ return 0;
+ }
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
if (en)
rc = ctl->set_vsync_handler(ctl, mdss_mdp_overlay_handle_vsync);
@@ -1016,7 +1031,9 @@
ret = -EFAULT;
}
break;
-
+ case MSMFB_OVERLAY_COMMIT:
+ ret = mdss_mdp_overlay_kickoff(mfd->ctl);
+ break;
default:
if (mfd->panel_info.type == WRITEBACK_PANEL)
ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
@@ -1040,7 +1057,8 @@
if (mfd->panel_info.type == WRITEBACK_PANEL)
mfd->kickoff_fnc = mdss_mdp_wb_kickoff;
- INIT_LIST_HEAD(&mfd->overlay_list);
+ INIT_LIST_HEAD(&mfd->pipes_used);
+ INIT_LIST_HEAD(&mfd->pipes_cleanup);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index c936b7d..c90ce8c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -560,16 +560,32 @@
pr_debug("pnum=%x\n", pipe->num);
- if (pipe->src_fmt->is_yuv)
- opmode |= (0 << 19) | /* DST_DATA=RGB */
- (1 << 18) | /* SRC_DATA=YCBCR */
- (1 << 17); /* CSC_1_EN */
-
- /* only need to program once */
- if (pipe->play_cnt == 0) {
- mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
- MDSS_MDP_CSC_YUV2RGB);
+ /* CSC Post Processing enabled? */
+ if (pipe->flags & MDP_OVERLAY_PP_CFG_EN) {
+ if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG) {
+ if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_ENABLE)
+ opmode |= 1 << 17; /* CSC_1_EN */
+ if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_YUV_IN)
+ opmode |= 1 << 18; /* SRC_DATA=YCBCR */
+ if (pipe->pp_cfg.csc_cfg.flags & MDP_CSC_FLAG_YUV_OUT)
+ opmode |= 1 << 19; /* DST_DATA=YCBCR */
+ /* only need to program once */
+ if (pipe->play_cnt == 0)
+ mdss_mdp_csc_setup_data(MDSS_MDP_BLOCK_SSPP,
+ pipe->num, 1, &pipe->pp_cfg.csc_cfg);
+ }
+ } else {
+ if (pipe->src_fmt->is_yuv)
+ opmode |= (0 << 19) | /* DST_DATA=RGB */
+ (1 << 18) | /* SRC_DATA=YCBCR */
+ (1 << 17); /* CSC_1_EN */
+ /* only need to program once */
+ if (pipe->play_cnt == 0) {
+ mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
+ MDSS_MDP_CSC_YUV2RGB);
+ }
}
+
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, opmode);
return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 7ab3b01..6e04124 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -15,6 +15,9 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = {
[MDSS_MDP_CSC_RGB2RGB] = {
@@ -74,26 +77,118 @@
#define MDSS_BLOCK_DISP_NUM (MDP_BLOCK_MAX - MDP_LOGICAL_BLOCK_DISP_0)
+#define IGC_LUT_ENTRIES 256
+#define GC_LUT_SEGMENTS 16
+#define ENHIST_LUT_ENTRIES 256
+#define HIST_V_SIZE 256
+
+#define HIST_WAIT_TIMEOUT 1000
+/* hist collect state */
+enum {
+ HIST_UNKNOWN,
+ HIST_IDLE,
+ HIST_RESET,
+ HIST_START,
+ HIST_READY,
+};
+
+struct pp_hist_col_info {
+ u32 col_state;
+ u32 col_en;
+ u32 read_request;
+ u32 hist_cnt_read;
+ u32 hist_cnt_sent;
+ u32 frame_cnt;
+ struct completion comp;
+ u32 data[HIST_V_SIZE];
+};
+
+static u32 dither_matrix[16] = {
+ 15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10};
+static u32 dither_depth_map[9] = {
+ 0, 0, 0, 0, 0, 1, 2, 3, 3};
+
+#define GAMUT_T0_SIZE 125
+#define GAMUT_T1_SIZE 100
+#define GAMUT_T2_SIZE 80
+#define GAMUT_T3_SIZE 100
+#define GAMUT_T4_SIZE 100
+#define GAMUT_T5_SIZE 80
+#define GAMUT_T6_SIZE 64
+#define GAMUT_T7_SIZE 80
+#define GAMUT_TOTAL_TABLE_SIZE (GAMUT_T0_SIZE + GAMUT_T1_SIZE + \
+ GAMUT_T2_SIZE + GAMUT_T3_SIZE + GAMUT_T4_SIZE + \
+ GAMUT_T5_SIZE + GAMUT_T6_SIZE + GAMUT_T7_SIZE)
+
struct pp_sts_type {
u32 pa_sts;
+ u32 pcc_sts;
+ u32 igc_sts;
+ u32 igc_tbl_idx;
+ u32 argc_sts;
+ u32 enhist_sts;
+ u32 dither_sts;
+ u32 gamut_sts;
};
#define PP_FLAGS_DIRTY_PA 0x1
+#define PP_FLAGS_DIRTY_PCC 0x2
+#define PP_FLAGS_DIRTY_IGC 0x4
+#define PP_FLAGS_DIRTY_ARGC 0x8
+#define PP_FLAGS_DIRTY_ENHIST 0x10
+#define PP_FLAGS_DIRTY_DITHER 0x20
+#define PP_FLAGS_DIRTY_GAMUT 0x40
+#define PP_FLAGS_DIRTY_HIST_COL 0x80
#define PP_STS_ENABLE 0x1
+#define PP_STS_GAMUT_FIRST 0x2
struct mdss_pp_res_type {
/* logical info */
u32 pp_disp_flags[MDSS_BLOCK_DISP_NUM];
+ u32 igc_lut_c0c1[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
+ u32 igc_lut_c2[MDSS_BLOCK_DISP_NUM][IGC_LUT_ENTRIES];
+ struct mdp_ar_gc_lut_data
+ gc_lut_r[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
+ struct mdp_ar_gc_lut_data
+ gc_lut_g[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
+ struct mdp_ar_gc_lut_data
+ gc_lut_b[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
+ u32 enhist_lut[MDSS_BLOCK_DISP_NUM][ENHIST_LUT_ENTRIES];
struct mdp_pa_cfg_data pa_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ struct mdp_pcc_cfg_data pcc_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ struct mdp_igc_lut_data igc_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ struct mdp_pgc_lut_data pgc_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ struct mdp_hist_lut_data enhist_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ struct mdp_dither_cfg_data dither_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM];
+ uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE];
+ struct pp_hist_col_info
+ *hist_col[MDSS_BLOCK_DISP_NUM][MDSS_MDP_MAX_DSPP];
+ u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE];
/* physical info */
struct pp_sts_type pp_dspp_sts[MDSS_MDP_MAX_DSPP];
+ struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP];
};
static DEFINE_MUTEX(mdss_pp_mutex);
+static DEFINE_SPINLOCK(mdss_hist_lock);
+static DEFINE_MUTEX(mdss_mdp_hist_mutex);
static struct mdss_pp_res_type *mdss_pp_res;
-static int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
+
+static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info);
+
+static void pp_update_pcc_regs(u32 offset,
+ struct mdp_pcc_cfg_data *cfg_ptr);
+static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
+ u32 offset, u32 blk_idx);
+static void pp_update_gc_one_lut(u32 offset,
+ struct mdp_ar_gc_lut_data *lut_data);
+static void pp_update_argc_lut(u32 offset,
+ struct mdp_pgc_lut_data *config);
+
+int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
struct mdp_csc_cfg *data)
{
int i, ret = 0;
@@ -181,19 +276,123 @@
data = &mdp_csc_convert[csc_type];
return mdss_mdp_csc_setup_data(block, blk_idx, tbl_idx, data);
}
-
-static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
+static int pp_mixer_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
struct mdss_mdp_mixer *mixer)
{
- u32 flags, base, offset, dspp_num, opmode = 0;
- struct mdp_pa_cfg_data *pa_config;
+ u32 flags, offset, dspp_num, opmode = 0;
+ struct mdp_pgc_lut_data *pgc_config;
struct pp_sts_type *pp_sts;
-
dspp_num = mixer->num;
/* no corresponding dspp */
if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
(dspp_num >= MDSS_MDP_MAX_DSPP))
return 0;
+ if (disp_num < MDSS_BLOCK_DISP_NUM)
+ flags = mdss_pp_res->pp_disp_flags[disp_num];
+ else
+ flags = 0;
+
+ pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
+ /* GC_LUT is in layer mixer */
+ if (flags & PP_FLAGS_DIRTY_ARGC) {
+ pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num];
+ if (pgc_config->flags & MDP_PP_OPS_WRITE) {
+ offset = MDSS_MDP_REG_LM_OFFSET(disp_num) +
+ MDSS_MDP_REG_LM_GC_LUT_BASE;
+ pp_update_argc_lut(offset, pgc_config);
+ }
+ if (pgc_config->flags & MDP_PP_OPS_DISABLE)
+ pp_sts->argc_sts &= ~PP_STS_ENABLE;
+ else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
+ pp_sts->argc_sts |= PP_STS_ENABLE;
+ ctl->flush_bits |= BIT(6) << dspp_num; /* LAYER_MIXER */
+ }
+ /* update LM opmode if LM needs flush */
+ if ((pp_sts->argc_sts & PP_STS_ENABLE) &&
+ (ctl->flush_bits & (BIT(6) << dspp_num))) {
+ offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
+ MDSS_MDP_REG_LM_OP_MODE;
+ opmode = MDSS_MDP_REG_READ(offset);
+ opmode |= (1 << 0); /* GC_LUT_EN */
+ MDSS_MDP_REG_WRITE(offset, opmode);
+ }
+ return 0;
+}
+static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
+ u32 base,
+ u32 *gamut_sts)
+{
+ u32 offset;
+ int i, j;
+ if (gamut_cfg->flags & MDP_PP_OPS_WRITE) {
+ offset = base + MDSS_MDP_REG_DSPP_GAMUT_BASE;
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+ MDSS_MDP_REG_WRITE(offset,
+ (u32)gamut_cfg->r_tbl[i][j]);
+ offset += 4;
+ }
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+ MDSS_MDP_REG_WRITE(offset,
+ (u32)gamut_cfg->g_tbl[i][j]);
+ offset += 4;
+ }
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
+ MDSS_MDP_REG_WRITE(offset,
+ (u32)gamut_cfg->b_tbl[i][j]);
+ offset += 4;
+ }
+ if (gamut_cfg->gamut_first)
+ *gamut_sts |= PP_STS_GAMUT_FIRST;
+ }
+
+ if (gamut_cfg->flags & MDP_PP_OPS_DISABLE)
+ *gamut_sts &= ~PP_STS_ENABLE;
+ else if (gamut_cfg->flags & MDP_PP_OPS_ENABLE)
+ *gamut_sts |= PP_STS_ENABLE;
+}
+static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_mixer *mixer)
+{
+ u32 flags, base, offset, dspp_num, opmode = 0;
+ struct mdp_pa_cfg_data *pa_config;
+ struct mdp_pcc_cfg_data *pcc_config;
+ struct mdp_igc_lut_data *igc_config;
+ struct mdp_hist_lut_data *enhist_cfg;
+ struct mdp_dither_cfg_data *dither_cfg;
+ struct pp_hist_col_info *hist_info;
+ struct pp_sts_type *pp_sts;
+ u32 data, tbl_idx, col_state;
+ int i;
+ dspp_num = mixer->num;
+ /* no corresponding dspp */
+ if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
+ (dspp_num >= MDSS_MDP_MAX_DSPP))
+ return 0;
+ base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
+ hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+ if (hist_info->col_en) {
+ /* HIST_EN & AUTO_CLEAR */
+ opmode |= (1 << 16) | (1 << 17);
+ mutex_lock(&mdss_mdp_hist_mutex);
+ if (hist_info->col_state == HIST_READY)
+ pp_hist_read(base + MDSS_MDP_REG_DSPP_HIST_CTL_BASE +
+ 0x1C, hist_info);
+ spin_lock(&mdss_hist_lock);
+ col_state = hist_info->col_state;
+ if ((col_state == HIST_IDLE) ||
+ (col_state == HIST_READY) ||
+ (col_state == HIST_START)) {
+ /* Kick off collection */
+ MDSS_MDP_REG_WRITE(base +
+ MDSS_MDP_REG_DSPP_HIST_CTL_BASE, 1);
+ hist_info->col_state = HIST_START;
+ }
+ spin_unlock(&mdss_hist_lock);
+ mutex_unlock(&mdss_mdp_hist_mutex);
+ }
if (disp_num < MDSS_BLOCK_DISP_NUM)
flags = mdss_pp_res->pp_disp_flags[disp_num];
@@ -201,10 +400,9 @@
flags = 0;
/* nothing to update */
- if (!flags)
+ if ((!flags) && (!(hist_info->col_en)))
return 0;
pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
- base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
if (flags & PP_FLAGS_DIRTY_PA) {
pa_config = &mdss_pp_res->pa_disp_cfg[disp_num];
if (pa_config->flags & MDP_PP_OPS_WRITE) {
@@ -224,10 +422,108 @@
}
if (pp_sts->pa_sts & PP_STS_ENABLE)
opmode |= (1 << 20); /* PA_EN */
+ if (flags & PP_FLAGS_DIRTY_PCC) {
+ pcc_config = &mdss_pp_res->pcc_disp_cfg[disp_num];
+ if (pcc_config->ops & MDP_PP_OPS_WRITE) {
+ offset = base + MDSS_MDP_REG_DSPP_PCC_BASE;
+ pp_update_pcc_regs(offset, pcc_config);
+ }
+ if (pcc_config->ops & MDP_PP_OPS_DISABLE)
+ pp_sts->pcc_sts &= ~PP_STS_ENABLE;
+ else if (pcc_config->ops & MDP_PP_OPS_ENABLE)
+ pp_sts->pcc_sts |= PP_STS_ENABLE;
+ }
+ if (pp_sts->pcc_sts & PP_STS_ENABLE)
+ opmode |= (1 << 4); /* PCC_EN */
+
+ if (flags & PP_FLAGS_DIRTY_IGC) {
+ igc_config = &mdss_pp_res->igc_disp_cfg[disp_num];
+ if (igc_config->ops & MDP_PP_OPS_WRITE) {
+ offset = MDSS_MDP_REG_IGC_DSPP_BASE;
+ pp_update_igc_lut(igc_config, offset, dspp_num);
+ }
+ if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
+ pp_sts->pcc_sts |= PP_STS_ENABLE;
+ tbl_idx = 1;
+ } else if (igc_config->ops & MDP_PP_IGC_FLAG_ROM1) {
+ pp_sts->pcc_sts |= PP_STS_ENABLE;
+ tbl_idx = 2;
+ } else {
+ tbl_idx = 0;
+ }
+ pp_sts->igc_tbl_idx = tbl_idx;
+ if (igc_config->ops & MDP_PP_OPS_DISABLE)
+ pp_sts->igc_sts &= ~PP_STS_ENABLE;
+ else if (igc_config->ops & MDP_PP_OPS_ENABLE)
+ pp_sts->igc_sts |= PP_STS_ENABLE;
+ }
+ if (pp_sts->igc_sts & PP_STS_ENABLE) {
+ opmode |= (1 << 0) | /* IGC_LUT_EN */
+ (pp_sts->igc_tbl_idx << 1);
+ }
+ if (flags & PP_FLAGS_DIRTY_ENHIST) {
+ enhist_cfg = &mdss_pp_res->enhist_disp_cfg[disp_num];
+ if (enhist_cfg->ops & MDP_PP_OPS_WRITE) {
+ offset = base + MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
+ for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
+ MDSS_MDP_REG_WRITE(offset, enhist_cfg->data[i]);
+ /* swap */
+ MDSS_MDP_REG_WRITE(offset + 4, 1);
+ }
+ if (enhist_cfg->ops & MDP_PP_OPS_DISABLE)
+ pp_sts->enhist_sts &= ~PP_STS_ENABLE;
+ else if (enhist_cfg->ops & MDP_PP_OPS_ENABLE)
+ pp_sts->enhist_sts |= PP_STS_ENABLE;
+ }
+ if (pp_sts->enhist_sts & PP_STS_ENABLE) {
+ opmode |= (1 << 19) | /* HIST_LUT_EN */
+ (1 << 20); /* PA_EN */
+ if (!(pp_sts->pa_sts & PP_STS_ENABLE)) {
+ /* Program default value */
+ offset = base + MDSS_MDP_REG_DSPP_PA_BASE;
+ MDSS_MDP_REG_WRITE(offset, 0);
+ MDSS_MDP_REG_WRITE(offset + 4, 0);
+ MDSS_MDP_REG_WRITE(offset + 8, 0);
+ MDSS_MDP_REG_WRITE(offset + 12, 0);
+ }
+ }
+ if (flags & PP_FLAGS_DIRTY_DITHER) {
+ dither_cfg = &mdss_pp_res->dither_disp_cfg[disp_num];
+ if (dither_cfg->flags & MDP_PP_OPS_WRITE) {
+ offset = base + MDSS_MDP_REG_DSPP_DITHER_DEPTH;
+ MDSS_MDP_REG_WRITE(offset,
+ dither_depth_map[dither_cfg->g_y_depth] |
+ (dither_depth_map[dither_cfg->b_cb_depth] << 2) |
+ (dither_depth_map[dither_cfg->r_cr_depth] << 4));
+ offset += 0x14;
+ for (i = 0; i << 16; i += 4) {
+ data = dither_matrix[i] |
+ (dither_matrix[i + 1] << 4) |
+ (dither_matrix[i + 2] << 8) |
+ (dither_matrix[i + 3] << 12);
+ MDSS_MDP_REG_WRITE(offset, data);
+ offset += 4;
+ }
+ }
+ if (dither_cfg->flags & MDP_PP_OPS_DISABLE)
+ pp_sts->dither_sts &= ~PP_STS_ENABLE;
+ else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
+ pp_sts->dither_sts |= PP_STS_ENABLE;
+ }
+ if (pp_sts->dither_sts & PP_STS_ENABLE)
+ opmode |= (1 << 8); /* DITHER_EN */
+ if (flags & PP_FLAGS_DIRTY_GAMUT)
+ pp_gamut_config(&mdss_pp_res->gamut_disp_cfg[disp_num],
+ base, &pp_sts->gamut_sts);
+ if (pp_sts->gamut_sts & PP_STS_ENABLE) {
+ opmode |= (1 << 23); /* GAMUT_EN */
+ if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
+ opmode |= (1 << 24); /* GAMUT_ORDER */
+ }
+
MDSS_MDP_REG_WRITE(base + MDSS_MDP_REG_DSPP_OP_MODE, opmode);
ctl->flush_bits |= BIT(13 + dspp_num); /* DSPP */
return 0;
-
}
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
{
@@ -239,10 +535,14 @@
disp_num = ctl->mfd->index;
mutex_lock(&mdss_pp_mutex);
- if (ctl->mixer_left)
+ if (ctl->mixer_left) {
+ pp_mixer_setup(disp_num, ctl, ctl->mixer_left);
pp_dspp_setup(disp_num, ctl, ctl->mixer_left);
- if (ctl->mixer_right)
+ }
+ if (ctl->mixer_right) {
+ pp_mixer_setup(disp_num, ctl, ctl->mixer_right);
pp_dspp_setup(disp_num, ctl, ctl->mixer_right);
+ }
/* clear dirty flag */
if (disp_num < MDSS_BLOCK_DISP_NUM)
mdss_pp_res->pp_disp_flags[disp_num] = 0;
@@ -275,12 +575,31 @@
mutex_unlock(&mdss_pp_mutex);
}
}
+static int pp_get_dspp_num(u32 disp_num, u32 *dspp_num)
+{
+ int i;
+ u32 mixer_cnt;
+ u32 mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+ mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+ if (!mixer_cnt)
+ return -EPERM;
+
+ /* only read the first mixer */
+ for (i = 0; i < mixer_cnt; i++) {
+ if (mixer_id[i] < MDSS_MDP_MAX_DSPP)
+ break;
+ }
+ if (i >= mixer_cnt)
+ return -EPERM;
+ *dspp_num = mixer_id[i];
+ return 0;
+}
int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback)
{
- int i, ret = 0;
- u32 pa_offset, disp_num, mixer_cnt;
- u32 mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+ int ret = 0;
+ u32 pa_offset, disp_num, dspp_num = 0;
if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
(config->block >= MDP_BLOCK_MAX))
@@ -290,24 +609,15 @@
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
if (config->flags & MDP_PP_OPS_READ) {
- mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
- if (!mixer_cnt) {
- ret = -EPERM;
- goto pa_config_exit;
- }
- /* only read the first mixer */
- for (i = 0; i < mixer_cnt; i++) {
- if (mixer_id[i] < MDSS_MDP_MAX_DSPP)
- break;
- }
- if (i >= mixer_cnt) {
- ret = -EPERM;
+ ret = pp_get_dspp_num(disp_num, &dspp_num);
+ if (ret) {
+ pr_err("%s, no dspp connects to disp %d",
+ __func__, disp_num);
goto pa_config_exit;
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- pa_offset = MDSS_MDP_REG_DSPP_OFFSET(mixer_id[i]) +
+ pa_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
MDSS_MDP_REG_DSPP_PA_BASE;
-
config->hue_adj = MDSS_MDP_REG_READ(pa_offset);
pa_offset += 4;
config->sat_adj = MDSS_MDP_REG_READ(pa_offset);
@@ -326,3 +636,910 @@
mutex_unlock(&mdss_pp_mutex);
return ret;
}
+
+static void pp_read_pcc_regs(u32 offset,
+ struct mdp_pcc_cfg_data *cfg_ptr)
+{
+ cfg_ptr->r.c = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.c = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.c = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.r = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.r = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.r = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.g = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.g = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.g = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.b = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.b = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.b = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.rr = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.rr = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.rr = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.rg = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.rg = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.rg = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.rb = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.rb = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.rb = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.gg = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.gg = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.gg = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.gb = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.gb = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.gb = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.bb = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.bb = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.bb = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.rgb_0 = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.rgb_0 = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.rgb_0 = MDSS_MDP_REG_READ(offset + 8);
+ offset += 0x10;
+
+ cfg_ptr->r.rgb_1 = MDSS_MDP_REG_READ(offset);
+ cfg_ptr->g.rgb_1 = MDSS_MDP_REG_READ(offset + 4);
+ cfg_ptr->b.rgb_1 = MDSS_MDP_REG_READ(offset + 8);
+}
+
+static void pp_update_pcc_regs(u32 offset,
+ struct mdp_pcc_cfg_data *cfg_ptr)
+{
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.c);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.c);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.c);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.r);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.r);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.r);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.g);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.g);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.g);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.b);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.b);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.b);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rr);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rr);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rr);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rg);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rg);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rg);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rb);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rb);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rb);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.gg);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.gg);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.gg);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.gb);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.gb);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.gb);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.bb);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.bb);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.bb);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rgb_0);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rgb_0);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_0);
+ offset += 0x10;
+
+ MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rgb_1);
+ MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rgb_1);
+ MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_1);
+}
+
+int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *config, u32 *copyback)
+{
+ int ret = 0;
+ u32 base, disp_num, dspp_num = 0;
+
+ if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (config->block >= MDP_BLOCK_MAX))
+ return -EINVAL;
+
+ mutex_lock(&mdss_pp_mutex);
+ disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+ if (config->ops & MDP_PP_OPS_READ) {
+ ret = pp_get_dspp_num(disp_num, &dspp_num);
+ if (ret) {
+ pr_err("%s, no dspp connects to disp %d",
+ __func__, disp_num);
+ goto pcc_config_exit;
+ }
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+ MDSS_MDP_REG_DSPP_PCC_BASE;
+ pp_read_pcc_regs(base, config);
+ *copyback = 1;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ } else {
+ mdss_pp_res->pcc_disp_cfg[disp_num] = *config;
+ mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PCC;
+ }
+
+pcc_config_exit:
+ mutex_unlock(&mdss_pp_mutex);
+ return ret;
+
+}
+
+static void pp_read_igc_lut(struct mdp_igc_lut_data *cfg,
+ u32 offset, u32 blk_idx)
+{
+ int i;
+ u32 data;
+
+ /* INDEX_UPDATE & VALUE_UPDATEN */
+ data = (3 << 24) | (((~(1 << blk_idx)) & 0x7) << 28);
+ MDSS_MDP_REG_WRITE(offset, data);
+
+ for (i = 0; i < cfg->len; i++)
+ cfg->c0_c1_data[i] = MDSS_MDP_REG_READ(offset) & 0xFFF;
+
+ offset += 0x4;
+ MDSS_MDP_REG_WRITE(offset, data);
+ for (i = 0; i < cfg->len; i++)
+ cfg->c0_c1_data[i] |= (MDSS_MDP_REG_READ(offset) & 0xFFF) << 16;
+
+ offset += 0x4;
+ MDSS_MDP_REG_WRITE(offset, data);
+ for (i = 0; i < cfg->len; i++)
+ cfg->c2_data[i] = MDSS_MDP_REG_READ(offset) & 0xFFF;
+}
+
+static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
+ u32 offset, u32 blk_idx)
+{
+ int i;
+ u32 data;
+ /* INDEX_UPDATE */
+ data = (1 << 25) | (((~(1 << blk_idx)) & 0x7) << 28);
+ MDSS_MDP_REG_WRITE(offset, (cfg->c0_c1_data[0] & 0xFFF) | data);
+
+ /* disable index update */
+ data &= ~(1 << 25);
+ for (i = 1; i < cfg->len; i++)
+ MDSS_MDP_REG_WRITE(offset, (cfg->c0_c1_data[i] & 0xFFF) | data);
+
+ offset += 0x4;
+ data |= (1 << 25);
+ MDSS_MDP_REG_WRITE(offset, ((cfg->c0_c1_data[0] >> 16) & 0xFFF) | data);
+ data &= ~(1 << 25);
+ for (i = 1; i < cfg->len; i++)
+ MDSS_MDP_REG_WRITE(offset,
+ ((cfg->c0_c1_data[i] >> 16) & 0xFFF) | data);
+
+ offset += 0x4;
+ data |= (1 << 25);
+ MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[0] & 0xFFF) | data);
+ data &= ~(1 << 25);
+ for (i = 1; i < cfg->len; i++)
+ MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
+}
+
+int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback)
+{
+ int ret = 0;
+ u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
+ struct mdp_igc_lut_data local_cfg;
+
+ if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (config->block >= MDP_BLOCK_MAX))
+ return -EINVAL;
+
+ mutex_lock(&mdss_pp_mutex);
+ disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+ if (config->ops & MDP_PP_OPS_READ) {
+ ret = pp_get_dspp_num(disp_num, &dspp_num);
+ if (ret) {
+ pr_err("%s, no dspp connects to disp %d",
+ __func__, disp_num);
+ goto igc_config_exit;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ if (config->ops & MDP_PP_IGC_FLAG_ROM0)
+ tbl_idx = 1;
+ else if (config->ops & MDP_PP_IGC_FLAG_ROM1)
+ tbl_idx = 2;
+ else
+ tbl_idx = 0;
+ igc_offset = MDSS_MDP_REG_IGC_DSPP_BASE + (0x10 * tbl_idx);
+ local_cfg = *config;
+ local_cfg.c0_c1_data =
+ &mdss_pp_res->igc_lut_c0c1[disp_num][0];
+ local_cfg.c2_data =
+ &mdss_pp_res->igc_lut_c2[disp_num][0];
+ pp_read_igc_lut(&local_cfg, igc_offset, dspp_num);
+ if (copy_to_user(config->c0_c1_data, local_cfg.c2_data,
+ config->len * sizeof(u32))) {
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
+ if (copy_to_user(config->c2_data, local_cfg.c0_c1_data,
+ config->len * sizeof(u32))) {
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
+ *copyback = 1;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ } else {
+ if (copy_from_user(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
+ config->c0_c1_data, config->len * sizeof(u32))) {
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
+ if (copy_from_user(&mdss_pp_res->igc_lut_c2[disp_num][0],
+ config->c2_data, config->len * sizeof(u32))) {
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
+ mdss_pp_res->igc_disp_cfg[disp_num] = *config;
+ mdss_pp_res->igc_disp_cfg[disp_num].c0_c1_data =
+ &mdss_pp_res->igc_lut_c0c1[disp_num][0];
+ mdss_pp_res->igc_disp_cfg[disp_num].c2_data =
+ &mdss_pp_res->igc_lut_c2[disp_num][0];
+ mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_IGC;
+ }
+
+igc_config_exit:
+ mutex_unlock(&mdss_pp_mutex);
+ return ret;
+}
+static void pp_update_gc_one_lut(u32 offset,
+ struct mdp_ar_gc_lut_data *lut_data)
+{
+ int i, start_idx;
+
+ start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+ for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
+ MDSS_MDP_REG_WRITE(offset, lut_data[i].x_start);
+ for (i = 0; i < start_idx; i++)
+ MDSS_MDP_REG_WRITE(offset, lut_data[i].x_start);
+ offset += 4;
+ start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+ for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
+ MDSS_MDP_REG_WRITE(offset, lut_data[i].slope);
+ for (i = 0; i < start_idx; i++)
+ MDSS_MDP_REG_WRITE(offset, lut_data[i].slope);
+ offset += 4;
+ start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+ for (i = start_idx; i < GC_LUT_SEGMENTS; i++)
+ MDSS_MDP_REG_WRITE(offset, lut_data[i].offset);
+ for (i = 0; i < start_idx; i++)
+ MDSS_MDP_REG_WRITE(offset, lut_data[i].offset);
+}
+static void pp_update_argc_lut(u32 offset, struct mdp_pgc_lut_data *config)
+{
+ pp_update_gc_one_lut(offset, config->r_data);
+ offset += 0x10;
+ pp_update_gc_one_lut(offset, config->g_data);
+ offset += 0x10;
+ pp_update_gc_one_lut(offset, config->b_data);
+}
+static void pp_read_gc_one_lut(u32 offset,
+ struct mdp_ar_gc_lut_data *gc_data)
+{
+ int i, start_idx, data;
+ data = MDSS_MDP_REG_READ(offset);
+ start_idx = (data >> 16) & 0xF;
+ gc_data[start_idx].x_start = data & 0xFFF;
+
+ for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
+ data = MDSS_MDP_REG_READ(offset);
+ gc_data[i].x_start = data & 0xFFF;
+ }
+ for (i = 0; i < start_idx; i++) {
+ data = MDSS_MDP_REG_READ(offset);
+ gc_data[i].x_start = data & 0xFFF;
+ }
+
+ offset += 4;
+ data = MDSS_MDP_REG_READ(offset);
+ start_idx = (data >> 16) & 0xF;
+ gc_data[start_idx].slope = data & 0x7FFF;
+ for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
+ data = MDSS_MDP_REG_READ(offset);
+ gc_data[i].slope = data & 0x7FFF;
+ }
+ for (i = 0; i < start_idx; i++) {
+ data = MDSS_MDP_REG_READ(offset);
+ gc_data[i].slope = data & 0x7FFF;
+ }
+ offset += 4;
+ data = MDSS_MDP_REG_READ(offset);
+ start_idx = (data >> 16) & 0xF;
+ gc_data[start_idx].offset = data & 0x7FFF;
+ for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
+ data = MDSS_MDP_REG_READ(offset);
+ gc_data[i].offset = data & 0x7FFF;
+ }
+ for (i = 0; i < start_idx; i++) {
+ data = MDSS_MDP_REG_READ(offset);
+ gc_data[i].offset = data & 0x7FFF;
+ }
+}
+
+static int pp_read_argc_lut(struct mdp_pgc_lut_data *config, u32 offset)
+{
+ int ret = 0;
+ pp_read_gc_one_lut(offset, config->r_data);
+ offset += 0x10;
+ pp_read_gc_one_lut(offset, config->g_data);
+ offset += 0x10;
+ pp_read_gc_one_lut(offset, config->b_data);
+ return ret;
+}
+int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config, u32 *copyback)
+{
+ int ret = 0;
+ u32 argc_offset, disp_num, dspp_num = 0;
+ struct mdp_pgc_lut_data local_cfg;
+ u32 tbl_size;
+
+ if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (config->block >= MDP_BLOCK_MAX))
+ return -EINVAL;
+
+ mutex_lock(&mdss_pp_mutex);
+ disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+ tbl_size = GC_LUT_SEGMENTS * sizeof(struct mdp_ar_gc_lut_data);
+ if (config->flags & MDP_PP_OPS_READ) {
+ ret = pp_get_dspp_num(disp_num, &dspp_num);
+ if (ret) {
+ pr_err("%s, no dspp connects to disp %d",
+ __func__, disp_num);
+ goto argc_config_exit;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ argc_offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
+ MDSS_MDP_REG_LM_GC_LUT_BASE;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ local_cfg = *config;
+ local_cfg.r_data =
+ &mdss_pp_res->gc_lut_r[disp_num][0];
+ local_cfg.g_data =
+ &mdss_pp_res->gc_lut_g[disp_num][0];
+ local_cfg.b_data =
+ &mdss_pp_res->gc_lut_b[disp_num][0];
+ pp_read_argc_lut(&local_cfg, argc_offset);
+ if (copy_to_user(config->r_data,
+ &mdss_pp_res->gc_lut_r[disp_num][0], tbl_size)) {
+ ret = -EFAULT;
+ goto argc_config_exit;
+ }
+ if (copy_to_user(config->g_data,
+ &mdss_pp_res->gc_lut_g[disp_num][0], tbl_size)) {
+ ret = -EFAULT;
+ goto argc_config_exit;
+ }
+ if (copy_to_user(config->b_data,
+ &mdss_pp_res->gc_lut_b[disp_num][0], tbl_size)) {
+ ret = -EFAULT;
+ goto argc_config_exit;
+ }
+ *copyback = 1;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ } else {
+ if (copy_from_user(&mdss_pp_res->gc_lut_r[disp_num][0],
+ config->r_data, tbl_size)) {
+ ret = -EFAULT;
+ goto argc_config_exit;
+ }
+ if (copy_from_user(&mdss_pp_res->gc_lut_g[disp_num][0],
+ config->g_data, tbl_size)) {
+ ret = -EFAULT;
+ goto argc_config_exit;
+ }
+ if (copy_from_user(&mdss_pp_res->gc_lut_b[disp_num][0],
+ config->b_data, tbl_size)) {
+ ret = -EFAULT;
+ goto argc_config_exit;
+ }
+ mdss_pp_res->pgc_disp_cfg[disp_num] = *config;
+ mdss_pp_res->pgc_disp_cfg[disp_num].r_data =
+ &mdss_pp_res->gc_lut_r[disp_num][0];
+ mdss_pp_res->pgc_disp_cfg[disp_num].g_data =
+ &mdss_pp_res->gc_lut_g[disp_num][0];
+ mdss_pp_res->pgc_disp_cfg[disp_num].b_data =
+ &mdss_pp_res->gc_lut_b[disp_num][0];
+ mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_ARGC;
+ }
+argc_config_exit:
+ mutex_unlock(&mdss_pp_mutex);
+ return ret;
+}
+int mdss_mdp_hist_lut_config(struct mdp_hist_lut_data *config, u32 *copyback)
+{
+ int i, ret = 0;
+ u32 hist_offset, disp_num, dspp_num = 0;
+
+ if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (config->block >= MDP_BLOCK_MAX))
+ return -EINVAL;
+
+ mutex_lock(&mdss_pp_mutex);
+ disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+ if (config->ops & MDP_PP_OPS_READ) {
+ ret = pp_get_dspp_num(disp_num, &dspp_num);
+ if (ret) {
+ pr_err("%s, no dspp connects to disp %d",
+ __func__, disp_num);
+ goto enhist_config_exit;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ hist_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+ MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
+ for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
+ mdss_pp_res->enhist_lut[disp_num][i] =
+ MDSS_MDP_REG_READ(hist_offset);
+ if (copy_to_user(config->data,
+ &mdss_pp_res->enhist_lut[disp_num][0],
+ ENHIST_LUT_ENTRIES * sizeof(u32))) {
+ ret = -EFAULT;
+ goto enhist_config_exit;
+ }
+ *copyback = 1;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ } else {
+ if (copy_from_user(&mdss_pp_res->enhist_lut[disp_num][0],
+ config->data, ENHIST_LUT_ENTRIES * sizeof(u32))) {
+ ret = -EFAULT;
+ goto enhist_config_exit;
+ }
+ mdss_pp_res->enhist_disp_cfg[disp_num] = *config;
+ mdss_pp_res->enhist_disp_cfg[disp_num].data =
+ &mdss_pp_res->enhist_lut[disp_num][0];
+ mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_ENHIST;
+ }
+enhist_config_exit:
+ mutex_unlock(&mdss_pp_mutex);
+ return ret;
+}
+
+int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback)
+{
+ u32 disp_num;
+ if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (config->block >= MDP_BLOCK_MAX))
+ return -EINVAL;
+ if (config->flags & MDP_PP_OPS_READ)
+ return -ENOTSUPP;
+
+ mutex_lock(&mdss_pp_mutex);
+ disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+ mdss_pp_res->dither_disp_cfg[disp_num] = *config;
+ mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_DITHER;
+ mutex_unlock(&mdss_pp_mutex);
+ return 0;
+}
+
+int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback)
+{
+ int i, j, size_total = 0, ret = 0;
+ u32 offset, disp_num, dspp_num = 0;
+ uint16_t *tbl_off;
+ struct mdp_gamut_cfg_data local_cfg;
+
+ if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (config->block >= MDP_BLOCK_MAX))
+ return -EINVAL;
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++)
+ size_total += config->tbl_size[i];
+ if (size_total != GAMUT_TOTAL_TABLE_SIZE)
+ return -EINVAL;
+
+ mutex_lock(&mdss_pp_mutex);
+ disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
+
+ if (config->flags & MDP_PP_OPS_READ) {
+ ret = pp_get_dspp_num(disp_num, &dspp_num);
+ if (ret) {
+ pr_err("%s, no dspp connects to disp %d",
+ __func__, disp_num);
+ goto gamut_config_exit;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+ MDSS_MDP_REG_DSPP_GAMUT_BASE;
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ for (j = 0; j < config->tbl_size[i]; j++)
+ config->r_tbl[i][j] =
+ (u16)MDSS_MDP_REG_READ(offset);
+ offset += 4;
+ }
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ for (j = 0; j < config->tbl_size[i]; j++)
+ config->g_tbl[i][j] =
+ (u16)MDSS_MDP_REG_READ(offset);
+ offset += 4;
+ }
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ for (j = 0; j < config->tbl_size[i]; j++)
+ config->b_tbl[i][j] =
+ (u16)MDSS_MDP_REG_READ(offset);
+ offset += 4;
+ }
+ *copyback = 1;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ } else {
+ local_cfg = *config;
+ tbl_off = mdss_pp_res->gamut_tbl[disp_num];
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ local_cfg.r_tbl[i] = tbl_off;
+ if (copy_from_user(tbl_off, config->r_tbl[i],
+ config->tbl_size[i] * sizeof(uint16_t))) {
+ ret = -EFAULT;
+ goto gamut_config_exit;
+ }
+ tbl_off += local_cfg.tbl_size[i];
+ }
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ local_cfg.g_tbl[i] = tbl_off;
+ if (copy_from_user(tbl_off, config->g_tbl[i],
+ config->tbl_size[i] * sizeof(uint16_t))) {
+ ret = -EFAULT;
+ goto gamut_config_exit;
+ }
+ tbl_off += local_cfg.tbl_size[i];
+ }
+ for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
+ local_cfg.b_tbl[i] = tbl_off;
+ if (copy_from_user(tbl_off, config->b_tbl[i],
+ config->tbl_size[i] * sizeof(uint16_t))) {
+ ret = -EFAULT;
+ goto gamut_config_exit;
+ }
+ tbl_off += local_cfg.tbl_size[i];
+ }
+ mdss_pp_res->gamut_disp_cfg[disp_num] = local_cfg;
+ mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_GAMUT;
+ }
+gamut_config_exit:
+ mutex_unlock(&mdss_pp_mutex);
+ return ret;
+}
+static void pp_hist_read(u32 v_base, struct pp_hist_col_info *hist_info)
+{
+ int i, i_start;
+ u32 data;
+ data = MDSS_MDP_REG_READ(v_base);
+ i_start = data >> 24;
+ hist_info->data[i_start] = data & 0xFFFFFF;
+ for (i = i_start + 1; i < HIST_V_SIZE; i++)
+ hist_info->data[i] = MDSS_MDP_REG_READ(v_base) & 0xFFFFFF;
+ for (i = 0; i < i_start - 1; i++)
+ hist_info->data[i] = MDSS_MDP_REG_READ(v_base) & 0xFFFFFF;
+ hist_info->hist_cnt_read++;
+}
+
+int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
+{
+ u32 ctl_base, done_shift_bit;
+ struct pp_hist_col_info *hist_info;
+ int i, ret = 0;
+ u32 disp_num, dspp_num = 0;
+ u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+
+ if ((req->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (req->block >= MDP_BLOCK_MAX))
+ return -EINVAL;
+
+ mutex_lock(&mdss_mdp_hist_mutex);
+ disp_num = req->block - MDP_LOGICAL_BLOCK_DISP_0;
+ mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+ if (!mixer_cnt) {
+ pr_err("%s, no dspp connects to disp %d",
+ __func__, disp_num);
+ ret = -EPERM;
+ goto hist_start_exit;
+ }
+ if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
+ pr_err("%s, Too many dspp connects to disp %d",
+ __func__, mixer_cnt);
+ ret = -EPERM;
+ goto hist_start_exit;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ for (i = 0; i < mixer_cnt; i++) {
+ dspp_num = mixer_id[i];
+ hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+ done_shift_bit = (dspp_num * 4) + 12;
+ /* check if it is idle */
+ if (hist_info->col_en) {
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ pr_info("%s Hist collection has already been enabled %d",
+ __func__, dspp_num);
+ goto hist_start_exit;
+ }
+ spin_lock(&mdss_hist_lock);
+ hist_info->frame_cnt = req->frame_cnt;
+ init_completion(&hist_info->comp);
+ hist_info->hist_cnt_read = 0;
+ hist_info->hist_cnt_sent = 0;
+ hist_info->read_request = false;
+ hist_info->col_state = HIST_RESET;
+ hist_info->col_en = true;
+ spin_unlock(&mdss_hist_lock);
+ mdss_pp_res->hist_col[disp_num][i] =
+ &mdss_pp_res->dspp_hist[dspp_num];
+ mdss_mdp_hist_irq_enable(3 << done_shift_bit);
+ ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+ MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+ MDSS_MDP_REG_WRITE(ctl_base + 8, req->frame_cnt);
+ /* Kick out reset start */
+ MDSS_MDP_REG_WRITE(ctl_base + 4, 1);
+ }
+ for (i = mixer_cnt; i < MDSS_MDP_MAX_DSPP; i++)
+ mdss_pp_res->hist_col[disp_num][i] = 0;
+ mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_HIST_COL;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+hist_start_exit:
+ mutex_unlock(&mdss_mdp_hist_mutex);
+ return ret;
+}
+
+int mdss_mdp_histogram_stop(u32 block)
+{
+ int i, ret = 0;
+ u32 dspp_num, disp_num, ctl_base, done_bit;
+ struct pp_hist_col_info *hist_info;
+ u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+
+ if ((block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (block >= MDP_BLOCK_MAX))
+ return -EINVAL;
+
+ mutex_lock(&mdss_mdp_hist_mutex);
+ disp_num = block - MDP_LOGICAL_BLOCK_DISP_0;
+ mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+ if (!mixer_cnt) {
+ pr_err("%s, no dspp connects to disp %d",
+ __func__, disp_num);
+ ret = -EPERM;
+ goto hist_stop_exit;
+ }
+ if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
+ pr_err("%s, Too many dspp connects to disp %d",
+ __func__, mixer_cnt);
+ ret = -EPERM;
+ goto hist_stop_exit;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ for (i = 0; i < mixer_cnt; i++) {
+ dspp_num = mixer_id[i];
+ hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+ done_bit = 3 << ((dspp_num * 4) + 12);
+ ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+ MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+ if (hist_info->col_en == false) {
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ goto hist_stop_exit;
+ }
+ complete_all(&hist_info->comp);
+ spin_lock(&mdss_hist_lock);
+ hist_info->col_en = false;
+ hist_info->col_state = HIST_UNKNOWN;
+ spin_unlock(&mdss_hist_lock);
+ mdss_mdp_hist_irq_disable(done_bit);
+ MDSS_MDP_REG_WRITE(ctl_base, (1 << 1));/* cancel */
+ }
+ for (i = 0; i < MDSS_MDP_MAX_DSPP; i++)
+ mdss_pp_res->hist_col[disp_num][i] = 0;
+ mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_HIST_COL;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+hist_stop_exit:
+ mutex_unlock(&mdss_mdp_hist_mutex);
+ return ret;
+}
+
+int mdss_mdp_hist_collect(struct fb_info *info,
+ struct mdp_histogram_data *hist, u32 *hist_data_addr)
+{
+ int i, j, wait_ret, ret = 0;
+ u32 timeout, v_base;
+ struct pp_hist_col_info *hist_info;
+ u32 dspp_num, disp_num, ctl_base;
+ u32 mixer_cnt, mixer_id[MDSS_MDP_MAX_LAYERMIXER];
+
+ if ((hist->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+ (hist->block >= MDP_BLOCK_MAX))
+ return -EINVAL;
+
+ mutex_lock(&mdss_mdp_hist_mutex);
+ disp_num = hist->block - MDP_LOGICAL_BLOCK_DISP_0;
+ mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+
+ if (!mixer_cnt) {
+ pr_err("%s, no dspp connects to disp %d",
+ __func__, disp_num);
+ ret = -EPERM;
+ goto hist_collect_exit;
+ }
+ if (mixer_cnt >= MDSS_MDP_MAX_DSPP) {
+ pr_err("%s, Too many dspp connects to disp %d",
+ __func__, mixer_cnt);
+ ret = -EPERM;
+ goto hist_collect_exit;
+ }
+ hist_info = &mdss_pp_res->dspp_hist[0];
+ for (i = 0; i < mixer_cnt; i++) {
+ dspp_num = mixer_id[i];
+ hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+ ctl_base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+ MDSS_MDP_REG_DSPP_HIST_CTL_BASE;
+ if ((hist_info->col_en == 0) ||
+ (hist_info->col_state == HIST_UNKNOWN)) {
+ ret = -EINVAL;
+ goto hist_collect_exit;
+ }
+ spin_lock(&mdss_hist_lock);
+ if ((hist_info->col_state == HIST_READY) ||
+ (hist_info->hist_cnt_read == 0)) {
+ /* wait for hist done if cache has no data */
+ if ((hist_info->col_state != HIST_READY) &&
+ (hist_info->hist_cnt_read == 0)) {
+ hist_info->read_request = true;
+ spin_unlock(&mdss_hist_lock);
+ timeout = HIST_WAIT_TIMEOUT *
+ hist_info->frame_cnt;
+ mutex_unlock(&mdss_mdp_hist_mutex);
+ wait_ret = wait_for_completion_killable_timeout(
+ &(hist_info->comp), timeout);
+
+ mutex_lock(&mdss_mdp_hist_mutex);
+ hist_info->read_request = false;
+ if (wait_ret == 0) {
+ ret = -ETIMEDOUT;
+ pr_debug("%s: bin collection timedout",
+ __func__);
+ goto hist_collect_exit;
+ } else if (wait_ret < 0) {
+ ret = -EINTR;
+ pr_debug("%s: bin collection interrupted",
+ __func__);
+ goto hist_collect_exit;
+ }
+ if (hist_info->col_state != HIST_READY) {
+ ret = -EBUSY;
+ pr_err("%s: collection state is not ready: %d",
+ __func__, hist_info->col_state);
+ goto hist_collect_exit;
+ }
+ } else {
+ spin_unlock(&mdss_hist_lock);
+ }
+ if (hist_info->col_state == HIST_READY) {
+ v_base = ctl_base + 0x1C;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ pp_hist_read(v_base, hist_info);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ spin_lock(&mdss_hist_lock);
+ hist_info->col_state = HIST_IDLE;
+ spin_unlock(&mdss_hist_lock);
+ }
+ } else {
+ spin_unlock(&mdss_hist_lock);
+ }
+ hist_info->hist_cnt_sent = hist_info->hist_cnt_read;
+ }
+ if (mixer_cnt > 1) {
+ memset(&mdss_pp_res->hist_data[disp_num][0],
+ 0, HIST_V_SIZE * sizeof(u32));
+ for (i = 0; i < mixer_cnt; i++) {
+ dspp_num = mixer_id[i];
+ hist_info = &mdss_pp_res->dspp_hist[dspp_num];
+ for (j = 0; j < HIST_V_SIZE; j++)
+ mdss_pp_res->hist_data[disp_num][i] +=
+ hist_info->data[i];
+ }
+ *hist_data_addr = (u32)&mdss_pp_res->hist_data[disp_num][0];
+ } else {
+ *hist_data_addr = (u32)hist_info->data;
+ }
+
+hist_collect_exit:
+ mutex_unlock(&mdss_mdp_hist_mutex);
+ return ret;
+}
+void mdss_mdp_hist_intr_done(u32 isr)
+{
+ u32 isr_blk, blk_idx;
+ struct pp_hist_col_info *hist_info;
+ isr &= 0x333333;
+ while (isr != 0) {
+ if (isr & 0xFFF000) {
+ if (isr & 0x3000) {
+ blk_idx = 0;
+ isr_blk = (isr >> 12) & 0x3;
+ isr &= ~0x3000;
+ } else if (isr & 0x30000) {
+ blk_idx = 1;
+ isr_blk = (isr >> 16) & 0x3;
+ isr &= ~0x30000;
+ } else {
+ blk_idx = 2;
+ isr_blk = (isr >> 20) & 0x3;
+ isr &= ~0x300000;
+ }
+ hist_info = &mdss_pp_res->dspp_hist[blk_idx];
+ } else {
+ if (isr & 0x3) {
+ blk_idx = 0;
+ isr_blk = isr & 0x3;
+ isr &= ~0x3;
+ } else if (isr & 0x30) {
+ blk_idx = 1;
+ isr_blk = (isr >> 4) & 0x3;
+ isr &= ~0x30;
+ } else {
+ blk_idx = 2;
+ isr_blk = (isr >> 8) & 0x3;
+ isr &= ~0x300;
+ }
+ /* SSPP block, not support yet*/
+ continue;
+ }
+ /* Histogram Done Interrupt */
+ if ((isr_blk & 0x1) &&
+ (hist_info->col_en)) {
+ spin_lock(&mdss_hist_lock);
+ hist_info->col_state = HIST_READY;
+ spin_unlock(&mdss_hist_lock);
+ if (hist_info->read_request)
+ complete(&hist_info->comp);
+ }
+ /* Histogram Reset Done Interrupt */
+ if ((isr_blk & 0x2) &&
+ (hist_info->col_en)) {
+ spin_lock(&mdss_hist_lock);
+ hist_info->col_state = HIST_IDLE;
+ spin_unlock(&mdss_hist_lock);
+ }
+ };
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 1e4b81e0..eb5b47a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -17,7 +17,7 @@
#include "mdss_mdp.h"
-#define MDSS_MDP_ROT_SESSION_MASK 0x80000000
+#define MDSS_MDP_ROT_SESSION_MASK 0x40000000
struct mdss_mdp_rotator_session {
u32 session_id;
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 57e8441..95c92fc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -112,22 +112,22 @@
irqreturn_t mdss_mdp_isr(int irq, void *ptr)
{
- u32 isr, mask;
+ u32 isr, mask, hist_isr, hist_mask;
isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_STATUS);
- pr_debug("isr=%x\n", isr);
-
if (isr == 0)
- goto done;
+ goto mdp_isr_done;
+
+ pr_debug("isr=%x\n", isr);
mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
isr &= mask;
if (isr == 0)
- goto done;
+ goto mdp_isr_done;
if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE)
mdss_mdp_intr_done(MDP_INTR_PING_PONG_0);
@@ -159,7 +159,17 @@
if (isr & MDSS_MDP_INTR_WB_2_DONE)
mdss_mdp_intr_done(MDP_INTR_WB_2);
-done:
+mdp_isr_done:
+ hist_isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_STATUS);
+ if (hist_isr == 0)
+ goto hist_isr_done;
+ hist_mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_EN);
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_HIST_INTR_CLEAR, hist_isr);
+ hist_isr &= hist_mask;
+ if (hist_isr == 0)
+ goto hist_isr_done;
+ mdss_mdp_hist_intr_done(hist_isr);
+hist_isr_done:
return IRQ_HANDLED;
}
@@ -203,7 +213,7 @@
} else {
u8 hmap[] = { 1, 2, 1, 2 };
u8 vmap[] = { 1, 1, 2, 2 };
- u8 horiz, vert, stride_align;
+ u8 horiz, vert, stride_align, height_align;
horiz = hmap[fmt->chroma_sample];
vert = vmap[fmt->chroma_sample];
@@ -211,18 +221,21 @@
switch (format) {
case MDP_Y_CR_CB_GH2V2:
stride_align = 16;
+ height_align = 1;
break;
case MDP_Y_CBCR_H2V2_VENUS:
stride_align = 32;
+ height_align = 32;
break;
default:
stride_align = 1;
+ height_align = 1;
break;
}
ps->ystride[0] = ALIGN(w, stride_align);
ps->ystride[1] = ALIGN(w / horiz, stride_align);
- ps->plane_size[0] = ps->ystride[0] * h;
+ ps->plane_size[0] = ps->ystride[0] * ALIGN(h, height_align);
ps->plane_size[1] = ps->ystride[1] * (h / vert);
if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index b0a67938..b18efbe 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -86,13 +86,13 @@
ihdl = ion_alloc(iclient, img_size, SZ_4K,
- ION_HEAP(ION_SF_HEAP_ID));
+ ION_HEAP(ION_SF_HEAP_ID), 0);
if (IS_ERR_OR_NULL(ihdl)) {
pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
return NULL;
}
- videomemory = ion_map_kernel(iclient, ihdl, 0);
+ videomemory = ion_map_kernel(iclient, ihdl);
ion_phys(iclient, ihdl, &mdss_wb_mem, &img_size);
if (is_mdss_iommu_attached()) {
diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c
index 2b75193..60311dc 100644
--- a/drivers/video/msm/mipi_dsi_host.c
+++ b/drivers/video/msm/mipi_dsi_host.c
@@ -25,6 +25,7 @@
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/iopoll.h>
#include <asm/system.h>
#include <asm/mach-types.h>
@@ -964,31 +965,30 @@
uint32 dsi_ctrl;
uint32 status;
- int cnt;
+ u32 sleep_us = 1000;
+ u32 timeout_us = 16000;
- cnt = 16;
- while (cnt--) {
- status = MIPI_INP(MIPI_DSI_BASE + 0x0004);
- status &= 0x02; /* CMD_MODE_DMA_BUSY */
- if (status == 0)
- break;
- usleep(1000);
- }
- if (cnt == 0)
+ /* Check for CMD_MODE_DMA_BUSY */
+ if (readl_poll_timeout((MIPI_DSI_BASE + 0x0004),
+ status,
+ ((status & 0x02) == 0),
+ sleep_us, timeout_us))
pr_info("%s: DSI status=%x failed\n", __func__, status);
- cnt = 16;
- while (cnt--) {
- status = MIPI_INP(MIPI_DSI_BASE + 0x0008);
- status &= 0x11111000; /* x_HS_FIFO_EMPTY */
- if (status == 0x11111000) /* all empty */
- break;
- usleep(1000);
- }
-
- if (cnt == 0)
+ /* Check for x_HS_FIFO_EMPTY */
+ if (readl_poll_timeout((MIPI_DSI_BASE + 0x0008),
+ status,
+ ((status & 0x11111000) == 0x11111000),
+ sleep_us, timeout_us))
pr_info("%s: FIFO status=%x failed\n", __func__, status);
+ /* Check for VIDEO_MODE_ENGINE_BUSY */
+ if (readl_poll_timeout((MIPI_DSI_BASE + 0x0004),
+ status,
+ ((status & 0x08) == 0),
+ sleep_us, timeout_us))
+ pr_info("%s: DSI status=%x failed\n", __func__, status);
+
dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000);
if (enable)
dsi_ctrl |= 0x01;
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 9c55fe8..1994b1b 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -185,8 +185,9 @@
if (!bl_lvl && value)
bl_lvl = 1;
-
+ down(&mfd->sem);
msm_fb_set_backlight(mfd, bl_lvl);
+ up(&mfd->sem);
}
static struct led_classdev backlight_led = {
@@ -809,7 +810,9 @@
struct mdp_bl_scale_data *data)
{
int ret = 0;
- int curr_bl = mfd->bl_level;
+ int curr_bl;
+ down(&mfd->sem);
+ curr_bl = mfd->bl_level;
bl_scale = data->scale;
bl_min_lvl = data->min_lvl;
pr_debug("%s: update scale = %d, min_lvl = %d\n", __func__, bl_scale,
@@ -817,6 +820,7 @@
/* update current backlight to use new scaling*/
msm_fb_set_backlight(mfd, curr_bl);
+ up(&mfd->sem);
return ret;
}
@@ -824,6 +828,7 @@
static void msm_fb_scale_bl(__u32 *bl_lvl)
{
__u32 temp = *bl_lvl;
+ pr_debug("%s: input = %d, scale = %d", __func__, temp, bl_scale);
if (temp >= bl_min_lvl) {
/* bl_scale is the numerator of scaling fraction (x/1024)*/
temp = ((*bl_lvl) * bl_scale) / 1024;
@@ -832,10 +837,12 @@
if (temp < bl_min_lvl)
temp = bl_min_lvl;
}
+ pr_debug("%s: output = %d", __func__, temp);
(*bl_lvl) = temp;
}
+/*must call this function from within mfd->sem*/
void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl)
{
struct msm_fb_panel_data *pdata;
@@ -847,20 +854,17 @@
unset_bl_level = 0;
}
- msm_fb_scale_bl(&temp);
pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
if ((pdata) && (pdata->set_backlight)) {
- down(&mfd->sem);
+ msm_fb_scale_bl(&temp);
if (bl_level_old == temp) {
- up(&mfd->sem);
return;
}
mfd->bl_level = temp;
pdata->set_backlight(mfd);
mfd->bl_level = bkl_lvl;
bl_level_old = temp;
- up(&mfd->sem);
}
}
@@ -2957,6 +2961,19 @@
return ret;
}
+static int msmfb_overlay_commit(struct fb_info *info, unsigned long *argp)
+{
+ int ret, ndx;
+
+ ret = copy_from_user(&ndx, argp, sizeof(ndx));
+ if (ret) {
+ pr_err("%s: ioctl failed\n", __func__);
+ return ret;
+ }
+
+ return mdp4_overlay_commit(info, ndx);
+}
+
static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)
{
int ret;
@@ -3376,49 +3393,36 @@
switch (cmd) {
#ifdef CONFIG_FB_MSM_OVERLAY
case MSMFB_OVERLAY_GET:
- down(&msm_fb_ioctl_ppp_sem);
ret = msmfb_overlay_get(info, argp);
- up(&msm_fb_ioctl_ppp_sem);
break;
case MSMFB_OVERLAY_SET:
- down(&msm_fb_ioctl_ppp_sem);
ret = msmfb_overlay_set(info, argp);
- up(&msm_fb_ioctl_ppp_sem);
break;
case MSMFB_OVERLAY_UNSET:
- down(&msm_fb_ioctl_ppp_sem);
ret = msmfb_overlay_unset(info, argp);
+ break;
+ case MSMFB_OVERLAY_COMMIT:
+ down(&msm_fb_ioctl_ppp_sem);
+ ret = msmfb_overlay_commit(info, argp);
up(&msm_fb_ioctl_ppp_sem);
break;
case MSMFB_OVERLAY_PLAY:
- down(&msm_fb_ioctl_ppp_sem);
ret = msmfb_overlay_play(info, argp);
- up(&msm_fb_ioctl_ppp_sem);
break;
case MSMFB_OVERLAY_PLAY_ENABLE:
- down(&msm_fb_ioctl_ppp_sem);
ret = msmfb_overlay_play_enable(info, argp);
- up(&msm_fb_ioctl_ppp_sem);
break;
case MSMFB_OVERLAY_PLAY_WAIT:
- down(&msm_fb_ioctl_ppp_sem);
ret = msmfb_overlay_play_wait(info, argp);
- up(&msm_fb_ioctl_ppp_sem);
break;
case MSMFB_OVERLAY_BLT:
- down(&msm_fb_ioctl_ppp_sem);
ret = msmfb_overlay_blt(info, argp);
- up(&msm_fb_ioctl_ppp_sem);
break;
case MSMFB_OVERLAY_3D:
- down(&msm_fb_ioctl_ppp_sem);
ret = msmfb_overlay_3d_sbys(info, argp);
- up(&msm_fb_ioctl_ppp_sem);
break;
case MSMFB_MIXER_INFO:
- down(&msm_fb_ioctl_ppp_sem);
ret = msmfb_mixer_info(info, argp);
- up(&msm_fb_ioctl_ppp_sem);
break;
case MSMFB_WRITEBACK_INIT:
ret = msmfb_overlay_ioctl_writeback_init(info);
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 2896349..7dc89ef 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -37,7 +37,6 @@
#include <linux/fb.h>
#include <linux/list.h>
#include <linux/types.h>
-
#include <linux/msm_mdp.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
@@ -189,6 +188,7 @@
int cont_splash_done;
void *copy_splash_buf;
unsigned char *copy_splash_phys;
+ void *cpu_pm_hdl;
};
struct dentry *msm_fb_get_debugfs_root(void);
diff --git a/drivers/video/msm/msm_fb_bl.c b/drivers/video/msm/msm_fb_bl.c
index 9afbbf1..b21adee 100644
--- a/drivers/video/msm/msm_fb_bl.c
+++ b/drivers/video/msm/msm_fb_bl.c
@@ -34,7 +34,9 @@
bl_lvl = pbd->props.brightness;
bl_lvl = mfd->fbi->bl_curve[bl_lvl];
+ down(&mfd->sem);
msm_fb_set_backlight(mfd, bl_lvl);
+ up(&mfd->sem);
return 0;
}
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index a2c3db1..7fc7a2f 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -168,7 +168,7 @@
__u32 frame_count;
__u32 is_3d_panel;
__u32 frame_rate;
-
+ __u32 frame_interval;
struct mddi_panel_info mddi;
struct lcd_panel_info lcd;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 400a3a7..2a850d8 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -292,6 +292,7 @@
u32 num_slices_comp;
struct vcd_property_slice_delivery_info slice_delivery_info;
struct ddl_batch_frame_data batch_frame;
+ u32 avc_delimiter_enable;
};
struct ddl_decoder_data {
struct ddl_codec_data_hdr hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index d4601f2..1782fd2 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -278,7 +278,8 @@
memset(frame[i].vcd_frm.virtual + luma_size,
0x80808080,
frame[i].vcd_frm.alloc_len - luma_size);
- if (frame[i].vcd_frm.ion_flag == CACHED) {
+ if (frame[i].vcd_frm.ion_flag
+ == ION_FLAG_CACHED) {
msm_ion_do_cache_op(
ddl_context->video_ion_client,
frame[i].vcd_frm.buff_ion_handle,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 931c1c8..d6558c3 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1047,6 +1047,20 @@
case VCD_REQ_PERF_LEVEL:
vcd_status = VCD_S_SUCCESS;
break;
+ case VCD_I_ENABLE_DELIMITER_FLAG:
+ {
+ struct vcd_property_avc_delimiter_enable *delimiter_enable =
+ (struct vcd_property_avc_delimiter_enable *)
+ property_value;
+ if (sizeof(struct vcd_property_avc_delimiter_enable) ==
+ property_hdr->sz &&
+ encoder->codec.codec == VCD_CODEC_H264) {
+ encoder->avc_delimiter_enable =
+ delimiter_enable->avc_delimiter_enable_flag;
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
+ }
default:
DDL_MSG_ERROR("INVALID ID %d\n", (int)property_hdr->prop_id);
vcd_status = VCD_ERR_ILLEGAL_OP;
@@ -1530,6 +1544,15 @@
vcd_status = VCD_S_SUCCESS;
}
break;
+ case VCD_I_ENABLE_DELIMITER_FLAG:
+ if (sizeof(struct vcd_property_avc_delimiter_enable) ==
+ property_hdr->sz) {
+ ((struct vcd_property_avc_delimiter_enable *)
+ property_value)->avc_delimiter_enable_flag =
+ encoder->avc_delimiter_enable;
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
default:
vcd_status = VCD_ERR_ILLEGAL_OP;
break;
@@ -1691,6 +1714,7 @@
encoder->slice_delivery_info.enable = 0;
encoder->slice_delivery_info.num_slices = 0;
encoder->slice_delivery_info.num_slices_enc = 0;
+ encoder->avc_delimiter_enable = 0;
}
static void ddl_set_default_enc_profile(struct ddl_encoder_data *encoder)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 8099234..40dc2aa 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -83,6 +83,8 @@
#define VIDC_SM_ENC_EXT_CTRL_ADDR 0x0028
#define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_BMSK 0xffff0000
#define VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_SHFT 16
+#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK 0x00000800
+#define VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT 11
#define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK 0x80
#define VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT 7
#define VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK 0X100
@@ -446,10 +448,10 @@
*shared_mem, u32 hec_enable,
enum VIDC_SM_frame_skip frame_skip_mode,
u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
- u32 sps_pps_control, u32 closed_gop_enable)
+ u32 sps_pps_control, u32 closed_gop_enable,
+ u32 au_delim_enable)
{
u32 enc_ctrl;
-
enc_ctrl = VIDC_SETFIELD((hec_enable) ? 1 : 0,
VIDC_SM_ENC_EXT_CTRL_HEC_ENABLE_SHFT,
VIDC_SM_ENC_EXT_CTRL_HEC_ENABLE_BMSK) |
@@ -470,7 +472,11 @@
VIDC_SM_ENC_EXT_CTRL_SPS_PPS_CONTROL_BMSK) |
VIDC_SETFIELD(closed_gop_enable,
VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT,
- VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK);
+ VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK) |
+ VIDC_SETFIELD((au_delim_enable) ? 1 : 0,
+ VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_SHFT,
+ VIDC_SM_ENC_EXT_CTRL_AU_DELIMITER_EN_BMSK);
+
DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
}
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 9cb1933..c4d577b 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -106,7 +106,7 @@
struct ddl_buf_addr *shared_mem, u32 hec_enable,
enum VIDC_SM_frame_skip frame_skip_mode, u32 seq_hdr_in_band,
u32 vbv_buffer_size, u32 cpcfc_enable, u32 sps_pps_control,
- u32 closed_gop_enable);
+ u32 closed_gop_enable, u32 au_delim_enable);
void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index 5897a33..31f60e5 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -45,7 +45,6 @@
unsigned long iova = 0;
unsigned long buffer_size = 0;
unsigned long *kernel_vaddr = NULL;
- unsigned long ionflag = 0;
unsigned long flags = 0;
int ret = 0;
ion_phys_addr_t phyaddr = 0;
@@ -71,20 +70,15 @@
alloc_size = (alloc_size+4095) & ~4095;
addr->alloc_handle = ion_alloc(
ddl_context->video_ion_client, alloc_size, SZ_4K,
- res_trk_get_mem_type());
+ res_trk_get_mem_type(), 0);
if (IS_ERR_OR_NULL(addr->alloc_handle)) {
DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
__func__);
goto bail_out;
}
- if (res_trk_check_for_sec_session() ||
- addr->mem_type == DDL_FW_MEM)
- ionflag = UNCACHED;
- else
- ionflag = CACHED;
kernel_vaddr = (unsigned long *) ion_map_kernel(
ddl_context->video_ion_client,
- addr->alloc_handle, ionflag);
+ addr->alloc_handle);
if (IS_ERR_OR_NULL(kernel_vaddr)) {
DDL_MSG_ERROR("%s() :DDL ION map failed\n",
__func__);
@@ -111,7 +105,7 @@
0,
&iova,
&buffer_size,
- UNCACHED, 0);
+ 0, 0);
if (ret || !iova) {
DDL_MSG_ERROR(
"%s():DDL ION ion map iommu failed, ret = %d iova = 0x%lx\n",
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 4687915..5eed305 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -596,7 +596,7 @@
[ddl->command_channel], hdr_ext_control,
r_cframe_skip, false, 0,
h263_cpfc_enable, encoder->sps_pps.sps_pps_for_idr_enable_flag,
- encoder->closed_gop);
+ encoder->closed_gop, encoder->avc_delimiter_enable);
vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
[ddl->command_channel],
encoder->target_bit_rate.target_bitrate);
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 3ac396c..3670dc81 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -27,8 +27,8 @@
#define PIL_FW_SIZE 0x200000
-static unsigned int vidc_clk_table[4] = {
- 48000000, 133330000, 200000000, 228570000,
+static unsigned int vidc_clk_table[5] = {
+ 48000000, 133330000, 200000000, 228570000, 266670000,
};
static unsigned int restrk_mmu_subsystem[] = {
MSM_SUBSYSTEM_VIDEO, MSM_SUBSYSTEM_VIDEO_FWARE};
@@ -69,7 +69,7 @@
if (res_trk_get_enable_ion() && addr->alloc_handle) {
kernel_vaddr = (unsigned long *) ion_map_kernel(
ddl_context->video_ion_client,
- addr->alloc_handle, UNCACHED);
+ addr->alloc_handle);
if (IS_ERR_OR_NULL(kernel_vaddr)) {
DDL_MSG_ERROR("%s():DDL ION client map failed\n",
__func__);
@@ -84,7 +84,7 @@
0,
&iova,
&buffer_size,
- UNCACHED, 0);
+ 0, 0);
if (ret || !iova) {
DDL_MSG_ERROR(
"%s():DDL ION client iommu map failed, ret = %d iova = 0x%lx\n",
@@ -209,7 +209,7 @@
addr->alloc_handle = ion_alloc(
ddl_context->video_ion_client,
alloc_size, SZ_4K,
- res_trk_get_mem_type());
+ res_trk_get_mem_type(), 0);
if (IS_ERR_OR_NULL(addr->alloc_handle)) {
DDL_MSG_ERROR("%s() :DDL ION alloc failed\n",
__func__);
@@ -629,7 +629,7 @@
vidc_freq = vidc_clk_table[2];
*pn_set_perf_lvl = RESTRK_1080P_MAX_PERF_LEVEL;
} else {
- vidc_freq = vidc_clk_table[3];
+ vidc_freq = vidc_clk_table[4];
*pn_set_perf_lvl = RESTRK_1080P_TURBO_PERF_LEVEL;
}
@@ -650,6 +650,10 @@
VCDRES_MSG_MED("%s(): Setting vidc freq to %u\n",
__func__, vidc_freq);
if (!res_trk_sel_clk_rate(vidc_freq)) {
+ if (vidc_freq == vidc_clk_table[4]) {
+ if (res_trk_sel_clk_rate(vidc_clk_table[3]))
+ goto ret;
+ }
VCDRES_MSG_ERROR("%s(): res_trk_sel_clk_rate FAILED\n",
__func__);
*pn_set_perf_lvl = 0;
@@ -657,7 +661,7 @@
}
}
#endif
- VCDRES_MSG_MED("%s() set perl level : %d", __func__, *pn_set_perf_lvl);
+ret: VCDRES_MSG_MED("%s() set perl level : %d", __func__, *pn_set_perf_lvl);
return true;
}
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
index 21f01d1..3b40640 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_utils.c
@@ -124,7 +124,7 @@
ddl_context->video_ion_client,
alloc_size,
SZ_4K,
- buff_addr->mem_type);
+ buff_addr->mem_type, 0);
if (!buff_addr->alloc_handle) {
ERR("\n%s(): DDL ION alloc failed\n",
__func__);
@@ -142,8 +142,7 @@
buff_addr->physical_base_addr = (u32 *)phyaddr;
kernel_vaddr = (unsigned long *) ion_map_kernel(
ddl_context->video_ion_client,
- buff_addr->alloc_handle,
- UNCACHED);
+ buff_addr->alloc_handle);
if (IS_ERR_OR_NULL(kernel_vaddr)) {
ERR("\n%s(): DDL ION map failed\n", __func__);
goto unmap_ion_buffer;
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 68bcd5c..59e19b7 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -347,7 +347,7 @@
ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
pmem_fd, kernel_vaddr, buffer_index,
&buff_handle);
- if (ion_flag == CACHED && buff_handle) {
+ if (ion_flag == ION_FLAG_CACHED && buff_handle) {
DBG("%s: Cache invalidate: vaddr (%p), "\
"size %u\n", __func__,
(void *)kernel_vaddr,
@@ -908,8 +908,7 @@
}
vcd_h264_mv_buffer->kernel_virtual_addr = (u8 *) ion_map_kernel(
client_ctx->user_ion_client,
- client_ctx->h264_mv_ion_handle,
- ionflag);
+ client_ctx->h264_mv_ion_handle);
if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
ERR("%s(): get_ION_kernel virtual addr failed\n",
__func__);
@@ -935,7 +934,7 @@
VIDEO_DOMAIN, VIDEO_MAIN_POOL,
SZ_4K, 0, (unsigned long *)&iova,
(unsigned long *)&buffer_size,
- UNCACHED, 0);
+ 0, 0);
if (rc || !iova) {
ERR(
"%s():get_ION_kernel physical addr fail, rc = %d iova = 0x%lx\n",
@@ -1298,7 +1297,7 @@
kernel_vaddr,
buffer_index,
&buff_handle);
- if (ion_flag == CACHED && buff_handle) {
+ if (ion_flag == ION_FLAG_CACHED && buff_handle) {
msm_ion_do_cache_op(client_ctx->user_ion_client,
buff_handle,
(unsigned long *)kernel_vaddr,
@@ -1812,7 +1811,7 @@
}
ker_vaddr = (unsigned long) ion_map_kernel(
client_ctx->user_ion_client,
- client_ctx->seq_hdr_ion_handle, ionflag);
+ client_ctx->seq_hdr_ion_handle);
if (!ker_vaddr) {
ERR("%s():get_ION_kernel virtual addr fail\n",
__func__);
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 67917b9..c7237e4 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -267,7 +267,7 @@
ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
pmem_fd, kernel_vaddr, buffer_index,
&buff_handle);
- if (ion_flag == CACHED && buff_handle) {
+ if (ion_flag == ION_FLAG_CACHED && buff_handle) {
msm_ion_do_cache_op(client_ctx->user_ion_client,
buff_handle,
(unsigned long *) kernel_vaddr,
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 5ee0a3d..8779432 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1688,7 +1688,7 @@
&buff_handle);
if (vcd_input_buffer.data_len > 0) {
- if (ion_flag == CACHED && buff_handle) {
+ if (ion_flag == ION_FLAG_CACHED && buff_handle) {
msm_ion_do_cache_op(
client_ctx->user_ion_client,
buff_handle,
@@ -1837,8 +1837,7 @@
}
control->kernel_virtual_addr = (u8 *) ion_map_kernel(
client_ctx->user_ion_client,
- client_ctx->recon_buffer_ion_handle[i],
- ionflag);
+ client_ctx->recon_buffer_ion_handle[i]);
if (!control->kernel_virtual_addr) {
ERR("%s(): get_ION_kernel virtual addr fail\n",
__func__);
@@ -1867,7 +1866,7 @@
0,
(unsigned long *)&iova,
(unsigned long *)&buffer_size,
- UNCACHED, 0);
+ 0, 0);
if (rc || !iova) {
ERR(
"%s():ION map iommu addr fail, rc = %d, iova = 0x%lx\n",
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 221c154..65dde68 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -647,8 +647,7 @@
*kernel_vaddr = (unsigned long)
ion_map_kernel(
client_ctx->user_ion_client,
- buff_ion_handle,
- ionflag);
+ buff_ion_handle);
if (IS_ERR_OR_NULL((void *)*kernel_vaddr)) {
ERR("%s():ION virtual addr fail\n",
__func__);
@@ -678,7 +677,7 @@
length,
(unsigned long *) &iova,
(unsigned long *) &buffer_size,
- UNCACHED,
+ 0,
ION_IOMMU_UNMAP_DELAYED);
if (ret || !iova) {
ERR(
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 71e8df8..5fdee02 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -92,7 +92,7 @@
} else {
map_buffer->alloc_handle = ion_alloc(
cctxt->vcd_ion_client, sz, SZ_4K,
- memtype);
+ memtype, 0);
if (!map_buffer->alloc_handle) {
pr_err("%s() ION alloc failed", __func__);
goto bailout;
@@ -105,8 +105,7 @@
}
*kernel_vaddr = (u8 *) ion_map_kernel(
cctxt->vcd_ion_client,
- map_buffer->alloc_handle,
- ionflag);
+ map_buffer->alloc_handle);
if (!(*kernel_vaddr)) {
pr_err("%s() ION map failed", __func__);
goto ion_free_bailout;
@@ -120,7 +119,7 @@
0,
(unsigned long *)&iova,
(unsigned long *)&buffer_size,
- UNCACHED, 0);
+ 0, 0);
if (ret || !iova) {
pr_err(
"%s() ION iommu map failed, ret = %d, iova = 0x%lx",
@@ -921,7 +920,7 @@
u32 i;
u32 found = false;
- for (i = 0; i <= pool->count && !found; i++) {
+ for (i = 1; i <= pool->count && !found; i++) {
if (pool->entries[i].virtual == addr)
found = true;
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index abcdeab..9a66ff9 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2088,7 +2088,7 @@
ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
struct ext4_extent *ex)
{
- struct ext4_ext_cache cex;
+ struct ext4_ext_cache cex = {0, 0, 0};
int ret = 0;
if (ext4_ext_check_cache(inode, block, &cex)) {
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 31a152d..5b07403 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -444,3 +444,4 @@
header-y += idle_stats_device.h
header-y += genlock.h
header-y += msm_audio_amrwb.h
+header-y += coresight-stm.h
diff --git a/include/linux/coresight-stm.h b/include/linux/coresight-stm.h
index 754f2f3..7c7c26e 100644
--- a/include/linux/coresight-stm.h
+++ b/include/linux/coresight-stm.h
@@ -28,6 +28,7 @@
STM_OPTION_GUARANTEED = 0x80,
};
+#ifdef __KERNEL__
#define stm_log_inv(entity_id, proto_id, data, size) \
stm_trace(STM_OPTION_NONE, entity_id, proto_id, data, size)
@@ -56,5 +57,6 @@
return 0;
}
#endif
+#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/epm_adc.h b/include/linux/epm_adc.h
index b7b7d90..ca1a425 100644
--- a/include/linux/epm_adc.h
+++ b/include/linux/epm_adc.h
@@ -13,6 +13,7 @@
int32_t physical;
};
+#ifdef __KERNEL__
struct epm_psoc_init_resp {
u8 cmd;
u8 version;
@@ -91,7 +92,6 @@
uint32_t vadc_voltage;
};
-#ifdef __KERNEL__
struct epm_chan_properties {
uint32_t resistorvalue;
uint32_t gain;
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 5c3c728..348a231 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -73,6 +73,7 @@
int irq_gpio;
u32 irq_gpio_flags;
int *key_codes;
+ bool need_calibration;
u8(*read_chg) (void);
int (*init_hw) (bool);
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 6ac2835..85e5002 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -39,8 +39,6 @@
ION_HEAP_TYPE_SYSTEM,
ION_HEAP_TYPE_SYSTEM_CONTIG,
ION_HEAP_TYPE_CARVEOUT,
- ION_HEAP_TYPE_IOMMU,
- ION_HEAP_TYPE_CP,
ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
are at the end of this enum */
ION_NUM_HEAPS,
@@ -49,86 +47,15 @@
#define ION_HEAP_SYSTEM_MASK (1 << ION_HEAP_TYPE_SYSTEM)
#define ION_HEAP_SYSTEM_CONTIG_MASK (1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
-#define ION_HEAP_CP_MASK (1 << ION_HEAP_TYPE_CP)
-
/**
- * These are the only ids that should be used for Ion heap ids.
- * The ids listed are the order in which allocation will be attempted
- * if specified. Don't swap the order of heap ids unless you know what
- * you are doing!
- * Id's are spaced by purpose to allow new Id's to be inserted in-between (for
- * possible fallbacks)
+ * heap flags - the lower 16 bits are used by core ion, the upper 16
+ * bits are reserved for use by the heaps themselves.
*/
-
-enum ion_heap_ids {
- INVALID_HEAP_ID = -1,
- ION_CP_MM_HEAP_ID = 8,
- ION_CP_MFC_HEAP_ID = 12,
- ION_CP_WB_HEAP_ID = 16, /* 8660 only */
- ION_CAMERA_HEAP_ID = 20, /* 8660 only */
- ION_SF_HEAP_ID = 24,
- ION_IOMMU_HEAP_ID = 25,
- ION_QSECOM_HEAP_ID = 27,
- ION_AUDIO_HEAP_ID = 28,
-
- ION_MM_FIRMWARE_HEAP_ID = 29,
- ION_SYSTEM_HEAP_ID = 30,
-
- ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_SECURE flag */
-};
-
-enum ion_fixed_position {
- NOT_FIXED,
- FIXED_LOW,
- FIXED_MIDDLE,
- FIXED_HIGH,
-};
-
-enum cp_mem_usage {
- VIDEO_BITSTREAM = 0x1,
- VIDEO_PIXEL = 0x2,
- VIDEO_NONPIXEL = 0x3,
- MAX_USAGE = 0x4,
- UNKNOWN = 0x7FFFFFFF,
-};
-
-/**
- * Flag to use when allocating to indicate that a heap is secure.
- */
-#define ION_SECURE (1 << ION_HEAP_ID_RESERVED)
-
-/**
- * Macro should be used with ion_heap_ids defined above.
- */
-#define ION_HEAP(bit) (1 << (bit))
-
-#define ION_VMALLOC_HEAP_NAME "vmalloc"
-#define ION_AUDIO_HEAP_NAME "audio"
-#define ION_SF_HEAP_NAME "sf"
-#define ION_MM_HEAP_NAME "mm"
-#define ION_CAMERA_HEAP_NAME "camera_preview"
-#define ION_IOMMU_HEAP_NAME "iommu"
-#define ION_MFC_HEAP_NAME "mfc"
-#define ION_WB_HEAP_NAME "wb"
-#define ION_MM_FIRMWARE_HEAP_NAME "mm_fw"
-#define ION_QSECOM_HEAP_NAME "qsecom"
-#define ION_FMEM_HEAP_NAME "fmem"
-
-#define CACHED 1
-#define UNCACHED 0
-
-#define ION_CACHE_SHIFT 0
-
-#define ION_SET_CACHE(__cache) ((__cache) << ION_CACHE_SHIFT)
-
-#define ION_IS_CACHED(__flags) ((__flags) & (1 << ION_CACHE_SHIFT))
-
-/*
- * This flag allows clients when mapping into the IOMMU to specify to
- * defer un-mapping from the IOMMU until the buffer memory is freed.
- */
-#define ION_IOMMU_UNMAP_DELAYED 1
+#define ION_FLAG_CACHED 1 /* mappings of this buffer should be
+ cached, ion will do cache
+ maintenance when the buffer is
+ mapped for dma */
#ifdef __KERNEL__
#include <linux/err.h>
@@ -170,72 +97,6 @@
};
/**
- * struct ion_cp_heap_pdata - defines a content protection heap in the given
- * platform
- * @permission_type: Memory ID used to identify the memory to TZ
- * @align: Alignment requirement for the memory
- * @secure_base: Base address for securing the heap.
- * Note: This might be different from actual base address
- * of this heap in the case of a shared heap.
- * @secure_size: Memory size for securing the heap.
- * Note: This might be different from actual size
- * of this heap in the case of a shared heap.
- * @reusable Flag indicating whether this heap is reusable of not.
- * (see FMEM)
- * @mem_is_fmem Flag indicating whether this memory is coming from fmem
- * or not.
- * @fixed_position If nonzero, position in the fixed area.
- * @virt_addr: Virtual address used when using fmem.
- * @iommu_map_all: Indicates whether we should map whole heap into IOMMU.
- * @iommu_2x_map_domain: Indicates the domain to use for overmapping.
- * @request_region: function to be called when the number of allocations
- * goes from 0 -> 1
- * @release_region: function to be called when the number of allocations
- * goes from 1 -> 0
- * @setup_region: function to be called upon ion registration
- *
- */
-struct ion_cp_heap_pdata {
- enum ion_permission_type permission_type;
- unsigned int align;
- ion_phys_addr_t secure_base; /* Base addr used when heap is shared */
- size_t secure_size; /* Size used for securing heap when heap is shared*/
- int reusable;
- int mem_is_fmem;
- enum ion_fixed_position fixed_position;
- int iommu_map_all;
- int iommu_2x_map_domain;
- ion_virt_addr_t *virt_addr;
- int (*request_region)(void *);
- int (*release_region)(void *);
- void *(*setup_region)(void);
-};
-
-/**
- * struct ion_co_heap_pdata - defines a carveout heap in the given platform
- * @adjacent_mem_id: Id of heap that this heap must be adjacent to.
- * @align: Alignment requirement for the memory
- * @mem_is_fmem Flag indicating whether this memory is coming from fmem
- * or not.
- * @fixed_position If nonzero, position in the fixed area.
- * @request_region: function to be called when the number of allocations
- * goes from 0 -> 1
- * @release_region: function to be called when the number of allocations
- * goes from 1 -> 0
- * @setup_region: function to be called upon ion registration
- *
- */
-struct ion_co_heap_pdata {
- int adjacent_mem_id;
- unsigned int align;
- int mem_is_fmem;
- enum ion_fixed_position fixed_position;
- int (*request_region)(void *);
- int (*release_region)(void *);
- void *(*setup_region)(void);
-};
-
-/**
* struct ion_platform_data - array of platform heaps passed from board file
* @has_outer_cache: set to 1 if outer cache is used, 0 otherwise.
* @nr: number of structures in the array
@@ -305,14 +166,18 @@
* @len: size of the allocation
* @align: requested allocation alignment, lots of hardware blocks have
* alignment requirements of some kind
- * @flags: mask of heaps to allocate from, if multiple bits are set
+ * @heap_mask: mask of heaps to allocate from, if multiple bits are set
* heaps will be tried in order from lowest to highest order bit
+ * @flags: heap flags, the low 16 bits are consumed by ion, the high 16
+ * bits are passed on to the respective heap and can be heap
+ * custom
*
* Allocate memory in one of the heaps provided in heap mask and return
* an opaque handle to it.
*/
struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
- size_t align, unsigned int flags);
+ size_t align, unsigned int heap_mask,
+ unsigned int flags);
/**
* ion_free - free a handle
@@ -363,8 +228,7 @@
* can be used to access this address. If no flags are specified, this
* will return a non-secure uncached mapping.
*/
-void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle,
- unsigned long flags);
+void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle);
/**
* ion_unmap_kernel() - destroy a kernel mapping for a handle
@@ -493,50 +357,6 @@
void *data);
/**
- * msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap.
- *
- * @heap_id - heap id to secure.
- *
- * Secure a heap
- * Returns 0 on success
- */
-int msm_ion_secure_heap(int heap_id);
-
-/**
- * msm_ion_unsecure_heap - unsecure a heap. Wrapper around ion_unsecure_heap.
- *
- * @heap_id - heap id to secure.
- *
- * Un-secure a heap
- * Returns 0 on success
- */
-int msm_ion_unsecure_heap(int heap_id);
-
-/**
- * msm_ion_secure_heap_2_0 - secure a heap using 2.0 APIs
- * Wrapper around ion_secure_heap.
- *
- * @heap_id - heap id to secure.
- * @usage - usage hint to TZ
- *
- * Secure a heap
- * Returns 0 on success
- */
-int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage);
-
-/**
- * msm_ion_unsecure_heap - unsecure a heap secured with 3.0 APIs.
- * Wrapper around ion_unsecure_heap.
- *
- * @heap_id - heap id to secure.
- * @usage - usage hint to TZ
- *
- * Un-secure a heap
- * Returns 0 on success
- */
-int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage);
-
-/**
* msm_ion_do_cache_op - do cache operations.
*
* @client - pointer to ION client.
@@ -574,7 +394,9 @@
static inline void ion_client_destroy(struct ion_client *client) { }
static inline struct ion_handle *ion_alloc(struct ion_client *client,
- size_t len, size_t align, unsigned int flags)
+ size_t len, size_t align,
+ unsigned int heap_mask,
+ unsigned int flags)
{
return ERR_PTR(-ENODEV);
}
@@ -651,28 +473,6 @@
return -ENODEV;
}
-static inline int msm_ion_secure_heap(int heap_id)
-{
- return -ENODEV;
-
-}
-
-static inline int msm_ion_unsecure_heap(int heap_id)
-{
- return -ENODEV;
-}
-
-static inline int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage)
-{
- return -ENODEV;
-}
-
-static inline int msm_ion_unsecure_heap_2_0(int heap_id,
- enum cp_mem_usage usage)
-{
- return -ENODEV;
-}
-
static inline int msm_ion_do_cache_op(struct ion_client *client,
struct ion_handle *handle, void *vaddr,
unsigned long len, unsigned int cmd)
@@ -695,6 +495,7 @@
* struct ion_allocation_data - metadata passed from userspace for allocations
* @len: size of the allocation
* @align: required alignment of the allocation
+ * @heap_mask: mask of heaps to allocate from
* @flags: flags passed to heap
* @handle: pointer that will be populated with a cookie to use to refer
* to this allocation
@@ -744,41 +545,6 @@
unsigned int cmd;
unsigned long arg;
};
-
-
-/* struct ion_flush_data - data passed to ion for flushing caches
- *
- * @handle: handle with data to flush
- * @fd: fd to flush
- * @vaddr: userspace virtual address mapped with mmap
- * @offset: offset into the handle to flush
- * @length: length of handle to flush
- *
- * Performs cache operations on the handle. If p is the start address
- * of the handle, p + offset through p + offset + length will have
- * the cache operations performed
- */
-struct ion_flush_data {
- struct ion_handle *handle;
- int fd;
- void *vaddr;
- unsigned int offset;
- unsigned int length;
-};
-
-/* struct ion_flag_data - information about flags for this buffer
- *
- * @handle: handle to get flags from
- * @flags: flags of this handle
- *
- * Takes handle as an input and outputs the flags from the handle
- * in the flag field.
- */
-struct ion_flag_data {
- struct ion_handle *handle;
- unsigned long flags;
-};
-
#define ION_IOC_MAGIC 'I'
/**
@@ -836,34 +602,4 @@
#define ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, struct ion_custom_data)
-/**
- * DOC: ION_IOC_CLEAN_CACHES - clean the caches
- *
- * Clean the caches of the handle specified.
- */
-#define ION_IOC_CLEAN_CACHES _IOWR(ION_IOC_MAGIC, 20, \
- struct ion_flush_data)
-/**
- * DOC: ION_MSM_IOC_INV_CACHES - invalidate the caches
- *
- * Invalidate the caches of the handle specified.
- */
-#define ION_IOC_INV_CACHES _IOWR(ION_IOC_MAGIC, 21, \
- struct ion_flush_data)
-/**
- * DOC: ION_MSM_IOC_CLEAN_CACHES - clean and invalidate the caches
- *
- * Clean and invalidate the caches of the handle specified.
- */
-#define ION_IOC_CLEAN_INV_CACHES _IOWR(ION_IOC_MAGIC, 22, \
- struct ion_flush_data)
-
-/**
- * DOC: ION_IOC_GET_FLAGS - get the flags of the handle
- *
- * Gets the flags of the current handle which indicate cachability,
- * secure state etc.
- */
-#define ION_IOC_GET_FLAGS _IOWR(ION_IOC_MAGIC, 23, \
- struct ion_flag_data)
#endif /* _LINUX_ION_H */
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
new file mode 100644
index 0000000..c55e47e
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -0,0 +1,155 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __PM8XXX_BMS_BATTERYDATA_H
+#define __PM8XXX_BMS_BATTERYDATA_H
+
+#include <linux/errno.h>
+
+#define FCC_CC_COLS 5
+#define FCC_TEMP_COLS 8
+
+#define PC_CC_ROWS 29
+#define PC_CC_COLS 13
+
+#define PC_TEMP_ROWS 29
+#define PC_TEMP_COLS 8
+
+#define MAX_SINGLE_LUT_COLS 20
+
+struct single_row_lut {
+ int x[MAX_SINGLE_LUT_COLS];
+ int y[MAX_SINGLE_LUT_COLS];
+ int cols;
+};
+
+/**
+ * struct sf_lut -
+ * @rows: number of percent charge entries should be <= PC_CC_ROWS
+ * @cols: number of charge cycle entries should be <= PC_CC_COLS
+ * @row_entries: the charge cycles/temperature at which sf data
+ * is available in the table.
+ * The charge cycles must be in increasing order from 0 to rows.
+ * @percent: the percent charge at which sf data is available in the table
+ * The percentcharge must be in decreasing order from 0 to cols.
+ * @sf: the scaling factor data
+ */
+struct sf_lut {
+ int rows;
+ int cols;
+ int row_entries[PC_CC_COLS];
+ int percent[PC_CC_ROWS];
+ int sf[PC_CC_ROWS][PC_CC_COLS];
+};
+
+/**
+ * struct pc_temp_ocv_lut -
+ * @rows: number of percent charge entries should be <= PC_TEMP_ROWS
+ * @cols: number of temperature entries should be <= PC_TEMP_COLS
+ * @temp: the temperatures at which ocv data is available in the table
+ * The temperatures must be in increasing order from 0 to rows.
+ * @percent: the percent charge at which ocv data is available in the table
+ * The percentcharge must be in decreasing order from 0 to cols.
+ * @ocv: the open circuit voltage
+ */
+struct pc_temp_ocv_lut {
+ int rows;
+ int cols;
+ int temp[PC_TEMP_COLS];
+ int percent[PC_TEMP_ROWS];
+ int ocv[PC_TEMP_ROWS][PC_TEMP_COLS];
+};
+
+enum battery_type {
+ BATT_UNKNOWN = 0,
+ BATT_PALLADIUM,
+ BATT_DESAY,
+};
+
+/**
+ * struct bms_battery_data -
+ * @fcc: full charge capacity (mAmpHour)
+ * @fcc_temp_lut: table to get fcc at a given temp
+ * @pc_temp_ocv_lut: table to get percent charge given batt temp and cycles
+ * @pc_sf_lut: table to get percent charge scaling factor given cycles
+ * and percent charge
+ * @rbatt_sf_lut: table to get battery resistance scaling factor given
+ * temperature and percent charge
+ * @default_rbatt_mohm: the default value of battery resistance to use when
+ * readings from bms are not available.
+ * @delta_rbatt_mohm: the resistance to be added towards lower soc to
+ * compensate for battery capacitance.
+ */
+
+struct bms_battery_data {
+ unsigned int fcc;
+ struct single_row_lut *fcc_temp_lut;
+ struct single_row_lut *fcc_sf_lut;
+ struct pc_temp_ocv_lut *pc_temp_ocv_lut;
+ struct sf_lut *pc_sf_lut;
+ struct sf_lut *rbatt_sf_lut;
+ int default_rbatt_mohm;
+ int delta_rbatt_mohm;
+};
+
+#if defined(CONFIG_PM8921_BMS) || \
+ defined(CONFIG_PM8921_BMS_MODULE)
+extern struct bms_battery_data palladium_1500_data;
+extern struct bms_battery_data desay_5200_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);
+int interpolate_scalingfactor_fcc(struct single_row_lut *fcc_sf_lut,
+ int cycles);
+int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv,
+ int batt_temp_degc, int ocv);
+int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
+ int batt_temp_degc, int pc);
+int linear_interpolate(int y0, int x0, int y1, int x1, int x);
+int is_between(int left, int right, int value);
+#else
+static inline int interpolate_fcc(struct single_row_lut *fcc_temp_lut,
+ int batt_temp)
+{
+ return -EINVAL;
+}
+static inline int interpolate_scalingfactor(struct sf_lut *sf_lut,
+ int row_entry, int pc)
+{
+ return -EINVAL;
+}
+static inline int interpolate_scalingfactor_fcc(
+ struct single_row_lut *fcc_sf_lut, int cycles)
+{
+ return -EINVAL;
+}
+static inline int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv,
+ int batt_temp_degc, int ocv)
+{
+ return -EINVAL;
+}
+static inline int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv,
+ int batt_temp_degc, int pc)
+{
+ return -EINVAL;
+}
+static inline int linear_interpolate(int y0, int x0, int y1, int x1, int x)
+{
+ return -EINVAL;
+}
+static inline int is_between(int left, int right, int value)
+{
+ return -EINVAL;
+}
+#endif
+
+#endif
diff --git a/include/linux/mfd/pm8xxx/pm8038.h b/include/linux/mfd/pm8xxx/pm8038.h
index 682abc8..574dab6 100644
--- a/include/linux/mfd/pm8xxx/pm8038.h
+++ b/include/linux/mfd/pm8xxx/pm8038.h
@@ -54,6 +54,7 @@
/* PMIC Interrupts */
#define PM8038_RTC_ALARM_IRQ PM8038_IRQ_BLOCK_BIT(4, 7)
+#define PM8038_BATT_ALARM_IRQ PM8921_IRQ_BLOCK_BIT(5, 6)
#define PM8038_PWRKEY_REL_IRQ PM8038_IRQ_BLOCK_BIT(6, 2)
#define PM8038_PWRKEY_PRESS_IRQ PM8038_IRQ_BLOCK_BIT(6, 3)
#define PM8038_KEYPAD_IRQ PM8038_IRQ_BLOCK_BIT(9, 2)
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index a73a284..5f2fe9f 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -14,87 +14,10 @@
#define __PM8XXX_BMS_H
#include <linux/errno.h>
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
#define PM8921_BMS_DEV_NAME "pm8921-bms"
-#define FCC_CC_COLS 5
-#define FCC_TEMP_COLS 8
-
-#define PC_CC_ROWS 29
-#define PC_CC_COLS 13
-
-#define PC_TEMP_ROWS 29
-#define PC_TEMP_COLS 8
-
-#define MAX_SINGLE_LUT_COLS 20
-
-struct single_row_lut {
- int x[MAX_SINGLE_LUT_COLS];
- int y[MAX_SINGLE_LUT_COLS];
- int cols;
-};
-
-/**
- * struct sf_lut -
- * @rows: number of percent charge entries should be <= PC_CC_ROWS
- * @cols: number of charge cycle entries should be <= PC_CC_COLS
- * @row_entries: the charge cycles/temperature at which sf data
- * is available in the table.
- * The charge cycles must be in increasing order from 0 to rows.
- * @percent: the percent charge at which sf data is available in the table
- * The percentcharge must be in decreasing order from 0 to cols.
- * @sf: the scaling factor data
- */
-struct sf_lut {
- int rows;
- int cols;
- int row_entries[PC_CC_COLS];
- int percent[PC_CC_ROWS];
- int sf[PC_CC_ROWS][PC_CC_COLS];
-};
-
-/**
- * struct pc_temp_ocv_lut -
- * @rows: number of percent charge entries should be <= PC_TEMP_ROWS
- * @cols: number of temperature entries should be <= PC_TEMP_COLS
- * @temp: the temperatures at which ocv data is available in the table
- * The temperatures must be in increasing order from 0 to rows.
- * @percent: the percent charge at which ocv data is available in the table
- * The percentcharge must be in decreasing order from 0 to cols.
- * @ocv: the open circuit voltage
- */
-struct pc_temp_ocv_lut {
- int rows;
- int cols;
- int temp[PC_TEMP_COLS];
- int percent[PC_TEMP_ROWS];
- int ocv[PC_TEMP_ROWS][PC_TEMP_COLS];
-};
-
-/**
- * struct pm8921_bms_battery_data -
- * @fcc: full charge capacity (mAmpHour)
- * @fcc_temp_lut: table to get fcc at a given temp
- * @pc_temp_ocv_lut: table to get percent charge given batt temp and cycles
- * @pc_sf_lut: table to get percent charge scaling factor given cycles
- * and percent charge
- * @rbatt_sf_lut: table to get battery resistance scaling factor given
- * temperature and percent charge
- * @default_rbatt_mohm: the default value of battery resistance to use when
- * readings from bms are not available.
- * @delta_rbatt_mohm: the resistance to be added towards lower soc to
- * compensate for battery capacitance.
- */
-struct pm8921_bms_battery_data {
- unsigned int fcc;
- struct single_row_lut *fcc_temp_lut;
- struct single_row_lut *fcc_sf_lut;
- struct pc_temp_ocv_lut *pc_temp_ocv_lut;
- struct sf_lut *pc_sf_lut;
- struct sf_lut *rbatt_sf_lut;
- int default_rbatt_mohm;
- int delta_rbatt_mohm;
-};
struct pm8xxx_bms_core_data {
unsigned int batt_temp_channel;
@@ -104,12 +27,6 @@
unsigned int batt_id_channel;
};
-enum battery_type {
- BATT_UNKNOWN = 0,
- BATT_PALLADIUM,
- BATT_DESAY,
-};
-
/**
* struct pm8921_bms_platform_data -
* @batt_type: allows to force chose battery calibration data
@@ -137,8 +54,6 @@
};
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
-extern struct pm8921_bms_battery_data palladium_1500_data;
-extern struct pm8921_bms_battery_data desay_5200_data;
/**
* pm8921_bms_get_vsense_avg - return the voltage across the sense
* resitor in microvolts
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 7b389c5..0e86f2a 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -63,6 +63,8 @@
* @ttrkl_time: max trckl charging time in minutes
* valid range 1 to 64 mins. PON default 15 min
* @update_time: how often the userland be updated of the charging (msec)
+ * @alarm_low_mv: the voltage (mV) when low battery alarm is triggered
+ * @alarm_high_mv: the voltage (mV) when high battery alarm is triggered
* @max_voltage: the max voltage (mV) the battery should be charged up to
* @min_voltage: the voltage (mV) where charging method switches from
* trickle to fast. This is also the minimum voltage the
@@ -128,6 +130,8 @@
unsigned int max_voltage;
unsigned int min_voltage;
unsigned int uvd_thresh_voltage;
+ unsigned int alarm_low_mv;
+ unsigned int alarm_high_mv;
unsigned int resume_voltage_delta;
unsigned int term_current;
int cool_temp;
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index f6d164d..421d758 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -15,6 +15,8 @@
#include <linux/interrupt.h>
#include <linux/pm_qos.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
#define WCD9XXX_NUM_IRQ_REGS 3
@@ -37,85 +39,49 @@
#define SITAR_IS_1P1(ver) \
((ver == SITAR_VERSION_1P1) ? 1 : 0)
-enum {
- TABLA_IRQ_SLIMBUS = 0,
- TABLA_IRQ_MBHC_REMOVAL,
- TABLA_IRQ_MBHC_SHORT_TERM,
- TABLA_IRQ_MBHC_PRESS,
- TABLA_IRQ_MBHC_RELEASE,
- TABLA_IRQ_MBHC_POTENTIAL,
- TABLA_IRQ_MBHC_INSERTION,
- TABLA_IRQ_BG_PRECHARGE,
- TABLA_IRQ_PA1_STARTUP,
- TABLA_IRQ_PA2_STARTUP,
- TABLA_IRQ_PA3_STARTUP,
- TABLA_IRQ_PA4_STARTUP,
- TABLA_IRQ_PA5_STARTUP,
- TABLA_IRQ_MICBIAS1_PRECHARGE,
- TABLA_IRQ_MICBIAS2_PRECHARGE,
- TABLA_IRQ_MICBIAS3_PRECHARGE,
- TABLA_IRQ_HPH_PA_OCPL_FAULT,
- TABLA_IRQ_HPH_PA_OCPR_FAULT,
- TABLA_IRQ_EAR_PA_OCPL_FAULT,
- TABLA_IRQ_HPH_L_PA_STARTUP,
- TABLA_IRQ_HPH_R_PA_STARTUP,
- TABLA_IRQ_EAR_PA_STARTUP,
- TABLA_NUM_IRQS,
-};
-enum {
- SITAR_IRQ_SLIMBUS = 0,
- SITAR_IRQ_MBHC_REMOVAL,
- SITAR_IRQ_MBHC_SHORT_TERM,
- SITAR_IRQ_MBHC_PRESS,
- SITAR_IRQ_MBHC_RELEASE,
- SITAR_IRQ_MBHC_POTENTIAL,
- SITAR_IRQ_MBHC_INSERTION,
- SITAR_IRQ_BG_PRECHARGE,
- SITAR_IRQ_PA1_STARTUP,
- SITAR_IRQ_PA2_STARTUP,
- SITAR_IRQ_PA3_STARTUP,
- SITAR_IRQ_PA4_STARTUP,
- SITAR_IRQ_PA5_STARTUP,
- SITAR_IRQ_MICBIAS1_PRECHARGE,
- SITAR_IRQ_MICBIAS2_PRECHARGE,
- SITAR_IRQ_MICBIAS3_PRECHARGE,
- SITAR_IRQ_HPH_PA_OCPL_FAULT,
- SITAR_IRQ_HPH_PA_OCPR_FAULT,
- SITAR_IRQ_EAR_PA_OCPL_FAULT,
- SITAR_IRQ_HPH_L_PA_STARTUP,
- SITAR_IRQ_HPH_R_PA_STARTUP,
- SITAR_IRQ_EAR_PA_STARTUP,
- SITAR_NUM_IRQS,
-};
+#define TAIKO_VERSION_1_0 0
+#define TAIKO_IS_1_0(ver) \
+ ((ver == TAIKO_VERSION_1_0) ? 1 : 0)
enum {
- TAIKO_IRQ_SLIMBUS = 0,
- TAIKO_IRQ_MBHC_REMOVAL,
- TAIKO_IRQ_MBHC_SHORT_TERM,
- TAIKO_IRQ_MBHC_PRESS,
- TAIKO_IRQ_MBHC_RELEASE,
- TAIKO_IRQ_MBHC_POTENTIAL,
- TAIKO_IRQ_MBHC_INSERTION,
- TAIKO_IRQ_BG_PRECHARGE,
- TAIKO_IRQ_PA1_STARTUP,
- TAIKO_IRQ_PA2_STARTUP,
- TAIKO_IRQ_PA3_STARTUP,
- TAIKO_IRQ_PA4_STARTUP,
- TAIKO_IRQ_PA5_STARTUP,
- TAIKO_IRQ_MICBIAS1_PRECHARGE,
- TAIKO_IRQ_MICBIAS2_PRECHARGE,
- TAIKO_IRQ_MICBIAS3_PRECHARGE,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT,
- TAIKO_IRQ_EAR_PA_OCPL_FAULT,
- TAIKO_IRQ_HPH_L_PA_STARTUP,
- TAIKO_IRQ_HPH_R_PA_STARTUP,
- TAIKO_IRQ_EAR_PA_STARTUP,
- TAIKO_NUM_IRQS,
+ WCD9XXX_IRQ_SLIMBUS = 0,
+ WCD9XXX_IRQ_MBHC_REMOVAL,
+ WCD9XXX_IRQ_MBHC_SHORT_TERM,
+ WCD9XXX_IRQ_MBHC_PRESS,
+ WCD9XXX_IRQ_MBHC_RELEASE,
+ WCD9XXX_IRQ_MBHC_POTENTIAL,
+ WCD9XXX_IRQ_MBHC_INSERTION,
+ WCD9XXX_IRQ_BG_PRECHARGE,
+ WCD9XXX_IRQ_PA1_STARTUP,
+ WCD9XXX_IRQ_PA2_STARTUP,
+ WCD9XXX_IRQ_PA3_STARTUP,
+ WCD9XXX_IRQ_PA4_STARTUP,
+ WCD9XXX_IRQ_PA5_STARTUP,
+ WCD9XXX_IRQ_MICBIAS1_PRECHARGE,
+ WCD9XXX_IRQ_MICBIAS2_PRECHARGE,
+ WCD9XXX_IRQ_MICBIAS3_PRECHARGE,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+ WCD9XXX_IRQ_EAR_PA_OCPL_FAULT,
+ WCD9XXX_IRQ_HPH_L_PA_STARTUP,
+ WCD9XXX_IRQ_HPH_R_PA_STARTUP,
+ WCD9XXX_IRQ_EAR_PA_STARTUP,
+ WCD9XXX_NUM_IRQS,
};
+enum {
+ TABLA_NUM_IRQS = WCD9XXX_NUM_IRQS,
+ SITAR_NUM_IRQS = WCD9XXX_NUM_IRQS,
+ TAIKO_NUM_IRQS = WCD9XXX_NUM_IRQS,
+};
+
+
+#define MAX(X, Y) (((int)X) >= ((int)Y) ? (X) : (Y))
+#define WCD9XXX_MAX_NUM_IRQS (MAX(MAX(TABLA_NUM_IRQS, SITAR_NUM_IRQS), \
+ TAIKO_NUM_IRQS))
+
enum wcd9xxx_pm_state {
WCD9XXX_PM_SLEEPABLE,
WCD9XXX_PM_AWAKE,
@@ -131,12 +97,6 @@
struct mutex irq_lock;
u8 version;
- unsigned int irq_base;
- unsigned int irq;
- u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
- u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
- u8 irq_level[WCD9XXX_NUM_IRQ_REGS];
-
int reset_gpio;
int (*read_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
@@ -158,6 +118,13 @@
int num_tx_port;
u8 idbyte[4];
+
+ unsigned int irq_base;
+ unsigned int irq;
+ u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
+ u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
+ bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
+ int num_irqs;
};
int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
@@ -181,40 +148,15 @@
enum wcd9xxx_pm_state o,
enum wcd9xxx_pm_state n);
-static inline int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq,
- irq_handler_t handler, const char *name,
- void *data)
-{
- if (!wcd9xxx->irq_base)
- return -EINVAL;
- return request_threaded_irq(wcd9xxx->irq_base + irq, NULL, handler,
- IRQF_TRIGGER_RISING, name,
- data);
-}
-static inline void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx,
- int irq, void *data)
-{
- if (!wcd9xxx->irq_base)
- return;
- free_irq(wcd9xxx->irq_base + irq, data);
-}
-static inline void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq)
-{
- if (!wcd9xxx->irq_base)
- return;
- enable_irq(wcd9xxx->irq_base + irq);
-}
-static inline void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq)
-{
- if (!wcd9xxx->irq_base)
- return;
- disable_irq_nosync(wcd9xxx->irq_base + irq);
-}
-static inline void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq)
-{
- if (!wcd9xxx->irq_base)
- return;
- disable_irq(wcd9xxx->irq_base + irq);
-}
+int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq,
+ irq_handler_t handler, const char *name, void *data);
+void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx, int irq, void *data);
+void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq);
+void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq);
+void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq);
+#ifdef CONFIG_OF
+int __init wcd9xxx_irq_of_init(struct device_node *node,
+ struct device_node *parent);
+#endif /* CONFIG_OF */
#endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9304_registers.h b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
index f7c483c..73919e0 100644
--- a/include/linux/mfd/wcd9xxx/wcd9304_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9304_registers.h
@@ -409,114 +409,163 @@
#define SITAR_A_CDC_ANC1_SMLPF_CTL__POR (0x00000000)
#define SITAR_A_CDC_ANC1_DCFLT_CTL (0x20B)
#define SITAR_A_CDC_ANC1_DCFLT_CTL__POR (0x00000000)
-#define SITAR_A_CDC_TX1_VOL_CTL_TIMER (0x220)
-#define SITAR_A_CDC_TX1_VOL_CTL_TIMER__POR (0x00000000)
-#define SITAR_A_CDC_TX1_VOL_CTL_GAIN (0x221)
-#define SITAR_A_CDC_TX1_VOL_CTL_GAIN__POR (0x00000000)
-#define SITAR_A_CDC_TX2_VOL_CTL_GAIN (0x229)
-#define SITAR_A_CDC_TX2_VOL_CTL_GAIN__POR (0x00000000)
-#define SITAR_A_CDC_TX3_VOL_CTL_GAIN (0x231)
-#define SITAR_A_CDC_TX3_VOL_CTL_GAIN__POR (0x00000000)
-#define SITAR_A_CDC_TX4_VOL_CTL_GAIN (0x239)
-#define SITAR_A_CDC_TX4_VOL_CTL_GAIN__POR (0x00000000)
-#define SITAR_A_CDC_TX5_VOL_CTL_GAIN (0x241)
-#define SITAR_A_CDC_TX5_VOL_CTL_GAIN__POR (0x00000000)
-#define SITAR_A_CDC_TX1_VOL_CTL_CFG (0x222)
-#define SITAR_A_CDC_TX1_VOL_CTL_CFG__POR (0x00000000)
-#define SITAR_A_CDC_TX2_VOL_CTL_CFG (0x22A)
-#define SITAR_A_CDC_TX2_VOL_CTL_CFG__POR (0x00000000)
-#define SITAR_A_CDC_TX3_VOL_CTL_CFG (0x232)
-#define SITAR_A_CDC_TX3_VOL_CTL_CFG__POR (0x00000000)
-#define SITAR_A_CDC_TX4_VOL_CTL_CFG (0x23A)
-#define SITAR_A_CDC_TX4_VOL_CTL_CFG__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_CTL (0x280)
+#define SITAR_A_CDC_ANC2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_SHIFT (0x281)
+#define SITAR_A_CDC_ANC2_SHIFT__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_IIR_B1_CTL (0x282)
+#define SITAR_A_CDC_ANC2_IIR_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_IIR_B2_CTL (0x283)
+#define SITAR_A_CDC_ANC2_IIR_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_IIR_B3_CTL (0x284)
+#define SITAR_A_CDC_ANC2_IIR_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_IIR_B4_CTL (0x285)
+#define SITAR_A_CDC_ANC2_IIR_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_LPF_B1_CTL (0x286)
+#define SITAR_A_CDC_ANC2_LPF_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_LPF_B2_CTL (0x287)
+#define SITAR_A_CDC_ANC2_LPF_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_LPF_B3_CTL (0x288)
+#define SITAR_A_CDC_ANC2_LPF_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_SPARE (0x289)
+#define SITAR_A_CDC_ANC2_SPARE__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_SMLPF_CTL (0x28A)
+#define SITAR_A_CDC_ANC2_SMLPF_CTL__POR (0x00000000)
+#define SITAR_A_CDC_ANC2_DCFLT_CTL (0x28B)
+#define SITAR_A_CDC_ANC2_DCFLT_CTL__POR (0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_TIMER (0x220)
+#define SITAR_A_CDC_TX1_VOL_CTL_TIMER__POR (0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_GAIN (0x221)
+#define SITAR_A_CDC_TX1_VOL_CTL_GAIN__POR (0x00000000)
+#define SITAR_A_CDC_TX1_VOL_CTL_CFG (0x222)
+#define SITAR_A_CDC_TX1_VOL_CTL_CFG__POR (0x00000000)
#define SITAR_A_CDC_TX1_MUX_CTL (0x223)
#define SITAR_A_CDC_TX1_MUX_CTL__POR (0x00000008)
-#define SITAR_A_CDC_TX1_CLK_FS_CTL (0x00000224)
-#define SITAR_A_CDC_TX1_CLK_FS_CTL__POR (0x00000003)
-#define SITAR_A_CDC_TX2_CLK_FS_CTL (0x0000022C)
-#define SITAR_A_CDC_TX2_CLK_FS_CTL__POR (0x00000003)
-#define SITAR_A_CDC_TX3_CLK_FS_CTL (0x00000234)
-#define SITAR_A_CDC_TX3_CLK_FS_CTL__POR (0x00000003)
-#define SITAR_A_CDC_TX4_CLK_FS_CTL (0x0000023C)
-#define SITAR_A_CDC_TX4_CLK_FS_CTL__POR (0x00000003)
-#define SITAR_A_CDC_TX1_DMIC_CTL (0x225)
+#define SITAR_A_CDC_TX1_CLK_FS_CTL (0x224)
+#define SITAR_A_CDC_TX1_CLK_FS_CTL__POR (0x00000003)
+#define SITAR_A_CDC_TX1_DMIC_CTL (0x225)
#define SITAR_A_CDC_TX1_DMIC_CTL__POR (0x00000000)
-#define SITAR_A_CDC_TX2_MUX_CTL (0x22B)
+
+#define SITAR_A_CDC_TX2_VOL_CTL_TIMER (0x228)
+#define SITAR_A_CDC_TX2_VOL_CTL_TIMER__POR (0x00000000)
+#define SITAR_A_CDC_TX2_VOL_CTL_GAIN (0x229)
+#define SITAR_A_CDC_TX2_VOL_CTL_GAIN__POR (0x00000000)
+#define SITAR_A_CDC_TX2_VOL_CTL_CFG (0x22A)
+#define SITAR_A_CDC_TX2_VOL_CTL_CFG__POR (0x00000000)
+#define SITAR_A_CDC_TX2_MUX_CTL (0x22B)
#define SITAR_A_CDC_TX2_MUX_CTL__POR (0x00000008)
-#define SITAR_A_CDC_TX3_MUX_CTL (0x233)
+#define SITAR_A_CDC_TX2_CLK_FS_CTL (0x22C)
+#define SITAR_A_CDC_TX2_CLK_FS_CTL__POR (0x00000003)
+#define SITAR_A_CDC_TX2_DMIC_CTL (0x22D)
+#define SITAR_A_CDC_TX2_DMIC_CTL__POR (0x00000000)
+
+#define SITAR_A_CDC_TX3_VOL_CTL_TIMER (0x230)
+#define SITAR_A_CDC_TX3_VOL_CTL_TIMER__POR (0x00000000)
+#define SITAR_A_CDC_TX3_VOL_CTL_GAIN (0x231)
+#define SITAR_A_CDC_TX3_VOL_CTL_GAIN__POR (0x00000000)
+#define SITAR_A_CDC_TX3_VOL_CTL_CFG (0x232)
+#define SITAR_A_CDC_TX3_VOL_CTL_CFG__POR (0x00000000)
+#define SITAR_A_CDC_TX3_MUX_CTL (0x233)
#define SITAR_A_CDC_TX3_MUX_CTL__POR (0x00000008)
-#define SITAR_A_CDC_TX4_MUX_CTL (0x23B)
+#define SITAR_A_CDC_TX3_CLK_FS_CTL (0x234)
+#define SITAR_A_CDC_TX3_CLK_FS_CTL__POR (0x00000003)
+#define SITAR_A_CDC_TX3_DMIC_CTL (0x235)
+#define SITAR_A_CDC_TX3_DMIC_CTL__POR (0x00000000)
+
+#define SITAR_A_CDC_TX4_VOL_CTL_TIMER (0x239)
+#define SITAR_A_CDC_TX4_VOL_CTL_TIMER__POR (0x00000000)
+#define SITAR_A_CDC_TX4_VOL_CTL_GAIN (0x23A)
+#define SITAR_A_CDC_TX4_VOL_CTL_GAIN__POR (0x00000000)
+#define SITAR_A_CDC_TX4_VOL_CTL_CFG (0x23B)
+#define SITAR_A_CDC_TX4_VOL_CTL_CFG__POR (0x00000000)
+#define SITAR_A_CDC_TX4_MUX_CTL (0x23C)
#define SITAR_A_CDC_TX4_MUX_CTL__POR (0x00000008)
-#define SITAR_A_CDC_TX5_MUX_CTL (0x243)
+#define SITAR_A_CDC_TX4_CLK_FS_CTL (0x23D)
+#define SITAR_A_CDC_TX4_CLK_FS_CTL__POR (0x00000003)
+#define SITAR_A_CDC_TX4_DMIC_CTL (0x23E)
+#define SITAR_A_CDC_TX4_DMIC_CTL__POR (0x00000000)
+
+#define SITAR_A_CDC_TX5_VOL_CTL_TIMER (0x240)
+#define SITAR_A_CDC_TX5_VOL_CTL_TIMER__POR (0x00000000)
+#define SITAR_A_CDC_TX5_VOL_CTL_GAIN (0x241)
+#define SITAR_A_CDC_TX5_VOL_CTL_GAIN__POR (0x00000000)
+#define SITAR_A_CDC_TX5_VOL_CTL_CFG (0x242)
+#define SITAR_A_CDC_TX5_VOL_CTL_CFG__POR (0x00000000)
+#define SITAR_A_CDC_TX5_MUX_CTL (0x243)
#define SITAR_A_CDC_TX5_MUX_CTL__POR (0x00000008)
+#define SITAR_A_CDC_TX5_CLK_FS_CTL (0x244)
+#define SITAR_A_CDC_TX5_CLK_FS_CTL__POR (0x00000003)
+#define SITAR_A_CDC_TX5_DMIC_CTL (0x245)
+#define SITAR_A_CDC_TX5_DMIC_CTL__POR (0x00000000)
#define SITAR_A_CDC_SRC1_PDA_CFG (0x2A0)
#define SITAR_A_CDC_SRC1_PDA_CFG__POR (0x00000000)
#define SITAR_A_CDC_SRC1_FS_CTL (0x2A1)
#define SITAR_A_CDC_SRC1_FS_CTL__POR (0x0000001b)
+#define SITAR_A_CDC_SRC2_PDA_CFG (0x2A8)
+#define SITAR_A_CDC_SRC2_PDA_CFG__POR (0x00000000)
+#define SITAR_A_CDC_SRC2_FS_CTL (0x2A9)
+#define SITAR_A_CDC_SRC2_FS_CTL__POR (0x0000001b)
-#define SITAR_A_CDC_RX1_B1_CTL (0x000002B0)
+#define SITAR_A_CDC_RX1_B1_CTL (0x2B0)
#define SITAR_A_CDC_RX1_B1_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX2_B1_CTL (0x000002B8)
-#define SITAR_A_CDC_RX2_B1_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX3_B1_CTL (0x000002C0)
-#define SITAR_A_CDC_RX3_B1_CTL__POR (0x00000000)
-
-#define SITAR_A_CDC_RX1_B2_CTL (0x000002B1)
+#define SITAR_A_CDC_RX1_B2_CTL (0x2B1)
#define SITAR_A_CDC_RX1_B2_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX2_B2_CTL (0x000002B9)
-#define SITAR_A_CDC_RX2_B2_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX3_B2_CTL (0x000002C1)
-#define SITAR_A_CDC_RX3_B2_CTL__POR (0x00000000)
-
-#define SITAR_A_CDC_RX1_B3_CTL (0x000002B2)
+#define SITAR_A_CDC_RX1_B3_CTL (0x2B2)
#define SITAR_A_CDC_RX1_B3_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX2_B3_CTL (0x000002BA)
-#define SITAR_A_CDC_RX2_B3_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX3_B3_CTL (0x000002C2)
-#define SITAR_A_CDC_RX3_B3_CTL__POR (0x00000000)
-
-#define SITAR_A_CDC_RX1_B4_CTL (0x000002B3)
+#define SITAR_A_CDC_RX1_B4_CTL (0x2B3)
#define SITAR_A_CDC_RX1_B4_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX2_B4_CTL (0x000002BB)
-#define SITAR_A_CDC_RX2_B4_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX3_B4_CTL (0x000002C3)
-#define SITAR_A_CDC_RX3_B4_CTL__POR (0x00000000)
-
-#define SITAR_A_CDC_RX1_B5_CTL (0x000002B4)
+#define SITAR_A_CDC_RX1_B5_CTL (0x2B4)
#define SITAR_A_CDC_RX1_B5_CTL__POR (0x00000078)
-#define SITAR_A_CDC_RX2_B5_CTL (0x000002BC)
-#define SITAR_A_CDC_RX2_B5_CTL__POR (0x00000078)
-#define SITAR_A_CDC_RX3_B5_CTL (0x000002C4)
-#define SITAR_A_CDC_RX3_B5_CTL__POR (0x00000078)
-
-#define SITAR_A_CDC_RX1_B6_CTL (0x000002B5)
+#define SITAR_A_CDC_RX1_B6_CTL (0x2B5)
#define SITAR_A_CDC_RX1_B6_CTL__POR (0x00000080)
-#define SITAR_A_CDC_RX2_B6_CTL (0x000002BD)
+#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL (0x2B6)
+#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL (0x2B7)
+#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B1_CTL (0x2B8)
+#define SITAR_A_CDC_RX2_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B2_CTL (0x2B9)
+#define SITAR_A_CDC_RX2_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B3_CTL (0x2BA)
+#define SITAR_A_CDC_RX2_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B4_CTL (0x2BB)
+#define SITAR_A_CDC_RX2_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_B5_CTL (0x2BC)
+#define SITAR_A_CDC_RX2_B5_CTL__POR (0x00000078)
+#define SITAR_A_CDC_RX2_B6_CTL (0x2BD)
#define SITAR_A_CDC_RX2_B6_CTL__POR (0x00000080)
-#define SITAR_A_CDC_RX3_B6_CTL (0x000002C5)
+#define SITAR_A_CDC_RX2_VOL_CTL_B1_CTL (0x2BE)
+#define SITAR_A_CDC_RX2_VOL_CTL_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX2_VOL_CTL_B2_CTL (0x2BF)
+#define SITAR_A_CDC_RX2_VOL_CTL_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B1_CTL (0x2C0)
+#define SITAR_A_CDC_RX3_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B2_CTL (0x2C1)
+#define SITAR_A_CDC_RX3_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B3_CTL (0x2C2)
+#define SITAR_A_CDC_RX3_B3_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B4_CTL (0x2C3)
+#define SITAR_A_CDC_RX3_B4_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_B5_CTL (0x2C4)
+#define SITAR_A_CDC_RX3_B5_CTL__POR (0x00000078)
+#define SITAR_A_CDC_RX3_B6_CTL (0x2C5)
#define SITAR_A_CDC_RX3_B6_CTL__POR (0x00000080)
+#define SITAR_A_CDC_RX3_VOL_CTL_B1_CTL (0x2C6)
+#define SITAR_A_CDC_RX3_VOL_CTL_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_RX3_VOL_CTL_B2_CTL (0x2C7)
+#define SITAR_A_CDC_RX3_VOL_CTL_B2_CTL__POR (0x00000000)
-
-#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL (0x2B6)
-#define SITAR_A_CDC_RX1_VOL_CTL_B1_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL (0x2B7)
-#define SITAR_A_CDC_RX1_VOL_CTL_B2_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX2_VOL_CTL_B2_CTL (0x2BF)
-#define SITAR_A_CDC_RX2_VOL_CTL_B2_CTL__POR (0x00000000)
-#define SITAR_A_CDC_RX3_VOL_CTL_B2_CTL (0x2C7)
-#define SITAR_A_CDC_RX3_VOL_CTL_B2_CTL__POR (0x00000000)
-
-#define SITAR_A_CDC_CLK_ANC_RESET_CTL (0x300)
-#define SITAR_A_CDC_CLK_ANC_RESET_CTL__POR (0x00000000)
-#define SITAR_A_CDC_CLK_RX_RESET_CTL (0x301)
-#define SITAR_A_CDC_CLK_RX_RESET_CTL__POR (0x00000000)
-#define SITAR_A_CDC_CLK_TX_RESET_B1_CTL (0x302)
-#define SITAR_A_CDC_CLK_TX_RESET_B1_CTL__POR (0x00000000)
-#define SITAR_A_CDC_CLK_TX_RESET_B2_CTL (0x303)
-#define SITAR_A_CDC_CLK_TX_RESET_B2_CTL__POR (0x00000000)
-#define SITAR_A_CDC_CLK_DMIC_CTL (0x304)
+#define SITAR_A_CDC_CLK_ANC_RESET_CTL (0x300)
+#define SITAR_A_CDC_CLK_ANC_RESET_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_RX_RESET_CTL (0x301)
+#define SITAR_A_CDC_CLK_RX_RESET_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_TX_RESET_B1_CTL (0x302)
+#define SITAR_A_CDC_CLK_TX_RESET_B1_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_TX_RESET_B2_CTL (0x303)
+#define SITAR_A_CDC_CLK_TX_RESET_B2_CTL__POR (0x00000000)
+#define SITAR_A_CDC_CLK_DMIC_CTL (0x304)
#define SITAR_A_CDC_CLK_DMIC_CTL__POR (0x00000000)
#define SITAR_A_CDC_CLK_RX_I2S_CTL (0x305)
#define SITAR_A_CDC_CLK_RX_I2S_CTL__POR (0x00000003)
@@ -654,7 +703,23 @@
#define SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS__POR (0x00000003)
#define SITAR_A_CDC_COMP1_FS_CFG (0x377)
#define SITAR_A_CDC_COMP1_FS_CFG__POR (0x0000001b)
-#define SITAR_A_CDC_CONN_RX1_B1_CTL (0x380)
+#define SITAR_A_CDC_COMP2_B1_CTL (0x378)
+#define SITAR_A_CDC_COMP2_B1_CTL__POR (0x00000030)
+#define SITAR_A_CDC_COMP2_B2_CTL (0x379)
+#define SITAR_A_CDC_COMP2_B2_CTL__POR (0x000000b5)
+#define SITAR_A_CDC_COMP2_B3_CTL (0x37A)
+#define SITAR_A_CDC_COMP2_B3_CTL__POR (0x00000028)
+#define SITAR_A_CDC_COMP2_B4_CTL (0x37B)
+#define SITAR_A_CDC_COMP2_B4_CTL__POR (0x0000003c)
+#define SITAR_A_CDC_COMP2_B5_CTL (0x37C)
+#define SITAR_A_CDC_COMP2_B5_CTL__POR (0x0000001f)
+#define SITAR_A_CDC_COMP2_B6_CTL (0x37D)
+#define SITAR_A_CDC_COMP2_B6_CTL__POR (0x00000000)
+#define SITAR_A_CDC_COMP2_SHUT_DOWN_STATUS (0x37E)
+#define SITAR_A_CDC_COMP2_SHUT_DOWN_STATUS__POR (0x00000003)
+#define SITAR_A_CDC_COMP2_FS_CFG (0x37F)
+#define SITAR_A_CDC_COMP2_FS_CFG__POR (0x0000001b)
+#define SITAR_A_CDC_CONN_RX1_B1_CTL (0x380)
#define SITAR_A_CDC_CONN_RX1_B1_CTL__POR (0x00000000)
#define SITAR_A_CDC_CONN_RX1_B2_CTL (0x381)
#define SITAR_A_CDC_CONN_RX1_B2_CTL__POR (0x00000000)
diff --git a/include/linux/mfd/wcd9xxx/wcd9320_registers.h b/include/linux/mfd/wcd9xxx/wcd9320_registers.h
index 5725e6e..4b8626a 100644
--- a/include/linux/mfd/wcd9xxx/wcd9320_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9320_registers.h
@@ -701,45 +701,45 @@
#define TAIKO_A_CDC_TX10_VOL_CTL_CFG (0x26A)
#define TAIKO_A_CDC_TX10_VOL_CTL_CFG__POR (0x00)
#define TAIKO_A_CDC_TX1_MUX_CTL (0x223)
-#define TAIKO_A_CDC_TX1_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX1_MUX_CTL__POR (0x08)
#define TAIKO_A_CDC_TX2_MUX_CTL (0x22B)
-#define TAIKO_A_CDC_TX2_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX2_MUX_CTL__POR (0x08)
#define TAIKO_A_CDC_TX3_MUX_CTL (0x233)
-#define TAIKO_A_CDC_TX3_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX3_MUX_CTL__POR (0x08)
#define TAIKO_A_CDC_TX4_MUX_CTL (0x23B)
-#define TAIKO_A_CDC_TX4_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX4_MUX_CTL__POR (0x08)
#define TAIKO_A_CDC_TX5_MUX_CTL (0x243)
-#define TAIKO_A_CDC_TX5_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX5_MUX_CTL__POR (0x08)
#define TAIKO_A_CDC_TX6_MUX_CTL (0x24B)
-#define TAIKO_A_CDC_TX6_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX6_MUX_CTL__POR (0x08)
#define TAIKO_A_CDC_TX7_MUX_CTL (0x253)
-#define TAIKO_A_CDC_TX7_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX7_MUX_CTL__POR (0x08)
#define TAIKO_A_CDC_TX8_MUX_CTL (0x25B)
-#define TAIKO_A_CDC_TX8_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX8_MUX_CTL__POR (0x08)
#define TAIKO_A_CDC_TX9_MUX_CTL (0x263)
-#define TAIKO_A_CDC_TX9_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX9_MUX_CTL__POR (0x08)
#define TAIKO_A_CDC_TX10_MUX_CTL (0x26B)
-#define TAIKO_A_CDC_TX10_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX10_MUX_CTL__POR (0x08)
#define TAIKO_A_CDC_TX1_CLK_FS_CTL (0x224)
-#define TAIKO_A_CDC_TX1_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX1_CLK_FS_CTL__POR (0x03)
#define TAIKO_A_CDC_TX2_CLK_FS_CTL (0x22C)
-#define TAIKO_A_CDC_TX2_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX2_CLK_FS_CTL__POR (0x03)
#define TAIKO_A_CDC_TX3_CLK_FS_CTL (0x234)
-#define TAIKO_A_CDC_TX3_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX3_CLK_FS_CTL__POR (0x03)
#define TAIKO_A_CDC_TX4_CLK_FS_CTL (0x23C)
-#define TAIKO_A_CDC_TX4_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX4_CLK_FS_CTL__POR (0x03)
#define TAIKO_A_CDC_TX5_CLK_FS_CTL (0x244)
-#define TAIKO_A_CDC_TX5_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX5_CLK_FS_CTL__POR (0x03)
#define TAIKO_A_CDC_TX6_CLK_FS_CTL (0x24C)
-#define TAIKO_A_CDC_TX6_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX6_CLK_FS_CTL__POR (0x03)
#define TAIKO_A_CDC_TX7_CLK_FS_CTL (0x254)
-#define TAIKO_A_CDC_TX7_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX7_CLK_FS_CTL__POR (0x03)
#define TAIKO_A_CDC_TX8_CLK_FS_CTL (0x25C)
-#define TAIKO_A_CDC_TX8_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX8_CLK_FS_CTL__POR (0x03)
#define TAIKO_A_CDC_TX9_CLK_FS_CTL (0x264)
-#define TAIKO_A_CDC_TX9_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX9_CLK_FS_CTL__POR (0x03)
#define TAIKO_A_CDC_TX10_CLK_FS_CTL (0x26C)
-#define TAIKO_A_CDC_TX10_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX10_CLK_FS_CTL__POR (0x03)
#define TAIKO_A_CDC_TX1_DMIC_CTL (0x225)
#define TAIKO_A_CDC_TX1_DMIC_CTL__POR (0x00)
#define TAIKO_A_CDC_TX2_DMIC_CTL (0x22D)
@@ -779,9 +779,9 @@
#define TAIKO_A_CDC_SRC2_PDA_CFG (0x2A8)
#define TAIKO_A_CDC_SRC2_PDA_CFG__POR (0x00)
#define TAIKO_A_CDC_SRC1_FS_CTL (0x2A1)
-#define TAIKO_A_CDC_SRC1_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_SRC1_FS_CTL__POR (0x1B)
#define TAIKO_A_CDC_SRC2_FS_CTL (0x2A9)
-#define TAIKO_A_CDC_SRC2_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_SRC2_FS_CTL__POR (0x1B)
#define TAIKO_A_CDC_RX1_B1_CTL (0x2B0)
#define TAIKO_A_CDC_RX1_B1_CTL__POR (0x00)
#define TAIKO_A_CDC_RX2_B1_CTL (0x2B8)
@@ -839,33 +839,33 @@
#define TAIKO_A_CDC_RX7_B4_CTL (0x2E3)
#define TAIKO_A_CDC_RX7_B4_CTL__POR (0x00)
#define TAIKO_A_CDC_RX1_B5_CTL (0x2B4)
-#define TAIKO_A_CDC_RX1_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX1_B5_CTL__POR (0x78)
#define TAIKO_A_CDC_RX2_B5_CTL (0x2BC)
-#define TAIKO_A_CDC_RX2_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX2_B5_CTL__POR (0x78)
#define TAIKO_A_CDC_RX3_B5_CTL (0x2C4)
-#define TAIKO_A_CDC_RX3_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX3_B5_CTL__POR (0x78)
#define TAIKO_A_CDC_RX4_B5_CTL (0x2CC)
-#define TAIKO_A_CDC_RX4_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX4_B5_CTL__POR (0x78)
#define TAIKO_A_CDC_RX5_B5_CTL (0x2D4)
-#define TAIKO_A_CDC_RX5_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX5_B5_CTL__POR (0x78)
#define TAIKO_A_CDC_RX6_B5_CTL (0x2DC)
-#define TAIKO_A_CDC_RX6_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX6_B5_CTL__POR (0x78)
#define TAIKO_A_CDC_RX7_B5_CTL (0x2E4)
-#define TAIKO_A_CDC_RX7_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX7_B5_CTL__POR (0x78)
#define TAIKO_A_CDC_RX1_B6_CTL (0x2B5)
-#define TAIKO_A_CDC_RX1_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX1_B6_CTL__POR (0x80)
#define TAIKO_A_CDC_RX2_B6_CTL (0x2BD)
-#define TAIKO_A_CDC_RX2_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX2_B6_CTL__POR (0x80)
#define TAIKO_A_CDC_RX3_B6_CTL (0x2C5)
-#define TAIKO_A_CDC_RX3_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX3_B6_CTL__POR (0x80)
#define TAIKO_A_CDC_RX4_B6_CTL (0x2CD)
-#define TAIKO_A_CDC_RX4_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX4_B6_CTL__POR (0x80)
#define TAIKO_A_CDC_RX5_B6_CTL (0x2D5)
-#define TAIKO_A_CDC_RX5_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX5_B6_CTL__POR (0x80)
#define TAIKO_A_CDC_RX6_B6_CTL (0x2DD)
-#define TAIKO_A_CDC_RX6_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX6_B6_CTL__POR (0x80)
#define TAIKO_A_CDC_RX7_B6_CTL (0x2E5)
-#define TAIKO_A_CDC_RX7_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX7_B6_CTL__POR (0x80)
#define TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL (0x2B6)
#define TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL__POR (0x00)
#define TAIKO_A_CDC_RX2_VOL_CTL_B1_CTL (0x2BE)
@@ -1041,9 +1041,9 @@
#define TAIKO_A_CDC_IIR2_GAIN_B8_CTL (0x357)
#define TAIKO_A_CDC_IIR2_GAIN_B8_CTL__POR (0x00)
#define TAIKO_A_CDC_IIR1_CTL (0x348)
-#define TAIKO_A_CDC_IIR1_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_CTL__POR (0x40)
#define TAIKO_A_CDC_IIR2_CTL (0x358)
-#define TAIKO_A_CDC_IIR2_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_CTL__POR (0x40)
#define TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL (0x349)
#define TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL__POR (0x00)
#define TAIKO_A_CDC_IIR2_GAIN_TIMER_CTL (0x359)
@@ -1059,35 +1059,35 @@
#define TAIKO_A_CDC_TOP_GAIN_UPDATE (0x360)
#define TAIKO_A_CDC_TOP_GAIN_UPDATE__POR (0x00)
#define TAIKO_A_CDC_COMP0_B1_CTL (0x368)
-#define TAIKO_A_CDC_COMP0_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B1_CTL__POR (0x30)
#define TAIKO_A_CDC_COMP1_B1_CTL (0x370)
-#define TAIKO_A_CDC_COMP1_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B1_CTL__POR (0x30)
#define TAIKO_A_CDC_COMP2_B1_CTL (0x378)
-#define TAIKO_A_CDC_COMP2_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B1_CTL__POR (0x30)
#define TAIKO_A_CDC_COMP0_B2_CTL (0x369)
-#define TAIKO_A_CDC_COMP0_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B2_CTL__POR (0xB5)
#define TAIKO_A_CDC_COMP1_B2_CTL (0x371)
-#define TAIKO_A_CDC_COMP1_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B2_CTL__POR (0xB5)
#define TAIKO_A_CDC_COMP2_B2_CTL (0x379)
-#define TAIKO_A_CDC_COMP2_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B2_CTL__POR (0xB5)
#define TAIKO_A_CDC_COMP0_B3_CTL (0x36A)
-#define TAIKO_A_CDC_COMP0_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B3_CTL__POR (0x28)
#define TAIKO_A_CDC_COMP1_B3_CTL (0x372)
-#define TAIKO_A_CDC_COMP1_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B3_CTL__POR (0x28)
#define TAIKO_A_CDC_COMP2_B3_CTL (0x37A)
-#define TAIKO_A_CDC_COMP2_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B3_CTL__POR (0x28)
#define TAIKO_A_CDC_COMP0_B4_CTL (0x36B)
-#define TAIKO_A_CDC_COMP0_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B4_CTL__POR (0x3C)
#define TAIKO_A_CDC_COMP1_B4_CTL (0x373)
-#define TAIKO_A_CDC_COMP1_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B4_CTL__POR (0x3C)
#define TAIKO_A_CDC_COMP2_B4_CTL (0x37B)
-#define TAIKO_A_CDC_COMP2_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B4_CTL__POR (0x3C)
#define TAIKO_A_CDC_COMP0_B5_CTL (0x36C)
-#define TAIKO_A_CDC_COMP0_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B5_CTL__POR (0x1F)
#define TAIKO_A_CDC_COMP1_B5_CTL (0x374)
-#define TAIKO_A_CDC_COMP1_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B5_CTL__POR (0x1F)
#define TAIKO_A_CDC_COMP2_B5_CTL (0x37C)
-#define TAIKO_A_CDC_COMP2_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B5_CTL__POR (0x1F)
#define TAIKO_A_CDC_COMP0_B6_CTL (0x36D)
#define TAIKO_A_CDC_COMP0_B6_CTL__POR (0x00)
#define TAIKO_A_CDC_COMP1_B6_CTL (0x375)
@@ -1095,17 +1095,17 @@
#define TAIKO_A_CDC_COMP2_B6_CTL (0x37D)
#define TAIKO_A_CDC_COMP2_B6_CTL__POR (0x00)
#define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS (0x36E)
-#define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS__POR (0x00)
+#define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS__POR (0x03)
#define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS (0x376)
-#define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS__POR (0x00)
+#define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS__POR (0x03)
#define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS (0x37E)
-#define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS__POR (0x00)
+#define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS__POR (0x03)
#define TAIKO_A_CDC_COMP0_FS_CFG (0x36F)
-#define TAIKO_A_CDC_COMP0_FS_CFG__POR (0x00)
+#define TAIKO_A_CDC_COMP0_FS_CFG__POR (0x03)
#define TAIKO_A_CDC_COMP1_FS_CFG (0x377)
-#define TAIKO_A_CDC_COMP1_FS_CFG__POR (0x00)
+#define TAIKO_A_CDC_COMP1_FS_CFG__POR (0x03)
#define TAIKO_A_CDC_COMP2_FS_CFG (0x37F)
-#define TAIKO_A_CDC_COMP2_FS_CFG__POR (0x00)
+#define TAIKO_A_CDC_COMP2_FS_CFG__POR (0x03)
#define TAIKO_A_CDC_CONN_RX1_B1_CTL (0x380)
#define TAIKO_A_CDC_CONN_RX1_B1_CTL__POR (0x00)
#define TAIKO_A_CDC_CONN_RX1_B2_CTL (0x381)
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
index c66e953..357f400 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -39,4 +39,12 @@
#define WCD9XXX_A_CDC_CTL__POR (0x00000000)
#define WCD9XXX_A_LEAKAGE_CTL (0x88)
#define WCD9XXX_A_LEAKAGE_CTL__POR (0x00000004)
+#define WCD9XXX_A_INTR_MODE (0x90)
+#define WCD9XXX_A_INTR_MASK0 (0x94)
+#define WCD9XXX_A_INTR_STATUS0 (0x98)
+#define WCD9XXX_A_INTR_CLEAR0 (0x9C)
+#define WCD9XXX_A_INTR_LEVEL0 (0xA0)
+#define WCD9XXX_A_INTR_LEVEL1 (0xA1)
+#define WCD9XXX_A_INTR_LEVEL2 (0xA2)
+
#endif
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index a80eb59..477733c 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -79,10 +79,13 @@
bool hpi_en; /* HPI enablebit */
bool hpi; /* HPI support bit */
unsigned int hpi_cmd; /* cmd used as HPI */
+ bool bkops; /* background support bit */
+ bool bkops_en; /* background enable bit */
unsigned int data_sector_size; /* 512 bytes or 4KB */
unsigned int data_tag_unit_size; /* DATA TAG UNIT size */
unsigned int boot_ro_lock; /* ro lock support */
bool boot_ro_lockable;
+ u8 raw_exception_status; /* 53 */
u8 raw_partition_support; /* 160 */
u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */
@@ -96,6 +99,7 @@
u8 raw_sec_erase_mult; /* 230 */
u8 raw_sec_feature_support;/* 231 */
u8 raw_trim_mult; /* 232 */
+ u8 raw_bkops_status; /* 246 */
u8 raw_sectors[4]; /* 212 - 4 bytes */
unsigned int feature_support;
@@ -183,6 +187,26 @@
#define SDIO_MAX_FUNCS 7
+enum mmc_packed_stop_reasons {
+ EXCEEDS_SEGMENTS = 0,
+ EXCEEDS_SECTORS,
+ WRONG_DATA_DIR,
+ FLUSH_OR_DISCARD,
+ EMPTY_QUEUE,
+ REL_WRITE,
+ THRESHOLD,
+ LARGE_SEC_ALIGN,
+ MAX_REASONS,
+};
+
+struct mmc_wr_pack_stats {
+ u32 *packing_events;
+ u32 pack_stop_reason[MAX_REASONS];
+ spinlock_t lock;
+ bool enabled;
+ bool print_in_read;
+};
+
/* The number of MMC physical partitions. These consist of:
* boot partitions (2), general purpose partitions (4) in MMC v4.4.
*/
@@ -205,23 +229,47 @@
#define MMC_BLK_DATA_AREA_GP (1<<2)
};
-enum mmc_packed_stop_reasons {
- EXCEEDS_SEGMENTS = 0,
- EXCEEDS_SECTORS,
- WRONG_DATA_DIR,
- FLUSH_OR_DISCARD,
- EMPTY_QUEUE,
- REL_WRITE,
- THRESHOLD,
- MAX_REASONS,
-};
-
-struct mmc_wr_pack_stats {
- u32 *packing_events;
- u32 pack_stop_reason[MAX_REASONS];
- spinlock_t lock;
- bool enabled;
- bool print_in_read;
+/**
+ * struct mmc_bkops_info - BKOPS data
+ * @dw: Idle time bkops delayed work
+ * @host_suspend_tout_ms: The host controller idle time,
+ * before getting into suspend
+ * @delay_ms: The time to start the BKOPS
+ * delayed work once MMC thread is idle
+ * @poll_for_completion: Poll on BKOPS completion
+ * @cancel_delayed_work: A flag to indicate if the delayed work
+ * should be cancelled
+ * @started_delayed_bkops: A flag to indicate if the delayed
+ * work was scheduled
+ * @sectors_changed: number of sectors written or
+ * discard since the last idle BKOPS were scheduled
+ */
+struct mmc_bkops_info {
+ struct delayed_work dw;
+ unsigned int host_suspend_tout_ms;
+ unsigned int delay_ms;
+ unsigned int min_sectors_to_queue_delayed_work;
+/*
+ * A default time for checking the need for non urgent BKOPS once mmcqd
+ * is idle.
+ */
+#define MMC_IDLE_BKOPS_TIME_MS 2000
+ struct work_struct poll_for_completion;
+/* Polling timeout and interval for waiting on non-blocking BKOPs completion */
+#define BKOPS_COMPLETION_POLLING_TIMEOUT_MS 10000 /* in ms */
+#define BKOPS_COMPLETION_POLLING_INTERVAL_MS 1000 /* in ms */
+ bool cancel_delayed_work;
+ bool started_delayed_bkops;
+ unsigned int sectors_changed;
+/*
+ * Since canceling the delayed work might have significant effect on the
+ * performance of small requests we won't queue the delayed work every time
+ * mmcqd thread is idle.
+ * The delayed work for idle BKOPS will be scheduled only after a significant
+ * amount of write or discard data.
+ * 100MB is chosen based on benchmark tests.
+ */
+#define BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK 204800 /* 100MB */
};
/*
@@ -247,6 +295,7 @@
#define MMC_CARD_REMOVED (1<<7) /* card has been removed */
#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
#define MMC_STATE_SLEEP (1<<9) /* card is in sleep state */
+#define MMC_STATE_DOING_BKOPS (1<<10) /* card is doing BKOPS */
unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
@@ -298,6 +347,8 @@
unsigned int nr_parts;
struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/
+
+ struct mmc_bkops_info bkops_info;
};
/*
@@ -315,6 +366,11 @@
card->nr_parts++;
}
+static inline bool mmc_large_sec(struct mmc_card *card)
+{
+ return card->ext_csd.data_sector_size == 4096;
+}
+
/*
* The world is not perfect and supplies us with broken mmc/sdio devices.
* For at least some of these bugs we need a work-around.
@@ -415,6 +471,7 @@
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#define mmc_card_is_sleep(c) ((c)->state & MMC_STATE_SLEEP)
+#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -427,7 +484,9 @@
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
#define mmc_card_set_sleep(c) ((c)->state |= MMC_STATE_SLEEP)
+#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS)
+#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS)
#define mmc_card_clr_sleep(c) ((c)->state &= ~MMC_STATE_SLEEP)
/*
* Quirk add/remove for MMC products.
@@ -518,7 +577,6 @@
extern void mmc_fixup_device(struct mmc_card *card,
const struct mmc_fixup *table);
-
extern struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics(
struct mmc_card *card);
extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 817862f..2795734 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -138,6 +138,8 @@
struct mmc_card;
struct mmc_async_req;
+extern int mmc_stop_bkops(struct mmc_card *);
+extern int mmc_read_bkops_status(struct mmc_card *);
extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
struct mmc_async_req *, int *);
extern int mmc_interrupt_hpi(struct mmc_card *);
@@ -146,6 +148,11 @@
extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
struct mmc_command *, int);
+extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
+extern void mmc_start_delayed_bkops(struct mmc_card *card);
+extern void mmc_start_idle_time_bkops(struct work_struct *work);
+extern void mmc_bkops_completion_polling(struct work_struct *work);
+extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index dcd9a6f..9e536be 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -246,7 +246,9 @@
#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
MMC_CAP2_PACKED_WR) /* Allow packed commands */
#define MMC_CAP2_PACKED_WR_CONTROL (1 << 12) /* Allow write packing control */
+
#define MMC_CAP2_SANITIZE (1 << 13) /* Support Sanitize */
+#define MMC_CAP2_INIT_BKOPS (1 << 15) /* Need to set BKOPS_EN */
#define MMC_CAP2_POWER_OFF_VCCQ_DURING_SUSPEND (1 << 16)
mmc_pm_flag_t pm_caps; /* supported pm features */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index ce4d3c2..92888c3 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -139,8 +139,8 @@
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
+#define R1_EXCEPTION_EVENT (1 << 6) /* sx, a */
#define R1_APP_CMD (1 << 5) /* sr, c */
-#define R1_EXP_EVENT (1 << 6) /* sr, a */
#define R1_STATE_IDLE 0
#define R1_STATE_READY 1
@@ -286,6 +286,8 @@
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
#define EXT_CSD_HPI_MGMT 161 /* R/W */
#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
+#define EXT_CSD_BKOPS_EN 163 /* R/W */
+#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_BOOT_WP 173 /* R/W */
@@ -319,6 +321,7 @@
#define EXT_CSD_PWR_CL_200_360 237 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */
+#define EXT_CSD_BKOPS_STATUS 246 /* RO */
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
@@ -326,6 +329,7 @@
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
+#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
@@ -395,6 +399,18 @@
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
+/*
+ * EXCEPTION_EVENT_STATUS field
+ */
+#define EXT_CSD_URGENT_BKOPS BIT(0)
+#define EXT_CSD_DYNCAP_NEEDED BIT(1)
+#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
+
+/*
+ * BKOPS status level
+ */
+#define EXT_CSD_BKOPS_LEVEL_2 0x2
+
#define EXT_CSD_PACKED_EVENT_EN (1 << 3)
#define EXT_CSD_PACKED_FAILURE (1 << 3)
diff --git a/include/linux/msm_charm.h b/include/linux/msm_charm.h
index 44d2553..1d1f3bb 100644
--- a/include/linux/msm_charm.h
+++ b/include/linux/msm_charm.h
@@ -12,6 +12,7 @@
#define WAIT_FOR_RESTART _IOR(CHARM_CODE, 7, int)
#define GET_DLOAD_STATUS _IOR(CHARM_CODE, 8, int)
#define IMAGE_UPGRADE _IOW(CHARM_CODE, 9, int)
+#define SHUTDOWN_CHARM _IOW(CHARM_CODE, 10, int)
enum charm_boot_type {
CHARM_NORMAL_BOOT = 0,
diff --git a/include/linux/msm_ion.h b/include/linux/msm_ion.h
index 0e28e54..21000f9 100644
--- a/include/linux/msm_ion.h
+++ b/include/linux/msm_ion.h
@@ -1,5 +1,4 @@
/*
- * include/linux/ion.h
*
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
@@ -19,4 +18,294 @@
#include <linux/ion.h>
+enum msm_ion_heap_types {
+ ION_HEAP_TYPE_MSM_START = ION_HEAP_TYPE_CUSTOM + 1,
+ ION_HEAP_TYPE_IOMMU = ION_HEAP_TYPE_MSM_START,
+ ION_HEAP_TYPE_CP,
+};
+
+/**
+ * These are the only ids that should be used for Ion heap ids.
+ * The ids listed are the order in which allocation will be attempted
+ * if specified. Don't swap the order of heap ids unless you know what
+ * you are doing!
+ * Id's are spaced by purpose to allow new Id's to be inserted in-between (for
+ * possible fallbacks)
+ */
+
+enum ion_heap_ids {
+ INVALID_HEAP_ID = -1,
+ ION_CP_MM_HEAP_ID = 8,
+ ION_CP_MFC_HEAP_ID = 12,
+ ION_CP_WB_HEAP_ID = 16, /* 8660 only */
+ ION_CAMERA_HEAP_ID = 20, /* 8660 only */
+ ION_SF_HEAP_ID = 24,
+ ION_IOMMU_HEAP_ID = 25,
+ ION_QSECOM_HEAP_ID = 27,
+ ION_AUDIO_HEAP_ID = 28,
+
+ ION_MM_FIRMWARE_HEAP_ID = 29,
+ ION_SYSTEM_HEAP_ID = 30,
+
+ ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_SECURE flag */
+};
+
+enum ion_fixed_position {
+ NOT_FIXED,
+ FIXED_LOW,
+ FIXED_MIDDLE,
+ FIXED_HIGH,
+};
+
+enum cp_mem_usage {
+ VIDEO_BITSTREAM = 0x1,
+ VIDEO_PIXEL = 0x2,
+ VIDEO_NONPIXEL = 0x3,
+ MAX_USAGE = 0x4,
+ UNKNOWN = 0x7FFFFFFF,
+};
+
+#define ION_HEAP_CP_MASK (1 << ION_HEAP_TYPE_CP)
+
+/**
+ * Flag to use when allocating to indicate that a heap is secure.
+ */
+#define ION_SECURE (1 << ION_HEAP_ID_RESERVED)
+
+/**
+ * Macro should be used with ion_heap_ids defined above.
+ */
+#define ION_HEAP(bit) (1 << (bit))
+
+#define ION_VMALLOC_HEAP_NAME "vmalloc"
+#define ION_AUDIO_HEAP_NAME "audio"
+#define ION_SF_HEAP_NAME "sf"
+#define ION_MM_HEAP_NAME "mm"
+#define ION_CAMERA_HEAP_NAME "camera_preview"
+#define ION_IOMMU_HEAP_NAME "iommu"
+#define ION_MFC_HEAP_NAME "mfc"
+#define ION_WB_HEAP_NAME "wb"
+#define ION_MM_FIRMWARE_HEAP_NAME "mm_fw"
+#define ION_QSECOM_HEAP_NAME "qsecom"
+#define ION_FMEM_HEAP_NAME "fmem"
+
+#define ION_SET_CACHED(__cache) (__cache | ION_FLAG_CACHED)
+#define ION_SET_UNCACHED(__cache) (__cache & ~ION_FLAG_CACHED)
+
+#define ION_IS_CACHED(__flags) ((__flags) & ION_FLAG_CACHED)
+
+#ifdef __KERNEL__
+
+/*
+ * This flag allows clients when mapping into the IOMMU to specify to
+ * defer un-mapping from the IOMMU until the buffer memory is freed.
+ */
+#define ION_IOMMU_UNMAP_DELAYED 1
+
+/**
+ * struct ion_cp_heap_pdata - defines a content protection heap in the given
+ * platform
+ * @permission_type: Memory ID used to identify the memory to TZ
+ * @align: Alignment requirement for the memory
+ * @secure_base: Base address for securing the heap.
+ * Note: This might be different from actual base address
+ * of this heap in the case of a shared heap.
+ * @secure_size: Memory size for securing the heap.
+ * Note: This might be different from actual size
+ * of this heap in the case of a shared heap.
+ * @reusable Flag indicating whether this heap is reusable of not.
+ * (see FMEM)
+ * @mem_is_fmem Flag indicating whether this memory is coming from fmem
+ * or not.
+ * @fixed_position If nonzero, position in the fixed area.
+ * @virt_addr: Virtual address used when using fmem.
+ * @iommu_map_all: Indicates whether we should map whole heap into IOMMU.
+ * @iommu_2x_map_domain: Indicates the domain to use for overmapping.
+ * @request_region: function to be called when the number of allocations
+ * goes from 0 -> 1
+ * @release_region: function to be called when the number of allocations
+ * goes from 1 -> 0
+ * @setup_region: function to be called upon ion registration
+ * @memory_type:Memory type used for the heap
+ *
+ */
+struct ion_cp_heap_pdata {
+ enum ion_permission_type permission_type;
+ unsigned int align;
+ ion_phys_addr_t secure_base; /* Base addr used when heap is shared */
+ size_t secure_size; /* Size used for securing heap when heap is shared*/
+ int reusable;
+ int mem_is_fmem;
+ enum ion_fixed_position fixed_position;
+ int iommu_map_all;
+ int iommu_2x_map_domain;
+ ion_virt_addr_t *virt_addr;
+ int (*request_region)(void *);
+ int (*release_region)(void *);
+ void *(*setup_region)(void);
+ enum ion_memory_types memory_type;
+};
+
+/**
+ * struct ion_co_heap_pdata - defines a carveout heap in the given platform
+ * @adjacent_mem_id: Id of heap that this heap must be adjacent to.
+ * @align: Alignment requirement for the memory
+ * @mem_is_fmem Flag indicating whether this memory is coming from fmem
+ * or not.
+ * @fixed_position If nonzero, position in the fixed area.
+ * @request_region: function to be called when the number of allocations
+ * goes from 0 -> 1
+ * @release_region: function to be called when the number of allocations
+ * goes from 1 -> 0
+ * @setup_region: function to be called upon ion registration
+ * @memory_type:Memory type used for the heap
+ *
+ */
+struct ion_co_heap_pdata {
+ int adjacent_mem_id;
+ unsigned int align;
+ int mem_is_fmem;
+ enum ion_fixed_position fixed_position;
+ int (*request_region)(void *);
+ int (*release_region)(void *);
+ void *(*setup_region)(void);
+ enum ion_memory_types memory_type;
+};
+
+#ifdef CONFIG_ION
+/**
+ * msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap.
+ *
+ * @heap_id - heap id to secure.
+ *
+ * Secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_secure_heap(int heap_id);
+
+/**
+ * msm_ion_unsecure_heap - unsecure a heap. Wrapper around ion_unsecure_heap.
+ *
+ * @heap_id - heap id to secure.
+ *
+ * Un-secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_unsecure_heap(int heap_id);
+
+/**
+ * msm_ion_secure_heap_2_0 - secure a heap using 2.0 APIs
+ * Wrapper around ion_secure_heap.
+ *
+ * @heap_id - heap id to secure.
+ * @usage - usage hint to TZ
+ *
+ * Secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage);
+
+/**
+ * msm_ion_unsecure_heap - unsecure a heap secured with 3.0 APIs.
+ * Wrapper around ion_unsecure_heap.
+ *
+ * @heap_id - heap id to secure.
+ * @usage - usage hint to TZ
+ *
+ * Un-secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage);
+#else
+static inline int msm_ion_secure_heap(int heap_id)
+{
+ return -ENODEV;
+
+}
+
+static inline int msm_ion_unsecure_heap(int heap_id)
+{
+ return -ENODEV;
+}
+
+static inline int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage)
+{
+ return -ENODEV;
+}
+
+static inline int msm_ion_unsecure_heap_2_0(int heap_id,
+ enum cp_mem_usage usage)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_ION */
+
+#endif /* __KERNEL */
+
+/* struct ion_flush_data - data passed to ion for flushing caches
+ *
+ * @handle: handle with data to flush
+ * @fd: fd to flush
+ * @vaddr: userspace virtual address mapped with mmap
+ * @offset: offset into the handle to flush
+ * @length: length of handle to flush
+ *
+ * Performs cache operations on the handle. If p is the start address
+ * of the handle, p + offset through p + offset + length will have
+ * the cache operations performed
+ */
+struct ion_flush_data {
+ struct ion_handle *handle;
+ int fd;
+ void *vaddr;
+ unsigned int offset;
+ unsigned int length;
+};
+
+/* struct ion_flag_data - information about flags for this buffer
+ *
+ * @handle: handle to get flags from
+ * @flags: flags of this handle
+ *
+ * Takes handle as an input and outputs the flags from the handle
+ * in the flag field.
+ */
+struct ion_flag_data {
+ struct ion_handle *handle;
+ unsigned long flags;
+};
+
+#define ION_IOC_MSM_MAGIC 'M'
+
+/**
+ * DOC: ION_IOC_CLEAN_CACHES - clean the caches
+ *
+ * Clean the caches of the handle specified.
+ */
+#define ION_IOC_CLEAN_CACHES _IOWR(ION_IOC_MSM_MAGIC, 0, \
+ struct ion_flush_data)
+/**
+ * DOC: ION_IOC_INV_CACHES - invalidate the caches
+ *
+ * Invalidate the caches of the handle specified.
+ */
+#define ION_IOC_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 1, \
+ struct ion_flush_data)
+/**
+ * DOC: ION_IOC_CLEAN_INV_CACHES - clean and invalidate the caches
+ *
+ * Clean and invalidate the caches of the handle specified.
+ */
+#define ION_IOC_CLEAN_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 2, \
+ struct ion_flush_data)
+
+/**
+ * DOC: ION_IOC_GET_FLAGS - get the flags of the handle
+ *
+ * Gets the flags of the current handle which indicate cachability,
+ * secure state etc.
+ */
+#define ION_IOC_GET_FLAGS _IOWR(ION_IOC_MSM_MAGIC, 3, \
+ struct ion_flag_data)
+
#endif
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 71ff639..6912087 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -2,7 +2,7 @@
#define _MSM_KGSL_H
#define KGSL_VERSION_MAJOR 3
-#define KGSL_VERSION_MINOR 12
+#define KGSL_VERSION_MINOR 14
/*context flags */
#define KGSL_CONTEXT_SAVE_GMEM 0x00000001
@@ -12,12 +12,47 @@
#define KGSL_CONTEXT_PREAMBLE 0x00000010
#define KGSL_CONTEXT_TRASH_STATE 0x00000020
#define KGSL_CONTEXT_PER_CONTEXT_TS 0x00000040
+#define KGSL_CONTEXT_USER_GENERATED_TS 0x00000080
#define KGSL_CONTEXT_INVALID 0xffffffff
/* Memory allocayion flags */
#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000
+#define KGSL_MEMTYPE_MASK 0x0000FF00
+#define KGSL_MEMTYPE_SHIFT 8
+
+/* Memory types for which allocations are made */
+#define KGSL_MEMTYPE_OBJECTANY 0
+#define KGSL_MEMTYPE_FRAMEBUFFER 1
+#define KGSL_MEMTYPE_RENDERBUFFER 2
+#define KGSL_MEMTYPE_ARRAYBUFFER 3
+#define KGSL_MEMTYPE_ELEMENTARRAYBUFFER 4
+#define KGSL_MEMTYPE_VERTEXARRAYBUFFER 5
+#define KGSL_MEMTYPE_TEXTURE 6
+#define KGSL_MEMTYPE_SURFACE 7
+#define KGSL_MEMTYPE_EGL_SURFACE 8
+#define KGSL_MEMTYPE_GL 9
+#define KGSL_MEMTYPE_CL 10
+#define KGSL_MEMTYPE_CL_BUFFER_MAP 11
+#define KGSL_MEMTYPE_CL_BUFFER_NOMAP 12
+#define KGSL_MEMTYPE_CL_IMAGE_MAP 13
+#define KGSL_MEMTYPE_CL_IMAGE_NOMAP 14
+#define KGSL_MEMTYPE_CL_KERNEL_STACK 15
+#define KGSL_MEMTYPE_COMMAND 16
+#define KGSL_MEMTYPE_2D 17
+#define KGSL_MEMTYPE_EGL_IMAGE 18
+#define KGSL_MEMTYPE_EGL_SHADOW 19
+#define KGSL_MEMTYPE_MULTISAMPLE 20
+#define KGSL_MEMTYPE_KERNEL 255
+
+/*
+ * Alignment hint, passed as the power of 2 exponent.
+ * i.e 4k (2^12) would be 12, 64k (2^16)would be 16.
+ */
+#define KGSL_MEMALIGN_MASK 0x00FF0000
+#define KGSL_MEMALIGN_SHIFT 16
+
/* generic flag values */
#define KGSL_FLAGS_NORMALMODE 0x00000000
#define KGSL_FLAGS_SAFEMODE 0x00000001
@@ -39,6 +74,9 @@
#define KGSL_CLK_MEM_IFACE 0x00000010
#define KGSL_CLK_AXI 0x00000020
+/* Server Side Sync Timeout in milliseconds */
+#define KGSL_SYNCOBJ_SERVER_TIMEOUT 2000
+
/*
* Reset status values for context
*/
@@ -278,8 +316,7 @@
unsigned int offset;
unsigned int hostptr; /*input param */
enum kgsl_user_mem_type memtype;
- unsigned int reserved; /* May be required to add
- params for another mem type */
+ unsigned int flags;
};
#define IOCTL_KGSL_MAP_USER_MEM \
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index d03ecfa..1cdc434 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -71,6 +71,8 @@
#define MSMFB_OVERLAY_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 160, unsigned int)
#define MSMFB_VSYNC_CTRL _IOW(MSMFB_IOCTL_MAGIC, 161, unsigned int)
#define MSMFB_METADATA_SET _IOW(MSMFB_IOCTL_MAGIC, 162, struct msmfb_metadata)
+#define MSMFB_OVERLAY_COMMIT _IOW(MSMFB_IOCTL_MAGIC, 163, unsigned int)
+
#define FB_TYPE_3D_PANEL 0x10101010
#define MDP_IMGTYPE2_START 0x10000
#define MSMFB_DRIVER_VERSION 0xF9E8D701
@@ -276,6 +278,8 @@
#define MDP_PP_OPS_READ 0x2
#define MDP_PP_OPS_WRITE 0x4
#define MDP_PP_OPS_DISABLE 0x8
+#define MDP_PP_IGC_FLAG_ROM0 0x10
+#define MDP_PP_IGC_FLAG_ROM1 0x20
struct mdp_qseed_cfg {
uint32_t table_num;
@@ -405,7 +409,7 @@
struct mdp_histogram_data {
uint32_t block;
- uint8_t bin_cnt;
+ uint32_t bin_cnt;
uint32_t *c0;
uint32_t *c1;
uint32_t *c2;
@@ -422,6 +426,8 @@
struct mdp_pcc_coeff r, g, b;
};
+#define MDP_GAMUT_TABLE_NUM 8
+
enum {
mdp_lut_igc,
mdp_lut_pgc,
@@ -484,6 +490,24 @@
uint32_t cont_adj;
};
+struct mdp_dither_cfg_data {
+ uint32_t block;
+ uint32_t flags;
+ uint32_t g_y_depth;
+ uint32_t r_cr_depth;
+ uint32_t b_cb_depth;
+};
+
+struct mdp_gamut_cfg_data {
+ uint32_t block;
+ uint32_t flags;
+ uint32_t gamut_first;
+ uint32_t tbl_size[MDP_GAMUT_TABLE_NUM];
+ uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM];
+ uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM];
+ uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
+};
+
enum {
mdp_op_pcc_cfg,
mdp_op_csc_cfg,
@@ -491,6 +515,8 @@
mdp_op_qseed_cfg,
mdp_bl_scale_cfg,
mdp_op_pa_cfg,
+ mdp_op_dither_cfg,
+ mdp_op_gamut_cfg,
mdp_op_max,
};
@@ -503,6 +529,8 @@
struct mdp_qseed_cfg_data qseed_cfg_data;
struct mdp_bl_scale_data bl_scale_data;
struct mdp_pa_cfg_data pa_cfg_data;
+ struct mdp_dither_cfg_data dither_cfg_data;
+ struct mdp_gamut_cfg_data gamut_cfg_data;
} data;
};
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 647a7ef..03390b1 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -223,9 +223,14 @@
extern int power_supply_set_supply_type(struct power_supply *psy,
enum power_supply_type supply_type);
extern int power_supply_is_system_supplied(void);
+extern int power_supply_register(struct device *parent,
+ struct power_supply *psy);
+extern void power_supply_unregister(struct power_supply *psy);
+extern int power_supply_powers(struct power_supply *psy, struct device *dev);
#else
static inline struct power_supply *power_supply_get_by_name(char *name)
- { return -ENOSYS; }
+ { return NULL; }
+static inline void power_supply_changed(struct power_supply *psy) { }
static inline int power_supply_am_i_supplied(struct power_supply *psy)
{ return -ENOSYS; }
static inline int power_supply_set_battery_charged(struct power_supply *psy)
@@ -243,16 +248,18 @@
int type)
{ return -ENOSYS; }
static inline int power_supply_set_supply_type(struct power_supply *psy,
- enum power_supply_type supply_type);
+ enum power_supply_type supply_type)
{ return -ENOSYS; }
static inline int power_supply_is_system_supplied(void) { return -ENOSYS; }
+static inline int power_supply_register(struct device *parent,
+ struct power_supply *psy)
+ { return -ENOSYS; }
+static inline void power_supply_unregister(struct power_supply *psy) { }
+static inline int power_supply_powers(struct power_supply *psy,
+ struct device *dev)
+ { return -ENOSYS; }
#endif
-extern int power_supply_register(struct device *parent,
- struct power_supply *psy);
-extern void power_supply_unregister(struct power_supply *psy);
-extern int power_supply_powers(struct power_supply *psy, struct device *dev);
-
/* For APM emulation, think legacy userspace. */
extern struct class *power_supply_class;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2c9509d..1f13da3 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -142,6 +142,8 @@
extern unsigned long nr_iowait_cpu(int cpu);
extern unsigned long this_cpu_load(void);
+extern void sched_update_nr_prod(int cpu, unsigned long nr, bool inc);
+extern void sched_get_nr_running_avg(int *avg, int *iowait_avg);
extern void calc_global_load(unsigned long ticks);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 68a87bf..44c64e8 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -368,6 +368,15 @@
struct mon_bus *mon_bus; /* non-null when associated */
int monitored; /* non-zero when monitored */
#endif
+ unsigned skip_resume:1; /* All USB devices are brought into full
+ * power state after system resume. It
+ * is desirable for some buses to keep
+ * their devices in suspend state even
+ * after system resume. The devices
+ * are resumed later when a remote
+ * wakeup is detected or an interface
+ * driver starts I/O.
+ */
};
/* ----------------------------------------------------------------------- */
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h
index a54b825..c3ea237 100644
--- a/include/linux/usb/audio.h
+++ b/include/linux/usb/audio.h
@@ -175,6 +175,7 @@
__u8 baInterfaceNr[n]; \
} __attribute__ ((packed))
+DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
/* 4.3.2.1 Input Terminal Descriptor */
struct uac_input_terminal_descriptor {
__u8 bLength; /* in bytes: 12 */
@@ -454,6 +455,7 @@
__u8 tSamFreq[n][3]; \
} __attribute__ ((packed))
+DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
#define UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(n) (8 + (n * 3))
struct uac_format_type_i_ext_descriptor {
diff --git a/include/linux/usb/f_accessory.h b/include/linux/usb/f_accessory.h
index 5b2dcf9..61ebe0a 100644
--- a/include/linux/usb/f_accessory.h
+++ b/include/linux/usb/f_accessory.h
@@ -36,13 +36,15 @@
#define ACCESSORY_STRING_URI 4
#define ACCESSORY_STRING_SERIAL 5
-/* Control request for retrieving device's protocol version (currently 1)
+/* Control request for retrieving device's protocol version
*
* requestType: USB_DIR_IN | USB_TYPE_VENDOR
* request: ACCESSORY_GET_PROTOCOL
* value: 0
* index: 0
* data version number (16 bits little endian)
+ * 1 for original accessory support
+ * 2 adds HID and device to host audio support
*/
#define ACCESSORY_GET_PROTOCOL 51
@@ -70,6 +72,65 @@
*/
#define ACCESSORY_START 53
+/* Control request for registering a HID device.
+ * Upon registering, a unique ID is sent by the accessory in the
+ * value parameter. This ID will be used for future commands for
+ * the device
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_REGISTER_HID_DEVICE
+ * value: Accessory assigned ID for the HID device
+ * index: total length of the HID report descriptor
+ * data none
+ */
+#define ACCESSORY_REGISTER_HID 54
+
+/* Control request for unregistering a HID device.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_REGISTER_HID
+ * value: Accessory assigned ID for the HID device
+ * index: 0
+ * data none
+ */
+#define ACCESSORY_UNREGISTER_HID 55
+
+/* Control request for sending the HID report descriptor.
+ * If the HID descriptor is longer than the endpoint zero max packet size,
+ * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
+ * commands. The data for the descriptor must be sent sequentially
+ * if multiple packets are needed.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SET_HID_REPORT_DESC
+ * value: Accessory assigned ID for the HID device
+ * index: offset of data in descriptor
+ * (needed when HID descriptor is too big for one packet)
+ * data the HID report descriptor
+ */
+#define ACCESSORY_SET_HID_REPORT_DESC 56
+
+/* Control request for sending HID events.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SEND_HID_EVENT
+ * value: Accessory assigned ID for the HID device
+ * index: 0
+ * data the HID report for the event
+ */
+#define ACCESSORY_SEND_HID_EVENT 57
+
+/* Control request for setting the audio mode.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SET_AUDIO_MODE
+ * value: 0 - no audio
+ * 1 - device to host, 44100 16-bit stereo PCM
+ * index: 0
+ * data none
+ */
+#define ACCESSORY_SET_AUDIO_MODE 58
+
/* ioctls for retrieving strings set by the host */
#define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[256])
#define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[256])
@@ -79,5 +140,7 @@
#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256])
/* returns 1 if there is a start request pending */
#define ACCESSORY_IS_START_REQUESTED _IO('M', 7)
+/* returns audio mode (set via the ACCESSORY_SET_AUDIO_MODE control request) */
+#define ACCESSORY_GET_AUDIO_MODE _IO('M', 8)
#endif /* __LINUX_USB_F_ACCESSORY_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 8e6550f..d45889c 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -192,9 +192,6 @@
* @mhl_enable: indicates MHL connector or not.
* @disable_reset_on_disconnect: perform USB PHY and LINK reset
* on USB cable disconnection.
- * @enable_dcd: Enable Data Contact Detection circuit. if not set
- * wait for 600msec before proceeding to primary
- * detection.
* @enable_lpm_on_suspend: Enable the USB core to go into Low
* Power Mode, when USB bus is suspended but cable
* is connected.
@@ -216,7 +213,6 @@
unsigned int mpm_otgsessvld_int;
bool mhl_enable;
bool disable_reset_on_disconnect;
- bool enable_dcd;
bool enable_lpm_on_dev_suspend;
bool core_clk_always_on_workaround;
struct msm_bus_scale_pdata *bus_scale_table;
@@ -294,6 +290,8 @@
* @xo_handle: TCXO buffer handle
* @bus_perf_client: Bus performance client handle to request BUS bandwidth
* @mhl_enabled: MHL driver registration successful and MHL enabled.
+ * @chg_check_timer: The timer used to implement the workaround to detect
+ * very slow plug in of wall charger.
*/
struct msm_otg {
struct usb_phy phy;
@@ -323,6 +321,7 @@
#define A_CONN 15
#define B_BUS_REQ 16
#define MHL 17
+#define B_FALSE_SDP 18
unsigned long inputs;
struct work_struct sm_work;
bool sm_work_pending;
@@ -345,6 +344,7 @@
struct msm_xo_voter *xo_handle;
uint32_t bus_perf_client;
bool mhl_enabled;
+ struct timer_list chg_check_timer;
/*
* Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
* analog regulators while going to low power mode.
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index b265eb9..07beb50 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1798,6 +1798,12 @@
V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0 = 7,
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE + 22)
+enum v4l2_mpeg_vidc_video_h264_au_delimiter {
+ V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED = 0,
+ V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED = 1
+};
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index d32bc57..7a194ca 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -58,6 +58,7 @@
int wcnss_hardware_type(void);
void *wcnss_prealloc_get(unsigned int size);
int wcnss_prealloc_put(void *ptr);
+void wcnss_reset_intr(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/vcd_property.h b/include/media/msm/vcd_property.h
index 484d08f..180b38d 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -55,6 +55,7 @@
#define VCD_I_SLICE_DELIVERY_MODE (VCD_START_BASE + 0x27)
#define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
#define VCD_I_SET_TURBO_CLK (VCD_START_BASE + 0x29)
+#define VCD_I_ENABLE_DELIMITER_FLAG (VCD_START_BASE + 0x2A)
#define VCD_START_REQ (VCD_START_BASE + 0x1000)
#define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1)
@@ -373,4 +374,8 @@
u32 sps_pps_for_idr_enable_flag;
};
+struct vcd_property_avc_delimiter_enable {
+ u32 avc_delimiter_enable_flag;
+};
+
#endif
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index ed9af2c..6658b8c 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -34,6 +34,8 @@
#define MSM_CAM_IOCTL_MAGIC 'm'
+#define MAX_SERVER_PAYLOAD_LENGTH 8192
+
#define MSM_CAM_IOCTL_GET_SENSOR_INFO \
_IOR(MSM_CAM_IOCTL_MAGIC, 1, struct msm_camsensor_info *)
@@ -862,7 +864,10 @@
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+16)
#define MSM_V4L2_EXT_CAPTURE_MODE_CSTA \
(MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+17)
-#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+18)
+#define MSM_V4L2_EXT_CAPTURE_MODE_V2X_LIVESHOT \
+ (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+18)
+#define MSM_V4L2_EXT_CAPTURE_MODE_MAX (MSM_V4L2_EXT_CAPTURE_MODE_DEFAULT+19)
+
#define MSM_V4L2_PID_MOTION_ISO V4L2_CID_PRIVATE_BASE
#define MSM_V4L2_PID_EFFECT (V4L2_CID_PRIVATE_BASE+1)
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index d7b1340..1cccb2b 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -104,6 +104,7 @@
#define MARIMBA_2_1 0x02010204
#define BAHAMA_1_0 0x0302010A
#define BAHAMA_2_0 0x04020205
+#define BAHAMA_2_1 0x04020309
#define WAIT_TIMEOUT 2000
#define RADIO_INIT_TIME 15
#define TAVARUA_DELAY 10
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 2641720..3b1bd7c2 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -13,6 +13,7 @@
#ifndef VCAP_FMT_H
#define VCAP_FMT_H
+#include <linux/videodev2.h>
#define V4L2_BUF_TYPE_INTERLACED_IN_DECODER (V4L2_BUF_TYPE_PRIVATE)
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index b2a538c..dd39124 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -41,6 +41,22 @@
#define VCAP_BASE (dev->vcapbase)
#define VCAP_OFFSET(off) (VCAP_BASE + off)
+struct reg_range {
+ u32 min_val;
+ u32 max_val;
+};
+
+#define VCAP_REG_RANGE_1_MIN 0x0
+#define VCAP_REG_RANGE_1_MAX 0x48
+#define VCAP_REG_RANGE_2_MIN 0x100
+#define VCAP_REG_RANGE_2_MAX 0x104
+#define VCAP_REG_RANGE_3_MIN 0x400
+#define VCAP_REG_RANGE_3_MAX 0x7F0
+#define VCAP_REG_RANGE_4_MIN 0x800
+#define VCAP_REG_RANGE_4_MAX 0x8A0
+#define VCAP_REG_RANGE_5_MIN 0xC00
+#define VCAP_REG_RANGE_5_MAX 0xDF0
+
#define VCAP_SW_RESET_REQ (VCAP_BASE + 0x024)
#define VCAP_SW_RESET_STATUS (VCAP_BASE + 0x028)
@@ -128,6 +144,16 @@
struct vcap_client_data *cd;
};
+struct vcap_debugfs_params {
+ atomic_t vc_drop_count;
+ uint32_t vc_timestamp;
+ uint32_t vp_timestamp;
+ uint32_t vp_ewma;/* Exponential moving average */
+ uint32_t clk_rate;
+ uint32_t bw_request;
+ uint32_t reg_addr;
+};
+
struct vcap_dev {
struct v4l2_device v4l2_dev;
@@ -176,6 +202,7 @@
struct nr_param nr_param;
bool nr_update;
+ struct vcap_debugfs_params dbg_p;
};
struct vp_format_data {
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 2918b94..a15d1f1 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -289,7 +289,6 @@
atomic_t queued_count;
struct list_head done_list;
spinlock_t done_lock;
- struct mutex q_lock;
wait_queue_head_t done_wq;
void *alloc_ctx[VIDEO_MAX_PLANES];
diff --git a/include/net/scm.h b/include/net/scm.h
index d456f4c..0c0017c 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -71,9 +71,11 @@
}
static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
- struct scm_cookie *scm)
+ struct scm_cookie *scm, bool forcecreds)
{
memset(scm, 0, sizeof(*scm));
+ if (forcecreds)
+ scm_set_cred(scm, task_tgid(current), current_cred());
unix_get_peersec_dgram(sock, scm);
if (msg->msg_controllen <= 0)
return 0;
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 1da6aa2..d902881 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -1890,6 +1890,7 @@
struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch;
struct afe_param_id_slimbus_cfg slim_sch;
struct afe_param_id_rt_proxy_port_cfg rtproxy;
+ struct afe_param_id_internal_bt_fm_cfg int_bt_fm;
} __packed;
struct afe_audioif_config_command {
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 90872c9..afbe7e0 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1170,6 +1170,7 @@
#define MPEG4_MULTI_AAC 0x00010D86
#define US_POINT_EPOS_FORMAT 0x00012310
#define US_RAW_FORMAT 0x0001127C
+#define US_PROX_FORMAT 0x00012721
#define MULTI_CHANNEL_PCM 0x00010C66
#define ASM_ENCDEC_SBCRATE 0x00010C13
diff --git a/include/sound/compress_params.h b/include/sound/compress_params.h
index 31d684b..54af7d6a 100644
--- a/include/sound/compress_params.h
+++ b/include/sound/compress_params.h
@@ -86,6 +86,7 @@
#define SND_AUDIOCODEC_DTS_PASS_THROUGH ((__u32) 0x00000012)
#define SND_AUDIOCODEC_DTS_LBR ((__u32) 0x00000013)
#define SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK ((__u32) 0x00000014)
+#define SND_AUDIOCODEC_PASS_THROUGH ((__u32) 0x00000015)
/*
* Profile and modes are listed with bit masks. This allows for a
@@ -331,6 +332,10 @@
__u32 bw; /* encoder bandwidth */
__s32 reserved[15];
};
+struct snd_dec_dts {
+ __u32 modelIdLength;
+ __u8 *modelId;
+};
union snd_codec_options {
struct snd_enc_wma wma;
@@ -338,6 +343,7 @@
struct snd_enc_real real;
struct snd_enc_flac flac;
struct snd_enc_generic generic;
+ struct snd_dec_dts dts;
};
/** struct snd_codec_desc - description of codec capabilities
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index 8ccc9f4..e107130 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -13,6 +13,8 @@
#define __Q6AFE_V2_H__
#include <sound/apr_audio-v2.h>
+#define IN 0x000
+#define OUT 0x001
#define MSM_AFE_MONO 0
#define MSM_AFE_MONO_RIGHT 1
#define MSM_AFE_MONO_LEFT 2
@@ -71,6 +73,40 @@
AFE_MAX_PORTS
};
+struct afe_audio_buffer {
+ dma_addr_t phys;
+ void *data;
+ uint32_t used;
+ uint32_t size;/* size of buffer */
+ uint32_t actual_size; /* actual number of bytes read by DSP */
+ struct ion_handle *handle;
+ struct ion_client *client;
+};
+
+struct afe_audio_port_data {
+ struct afe_audio_buffer *buf;
+ uint32_t max_buf_cnt;
+ uint32_t dsp_buf;
+ uint32_t cpu_buf;
+ struct list_head mem_map_handle;
+ uint32_t tmp_hdl;
+ /* read or write locks */
+ struct mutex lock;
+ spinlock_t dsp_lock;
+};
+
+struct afe_audio_client {
+ atomic_t cmd_state;
+ /* Relative or absolute TS */
+ uint32_t time_flag;
+ void *priv;
+ uint64_t time_stamp;
+ struct mutex cmd_lock;
+ /* idx:1 out port, 0: in port*/
+ struct afe_audio_port_data port[2];
+ wait_queue_head_t cmd_wait;
+};
+
int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
int afe_close(int port_id);
int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
@@ -80,6 +116,7 @@
int afe_get_port_index(u16 port_id);
int afe_start_pseudo_port(u16 port_id);
int afe_stop_pseudo_port(u16 port_id);
+uint32_t afe_req_mmap_handle(void);
int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz);
int afe_cmd_memory_map_nowait(int port_id, u32 dma_addr_p, u32 dma_buf_sz);
int afe_cmd_memory_unmap(u32 dma_addr_p);
@@ -98,6 +135,14 @@
int afe_apply_gain(u16 port_id, u16 gain);
int afe_q6_interface_prepare(void);
int afe_get_port_type(u16 port_id);
+int q6afe_audio_client_buf_alloc_contiguous(unsigned int dir,
+ struct afe_audio_client *ac,
+ unsigned int bufsz,
+ unsigned int bufcnt);
+struct afe_audio_client *q6afe_audio_client_alloc(void *priv);
+int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
+ struct afe_audio_client *ac);
+void q6afe_audio_client_free(struct afe_audio_client *ac);
/* if port_id is virtual, convert to physical..
* if port_id is already physical, return physical
*/
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 4021d48..9cc0de4 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -49,6 +49,7 @@
#define FORMAT_MAT 0x0017
#define FORMAT_AAC 0x0018
#define FORMAT_DTS_LBR 0x0019
+#define FORMAT_PASS_THROUGH 0x0020
#define ENCDEC_SBCBITRATE 0x0001
#define ENCDEC_IMMEDIATE_DECODE 0x0002
@@ -283,7 +284,8 @@
uint32_t rate, uint32_t channels);
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
- uint32_t rate, uint32_t channels);
+ uint32_t rate, uint32_t channels,
+ char *channel_map);
int q6asm_media_format_block_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
diff --git a/include/trace/events/mpdcvs_trace.h b/include/trace/events/mpdcvs_trace.h
new file mode 100644
index 0000000..0db1378
--- /dev/null
+++ b/include/trace/events/mpdcvs_trace.h
@@ -0,0 +1,156 @@
+/* Copyright (c) 2012, Free Software 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.
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mpdcvs_trace
+
+#if !defined(_TRACE_MPDCVS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MPDCVS_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(msm_mp,
+
+ TP_PROTO(const char *name, int mp_val),
+
+ TP_ARGS(name, mp_val),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __field(int, mp_val)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->mp_val = mp_val;
+ ),
+
+ TP_printk("ev_name=%s ev_level=%d",
+ __get_str(name),
+ __entry->mp_val)
+);
+
+/* Core function of run_q */
+
+DEFINE_EVENT(msm_mp, msm_mp_runq,
+
+ TP_PROTO(const char *name, int mp_val),
+
+ TP_ARGS(name, mp_val)
+);
+
+DEFINE_EVENT(msm_mp, msm_mp_cpusonline,
+
+ TP_PROTO(const char *name, int mp_val),
+
+ TP_ARGS(name, mp_val)
+);
+
+DEFINE_EVENT(msm_mp, msm_mp_slacktime,
+
+ TP_PROTO(const char *name, int mp_val),
+
+ TP_ARGS(name, mp_val)
+);
+
+DECLARE_EVENT_CLASS(msm_dcvs,
+
+ TP_PROTO(const char *name, const char *cpuid, int val),
+
+ TP_ARGS(name, cpuid, val),
+
+ TP_STRUCT__entry(
+ __string(name, name)
+ __string(cpuid, cpuid)
+ __field(int, val)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __assign_str(cpuid, cpuid);
+ __entry->val = val;
+ ),
+
+ TP_printk("ev_name=%s d_name=%s ev_level=%d",
+ __get_str(name),
+ __get_str(cpuid),
+ __entry->val)
+);
+
+/* Core function of dcvs */
+
+DEFINE_EVENT(msm_dcvs, msm_dcvs_idle,
+
+ TP_PROTO(const char *name, const char *cpuid, int val),
+
+ TP_ARGS(name, cpuid, val)
+);
+
+DEFINE_EVENT(msm_dcvs, msm_dcvs_iowait,
+
+ TP_PROTO(const char *name, const char *cpuid, int val),
+
+ TP_ARGS(name, cpuid, val)
+);
+
+DEFINE_EVENT(msm_dcvs, msm_dcvs_slack_time,
+
+ TP_PROTO(const char *name, const char *cpuid, int val),
+
+ TP_ARGS(name, cpuid, val)
+);
+
+DECLARE_EVENT_CLASS(msm_dcvs_scm,
+
+ TP_PROTO(unsigned long cpuid, int ev_type, unsigned long param0,
+ unsigned long param1, unsigned long ret0, unsigned long ret1),
+
+ TP_ARGS(cpuid, ev_type, param0, param1, ret0, ret1),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, cpuid)
+ __field(int, ev_type)
+ __field(unsigned long, param0)
+ __field(unsigned long, param1)
+ __field(unsigned long, ret0)
+ __field(unsigned long, ret1)
+ ),
+
+ TP_fast_assign(
+ __entry->cpuid = cpuid;
+ __entry->ev_type = ev_type;
+ __entry->param0 = param0;
+ __entry->param1 = param1;
+ __entry->ret0 = ret0;
+ __entry->ret1 = ret1;
+ ),
+
+ TP_printk("dev=%lu ev_type=%d ev_param0=%lu ev_param1=%lu ev_ret0=%lu ev_ret1=%lu",
+ __entry->cpuid,
+ __entry->ev_type,
+ __entry->param0,
+ __entry->param1,
+ __entry->ret0,
+ __entry->ret1)
+);
+
+DEFINE_EVENT(msm_dcvs_scm, msm_dcvs_scm_event,
+
+ TP_PROTO(unsigned long cpuid, int ev_type, unsigned long param0,
+ unsigned long param1, unsigned long ret0, unsigned long ret1),
+
+ TP_ARGS(cpuid, ev_type, param0, param1, ret0, ret1)
+);
+
+#endif /* _TRACE_MPDCVS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/kernel/printk.c b/kernel/printk.c
index 4cf4670..7f51b03 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1224,13 +1224,13 @@
unsigned long action, void *hcpu)
{
switch (action) {
- case CPU_ONLINE:
case CPU_DEAD:
case CPU_DOWN_FAILED:
case CPU_UP_CANCELED:
console_lock();
console_unlock();
break;
+ case CPU_ONLINE:
case CPU_DYING:
/* invoked with preemption disabled, so defer */
if (!console_trylock())
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index d0c5baf..4eec66e 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -295,7 +295,9 @@
static int
cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
{
- return *rdp->nxttail[RCU_DONE_TAIL] && !rcu_gp_in_progress(rsp);
+ return *rdp->nxttail[RCU_DONE_TAIL +
+ ACCESS_ONCE(rsp->completed) != rdp->completed] &&
+ !rcu_gp_in_progress(rsp);
}
/*
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index 9a7dd35..3ede7d9 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -11,7 +11,7 @@
CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer
endif
-obj-y += core.o clock.o idle_task.o fair.o rt.o stop_task.o
+obj-y += core.o clock.o idle_task.o fair.o rt.o stop_task.o sched_avg.o
obj-$(CONFIG_SMP) += cpupri.o
obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
obj-$(CONFIG_SCHEDSTATS) += stats.o
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index fb3acba..451bd4f 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -916,11 +916,13 @@
static inline void inc_nr_running(struct rq *rq)
{
+ sched_update_nr_prod(cpu_of(rq), rq->nr_running, true);
rq->nr_running++;
}
static inline void dec_nr_running(struct rq *rq)
{
+ sched_update_nr_prod(cpu_of(rq), rq->nr_running, false);
rq->nr_running--;
}
diff --git a/kernel/sched/sched_avg.c b/kernel/sched/sched_avg.c
new file mode 100644
index 0000000..8eaf2f7
--- /dev/null
+++ b/kernel/sched/sched_avg.c
@@ -0,0 +1,106 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Scheduler hook for average runqueue determination
+ */
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/hrtimer.h>
+#include <linux/sched.h>
+#include <linux/math64.h>
+
+static DEFINE_PER_CPU(u64, nr_prod_sum);
+static DEFINE_PER_CPU(u64, last_time);
+static DEFINE_PER_CPU(u64, nr);
+static DEFINE_PER_CPU(unsigned long, iowait_prod_sum);
+static DEFINE_PER_CPU(spinlock_t, nr_lock) = __SPIN_LOCK_UNLOCKED(nr_lock);
+static s64 last_get_time;
+
+/**
+ * sched_get_nr_running_avg
+ * @return: Average nr_running and iowait value since last poll.
+ * Returns the avg * 100 to return up to two decimal points
+ * of accuracy.
+ *
+ * Obtains the average nr_running value since the last poll.
+ * This function may not be called concurrently with itself
+ */
+void sched_get_nr_running_avg(int *avg, int *iowait_avg)
+{
+ int cpu;
+ u64 curr_time = sched_clock();
+ u64 diff = curr_time - last_get_time;
+ u64 tmp_avg = 0, tmp_iowait = 0;
+
+ *avg = 0;
+ *iowait_avg = 0;
+
+ if (!diff)
+ return;
+
+ last_get_time = curr_time;
+ /* read and reset nr_running counts */
+ for_each_possible_cpu(cpu) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&per_cpu(nr_lock, cpu), flags);
+ tmp_avg += per_cpu(nr_prod_sum, cpu);
+ tmp_avg += per_cpu(nr, cpu) *
+ (curr_time - per_cpu(last_time, cpu));
+ tmp_iowait = per_cpu(iowait_prod_sum, cpu);
+ tmp_iowait += nr_iowait_cpu(cpu) *
+ (curr_time - per_cpu(last_time, cpu));
+ per_cpu(last_time, cpu) = curr_time;
+ per_cpu(nr_prod_sum, cpu) = 0;
+ per_cpu(iowait_prod_sum, cpu) = 0;
+ spin_unlock_irqrestore(&per_cpu(nr_lock, cpu), flags);
+ }
+
+ *avg = (int)div64_u64(tmp_avg * 100, diff);
+ *iowait_avg = (int)div64_u64(tmp_iowait * 100, diff);
+
+ BUG_ON(*avg < 0);
+ pr_debug("%s - avg:%d\n", __func__, *avg);
+ BUG_ON(*iowait_avg < 0);
+ pr_debug("%s - avg:%d\n", __func__, *iowait_avg);
+}
+EXPORT_SYMBOL(sched_get_nr_running_avg);
+
+/**
+ * sched_update_nr_prod
+ * @cpu: The core id of the nr running driver.
+ * @nr: Updated nr running value for cpu.
+ * @inc: Whether we are increasing or decreasing the count
+ * @return: N/A
+ *
+ * Update average with latest nr_running value for CPU
+ */
+void sched_update_nr_prod(int cpu, unsigned long nr_running, bool inc)
+{
+ int diff;
+ s64 curr_time;
+ unsigned long flags;
+
+ spin_lock_irqsave(&per_cpu(nr_lock, cpu), flags);
+ curr_time = sched_clock();
+ diff = curr_time - per_cpu(last_time, cpu);
+ per_cpu(last_time, cpu) = curr_time;
+ per_cpu(nr, cpu) = nr_running + (inc ? 1 : -1);
+
+ BUG_ON(per_cpu(nr, cpu) < 0);
+
+ per_cpu(nr_prod_sum, cpu) += nr_running * diff;
+ per_cpu(iowait_prod_sum, cpu) += nr_iowait_cpu(cpu) * diff;
+ spin_unlock_irqrestore(&per_cpu(nr_lock, cpu), flags);
+}
+EXPORT_SYMBOL(sched_update_nr_prod);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index a1d2849..5ba1770 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -418,6 +418,19 @@
If in doubt, say N.
+config CPU_FREQ_SWITCH_PROFILER
+ bool "CPU frequency switch time profiler"
+ select GENERIC_TRACER
+ help
+ This option enables the CPU frequency switch profiler. A file is
+ created in debugfs called "cpu_freq_switch_profile_enabled", which
+ defaults to zero. When a 1 is echoed into this file, profiling begins.
+ When a zero is echoed, profiling stops. A "cpu_freq_switch" file is
+ also created in the trace_stats directory; this file shows the
+ switches that have occurred and duration statistics.
+
+ If in doubt, say N.
+
config FTRACE_MCOUNT_RECORD
def_bool y
depends on DYNAMIC_FTRACE
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 5f39a07..3c13931 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -36,6 +36,7 @@
obj-$(CONFIG_IRQSOFF_TRACER) += trace_irqsoff.o
obj-$(CONFIG_PREEMPT_TRACER) += trace_irqsoff.o
obj-$(CONFIG_SCHED_TRACER) += trace_sched_wakeup.o
+obj-$(CONFIG_CPU_FREQ_SWITCH_PROFILER) += trace_cpu_freq_switch.o
obj-$(CONFIG_NOP_TRACER) += trace_nop.o
obj-$(CONFIG_STACK_TRACER) += trace_stack.o
obj-$(CONFIG_MMIOTRACE) += trace_mmiotrace.o
diff --git a/kernel/trace/trace_cpu_freq_switch.c b/kernel/trace/trace_cpu_freq_switch.c
new file mode 100644
index 0000000..7e7b104
--- /dev/null
+++ b/kernel/trace/trace_cpu_freq_switch.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+#include <linux/hrtimer.h>
+#include <linux/debugfs.h>
+#include <linux/ktime.h>
+#include <trace/events/power.h>
+#include "trace_stat.h"
+#include "trace.h"
+
+struct trans {
+ struct rb_node node;
+ unsigned int cpu;
+ unsigned int start_freq;
+ unsigned int end_freq;
+ unsigned int min_us;
+ unsigned int max_us;
+ ktime_t total_t;
+ unsigned int count;
+};
+static struct rb_root freq_trans_tree = RB_ROOT;
+
+static struct trans *tr_search(struct rb_root *root, unsigned int cpu,
+ unsigned int start_freq, unsigned int end_freq)
+{
+ struct rb_node *node = root->rb_node;
+
+ while (node) {
+ struct trans *tr = container_of(node, struct trans, node);
+
+ if (cpu < tr->cpu)
+ node = node->rb_left;
+ else if (cpu > tr->cpu)
+ node = node->rb_right;
+ else if (start_freq < tr->start_freq)
+ node = node->rb_left;
+ else if (start_freq > tr->start_freq)
+ node = node->rb_right;
+ else if (end_freq < tr->end_freq)
+ node = node->rb_left;
+ else if (end_freq > tr->end_freq)
+ node = node->rb_right;
+ else
+ return tr;
+ }
+ return NULL;
+}
+
+static int tr_insert(struct rb_root *root, struct trans *tr)
+{
+ struct rb_node **new = &(root->rb_node), *parent = NULL;
+
+ while (*new) {
+ struct trans *this = container_of(*new, struct trans, node);
+
+ parent = *new;
+ if (tr->cpu < this->cpu)
+ new = &((*new)->rb_left);
+ else if (tr->cpu > this->cpu)
+ new = &((*new)->rb_right);
+ else if (tr->start_freq < this->start_freq)
+ new = &((*new)->rb_left);
+ else if (tr->start_freq > this->start_freq)
+ new = &((*new)->rb_right);
+ else if (tr->end_freq < this->end_freq)
+ new = &((*new)->rb_left);
+ else if (tr->end_freq > this->end_freq)
+ new = &((*new)->rb_right);
+ else
+ return -EINVAL;
+ }
+
+ rb_link_node(&tr->node, parent, new);
+ rb_insert_color(&tr->node, root);
+
+ return 0;
+}
+
+struct trans_state {
+ spinlock_t lock;
+ unsigned int start_freq;
+ unsigned int end_freq;
+ ktime_t start_t;
+ bool started;
+};
+static DEFINE_PER_CPU(struct trans_state, freq_trans_state);
+
+static DEFINE_SPINLOCK(state_lock);
+
+static void probe_start(void *ignore, unsigned int start_freq,
+ unsigned int end_freq, unsigned int cpu)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&state_lock, flags);
+ per_cpu(freq_trans_state, cpu).start_freq = start_freq;
+ per_cpu(freq_trans_state, cpu).end_freq = end_freq;
+ per_cpu(freq_trans_state, cpu).start_t = ktime_get();
+ per_cpu(freq_trans_state, cpu).started = true;
+ spin_unlock_irqrestore(&state_lock, flags);
+}
+
+static void probe_end(void *ignore, unsigned int cpu)
+{
+ unsigned long flags;
+ struct trans *tr;
+ s64 dur_us;
+ ktime_t dur_t, end_t = ktime_get();
+
+ spin_lock_irqsave(&state_lock, flags);
+
+ if (!per_cpu(freq_trans_state, cpu).started)
+ goto out;
+
+ dur_t = ktime_sub(end_t, per_cpu(freq_trans_state, cpu).start_t);
+ dur_us = ktime_to_us(dur_t);
+
+ tr = tr_search(&freq_trans_tree, cpu,
+ per_cpu(freq_trans_state, cpu).start_freq,
+ per_cpu(freq_trans_state, cpu).end_freq);
+ if (!tr) {
+ tr = kzalloc(sizeof(*tr), GFP_ATOMIC);
+ if (!tr) {
+ WARN_ONCE(1, "CPU frequency trace is now invalid!\n");
+ goto out;
+ }
+
+ tr->start_freq = per_cpu(freq_trans_state, cpu).start_freq;
+ tr->end_freq = per_cpu(freq_trans_state, cpu).end_freq;
+ tr->cpu = cpu;
+ tr->min_us = UINT_MAX;
+ tr_insert(&freq_trans_tree, tr);
+ }
+ tr->total_t = ktime_add(tr->total_t, dur_t);
+ tr->count++;
+
+ if (dur_us > tr->max_us)
+ tr->max_us = dur_us;
+ if (dur_us < tr->min_us)
+ tr->min_us = dur_us;
+
+ per_cpu(freq_trans_state, cpu).started = false;
+out:
+ spin_unlock_irqrestore(&state_lock, flags);
+}
+
+static void *freq_switch_stat_start(struct tracer_stat *trace)
+{
+ struct rb_node *n;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state_lock, flags);
+ n = rb_first(&freq_trans_tree);
+ spin_unlock_irqrestore(&state_lock, flags);
+
+ return n;
+}
+
+static void *freq_switch_stat_next(void *prev, int idx)
+{
+ struct rb_node *n;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state_lock, flags);
+ n = rb_next(prev);
+ spin_unlock_irqrestore(&state_lock, flags);
+
+ return n;
+}
+
+static int freq_switch_stat_show(struct seq_file *s, void *p)
+{
+ unsigned long flags;
+ struct trans *tr = p;
+
+ spin_lock_irqsave(&state_lock, flags);
+ seq_printf(s, "%3d %9d %8d %5d %6lld %6d %6d\n", tr->cpu,
+ tr->start_freq, tr->end_freq, tr->count,
+ div_s64(ktime_to_us(tr->total_t), tr->count),
+ tr->min_us, tr->max_us);
+ spin_unlock_irqrestore(&state_lock, flags);
+
+ return 0;
+}
+
+static void freq_switch_stat_release(void *stat)
+{
+ struct trans *tr = stat;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state_lock, flags);
+ rb_erase(&tr->node, &freq_trans_tree);
+ spin_unlock_irqrestore(&state_lock, flags);
+ kfree(tr);
+}
+
+static int freq_switch_stat_headers(struct seq_file *s)
+{
+ seq_printf(s, "CPU START_KHZ END_KHZ COUNT AVG_US MIN_US MAX_US\n");
+ seq_printf(s, " | | | | | | |\n");
+ return 0;
+}
+
+struct tracer_stat freq_switch_stats __read_mostly = {
+ .name = "cpu_freq_switch",
+ .stat_start = freq_switch_stat_start,
+ .stat_next = freq_switch_stat_next,
+ .stat_show = freq_switch_stat_show,
+ .stat_release = freq_switch_stat_release,
+ .stat_headers = freq_switch_stat_headers
+};
+
+static void trace_freq_switch_disable(void)
+{
+ unregister_stat_tracer(&freq_switch_stats);
+ unregister_trace_cpu_frequency_switch_end(probe_end, NULL);
+ unregister_trace_cpu_frequency_switch_start(probe_start, NULL);
+ pr_info("disabled cpu frequency switch time profiling\n");
+}
+
+static int trace_freq_switch_enable(void)
+{
+ int ret;
+
+ ret = register_trace_cpu_frequency_switch_start(probe_start, NULL);
+ if (ret)
+ goto out;
+
+ ret = register_trace_cpu_frequency_switch_end(probe_end, NULL);
+ if (ret)
+ goto err_register_switch_end;
+
+ ret = register_stat_tracer(&freq_switch_stats);
+ if (ret)
+ goto err_register_stat_tracer;
+
+ pr_info("enabled cpu frequency switch time profiling\n");
+ return 0;
+
+err_register_stat_tracer:
+ unregister_trace_cpu_frequency_switch_end(probe_end, NULL);
+err_register_switch_end:
+ register_trace_cpu_frequency_switch_start(probe_start, NULL);
+out:
+ pr_err("failed to enable cpu frequency switch time profiling\n");
+
+ return ret;
+}
+
+static DEFINE_MUTEX(debugfs_lock);
+static bool trace_freq_switch_enabled;
+
+static int debug_toggle_tracing(void *data, u64 val)
+{
+ int ret = 0;
+
+ mutex_lock(&debugfs_lock);
+
+ if (val == 1 && !trace_freq_switch_enabled)
+ ret = trace_freq_switch_enable();
+ else if (val == 0 && trace_freq_switch_enabled)
+ trace_freq_switch_disable();
+ else if (val > 1)
+ ret = -EINVAL;
+
+ if (!ret)
+ trace_freq_switch_enabled = val;
+
+ mutex_unlock(&debugfs_lock);
+
+ return ret;
+}
+
+static int debug_tracing_state_get(void *data, u64 *val)
+{
+ mutex_lock(&debugfs_lock);
+ *val = trace_freq_switch_enabled;
+ mutex_unlock(&debugfs_lock);
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debug_tracing_state_fops, debug_tracing_state_get,
+ debug_toggle_tracing, "%llu\n");
+
+static int __init trace_freq_switch_init(void)
+{
+ struct dentry *d_tracer = tracing_init_dentry();
+ if (!d_tracer)
+ return 0;
+
+ debugfs_create_file("cpu_freq_switch_profile_enabled",
+ S_IRUGO | S_IWUSR, d_tracer, NULL, &debug_tracing_state_fops);
+
+ return 0;
+}
+late_initcall(trace_freq_switch_init);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index faa48f7..59debb7 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1329,7 +1329,7 @@
if (NULL == siocb->scm)
siocb->scm = &scm;
- err = scm_send(sock, msg, siocb->scm);
+ err = scm_send(sock, msg, siocb->scm, true);
if (err < 0)
return err;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index d510353..109e30b 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1446,7 +1446,7 @@
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
wait_for_unix_gc();
- err = scm_send(sock, msg, siocb->scm);
+ err = scm_send(sock, msg, siocb->scm, false);
if (err < 0)
return err;
@@ -1607,7 +1607,7 @@
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
wait_for_unix_gc();
- err = scm_send(sock, msg, siocb->scm);
+ err = scm_send(sock, msg, siocb->scm, false);
if (err < 0)
return err;
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 4c655c2..d2f60a0 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1629,6 +1629,8 @@
$exec_file =~ /^.+\.ihex$/ or
$exec_file =~ /^.+\.hex$/ or
$exec_file =~ /^.+\.HEX$/ or
+ $exec_file =~ /^.+\.dts$/ or
+ $exec_file =~ /^.+\.dtsi$/ or
$exec_file =~ /^.+defconfig$/ or
$exec_file =~ /^Makefile$/ or
$exec_file =~ /^Kconfig$/) &&
diff --git a/sound/soc/codecs/wcd9304-tables.c b/sound/soc/codecs/wcd9304-tables.c
index f0d76e8..ba0b6b6 100644
--- a/sound/soc/codecs/wcd9304-tables.c
+++ b/sound/soc/codecs/wcd9304-tables.c
@@ -419,6 +419,10 @@
[SITAR_A_QFUSE_DATA_OUT1] = 1,
[SITAR_A_QFUSE_DATA_OUT2] = 1,
[SITAR_A_QFUSE_DATA_OUT3] = 1,
+ [SITAR_A_QFUSE_DATA_OUT4] = 1,
+ [SITAR_A_QFUSE_DATA_OUT5] = 1,
+ [SITAR_A_QFUSE_DATA_OUT6] = 1,
+ [SITAR_A_QFUSE_DATA_OUT7] = 1,
[SITAR_A_CDC_CTL] = 1,
[SITAR_A_LEAKAGE_CTL] = 1,
[SITAR_A_INTR_MODE] = 1,
@@ -428,6 +432,9 @@
[SITAR_A_INTR_STATUS0] = 1,
[SITAR_A_INTR_STATUS1] = 1,
[SITAR_A_INTR_STATUS2] = 1,
+ [SITAR_A_INTR_CLEAR0] = 1,
+ [SITAR_A_INTR_CLEAR1] = 1,
+ [SITAR_A_INTR_CLEAR2] = 1,
[SITAR_A_INTR_LEVEL0] = 1,
[SITAR_A_INTR_LEVEL1] = 1,
[SITAR_A_INTR_LEVEL2] = 1,
@@ -593,24 +600,76 @@
[SITAR_A_CDC_ANC1_SPARE] = 1,
[SITAR_A_CDC_ANC1_SMLPF_CTL] = 1,
[SITAR_A_CDC_ANC1_DCFLT_CTL] = 1,
+ [SITAR_A_CDC_ANC2_CTL] = 1,
+ [SITAR_A_CDC_ANC2_SHIFT] = 1,
+ [SITAR_A_CDC_ANC2_IIR_B1_CTL] = 1,
+ [SITAR_A_CDC_ANC2_IIR_B2_CTL] = 1,
+ [SITAR_A_CDC_ANC2_IIR_B3_CTL] = 1,
+ [SITAR_A_CDC_ANC2_IIR_B4_CTL] = 1,
+ [SITAR_A_CDC_ANC2_LPF_B1_CTL] = 1,
+ [SITAR_A_CDC_ANC2_LPF_B2_CTL] = 1,
+ [SITAR_A_CDC_ANC2_LPF_B3_CTL] = 1,
+ [SITAR_A_CDC_ANC2_SPARE] = 1,
+ [SITAR_A_CDC_ANC2_SMLPF_CTL] = 1,
+ [SITAR_A_CDC_ANC2_DCFLT_CTL] = 1,
[SITAR_A_CDC_TX1_VOL_CTL_TIMER] = 1,
[SITAR_A_CDC_TX1_VOL_CTL_GAIN] = 1,
[SITAR_A_CDC_TX1_VOL_CTL_CFG] = 1,
[SITAR_A_CDC_TX1_MUX_CTL] = 1,
[SITAR_A_CDC_TX1_CLK_FS_CTL] = 1,
[SITAR_A_CDC_TX1_DMIC_CTL] = 1,
+ [SITAR_A_CDC_TX2_VOL_CTL_TIMER] = 1,
+ [SITAR_A_CDC_TX2_VOL_CTL_GAIN] = 1,
+ [SITAR_A_CDC_TX2_VOL_CTL_CFG] = 1,
+ [SITAR_A_CDC_TX2_MUX_CTL] = 1,
+ [SITAR_A_CDC_TX2_CLK_FS_CTL] = 1,
+ [SITAR_A_CDC_TX2_DMIC_CTL] = 1,
+ [SITAR_A_CDC_TX3_VOL_CTL_TIMER] = 1,
+ [SITAR_A_CDC_TX3_VOL_CTL_GAIN] = 1,
+ [SITAR_A_CDC_TX3_VOL_CTL_CFG] = 1,
+ [SITAR_A_CDC_TX3_MUX_CTL] = 1,
+ [SITAR_A_CDC_TX3_CLK_FS_CTL] = 1,
+ [SITAR_A_CDC_TX3_DMIC_CTL] = 1,
+ [SITAR_A_CDC_TX4_VOL_CTL_TIMER] = 1,
+ [SITAR_A_CDC_TX4_VOL_CTL_GAIN] = 1,
+ [SITAR_A_CDC_TX4_VOL_CTL_CFG] = 1,
+ [SITAR_A_CDC_TX4_MUX_CTL] = 1,
+ [SITAR_A_CDC_TX4_CLK_FS_CTL] = 1,
+ [SITAR_A_CDC_TX4_DMIC_CTL] = 1,
+ [SITAR_A_CDC_TX5_VOL_CTL_TIMER] = 1,
+ [SITAR_A_CDC_TX5_VOL_CTL_GAIN] = 1,
+ [SITAR_A_CDC_TX5_VOL_CTL_CFG] = 1,
+ [SITAR_A_CDC_TX5_MUX_CTL] = 1,
+ [SITAR_A_CDC_TX5_CLK_FS_CTL] = 1,
+ [SITAR_A_CDC_TX5_DMIC_CTL] = 1,
[SITAR_A_CDC_SRC1_PDA_CFG] = 1,
[SITAR_A_CDC_SRC1_FS_CTL] = 1,
+ [SITAR_A_CDC_SRC2_PDA_CFG] = 1,
+ [SITAR_A_CDC_SRC2_FS_CTL] = 1,
[SITAR_A_CDC_RX1_B1_CTL] = 1,
[SITAR_A_CDC_RX1_B2_CTL] = 1,
[SITAR_A_CDC_RX1_B3_CTL] = 1,
[SITAR_A_CDC_RX1_B4_CTL] = 1,
[SITAR_A_CDC_RX1_B5_CTL] = 1,
- [SITAR_A_CDC_RX2_B5_CTL] = 1,
- [SITAR_A_CDC_RX3_B5_CTL] = 1,
[SITAR_A_CDC_RX1_B6_CTL] = 1,
[SITAR_A_CDC_RX1_VOL_CTL_B1_CTL] = 1,
[SITAR_A_CDC_RX1_VOL_CTL_B2_CTL] = 1,
+ [SITAR_A_CDC_RX2_B1_CTL] = 1,
+ [SITAR_A_CDC_RX2_B2_CTL] = 1,
+ [SITAR_A_CDC_RX2_B3_CTL] = 1,
+ [SITAR_A_CDC_RX2_B4_CTL] = 1,
+ [SITAR_A_CDC_RX2_B5_CTL] = 1,
+ [SITAR_A_CDC_RX2_B6_CTL] = 1,
+ [SITAR_A_CDC_RX2_VOL_CTL_B1_CTL] = 1,
+ [SITAR_A_CDC_RX2_VOL_CTL_B2_CTL] = 1,
+ [SITAR_A_CDC_RX3_B1_CTL] = 1,
+ [SITAR_A_CDC_RX3_B2_CTL] = 1,
+ [SITAR_A_CDC_RX3_B3_CTL] = 1,
+ [SITAR_A_CDC_RX3_B4_CTL] = 1,
+ [SITAR_A_CDC_RX3_B5_CTL] = 1,
+ [SITAR_A_CDC_RX3_B6_CTL] = 1,
+ [SITAR_A_CDC_RX3_VOL_CTL_B1_CTL] = 1,
+ [SITAR_A_CDC_RX3_VOL_CTL_B2_CTL] = 1,
[SITAR_A_CDC_CLK_ANC_RESET_CTL] = 1,
[SITAR_A_CDC_CLK_RX_RESET_CTL] = 1,
[SITAR_A_CDC_CLK_TX_RESET_B1_CTL] = 1,
@@ -652,6 +711,21 @@
[SITAR_A_CDC_IIR1_COEF_B3_CTL] = 1,
[SITAR_A_CDC_IIR1_COEF_B4_CTL] = 1,
[SITAR_A_CDC_IIR1_COEF_B5_CTL] = 1,
+ [SITAR_A_CDC_IIR2_GAIN_B1_CTL] = 1,
+ [SITAR_A_CDC_IIR2_GAIN_B2_CTL] = 1,
+ [SITAR_A_CDC_IIR2_GAIN_B3_CTL] = 1,
+ [SITAR_A_CDC_IIR2_GAIN_B4_CTL] = 1,
+ [SITAR_A_CDC_IIR2_GAIN_B5_CTL] = 1,
+ [SITAR_A_CDC_IIR2_GAIN_B6_CTL] = 1,
+ [SITAR_A_CDC_IIR2_GAIN_B7_CTL] = 1,
+ [SITAR_A_CDC_IIR2_GAIN_B8_CTL] = 1,
+ [SITAR_A_CDC_IIR2_CTL] = 1,
+ [SITAR_A_CDC_IIR2_GAIN_TIMER_CTL] = 1,
+ [SITAR_A_CDC_IIR2_COEF_B1_CTL] = 1,
+ [SITAR_A_CDC_IIR2_COEF_B2_CTL] = 1,
+ [SITAR_A_CDC_IIR2_COEF_B3_CTL] = 1,
+ [SITAR_A_CDC_IIR2_COEF_B4_CTL] = 1,
+ [SITAR_A_CDC_IIR2_COEF_B5_CTL] = 1,
[SITAR_A_CDC_TOP_GAIN_UPDATE] = 1,
[SITAR_A_CDC_TOP_RDAC_DOUT_CTL] = 1,
[SITAR_A_CDC_DEBUG_B1_CTL] = 1,
@@ -669,6 +743,14 @@
[SITAR_A_CDC_COMP1_B6_CTL] = 1,
[SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS] = 1,
[SITAR_A_CDC_COMP1_FS_CFG] = 1,
+ [SITAR_A_CDC_COMP2_B1_CTL] = 1,
+ [SITAR_A_CDC_COMP2_B2_CTL] = 1,
+ [SITAR_A_CDC_COMP2_B3_CTL] = 1,
+ [SITAR_A_CDC_COMP2_B4_CTL] = 1,
+ [SITAR_A_CDC_COMP2_B5_CTL] = 1,
+ [SITAR_A_CDC_COMP2_B6_CTL] = 1,
+ [SITAR_A_CDC_COMP2_SHUT_DOWN_STATUS] = 1,
+ [SITAR_A_CDC_COMP2_FS_CFG] = 1,
[SITAR_A_CDC_CONN_RX1_B1_CTL] = 1,
[SITAR_A_CDC_CONN_RX1_B2_CTL] = 1,
[SITAR_A_CDC_CONN_RX1_B3_CTL] = 1,
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 9432a06..fa7abb1 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -41,6 +41,7 @@
#define ADC_DMIC_SEL_ADC 0
#define ADC_DMIC_SEL_DMIC 1
+#define NUM_AMIC 3
#define NUM_DECIMATORS 4
#define NUM_INTERPOLATORS 3
#define BITS_PER_REG 8
@@ -1712,7 +1713,7 @@
/* reset retry counter as PA is turned off signifying
* start of new OCP detection session
*/
- if (SITAR_IRQ_HPH_PA_OCPL_FAULT)
+ if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
sitar->hphlocp_cnt = 0;
else
sitar->hphrocp_cnt = 0;
@@ -1724,14 +1725,16 @@
{
struct sitar_priv *sitar = container_of(work, struct sitar_priv,
hphlocp_work);
- hphocp_off_report(sitar, SND_JACK_OC_HPHL, SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ hphocp_off_report(sitar, SND_JACK_OC_HPHL,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
}
static void hphrocp_off_report(struct work_struct *work)
{
struct sitar_priv *sitar = container_of(work, struct sitar_priv,
hphrocp_work);
- hphocp_off_report(sitar, SND_JACK_OC_HPHR, SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ hphocp_off_report(sitar, SND_JACK_OC_HPHR,
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
}
static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
@@ -3186,7 +3189,7 @@
short bias_value;
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
if (noreldetection)
sitar_turn_onoff_rel_detection(codec, false);
@@ -3222,7 +3225,7 @@
if (noreldetection)
sitar_turn_onoff_rel_detection(codec, true);
- wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
return bias_value;
}
@@ -3440,7 +3443,7 @@
sitar = snd_soc_codec_get_drvdata(codec);
calibration = sitar->mbhc_cfg.calibration;
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
sitar_turn_onoff_rel_detection(codec, false);
/* First compute the DCE / STA wait times
@@ -3523,7 +3526,7 @@
snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
usleep_range(100, 100);
- wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
sitar_turn_onoff_rel_detection(codec, true);
}
@@ -3807,9 +3810,9 @@
}
sitar_set_and_turnoff_hph_padac(codec);
hphocp_off_report(sitar, SND_JACK_OC_HPHR,
- SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
hphocp_off_report(sitar, SND_JACK_OC_HPHL,
- SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
sitar->current_plug = PLUG_TYPE_NONE;
sitar->mbhc_polling_active = false;
} else {
@@ -4231,9 +4234,9 @@
snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
0x10, 0x10);
wcd9xxx_enable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
wcd9xxx_enable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
/* Bootup time detection */
sitar_hs_gpio_handler(codec);
}
@@ -4623,7 +4626,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
sitar->hphlocp_cnt = 0;
sitar->hph_status |= SND_JACK_OC_HPHL;
if (sitar->mbhc_cfg.headset_jack)
@@ -4656,7 +4659,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
sitar->hphrocp_cnt = 0;
sitar->hph_status |= SND_JACK_OC_HPHR;
if (sitar->mbhc_cfg.headset_jack)
@@ -4679,7 +4682,7 @@
pr_debug("%s: enter\n", __func__);
SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
@@ -4860,6 +4863,7 @@
u8 flag = pdata->amic_settings.use_pdata;
u8 i = 0, j = 0;
u8 val_txfe = 0, value = 0;
+ int amic_reg_count = 0;
if (!pdata) {
rc = -ENODEV;
@@ -4905,7 +4909,8 @@
snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x10,
(pdata->micbias.bias2_cap_mode << 4));
- for (i = 0; i < 6; j++, i += 2) {
+ amic_reg_count = (NUM_AMIC % 2) ? NUM_AMIC + 1 : NUM_AMIC;
+ for (i = 0; i < amic_reg_count; j++, i += 2) {
if (flag & (0x01 << i)) {
value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
@@ -4976,6 +4981,7 @@
SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
+ SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x5B),
};
@@ -5132,44 +5138,49 @@
snd_soc_dapm_sync(dapm);
- ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION,
sitar_hs_insert_irq, "Headset insert detect", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_MBHC_INSERTION);
+ WCD9XXX_IRQ_MBHC_INSERTION);
goto err_insert_irq;
}
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
- ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_REMOVAL,
sitar_hs_remove_irq, "Headset remove detect", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_MBHC_REMOVAL);
+ WCD9XXX_IRQ_MBHC_REMOVAL);
goto err_remove_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_POTENTIAL,
sitar_dce_handler, "DC Estimation detect", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_MBHC_POTENTIAL);
+ WCD9XXX_IRQ_MBHC_POTENTIAL);
goto err_potential_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE,
- sitar_release_handler, "Button Release detect", sitar);
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_RELEASE,
+ sitar_release_handler,
+ "Button Release detect", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_MBHC_RELEASE);
+ WCD9XXX_IRQ_MBHC_RELEASE);
goto err_release_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_SLIMBUS,
- sitar_slimbus_irq, "SLIMBUS Slave", sitar);
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+ sitar_slimbus_irq, "SLIMBUS Slave", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_SLIMBUS);
+ WCD9XXX_IRQ_SLIMBUS);
goto err_slimbus_irq;
}
@@ -5179,24 +5190,27 @@
ret = wcd9xxx_request_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar_hphl_ocp_irq,
- "HPH_L OCP detect", sitar);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+ sitar_hphl_ocp_irq,
+ "HPH_L OCP detect", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_disable_irq(codec->control_data,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
ret = wcd9xxx_request_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPR_FAULT, sitar_hphr_ocp_irq,
- "HPH_R OCP detect", sitar);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+ sitar_hphr_ocp_irq, "HPH_R OCP detect",
+ sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
for (i = 0; i < ARRAY_SIZE(sitar_dai); i++) {
switch (sitar_dai[i].id) {
@@ -5223,23 +5237,20 @@
return ret;
err_hphr_ocp_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+ sitar);
err_hphl_ocp_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_SLIMBUS, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
err_slimbus_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_MBHC_RELEASE, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
err_release_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_MBHC_POTENTIAL, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ sitar);
err_potential_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_MBHC_REMOVAL, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
err_remove_irq:
- wcd9xxx_free_irq(codec->control_data,
- SITAR_IRQ_MBHC_INSERTION, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ sitar);
err_insert_irq:
err_pdata:
mutex_destroy(&sitar->codec_resource_lock);
@@ -5250,11 +5261,13 @@
{
int i;
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_SLIMBUS, sitar);
- wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE, sitar);
- wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL, sitar);
- wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL, sitar);
- wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ sitar);
SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
sitar_codec_disable_clock_block(codec);
SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index a47e446..b64a6a7 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -33,6 +33,9 @@
#include <linux/pm_runtime.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/wakelock.h>
+#include <linux/suspend.h>
#include "wcd9310.h"
static int cfilt_adjust_ms = 10;
@@ -340,6 +343,9 @@
*/
struct work_struct hs_correct_plug_work_nogpio;
+ bool gpio_irq_resend;
+ struct wake_lock irq_resend_wlock;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_poke;
struct dentry *debugfs_mbhc;
@@ -2905,7 +2911,7 @@
/* reset retry counter as PA is turned off signifying
* start of new OCP detection session
*/
- if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
+ if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
tabla->hphlocp_cnt = 0;
else
tabla->hphrocp_cnt = 0;
@@ -2917,14 +2923,16 @@
{
struct tabla_priv *tabla = container_of(work, struct tabla_priv,
hphlocp_work);
- hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ hphocp_off_report(tabla, SND_JACK_OC_HPHL,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
}
static void hphrocp_off_report(struct work_struct *work)
{
struct tabla_priv *tabla = container_of(work, struct tabla_priv,
hphrocp_work);
- hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ hphocp_off_report(tabla, SND_JACK_OC_HPHR,
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
}
static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
@@ -5114,7 +5122,7 @@
short bias_value;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
if (noreldetection)
tabla_turn_onoff_rel_detection(codec, false);
@@ -5150,7 +5158,7 @@
if (noreldetection)
tabla_turn_onoff_rel_detection(codec, true);
- wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
return bias_value;
}
@@ -5339,9 +5347,9 @@
}
tabla_set_and_turnoff_hph_padac(codec);
hphocp_off_report(tabla, SND_JACK_OC_HPHR,
- TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
hphocp_off_report(tabla, SND_JACK_OC_HPHL,
- TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
tabla->current_plug = PLUG_TYPE_NONE;
tabla->mbhc_polling_active = false;
} else {
@@ -5504,7 +5512,7 @@
snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
tabla->mbhc_cfg.micbias);
- wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
pr_debug("%s: leave\n", __func__);
return 0;
@@ -5634,7 +5642,7 @@
tabla = snd_soc_codec_get_drvdata(codec);
calibration = tabla->mbhc_cfg.calibration;
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
tabla_turn_onoff_rel_detection(codec, false);
/* First compute the DCE / STA wait times
@@ -5740,7 +5748,7 @@
snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
usleep_range(100, 100);
- wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
tabla_turn_onoff_rel_detection(codec, true);
}
@@ -6328,7 +6336,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
tabla->hph_status |= SND_JACK_OC_HPHL;
if (tabla->mbhc_cfg.headset_jack)
tabla_snd_soc_jack_report(tabla,
@@ -6362,7 +6370,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
tabla->hph_status |= SND_JACK_OC_HPHR;
if (tabla->mbhc_cfg.headset_jack)
tabla_snd_soc_jack_report(tabla,
@@ -6526,7 +6534,7 @@
s16 mb_v[num_det];
s32 mic_mv[num_det];
bool inval;
- bool highdelta;
+ bool highdelta = false;
bool ahighv = false, highv;
bool gndmicswapped = false;
@@ -6587,26 +6595,29 @@
if (vddioswitch)
__tabla_codec_switch_micbias(tabla->codec, 0,
false, false);
- /* claim UNSUPPORTED plug insertion when
- * good headset is detected but HPHR GND switch makes
- * delta difference */
- if (i == (num_det - 2) && highdelta && !ahighv)
- gndmicswapped = true;
- else if (i == (num_det - 1) && inval) {
- if (gndmicswapped)
- plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
- else
- plug_type[0] = PLUG_TYPE_INVALID;
- }
}
pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
"VDDIO %d, inval %d\n", __func__,
i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
vddioswitch, inval);
/* don't need to run further DCEs */
- if (ahighv && inval)
+ if ((ahighv || !vddioswitch) && inval)
break;
mic_mv[i] = scaled;
+
+ /*
+ * claim UNSUPPORTED plug insertion when
+ * good headset is detected but HPHR GND switch makes
+ * delta difference
+ */
+ if (i == (num_det - 2) && highdelta && !ahighv)
+ gndmicswapped = true;
+ else if (i == (num_det - 1) && inval) {
+ if (gndmicswapped)
+ plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
+ else
+ plug_type[0] = PLUG_TYPE_INVALID;
+ }
}
for (i = 0; (plug_type[0] != PLUG_TYPE_GND_MIC_SWAP && !inval) &&
@@ -6968,7 +6979,7 @@
wcd9xxx_unlock_sleep(core);
} else {
wcd9xxx_enable_irq(codec->control_data,
- TABLA_IRQ_MBHC_INSERTION);
+ WCD9XXX_IRQ_MBHC_INSERTION);
pr_err("%s: Error detecting plug insertion\n",
__func__);
}
@@ -7006,7 +7017,7 @@
pr_debug("%s: enter\n", __func__);
TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
0x10);
@@ -7253,7 +7264,8 @@
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
- wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq_sync(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION);
tabla_codec_detect_plug_type(codec);
wcd9xxx_unlock_sleep(tabla_core);
}
@@ -7349,9 +7361,18 @@
{
int r = IRQ_HANDLED;
struct snd_soc_codec *codec = data;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
pr_warn("%s: failed to hold suspend\n", __func__);
+ /*
+ * Give up this IRQ for now and resend this IRQ so IRQ can be
+ * handled after system resume
+ */
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+ tabla->gpio_irq_resend = true;
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ wake_lock_timeout(&tabla->irq_resend_wlock, HZ);
r = IRQ_NONE;
} else {
tabla_hs_gpio_handler(codec);
@@ -7467,9 +7488,9 @@
if (!IS_ERR_VALUE(ret)) {
snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
wcd9xxx_enable_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
wcd9xxx_enable_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
if (tabla->mbhc_cfg.gpio) {
ret = request_threaded_irq(tabla->mbhc_cfg.gpio_irq,
@@ -8200,44 +8221,50 @@
snd_soc_dapm_sync(dapm);
- ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION,
tabla_hs_insert_irq, "Headset insert detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_MBHC_INSERTION);
+ WCD9XXX_IRQ_MBHC_INSERTION);
goto err_insert_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
- ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
- tabla_hs_remove_irq, "Headset remove detect", tabla);
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_REMOVAL,
+ tabla_hs_remove_irq,
+ "Headset remove detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_MBHC_REMOVAL);
+ WCD9XXX_IRQ_MBHC_REMOVAL);
goto err_remove_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
- tabla_dce_handler, "DC Estimation detect", tabla);
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_POTENTIAL,
+ tabla_dce_handler, "DC Estimation detect",
+ tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_MBHC_POTENTIAL);
+ WCD9XXX_IRQ_MBHC_POTENTIAL);
goto err_potential_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
- tabla_release_handler, "Button Release detect", tabla);
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE,
+ tabla_release_handler,
+ "Button Release detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_MBHC_RELEASE);
+ WCD9XXX_IRQ_MBHC_RELEASE);
goto err_release_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
- tabla_slimbus_irq, "SLIMBUS Slave", tabla);
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+ tabla_slimbus_irq, "SLIMBUS Slave", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_SLIMBUS);
+ WCD9XXX_IRQ_SLIMBUS);
goto err_slimbus_irq;
}
@@ -8246,24 +8273,35 @@
TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
ret = wcd9xxx_request_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
- "HPH_L OCP detect", tabla);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+ tabla_hphl_ocp_irq,
+ "HPH_L OCP detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
ret = wcd9xxx_request_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
- "HPH_R OCP detect", tabla);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+ tabla_hphr_ocp_irq,
+ "HPH_R OCP detect", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+
+ /*
+ * Register suspend lock and notifier to resend edge triggered
+ * gpio IRQs
+ */
+ wake_lock_init(&tabla->irq_resend_wlock, WAKE_LOCK_SUSPEND,
+ "tabla_gpio_irq_resend");
+ tabla->gpio_irq_resend = false;
+
for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
switch (tabla_dai[i].id) {
case AIF1_PB:
@@ -8307,17 +8345,19 @@
err_hphr_ocp_irq:
wcd9xxx_free_irq(codec->control_data,
- TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, tabla);
err_hphl_ocp_irq:
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tabla);
err_slimbus_irq:
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
err_release_irq:
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ tabla);
err_potential_irq:
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
err_remove_irq:
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ tabla);
err_insert_irq:
err_pdata:
mutex_destroy(&tabla->codec_resource_lock);
@@ -8328,11 +8368,16 @@
{
int i;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
- wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
+
+ wake_lock_destroy(&tabla->irq_resend_wlock);
+
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ tabla);
TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
tabla_codec_disable_clock_block(codec);
TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
@@ -8377,11 +8422,29 @@
static int tabla_resume(struct device *dev)
{
+ int irq;
struct platform_device *pdev = to_platform_device(dev);
struct tabla_priv *tabla = platform_get_drvdata(pdev);
+
dev_dbg(dev, "%s: system resume tabla %p\n", __func__, tabla);
- if (tabla)
+ if (tabla) {
+ TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
tabla->mbhc_last_resume = jiffies;
+ if (tabla->gpio_irq_resend) {
+ WARN_ON(!tabla->mbhc_cfg.gpio_irq);
+ tabla->gpio_irq_resend = false;
+
+ irq = tabla->mbhc_cfg.gpio_irq;
+ pr_debug("%s: Resending GPIO IRQ %d\n", __func__, irq);
+ irq_set_pending(irq);
+ check_irq_resend(irq_to_desc(irq), irq);
+
+ /* release suspend lock */
+ wake_unlock(&tabla->irq_resend_wlock);
+ }
+ TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/wcd9320-tables.c b/sound/soc/codecs/wcd9320-tables.c
index 68a4670..c49c276 100644
--- a/sound/soc/codecs/wcd9320-tables.c
+++ b/sound/soc/codecs/wcd9320-tables.c
@@ -673,7 +673,7 @@
[TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL] = 1,
};
-const u8 taiko_reg_defaults[TAIKO_CACHE_SIZE] = {
+const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE] = {
[TAIKO_A_CHIP_CTL] = TAIKO_A_CHIP_CTL__POR,
[TAIKO_A_CHIP_STATUS] = TAIKO_A_CHIP_STATUS__POR,
[TAIKO_A_CHIP_ID_BYTE_0] = TAIKO_A_CHIP_ID_BYTE_0__POR,
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 136024c..d187ea5 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -685,7 +685,7 @@
u32 compander, u32 enable, int event)
{
int value = 0;
- int mask = 1 << 4;
+ int mask = 1 << 5;
int gain = 0;
int gain_offset;
if (compander >= COMPANDER_MAX) {
@@ -778,6 +778,9 @@
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
u32 rate = taiko->comp_fs[w->shift];
+ pr_debug("%s: %s event %d enabled = %d", __func__, w->name,
+ event, taiko->comp_enabled[w->shift]);
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (taiko->comp_enabled[w->shift] != 0) {
@@ -828,19 +831,23 @@
break;
case SND_SOC_DAPM_PRE_PMD:
/* Halt the compander*/
- snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
- w->shift * 8, 1 << 2, 1 << 2);
+ if (taiko->comp_enabled[w->shift] != 0) {
+ snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 1 << 2, 1 << 2);
+ }
break;
case SND_SOC_DAPM_POST_PMD:
/* Restore the gain */
- taiko_config_gain_compander(codec, w->shift,
- taiko->comp_enabled[w->shift], event);
- /* Disable the compander*/
- snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
- w->shift * 8, 0x03, 0x00);
- /* Turn off the clock for compander in pair*/
- snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_B2_CTL,
- 0x03 << comp_shift[w->shift], 0);
+ if (taiko->comp_enabled[w->shift] != 0) {
+ taiko_config_gain_compander(codec, w->shift,
+ taiko->comp_enabled[w->shift], event);
+ /* Disable the compander*/
+ snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x00);
+ /* Turn off the clock for compander in pair*/
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_B2_CTL,
+ 0x03 << comp_shift[w->shift], 0);
+ }
break;
}
return 0;
@@ -1716,7 +1723,7 @@
usleep_range(100, 100);
taiko_codec_enable_audio_mode_bandgap(codec);
} else if (choice == TAIKO_BANDGAP_OFF) {
- snd_soc_write(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x00);
+ snd_soc_write(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x50);
} else {
pr_err("%s: Error, Invalid bandgap settings\n", __func__);
}
@@ -1730,7 +1737,7 @@
snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN2, 0x04, 0x00);
usleep_range(50, 50);
snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN2, 0x02, 0x02);
- snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x05, 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x01, 0x00);
usleep_range(50, 50);
taiko->clock_active = false;
}
@@ -1815,10 +1822,9 @@
/* switch to MCLK */
snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x08, 0x00);
- if (taiko->mbhc_polling_active) {
+ if (taiko->mbhc_polling_active)
snd_soc_write(codec, TAIKO_A_CLK_BUFF_EN2, 0x02);
- taiko_codec_enable_config_mode(codec, 0);
- }
+ taiko_codec_enable_config_mode(codec, 0);
}
snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x01, 0x01);
@@ -2658,7 +2664,7 @@
return ret;
}
-static int taiko_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
+static int taiko_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
@@ -2763,7 +2769,7 @@
/* reset retry counter as PA is turned off signifying
* start of new OCP detection session
*/
- if (TAIKO_IRQ_HPH_PA_OCPL_FAULT)
+ if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
taiko->hphlocp_cnt = 0;
else
taiko->hphrocp_cnt = 0;
@@ -2774,15 +2780,17 @@
static void hphlocp_off_report(struct work_struct *work)
{
struct taiko_priv *taiko = container_of(work, struct taiko_priv,
- hphlocp_work);
- hphocp_off_report(taiko, SND_JACK_OC_HPHL, TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ hphlocp_work);
+ hphocp_off_report(taiko, SND_JACK_OC_HPHL,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
}
static void hphrocp_off_report(struct work_struct *work)
{
struct taiko_priv *taiko = container_of(work, struct taiko_priv,
- hphrocp_work);
- hphocp_off_report(taiko, SND_JACK_OC_HPHR, TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ hphrocp_work);
+ hphocp_off_report(taiko, SND_JACK_OC_HPHR,
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
}
static int taiko_hph_pa_event(struct snd_soc_dapm_widget *w,
@@ -3120,7 +3128,7 @@
{"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
{"SPK PA", NULL, "SPK DAC"},
- {"SPK DAC", NULL, "RX7 MIX1"},
+ {"SPK DAC", NULL, "RX7 MIX2"},
{"RX1 CHAIN", NULL, "RX1 MIX2"},
{"RX2 CHAIN", NULL, "RX2 MIX2"},
@@ -4294,38 +4302,38 @@
taiko_spk_dac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
- 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
- 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER_E("RX7 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
- 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER_E("RX4 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
- 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER_E("RX5 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
- 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER_E("RX6 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
- 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_MIXER_E("RX7 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
- 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU),
-
SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX7 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+ 0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+ 0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+ 0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX4 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
+ 0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX5 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
+ 0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX6 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
+ 0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX7 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
+ 0, taiko_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0,
- &rx4_dsm_mux, taiko_codec_reset_interpolator,
+ &rx4_dsm_mux, taiko_codec_enable_interpolator,
SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0,
- &rx6_dsm_mux, taiko_codec_reset_interpolator,
+ &rx6_dsm_mux, taiko_codec_enable_interpolator,
SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MIXER("RX1 CHAIN", TAIKO_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
@@ -4381,10 +4389,10 @@
SND_SOC_DAPM_SUPPLY("CLASS_H_EAR", TAIKO_A_CDC_CLSH_B1_CTL, 4, 0,
taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
+ SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
+ SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
@@ -4678,7 +4686,7 @@
short bias_value;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
if (noreldetection)
taiko_turn_onoff_rel_detection(codec, false);
@@ -4714,7 +4722,7 @@
if (noreldetection)
taiko_turn_onoff_rel_detection(codec, true);
- wcd9xxx_enable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
return bias_value;
}
@@ -4901,9 +4909,9 @@
}
taiko_set_and_turnoff_hph_padac(codec);
hphocp_off_report(taiko, SND_JACK_OC_HPHR,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
hphocp_off_report(taiko, SND_JACK_OC_HPHL,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
taiko->current_plug = PLUG_TYPE_NONE;
taiko->mbhc_polling_active = false;
} else {
@@ -5047,7 +5055,7 @@
snd_soc_update_bits(codec, taiko->reg_addr.micb_4_mbhc, 0x3,
taiko->mbhc_cfg.micbias);
- wcd9xxx_enable_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
return 0;
}
@@ -5156,7 +5164,7 @@
taiko = snd_soc_codec_get_drvdata(codec);
calibration = taiko->mbhc_cfg.calibration;
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
taiko_turn_onoff_rel_detection(codec, false);
/* First compute the DCE / STA wait times
@@ -5239,7 +5247,7 @@
snd_soc_write(codec, TAIKO_A_MBHC_SCALING_MUX_1, 0x84);
usleep_range(100, 100);
- wcd9xxx_enable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
taiko_turn_onoff_rel_detection(codec, true);
}
@@ -5789,7 +5797,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
taiko->hphlocp_cnt = 0;
taiko->hph_status |= SND_JACK_OC_HPHL;
if (taiko->mbhc_cfg.headset_jack)
@@ -5822,7 +5830,7 @@
0x10);
} else {
wcd9xxx_disable_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
taiko->hphrocp_cnt = 0;
taiko->hph_status |= SND_JACK_OC_HPHR;
if (taiko->mbhc_cfg.headset_jack)
@@ -6348,7 +6356,7 @@
wcd9xxx_unlock_sleep(core);
} else {
wcd9xxx_enable_irq(codec->control_data,
- TAIKO_IRQ_MBHC_INSERTION);
+ WCD9XXX_IRQ_MBHC_INSERTION);
pr_err("%s: Error detecting plug insertion\n",
__func__);
}
@@ -6363,7 +6371,7 @@
pr_debug("%s: enter\n", __func__);
TAIKO_ACQUIRE_LOCK(priv->codec_resource_lock);
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
0x10);
@@ -6587,7 +6595,8 @@
snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x13, 0x00);
snd_soc_update_bits(codec, taiko->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
- wcd9xxx_disable_irq_sync(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq_sync(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION);
taiko_codec_detect_plug_type(codec);
wcd9xxx_unlock_sleep(taiko_core);
}
@@ -6722,9 +6731,9 @@
if (!IS_ERR_VALUE(ret)) {
snd_soc_update_bits(codec, TAIKO_A_RX_HPH_OCP_CTL, 0x10, 0x10);
wcd9xxx_enable_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
wcd9xxx_enable_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
if (taiko->mbhc_cfg.gpio) {
ret = request_threaded_irq(taiko->mbhc_cfg.gpio_irq,
@@ -7088,7 +7097,7 @@
return rc;
}
-static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+static const struct taiko_reg_mask_val taiko_reg_defaults[] = {
/* set MCLk to 9.6 */
TAIKO_REG_VAL(TAIKO_A_CHIP_CTL, 0x0A),
@@ -7096,14 +7105,10 @@
/* EAR PA deafults */
TAIKO_REG_VAL(TAIKO_A_RX_EAR_CMBUFF, 0x05),
- /* HPH PA */
- TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
/** BUCK and NCP defaults for EAR and HS */
TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x50),
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_1, 0x5B),
- TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
/* CLASS-H defaults for EAR and HS */
TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
@@ -7120,7 +7125,6 @@
*/
TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B1_CTL, 0x26),
-
/* RX deafults */
TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B5_CTL, 0x78),
TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B5_CTL, 0x78),
@@ -7142,20 +7146,50 @@
TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
};
+static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+ /*
+ * The following only need to be written for Taiko 1.0 parts.
+ * Taiko 2.0 will have appropriate defaults for these registers.
+ */
+ /* Choose max non-overlap time for NCP */
+ TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
+ /* Use 25mV/50mV for deltap/m to reduce ripple */
+ TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
+ /*
+ * Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
+ * Note that the other bits of this register will be changed during
+ * Rx PA bring up.
+ */
+ TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
+ /* Reduce HPH DAC bias to 70% */
+ TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
+ /*Reduce EAR DAC bias to 70% */
+ TAIKO_REG_VAL(TAIKO_A_RX_EAR_BIAS_PA, 0x76),
+ /* Reduce LINE DAC bias to 70% */
+ TAIKO_REG_VAL(TAIKO_A_RX_LINE_BIAS_PA, 0x78),
+};
+
static void taiko_update_reg_defaults(struct snd_soc_codec *codec)
{
u32 i;
+ struct wcd9xxx *taiko_core = dev_get_drvdata(codec->dev->parent);
- for (i = 0; i < ARRAY_SIZE(taiko_1_0_reg_defaults); i++)
- snd_soc_write(codec, taiko_1_0_reg_defaults[i].reg,
+ for (i = 0; i < ARRAY_SIZE(taiko_reg_defaults); i++)
+ snd_soc_write(codec, taiko_reg_defaults[i].reg,
+ taiko_reg_defaults[i].val);
+
+ if (TAIKO_IS_1_0(taiko_core->version)) {
+ for (i = 0; i < ARRAY_SIZE(taiko_1_0_reg_defaults); i++)
+ snd_soc_write(codec, taiko_1_0_reg_defaults[i].reg,
taiko_1_0_reg_defaults[i].val);
+ }
}
static const struct taiko_reg_mask_val taiko_codec_reg_init_val[] = {
/* Initialize current threshold to 350MA
* number of wait and run cycles to 4096
*/
- {TAIKO_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
+ {TAIKO_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
{TAIKO_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
/* Initialize gain registers to use register gain */
@@ -7185,7 +7219,7 @@
/* Use 16 bit sample size for RX */
{TAIKO_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
- {TAIKO_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
+ {TAIKO_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
/*enable HPF filter for TX paths */
{TAIKO_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
@@ -7350,48 +7384,51 @@
int i;
struct snd_soc_codec *codec = taiko->codec;
- ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION,
taiko_hs_insert_irq, "Headset insert detect",
taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_MBHC_INSERTION);
+ WCD9XXX_IRQ_MBHC_INSERTION);
goto err_insert_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION);
- ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_REMOVAL,
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL,
taiko_hs_remove_irq, "Headset remove detect",
taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_MBHC_REMOVAL);
+ WCD9XXX_IRQ_MBHC_REMOVAL);
goto err_remove_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL,
+ ret = wcd9xxx_request_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_POTENTIAL,
taiko_dce_handler, "DC Estimation detect",
taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_MBHC_POTENTIAL);
+ WCD9XXX_IRQ_MBHC_POTENTIAL);
goto err_potential_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_RELEASE,
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE,
taiko_release_handler, "Button Release detect",
taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_MBHC_RELEASE);
+ WCD9XXX_IRQ_MBHC_RELEASE);
goto err_release_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_SLIMBUS,
+ ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
taiko_slimbus_irq, "SLIMBUS Slave", taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_SLIMBUS);
+ WCD9XXX_IRQ_SLIMBUS);
goto err_slimbus_irq;
}
@@ -7401,40 +7438,44 @@
0xFF);
ret = wcd9xxx_request_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT,
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
taiko_hphl_ocp_irq,
"HPH_L OCP detect", taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
ret = wcd9xxx_request_irq(codec->control_data,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT,
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
taiko_hphr_ocp_irq,
"HPH_R OCP detect", taiko);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
- TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+
+ return 0;
err_hphr_ocp_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_HPH_PA_OCPL_FAULT,
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
taiko);
err_hphl_ocp_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_SLIMBUS, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, taiko);
err_slimbus_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_RELEASE, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, taiko);
err_release_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL, taiko);
+ wcd9xxx_free_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_POTENTIAL, taiko);
err_potential_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_REMOVAL, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, taiko);
err_remove_irq:
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION, taiko);
+ wcd9xxx_free_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION, taiko);
err_insert_irq:
return ret;
@@ -7569,11 +7610,13 @@
{
int i;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_SLIMBUS, taiko);
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_RELEASE, taiko);
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL, taiko);
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_REMOVAL, taiko);
- wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, taiko);
+ wcd9xxx_free_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_POTENTIAL, taiko);
+ wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, taiko);
+ wcd9xxx_free_irq(codec->control_data,
+ WCD9XXX_IRQ_MBHC_INSERTION, taiko);
TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
taiko_codec_disable_clock_block(codec);
TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
@@ -7601,7 +7644,7 @@
.volatile_register = taiko_volatile,
.reg_cache_size = TAIKO_CACHE_SIZE,
- .reg_cache_default = taiko_reg_defaults,
+ .reg_cache_default = taiko_reset_reg_defaults,
.reg_word_size = 1,
.controls = taiko_snd_controls,
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 739ab17..7ca8ff0 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -36,7 +36,7 @@
SND_JACK_BTN_6 | SND_JACK_BTN_7)
extern const u8 taiko_reg_readable[TAIKO_CACHE_SIZE];
-extern const u8 taiko_reg_defaults[TAIKO_CACHE_SIZE];
+extern const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE];
enum taiko_micbias_num {
TAIKO_MICBIAS1 = 0,
diff --git a/sound/soc/msm/apq8064-i2s.c b/sound/soc/msm/apq8064-i2s.c
index 162f39d..e309370 100644
--- a/sound/soc/msm/apq8064-i2s.c
+++ b/sound/soc/msm/apq8064-i2s.c
@@ -63,9 +63,8 @@
#define JACK_DETECT_GPIO 38
-#define APQ_I2S_SLAVE_CONFIG 0
/* MCLK selection GPIOs from PMIC */
-#define PM_GPIO_MCLK_MDM 10
+#define PM_GPIO_MCLK_MDM 27
#define PM_GPIO_MCLK_APQ 41
/* SPKR I2S Configuration */
@@ -170,10 +169,8 @@
};
-#if APQ_I2S_SLAVE_CONFIG
static u32 mdm_mclk_gpio = PM8921_GPIO_PM_TO_SYS(PM_GPIO_MCLK_MDM);
static u32 apq_mclk_gpio = PM8921_GPIO_PM_TO_SYS(PM_GPIO_MCLK_APQ);
-#endif
static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
static int msm_spk_control;
@@ -186,9 +183,6 @@
static struct clk *i2s_rx_bit_clk;
static struct clk *i2s_tx_bit_clk;
-#if (!APQ_I2S_SLAVE_CONFIG)
-static struct clk *mi2s_osr_clk;
-#endif
static struct clk *mi2s_bit_clk;
static int msm_i2s_rx_ch = 1;
@@ -208,6 +202,7 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
static int apq8064_i2s_hs_detect_use_gpio = -1;
module_param(apq8064_i2s_hs_detect_use_gpio, int, 0444);
@@ -952,14 +947,10 @@
static int msm_mi2s_rx_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;
+ pr_debug("%s(): channels = %d\n", __func__, msm_mi2s_rx_ch);
channels->min = channels->max = msm_mi2s_rx_ch;
return 0;
@@ -968,15 +959,10 @@
static int msm_mi2s_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;
-
+ pr_debug("%s(): channels = %d\n", __func__, msm_mi2s_tx_ch);
channels->min = channels->max = msm_mi2s_tx_ch;
return 0;
@@ -986,14 +972,10 @@
static int msm_i2s_rx_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;
+ pr_debug("%s(): channels = %d\n", __func__, msm_i2s_rx_ch);
channels->min = channels->max = msm_i2s_rx_ch;
return 0;
@@ -1002,15 +984,10 @@
static int msm_i2s_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;
-
+ pr_debug("%s(): channels = %d\n", __func__, msm_i2s_tx_ch);
channels->min = channels->max = msm_i2s_tx_ch;
return 0;
@@ -1037,7 +1014,6 @@
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-#if APQ_I2S_SLAVE_CONFIG
struct pm_gpio param = {
.direction = PM_GPIO_DIR_OUT,
.output_buffer = PM_GPIO_OUT_BUF_CMOS,
@@ -1047,14 +1023,13 @@
.out_strength = PM_GPIO_STRENGTH_MED,
.function = PM_GPIO_FUNC_NORMAL,
};
-#endif
+
pr_debug("%s(), dev_name(%s)\n", __func__, dev_name(cpu_dai->dev));
ret = gpio_request(GPIO_MI2S_MCLK, "MI2S_MCLK");
if (ret)
pr_err("%s: Failed to request gpio %d\n", __func__,
GPIO_MI2S_MCLK);
-#if APQ_I2S_SLAVE_CONFIG
/* APQ provides the mclk to codec */
ret = gpio_request(mdm_mclk_gpio, "MDM_MCLK_SWITCH");
if (ret) {
@@ -1069,6 +1044,7 @@
else
gpio_direction_output(mdm_mclk_gpio, 0);
+ pr_debug("%s: Config mdm_mclk_gpio\n", __func__);
ret = gpio_request(apq_mclk_gpio, "APQ_MCLK_SWITCH");
if (ret) {
pr_err("%s: Failed to request gpio %d\n", __func__,
@@ -1081,12 +1057,9 @@
apq_mclk_gpio);
else
gpio_direction_output(apq_mclk_gpio, 1);
- pr_debug("%s: Config mdm_mclk_gpio and apq_mclk_gpio\n",
- __func__);
-#else
- pr_debug("%s: Not config mdm_mclk_gpio and apq_mclk_gpio\n",
- __func__);
-#endif
+
+ pr_debug("%s: Config apq_mclk_gpio\n", __func__);
+
snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
ARRAY_SIZE(apq8064_dapm_widgets));
@@ -1171,12 +1144,10 @@
ret = tabla_hs_detect(codec, &mbhc_cfg);
-#if APQ_I2S_SLAVE_CONFIG
/* MDM provides the mclk to codec */
gpio_direction_output(apq_mclk_gpio, 0);
gpio_direction_output(mdm_mclk_gpio, 1);
- pr_debug("%s: Should not running here if no clock switch\n", __func__);
-#endif
+ pr_debug("%s: Clock switch to MDM\n", __func__);
/* Should we add code to put back codec clock?*/
gpio_free(GPIO_MI2S_MCLK);
pr_debug("%s: Free MCLK GPIO\n", __func__);
@@ -1201,13 +1172,6 @@
clk_put(mi2s_bit_clk);
mi2s_bit_clk = NULL;
}
-#if (!APQ_I2S_SLAVE_CONFIG)
- if (mi2s_osr_clk) {
- clk_disable_unprepare(mi2s_osr_clk);
- clk_put(mi2s_osr_clk);
- mi2s_osr_clk = NULL;
- }
-#endif
msm_mi2s_free_gpios();
}
}
@@ -1249,8 +1213,6 @@
if (atomic_inc_return(&mi2s_rsc_ref) == 1) {
pr_debug("%s: acquire mi2s resources\n", __func__);
msm_configure_mi2s_gpio();
-
-#if APQ_I2S_SLAVE_CONFIG
pr_debug("%s: APQ is MI2S slave\n", __func__);
mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
if (IS_ERR(mi2s_bit_clk))
@@ -1265,38 +1227,6 @@
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM);
if (IS_ERR_VALUE(ret))
pr_err("set format for CPU dai failed\n");
-#else
- pr_debug("%s: APQ is MI2S master\n", __func__);
- mi2s_osr_clk = clk_get(cpu_dai->dev, "osr_clk");
- if (IS_ERR(mi2s_osr_clk))
- return PTR_ERR(mi2s_osr_clk);
- clk_set_rate(mi2s_osr_clk, TABLA_EXT_CLK_RATE);
- ret = clk_prepare_enable(mi2s_osr_clk);
- if (IS_ERR_VALUE(ret)) {
- pr_err("Unable to enable mi2s_osr_clk\n");
- clk_put(mi2s_osr_clk);
- return ret;
- }
- mi2s_bit_clk = clk_get(cpu_dai->dev, "bit_clk");
- if (IS_ERR(mi2s_bit_clk)) {
- pr_err("Unable to get mi2s_bit_clk\n");
- clk_disable_unprepare(mi2s_osr_clk);
- clk_put(mi2s_osr_clk);
- return PTR_ERR(mi2s_bit_clk);
- }
- clk_set_rate(mi2s_bit_clk, 8);
- ret = clk_prepare_enable(mi2s_bit_clk);
- if (IS_ERR_VALUE(ret)) {
- pr_err("Unable to enable mi2s_bit_clk\n");
- clk_disable_unprepare(mi2s_osr_clk);
- clk_put(mi2s_osr_clk);
- clk_put(mi2s_bit_clk);
- return ret;
- }
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
- if (IS_ERR_VALUE(ret))
- pr_err("set format for CPU dai failed\n");
-#endif
}
return ret;
@@ -2027,57 +1957,11 @@
static int msm_aux_pcm_get_gpios(void)
{
- int ret = 0;
-
- pr_debug("%s\n", __func__);
-
- ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
- __func__, GPIO_AUX_PCM_DOUT);
- goto fail_dout;
- }
-
- ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
- __func__, GPIO_AUX_PCM_DIN);
- goto fail_din;
- }
-
- ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
- __func__, GPIO_AUX_PCM_SYNC);
- goto fail_sync;
- }
- ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
- __func__, GPIO_AUX_PCM_CLK);
- goto fail_clk;
- }
-
return 0;
-
-fail_clk:
- gpio_free(GPIO_AUX_PCM_SYNC);
-fail_sync:
- gpio_free(GPIO_AUX_PCM_DIN);
-fail_din:
- gpio_free(GPIO_AUX_PCM_DOUT);
-fail_dout:
-
- return ret;
}
static int msm_aux_pcm_free_gpios(void)
{
- gpio_free(GPIO_AUX_PCM_DIN);
- gpio_free(GPIO_AUX_PCM_DOUT);
- gpio_free(GPIO_AUX_PCM_SYNC);
- gpio_free(GPIO_AUX_PCM_CLK);
-
return 0;
}
static int msm_startup(struct snd_pcm_substream *substream)
@@ -2095,8 +1979,10 @@
{
int ret = 0;
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm_aux_pcm_get_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+ ret = msm_aux_pcm_get_gpios();
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -2120,8 +2006,10 @@
static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm_aux_pcm_free_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm_aux_pcm_free_gpios();
}
static void msm_shutdown(struct snd_pcm_substream *substream)
@@ -2441,6 +2329,14 @@
static struct snd_soc_dai_link msm_dai[] = {
/* FrontEnd DAI Links */
{
+ /*
+ * In APQ8064 I2S platform, there is no playback support
+ * only voice call is supported so there is no even system
+ * tone or dialing tone which is by design because I2S clock
+ * is provided by MDM which matches voice call sample rate
+ * 8kHz or 16kHz while system tone is 48kHz. We disable the
+ * playback by feeding the audio to AUX PCM port.
+ */
.name = "MSM8960 Media1",
.stream_name = "MultiMedia1",
.cpu_dai_name = "MultiMedia1",
@@ -2710,6 +2606,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
},
};
@@ -2785,6 +2682,7 @@
mutex_init(&cdc_mclk_mutex);
atomic_set(&mi2s_rsc_ref, 0);
+ atomic_set(&auxpcm_rsc_ref, 0);
return ret;
}
@@ -2792,7 +2690,8 @@
static void __exit msm_audio_exit(void)
{
- if (!cpu_is_apq8064() || (socinfo_get_id() == 130)) {
+ if (!(cpu_is_apq8064() || cpu_is_apq8064ab()) ||
+ (socinfo_get_id() == 130)) {
pr_err("%s: Not the right machine type\n", __func__);
return ;
}
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 80d6e5d..7894368 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -100,6 +100,7 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
static int apq8064_hs_detect_use_gpio = -1;
module_param(apq8064_hs_detect_use_gpio, int, 0444);
@@ -1352,6 +1353,8 @@
pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
channels->min, channels->max);
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
rate->min = rate->max = 48000;
return 0;
@@ -1468,8 +1471,10 @@
{
int ret = 0;
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm_aux_pcm_get_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+ ret = msm_aux_pcm_get_gpios();
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -1493,8 +1498,10 @@
static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm_aux_pcm_free_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm_aux_pcm_free_gpios();
}
static void msm_shutdown(struct snd_pcm_substream *substream)
@@ -1933,6 +1940,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
},
{
.name = LPASS_BE_STUB_RX,
@@ -2095,7 +2103,8 @@
{
int ret;
u32 version = socinfo_get_platform_version();
- if (!cpu_is_apq8064() || (socinfo_get_id() == 130) ||
+ if (!(cpu_is_apq8064() || cpu_is_apq8064ab()) ||
+ (socinfo_get_id() == 130) ||
(machine_is_apq8064_mtp() &&
(SOCINFO_VERSION_MINOR(version) == 1))) {
pr_info("%s: Not APQ8064 in SLIMBUS mode\n", __func__);
@@ -2127,6 +2136,7 @@
}
mutex_init(&cdc_mclk_mutex);
+ atomic_set(&auxpcm_rsc_ref, 0);
return ret;
}
@@ -2134,7 +2144,8 @@
static void __exit msm_audio_exit(void)
{
- if (!cpu_is_apq8064() || (socinfo_get_id() == 130)) {
+ if (!(cpu_is_apq8064() || cpu_is_apq8064ab()) ||
+ (socinfo_get_id() == 130)) {
pr_err("%s: Not the right machine type\n", __func__);
return ;
}
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 499e4b6..011b798 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -45,6 +45,11 @@
#define TOP_SPK_AMP_POS 0x4
#define TOP_SPK_AMP_NEG 0x8
+#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 TABLA_EXT_CLK_RATE 12288000
#define TABLA_MBHC_DEF_BUTTONS 8
@@ -134,7 +139,7 @@
static int msm_slim_0_rx_ch = 1;
static int msm_slim_0_tx_ch = 1;
static int msm_hdmi_rx_ch = 8;
-
+static int mi2s_rate_variable;
static struct clk *codec_clk;
static int clk_users;
@@ -517,6 +522,7 @@
static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
static const char * const hdmi_rx_ch_text[] = {"Two", "Three", "Four",
"Five", "Six", "Seven", "Eight"};
+static const char * const mi2s_rate[] = {"Default", "Variable"};
static const struct soc_enum msm_enum[] = {
@@ -524,6 +530,7 @@
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, mi2s_rate),
};
@@ -584,6 +591,20 @@
return 1;
}
+static int msm_mi2s_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mi2s_rate_variable = ucontrol->value.integer.value[0];
+ pr_debug("%s: mi2s_rate_variable = %d\n", __func__, mi2s_rate_variable);
+ return 0;
+}
+
+static int msm_mi2s_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = mi2s_rate_variable;
+ return 0;
+}
static const struct snd_kcontrol_new tabla_msm_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
@@ -594,6 +615,9 @@
msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
SOC_ENUM_EXT("HDMI_RX Channels", msm_enum[3],
msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+ SOC_ENUM_EXT("SEC RX Rate", msm_enum[4],
+ msm_mi2s_rate_get,
+ msm_mi2s_rate_put),
};
@@ -813,11 +837,16 @@
static int msm_be_i2s_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__);
+ pr_debug("%s mi2s_rate_variable = %d\n", __func__, mi2s_rate_variable);
+ /*Configure the sample rate as 48000 KHz for the LPCM playback*/
+ if (!mi2s_rate_variable)
+ rate->min = rate->max = 48000;
channels->min = channels->max = 2;
return 0;
@@ -918,6 +947,78 @@
return ret;
}
+static int mpq8064_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);
+
+ /* PCM only supports mono output with 8khz sample rate */
+ rate->min = rate->max = 8000;
+ channels->min = channels->max = 1;
+
+ return 0;
+}
+
+static int mpq8064_aux_pcm_get_gpios(void)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
+ __func__, GPIO_AUX_PCM_DOUT);
+ goto fail_dout;
+ }
+
+ ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
+ __func__, GPIO_AUX_PCM_DIN);
+ goto fail_din;
+ }
+
+ ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
+ __func__, GPIO_AUX_PCM_SYNC);
+ goto fail_sync;
+ }
+ ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
+ __func__, GPIO_AUX_PCM_CLK);
+ goto fail_clk;
+ }
+
+ return 0;
+
+fail_clk:
+ gpio_free(GPIO_AUX_PCM_SYNC);
+fail_sync:
+ gpio_free(GPIO_AUX_PCM_DIN);
+fail_din:
+ gpio_free(GPIO_AUX_PCM_DOUT);
+fail_dout:
+
+ return ret;
+}
+
+static int mpq8064_aux_pcm_free_gpios(void)
+{
+ gpio_free(GPIO_AUX_PCM_DIN);
+ gpio_free(GPIO_AUX_PCM_DOUT);
+ gpio_free(GPIO_AUX_PCM_SYNC);
+ gpio_free(GPIO_AUX_PCM_CLK);
+
+ return 0;
+}
+
static int msm_startup(struct snd_pcm_substream *substream)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -931,12 +1032,39 @@
substream->name, substream->stream);
}
+static int mpq8064_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s\n", __func__, substream->name);
+ ret = mpq8064_aux_pcm_get_gpios();
+ if (ret < 0) {
+ pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void mpq8064_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+
+ pr_debug("%s(): substream = %s\n", __func__, substream->name);
+ mpq8064_aux_pcm_free_gpios();
+}
+
+
static struct snd_soc_ops msm_be_ops = {
.startup = msm_startup,
.hw_params = msm_hw_params,
.shutdown = msm_shutdown,
};
+static struct snd_soc_ops mpq8064_auxpcm_be_ops = {
+ .startup = mpq8064_auxpcm_startup,
+ .shutdown = mpq8064_auxpcm_shutdown,
+};
+
+
static int mpq8064_sec_i2s_rx_free_gpios(void)
{
int i;
@@ -1317,6 +1445,20 @@
.ignore_pmdown_time = 1, /* this dailink has playback support */
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
},
+ {
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* dainlink has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
@@ -1427,6 +1569,31 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
},
+ /* AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6.2",
+ .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 = mpq8064_auxpcm_be_params_fixup,
+ .ops = &mpq8064_auxpcm_be_ops,
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6.3",
+ .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 = mpq8064_auxpcm_be_params_fixup,
+ },
};
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 78b3abc..0b9d54f 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -31,6 +31,7 @@
#include <linux/dma-mapping.h>
#include <linux/android_pmem.h>
#include <sound/timer.h>
+#include <mach/qdsp6v2/q6core.h>
#include "msm-compr-q6.h"
#include "msm-pcm-routing.h"
@@ -332,6 +333,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct compr_audio *compr = runtime->private_data;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct msm_audio *prtd = &compr->prtd;
struct asm_aac_cfg aac_cfg;
struct asm_wma_cfg wma_cfg;
@@ -373,11 +375,14 @@
pr_err("%s: CMD Format block failed\n", __func__);
break;
case SND_AUDIOCODEC_AC3_PASS_THROUGH:
- pr_debug("compressd playback, no need to send"
- " the decoder params\n");
- break;
case SND_AUDIOCODEC_DTS_PASS_THROUGH:
- pr_debug("compressd DTS playback,dont send the decoder params\n");
+ pr_debug("compressd playback, no need to send decoder params");
+ pr_debug("decoder id: %d\n",
+ compr->info.codec_param.codec.id);
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream,
+ 1);
break;
case SND_AUDIOCODEC_WMA:
pr_debug("SND_AUDIOCODEC_WMA\n");
@@ -470,6 +475,7 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct compr_audio *compr = runtime->private_data;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct msm_audio *prtd = &compr->prtd;
struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
struct snd_codec *codec = &compr->info.codec_param.codec;
@@ -499,6 +505,13 @@
pr_err("%s: CMD Format block" \
"failed: %d\n", __func__, ret);
break;
+ case SND_AUDIOCODEC_PCM:
+ pr_debug("SND_AUDIOCODEC_PCM\n");
+ ret = q6asm_enc_cfg_blk_multi_ch_pcm(prtd->audio_client,
+ prtd->samp_rate, prtd->channel_mode);
+ if (ret < 0)
+ pr_info("%s: CMD Format block failed\n", __func__);
+ break;
default:
pr_debug("No config for codec %d\n", codec->id);
}
@@ -511,6 +524,7 @@
read_param.uid = i;
switch (codec->id) {
case SND_AUDIOCODEC_AMRWB:
+ case SND_AUDIOCODEC_PCM:
read_param.len = prtd->pcm_count
- COMPRE_CAPTURE_HEADER_SIZE;
read_param.paddr = (unsigned long)(buf[i].phys)
@@ -521,17 +535,28 @@
buf[i].data);
q6asm_async_read(prtd->audio_client, &read_param);
break;
- default:
+ case SND_AUDIOCODEC_PASS_THROUGH:
read_param.paddr = (unsigned long)(buf[i].phys);
q6asm_async_read_compressed(prtd->audio_client,
&read_param);
break;
+ default:
+ pr_err("Invalid format");
+ ret = -EINVAL;
+ break;
}
}
prtd->periods = runtime->periods;
prtd->enabled = 1;
+ if (compr->info.codec_param.codec.id ==
+ SND_AUDIOCODEC_PASS_THROUGH)
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream,
+ 1);
+
return ret;
}
@@ -539,7 +564,6 @@
{
int ret = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct compr_audio *compr = runtime->private_data;
struct msm_audio *prtd = &compr->prtd;
@@ -547,28 +571,7 @@
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
prtd->pcm_irq_pos = 0;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_AC3_PASS_THROUGH ||
- compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_DTS_PASS_THROUGH) {
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream,
- 1);
- }
- } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_AMRWB:
- break;
- default:
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream,
- 1);
- break;
- }
- }
+ /* intentional fall-through */
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
pr_debug("%s: Trigger start\n", __func__);
@@ -576,29 +579,6 @@
atomic_set(&prtd->start, 1);
break;
case SNDRV_PCM_TRIGGER_STOP:
- pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_AC3_PASS_THROUGH ||
- compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_DTS_PASS_THROUGH) {
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream,
- 0);
- }
- } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- switch (compr->info.codec_param.codec.id) {
- case SND_AUDIOCODEC_AMRWB:
- break;
- default:
- msm_pcm_routing_reg_psthr_stream(
- soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream,
- 0);
- break;
- }
- }
atomic_set(&prtd->start, 0);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -620,7 +600,7 @@
{
pr_debug("%s\n", __func__);
/* MP3 Block */
- compr->info.compr_cap.num_codecs = 10;
+ compr->info.compr_cap.num_codecs = 12;
compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -635,6 +615,8 @@
compr->info.compr_cap.codecs[7] = SND_AUDIOCODEC_DTS_PASS_THROUGH;
compr->info.compr_cap.codecs[8] = SND_AUDIOCODEC_AMRWB;
compr->info.compr_cap.codecs[9] = SND_AUDIOCODEC_AMRWBPLUS;
+ compr->info.compr_cap.codecs[10] = SND_AUDIOCODEC_PASS_THROUGH;
+ compr->info.compr_cap.codecs[11] = SND_AUDIOCODEC_PCM;
/* Add new codecs here and update num_codecs*/
}
@@ -753,11 +735,18 @@
compressed_audio.prtd = NULL;
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
- if (!(compr->info.codec_param.codec.id ==
- SND_AUDIOCODEC_AC3_PASS_THROUGH))
+ if ((compr->info.codec_param.codec.id !=
+ SND_AUDIOCODEC_AC3_PASS_THROUGH) &&
+ (compr->info.codec_param.codec.id !=
+ SND_AUDIOCODEC_DTS_PASS_THROUGH))
msm_pcm_routing_dereg_phy_stream(
soc_prtd->dai_link->be_id,
SNDRV_PCM_STREAM_PLAYBACK);
+ else
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream,
+ 0);
q6asm_audio_client_free(prtd->audio_client);
kfree(prtd);
return 0;
@@ -776,8 +765,15 @@
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
- msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
- SNDRV_PCM_STREAM_CAPTURE);
+ if (compr->info.codec_param.codec.id ==
+ SND_AUDIOCODEC_PASS_THROUGH)
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream,
+ 0);
+ else
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
q6asm_audio_client_free(prtd->audio_client);
kfree(prtd);
@@ -909,12 +905,30 @@
prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
break;
- default:
+ case SND_AUDIOCODEC_PCM:
+ pr_debug("q6asm_open_read(FORMAT_PCM)\n");
+ ret = q6asm_open_read(prtd->audio_client,
+ FORMAT_MULTI_CHANNEL_LINEAR_PCM);
+ if (ret < 0) {
+ pr_err("%s: compressed Session open failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ pr_debug("msm_pcm_routing_reg_phy_stream\n");
+ msm_pcm_routing_reg_phy_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
+ prtd->session_id, substream->stream);
+ break;
+ case SND_AUDIOCODEC_PASS_THROUGH:
pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
ret = q6asm_open_read_compressed(prtd->audio_client,
MAX_NUM_FRAMES_PER_BUFFER,
COMPRESSED_META_DATA_MODE);
break;
+ default:
+ pr_err("Invalid codec for compressed session open\n");
+ return -EFAULT;
}
if (ret < 0) {
@@ -1047,13 +1061,37 @@
pr_debug("SND_AUDIOCODEC_DTS_PASS_THROUGH\n");
compr->codec = FORMAT_DTS;
break;
- case SND_AUDIOCODEC_DTS:
+ case SND_AUDIOCODEC_DTS: {
+ char modelId[128];
+ struct snd_dec_dts opt_dts =
+ compr->info.codec_param.codec.options.dts;
+ int modelIdLength = opt_dts.modelIdLength;
pr_debug("SND_AUDIOCODEC_DTS\n");
+ if (copy_from_user(modelId, (void *)opt_dts.modelId,
+ modelIdLength))
+ pr_err("%s: ERROR: copy modelId\n", __func__);
+ modelId[modelIdLength] = '\0';
+ pr_debug("%s: Received modelId =%s,length=%d\n",
+ __func__, modelId, modelIdLength);
+ core_set_dts_model_id(modelIdLength, modelId);
compr->codec = FORMAT_DTS;
+ }
break;
- case SND_AUDIOCODEC_DTS_LBR:
- pr_debug("SND_AUDIOCODEC_DTS\n");
+ case SND_AUDIOCODEC_DTS_LBR:{
+ char modelId[128];
+ struct snd_dec_dts opt_dts =
+ compr->info.codec_param.codec.options.dts;
+ int modelIdLength = opt_dts.modelIdLength;
+ pr_debug("SND_AUDIOCODEC_DTS_LBR\n");
+ if (copy_from_user(modelId, (void *)opt_dts.modelId,
+ modelIdLength))
+ pr_err("%s: ERROR: copy modelId\n", __func__);
+ modelId[modelIdLength] = '\0';
+ pr_debug("%s: Received modelId =%s,length=%d\n",
+ __func__, modelId, modelIdLength);
+ core_set_dts_model_id(modelIdLength, modelId);
compr->codec = FORMAT_DTS_LBR;
+ }
break;
case SND_AUDIOCODEC_AMRWB:
pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWB\n");
@@ -1063,11 +1101,19 @@
pr_debug("msm_compr_ioctl SND_AUDIOCODEC_AMRWBPLUS\n");
compr->codec = FORMAT_AMR_WB_PLUS;
break;
- default:
- /*Needed for the HDMI IN compressed use case*/
- pr_debug("FORMAT_LINEAR_PCM\n");
- compr->codec = FORMAT_LINEAR_PCM;
+ case SND_AUDIOCODEC_PASS_THROUGH:
+ /* format pass through is used for HDMI IN compressed
+ where the decoder format is indicated by LPASS */
+ pr_debug("msm_compr_ioctl SND_AUDIOCODEC_PASSTHROUGH\n");
+ compr->codec = FORMAT_PASS_THROUGH;
break;
+ case SND_AUDIOCODEC_PCM:
+ pr_debug("msm_compr_ioctl SND_AUDIOCODEC_PCM\n");
+ compr->codec = FORMAT_MULTI_CHANNEL_LINEAR_PCM;
+ break;
+ default:
+ pr_err("msm_compr_ioctl failed..unknown codec\n");
+ return -EFAULT;
}
return 0;
case SNDRV_PCM_IOCTL1_RESET:
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 16a4aaa..dc8d9e6 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -270,9 +270,9 @@
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 192000,
},
.capture = {
.stream_name = "SLIMBUS0 Hostless Capture",
@@ -280,9 +280,9 @@
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 192000,
},
.ops = &msm_fe_dai_ops,
.name = "SLIMBUS0_HOSTLESS",
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
index 129f69f..fcfcb66 100644
--- a/sound/soc/msm/msm-lowlatency-pcm-q6.c
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -218,8 +218,27 @@
if (prtd->enabled)
return 0;
+ if (!prtd->set_channel_map) {
+ memset(prtd->channel_map, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ if (prtd->channel_mode == 1) {
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ } else if (prtd->channel_mode == 2) {
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ prtd->channel_map[0] = PCM_CHANNEL_FR;
+ } else if (prtd->channel_mode == 6) {
+ prtd->channel_map[0] = PCM_CHANNEL_FC;
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ prtd->channel_map[0] = PCM_CHANNEL_FR;
+ prtd->channel_map[0] = PCM_CHANNEL_LB;
+ prtd->channel_map[0] = PCM_CHANNEL_RB;
+ prtd->channel_map[0] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+ prtd->channel_mode);
+ }
+ }
ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
- runtime->rate, runtime->channels);
+ runtime->rate, runtime->channels, prtd->channel_map);
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -389,6 +408,7 @@
}
prtd->dsp_cnt = 0;
+ prtd->set_channel_map = false;
runtime->private_data = prtd;
pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index 5b0759c..7d04f95 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -269,9 +269,29 @@
prtd->channel_mode = runtime->channels;
if (prtd->enabled)
return 0;
-
+ pr_debug("prtd->set_channel_map: %d", prtd->set_channel_map);
+ if (!prtd->set_channel_map) {
+ pr_debug("using default channel map");
+ memset(prtd->channel_map, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ if (prtd->channel_mode == 1) {
+ prtd->channel_map[0] = PCM_CHANNEL_FL;
+ } else if (prtd->channel_mode == 2) {
+ prtd->channel_map[1] = PCM_CHANNEL_FL;
+ prtd->channel_map[2] = PCM_CHANNEL_FR;
+ } else if (prtd->channel_mode == 6) {
+ prtd->channel_map[0] = PCM_CHANNEL_FC;
+ prtd->channel_map[1] = PCM_CHANNEL_FL;
+ prtd->channel_map[2] = PCM_CHANNEL_FR;
+ prtd->channel_map[3] = PCM_CHANNEL_LB;
+ prtd->channel_map[4] = PCM_CHANNEL_RB;
+ prtd->channel_map[5] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+ prtd->channel_mode);
+ }
+ }
ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
- runtime->rate, runtime->channels);
+ runtime->rate, runtime->channels, prtd->channel_map);
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -452,6 +472,7 @@
}
prtd->dsp_cnt = 0;
+ prtd->set_channel_map = false;
runtime->private_data = prtd;
pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
@@ -492,6 +513,15 @@
return rc;
}
+void multi_ch_pcm_set_channel_map(char *channel_mapping)
+{
+ pr_debug("%s\n", __func__);
+ if (multi_ch_pcm_audio.prtd) {
+ multi_ch_pcm_audio.prtd->set_channel_map = true;
+ memcpy(multi_ch_pcm_audio.prtd->channel_map, channel_mapping,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+}
static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
diff --git a/sound/soc/msm/msm-pcm-q6.h b/sound/soc/msm/msm-pcm-q6.h
index f1af99a..2678498 100644
--- a/sound/soc/msm/msm-pcm-q6.h
+++ b/sound/soc/msm/msm-pcm-q6.h
@@ -81,6 +81,8 @@
int periods;
int mmap_flag;
atomic_t pending_buffer;
+ bool set_channel_map;
+ char channel_map[8];
};
struct output_meta_data_st {
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 9073e1e..5967bb2 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -78,6 +78,7 @@
static const DECLARE_TLV_DB_LINEAR(compressed2_rx_vol_gain, 0,
INT_RX_VOL_MAX_STEPS);
static int msm_route_ec_ref_rx;
+static char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
/* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
#define MAX_EQ_SESSIONS MSM_FRONTEND_DAI_CS_VOICE
@@ -863,6 +864,27 @@
return 0;
}
+static int msm_routing_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ ucontrol->value.integer.value[i] = channel_mapping[i];
+ return 0;
+}
+
+static int msm_routing_put_channel_map_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+
+ for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+ channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
+ multi_ch_pcm_set_channel_map(channel_mapping);
+
+ return 0;
+}
+
static int msm_routing_set_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1910,6 +1932,12 @@
msm_routing_set_compressed2_vol_mixer, compressed2_rx_vol_gain),
};
+static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
+ SOC_SINGLE_MULTI_EXT("Playback Channel Map", SND_SOC_NOPM, 0, 8,
+ 0, 8, msm_routing_get_channel_map_mixer,
+ msm_routing_put_channel_map_mixer),
+};
+
static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "SRS TruMedia",
@@ -2894,6 +2922,10 @@
snd_soc_add_platform_controls(platform,
ec_ref_rx_mixer_controls,
ARRAY_SIZE(ec_ref_rx_mixer_controls));
+
+ snd_soc_add_platform_controls(platform,
+ multi_ch_channel_map_mixer_controls,
+ ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
return 0;
}
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 7ee7257..e11133e 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -128,4 +128,6 @@
int compressed_set_volume(unsigned volume);
+void multi_ch_pcm_set_channel_map(char *channel_mapping);
+
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index c8d4b02..4725e8e 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -66,6 +66,7 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
static int msm8930_enable_codec_ext_clk(
struct snd_soc_codec *codec, int enable,
@@ -860,8 +861,10 @@
{
int ret = 0;
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm8930_aux_pcm_get_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+ ret = msm8930_aux_pcm_get_gpios();
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -872,8 +875,10 @@
static void msm8930_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm8930_aux_pcm_free_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm8930_aux_pcm_free_gpios();
}
static void msm8930_shutdown(struct snd_pcm_substream *substream)
@@ -1229,6 +1234,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
+ .ops = &msm8930_auxpcm_be_ops,
},
/* Incall Music BACK END DAI Link */
{
@@ -1336,6 +1342,7 @@
} else
msm8930_headset_gpios_configured = 1;
+ atomic_set(&auxpcm_rsc_ref, 0);
return ret;
}
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 1338e2f..6ec44bf 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -83,6 +83,7 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
+static atomic_t auxpcm_rsc_ref;
static bool hs_detect_use_gpio;
module_param(hs_detect_use_gpio, bool, 0444);
@@ -1017,6 +1018,8 @@
pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
channels->min, channels->max);
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
rate->min = rate->max = 48000;
return 0;
@@ -1131,8 +1134,11 @@
{
int ret = 0;
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm8960_aux_pcm_get_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+ ret = msm8960_aux_pcm_get_gpios();
+
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -1142,9 +1148,10 @@
static void msm8960_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
-
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm8960_aux_pcm_free_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm8960_aux_pcm_free_gpios();
}
static void msm8960_shutdown(struct snd_pcm_substream *substream)
@@ -1522,6 +1529,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
+ .ops = &msm8960_auxpcm_be_ops,
},
/* Incall Music BACK END DAI Link */
{
@@ -1819,7 +1827,7 @@
}
mutex_init(&cdc_mclk_mutex);
-
+ atomic_set(&auxpcm_rsc_ref, 0);
return ret;
}
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 7e56a42..f462299 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -81,6 +81,7 @@
static int msm_slim_0_tx_ch = 1;
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
@@ -88,6 +89,7 @@
static struct mutex cdc_mclk_mutex;
static struct q_clkdiv *codec_clk;
static int clk_users;
+static atomic_t auxpcm_rsc_ref;
static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
{
@@ -479,6 +481,21 @@
msm_btsco_rate_get, msm_btsco_rate_put),
};
+static int msm_btsco_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);
+
+ rate->min = rate->max = msm_btsco_rate;
+ channels->min = channels->max = msm_btsco_ch;
+
+ return 0;
+}
+
static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -494,6 +511,19 @@
return 0;
}
+
+static int msm_proxy_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);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+
+ return 0;
+}
+
static int msm_aux_pcm_get_gpios(void)
{
int ret = 0;
@@ -553,8 +583,10 @@
{
int ret = 0;
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = msm_aux_pcm_get_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
+ ret = msm_aux_pcm_get_gpios();
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -565,8 +597,10 @@
static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s\n", __func__, substream->name);
- msm_aux_pcm_free_gpios();
+ pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&auxpcm_rsc_ref));
+ if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
+ msm_aux_pcm_free_gpios();
}
static struct snd_soc_ops msm_auxpcm_be_ops = {
.startup = msm_auxpcm_startup,
@@ -775,19 +809,19 @@
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
},
{
- .name = "MSM VoIP",
- .stream_name = "VoIP",
- .cpu_dai_name = "VoIP",
- .platform_name = "msm-voip-dsp",
+ .name = "MSM8974 Media2",
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-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",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.ignore_suspend = 1,
/* this dainlink has playback support */
.ignore_pmdown_time = 1,
- .be_id = MSM_FRONTEND_DAI_VOIP,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
},
{
.name = "Circuit-Switch Voice",
@@ -806,6 +840,21 @@
.be_id = MSM_FRONTEND_DAI_CS_VOICE,
},
{
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-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,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {
.name = "MSM8974 LPA",
.stream_name = "LPA",
.cpu_dai_name = "MultiMedia3",
@@ -836,6 +885,41 @@
.codec_name = "snd-soc-dummy",
},
{
+ .name = "INT_FM Hostless",
+ .stream_name = "INT_FM Hostless",
+ .cpu_dai_name = "INT_FM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {
.name = "MSM8974 Compr",
.stream_name = "COMPR",
.cpu_dai_name = "MultiMedia4",
@@ -865,19 +949,55 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ /* Backend BT/FM DAI Links */
{
- .name = "MSM8974 Media2",
- .stream_name = "MultiMedia2",
- .cpu_dai_name = "MultiMedia2",
- .platform_name = "msm-pcm-dsp",
- .dynamic = 1,
- .codec_dai_name = "snd-soc-dummy-dai",
- .codec_name = "snd-soc-dummy",
- .trigger = {SND_SOC_DPCM_TRIGGER_POST,
- SND_SOC_DPCM_TRIGGER_POST},
- .ignore_suspend = 1,
+ .name = LPASS_BE_INT_BT_SCO_RX,
+ .stream_name = "Internal BT-SCO Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.12288",
+ .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_INT_BT_SCO_RX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ /* this dainlink has playback support */
.ignore_pmdown_time = 1,
- .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {
+ .name = LPASS_BE_INT_BT_SCO_TX,
+ .stream_name = "Internal BT-SCO Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.12289",
+ .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_INT_BT_SCO_TX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ },
+ /* Backend AFE DAI Links */
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_proxy_be_hw_params_fixup,
},
/* AUX PCM Backend DAI Links */
{
@@ -904,6 +1024,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
},
/* Backend DAI Links */
{
@@ -1041,6 +1162,8 @@
goto err;
}
mutex_init(&cdc_mclk_mutex);
+ atomic_set(&auxpcm_rsc_ref, 0);
+
return 0;
err:
devm_kfree(&pdev->dev, pdata);
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 3a226b4..0aad217 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -529,7 +529,7 @@
}
buf[cnt].handle = ion_alloc
(buf[cnt].client, bufsz, SZ_4K,
- (0x1 << ION_AUDIO_HEAP_ID));
+ (0x1 << ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL((void *)
buf[cnt].handle)) {
pr_err("%s: ION memory allocation for AUDIO failed\n",
@@ -551,8 +551,7 @@
}
buf[cnt].data = ion_map_kernel
- (buf[cnt].client, buf[cnt].handle,
- 0);
+ (buf[cnt].client, buf[cnt].handle);
if (IS_ERR_OR_NULL((void *)
buf[cnt].data)) {
pr_err("%s: ION memory mapping for AUDIO failed\n",
@@ -665,7 +664,7 @@
goto fail;
}
buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
- (0x1 << ION_AUDIO_HEAP_ID));
+ (0x1 << ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
pr_err("%s: ION memory allocation for AUDIO failed\n",
__func__);
@@ -682,7 +681,7 @@
goto fail;
}
- buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle, 0);
+ buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle);
if (IS_ERR_OR_NULL((void *) buf[0].data)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
mutex_unlock(&ac->cmd_lock);
@@ -799,6 +798,25 @@
return 0;
}
+static int32_t is_no_wait_cmd_rsp(uint32_t opcode, uint32_t *cmd_type)
+{
+ if (opcode == APR_BASIC_RSP_RESULT) {
+ if (cmd_type != NULL) {
+ switch (cmd_type[0]) {
+ case ASM_SESSION_CMD_RUN:
+ case ASM_SESSION_CMD_PAUSE:
+ case ASM_DATA_CMD_EOS:
+ return 1;
+ default:
+ break;
+ }
+ } else
+ pr_err("%s: null pointer!", __func__);
+ } else if (opcode == ASM_DATA_CMDRSP_EOS)
+ return 1;
+
+ return 0;
+}
static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
{
@@ -819,14 +837,16 @@
ac->session);
return -EINVAL;
}
- if (atomic_read(&ac->nowait_cmd_cnt) > 0) {
+
+ payload = data->payload;
+ if ((atomic_read(&ac->nowait_cmd_cnt) > 0) &&
+ is_no_wait_cmd_rsp(data->opcode, payload)) {
pr_debug("%s: nowait_cmd_cnt %d\n",
__func__,
atomic_read(&ac->nowait_cmd_cnt));
atomic_dec(&ac->nowait_cmd_cnt);
wakeup_flag = 0;
}
- payload = data->payload;
if (data->opcode == RESET_EVENTS) {
pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
@@ -876,8 +896,9 @@
case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
if (atomic_read(&ac->cmd_state) && wakeup_flag) {
atomic_set(&ac->cmd_state, 0);
- if (payload[1] == ADSP_EUNSUPPORTED) {
- pr_debug("paload[1]:%d unsupported",
+ if (payload[1] == ADSP_EUNSUPPORTED ||
+ payload[1] == ADSP_EFAILED) {
+ pr_debug("payload[1]:%d unsupported",
payload[1]);
atomic_set(&ac->cmd_response, 1);
}
@@ -2296,7 +2317,7 @@
}
int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
- uint32_t rate, uint32_t channels)
+ uint32_t rate, uint32_t channels, char *channel_map)
{
struct asm_stream_media_format_update fmt;
u8 *channel_mapping;
@@ -2319,39 +2340,7 @@
channel_mapping =
fmt.write_cfg.multi_ch_pcm_cfg.channel_mapping;
- memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
-
- if (channels == 1) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- } else if (channels == 2) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- channel_mapping[1] = PCM_CHANNEL_FR;
- } else if (channels == 4) {
- channel_mapping[0] = PCM_CHANNEL_FL;
- channel_mapping[1] = PCM_CHANNEL_FR;
- channel_mapping[1] = PCM_CHANNEL_LB;
- channel_mapping[1] = PCM_CHANNEL_RB;
- } else if (channels == 6) {
- channel_mapping[0] = PCM_CHANNEL_FC;
- channel_mapping[1] = PCM_CHANNEL_FL;
- channel_mapping[2] = PCM_CHANNEL_FR;
- channel_mapping[3] = PCM_CHANNEL_LB;
- channel_mapping[4] = PCM_CHANNEL_RB;
- channel_mapping[5] = PCM_CHANNEL_LFE;
- } else if (channels == 8) {
- channel_mapping[0] = PCM_CHANNEL_FC;
- channel_mapping[1] = PCM_CHANNEL_FL;
- channel_mapping[2] = PCM_CHANNEL_FR;
- channel_mapping[3] = PCM_CHANNEL_LB;
- channel_mapping[4] = PCM_CHANNEL_RB;
- channel_mapping[5] = PCM_CHANNEL_LFE;
- channel_mapping[6] = PCM_CHANNEL_FLC;
- channel_mapping[7] = PCM_CHANNEL_FRC;
- } else {
- pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
- channels);
- return -EINVAL;
- }
+ memcpy(channel_mapping, channel_map, PCM_FORMAT_MAX_NUM_CHANNEL);
rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
if (rc < 0) {
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 2a21dfa..cb2e39b 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -4061,7 +4061,7 @@
common.ion_handle = ion_alloc(common.ion_client,
TOTAL_VOICE_CAL_SIZE,
- SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID));
+ SZ_4K, ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL((void *) common.ion_handle)) {
pr_err("%s: ION memory allocation failed\n",
__func__);
@@ -4076,8 +4076,7 @@
goto err_ion_handle;
}
- kvptr = ion_map_kernel(common.ion_client,
- common.ion_handle, 0);
+ kvptr = ion_map_kernel(common.ion_client, common.ion_handle);
if (IS_ERR_OR_NULL(kvptr)) {
pr_err("%s: ION memory mapping failed\n", __func__);
goto err_ion_handle;
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 86a82e2..c046b63 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -106,9 +106,13 @@
break;
case OCMEM_ALLOC_GROW:
audio_ocmem_lcl.buf = data;
+ pr_debug("%s: Alloc grow request received buf->addr: 0x%ld\n",
+ __func__,
+ (audio_ocmem_lcl.buf)->addr);
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_GROW);
break;
case OCMEM_ALLOC_SHRINK:
+ pr_debug("%s: Alloc shrink request received\n", __func__);
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_SHRINK);
break;
default:
@@ -150,11 +154,14 @@
audio_ocmem_lcl.buf = buf;
atomic_set(&audio_ocmem_lcl.audio_exit, 0);
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+ pr_debug("%s: buf->len: %ld\n", __func__, buf->len);
if (!buf->len) {
+ pr_debug("%s: buf.len is 0, waiting for ocmem region\n",
+ __func__);
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
(atomic_read(&audio_ocmem_lcl.audio_cond) == 0) ||
(atomic_read(&audio_ocmem_lcl.audio_exit) == 1));
-
if (atomic_read(&audio_ocmem_lcl.audio_exit)) {
pr_err("%s: audio playback ended while waiting for ocmem\n",
__func__);
@@ -162,6 +169,7 @@
goto fail_cmd;
}
}
+ pr_debug("%s: buf->len: %ld\n", __func__, (audio_ocmem_lcl.buf)->len);
if (audio_ocmem_lcl.lp_memseg_ptr == NULL) {
/* Retrieve low power segments */
ret = core_get_low_power_segments(
@@ -190,19 +198,28 @@
/* vote for ocmem bus bandwidth */
ret = msm_bus_scale_client_update_request(
audio_ocmem_lcl.audio_ocmem_bus_client,
- 0);
+ 1);
if (ret)
pr_err("%s: failed to vote for bus bandwidth\n", __func__);
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_TRANSITION);
+ pr_debug("%s: buf->addr: 0x%ld, len: %ld, audio_state[0x%x]\n",
+ __func__,
+ audio_ocmem_lcl.buf->addr,
+ audio_ocmem_lcl.buf->len,
+ atomic_read(&audio_ocmem_lcl.audio_state));
+
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
ret = ocmem_map(cid, audio_ocmem_lcl.buf, &audio_ocmem_lcl.mlist);
if (ret) {
pr_err("%s: ocmem_map failed\n", __func__);
goto fail_cmd;
}
-
+ pr_debug("%s: audio_cond[%d] audio_state[0x%x]\n", __func__,
+ atomic_read(&audio_ocmem_lcl.audio_cond),
+ atomic_read(&audio_ocmem_lcl.audio_state));
while ((atomic_read(&audio_ocmem_lcl.audio_state) !=
OCMEM_STATE_EXIT)) {
@@ -219,6 +236,8 @@
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
break;
case OCMEM_STATE_SHRINK:
+ pr_debug("%s: ocmem shrink request process\n",
+ __func__);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
&audio_ocmem_lcl.mlist);
@@ -242,9 +261,11 @@
atomic_read(&audio_ocmem_lcl.audio_state));
goto fail_cmd;
}
-
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
break;
case OCMEM_STATE_GROW:
+ pr_debug("%s: ocmem grow request process\n",
+ __func__);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
ret = ocmem_map(cid, audio_ocmem_lcl.buf,
&audio_ocmem_lcl.mlist);
@@ -260,6 +281,7 @@
atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
atomic_set(&audio_ocmem_lcl.audio_state,
OCMEM_STATE_MAP_COMPL);
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
break;
}
}
@@ -280,8 +302,10 @@
{
int ret;
+ pr_debug("%s: disable\n", __func__);
if (atomic_read(&audio_ocmem_lcl.audio_cond))
atomic_set(&audio_ocmem_lcl.audio_cond, 0);
+
pr_debug("%s: audio_cond[0x%x], audio_state[0x%x]\n", __func__,
atomic_read(&audio_ocmem_lcl.audio_cond),
atomic_read(&audio_ocmem_lcl.audio_state));
@@ -309,6 +333,7 @@
atomic_read(&audio_ocmem_lcl.audio_state));
goto fail_cmd;
}
+ atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
pr_debug("%s: ocmem_free success\n", __func__);
default:
pr_debug("%s: state=%d", __func__,
@@ -316,6 +341,9 @@
break;
}
+ msm_bus_scale_client_update_request(
+ audio_ocmem_lcl.audio_ocmem_bus_client,
+ 0);
return 0;
fail_cmd:
return ret;
@@ -345,6 +373,7 @@
rc = -EINVAL;
}
+ return;
}
/**
* voice_ocmem_process_req() - disable/enable OCMEM during voice call
@@ -441,6 +470,7 @@
rc = -EINVAL;
}
+ return;
}
/**
@@ -484,86 +514,21 @@
static int audio_ocmem_platform_data_populate(struct platform_device *pdev)
{
- int ret;
- struct msm_bus_scale_pdata *audio_ocmem_bus_scale_pdata = NULL;
- struct msm_bus_vectors *audio_ocmem_bus_vectors = NULL;
- struct msm_bus_paths *ocmem_audio_bus_paths = NULL;
- u32 val;
+ struct msm_bus_scale_pdata *audio_ocmem_adata = NULL;
if (!pdev->dev.of_node) {
pr_err("%s: device tree information missing\n", __func__);
return -ENODEV;
}
-
- audio_ocmem_bus_vectors = kzalloc(sizeof(struct msm_bus_vectors),
- GFP_KERNEL);
- if (!audio_ocmem_bus_vectors) {
- dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
- return -ENOMEM;
+ audio_ocmem_adata = msm_bus_cl_get_pdata(pdev);
+ if (!audio_ocmem_adata) {
+ pr_err("%s: bus device tree allocation failed\n", __func__);
+ return -EINVAL;
}
- ret = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-ocmem-audio-src-id", &val);
- if (ret) {
- dev_err(&pdev->dev, "%s: qcom,msm-ocmem-audio-src-id missing in DT node\n",
- __func__);
- goto fail1;
- }
- audio_ocmem_bus_vectors->src = val;
- ret = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-ocmem-audio-dst-id", &val);
- if (ret) {
- dev_err(&pdev->dev, "%s: qcom,msm-ocmem-audio-dst-id missing in DT node\n",
- __func__);
- goto fail1;
- }
- audio_ocmem_bus_vectors->dst = val;
- ret = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-ocmem-audio-ab", &val);
- if (ret) {
- dev_err(&pdev->dev, "%s: qcom,msm-ocmem-audio-ab missing in DT node\n",
- __func__);
- goto fail1;
- }
- audio_ocmem_bus_vectors->ab = val;
- ret = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-ocmem-audio-ib", &val);
- if (ret) {
- dev_err(&pdev->dev, "%s: qcom,msm-ocmem-audio-ib missing in DT node\n",
- __func__);
- goto fail1;
- }
- audio_ocmem_bus_vectors->ib = val;
+ dev_set_drvdata(&pdev->dev, audio_ocmem_adata);
- ocmem_audio_bus_paths = kzalloc(sizeof(struct msm_bus_paths),
- GFP_KERNEL);
- if (!ocmem_audio_bus_paths) {
- dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
- goto fail1;
- }
- ocmem_audio_bus_paths->num_paths = 1;
- ocmem_audio_bus_paths->vectors = audio_ocmem_bus_vectors;
-
- audio_ocmem_bus_scale_pdata =
- kzalloc(sizeof(struct msm_bus_scale_pdata), GFP_KERNEL);
-
- if (!audio_ocmem_bus_scale_pdata) {
- dev_err(&pdev->dev, "Failed to allocate memory for platform data\n");
- goto fail2;
- }
-
- audio_ocmem_bus_scale_pdata->usecase = ocmem_audio_bus_paths;
- audio_ocmem_bus_scale_pdata->num_usecases = 1;
- audio_ocmem_bus_scale_pdata->name = "audio-ocmem";
-
- dev_set_drvdata(&pdev->dev, audio_ocmem_bus_scale_pdata);
- return ret;
-
-fail2:
- kfree(ocmem_audio_bus_paths);
-fail1:
- kfree(audio_ocmem_bus_vectors);
- return ret;
+ return 0;
}
static int ocmem_audio_client_probe(struct platform_device *pdev)
{
@@ -628,9 +593,7 @@
audio_ocmem_bus_scale_pdata = (struct msm_bus_scale_pdata *)
dev_get_drvdata(&pdev->dev);
- kfree(audio_ocmem_bus_scale_pdata->usecase->vectors);
- kfree(audio_ocmem_bus_scale_pdata->usecase);
- kfree(audio_ocmem_bus_scale_pdata);
+ msm_bus_cl_clear_pdata(audio_ocmem_bus_scale_pdata);
ocmem_notifier_unregister(audio_ocmem_lcl.audio_hdl,
&audio_ocmem_client_nb);
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 6f3249a..01a9538 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -25,12 +25,25 @@
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/control.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm_params.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/android_pmem.h>
+#include <sound/timer.h>
#include "msm-compr-q6-v2.h"
#include "msm-pcm-routing-v2.h"
+#include "audio_ocmem.h"
+
+#define COMPRE_CAPTURE_NUM_PERIODS 16
+/* Allocate the worst case frame size for compressed audio */
+#define COMPRE_CAPTURE_HEADER_SIZE (sizeof(struct snd_compr_audio_info))
+#define COMPRE_CAPTURE_MAX_FRAME_SIZE (6144)
+#define COMPRE_CAPTURE_PERIOD_SIZE ((COMPRE_CAPTURE_MAX_FRAME_SIZE + \
+ COMPRE_CAPTURE_HEADER_SIZE) * \
+ MAX_NUM_FRAMES_PER_BUFFER)
+#define COMPRE_OUTPUT_METADATA_SIZE (sizeof(struct output_meta_data_st))
struct snd_msm {
struct msm_audio *prtd;
@@ -40,7 +53,7 @@
static struct audio_locks the_locks;
-static struct snd_pcm_hardware msm_compr_hardware_playback = {
+static struct snd_pcm_hardware msm_compr_hardware_capture = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -51,12 +64,33 @@
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
+ .buffer_bytes_max =
+ COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS ,
+ .period_bytes_min = COMPRE_CAPTURE_PERIOD_SIZE,
+ .period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE,
+ .periods_min = COMPRE_CAPTURE_NUM_PERIODS,
+ .periods_max = COMPRE_CAPTURE_NUM_PERIODS,
+ .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware msm_compr_hardware_playback = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 8,
.buffer_bytes_max = 1200 * 1024 * 2,
- .period_bytes_min = 4800,
+ .period_bytes_min = 2400,
.period_bytes_max = 1200 * 1024,
.periods_min = 2,
- .periods_max = 512,
+ .periods_max = 1024,
.fifo_size = 0,
};
@@ -79,8 +113,13 @@
struct snd_pcm_substream *substream = prtd->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_aio_write_param param;
+ struct audio_aio_read_param read_param;
struct audio_buffer *buf = NULL;
+ struct output_meta_data_st output_meta_data;
+ uint32_t *ptrmem = (uint32_t *)payload;
int i = 0;
+ int time_stamp_flag = 0;
+ int buffer_length = 0;
pr_debug("%s opcode =%08x\n", __func__, opcode);
switch (opcode) {
@@ -91,6 +130,9 @@
prtd->pcm_irq_pos += prtd->pcm_count;
if (atomic_read(&prtd->start))
snd_pcm_period_elapsed(substream);
+ else
+ if (substream->timer_running)
+ snd_timer_interrupt(substream->timer, 1);
atomic_inc(&prtd->out_count);
wake_up(&the_locks.write_wait);
if (!atomic_read(&prtd->start)) {
@@ -98,9 +140,6 @@
break;
} else
atomic_set(&prtd->pending_buffer, 0);
-
- if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
- break;
buf = prtd->audio_client->port[IN].buf;
pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
__func__, prtd->pcm_count, prtd->out_head);
@@ -109,14 +148,38 @@
((unsigned int)buf[0].phys
+ (prtd->out_head * prtd->pcm_count)));
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
+ time_stamp_flag = SET_TIMESTAMP;
+ memcpy(&output_meta_data, (char *)(buf->data +
+ prtd->out_head * prtd->pcm_count),
+ COMPRE_OUTPUT_METADATA_SIZE);
+ } else {
+ time_stamp_flag = NO_TIMESTAMP;
+ memset(&output_meta_data, 0,
+ COMPRE_OUTPUT_METADATA_SIZE);
+ output_meta_data.frame_size = prtd->pcm_count;
+ }
+ buffer_length = output_meta_data.frame_size;
+ pr_debug("meta_data_length: %d, frame_length: %d\n",
+ output_meta_data.meta_data_length,
+ output_meta_data.frame_size);
+ pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+ output_meta_data.timestamp_msw,
+ output_meta_data.timestamp_lsw);
+ if (buffer_length == 0) {
+ pr_debug("Recieved a zero length buffer-break out");
+ break;
+ }
param.paddr = (unsigned long)buf[0].phys
- + (prtd->out_head * prtd->pcm_count);
- param.len = prtd->pcm_count;
- param.msw_ts = 0;
- param.lsw_ts = 0;
- param.flags = NO_TIMESTAMP;
+ + (prtd->out_head * prtd->pcm_count)
+ + output_meta_data.meta_data_length;
+ param.len = buffer_length;
+ param.msw_ts = output_meta_data.timestamp_msw;
+ param.lsw_ts = output_meta_data.timestamp_lsw;
+ param.flags = time_stamp_flag;
param.uid = (unsigned long)buf[0].phys
- + (prtd->out_head * prtd->pcm_count);
+ + (prtd->out_head * prtd->pcm_count
+ + output_meta_data.meta_data_length);
for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
i++, ++ptrmem)
pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
@@ -131,12 +194,60 @@
}
case ASM_DATA_EVENT_RENDERED_EOS:
pr_debug("ASM_DATA_CMDRSP_EOS\n");
- prtd->cmd_ack = 1;
- wake_up(&the_locks.eos_wait);
+ if (atomic_read(&prtd->eos)) {
+ pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
+ prtd->cmd_ack = 1;
+ wake_up(&the_locks.eos_wait);
+ atomic_set(&prtd->eos, 0);
+ }
break;
+ case ASM_DATA_EVENT_READ_DONE_V2: {
+ pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+ pr_debug("buf = %p, data = 0x%X, *data = %p,\n"
+ "prtd->pcm_irq_pos = %d\n",
+ prtd->audio_client->port[OUT].buf,
+ *(uint32_t *)prtd->audio_client->port[OUT].buf->data,
+ prtd->audio_client->port[OUT].buf->data,
+ prtd->pcm_irq_pos);
+
+ memcpy(prtd->audio_client->port[OUT].buf->data +
+ prtd->pcm_irq_pos, (ptrmem + 2),
+ COMPRE_CAPTURE_HEADER_SIZE);
+ pr_debug("buf = %p, updated data = 0x%X, *data = %p\n",
+ prtd->audio_client->port[OUT].buf,
+ *(uint32_t *)(prtd->audio_client->port[OUT].buf->data +
+ prtd->pcm_irq_pos),
+ prtd->audio_client->port[OUT].buf->data);
+ if (!atomic_read(&prtd->start))
+ break;
+ pr_debug("frame size=%d, buffer = 0x%X\n", ptrmem[2],
+ ptrmem[1]);
+ if (ptrmem[2] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
+ pr_err("Frame length exceeded the max length");
+ break;
+ }
+ buf = prtd->audio_client->port[OUT].buf;
+ pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%X\n",
+ prtd->pcm_irq_pos, (uint32_t)buf[0].phys);
+ read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
+ read_param.paddr = (unsigned long)(buf[0].phys) +
+ prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
+ prtd->pcm_irq_pos += prtd->pcm_count;
+
+ if (atomic_read(&prtd->start))
+ snd_pcm_period_elapsed(substream);
+
+ q6asm_async_read(prtd->audio_client, &read_param);
+ break;
+ }
case APR_BASIC_RSP_RESULT: {
switch (payload[0]) {
case ASM_SESSION_CMD_RUN_V2: {
+ if (substream->stream
+ != SNDRV_PCM_STREAM_PLAYBACK) {
+ atomic_set(&prtd->start, 1);
+ break;
+ }
if (!atomic_read(&prtd->pending_buffer))
break;
pr_debug("%s:writing %d bytes of buffer[%d] to dsp\n",
@@ -146,12 +257,32 @@
__func__, prtd->out_head,
((unsigned int)buf[0].phys
+ (prtd->out_head * prtd->pcm_count)));
- param.paddr = (unsigned long)buf[prtd->out_head].phys;
- param.len = prtd->pcm_count;
- param.msw_ts = 0;
- param.lsw_ts = 0;
- param.flags = NO_TIMESTAMP;
- param.uid = (unsigned long)buf[prtd->out_head].phys;
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
+ time_stamp_flag = SET_TIMESTAMP;
+ memcpy(&output_meta_data, (char *)(buf->data +
+ prtd->out_head * prtd->pcm_count),
+ COMPRE_OUTPUT_METADATA_SIZE);
+ } else {
+ time_stamp_flag = NO_TIMESTAMP;
+ memset(&output_meta_data, 0,
+ COMPRE_OUTPUT_METADATA_SIZE);
+ output_meta_data.frame_size = prtd->pcm_count;
+ }
+ buffer_length = output_meta_data.frame_size;
+ pr_debug("meta_data_length: %d, frame_length: %d\n",
+ output_meta_data.meta_data_length,
+ output_meta_data.frame_size);
+ pr_debug("timestamp_msw: %d, timestamp_lsw: %d\n",
+ output_meta_data.timestamp_msw,
+ output_meta_data.timestamp_lsw);
+ param.paddr = (unsigned long)buf[prtd->out_head].phys
+ + output_meta_data.meta_data_length;
+ param.len = buffer_length;
+ param.msw_ts = output_meta_data.timestamp_msw;
+ param.lsw_ts = output_meta_data.timestamp_lsw;
+ param.flags = time_stamp_flag;
+ param.uid = (unsigned long)buf[prtd->out_head].phys
+ + output_meta_data.meta_data_length;
if (q6asm_async_write(prtd->audio_client,
¶m) < 0)
pr_err("%s:q6asm_async_write failed\n",
@@ -166,7 +297,7 @@
case ASM_STREAM_CMD_FLUSH:
pr_debug("ASM_STREAM_CMD_FLUSH\n");
prtd->cmd_ack = 1;
- wake_up(&the_locks.eos_wait);
+ wake_up(&the_locks.flush_wait);
break;
default:
break;
@@ -187,7 +318,7 @@
struct asm_aac_cfg aac_cfg;
int ret;
- pr_debug("%s\n", __func__);
+ pr_debug("compressed stream prepare\n");
prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
prtd->pcm_irq_pos = 0;
@@ -205,7 +336,7 @@
/* No media format block for mp3 */
break;
case SND_AUDIOCODEC_AAC:
- pr_debug("SND_AUDIOCODEC_AAC\n");
+ pr_debug("%s: SND_AUDIOCODEC_AAC\n", __func__);
memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
aac_cfg.format = 0x03;
@@ -226,10 +357,83 @@
return 0;
}
+static int msm_compr_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
+ struct snd_codec *codec = &compr->info.codec_param.codec;
+ struct audio_aio_read_param read_param;
+ int ret = 0;
+ int i;
+ prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+ prtd->pcm_irq_pos = 0;
+
+ /* rate and channels are sent to audio driver */
+ prtd->samp_rate = runtime->rate;
+ prtd->channel_mode = runtime->channels;
+
+ if (prtd->enabled)
+ return ret;
+ read_param.len = prtd->pcm_count;
+
+ switch (codec->id) {
+ case SND_AUDIOCODEC_AMRWB:
+ pr_debug("SND_AUDIOCODEC_AMRWB\n");
+ ret = q6asm_enc_cfg_blk_amrwb(prtd->audio_client,
+ MAX_NUM_FRAMES_PER_BUFFER,
+ codec->options.generic.reserved[0] /*bitrate 0-8*/,
+ codec->options.generic.reserved[1] /*dtx mode 0/1*/);
+ if (ret < 0)
+ pr_err("%s: CMD Format block" \
+ "failed: %d\n", __func__, ret);
+ break;
+ default:
+ pr_debug("No config for codec %d\n", codec->id);
+ }
+ pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
+ "pcm_count = %d, periods = %d\n",
+ __func__, prtd->samp_rate, prtd->channel_mode,
+ prtd->pcm_size, prtd->pcm_count, runtime->periods);
+
+ for (i = 0; i < runtime->periods; i++) {
+ read_param.uid = i;
+ switch (codec->id) {
+ case SND_AUDIOCODEC_AMRWB:
+ read_param.len = prtd->pcm_count
+ - COMPRE_CAPTURE_HEADER_SIZE;
+ read_param.paddr = (unsigned long)(buf[i].phys)
+ + COMPRE_CAPTURE_HEADER_SIZE;
+ pr_debug("Push buffer [%d] to DSP, "\
+ "paddr: %p, vaddr: %p\n",
+ i, (void *) read_param.paddr,
+ buf[i].data);
+ q6asm_async_read(prtd->audio_client, &read_param);
+ break;
+ default:
+ read_param.paddr = (unsigned long)(buf[i].phys);
+ /*q6asm_async_read_compressed(prtd->audio_client,
+ &read_param);*/
+ pr_debug("%s: To add support for read compressed\n",
+ __func__);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ prtd->periods = runtime->periods;
+
+ prtd->enabled = 1;
+
+ return ret;
+}
+
static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
{
int ret = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct compr_audio *compr = runtime->private_data;
struct msm_audio *prtd = &compr->prtd;
@@ -237,6 +441,20 @@
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
prtd->pcm_irq_pos = 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ audio_ocmem_process_req(AUDIO, true);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AMRWB:
+ break;
+ default:
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+ break;
+ }
+ }
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
pr_debug("%s: Trigger start\n", __func__);
@@ -245,6 +463,20 @@
break;
case SNDRV_PCM_TRIGGER_STOP:
pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ audio_ocmem_process_req(AUDIO, false);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AMRWB:
+ break;
+ default:
+ msm_pcm_routing_reg_psthr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+ break;
+ }
+ }
atomic_set(&prtd->start, 0);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -266,7 +498,7 @@
{
pr_debug("%s\n", __func__);
/* MP3 Block */
- compr->info.compr_cap.num_codecs = 1;
+ compr->info.compr_cap.num_codecs = 2;
compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
@@ -294,10 +526,6 @@
.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
};
- /* Capture path */
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- return -EINVAL;
-
pr_debug("%s\n", __func__);
compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
if (compr == NULL) {
@@ -313,12 +541,18 @@
kfree(prtd);
return -ENOMEM;
}
- runtime->hw = msm_compr_hardware_playback;
pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
- prtd->cmd_ack = 1;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw = msm_compr_hardware_playback;
+ prtd->cmd_ack = 1;
+ } else {
+ runtime->hw = msm_compr_hardware_capture;
+ }
+
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
@@ -333,9 +567,11 @@
prtd->dsp_cnt = 0;
atomic_set(&prtd->pending_buffer, 1);
- compr->codec = FORMAT_MP3;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ compr->codec = FORMAT_MP3;
populate_codec_list(compr, runtime);
runtime->private_data = compr;
+ atomic_set(&prtd->eos, 0);
compressed_audio.prtd = &compr->prtd;
ret = compressed_set_volume(compressed_audio.volume);
if (ret < 0)
@@ -382,13 +618,34 @@
dir = IN;
atomic_set(&prtd->pending_buffer, 0);
+ prtd->pcm_irq_pos = 0;
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
compressed_audio.prtd = NULL;
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
+ msm_pcm_routing_dereg_phy_stream(
+ soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+ return 0;
+}
+static int msm_compr_capture_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+ struct compr_audio *compr = runtime->private_data;
+ struct msm_audio *prtd = &compr->prtd;
+ int dir = OUT;
+
+ pr_debug("%s\n", __func__);
+ atomic_set(&prtd->pending_buffer, 0);
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
- SNDRV_PCM_STREAM_PLAYBACK);
+ SNDRV_PCM_STREAM_CAPTURE);
q6asm_audio_client_free(prtd->audio_client);
kfree(prtd);
return 0;
@@ -401,7 +658,7 @@
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ret = msm_compr_playback_close(substream);
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ret = EINVAL;
+ ret = msm_compr_capture_close(substream);
return ret;
}
static int msm_compr_prepare(struct snd_pcm_substream *substream)
@@ -411,7 +668,7 @@
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ret = msm_compr_playback_prepare(substream);
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- ret = EINVAL;
+ ret = msm_compr_capture_prepare(substream);
return ret;
}
@@ -425,7 +682,10 @@
if (prtd->pcm_irq_pos >= prtd->pcm_size)
prtd->pcm_irq_pos = 0;
- pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+ pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n"
+ "frame_bits = %d\n", __func__, prtd->pcm_irq_pos,
+ prtd->pcm_size, runtime->sample_bits,
+ runtime->frame_bits);
return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
}
@@ -467,22 +727,69 @@
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = IN;
else
- return -EINVAL;
+ dir = OUT;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = q6asm_open_write(prtd->audio_client,
+ compr->codec);
+ if (ret < 0) {
+ pr_err("%s: Session out open failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ msm_pcm_routing_reg_phy_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id,
+ substream->stream);
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ switch (compr->info.codec_param.codec.id) {
+ case SND_AUDIOCODEC_AMRWB:
+ pr_debug("q6asm_open_read(FORMAT_AMRWB)\n");
+ ret = q6asm_open_read(prtd->audio_client,
+ FORMAT_AMRWB);
+ if (ret < 0) {
+ pr_err("%s: compressed Session out open failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ pr_debug("msm_pcm_routing_reg_phy_stream\n");
+ msm_pcm_routing_reg_phy_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+ break;
+ default:
+ pr_debug("q6asm_open_read_compressed(COMPRESSED_META_DATA_MODE)\n");
+ /*
+ ret = q6asm_open_read_compressed(prtd->audio_client,
+ MAX_NUM_FRAMES_PER_BUFFER,
+ COMPRESSED_META_DATA_MODE);
+ */
+ ret = -EINVAL;
+ break;
+ }
- ret = q6asm_open_write(prtd->audio_client, compr->codec);
- if (ret < 0) {
- pr_err("%s: Session out open failed\n", __func__);
- return -ENOMEM;
+ if (ret < 0) {
+ pr_err("%s: compressed Session out open failed\n",
+ __func__);
+ return -ENOMEM;
+ }
}
- msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream);
ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
if (ret < 0) {
pr_err("%s: Set IO mode failed\n", __func__);
return -ENOMEM;
}
-
+ /* Modifying kernel hardware params based on userspace config */
+ if (params_periods(params) > 0 &&
+ (params_periods(params) != runtime->hw.periods_max)) {
+ runtime->hw.periods_max = params_periods(params);
+ }
+ if (params_period_bytes(params) > 0 &&
+ (params_period_bytes(params) != runtime->hw.period_bytes_min)) {
+ runtime->hw.period_bytes_min = params_period_bytes(params);
+ }
+ runtime->hw.buffer_bytes_max =
+ runtime->hw.period_bytes_min * runtime->hw.periods_max;
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
runtime->hw.period_bytes_min,
@@ -494,13 +801,17 @@
}
buf = prtd->audio_client->port[dir].buf;
- pr_debug("%s:buf = %p\n", __func__, buf);
dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
dma_buf->dev.dev = substream->pcm->card->dev;
dma_buf->private_data = NULL;
dma_buf->area = buf[0].data;
dma_buf->addr = buf[0].phys;
dma_buf->bytes = runtime->hw.buffer_bytes_max;
+
+ pr_debug("%s: buf[%p]dma_buf->area[%p]dma_buf->addr[%p]\n"
+ "dma_buf->bytes[%d]\n", __func__,
+ (void *)buf, (void *)dma_buf->area,
+ (void *)dma_buf->addr, dma_buf->bytes);
if (!dma_buf->area)
return -ENOMEM;
@@ -577,16 +888,47 @@
}
return 0;
case SNDRV_PCM_IOCTL1_RESET:
- prtd->cmd_ack = 0;
- rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
- if (rc < 0)
- pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
- rc = wait_event_timeout(the_locks.eos_wait,
- prtd->cmd_ack, 5 * HZ);
- if (rc < 0)
- pr_err("Flush cmd timeout\n");
- prtd->pcm_irq_pos = 0;
+ pr_debug("SNDRV_PCM_IOCTL1_RESET\n");
+ /* Flush only when session is started during CAPTURE,
+ while PLAYBACK has no such restriction. */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+ (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+ atomic_read(&prtd->start))) {
+ if (atomic_read(&prtd->eos)) {
+ prtd->cmd_ack = 1;
+ wake_up(&the_locks.eos_wait);
+ atomic_set(&prtd->eos, 0);
+ }
+
+ /* A unlikely race condition possible with FLUSH
+ DRAIN if ack is set by flush and reset by drain */
+ prtd->cmd_ack = 0;
+ rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ if (rc < 0) {
+ pr_err("%s: flush cmd failed rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ rc = wait_event_timeout(the_locks.flush_wait,
+ prtd->cmd_ack, 5 * HZ);
+ if (rc < 0)
+ pr_err("Flush cmd timeout\n");
+ prtd->pcm_irq_pos = 0;
+ }
break;
+ case SNDRV_COMPRESS_DRAIN:
+ pr_debug("%s: SNDRV_COMPRESS_DRAIN\n", __func__);
+ atomic_set(&prtd->eos, 1);
+ atomic_set(&prtd->pending_buffer, 0);
+ prtd->cmd_ack = 0;
+ q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ /* Wait indefinitely for DRAIN. Flush can also signal this*/
+ rc = wait_event_interruptible(the_locks.eos_wait,
+ prtd->cmd_ack);
+ if (rc < 0)
+ pr_err("EOS cmd interrupted\n");
+ pr_debug("%s: SNDRV_COMPRESS_DRAIN out of wait\n", __func__);
+ return 0;
default:
break;
}
@@ -658,6 +1000,7 @@
init_waitqueue_head(&the_locks.eos_wait);
init_waitqueue_head(&the_locks.write_wait);
init_waitqueue_head(&the_locks.read_wait);
+ init_waitqueue_head(&the_locks.flush_wait);
return platform_driver_register(&msm_compr_driver);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 3eab972..dacd59c 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -540,6 +540,14 @@
memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
+ pr_debug("%s: setting bt_fm parameters\n", __func__);
+
+ dai_data->port_config.int_bt_fm.bt_fm_cfg_minor_version =
+ AFE_API_VERSION_INTERNAL_BT_FM_CONFIG;
+ dai_data->port_config.int_bt_fm.num_channels = dai_data->channels;
+ dai_data->port_config.int_bt_fm.sample_rate = dai_data->rate;
+ dai_data->port_config.int_bt_fm.bit_width = 16;
+
return 0;
}
@@ -805,6 +813,36 @@
return 0;
}
+static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
+ .playback = {
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
+ .capture = {
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
@@ -833,6 +871,34 @@
.remove = msm_dai_q6_dai_remove,
};
+static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
static int __devinit msm_auxpcm_dev_probe(struct platform_device *pdev)
{
int id;
@@ -1025,7 +1091,7 @@
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
@@ -1040,7 +1106,7 @@
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
@@ -1084,6 +1150,22 @@
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_slimbus_1_tx_dai);
break;
+ case INT_BT_SCO_RX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_bt_sco_rx_dai);
+ break;
+ case INT_BT_SCO_TX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_bt_sco_tx_dai);
+ break;
+ case RT_PROXY_DAI_001_RX:
+ case RT_PROXY_DAI_002_RX:
+ rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
+ break;
+ case RT_PROXY_DAI_001_TX:
+ case RT_PROXY_DAI_002_TX:
+ rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
+ break;
default:
rc = -ENODEV;
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 4593784..73a04c2 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -29,6 +29,8 @@
#include <sound/control.h>
#include <sound/q6adm-v2.h>
#include <asm/dma.h>
+#include <linux/memory_alloc.h>
+#include <mach/msm_subsystem_map.h>
#include "msm-pcm-afe-v2.h"
#define MIN_PERIOD_SIZE (128 * 2)
@@ -63,6 +65,11 @@
struct snd_pcm_substream *substream = prtd->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
u32 mem_map_handle = 0;
+
+ mem_map_handle = afe_req_mmap_handle();
+ if (!mem_map_handle)
+ pr_err("%s: mem_map_handle is NULL\n", __func__);
+
if (prtd->start) {
pr_debug("sending frame to DSP: poll_time: %d\n",
prtd->poll_time);
@@ -89,10 +96,15 @@
struct snd_pcm_substream *substream = prtd->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
u32 mem_map_handle = 0;
+
+ mem_map_handle = afe_req_mmap_handle();
+ if (!mem_map_handle)
+ pr_err("%s: mem_map_handle is NULL\n", __func__);
+
if (prtd->start) {
if (prtd->dsp_cnt == runtime->periods)
prtd->dsp_cnt = 0;
- pr_err("%s: mem_map_handle 0x%x\n", __func__, mem_map_handle);
+ pr_debug("%s: mem_map_handle 0x%x\n", __func__, mem_map_handle);
afe_rt_proxy_port_read(
(prtd->dma_addr + (prtd->dsp_cnt
* snd_pcm_lib_period_bytes(prtd->substream))), mem_map_handle,
@@ -137,9 +149,6 @@
runtime->channels * 2)));
pr_debug("prtd->poll_time: %d",
prtd->poll_time);
- hrtimer_start(&prtd->hrt,
- ns_to_ktime(0),
- HRTIMER_MODE_REL);
break;
}
case AFE_EVENT_RTPORT_STOP:
@@ -203,9 +212,6 @@
snd_pcm_lib_period_bytes(prtd->substream)
* 1000 * 1000)/(runtime->rate
* runtime->channels * 2)));
- hrtimer_start(&prtd->hrt,
- ns_to_ktime(0),
- HRTIMER_MODE_REL);
pr_debug("prtd->poll_time : %d", prtd->poll_time);
break;
}
@@ -321,13 +327,21 @@
runtime->hw = msm_afe_hardware;
prtd->substream = substream;
runtime->private_data = prtd;
- mutex_unlock(&prtd->lock);
+ prtd->audio_client = q6afe_audio_client_alloc(prtd);
+ if (!prtd->audio_client) {
+ pr_debug("%s: Could not allocate memory\n", __func__);
+ kfree(prtd);
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
+
hrtimer_init(&prtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
prtd->hrt.function = afe_hrtimer_callback;
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
prtd->hrt.function = afe_hrtimer_rec_callback;
+ mutex_unlock(&prtd->lock);
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&constraints_sample_rates);
@@ -350,6 +364,7 @@
struct pcm_afe_info *prtd;
struct snd_soc_pcm_runtime *rtd = NULL;
struct snd_soc_dai *dai = NULL;
+ int dir = IN;
int ret = 0;
pr_debug("%s\n", __func__);
@@ -365,17 +380,19 @@
mutex_lock(&prtd->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dir = IN;
ret = afe_unregister_get_events(dai->id);
if (ret < 0)
pr_err("AFE unregister for events failed\n");
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ dir = OUT;
ret = afe_unregister_get_events(dai->id);
if (ret < 0)
pr_err("AFE unregister for events failed\n");
}
hrtimer_cancel(&prtd->hrt);
- rc = afe_cmd_memory_unmap(runtime->dma_addr);
+ rc = afe_cmd_memory_unmap(afe_req_mmap_handle());
if (rc < 0)
pr_err("AFE memory unmap failed\n");
@@ -384,15 +401,14 @@
if (dma_buf == NULL) {
pr_debug("dma_buf is NULL\n");
goto done;
- }
- if (dma_buf->area != NULL) {
- dma_free_coherent(substream->pcm->card->dev,
- runtime->hw.buffer_bytes_max, dma_buf->area,
- dma_buf->addr);
- dma_buf->area = NULL;
}
+
+ if (dma_buf->area)
+ dma_buf->area = NULL;
+ q6afe_audio_client_buf_free_contiguous(dir, prtd->audio_client);
done:
pr_debug("%s: dai->id =%x\n", __func__, dai->id);
+ q6afe_audio_client_free(prtd->audio_client);
mutex_unlock(&prtd->lock);
prtd->prepared--;
kfree(prtd);
@@ -420,14 +436,21 @@
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct pcm_afe_info *prtd = runtime->private_data;
+ int result = 0;
pr_debug("%s\n", __func__);
prtd->mmap_flag = 1;
- dma_mmap_coherent(substream->pcm->card->dev, vma,
- runtime->dma_area,
- runtime->dma_addr,
- runtime->dma_bytes);
- return 0;
+ if (runtime->dma_addr && runtime->dma_bytes) {
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ result = remap_pfn_range(vma, vma->vm_start,
+ runtime->dma_addr >> PAGE_SHIFT,
+ runtime->dma_bytes,
+ vma->vm_page_prot);
+ } else {
+ pr_err("Physical address or size of buf is NULL");
+ return -EINVAL;
+ }
+ return result;
}
static int msm_afe_trigger(struct snd_pcm_substream *substream, int cmd)
{
@@ -441,6 +464,8 @@
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
pr_debug("%s: SNDRV_PCM_TRIGGER_START\n", __func__);
prtd->start = 1;
+ hrtimer_start(&prtd->hrt, ns_to_ktime(0),
+ HRTIMER_MODE_REL);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -460,27 +485,45 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
struct pcm_afe_info *prtd = runtime->private_data;
- int rc;
+ struct afe_audio_buffer *buf;
+ int dir, rc;
pr_debug("%s:\n", __func__);
mutex_lock(&prtd->lock);
-
- dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
- dma_buf->dev.dev = substream->pcm->card->dev;
- dma_buf->private_data = NULL;
- dma_buf->area = dma_alloc_coherent(dma_buf->dev.dev,
- runtime->hw.buffer_bytes_max,
- &dma_buf->addr, GFP_KERNEL);
-
- pr_debug("%s: dma_buf->area: 0x%p, dma_buf->addr: 0x%x", __func__,
- (unsigned int *) dma_buf->area, dma_buf->addr);
- if (!dma_buf->area) {
- pr_err("%s:MSM AFE memory allocation failed\n", __func__);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ rc = q6afe_audio_client_buf_alloc_contiguous(dir,
+ prtd->audio_client,
+ runtime->hw.period_bytes_min,
+ runtime->hw.periods_max);
+ if (rc < 0) {
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n", rc);
mutex_unlock(&prtd->lock);
return -ENOMEM;
}
+ buf = prtd->audio_client->port[dir].buf;
+
+ if (buf == NULL || buf[0].data == NULL) {
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
+
+ pr_debug("%s:buf = %p\n", __func__, buf);
+ dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ dma_buf->dev.dev = substream->pcm->card->dev;
+ dma_buf->private_data = NULL;
+ dma_buf->area = buf[0].data;
+ dma_buf->addr = buf[0].phys;
dma_buf->bytes = runtime->hw.buffer_bytes_max;
+ if (!dma_buf->area) {
+ pr_err("%s:MSM AFE physical memory allocation failed\n",
+ __func__);
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
prtd->dma_addr = (u32) dma_buf->addr;
@@ -542,6 +585,9 @@
static __devinit int msm_afe_probe(struct platform_device *pdev)
{
+ if (pdev->dev.of_node)
+ dev_set_name(&pdev->dev, "%s", "msm-pcm-afe");
+
pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
return snd_soc_register_platform(&pdev->dev,
&msm_soc_platform);
@@ -553,11 +599,17 @@
snd_soc_unregister_platform(&pdev->dev);
return 0;
}
+static const struct of_device_id msm_pcm_afe_dt_match[] = {
+ {.compatible = "qcom,msm-pcm-afe"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_pcm_afe_dt_match);
static struct platform_driver msm_afe_driver = {
.driver = {
.name = "msm-pcm-afe",
.owner = THIS_MODULE,
+ .of_match_table = msm_pcm_afe_dt_match,
},
.probe = msm_afe_probe,
.remove = __devexit_p(msm_afe_remove),
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h
index 20d6377..446409f 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.h
@@ -30,6 +30,7 @@
int prepared;
struct hrtimer hrt;
int poll_time;
+ struct afe_audio_client *audio_client;
};
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 7483bb6..af1e19c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -56,7 +56,7 @@
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.buffer_bytes_max = CAPTURE_NUM_PERIODS * CAPTURE_PERIOD_SIZE,
.period_bytes_min = CAPTURE_PERIOD_SIZE,
.period_bytes_max = CAPTURE_PERIOD_SIZE,
@@ -297,7 +297,6 @@
static int msm_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct msm_audio *prtd;
int ret = 0;
@@ -315,36 +314,14 @@
kfree(prtd);
return -ENOMEM;
}
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- runtime->hw = msm_pcm_hardware_playback;
- ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
- if (ret < 0) {
- pr_err("%s: pcm out open failed\n", __func__);
- q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
- return -ENOMEM;
- }
- }
- /* Capture path */
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- runtime->hw = msm_pcm_hardware_capture;
- ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
- if (ret < 0) {
- pr_err("%s: pcm in open failed\n", __func__);
- q6asm_audio_client_free(prtd->audio_client);
- kfree(prtd);
- return -ENOMEM;
- }
- }
-
- pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
-
- prtd->session_id = prtd->audio_client->session;
- msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream);
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- prtd->cmd_ack = 1;
+ runtime->hw = msm_pcm_hardware_playback;
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ runtime->hw = msm_pcm_hardware_capture;
+ else {
+ pr_err("Invalid Stream type %d\n", substream->stream);
+ return -EINVAL;
+ }
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
@@ -530,12 +507,15 @@
int dir = OUT;
pr_debug("%s\n", __func__);
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
- q6asm_audio_client_buf_free_contiguous(dir,
+ if (prtd->audio_client) {
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
+ q6asm_audio_client_free(prtd->audio_client);
+ }
+
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
- SNDRV_PCM_STREAM_CAPTURE);
- q6asm_audio_client_free(prtd->audio_client);
+ SNDRV_PCM_STREAM_CAPTURE);
kfree(prtd);
return 0;
@@ -617,13 +597,43 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd = runtime->private_data;
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct audio_buffer *buf;
int dir, ret;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dir = IN;
- else
+ pr_debug("%s Opening %d-ch PCM Write stream\n",
+ __func__, params_channels(params));
+
+ ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
+ if (ret < 0) {
+ pr_err("%s: pcm out open failed\n", __func__);
+ q6asm_audio_client_free(prtd->audio_client);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ } else {
dir = OUT;
+ pr_debug("%s Opening %d-ch PCM read stream\n",
+ __func__, params_channels(params));
+ ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
+ if (ret < 0) {
+ pr_err("%s: pcm in open failed\n", __func__);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return -ENOMEM;
+ }
+ }
+
+ pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+ prtd->session_id = prtd->audio_client->session;
+ msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prtd->cmd_ack = 1;
+
pr_debug("%s: before buf alloc\n", __func__);
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 22bf0cc..e25d356 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -49,6 +49,7 @@
wait_queue_head_t write_wait;
wait_queue_head_t eos_wait;
wait_queue_head_t enable_wait;
+ wait_queue_head_t flush_wait;
};
struct msm_audio {
@@ -76,10 +77,19 @@
atomic_t out_count;
atomic_t in_count;
atomic_t out_needed;
+ atomic_t eos;
int out_head;
int periods;
int mmap_flag;
atomic_t pending_buffer;
};
+struct output_meta_data_st {
+ uint32_t meta_data_length;
+ uint32_t frame_size;
+ uint32_t timestamp_lsw;
+ uint32_t timestamp_msw;
+ uint32_t reserved[12];
+};
+
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 492569b..c7a8031 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -32,8 +32,9 @@
#include "q6voice.h"
#include "audio_ocmem.h"
+#define SHARED_MEM_BUF 2
#define VOIP_MAX_Q_LEN 10
-#define VOIP_MAX_VOC_PKT_SIZE 640
+#define VOIP_MAX_VOC_PKT_SIZE 4096
#define VOIP_MIN_VOC_PKT_SIZE 320
/* Length of the DSP frame info header added to the voc packet. */
@@ -259,8 +260,8 @@
/* capture path */
static void voip_process_ul_pkt(uint8_t *voc_pkt,
- uint32_t pkt_len,
- void *private_data)
+ uint32_t pkt_len,
+ void *private_data)
{
struct voip_buf_node *buf_node = NULL;
struct voip_drv_info *prtd = private_data;
@@ -315,8 +316,8 @@
default: {
buf_node->frame.len = pkt_len;
memcpy(&buf_node->frame.voc_pkt[0],
- voc_pkt,
- buf_node->frame.len);
+ voc_pkt,
+ buf_node->frame.len);
list_add_tail(&buf_node->list, &prtd->out_queue);
}
}
@@ -334,15 +335,12 @@
}
/* playback path */
-static void voip_process_dl_pkt(uint8_t *voc_pkt,
- uint32_t *pkt_len,
- void *private_data)
+static void voip_process_dl_pkt(uint8_t *voc_pkt, void *private_data)
{
struct voip_buf_node *buf_node = NULL;
struct voip_drv_info *prtd = private_data;
unsigned long dsp_flags;
-
if (prtd->playback_substream == NULL)
return;
@@ -355,14 +353,18 @@
switch (prtd->mode) {
case MODE_AMR:
case MODE_AMR_WB: {
- /* Add the DSP frame info header. Header format:
+ *((uint32_t *)voc_pkt) = buf_node->frame.len +
+ DSP_FRAME_HDR_LEN;
+ /* Advance to the header of voip packet */
+ voc_pkt = voc_pkt + sizeof(uint32_t);
+ /*
+ * Add the DSP frame info header. Header format:
* Bits 0-3: Frame rate
* Bits 4-7: Frame type
*/
*voc_pkt = ((buf_node->frame.header.frame_type &
0x0F) << 4) | (prtd->rate_type & 0x0F);
voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
- *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
memcpy(voc_pkt,
&buf_node->frame.voc_pkt[0],
buf_node->frame.len);
@@ -372,12 +374,16 @@
case MODE_IS127:
case MODE_4GV_NB:
case MODE_4GV_WB: {
- /* Add the DSP frame info header. Header format:
+ *((uint32_t *)voc_pkt) = buf_node->frame.len +
+ DSP_FRAME_HDR_LEN;
+ /* Advance to the header of voip packet */
+ voc_pkt = voc_pkt + sizeof(uint32_t);
+ /*
+ * Add the DSP frame info header. Header format:
* Bits 0-3 : Frame rate
- */
+ */
*voc_pkt = buf_node->frame.header.packet_rate & 0x0F;
voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
- *pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
memcpy(voc_pkt,
&buf_node->frame.voc_pkt[0],
@@ -387,22 +393,19 @@
break;
}
default: {
- *pkt_len = buf_node->frame.len;
-
+ *((uint32_t *)voc_pkt) = buf_node->frame.len;
+ voc_pkt = voc_pkt + sizeof(uint32_t);
memcpy(voc_pkt,
- &buf_node->frame.voc_pkt[0],
- buf_node->frame.len);
-
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.len);
list_add_tail(&buf_node->list, &prtd->free_in_queue);
}
}
- pr_debug("dl_pkt: pkt_len=%d, frame_len=%d\n", *pkt_len,
- buf_node->frame.len);
prtd->pcm_playback_irq_pos += prtd->pcm_count;
spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
snd_pcm_period_elapsed(prtd->playback_substream);
} else {
- *pkt_len = 0;
+ *((uint32_t *)voc_pkt) = 0;
spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
pr_err("DL data not available\n");
}
@@ -556,7 +559,7 @@
pr_err("%s: No free DL buffs\n", __func__);
ret = -ETIMEDOUT;
} else {
- pr_err("%s: playback copy was interrupted\n", __func__);
+ pr_err("%s: playback copy was interrupted %d\n", __func__, ret);
}
return ret;
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 62257b4..0466eb6 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -116,8 +116,18 @@
wake_up(&this_adm.wait[index]);
break;
case ADM_CMD_SHARED_MEM_MAP_REGIONS:
- /* Block until memory handle comes back */
- /* via ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+ pr_debug("%s: ADM_CMD_SHARED_MEM_MAP_REGIONS\n",
+ __func__);
+ /* Should only come here if there is an APR */
+ /* error or malformed APR packet. Otherwise */
+ /* response will be returned as */
+ /* ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+ if (payload[1] != 0) {
+ pr_err("%s: ADM map error, resuming\n",
+ __func__);
+ atomic_set(&this_adm.copp_stat[0], 1);
+ wake_up(&this_adm.wait[index]);
+ }
break;
default:
pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
@@ -247,24 +257,27 @@
get_audproc_cal(acdb_path, &aud_cal);
/* map & cache buffers used */
+ atomic_set(&mem_map_index, acdb_path);
if (((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr) &&
(aud_cal.cal_size > 0)) ||
(aud_cal.cal_size > mem_addr_audproc[acdb_path].cal_size)) {
- atomic_set(&mem_map_index, acdb_path);
if (mem_addr_audproc[acdb_path].cal_paddr != 0)
adm_memory_unmap_regions(port_id,
&mem_addr_audproc[acdb_path].cal_paddr,
&size, 1);
result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
- 0, &aud_cal.cal_size, 1);
- if (result < 0)
+ 0, &size, 1);
+ if (result < 0) {
pr_err("ADM audproc mmap did not work! path = %d, addr = 0x%x, size = %d\n",
acdb_path, aud_cal.cal_paddr,
aud_cal.cal_size);
- else
- mem_addr_audproc[acdb_path] = aud_cal;
+ } else {
+ mem_addr_audproc[acdb_path].cal_paddr =
+ aud_cal.cal_paddr;
+ mem_addr_audproc[acdb_path].cal_size = size;
+ }
}
if (!send_adm_cal_block(port_id, &aud_cal))
@@ -278,24 +291,27 @@
get_audvol_cal(acdb_path, &aud_cal);
/* map & cache buffers used */
+ atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
if (((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr) &&
(aud_cal.cal_size > 0)) ||
(aud_cal.cal_size > mem_addr_audvol[acdb_path].cal_size)) {
- atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
if (mem_addr_audvol[acdb_path].cal_paddr != 0)
adm_memory_unmap_regions(port_id,
&mem_addr_audvol[acdb_path].cal_paddr,
&size, 1);
result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
- 0, &aud_cal.cal_size, 1);
- if (result < 0)
+ 0, &size, 1);
+ if (result < 0) {
pr_err("ADM audvol mmap did not work! path = %d, addr = 0x%x, size = %d\n",
acdb_path, aud_cal.cal_paddr,
aud_cal.cal_size);
- else
- mem_addr_audvol[acdb_path] = aud_cal;
+ } else {
+ mem_addr_audvol[acdb_path].cal_paddr =
+ aud_cal.cal_paddr;
+ mem_addr_audvol[acdb_path].cal_size = size;
+ }
}
if (!send_adm_cal_block(port_id, &aud_cal))
@@ -454,6 +470,21 @@
} else if (channel_mode == 2) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channel_mode == 3) {
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FR;
+ open.dev_channel_mapping[1] = PCM_CHANNEL_FC;
+ } else if (channel_mode == 4) {
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_RB;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
+ } else if (channel_mode == 5) {
+ open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+ open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+ open.dev_channel_mapping[2] = PCM_CHANNEL_FC;
+ open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
+ open.dev_channel_mapping[4] = PCM_CHANNEL_RB;
} else if (channel_mode == 6) {
open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
@@ -461,6 +492,15 @@
open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
+ } else if (channel_mode == 8) {
+ 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[4] = PCM_CHANNEL_LB;
+ open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
+ open.dev_channel_mapping[6] = PCM_CHANNEL_FLC;
+ open.dev_channel_mapping[7] = PCM_CHANNEL_FRC;
} else {
pr_err("%s invalid num_chan %d\n", __func__,
channel_mode);
@@ -664,8 +704,8 @@
APR_PKT_VER);
mmap_regions->hdr.pkt_size = cmd_size;
mmap_regions->hdr.src_port = 0;
- mmap_regions->hdr.dest_port = 0;
- mmap_regions->hdr.token = 0;
+ mmap_regions->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ mmap_regions->hdr.token = port_id;
mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
mmap_regions->num_regions = bufcnt & 0x00ff;
@@ -733,8 +773,8 @@
APR_PKT_VER);
unmap_regions.hdr.pkt_size = cmd_size;
unmap_regions.hdr.src_port = 0;
- unmap_regions.hdr.dest_port = 0;
- unmap_regions.hdr.token = 0;
+ unmap_regions.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ unmap_regions.hdr.token = port_id;
unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
unmap_regions.mem_map_handle = atomic_read(&mem_map_handles[
atomic_read(&mem_map_index)]);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 0b25545..f0465a5 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -18,6 +18,7 @@
#include <linux/wait.h>
#include <linux/jiffies.h>
#include <linux/sched.h>
+#include <linux/msm_ion.h>
#include <mach/qdsp6v2/audio_acdb.h>
#include <sound/apr_audio-v2.h>
#include <sound/q6afe-v2.h>
@@ -37,6 +38,7 @@
uint32_t token, uint32_t *payload, void *priv);
void *tx_private_data;
void *rx_private_data;
+ uint32_t mmap_handle;
};
static struct afe_ctl this_afe;
@@ -107,6 +109,13 @@
payload[0]);
break;
}
+ } else if (data->opcode ==
+ AFE_SERVICE_CMDRSP_SHARED_MEM_MAP_REGIONS) {
+ pr_debug("%s: mmap_handle: 0x%x\n",
+ __func__, payload[0]);
+ this_afe.mmap_handle = (uint32_t)payload[0];
+ atomic_set(&this_afe.state, 0);
+ wake_up(&this_afe.wait[data->token]);
} else if (data->opcode == AFE_EVENT_RT_PROXY_PORT_STATUS) {
port_id = (uint16_t)(0x0000FFFF & payload[0]);
}
@@ -266,17 +275,21 @@
ret = -EINVAL;
return ret;
}
- index = q6audio_get_port_index(port_id);
- if (q6audio_validate_port(port_id) < 0)
- return -EINVAL;
if ((port_id == RT_PROXY_DAI_001_RX) ||
(port_id == RT_PROXY_DAI_002_TX))
- return -EINVAL;
+ return 0;
if ((port_id == RT_PROXY_DAI_002_RX) ||
(port_id == RT_PROXY_DAI_001_TX))
port_id = VIRTUAL_ID_TO_PORTID(port_id);
+ pr_debug("%s: port id: %d\n", __func__, port_id);
+ index = q6audio_get_port_index(port_id);
+ if (q6audio_validate_port(port_id) < 0) {
+ pr_err("%s: port id: %d\n", __func__, port_id);
+ return -EINVAL;
+ }
+
ret = afe_q6_interface_prepare();
if (IS_ERR_VALUE(ret))
return ret;
@@ -325,6 +338,14 @@
case SLIMBUS_4_TX:
cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG;
break;
+ case RT_PROXY_PORT_001_RX:
+ case RT_PROXY_PORT_001_TX:
+ cfg_type = AFE_PARAM_ID_RT_PROXY_CONFIG;
+ break;
+ case INT_BT_SCO_RX:
+ case INT_BT_SCO_TX:
+ cfg_type = AFE_PARAM_ID_INTERNAL_BT_FM_CONFIG;
+ break;
default:
pr_err("%s: Invalid port id 0x%x\n", __func__, port_id);
ret = -EINVAL;
@@ -904,7 +925,133 @@
return 0;
}
-/*bharath, memory map handle needs to be stored by AFE client */
+uint32_t afe_req_mmap_handle(void)
+{
+ return this_afe.mmap_handle;
+}
+
+struct afe_audio_client *q6afe_audio_client_alloc(void *priv)
+{
+ struct afe_audio_client *ac;
+ int lcnt = 0;
+
+ ac = kzalloc(sizeof(struct afe_audio_client), GFP_KERNEL);
+ if (!ac) {
+ pr_err("%s: cannot allocate audio client for afe\n", __func__);
+ return NULL;
+ }
+ ac->priv = priv;
+
+ init_waitqueue_head(&ac->cmd_wait);
+ INIT_LIST_HEAD(&ac->port[0].mem_map_handle);
+ INIT_LIST_HEAD(&ac->port[1].mem_map_handle);
+ pr_debug("%s: mem_map_handle list init'ed\n", __func__);
+ mutex_init(&ac->cmd_lock);
+ for (lcnt = 0; lcnt <= OUT; lcnt++) {
+ mutex_init(&ac->port[lcnt].lock);
+ spin_lock_init(&ac->port[lcnt].dsp_lock);
+ }
+ atomic_set(&ac->cmd_state, 0);
+
+ return ac;
+}
+
+int q6afe_audio_client_buf_alloc_contiguous(unsigned int dir,
+ struct afe_audio_client *ac,
+ unsigned int bufsz,
+ unsigned int bufcnt)
+{
+ int cnt = 0;
+ int rc = 0;
+ struct afe_audio_buffer *buf;
+ int len;
+
+ if (!(ac) || ((dir != IN) && (dir != OUT)))
+ return -EINVAL;
+
+ pr_debug("%s: bufsz[%d]bufcnt[%d]\n",
+ __func__,
+ bufsz, bufcnt);
+
+ if (ac->port[dir].buf) {
+ pr_debug("%s: buffer already allocated\n", __func__);
+ return 0;
+ }
+ mutex_lock(&ac->cmd_lock);
+ buf = kzalloc(((sizeof(struct afe_audio_buffer))*bufcnt),
+ GFP_KERNEL);
+
+ if (!buf) {
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+
+ ac->port[dir].buf = buf;
+
+ buf[0].client = msm_ion_client_create(UINT_MAX, "audio_client");
+ if (IS_ERR_OR_NULL((void *)buf[0].client)) {
+ pr_err("%s: ION create client for AUDIO failed\n", __func__);
+ goto fail;
+ }
+ buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
+ (0x1 << ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
+ pr_err("%s: ION memory allocation for AUDIO failed\n",
+ __func__);
+ goto fail;
+ }
+
+ rc = ion_phys(buf[0].client, buf[0].handle,
+ (ion_phys_addr_t *)&buf[0].phys, (size_t *)&len);
+ if (rc) {
+ pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle);
+ if (IS_ERR_OR_NULL((void *) buf[0].data)) {
+ pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+ goto fail;
+ }
+ memset((void *)buf[0].data, 0, (bufsz * bufcnt));
+ if (!buf[0].data) {
+ pr_err("%s:invalid vaddr, iomap failed\n", __func__);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+
+ buf[0].used = dir ^ 1;
+ buf[0].size = bufsz;
+ buf[0].actual_size = bufsz;
+ cnt = 1;
+ while (cnt < bufcnt) {
+ if (bufsz > 0) {
+ buf[cnt].data = buf[0].data + (cnt * bufsz);
+ buf[cnt].phys = buf[0].phys + (cnt * bufsz);
+ if (!buf[cnt].data) {
+ pr_err("%s Buf alloc failed\n",
+ __func__);
+ mutex_unlock(&ac->cmd_lock);
+ goto fail;
+ }
+ buf[cnt].used = dir ^ 1;
+ buf[cnt].size = bufsz;
+ buf[cnt].actual_size = bufsz;
+ pr_debug("%s data[%p]phys[%p][%p]\n", __func__,
+ (void *)buf[cnt].data,
+ (void *)buf[cnt].phys,
+ (void *)&buf[cnt].phys);
+ }
+ cnt++;
+ }
+ ac->port[dir].max_buf_cnt = cnt;
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+fail:
+ q6afe_audio_client_buf_free_contiguous(dir, ac);
+ return -EINVAL;
+}
int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz)
{
int ret = 0;
@@ -941,7 +1088,7 @@
mmap_region_cmd;
mregion->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
- mregion->hdr.pkt_size = sizeof(mregion);
+ mregion->hdr.pkt_size = cmd_size;
mregion->hdr.src_port = 0;
mregion->hdr.dest_port = 0;
mregion->hdr.token = 0;
@@ -961,13 +1108,15 @@
mregion_pl->shm_addr_msw = 0x00;
mregion_pl->mem_size_bytes = dma_buf_sz;
+ pr_debug("%s: dma_addr_p 0x%x , size %d\n", __func__,
+ dma_addr_p, dma_buf_sz);
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) mmap_region_cmd);
if (ret < 0) {
pr_err("%s: AFE memory map cmd failed %d\n",
__func__, ret);
ret = -EINVAL;
- return ret;
+ goto fail_cmd;
}
ret = wait_event_timeout(this_afe.wait[index],
@@ -976,10 +1125,13 @@
if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
- return ret;
+ goto fail_cmd;
}
-
+ pr_debug("%s: mmap handle 0x%x\n", __func__, this_afe.mmap_handle);
return 0;
+fail_cmd:
+ kfree(mmap_region_cmd);
+ return ret;
}
int afe_cmd_memory_map_nowait(int port_id, u32 dma_addr_p, u32 dma_buf_sz)
@@ -1047,6 +1199,60 @@
}
return 0;
}
+int q6afe_audio_client_buf_free_contiguous(unsigned int dir,
+ struct afe_audio_client *ac)
+{
+ struct afe_audio_port_data *port;
+ int cnt = 0;
+ mutex_lock(&ac->cmd_lock);
+ port = &ac->port[dir];
+ if (!port->buf) {
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+ }
+ cnt = port->max_buf_cnt - 1;
+
+ if (port->buf[0].data) {
+ ion_unmap_kernel(port->buf[0].client, port->buf[0].handle);
+ ion_free(port->buf[0].client, port->buf[0].handle);
+ ion_client_destroy(port->buf[0].client);
+ pr_debug("%s:data[%p]phys[%p][%p] , client[%p] handle[%p]\n",
+ __func__,
+ (void *)port->buf[0].data,
+ (void *)port->buf[0].phys,
+ (void *)&port->buf[0].phys,
+ (void *)port->buf[0].client,
+ (void *)port->buf[0].handle);
+ }
+
+ while (cnt >= 0) {
+ port->buf[cnt].data = NULL;
+ port->buf[cnt].phys = 0;
+ cnt--;
+ }
+ port->max_buf_cnt = 0;
+ kfree(port->buf);
+ port->buf = NULL;
+ mutex_unlock(&ac->cmd_lock);
+ return 0;
+}
+
+void q6afe_audio_client_free(struct afe_audio_client *ac)
+{
+ int loopcnt;
+ struct afe_audio_port_data *port;
+ if (!ac)
+ return;
+ for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+ port = &ac->port[loopcnt];
+ if (!port->buf)
+ continue;
+ pr_debug("%s:loopcnt = %d\n", __func__, loopcnt);
+ q6afe_audio_client_buf_free_contiguous(loopcnt, ac);
+ }
+ kfree(ac);
+ return;
+}
int afe_cmd_memory_unmap(u32 mem_map_handle)
{
@@ -1143,7 +1349,7 @@
int ret = 0;
struct afe_service_cmd_register_rt_port_driver rtproxy;
- pr_debug("%s:\n", __func__);
+ pr_debug("%s: port_id: %d\n", __func__, port_id);
if (this_afe.apr == NULL) {
this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
@@ -1206,9 +1412,6 @@
return ret;
}
}
- index = q6audio_get_port_index(port_id);
- if (q6audio_validate_port(port_id) < 0)
- return -EINVAL;
if ((port_id == RT_PROXY_DAI_002_RX) ||
(port_id == RT_PROXY_DAI_001_TX))
@@ -1216,6 +1419,10 @@
else
return -EINVAL;
+ index = q6audio_get_port_index(port_id);
+ if (q6audio_validate_port(port_id) < 0)
+ return -EINVAL;
+
rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
rtproxy.hdr.pkt_size = sizeof(rtproxy);
@@ -1318,6 +1525,7 @@
afecmd_rd.buffer_address_lsw = (uint32_t)buf_addr_p;
afecmd_rd.buffer_address_msw = 0x00;
afecmd_rd.available_bytes = bytes;
+ afecmd_rd.mem_map_handle = mem_map_handle;
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
if (ret < 0) {
@@ -1665,11 +1873,11 @@
}
pr_debug("%s: port_id=%d\n", __func__, port_id);
+ port_id = q6audio_convert_virtual_to_portid(port_id);
index = q6audio_get_port_index(port_id);
if (q6audio_validate_port(port_id) < 0)
return -EINVAL;
- port_id = q6audio_convert_virtual_to_portid(port_id);
stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -1708,6 +1916,7 @@
atomic_set(&this_afe.state, 0);
atomic_set(&this_afe.status, 0);
this_afe.apr = NULL;
+ this_afe.mmap_handle = 0;
for (i = 0; i < AFE_MAX_PORTS; i++)
init_waitqueue_head(&this_afe.wait[i]);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 714b2ce..072e293 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -632,7 +632,7 @@
}
buf[cnt].handle = ion_alloc
(buf[cnt].client, bufsz, SZ_4K,
- (0x1 << ION_AUDIO_HEAP_ID));
+ (0x1 << ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL((void *)
buf[cnt].handle)) {
pr_err("%s: ION memory allocation for AUDIO failed\n",
@@ -652,8 +652,7 @@
}
buf[cnt].data = ion_map_kernel
- (buf[cnt].client, buf[cnt].handle,
- 0);
+ (buf[cnt].client, buf[cnt].handle);
if (IS_ERR_OR_NULL((void *)
buf[cnt].data)) {
pr_err("%s: ION memory mapping for AUDIO failed\n",
@@ -729,7 +728,7 @@
goto fail;
}
buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
- (0x1 << ION_AUDIO_HEAP_ID));
+ (0x1 << ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
pr_err("%s: ION memory allocation for AUDIO failed\n",
__func__);
@@ -744,7 +743,7 @@
goto fail;
}
- buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle, 0);
+ buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle);
if (IS_ERR_OR_NULL((void *) buf[0].data)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
goto fail;
@@ -820,6 +819,10 @@
}
sid = (data->token >> 8) & 0x0F;
ac = q6asm_get_audio_client(sid);
+ if (!ac) {
+ pr_debug("%s: session[%d] already freed\n", __func__, sid);
+ return 0;
+ }
pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]sid[%d]dir[%d]\n",
__func__, payload[0], payload[1], data->opcode, data->token,
data->payload_size, data->src_port, data->dest_port, sid, dir);
@@ -1690,7 +1693,7 @@
enc_cfg.bits_per_sample = 16;
enc_cfg.sample_rate = rate;
enc_cfg.is_signed = 1;
- channel_mapping = enc_cfg.channel_mapping; /* ??? PHANI */
+ channel_mapping = enc_cfg.channel_mapping;
memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
@@ -1740,7 +1743,8 @@
enc_cfg.bits_per_sample = 16;
enc_cfg.sample_rate = 0;/*rate;*/
enc_cfg.is_signed = 1;
- channel_mapping = enc_cfg.channel_mapping; /* ??? PHANI */
+ channel_mapping = enc_cfg.channel_mapping;
+
memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
@@ -1775,27 +1779,36 @@
lchannel_mapping[0] = PCM_CHANNEL_FL;
lchannel_mapping[1] = PCM_CHANNEL_FR;
} else if (channels == 3) {
- lchannel_mapping[0] = PCM_CHANNEL_FC;
- lchannel_mapping[1] = PCM_CHANNEL_FL;
- lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
} else if (channels == 4) {
- lchannel_mapping[0] = PCM_CHANNEL_FC;
- lchannel_mapping[1] = PCM_CHANNEL_FL;
- lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_RB;
lchannel_mapping[3] = PCM_CHANNEL_LB;
} else if (channels == 5) {
- lchannel_mapping[0] = PCM_CHANNEL_FC;
- lchannel_mapping[1] = PCM_CHANNEL_FL;
- lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_FC;
lchannel_mapping[3] = PCM_CHANNEL_LB;
lchannel_mapping[4] = PCM_CHANNEL_RB;
} else if (channels == 6) {
- lchannel_mapping[0] = PCM_CHANNEL_FC;
- lchannel_mapping[1] = PCM_CHANNEL_FL;
- lchannel_mapping[2] = PCM_CHANNEL_FR;
- lchannel_mapping[3] = PCM_CHANNEL_LB;
- lchannel_mapping[4] = PCM_CHANNEL_RB;
- lchannel_mapping[5] = PCM_CHANNEL_LFE;
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_LFE;
+ lchannel_mapping[3] = PCM_CHANNEL_FC;
+ lchannel_mapping[4] = PCM_CHANNEL_LB;
+ lchannel_mapping[5] = PCM_CHANNEL_RB;
+ } else if (channels == 6) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ lchannel_mapping[2] = PCM_CHANNEL_LFE;
+ lchannel_mapping[3] = PCM_CHANNEL_FC;
+ lchannel_mapping[4] = PCM_CHANNEL_LB;
+ lchannel_mapping[5] = PCM_CHANNEL_RB;
+ lchannel_mapping[6] = PCM_CHANNEL_FLC;
+ lchannel_mapping[7] = PCM_CHANNEL_FRC;
} else {
pr_err("%s: ERROR.unsupported num_ch = %u\n",
__func__, channels);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index f84b456..1f6dbf1 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -50,6 +50,15 @@
static int voice_send_set_device_cmd(struct voice_data *v);
static int voice_send_disable_vocproc_cmd(struct voice_data *v);
static int voice_send_vol_index_cmd(struct voice_data *v);
+static int voice_send_mvm_map_memory_physical_cmd(struct voice_data *v);
+static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
+ unsigned int bufcnt);
+static int voice_send_mvm_cal_network_cmd(struct voice_data *v);
+static int voice_send_mvm_media_type_cmd(struct voice_data *v);
+static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v);
+static int voice_send_cvs_packet_exchange_config_cmd(struct voice_data *v);
+static int voice_set_packet_exchange_mode_and_config(uint16_t session_id,
+ uint32_t mode);
static int voice_cvs_stop_playback(struct voice_data *v);
static int voice_cvs_start_playback(struct voice_data *v);
static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode);
@@ -594,7 +603,6 @@
detach_stream.detach_stream.handle = cvs_handle;
v->mvm_state = CMD_STATUS_FAIL;
-
ret = apr_send_pkt(apr_mvm, (uint32_t *) &detach_stream);
if (ret < 0) {
pr_err("%s: Error %d sending DETACH_STREAM\n",
@@ -608,6 +616,7 @@
pr_err("%s: wait event timeout\n", __func__);
goto fail;
}
+
/* Destroy CVS. */
pr_debug("%s: CVS destroy session\n", __func__);
@@ -622,7 +631,6 @@
cvs_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
v->cvs_state = CMD_STATUS_FAIL;
-
ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_destroy);
if (ret < 0) {
pr_err("%s: Error %d sending CVS DESTROY\n",
@@ -640,6 +648,13 @@
cvs_handle = 0;
voice_set_cvs_handle(v, cvs_handle);
+ ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+ NUM_OF_BUFFERS);
+ if (ret < 0) {
+ pr_err("%s CMD Memory_unmap_regions failed %d\n",
+ __func__, ret);
+ }
+
/* Destroy MVM. */
pr_debug("MVM destroy session\n");
@@ -667,7 +682,6 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait event timeout\n", __func__);
-
goto fail;
}
mvm_handle = 0;
@@ -788,6 +802,58 @@
return 0;
}
+static int voice_send_mvm_media_type_cmd(struct voice_data *v)
+{
+ struct vss_imvm_cmd_set_cal_media_type_t mvm_set_cal_media_type;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_set_cal_media_type.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_cal_media_type.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_cal_media_type) -
+ APR_HDR_SIZE);
+ mvm_set_cal_media_type.hdr.src_port = v->session_id;
+ mvm_set_cal_media_type.hdr.dest_port = mvm_handle;
+ mvm_set_cal_media_type.hdr.token = 0;
+ mvm_set_cal_media_type.hdr.opcode = VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE;
+ mvm_set_cal_media_type.media_id = common.mvs_info.media_type;
+ pr_debug("%s: setting media_id as %x\n",
+ __func__ , mvm_set_cal_media_type.media_id);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_cal_media_type);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending media type\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
+ return 0;
+fail:
+ return -EINVAL;
+}
static int voice_config_cvs_vocoder(struct voice_data *v)
{
int ret = 0;
@@ -813,7 +879,8 @@
APR_HDR_LEN(APR_HDR_SIZE),
APR_PKT_VER);
cvs_set_media_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_media_cmd) - APR_HDR_SIZE);
+ sizeof(cvs_set_media_cmd) -
+ APR_HDR_SIZE);
cvs_set_media_cmd.hdr.src_port = v->session_id;
cvs_set_media_cmd.hdr.dest_port = cvs_handle;
cvs_set_media_cmd.hdr.token = 0;
@@ -826,7 +893,7 @@
ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_media_cmd);
if (ret < 0) {
pr_err("%s: Error %d sending SET_MEDIA_TYPE\n",
- __func__, ret);
+ __func__, ret);
goto fail;
}
@@ -1196,6 +1263,102 @@
return -EINVAL;
}
+static int voice_send_mvm_map_memory_physical_cmd(struct voice_data *v)
+{
+ struct vss_imemory_cmd_map_physical_t mvm_map_phys_cmd;
+ uint32_t *memtable;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!v->shmem_info.memtbl.data) {
+ pr_err("%s: shmem_info.memtbl.data is NULL.\n", __func__);
+ return -EINVAL;
+ }
+
+ memtable = (uint32_t *)v->shmem_info.memtbl.data;
+
+ /*
+ * Store next table descriptor's address(64 bit) as NULL as there
+ * is only one memory block
+ */
+ memtable[0] = (uint32_t)NULL;
+ memtable[1] = (uint32_t)NULL;
+
+ /* Store next table descriptor's size */
+ memtable[2] = 0;
+
+ /* Store shared mem add */
+ memtable[3] = v->shmem_info.sh_buf.buf[0].phys;
+ memtable[4] = 0;
+
+ /* Store shared memory size */
+ memtable[5] = v->shmem_info.sh_buf.buf[0].size * NUM_OF_BUFFERS;
+
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_map_phys_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ mvm_map_phys_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_map_phys_cmd) - APR_HDR_SIZE);
+ mvm_map_phys_cmd.hdr.src_port = v->session_id;
+ mvm_map_phys_cmd.hdr.dest_port = mvm_handle;
+ mvm_map_phys_cmd.hdr.token = 0;
+ mvm_map_phys_cmd.hdr.opcode = VSS_IMEMORY_CMD_MAP_PHYSICAL;
+
+ mvm_map_phys_cmd.table_descriptor.mem_address =
+ v->shmem_info.memtbl.phys;
+ mvm_map_phys_cmd.table_descriptor.mem_size =
+ sizeof(struct vss_imemory_block_t) +
+ sizeof(struct vss_imemory_table_descriptor_t);
+ mvm_map_phys_cmd.is_cached = true;
+ mvm_map_phys_cmd.cache_line_size = 128;
+ mvm_map_phys_cmd.access_mask = 3;
+ mvm_map_phys_cmd.page_align = 4096;
+ mvm_map_phys_cmd.min_data_width = 8;
+ mvm_map_phys_cmd.max_data_width = 64;
+
+ pr_debug("%s: ntd->add: %lld, ntd->size: %d, table->add: 0x%x\n",
+ __func__,
+ *((uint64_t *)v->shmem_info.memtbl.data),
+ *(((uint32_t *)(v->shmem_info.memtbl.data)) + 2),
+ *(((uint32_t *)(v->shmem_info.memtbl.data)) + 3));
+ pr_debug("%s: table->size: %d, pkt_size: %d, mvm_handle: 0x%x\n",
+ __func__,
+ *(((uint32_t *)(v->shmem_info.memtbl.data)) + 5),
+ mvm_map_phys_cmd.hdr.pkt_size, mvm_handle);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_map_phys_cmd);
+ if (ret < 0) {
+ pr_err("Fail: sending mvm map phy cmd %d\n", ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ return -EINVAL;
+}
static int voice_setup_vocproc(struct voice_data *v)
{
@@ -1225,7 +1388,7 @@
cvp_session_cmd.hdr.dest_port = 0;
cvp_session_cmd.hdr.token = 0;
cvp_session_cmd.hdr.opcode =
- VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION;
+ VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2;
/* Use default topology if invalid value in ACDB */
cvp_session_cmd.cvp_session.tx_topology_id =
@@ -1241,16 +1404,24 @@
VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
cvp_session_cmd.cvp_session.direction = 2; /*tx and rx*/
- cvp_session_cmd.cvp_session.network_id = VSS_NETWORK_ID_DEFAULT;
cvp_session_cmd.cvp_session.tx_port_id = v->dev_tx.port_id;
cvp_session_cmd.cvp_session.rx_port_id = v->dev_rx.port_id;
+ cvp_session_cmd.cvp_session.profile_id =
+ VSS_ICOMMON_CAL_NETWORK_ID_NONE;
+ cvp_session_cmd.cvp_session.vocproc_mode =
+ VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING;
+ cvp_session_cmd.cvp_session.ec_ref_port_id =
+ VSS_IVOCPROC_PORT_ID_NONE;
- pr_debug("topology=%d net_id=%d, dir=%d tx_port_id=%d, rx_port_id=%d\n",
+ pr_debug("tx_topology: %d tx_port_id=%d, rx_port_id=%d, mode: 0x%x\n",
cvp_session_cmd.cvp_session.tx_topology_id,
- cvp_session_cmd.cvp_session.network_id,
- cvp_session_cmd.cvp_session.direction,
cvp_session_cmd.cvp_session.tx_port_id,
- cvp_session_cmd.cvp_session.rx_port_id);
+ cvp_session_cmd.cvp_session.rx_port_id,
+ cvp_session_cmd.cvp_session.vocproc_mode);
+ pr_debug("rx_topology: %d, profile_id: 0x%x, pkt_size: %d\n",
+ cvp_session_cmd.cvp_session.rx_topology_id,
+ cvp_session_cmd.cvp_session.profile_id,
+ cvp_session_cmd.hdr.pkt_size);
v->cvp_state = CMD_STATUS_FAIL;
ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_session_cmd);
@@ -1266,7 +1437,6 @@
goto fail;
}
-
/* enable vocproc */
ret = voice_send_enable_vocproc_cmd(v);
if (ret < 0)
@@ -1280,9 +1450,19 @@
/* send tty mode if tty device is used */
voice_send_tty_mode_cmd(v);
+ if (is_voip_session(v->session_id)) {
+ ret = voice_send_mvm_cal_network_cmd(v);
+ if (ret < 0)
+ pr_err("%s: voice_send_mvm_cal_network_cmd: %d\n",
+ __func__, ret);
- if (is_voip_session(v->session_id))
+ ret = voice_send_mvm_media_type_cmd(v);
+ if (ret < 0)
+ pr_err("%s: voice_send_mvm_media_type_cmd: %d\n",
+ __func__, ret);
+
voice_send_netid_timing_cmd(v);
+ }
/* Start in-call music delivery if this feature is enabled */
if (v->music_info.play_enable)
@@ -1350,6 +1530,55 @@
return -EINVAL;
}
+static int voice_send_mvm_cal_network_cmd(struct voice_data *v)
+{
+ struct vss_imvm_cmd_set_cal_network_t mvm_set_cal_network;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mvm_set_cal_network.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mvm_set_cal_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mvm_set_cal_network) - APR_HDR_SIZE);
+ mvm_set_cal_network.hdr.src_port = v->session_id;
+ mvm_set_cal_network.hdr.dest_port = mvm_handle;
+ mvm_set_cal_network.hdr.token = 0;
+ mvm_set_cal_network.hdr.opcode = VSS_IMVM_CMD_SET_CAL_NETWORK;
+ mvm_set_cal_network.network_id = VSS_ICOMMON_CAL_NETWORK_ID_NONE;
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_cal_network);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_NETWORK\n", __func__, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
+ return 0;
+fail:
+ return -EINVAL;
+}
+
static int voice_send_netid_timing_cmd(struct voice_data *v)
{
int ret = 0;
@@ -1590,10 +1819,177 @@
cvp_handle = 0;
voice_set_cvp_handle(v, cvp_handle);
+ return 0;
+fail:
+ return -EINVAL;
+}
+static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
+ unsigned int bufcnt)
+{
+ struct vss_imemory_cmd_unmap_t mem_unmap;
+ int ret = 0;
+ void *apr_mvm;
+ u16 mvm_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_mvm = common.apr_q6_mvm;
+
+ if (!apr_mvm) {
+ pr_err("%s: apr_mvm is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ mvm_handle = voice_get_mvm_handle(v);
+
+ mem_unmap.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ mem_unmap.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(mem_unmap) - APR_HDR_SIZE);
+ mem_unmap.hdr.src_port = v->session_id;
+ mem_unmap.hdr.dest_port = mvm_handle;
+ mem_unmap.hdr.token = 0;
+ mem_unmap.hdr.opcode = VSS_IMEMORY_CMD_UNMAP;
+ mem_unmap.mem_handle = v->shmem_info.mem_handle;
+
+ pr_debug("%s: mem_handle: ox%x\n", __func__, mem_unmap.mem_handle);
+
+ v->mvm_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_mvm, (uint32_t *) &mem_unmap);
+ if (ret < 0) {
+ pr_err("mem_unmap op[0x%x]ret[%d]\n",
+ mem_unmap.hdr.opcode, ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->mvm_wait,
+ (v->mvm_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+ goto fail;
+ }
return 0;
fail:
+ return ret;
+}
+
+static int voice_send_cvs_packet_exchange_config_cmd(struct voice_data *v)
+{
+ struct vss_istream_cmd_set_oob_packet_exchange_config_t
+ packet_exchange_config_pkt;
+ int ret = 0;
+ uint64_t *dec_buf;
+ uint64_t *enc_buf;
+ void *apr_cvs;
+ u16 cvs_handle;
+ dec_buf = (uint64_t *)v->shmem_info.sh_buf.buf[0].phys;
+ enc_buf = (uint64_t *)v->shmem_info.sh_buf.buf[1].phys;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ packet_exchange_config_pkt.hdr.hdr_field = APR_HDR_FIELD(
+ APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ packet_exchange_config_pkt.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(packet_exchange_config_pkt) -
+ APR_HDR_SIZE);
+ packet_exchange_config_pkt.hdr.src_port = v->session_id;
+ packet_exchange_config_pkt.hdr.dest_port = cvs_handle;
+ packet_exchange_config_pkt.hdr.token = 0;
+ packet_exchange_config_pkt.hdr.opcode =
+ VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG;
+ packet_exchange_config_pkt.mem_handle = v->shmem_info.mem_handle;
+ packet_exchange_config_pkt.dec_buf_addr = (uint32_t)dec_buf;
+ packet_exchange_config_pkt.dec_buf_size = 4096;
+ packet_exchange_config_pkt.enc_buf_addr = (uint32_t)enc_buf;
+ packet_exchange_config_pkt.enc_buf_size = 4096;
+
+ pr_debug("%s: dec buf: add %p, size %d, enc buf: add %p, size %d\n",
+ __func__,
+ dec_buf,
+ packet_exchange_config_pkt.dec_buf_size,
+ enc_buf,
+ packet_exchange_config_pkt.enc_buf_size);
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &packet_exchange_config_pkt);
+ if (ret < 0) {
+ pr_err("Failed to send packet exchange config cmd %d\n", ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret)
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v)
+{
+ struct vss_istream_cmd_set_packet_exchange_mode_t data_exchange_pkt;
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ data_exchange_pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ data_exchange_pkt.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(data_exchange_pkt) - APR_HDR_SIZE);
+ data_exchange_pkt.hdr.src_port = v->session_id;
+ data_exchange_pkt.hdr.dest_port = cvs_handle;
+ data_exchange_pkt.hdr.token = 0;
+ data_exchange_pkt.hdr.opcode = VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE;
+ data_exchange_pkt.mode = VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &data_exchange_pkt);
+ if (ret < 0) {
+ pr_err("Failed to send data exchange mode %d\n", ret);
+ goto fail;
+ }
+
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret)
+ pr_err("%s: wait_event timeout %d\n", __func__, ret);
+
+ return 0;
+fail:
return -EINVAL;
}
@@ -1878,7 +2274,6 @@
return 0;
fail:
-
return ret;
}
@@ -2202,16 +2597,54 @@
pr_err("%s: set device failed\n", __func__);
goto fail;
}
- /* send tty mode if tty device is used */
- voice_send_tty_mode_cmd(v);
- v->voc_state = VOC_RUN;
+ ret = voice_send_enable_vocproc_cmd(v);
+ if (ret < 0) {
+ pr_err("%s: enable vocproc failed %d\n", __func__, ret);
+ goto fail;
+ }
+
+ /* Send tty mode if tty device is used */
+ voice_send_tty_mode_cmd(v);
+
+ v->voc_state = VOC_RUN;
}
fail:
mutex_unlock(&v->lock);
+ return ret;
+}
+
+static int voice_set_packet_exchange_mode_and_config(uint16_t session_id,
+ uint32_t mode)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+ return -EINVAL;
+ }
+
+ if (v->voc_state != VOC_RUN)
+ ret = voice_send_cvs_data_exchange_mode_cmd(v);
+
+ if (ret) {
+ pr_err("%s: Error voice_send_data_exchange_mode_cmd %d\n",
+ __func__, ret);
+ goto fail;
+ }
+
+ ret = voice_send_cvs_packet_exchange_config_cmd(v);
+ if (ret) {
+ pr_err("%s: Error: voice_send_packet_exchange_config_cmd %d\n",
+ __func__, ret);
+ goto fail;
+ }
return ret;
+fail:
+ return -EINVAL;
}
int voc_set_tx_mute(uint16_t session_id, uint32_t dir, uint32_t mute)
@@ -2552,6 +2985,22 @@
pr_err("create mvm and cvs failed\n");
goto fail;
}
+ if (is_voip_session(session_id)) {
+ ret = voice_send_mvm_map_memory_physical_cmd(v);
+ if (ret) {
+ pr_err("%s: mvm_map_memory_phy failed %d\n",
+ __func__, ret);
+ goto fail;
+ }
+ ret = voice_set_packet_exchange_mode_and_config(
+ session_id,
+ VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND);
+ if (ret) {
+ pr_err("%s: Err: exchange_mode_and_config %d\n",
+ __func__, ret);
+ goto fail;
+ }
+ }
ret = voice_send_dual_control_cmd(v);
if (ret < 0) {
pr_err("Err Dual command failed\n");
@@ -2570,7 +3019,8 @@
v->voc_state = VOC_RUN;
}
-fail: mutex_unlock(&v->lock);
+fail:
+ mutex_unlock(&v->lock);
return ret;
}
@@ -2638,6 +3088,7 @@
if (data->payload_size) {
ptr = data->payload;
+ pr_info("%x %x\n", ptr[0], ptr[1]);
/* ping mvm service ACK */
switch (ptr[0]) {
case VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
@@ -2666,6 +3117,9 @@
case VSS_ICOMMON_CMD_SET_VOICE_TIMING:
case VSS_IWIDEVOICE_CMD_SET_WIDEVOICE:
case VSS_IMVM_CMD_SET_POLICY_DUAL_CONTROL:
+ case VSS_IMVM_CMD_SET_CAL_NETWORK:
+ case VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE:
+ case VSS_IMEMORY_CMD_UNMAP:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
v->mvm_state = CMD_STATUS_SUCCESS;
wake_up(&v->mvm_wait);
@@ -2676,8 +3130,19 @@
break;
}
}
+ } else if (data->opcode == VSS_IMEMORY_RSP_MAP) {
+ pr_debug("%s, Revd VSS_IMEMORY_RSP_MAP response\n", __func__);
+ if (data->payload_size) {
+ ptr = data->payload;
+ if (ptr[0]) {
+ v->shmem_info.mem_handle = ptr[0];
+ pr_debug("%s: shared mem_handle: 0x[%x]\n",
+ __func__, v->shmem_info.mem_handle);
+ v->mvm_state = CMD_STATUS_SUCCESS;
+ wake_up(&v->mvm_wait);
+ }
+ }
}
-
return 0;
}
@@ -2725,6 +3190,7 @@
if (data->payload_size) {
ptr = data->payload;
+ pr_info("%x %x\n", ptr[0], ptr[1]);
/*response from CVS */
switch (ptr[0]) {
case VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION:
@@ -2754,6 +3220,8 @@
case VSS_ISTREAM_CMD_STOP_PLAYBACK:
case VSS_ISTREAM_CMD_START_RECORD:
case VSS_ISTREAM_CMD_STOP_RECORD:
+ case VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE:
+ case VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
v->cvs_state = CMD_STATUS_SUCCESS;
wake_up(&v->cvs_wait);
@@ -2765,63 +3233,117 @@
break;
}
}
- } else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
- uint32_t *voc_pkt = data->payload;
- uint32_t pkt_len = data->payload_size;
-
- if (voc_pkt != NULL && c->mvs_info.ul_cb != NULL) {
- pr_debug("%s: Media type is 0x%x\n",
- __func__, voc_pkt[0]);
-
- /* Remove media ID from payload. */
- voc_pkt++;
- pkt_len = pkt_len - 4;
-
- c->mvs_info.ul_cb((uint8_t *)voc_pkt,
- pkt_len,
- c->mvs_info.private_data);
- } else
- pr_err("%s: voc_pkt is 0x%x ul_cb is 0x%x\n",
- __func__, (unsigned int)voc_pkt,
- (unsigned int) c->mvs_info.ul_cb);
- } else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
- struct cvs_send_dec_buf_cmd send_dec_buf;
+ } else if (data->opcode ==
+ VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_READY) {
int ret = 0;
- uint32_t pkt_len = 0;
+ u16 cvs_handle;
+ uint32_t *cvs_voc_pkt;
+ struct cvs_enc_buffer_consumed_cmd send_enc_buf_consumed_cmd;
+ void *apr_cvs;
- if (c->mvs_info.dl_cb != NULL) {
- send_dec_buf.dec_buf.media_id = c->mvs_info.media_type;
+ pr_debug("Encoder buffer is ready\n");
- c->mvs_info.dl_cb(
- (uint8_t *)&send_dec_buf.dec_buf.packet_data,
- &pkt_len,
- c->mvs_info.private_data);
+ apr_cvs = common.apr_q6_cvs;
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
- send_dec_buf.hdr.hdr_field =
- APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(send_dec_buf.dec_buf.media_id) + pkt_len);
- send_dec_buf.hdr.src_port = v->session_id;
- send_dec_buf.hdr.dest_port = voice_get_cvs_handle(v);
- send_dec_buf.hdr.token = 0;
- send_dec_buf.hdr.opcode =
- VSS_ISTREAM_EVT_SEND_DEC_BUFFER;
+ send_enc_buf_consumed_cmd.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ send_enc_buf_consumed_cmd.hdr.pkt_size =
+ APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(send_enc_buf_consumed_cmd) - APR_HDR_SIZE);
- ret = apr_send_pkt(c->apr_q6_cvs,
- (uint32_t *) &send_dec_buf);
+ send_enc_buf_consumed_cmd.hdr.src_port = v->session_id;
+ send_enc_buf_consumed_cmd.hdr.dest_port = cvs_handle;
+ send_enc_buf_consumed_cmd.hdr.token = 0;
+ send_enc_buf_consumed_cmd.hdr.opcode =
+ VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_CONSUMED;
+
+ cvs_voc_pkt = v->shmem_info.sh_buf.buf[1].data;
+ if (cvs_voc_pkt != NULL && common.mvs_info.ul_cb != NULL) {
+ common.mvs_info.ul_cb((uint8_t *)&cvs_voc_pkt[3],
+ cvs_voc_pkt[2],
+ common.mvs_info.private_data);
+ } else
+ pr_err("%s: cvs_voc_pkt or ul_cb is NULL\n", __func__);
+
+ ret = apr_send_pkt(apr_cvs,
+ (uint32_t *) &send_enc_buf_consumed_cmd);
+ if (ret < 0) {
+ pr_err("%s: Err send ENC_BUF_CONSUMED_NOTIFY %d\n",
+ __func__, ret);
+ goto fail;
+ }
+ } else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
+ pr_debug("Recd VSS_ISTREAM_EVT_SEND_ENC_BUFFER\n");
+ } else if (data->opcode ==
+ VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_REQUEST) {
+ int ret = 0;
+ u16 cvs_handle;
+ uint32_t *cvs_voc_pkt;
+ struct cvs_dec_buffer_ready_cmd send_dec_buf;
+ void *apr_cvs;
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL\n", __func__);
+ return -EINVAL;
+ }
+ cvs_handle = voice_get_cvs_handle(v);
+
+ send_dec_buf.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+
+ send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(send_dec_buf) - APR_HDR_SIZE);
+
+ send_dec_buf.hdr.src_port = v->session_id;
+ send_dec_buf.hdr.dest_port = cvs_handle;
+ send_dec_buf.hdr.token = 0;
+ send_dec_buf.hdr.opcode =
+ VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_READY;
+
+ cvs_voc_pkt = (uint32_t *)(v->shmem_info.sh_buf.buf[0].data);
+ if (cvs_voc_pkt != NULL && common.mvs_info.dl_cb != NULL) {
+ /* Set timestamp to 0 and advance the pointer */
+ cvs_voc_pkt[0] = 0;
+ /* Set media_type and advance the pointer */
+ cvs_voc_pkt[1] = common.mvs_info.media_type;
+ common.mvs_info.dl_cb(
+ (uint8_t *)&cvs_voc_pkt[2],
+ common.mvs_info.private_data);
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &send_dec_buf);
if (ret < 0) {
- pr_err("%s: Error %d sending DEC_BUF\n",
- __func__, ret);
+ pr_err("%s: Err send DEC_BUF_READY_NOTIFI %d\n",
+ __func__, ret);
goto fail;
}
- } else
- pr_debug("%s: dl_cb is NULL\n", __func__);
+ } else {
+ pr_debug("%s: voc_pkt or dl_cb is NULL\n", __func__);
+ goto fail;
+ }
+ } else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
+ pr_debug("Recd VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER\n");
} else if (data->opcode == VSS_ISTREAM_EVT_SEND_DEC_BUFFER) {
pr_debug("Send dec buf resp\n");
+ } else if (data->opcode == APR_RSP_ACCEPTED) {
+ ptr = data->payload;
+ if (ptr[0])
+ pr_debug("%s: APR_RSP_ACCEPTED for 0x%x:\n",
+ __func__, ptr[0]);
+ } else if (data->opcode == VSS_ISTREAM_EVT_NOT_READY) {
+ pr_debug("Recd VSS_ISTREAM_EVT_NOT_READY\n");
+ } else if (data->opcode == VSS_ISTREAM_EVT_READY) {
+ pr_debug("Recd VSS_ISTREAM_EVT_READY\n");
} else
- pr_debug("Unknown opcode 0x%x\n", data->opcode);
+ pr_err("Unknown opcode 0x%x\n", data->opcode);
fail:
return 0;
@@ -2869,13 +3391,15 @@
if (data->payload_size) {
ptr = data->payload;
+ pr_info("%x %x\n", ptr[0], ptr[1]);
switch (ptr[0]) {
- case VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION:
+ case VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2:
/*response from CVP */
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
if (!ptr[1]) {
voice_set_cvp_handle(v, data->src_port);
- pr_debug("cvphdl=%d\n", data->src_port);
+ pr_debug("status: %d, cvphdl=%d\n",
+ ptr[1], data->src_port);
} else
pr_err("got NACK from CVP create session response\n");
v->cvp_state = CMD_STATUS_SUCCESS;
@@ -2908,6 +3432,137 @@
return 0;
}
+static int voice_alloc_oob_shared_mem(void)
+{
+ int cnt = 0;
+ int rc = 0;
+ int len;
+ void *mem_addr;
+ dma_addr_t phys;
+ int bufsz = BUFFER_BLOCK_SIZE;
+ int bufcnt = NUM_OF_BUFFERS;
+ struct voice_data *v = voice_get_session(
+ common.voice[VOC_PATH_FULL].session_id);
+
+ v->shmem_info.sh_buf.client = msm_ion_client_create(UINT_MAX,
+ "voip_client");
+ if (IS_ERR_OR_NULL((void *)v->shmem_info.sh_buf.client)) {
+ pr_err("%s: ION create client failed\n", __func__);
+ goto err;
+ }
+
+ v->shmem_info.sh_buf.handle = ion_alloc(v->shmem_info.sh_buf.client,
+ bufsz * bufcnt, SZ_4K,
+ (0x1 << ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL((void *)v->shmem_info.sh_buf.handle)) {
+ pr_err("%s: ION memory allocation failed\n",
+ __func__);
+ goto err_ion_client;
+ }
+
+ rc = ion_phys(v->shmem_info.sh_buf.client, v->shmem_info.sh_buf.handle,
+ (ion_phys_addr_t *)&phys, (size_t *)&len);
+ if (rc) {
+ pr_err("%s: ION Get Physical failed, rc = %d\n",
+ __func__, rc);
+ goto err_ion_handle;
+ }
+
+ mem_addr = ion_map_kernel(v->shmem_info.sh_buf.client,
+ v->shmem_info.sh_buf.handle);
+ if (IS_ERR_OR_NULL(mem_addr)) {
+ pr_err("%s: ION memory mapping failed\n", __func__);
+ goto err_ion_handle;
+ }
+
+ while (cnt < bufcnt) {
+ v->shmem_info.sh_buf.buf[cnt].data = mem_addr + (cnt * bufsz);
+ v->shmem_info.sh_buf.buf[cnt].phys = phys + (cnt * bufsz);
+ v->shmem_info.sh_buf.buf[cnt].size = bufsz;
+ cnt++;
+ }
+
+ pr_debug("%s buf[0].data:[%p], buf[0].phys:[%p], &buf[0].phys:[%p],\n",
+ __func__,
+ (void *)v->shmem_info.sh_buf.buf[0].data,
+ (void *)v->shmem_info.sh_buf.buf[0].phys,
+ (void *)&v->shmem_info.sh_buf.buf[0].phys);
+ pr_debug("%s: buf[1].data:[%p], buf[1].phys[%p], &buf[1].phys[%p]\n",
+ __func__,
+ (void *)v->shmem_info.sh_buf.buf[1].data,
+ (void *)v->shmem_info.sh_buf.buf[1].phys,
+ (void *)&v->shmem_info.sh_buf.buf[1].phys);
+
+ memset((void *)v->shmem_info.sh_buf.buf[0].data, 0, (bufsz * bufcnt));
+
+ return 0;
+
+err_ion_handle:
+ ion_free(v->shmem_info.sh_buf.client, v->shmem_info.sh_buf.handle);
+err_ion_client:
+ ion_client_destroy(v->shmem_info.sh_buf.client);
+err:
+ return -EINVAL;
+}
+
+static int voice_alloc_oob_mem_table(void)
+{
+ int rc = 0;
+ int len;
+ struct voice_data *v = voice_get_session(
+ common.voice[VOC_PATH_FULL].session_id);
+
+ v->shmem_info.memtbl.client = msm_ion_client_create(UINT_MAX,
+ "voip_client");
+ if (IS_ERR_OR_NULL((void *)v->shmem_info.memtbl.client)) {
+ pr_err("%s: ION create client for memtbl failed\n", __func__);
+ goto err;
+ }
+
+ v->shmem_info.memtbl.handle = ion_alloc(v->shmem_info.memtbl.client,
+ sizeof(struct vss_imemory_table_t), SZ_4K,
+ (0x1 << ION_AUDIO_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL((void *) v->shmem_info.memtbl.handle)) {
+ pr_err("%s: ION memory allocation for memtbl failed\n",
+ __func__);
+ goto err_ion_client;
+ }
+
+ rc = ion_phys(v->shmem_info.memtbl.client, v->shmem_info.memtbl.handle,
+ (ion_phys_addr_t *)&v->shmem_info.memtbl.phys, (size_t *)&len);
+ if (rc) {
+ pr_err("%s: ION Get Physical for memtbl failed, rc = %d\n",
+ __func__, rc);
+ goto err_ion_handle;
+ }
+
+ v->shmem_info.memtbl.data = ion_map_kernel(v->shmem_info.memtbl.client,
+ v->shmem_info.memtbl.handle);
+ if (IS_ERR_OR_NULL((void *)v->shmem_info.memtbl.data)) {
+ pr_err("%s: ION memory mapping for memtbl failed\n",
+ __func__);
+ goto err_ion_handle;
+ }
+
+ memset(v->shmem_info.memtbl.data, 0,
+ sizeof(struct vss_imemory_table_t));
+
+ v->shmem_info.memtbl.size = sizeof(struct vss_imemory_table_t);
+
+ pr_debug("%s data[%p]phys[%p][%p]\n", __func__,
+ (void *)v->shmem_info.memtbl.data,
+ (void *)v->shmem_info.memtbl.phys,
+ (void *)&v->shmem_info.memtbl.phys);
+
+ return 0;
+
+err_ion_handle:
+ ion_free(v->shmem_info.memtbl.client, v->shmem_info.memtbl.handle);
+err_ion_client:
+ ion_client_destroy(v->shmem_info.memtbl.client);
+err:
+ return -EINVAL;
+}
static int __init voice_init(void)
{
@@ -2946,6 +3601,17 @@
mutex_init(&common.voice[i].lock);
}
+ /* Allocate shared memory for OOB Voip */
+ rc = voice_alloc_oob_shared_mem();
+ if (rc < 0)
+ pr_err("failed to alloc shared memory for OOB %d\n", rc);
+ else {
+ /* Allocate mem map table for OOB */
+ rc = voice_alloc_oob_mem_table();
+ if (rc < 0)
+ pr_err("failed to alloc mem map talbe %d\n", rc);
+ }
+
return rc;
}
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 8bafe04..df0cbec 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -17,6 +17,13 @@
#define MAX_VOC_PKT_SIZE 642
#define SESSION_NAME_LEN 20
+#define NUM_OF_MEMORY_BLOCKS 1
+#define NUM_OF_BUFFERS 2
+/*
+ * BUFFER BLOCK SIZE based on
+ * the supported page size
+ */
+#define BUFFER_BLOCK_SIZE 4096
#define VOC_REC_UPLINK 0x00
#define VOC_REC_DOWNLINK 0x01
@@ -60,6 +67,26 @@
VOC_RELEASE,
};
+struct mem_buffer {
+ dma_addr_t phys;
+ void *data;
+ uint32_t size; /* size of buffer */
+};
+
+struct share_mem_buf {
+ struct ion_handle *handle;
+ struct ion_client *client;
+ struct mem_buffer buf[NUM_OF_BUFFERS];
+};
+
+struct mem_map_table {
+ dma_addr_t phys;
+ void *data;
+ uint32_t size; /* size of buffer */
+ struct ion_handle *handle;
+ struct ion_client *client;
+};
+
/* Common */
#define VSS_ICOMMON_CMD_SET_UI_PROPERTY 0x00011103
/* Set a UI property */
@@ -119,8 +146,6 @@
#define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION 0x000110FE
/* Create a new full control MVM session. */
-#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2 0x000112BF
-
#define APRV2_IBASIC_CMD_DESTROY_SESSION 0x0001003C
/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
@@ -165,6 +190,12 @@
#define VSS_IWIDEVOICE_CMD_SET_WIDEVOICE 0x00011243
/* Enable/disable WideVoice */
+#define VSS_IMEMORY_CMD_MAP_PHYSICAL 0x00011334
+#define VSS_IMEMORY_RSP_MAP 0x00011336
+#define VSS_IMEMORY_CMD_UNMAP 0x00011337
+#define VSS_IMVM_CMD_SET_CAL_NETWORK 0x0001137A
+#define VSS_IMVM_CMD_SET_CAL_MEDIA_TYPE 0x0001137B
+
enum msm_audio_voc_rate {
VOC_0_RATE, /* Blank frame */
VOC_8_RATE, /* 1/8 rate */
@@ -311,6 +342,92 @@
struct vss_iwidevoice_cmd_set_widevoice_t vss_set_wv;
} __packed;
+struct vss_imemory_table_descriptor_t {
+ uint64_t mem_address;
+ /*
+ * Base physical address of the table. The address must be aligned
+ * to LCM( cache_line_size, page_align, max_data_width ), where the
+ * attributes are specified in #VSS_IMEMORY_CMD_MAP_PHYSICAL, and
+ * LCM = Least Common Multiple. The table at the address must have
+ * the format specified by #vss_imemory_table_t.
+ */
+ uint32_t mem_size;
+ /* Size in bytes of the table. */
+} __packed;
+
+struct vss_imemory_block_t {
+ uint64_t mem_address;
+ /*
+ * Base address of the memory block. The address is virtual for virtual
+ * memory and physical for physical memory. The address must be aligned
+ * to LCM( cache_line_size, page_align, max_data_width ), where the
+ * attributes are specified in VSS_IMEMORY_CMD_MAP_VIRTUAL or
+ * VSS_IMEMORY_CMD_MAP_PHYSICAL, and LCM = Least Common Multiple.
+ */
+ uint32_t mem_size;
+ /*
+ * Size in bytes of the memory block. The size must be multiple of
+ * page_align, where page_align is specified in
+ * VSS_IMEMORY_CMD_MAP_VIRTUAL or #VSS_IMEMORY_CMD_MAP_PHYSICAL.
+ */
+} __packed;
+
+struct vss_imemory_table_t {
+ struct vss_imemory_table_descriptor_t next_table_descriptor;
+ /*
+ * Specifies the next table. If there is no next table,
+ * set the size of the table to 0 and the table address is ignored.
+ */
+ struct vss_imemory_block_t blocks[NUM_OF_MEMORY_BLOCKS];
+ /* Specifies one ore more memory blocks. */
+} __packed;
+
+struct vss_imemory_cmd_map_physical_t {
+ struct apr_hdr hdr;
+ struct vss_imemory_table_descriptor_t table_descriptor;
+ bool is_cached;
+ /*
+ * Indicates cached or uncached memory. Supported values:
+ * TRUE - Cached.
+ */
+ uint16_t cache_line_size;
+ /* Cache line size in bytes. Supported values: 128 */
+ uint32_t access_mask;
+ /*
+ * CVD's access permission to the memory while it is mapped.
+ * Supported values:
+ * bit 0 - If set, the memory is readable.
+ * bit 1 - If set, the memory is writable.
+ */
+ uint32_t page_align;
+ /* Page frame alignment in bytes. Supported values: 4096 */
+ uint8_t min_data_width;
+ /*
+ * Minimum native data type width in bits that can be accessed.
+ * Supported values: 8
+ */
+ uint8_t max_data_width;
+ /*
+ * Maximum native data type width in bits that can be accessed.
+ * Supported values: 64
+ */
+} __packed;
+
+struct vss_imvm_cmd_set_cal_network_t {
+ struct apr_hdr hdr;
+ uint32_t network_id;
+} __packed;
+
+struct vss_imvm_cmd_set_cal_media_type_t {
+ struct apr_hdr hdr;
+ uint32_t media_id;
+} __packed;
+
+struct vss_imemory_cmd_unmap_t {
+ struct apr_hdr hdr;
+ uint32_t mem_handle;
+} __packed;
+
/* TO CVS commands */
#define VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION 0x00011140
/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
@@ -337,6 +454,8 @@
* The client should respond with a VSS_ISTREAM_EVT_SEND_DEC_BUFFER event.
*/
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_REQUEST 0x0001136E
+
#define VSS_ISTREAM_EVT_SEND_DEC_BUFFER 0x00011016
/* Event sent by the client to the stream in response to a
* VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER event, providing a decoder packet.
@@ -376,6 +495,29 @@
#define VSS_TAP_POINT_STREAM_END 0x00010F79
/* Indicates that specified path should be tapped at the end of the stream. */
+#define VSS_ISTREAM_EVT_NOT_READY 0x000110FD
+
+#define VSS_ISTREAM_EVT_READY 0x000110FC
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_DEC_BUFFER_READY 0x0001136F
+/*notify dsp that decoder buffer is ready*/
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_READY 0x0001136C
+/*dsp notifying client that encoder buffer is ready*/
+
+#define VSS_ISTREAM_EVT_OOB_NOTIFY_ENC_BUFFER_CONSUMED 0x0001136D
+/*notify dsp that encoder buffer is consumed*/
+
+#define VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG 0x0001136B
+
+#define VSS_ISTREAM_PACKET_EXCHANGE_MODE_INBAND 0
+/* In-band packet exchange mode. */
+
+#define VSS_ISTREAM_PACKET_EXCHANGE_MODE_OUT_OF_BAND 1
+/* Out-of-band packet exchange mode. */
+
+#define VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE 0x0001136A
+
struct vss_istream_cmd_start_record_t {
uint32_t rx_tap_point;
/* Tap point to use on the Rx path. Supported values are:
@@ -614,6 +756,28 @@
struct vss_istream_cmd_start_record_t rec_mode;
} __packed;
+struct cvs_dec_buffer_ready_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct cvs_enc_buffer_consumed_cmd {
+ struct apr_hdr hdr;
+} __packed;
+
+struct vss_istream_cmd_set_oob_packet_exchange_config_t {
+ struct apr_hdr hdr;
+ uint32_t mem_handle;
+ uint64_t enc_buf_addr;
+ uint32_t enc_buf_size;
+ uint64_t dec_buf_addr;
+ uint32_t dec_buf_size;
+} __packed;
+
+struct vss_istream_cmd_set_packet_exchange_mode_t {
+ struct apr_hdr hdr;
+ uint32_t mode;
+} __packed;
+
/* TO CVP commands */
#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION 0x000100C3
@@ -646,6 +810,17 @@
#define VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT 0x00010F77
/* Newtwork IDs */
+#define VSS_ICOMMON_CAL_NETWORK_ID_NONE 0x0001135E
+
+/* Select internal mixing mode. */
+#define VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING 0x00010F7C
+
+/* Select external mixing mode. */
+#define VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING 0x00010F7D
+
+/* Default AFE port ID. Applicable to Tx and Rx. */
+#define VSS_IVOCPROC_PORT_ID_NONE 0xFFFF
+
#define VSS_NETWORK_ID_DEFAULT 0x00010037
#define VSS_NETWORK_ID_VOIP_NB 0x00011240
#define VSS_NETWORK_ID_VOIP_WB 0x00011241
@@ -678,73 +853,92 @@
#define VOICE_CMD_GET_PARAM 0x00011007
#define VOICE_EVT_GET_PARAM_ACK 0x00011008
-struct vss_ivocproc_cmd_create_full_control_session_t {
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION_V2 0x000112BF
+
+struct vss_ivocproc_cmd_create_full_control_session_v2_t {
uint16_t direction;
/*
- * stream direction.
- * 0 : TX only
- * 1 : RX only
- * 2 : TX and RX
+ * Vocproc direction. The supported values:
+ * VSS_IVOCPROC_DIRECTION_RX
+ * VSS_IVOCPROC_DIRECTION_TX
+ * VSS_IVOCPROC_DIRECTION_RX_TX
*/
- uint32_t tx_port_id;
+ uint16_t tx_port_id;
/*
- * TX device port ID which vocproc will connect to. If not supplying a
- * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+ * Tx device port ID to which the vocproc connects. If a port ID is
+ * not being supplied, set this to #VSS_IVOCPROC_PORT_ID_NONE.
*/
uint32_t tx_topology_id;
/*
- * Tx leg topology ID. If not supplying a topology ID set to
- * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+ * Tx path topology ID. If a topology ID is not being supplied, set
+ * this to #VSS_IVOCPROC_TOPOLOGY_ID_NONE.
*/
- uint32_t rx_port_id;
+ uint16_t rx_port_id;
/*
- * RX device port ID which vocproc will connect to. If not supplying a
- * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+ * Rx device port ID to which the vocproc connects. If a port ID is
+ * not being supplied, set this to #VSS_IVOCPROC_PORT_ID_NONE.
*/
uint32_t rx_topology_id;
/*
- * Rx leg topology ID. If not supplying a topology ID set to
- * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+ * Rx path topology ID. If a topology ID is not being supplied, set
+ * this to #VSS_IVOCPROC_TOPOLOGY_ID_NONE.
*/
- int32_t network_id;
+ uint32_t profile_id;
+ /* Voice calibration profile ID. */
+ uint32_t vocproc_mode;
/*
- * Network ID. (Refer to VSS_NETWORK_ID_XXX). If not supplying a network
- * ID set to VSS_NETWORK_ID_DEFAULT.
+ * Vocproc mode. The supported values:
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_EXT_MIXING
+ */
+ uint16_t ec_ref_port_id;
+ /*
+ * Port ID to which the vocproc connects for receiving echo
+ * cancellation reference signal. If a port ID is not being supplied,
+ * set this to #VSS_IVOCPROC_PORT_ID_NONE. This parameter value is
+ * ignored when the vocproc_mode parameter is set to
+ * VSS_IVOCPROC_VOCPROC_MODE_EC_INT_MIXING.
+ */
+ char name[SESSION_NAME_LEN];
+ /*
+ * Session name string used to identify a session that can be shared
+ * with passive controllers (optional). The string size, including the
+ * NULL termination character, is limited to 31 characters.
*/
} __packed;
struct vss_ivocproc_cmd_set_volume_index_t {
uint16_t vol_index;
- /**<
- * Volume index utilized by the vocproc to index into the volume table
- * provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
- * volume on the VDSP.
- */
+ /*
+ * Volume index utilized by the vocproc to index into the volume table
+ * provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
+ * volume on the VDSP.
+ */
} __packed;
struct vss_ivocproc_cmd_set_device_t {
uint32_t tx_port_id;
- /**<
- * TX device port ID which vocproc will connect to.
- * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
- */
+ /*
+ * TX device port ID which vocproc will connect to.
+ * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+ */
uint32_t tx_topology_id;
- /**<
- * TX leg topology ID.
- * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
- * pre/post-processing blocks and is pass-through.
- */
+ /*
+ * TX leg topology ID.
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+ * pre/post-processing blocks and is pass-through.
+ */
int32_t rx_port_id;
- /**<
- * RX device port ID which vocproc will connect to.
- * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
- */
+ /*
+ * RX device port ID which vocproc will connect to.
+ * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+ */
uint32_t rx_topology_id;
- /**<
- * RX leg topology ID.
- * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
- * pre/post-processing blocks and is pass-through.
- */
+ /*
+ * RX leg topology ID.
+ * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+ * pre/post-processing blocks and is pass-through.
+ */
} __packed;
struct vss_ivocproc_cmd_register_calibration_data_t {
@@ -784,7 +978,7 @@
struct cvp_create_full_ctl_session_cmd {
struct apr_hdr hdr;
- struct vss_ivocproc_cmd_create_full_control_session_t cvp_session;
+ struct vss_ivocproc_cmd_create_full_control_session_v2_t cvp_session;
} __packed;
struct cvp_command {
@@ -835,7 +1029,6 @@
/* CB for down-link packets. */
typedef void (*dl_cb_fn)(uint8_t *voc_pkt,
- uint32_t *pkt_len,
void *private_data);
@@ -862,9 +1055,18 @@
int force;
};
+struct share_memory_info {
+ u32 mem_handle;
+ struct share_mem_buf sh_buf;
+ struct mem_map_table memtbl;
+};
+
struct voice_data {
int voc_state;/*INIT, CHANGE, RELEASE, RUN */
+ /* Shared mem to store decoder and encoder packets */
+ struct share_memory_info shmem_info;
+
wait_queue_head_t mvm_wait;
wait_queue_head_t cvs_wait;
wait_queue_head_t cvp_wait;
@@ -959,7 +1161,8 @@
};
/* called by alsa driver */
-int voc_set_pp_enable(uint16_t session_id, uint32_t module_id, uint32_t enable);
+int voc_set_pp_enable(uint16_t session_id, uint32_t module_id,
+ uint32_t enable);
int voc_get_pp_enable(uint16_t session_id, uint32_t module_id);
int voc_set_widevoice_enable(uint16_t session_id, uint32_t wv_enable);
uint32_t voc_get_widevoice_enable(uint16_t session_id);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 2d2b333..4c6a5a4 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -308,7 +308,7 @@
{
static char buf[32];
- if (type == PERF_TYPE_RAW) {
+ if (!pmu_name && type == PERF_TYPE_RAW) {
sprintf(buf, "raw 0x%" PRIx64, config);
return buf;
}
@@ -684,6 +684,7 @@
{
struct perf_event_attr attr;
struct perf_pmu *pmu;
+ char *ev_name;
pmu = perf_pmu__find(name);
if (!pmu)
@@ -700,7 +701,9 @@
if (perf_pmu__config(pmu, &attr, head_config))
return -EINVAL;
- return add_event(list, idx, &attr, pmu->name);
+ ev_name = (char *) __event_name(attr.type, attr.config, pmu->name);
+
+ return add_event(list, idx, &attr, ev_name);
}
void parse_events_update_lists(struct list_head *list_event,