Merge "msm: kgsl: Change an overflow check to be "smart" compiler proof"
diff --git a/Documentation/bif-framework.txt b/Documentation/bif-framework.txt
index 3ba500d..9831c80 100644
--- a/Documentation/bif-framework.txt
+++ b/Documentation/bif-framework.txt
@@ -235,10 +235,10 @@
Get/put handle for a BIF slave:
-------------------------------
-int bif_slave_match_count(const struct bif_ctrl *ctrl,
+int bif_slave_match_count(struct bif_ctrl *ctrl,
const struct bif_match_criteria *match_criteria);
-struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+struct bif_slave *bif_slave_match_get(struct bif_ctrl *ctrl,
unsigned int id, const struct bif_match_criteria *match_criteria);
void bif_slave_put(struct bif_slave *slave);
@@ -293,7 +293,6 @@
int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
struct notifier_block *nb);
-
Read or write BIF slave registers:
----------------------------------
@@ -302,6 +301,53 @@
int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf, int len);
+BIF slave non-volatile memory manipulation:
+-------------------------------------------
+
+int bif_slave_nvm_raw_read(struct bif_slave *slave, u16 offset, u8 *buf,
+ int len);
+
+int bif_slave_nvm_raw_write(struct bif_slave *slave, u16 offset, u8 *buf,
+ int len);
+
+Raw NVM writing may be needed in order to intialize the NVM BIF object list.
+However, its use can be dangerous as it can overwrite existing objects in the
+list and make the list unparsable.
+
+BIF object search in slave non-volatile memory:
+-----------------------------------------------
+int bif_object_match_count(struct bif_slave *slave,
+ const struct bif_obj_match_criteria *match_criteria);
+
+struct bif_object *bif_object_match_get(struct bif_slave *slave,
+ unsigned int id, const struct bif_obj_match_criteria *match_criteria);
+
+void bif_object_put(struct bif_object *object);
+
+bif_object_match_count() and bif_object_match_get() can be used together in
+order to retrieve the set of BIF objects within a slave which match certain
+criteria. bif_object_put() is used to free the memory allocated by
+bif_object_match_get().
+
+BIF object manipulation in slave non-volatile memory:
+-----------------------------------------------------
+int bif_object_write(struct bif_slave *slave, u8 type, u8 version, u16
+ manufacturer_id, const u8 *data, int data_len);
+
+int bif_object_overwrite(struct bif_slave *slave,
+ struct bif_object *object, u8 type, u8 version,
+ u16 manufacturer_id, const u8 *data, int data_len);
+
+int bif_object_delete(struct bif_slave *slave, const struct bif_object *object);
+
+bif_object_write() can be used to write a new BIF data object into the NVM of
+a given slave. The new object is added to the end of the NVM object list.
+bif_object_overwrite() can be used to overwrite an existing BIF data object
+in the NVM of a slave. The new object data must be the same size as the
+existing object data. bif_object_delete() can be used to delete a object from
+the NVM object list and shift all of the objects after it in order to fill the
+deleted object's space.
+
Get or set the BIF bus state or period:
---------------------------------------
@@ -341,11 +387,17 @@
int bif_task_is_busy(struct bif_slave *slave, unsigned int task);
+int bif_enable_auto_task(struct bif_slave *slave, unsigned int task);
+
+int bif_disable_auto_task(struct bif_slave *slave, unsigned int task);
+
A consumer can request a slave interrupt and specify a notifier to call when the
interrupt is triggered. Once the interrupt is requested the consumer will need
to call bif_trigger_task() in order to start the task associated with the
interrupt (both are identified by the same index). Polling for task completion
-is also supported via the bif_task_is_busy() function.
+is also supported via the bif_task_is_busy() function. Auto task triggered can
+be enabled and disabled for a given task using bif_enable_auto_task() and
+bif_disable_auto_task() respectively.
Raw BIF bus transactions:
-------------------------
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 17ff3f0..737e262 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -22,10 +22,24 @@
"arm,coresight-cti" for coresight cti devices,
"qcom,coresight-hwevent" for coresight hardware event devices
"arm,coresight-fuse" for coresight fuse device,
-- reg : physical base address and length of the register set(s) of the component
-- reg-names : names corresponding to each reg property value. The reg-names that
- need to be used with corresponding compatible string for a coresight device
- are:
+ "qcom,coresight-audio-etm" for coresight audio etm trace device,
+ "qcom,coresight-modem-etm" for coresight modem etm trace device,
+ "qcom,coresight-wcn-etm" for coresight wireless etm trace device,
+ "qcom,coresight-rpm-etm" for coresight rpm etm trace device
+- reg : physical base address and length of the register set(s) of the component.
+ Not required for the following compatible strings:
+ - "qcom,coresight-audio-etm",
+ - "qcom,coresight-modem-etm",
+ - "qcom,coresight-wcn-etm",
+ - "qcom,coresight-rpm-etm"
+- reg-names : names corresponding to each reg property value.
+ Not required for the following compatible strings:
+ - "qcom,coresight-audio-etm",
+ - "qcom,coresight-modem-etm",
+ - "qcom,coresight-wcn-etm",
+ - "qcom,coresight-rpm-etm"
+ The reg-names that need to be used with corresponding compatible string
+ for a coresight device are:
- for coresight tmc-etr or tmc-etf device:
compatible : should be "arm,coresight-tmc"
reg-names : should be:
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index bf30879..8f17a90 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -107,6 +107,7 @@
Optional properties:
- vdd-cx-supply : Phandle for vdd CX regulator device node.
+- batfet-supply : Phandle for battery FET regulator device node.
- qcom,vbif-settings : Array with key-value pairs of constant VBIF register
settings used to setup MDSS QoS for optimum performance.
The key used should be offset from "vbif_phys" register
@@ -179,6 +180,7 @@
interrupts = <0 72 0>;
vdd-supply = <&gdsc_mdss>;
vdd-cx-supply = <&pm8841_s2_corner>;
+ batfet-supply = <&pm8941_chg_batif>;
qcom,max-clk-rate = <320000000>;
qcom,vbif-settings = <0x0004 0x00000001>,
<0x00D8 0x00000707>;
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
index c7c6415..cf21158 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
@@ -14,6 +14,7 @@
- qcom,needs-alt-core-clk : boolean to enable the secondary core clock for
access to the IOMMU configuration registers
- Bus scaling properties: See msm_bus.txt
+- qcom,msm-enable-remote-spinlock : boolean to enable use of remote spinlock
- List of sub nodes, one for each of the translation context banks supported.
Required properties for each sub-node:
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 81448d2..5425c92 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -37,6 +37,9 @@
- qcom,maxinput-usb-ma: Maximum input current USB.
- qcom,maxinput-dc-ma: Maximum input current DC.
- qcom,vbatdet-delta-mv: Battery charging resume delta.
+- qcom,vbatweak-mv: Weak battery voltage threshold in mV, above which
+ fast charging can start. The supported voltage range is
+ from 2100mV to 3600mV with a step size of 100mV.
- qcom,charging-disabled: Set this property to disable charging
by default. This can then be overriden
writing the the module parameter
@@ -204,6 +207,7 @@
qcom,ibatmax-ma = <1500>;
qcom,ibatterm-ma = <200>;
qcom,ibatsafe-ma = <1500>;
+ qcom,vbatweak-mv = <3200>;
qcom,thermal-mitigation = <1500 700 600 325>;
qcom,cool-bat-degc = <10>;
qcom,cool-bat-mv = <4100>;
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 21a42d2..adcf168 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -222,7 +222,8 @@
default DRAM_BASE if REMAP_VECTORS_TO_RAM
default 0x00000000
help
- The base address of exception vectors.
+ The base address of exception vectors. This must be two pages
+ in size.
config ARM_PATCH_PHYS_VIRT
bool "Patch physical to virtual translations at runtime" if EMBEDDED
@@ -1852,36 +1853,13 @@
config ENABLE_DMM
def_bool n
-choice
- prompt "Virtual Memory Reclaim"
- default NO_VM_RECLAIM
- help
- Select the method of reclaiming virtual memory
-
config DONT_MAP_HOLE_AFTER_MEMBANK0
- bool "Map around the largest hole"
- help
- Do not map the memory belonging to the largest hole
- into the virtual space. This results in more lowmem.
- If multiple holes are present, only the largest hole
- in the first 256MB of memory is not mapped.
+ def_bool n
+ depends on ENABLE_VMALLOC_SAVING=n
config ENABLE_VMALLOC_SAVING
- bool "Reclaim memory for each subsystem"
- help
- Enable this config to reclaim the virtual space belonging
- to any subsystem which is expected to have a lifetime of
- the entire system. This feature allows lowmem to be non-
- contiguous.
-
-config NO_VM_RECLAIM
- bool "Do not reclaim memory"
- help
- Do not reclaim any memory. This might result in less lowmem
- and wasting virtual memory space which could otherwise be
- reclaimed by using any of the other two config options.
-
-endchoice
+ def_bool n
+ depends on DONT_MAP_HOLE_AFTER_MEMBANK0=n
config HOLES_IN_ZONE
def_bool n
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 60bb518..8afd986 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -23,9 +23,12 @@
status = "ok";
};
- qcom,mdss_dsi_sharp_qhd_video {
- status = "ok";
- qcom,cont-splash-enabled;
+ qcom,mdss_dsi@fd922800 {
+ qcom,dsi-pref-prim-pan = <&dsi_sharp_qhd_vid>;
+ };
+
+ qcom,mdss_mdp@fd900000 {
+ qcom,mdss-pref-prim-intf = "dsi";
};
qcom,hdmi_tx@fd922100 {
@@ -670,3 +673,7 @@
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
status = "ok";
};
+
+&dsi_sharp_qhd_vid {
+ qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 8ab9985..8891935 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -33,6 +33,7 @@
qcom,msm-bus,vectors-KBps =
<11 512 0 0>,
<11 512 0 1000>;
+ qcom,msm-enable-remote-spinlock;
status = "disabled";
lpass_q6_fw: qcom,iommu-ctx@fd000000 {
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 6969940..8523524 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -113,7 +113,7 @@
"vdd-loop";
};
- qcom,bat-if@1200 {
+ pm8110_chg_batif: qcom,bat-if@1200 {
status = "disabled";
reg = <0x1200 0x100>;
interrupts = <0x0 0x12 0x0>,
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index ba1bf08..5e0abea 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -131,7 +131,7 @@
"vdd-loop";
};
- qcom,bat-if@1200 {
+ pm8226_chg_batif: qcom,bat-if@1200 {
status = "disabled";
reg = <0x1200 0x100>;
interrupts = <0x0 0x12 0x0>,
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 98d2f5e..8a239cc 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -250,7 +250,7 @@
"vdd-loop";
};
- qcom,bat-if@1200 {
+ pm8941_chg_batif: qcom,bat-if@1200 {
status = "disabled";
reg = <0x1200 0x100>;
interrupts = <0x0 0x12 0x0>,
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 838592c..23a2158 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -491,6 +491,10 @@
otg-parent-supply = <&pm8226_chg_boost>;
};
+&pm8226_chg_batif {
+ regulator-name = "batfet";
+};
+
&pm8226_chg_otg {
regulator-name = "8226_smbbp_otg";
};
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index 6b72e66..c6e81d8 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -56,8 +56,8 @@
qcom,ws = <10000>;
qcom,qport = <2>;
qcom,mas-hw-id = <11>;
- qcom,prio1 = <2>;
- qcom,prio0 = <2>;
+ qcom,prio1 = <3>;
+ qcom,prio0 = <3>;
};
mas-mdpe {
@@ -71,8 +71,8 @@
qcom,ws = <10000>;
qcom,qport = <7>;
qcom,mas-hw-id = <11>;
- qcom,prio1 = <2>;
- qcom,prio0 = <2>;
+ qcom,prio1 = <1>;
+ qcom,prio0 = <1>;
};
fab-bimc {
@@ -913,7 +913,7 @@
qcom,fabclk-dual = "mem_clk";
qcom,fabclk-active = "mem_a_clk";
qcom,ntieredslaves = <0>;
- qcom,qos-freq = <4800>;
+ qcom,qos-freq = <19200>;
qcom,hw-sel = "BIMC";
qcom,rpm-en;
@@ -930,13 +930,19 @@
qcom,masterp = <0>;
qcom,tier = <2>;
qcom,hw-sel = "BIMC";
- qcom,mode = "Fixed";
+ qcom,mode = "Limiter";
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <0>;
qcom,prio-rd = <0>;
qcom,prio-wr = <0>;
qcom,prio-lvl = <0>;
+ qcom,mode-thresh = "Fixed";
+ qcom,thresh = <800000>;
+ qcom,dual-conf;
+ qcom,bimc,bw = <300000>;
+ qcom,bimc,gp = <5>;
+ qcom,bimc,thmp = <50>;
};
mas-mss-proc {
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index 17bf329..2fe6a34 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -44,6 +44,40 @@
focaltech,no-force-update;
focaltech,i2c-pull-up;
};
+ goodix@5d {
+ compatible = "goodix,gt9xx";
+ reg = <0x5d>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2008>;
+ reset-gpios = <&msmgpio 0 0x00>;
+ interrupt-gpios = <&msmgpio 1 0x00>;
+ vdd-supply = <&pm8110_l19>;
+ vcc-i2c-supply = <&pm8110_l14>;
+ goodix,panel-coords = <0 0 540 980>;
+ goodix,display-coords = <0 0 540 960>;
+ goodix,button-map= <139 102 158>;
+ goodix,product-id = "915";
+ goodix,cfg-data0 = [
+ 46 1C 02 C0 03 0A 05 11 01 08
+ 14 3B 46 32 03 05 00 00 00 00
+ 00 00 00 00 00 00 00 8A 09 0B
+ 39 00 99 0A 00 00 02 83 03 1D
+ 00 08 00 00 00 00 00 00 00 00
+ 00 1D 73 94 C5 02 07 00 00 04
+ 78 21 00 5C 2C 00 48 3A 00 3A
+ 4C 00 2F 65 00 30 10 30 50 00
+ 56 45 35 FF FF 17 00 00 00 00
+ 00 01 1C 15 0C 14 5F 03 02 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 16 14 12 10 0E 0C 0A 08
+ 06 04 02 FF FF FF 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 22 21 20 1F 1E 1D 1C 18
+ 16 12 10 0F 0C 0A 08 06 04 02
+ 00 FF FF FF FF FF FF FF 00 00
+ 00 FF FF FF FF FF FF FF FF FF
+ F8 FF FF FF E4 01];
+ };
};
gen-vkeys {
compatible = "qcom,gen-vkeys";
@@ -55,6 +89,7 @@
qcom,key-codes = <139 102 158>;
qcom,y-offset = <0>;
};
+
i2c@f9925000 {
fsl@1c {
compatible = "fsl,mma8x5x";
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index eb69678..f97d991 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -391,3 +391,7 @@
};
};
};
+
+&pm8110_chg_batif {
+ regulator-name = "batfet";
+};
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index e9b7b0b..bbddec3 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -49,6 +49,50 @@
qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor5",
"tsens_tz_sensor1", "tsens_tz_sensor1";
};
+
+ qcom,mpm@fc4281d0 {
+ qcom,gpio-map = <3 1>,
+ <4 4 >,
+ <5 5 >,
+ <6 9 >,
+ <7 13>,
+ <8 17>,
+ <9 21>,
+ <10 27>,
+ <11 29>,
+ <12 31>,
+ <13 33>,
+ <14 35>,
+ <15 37>,
+ <16 38>,
+ <17 39>,
+ <18 41>,
+ <19 46>,
+ <20 48>,
+ <21 49>,
+ <22 50>,
+ <23 51>,
+ <24 52>,
+ <25 54>,
+ <26 62>,
+ <27 63>,
+ <28 64>,
+ <29 65>,
+ <30 66>,
+ <31 67>,
+ <32 68>,
+ <33 69>,
+ <34 71>,
+ <35 72>,
+ <36 106>,
+ <37 107>,
+ <38 108>,
+ <39 109>,
+ <40 110>,
+ <41 119>,
+ <54 111>,
+ <55 113>;
+ };
};
&pm8226_l3 {
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index a88a709..344c26f 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -560,6 +560,10 @@
regulator-name = "8941_smbb_boost";
};
+&pm8941_chg_batif {
+ regulator-name = "batfet";
+};
+
&pm8941_chg_otg {
regulator-name = "8941_smbb_otg";
};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-cdp.dts b/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
deleted file mode 100644
index 646eb56..0000000
--- a/arch/arm/boot/dts/msm8974pro-ab-cdp.dts
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/dts-v1/;
-
-/include/ "msm8974pro-ab.dtsi"
-/include/ "msm8974-cdp.dtsi"
-
-/ {
- model = "Qualcomm MSM 8974Pro CDP";
- compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
- qcom,msm-id = <208 1 0x10000>,
- <209 1 0x10000>,
- <211 1 0x10000>,
- <212 1 0x10000>,
- <214 1 0x10000>,
- <215 1 0x10000>,
- <217 1 0x10000>,
- <218 1 0x10000>,
- <194 1 0x10000>, /* 8974Pro-AC IDs */
- <210 1 0x10000>,
- <213 1 0x10000>,
- <216 1 0x10000>;
-};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
similarity index 61%
copy from arch/arm/boot/dts/msm8974pro-ab-fluid.dts
copy to arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
index 9a31834..b6a6fcb 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
@@ -12,17 +12,11 @@
/dts-v1/;
-/include/ "msm8974pro-ab.dtsi"
-/include/ "msm8974-fluid.dtsi"
+/include/ "msm8974pro-ab-pm8941.dtsi"
+/include/ "msm8974-cdp.dtsi"
/ {
- model = "Qualcomm MSM 8974Pro FLUID";
- compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
- qcom,msm-id = <209 3 0x10000>,
- <211 3 0x10000>,
- <212 3 0x10000>,
- <214 3 0x10000>,
- <215 3 0x10000>,
- <217 3 0x10000>,
- <218 3 0x10000>;
+ model = "Qualcomm MSM 8974Pro-AA/AB CDP";
+ compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
+ qcom,board-id = <1 0>;
};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
similarity index 71%
rename from arch/arm/boot/dts/msm8974pro-ab-fluid.dts
rename to arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
index 9a31834..be298d1 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
@@ -12,17 +12,11 @@
/dts-v1/;
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ab-pm8941.dtsi"
/include/ "msm8974-fluid.dtsi"
/ {
- model = "Qualcomm MSM 8974Pro FLUID";
+ model = "Qualcomm MSM 8974Pro-AA/AB FLUID";
compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
- qcom,msm-id = <209 3 0x10000>,
- <211 3 0x10000>,
- <212 3 0x10000>,
- <214 3 0x10000>,
- <215 3 0x10000>,
- <217 3 0x10000>,
- <218 3 0x10000>;
+ qcom,board-id = <3 0>;
};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-liquid.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
similarity index 71%
copy from arch/arm/boot/dts/msm8974pro-ab-liquid.dts
copy to arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
index 0ec9d8a..49c3df0 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-liquid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
@@ -12,17 +12,11 @@
/dts-v1/;
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ab-pm8941.dtsi"
/include/ "msm8974-liquid.dtsi"
/ {
- model = "Qualcomm MSM 8974Pro LIQUID";
+ model = "Qualcomm MSM 8974Pro-AA/AB LIQUID";
compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
- qcom,msm-id = <209 9 0x10000>,
- <211 9 0x10000>,
- <212 9 0x10000>,
- <214 9 0x10000>,
- <215 9 0x10000>,
- <217 9 0x10000>,
- <218 9 0x10000>;
+ qcom,board-id = <9 0>;
};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
similarity index 73%
rename from arch/arm/boot/dts/msm8974pro-ab-mtp.dts
rename to arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index f61b4a6..fa313bf 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
@@ -12,19 +12,13 @@
/dts-v1/;
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ab-pm8941.dtsi"
/include/ "msm8974-mtp.dtsi"
/ {
- model = "Qualcomm MSM 8974Pro MTP";
+ model = "Qualcomm MSM 8974Pro-AA/AB MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
- qcom,msm-id = <209 8 0x10000>,
- <211 8 0x10000>,
- <212 8 0x10000>,
- <214 8 0x10000>,
- <215 8 0x10000>,
- <217 8 0x10000>,
- <218 8 0x10000>;
+ qcom,board-id = <8 0>;
};
&sdhc_1 {
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
new file mode 100644
index 0000000..a44bc56
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941.dtsi
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "msm8974pro-pm8941.dtsi"
+
+/ {
+ qcom,msm-id = <208 0x10000>,
+ <209 0x10000>,
+ <211 0x10000>,
+ <212 0x10000>,
+ <214 0x10000>,
+ <215 0x10000>,
+ <217 0x10000>,
+ <218 0x10000>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
similarity index 61%
copy from arch/arm/boot/dts/msm8974pro-ab-fluid.dts
copy to arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
index 9a31834..3e0feda 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-fluid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
@@ -12,17 +12,11 @@
/dts-v1/;
-/include/ "msm8974pro-ab.dtsi"
-/include/ "msm8974-fluid.dtsi"
+/include/ "msm8974pro-ac-pm8941.dtsi"
+/include/ "msm8974-cdp.dtsi"
/ {
- model = "Qualcomm MSM 8974Pro FLUID";
- compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
- qcom,msm-id = <209 3 0x10000>,
- <211 3 0x10000>,
- <212 3 0x10000>,
- <214 3 0x10000>,
- <215 3 0x10000>,
- <217 3 0x10000>,
- <218 3 0x10000>;
+ model = "Qualcomm MSM 8974Pro-AC CDP";
+ compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
+ qcom,board-id = <1 0>;
};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-liquid.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
similarity index 71%
rename from arch/arm/boot/dts/msm8974pro-ab-liquid.dts
rename to arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
index 0ec9d8a..7b88abe 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-liquid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
@@ -12,17 +12,11 @@
/dts-v1/;
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ac-pm8941.dtsi"
/include/ "msm8974-liquid.dtsi"
/ {
- model = "Qualcomm MSM 8974Pro LIQUID";
+ model = "Qualcomm MSM 8974Pro-AC LIQUID";
compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
- qcom,msm-id = <209 9 0x10000>,
- <211 9 0x10000>,
- <212 9 0x10000>,
- <214 9 0x10000>,
- <215 9 0x10000>,
- <217 9 0x10000>,
- <218 9 0x10000>;
+ qcom,board-id = <9 0>;
};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
similarity index 61%
copy from arch/arm/boot/dts/msm8974pro-ab-mtp.dts
copy to arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
index f61b4a6..f79d361 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
@@ -12,21 +12,19 @@
/dts-v1/;
-/include/ "msm8974pro-ab.dtsi"
+/include/ "msm8974pro-ac-pm8941.dtsi"
/include/ "msm8974-mtp.dtsi"
/ {
- model = "Qualcomm MSM 8974Pro MTP";
+ model = "Qualcomm MSM 8974Pro-AC MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
- qcom,msm-id = <209 8 0x10000>,
- <211 8 0x10000>,
- <212 8 0x10000>,
- <214 8 0x10000>,
- <215 8 0x10000>,
- <217 8 0x10000>,
- <218 8 0x10000>;
+ qcom,board-id = <8 0>;
};
&sdhc_1 {
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 384000000>;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+ qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
index cc4b6ed..cdcfecb 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
@@ -10,243 +10,15 @@
* GNU General Public License for more details.
*/
-/include/ "msm8974pro-ac.dtsi"
-&spmi_bus {
- pm8941_lsid0: qcom,pm8941@2 {
- reg = <0x2>;
- };
- pm8941_lsid1: qcom,pm8941@3 {
- reg = <0x3>;
- };
-};
-/include/ "msm-pm8941.dtsi"
+/include/ "msm8974pro-pm8941.dtsi"
-&pm8941_lsid0 {
- qcom,power-on@800 {
- status = "disabled";
- };
-
- clkdiv@5b00 {
- status = "disabled";
- };
-
- clkdiv@5c00 {
- status = "disabled";
- };
-
- clkdiv@5d00 {
- status = "disabled";
- };
-
- qcom,pm8941_rtc {
- status = "disabled";
- };
-
- gpios {
- status = "disabled";
- };
-
- mpps {
- status = "disabled";
- };
+/ {
+ qcom,msm-id = <194 0x10000>,
+ <210 0x10000>,
+ <213 0x10000>,
+ <216 0x10000>;
};
-&pm8941_lsid1 {
- pm8941_boost: regulator@a000 {
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- qcom,enable-time = <500>;
- status = "okay";
- };
-
- pm8941_mvs1: regulator@8300 {
- parent-supply = <&pm8941_chg_otg>;
- qcom,enable-time = <1000>;
- qcom,pull-down-enable = <1>;
- interrupts = <0x3 0x83 0x2>;
- interrupt-names = "ocp";
- qcom,ocp-enable = <1>;
- qcom,ocp-max-retries = <10>;
- qcom,ocp-retry-delay = <30>;
- qcom,soft-start-enable = <1>;
- qcom,vs-soft-start-strength = <0>;
- qcom,hpm-enable = <1>;
- qcom,auto-mode-enable = <0>;
- status = "okay";
- };
-};
-
-&pma8084_mvs1 {
- parent-supply = <&pm8941_boost>;
-};
-
-&pm8941_chg {
- otg-parent-supply = <&pm8941_boost>;
-};
-
-&pm8941_chg_boost {
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- regulator-name = "8941_smbb_boost";
-};
-
-&pm8941_chg_otg {
- regulator-name = "8941_smbb_otg";
-};
-
-&usb3 {
- vbus_dwc3-supply = <&pm8941_mvs1>;
- qcom,misc-ref = <&pm8941_misc>;
- dwc_usb3-adc_tm = <&pm8941_adc_tm>;
- interrupt-map-mask = <0x0 0xffffffff>;
- interrupt-map = <0x0 0 &intc 0 133 0
- 0x0 1 &spmi_bus 0x0 0x2 0x9 0x0>;
- interrupt-names = "hs_phy_irq", "pmic_id_irq";
-};
-
-/* Correct PM8941 local slave ID 0 to use global SID 4 for all interrupts. */
-&pm8941_lsid0 {
- qcom,temp-alarm@2400 {
- interrupts = <0x2 0x24 0x0>;
- };
-
- qcom,power-on@800 {
- interrupts = <0x2 0x8 0x0>,
- <0x2 0x8 0x1>,
- <0x2 0x8 0x4>,
- <0x2 0x8 0x5>;
- interrupt-names = "kpdpwr", "resin",
- "resin-bark", "kpdpwr-resin-bark";
- };
-
- qcom,bsi@1b00 {
- interrupts = <0x2 0x1b 0x0>,
- <0x2 0x1b 0x1>,
- <0x2 0x1b 0x2>,
- <0x2 0x12 0x0>;
- interrupt-names = "err",
- "rx",
- "tx",
- "batt-present";
- };
-
- qcom,bms {
- qcom,bms-bms@4000 {
- interrupts = <0x2 0x40 0x0>,
- <0x2 0x40 0x1>,
- <0x2 0x40 0x2>,
- <0x2 0x40 0x3>,
- <0x2 0x40 0x4>,
- <0x2 0x40 0x5>,
- <0x2 0x40 0x6>,
- <0x2 0x40 0x7>;
- interrupt-names = "cc_thr",
- "ocv_for_r",
- "good_ocv",
- "charge_begin",
- "ocv_thr",
- "sw_cc_thr",
- "vsense_avg",
- "vsense_for_r";
- };
- };
-
- qcom,charger {
- qcom,chgr@1000 {
- interrupts = <0x2 0x10 0x0>,
- <0x2 0x10 0x1>,
- <0x2 0x10 0x2>,
- <0x2 0x10 0x3>,
- <0x2 0x10 0x4>,
- <0x2 0x10 0x5>,
- <0x2 0x10 0x6>,
- <0x2 0x10 0x7>;
- interrupt-names = "vbat-det-lo",
- "vbat-det-hi",
- "chgwdog",
- "state-change",
- "trkl-chg-on",
- "fast-chg-on",
- "chg-failed",
- "chg-done";
- };
-
- qcom,buck@1100 {
- interrupts = <0x2 0x11 0x0>,
- <0x2 0x11 0x1>,
- <0x2 0x11 0x2>,
- <0x2 0x11 0x3>,
- <0x2 0x11 0x4>,
- <0x2 0x11 0x5>,
- <0x2 0x11 0x6>;
- interrupt-names = "vbat-ov",
- "vreg-ov",
- "overtemp",
- "vchg-loop",
- "ichg-loop",
- "ibat-loop",
- "vdd-loop";
- };
-
- qcom,bat-if@1200 {
- interrupts = <0x2 0x12 0x0>,
- <0x2 0x12 0x1>,
- <0x2 0x12 0x2>,
- <0x2 0x12 0x3>,
- <0x2 0x12 0x4>;
- interrupt-names = "batt-pres",
- "bat-temp-ok",
- "bat-fet-on",
- "vcp-on",
- "psi";
- };
-
- qcom,usb-chgpth@1300 {
- interrupts = <0x2 0x13 0x0>,
- <0x2 0x13 0x1>,
- <0x2 0x13 0x2>;
- interrupt-names = "coarse-det-usb",
- "usbin-valid",
- "chg-gone";
- };
-
- qcom,dc-chgpth@1400 {
- interrupts = <0x2 0x14 0x0>,
- <0x2 0x14 0x1>;
- interrupt-names = "coarse-det-dc",
- "dcin-valid";
- };
-
- qcom,boost@1500 {
- interrupts = <0x2 0x15 0x0>,
- <0x2 0x15 0x1>;
- interrupt-names = "boost-pwr-ok",
- "limit-error";
- };
- };
-
- qcom,pm8941_rtc {
- qcom,pm8941_rtc_alarm@6100 {
- interrupts = <0x2 0x61 0x1>;
- };
- };
-
- vadc@3100 {
- interrupts = <0x2 0x31 0x0>;
- interrupt-names = "eoc-int-en-set";
- };
-
- iadc@3600 {
- interrupts = <0x2 0x36 0x0>;
- interrupt-names = "eoc-int-en-set";
- };
-
- qcom,vadc@3400 {
- interrupts = <0x2 0x34 0x0>,
- <0x2 0x34 0x3>,
- <0x2 0x34 0x4>;
- interrupt-names = "eoc-int-en-set",
- "high-thr-en-set",
- "low-thr-en-set";
- };
+&sdhc_1 {
+ reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941-mtp.dts
similarity index 82%
rename from arch/arm/boot/dts/msm8974pro-ac-mtp.dts
rename to arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941-mtp.dts
index e1d7605..8a4ad45 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941-mtp.dts
@@ -12,16 +12,13 @@
/dts-v1/;
-/include/ "msm8974pro-ac-pm8941.dtsi"
-/include/ "msm8974pro-ac-mtp.dtsi"
+/include/ "msm8974pro-ac-pma8084-pm8941.dtsi"
+/include/ "msm8974pro-pma8084-mtp.dtsi"
/ {
- model = "Qualcomm MSM 8974Pro-AC MTP";
+ model = "Qualcomm MSM 8974Pro-AC + PMA8084 MTP";
compatible = "qcom,msm8974-mtp", "qcom,msm8974", "qcom,mtp";
- qcom,msm-id = <194 8 0x10000>,
- <210 8 0x10000>,
- <213 8 0x10000>,
- <216 8 0x10000>;
+ qcom,board-id = <8 1>;
};
&pma8084_vadc {
@@ -123,12 +120,3 @@
qcom,thermal-node;
};
};
-
-&sdhc_1 {
- reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
- qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000 384000000>;
- qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
-
- qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
- qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
-};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
new file mode 100644
index 0000000..746702b
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
@@ -0,0 +1,256 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "msm8974pro-ac-pma8084.dtsi"
+&spmi_bus {
+ pm8941_lsid0: qcom,pm8941@2 {
+ reg = <0x2>;
+ };
+ pm8941_lsid1: qcom,pm8941@3 {
+ reg = <0x3>;
+ };
+};
+/include/ "msm-pm8941.dtsi"
+
+&pm8941_lsid0 {
+ qcom,power-on@800 {
+ status = "disabled";
+ };
+
+ clkdiv@5b00 {
+ status = "disabled";
+ };
+
+ clkdiv@5c00 {
+ status = "disabled";
+ };
+
+ clkdiv@5d00 {
+ status = "disabled";
+ };
+
+ qcom,pm8941_rtc {
+ status = "disabled";
+ };
+
+ gpios {
+ status = "disabled";
+ };
+
+ mpps {
+ status = "disabled";
+ };
+};
+
+&pm8941_lsid1 {
+ pm8941_boost: regulator@a000 {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ qcom,enable-time = <500>;
+ status = "okay";
+ };
+
+ pm8941_mvs1: regulator@8300 {
+ parent-supply = <&pm8941_chg_otg>;
+ qcom,enable-time = <1000>;
+ qcom,pull-down-enable = <1>;
+ interrupts = <0x3 0x83 0x2>;
+ interrupt-names = "ocp";
+ qcom,ocp-enable = <1>;
+ qcom,ocp-max-retries = <10>;
+ qcom,ocp-retry-delay = <30>;
+ qcom,soft-start-enable = <1>;
+ qcom,vs-soft-start-strength = <0>;
+ qcom,hpm-enable = <1>;
+ qcom,auto-mode-enable = <0>;
+ status = "okay";
+ };
+};
+
+&pma8084_mvs1 {
+ parent-supply = <&pm8941_boost>;
+};
+
+&pm8941_chg {
+ otg-parent-supply = <&pm8941_boost>;
+};
+
+&pm8941_chg_boost {
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-name = "8941_smbb_boost";
+};
+
+&pm8941_chg_batif {
+ regulator-name = "batfet";
+};
+
+&pm8941_chg_otg {
+ regulator-name = "8941_smbb_otg";
+};
+
+&usb3 {
+ vbus_dwc3-supply = <&pm8941_mvs1>;
+ qcom,misc-ref = <&pm8941_misc>;
+ dwc_usb3-adc_tm = <&pm8941_adc_tm>;
+ interrupt-map-mask = <0x0 0xffffffff>;
+ interrupt-map = <0x0 0 &intc 0 133 0
+ 0x0 1 &spmi_bus 0x0 0x2 0x9 0x0>;
+ interrupt-names = "hs_phy_irq", "pmic_id_irq";
+};
+
+/* Correct PM8941 local slave ID 0 to use global SID 4 for all interrupts. */
+&pm8941_lsid0 {
+ qcom,temp-alarm@2400 {
+ interrupts = <0x2 0x24 0x0>;
+ };
+
+ qcom,power-on@800 {
+ interrupts = <0x2 0x8 0x0>,
+ <0x2 0x8 0x1>,
+ <0x2 0x8 0x4>,
+ <0x2 0x8 0x5>;
+ interrupt-names = "kpdpwr", "resin",
+ "resin-bark", "kpdpwr-resin-bark";
+ };
+
+ qcom,bsi@1b00 {
+ interrupts = <0x2 0x1b 0x0>,
+ <0x2 0x1b 0x1>,
+ <0x2 0x1b 0x2>,
+ <0x2 0x12 0x0>;
+ interrupt-names = "err",
+ "rx",
+ "tx",
+ "batt-present";
+ };
+
+ qcom,bms {
+ qcom,bms-bms@4000 {
+ interrupts = <0x2 0x40 0x0>,
+ <0x2 0x40 0x1>,
+ <0x2 0x40 0x2>,
+ <0x2 0x40 0x3>,
+ <0x2 0x40 0x4>,
+ <0x2 0x40 0x5>,
+ <0x2 0x40 0x6>,
+ <0x2 0x40 0x7>;
+ interrupt-names = "cc_thr",
+ "ocv_for_r",
+ "good_ocv",
+ "charge_begin",
+ "ocv_thr",
+ "sw_cc_thr",
+ "vsense_avg",
+ "vsense_for_r";
+ };
+ };
+
+ qcom,charger {
+ qcom,chgr@1000 {
+ interrupts = <0x2 0x10 0x0>,
+ <0x2 0x10 0x1>,
+ <0x2 0x10 0x2>,
+ <0x2 0x10 0x3>,
+ <0x2 0x10 0x4>,
+ <0x2 0x10 0x5>,
+ <0x2 0x10 0x6>,
+ <0x2 0x10 0x7>;
+ interrupt-names = "vbat-det-lo",
+ "vbat-det-hi",
+ "chgwdog",
+ "state-change",
+ "trkl-chg-on",
+ "fast-chg-on",
+ "chg-failed",
+ "chg-done";
+ };
+
+ qcom,buck@1100 {
+ interrupts = <0x2 0x11 0x0>,
+ <0x2 0x11 0x1>,
+ <0x2 0x11 0x2>,
+ <0x2 0x11 0x3>,
+ <0x2 0x11 0x4>,
+ <0x2 0x11 0x5>,
+ <0x2 0x11 0x6>;
+ interrupt-names = "vbat-ov",
+ "vreg-ov",
+ "overtemp",
+ "vchg-loop",
+ "ichg-loop",
+ "ibat-loop",
+ "vdd-loop";
+ };
+
+ qcom,bat-if@1200 {
+ interrupts = <0x2 0x12 0x0>,
+ <0x2 0x12 0x1>,
+ <0x2 0x12 0x2>,
+ <0x2 0x12 0x3>,
+ <0x2 0x12 0x4>;
+ interrupt-names = "batt-pres",
+ "bat-temp-ok",
+ "bat-fet-on",
+ "vcp-on",
+ "psi";
+ };
+
+ qcom,usb-chgpth@1300 {
+ interrupts = <0x2 0x13 0x0>,
+ <0x2 0x13 0x1>,
+ <0x2 0x13 0x2>;
+ interrupt-names = "coarse-det-usb",
+ "usbin-valid",
+ "chg-gone";
+ };
+
+ qcom,dc-chgpth@1400 {
+ interrupts = <0x2 0x14 0x0>,
+ <0x2 0x14 0x1>;
+ interrupt-names = "coarse-det-dc",
+ "dcin-valid";
+ };
+
+ qcom,boost@1500 {
+ interrupts = <0x2 0x15 0x0>,
+ <0x2 0x15 0x1>;
+ interrupt-names = "boost-pwr-ok",
+ "limit-error";
+ };
+ };
+
+ qcom,pm8941_rtc {
+ qcom,pm8941_rtc_alarm@6100 {
+ interrupts = <0x2 0x61 0x1>;
+ };
+ };
+
+ vadc@3100 {
+ interrupts = <0x2 0x31 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ };
+
+ iadc@3600 {
+ interrupts = <0x2 0x36 0x0>;
+ interrupt-names = "eoc-int-en-set";
+ };
+
+ qcom,vadc@3400 {
+ interrupts = <0x2 0x34 0x0>,
+ <0x2 0x34 0x3>,
+ <0x2 0x34 0x4>;
+ interrupt-names = "eoc-int-en-set",
+ "high-thr-en-set",
+ "low-thr-en-set";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi
new file mode 100644
index 0000000..4b7ed1d
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "msm8974pro-pma8084.dtsi"
+
+/ {
+ qcom,msm-id = <194 0x10000>,
+ <210 0x10000>,
+ <213 0x10000>,
+ <216 0x10000>;
+};
+
+&sdhc_1 {
+ reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ion.dtsi b/arch/arm/boot/dts/msm8974pro-ion.dtsi
index 7faee21..4c427bf 100644
--- a/arch/arm/boot/dts/msm8974pro-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ion.dtsi
@@ -17,7 +17,7 @@
compatible = "qcom,msm-ion-reserve";
reg = <23>;
qcom,heap-align = <0x1000>;
- qcom,memory-fixed = <0x05400000 0x2700000>;
+ qcom,memory-fixed = <0x05a00000 0x2100000>;
};
qcom,ion-heap@26 { /* MODEM HEAP */
diff --git a/arch/arm/boot/dts/msm8974pro-ab.dtsi b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8974pro-ab.dtsi
rename to arch/arm/boot/dts/msm8974pro-pm8941.dtsi
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
similarity index 95%
rename from arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
rename to arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
index cdb4ed0..26fdebb 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
@@ -91,6 +91,12 @@
&sdhc_1 {
vdd-supply = <&pma8084_l20>;
vdd-io-supply = <&pma8084_s4>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000 384000000>;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
+ qcom,pad-pull-off = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
};
&sdhc_2 {
diff --git a/arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8974pro-ac-regulator.dtsi
rename to arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
diff --git a/arch/arm/boot/dts/msm8974pro-ac.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
similarity index 98%
rename from arch/arm/boot/dts/msm8974pro-ac.dtsi
rename to arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index f8a371d..cd485c5 100644
--- a/arch/arm/boot/dts/msm8974pro-ac.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -20,7 +20,7 @@
/include/ "msm-pma8084-rpm-regulator.dtsi"
/include/ "msm-pma8084.dtsi"
-/include/ "msm8974pro-ac-regulator.dtsi"
+/include/ "msm8974pro-pma8084-regulator.dtsi"
/*
* Override PM8841 and PM8941 resources with proper PMA8084 resources for
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index 4ba07fc..f45d75e 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -233,5 +233,6 @@
};
&memory_hole {
- qcom,memblock-remove = <0x05400000 0xab00000>; /* Address and size of the hole */
+ qcom,memblock-remove = <0x05a00000 0x7800000
+ 0x0fa00000 0x500000>; /* Address and size of the hole */
};
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index b822288..108907a 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -234,7 +234,6 @@
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
CONFIG_TUN=y
-CONFIG_KS8851=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_PPP=y
@@ -350,6 +349,7 @@
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DATAFAB=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 546b6b9..6d50e8d 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -236,7 +236,6 @@
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
CONFIG_TUN=y
-CONFIG_KS8851=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_PPP=y
@@ -376,6 +375,7 @@
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DATAFAB=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index c572ad8..325aba1 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -234,6 +234,8 @@
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_GPIO=m
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 6a7097d..2c5363d 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -236,6 +236,8 @@
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_TOUCHSCREEN_GT9XX=y
+CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
CONFIG_INPUT_GPIO=m
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index 38050b1..56211f2 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -130,4 +130,10 @@
extern unsigned long arch_randomize_brk(struct mm_struct *mm);
#define arch_randomize_brk arch_randomize_brk
+#ifdef CONFIG_MMU
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+int arch_setup_additional_pages(struct linux_binprm *, int);
+#endif
+
#endif
diff --git a/arch/arm/include/asm/mach/irq.h b/arch/arm/include/asm/mach/irq.h
index febe495..15cb035 100644
--- a/arch/arm/include/asm/mach/irq.h
+++ b/arch/arm/include/asm/mach/irq.h
@@ -17,7 +17,7 @@
/*
* This is internal. Do not use it.
*/
-extern void init_FIQ(void);
+extern void init_FIQ(int);
extern int show_fiq_list(struct seq_file *, int);
#ifdef CONFIG_MULTI_IRQ_HANDLER
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index b8e580a..cf0c81f 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -9,6 +9,7 @@
raw_spinlock_t id_lock;
#endif
unsigned int kvm_seq;
+ unsigned long sigpage;
} mm_context_t;
#ifdef CONFIG_CPU_HAS_ASID
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index afc1ca7..673205e 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -151,7 +151,9 @@
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
extern void copy_page(void *to, const void *from);
+#ifdef CONFIG_KUSER_HELPERS
#define __HAVE_ARCH_GATE_AREA 1
+#endif
#ifdef CONFIG_ARM_LPAE
#include <asm/pgtable-3level-types.h>
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index a3d2004..317400a 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -755,6 +755,18 @@
#endif
.endm
+ .macro kuser_pad, sym, size
+ .if (. - \sym) & 3
+ .rept 4 - (. - \sym) & 3
+ .byte 0
+ .endr
+ .endif
+ .rept (\size - (. - \sym)) / 4
+ .word 0xe7fddef1
+ .endr
+ .endm
+
+#ifdef CONFIG_KUSER_HELPERS
.align 5
.globl __kuser_helper_start
__kuser_helper_start:
@@ -936,18 +948,13 @@
#error "incoherent kernel configuration"
#endif
- /* pad to next slot */
- .rept (16 - (. - __kuser_cmpxchg64)/4)
- .word 0
- .endr
-
- .align 5
+ kuser_pad __kuser_cmpxchg64, 64
__kuser_memory_barrier: @ 0xffff0fa0
smp_dmb arm
usr_ret lr
- .align 5
+ kuser_pad __kuser_memory_barrier, 32
__kuser_cmpxchg: @ 0xffff0fc0
@@ -1020,13 +1027,14 @@
#endif
- .align 5
+ kuser_pad __kuser_cmpxchg, 32
__kuser_get_tls: @ 0xffff0fe0
ldr r0, [pc, #(16 - 8)] @ read TLS, set in kuser_get_tls_init
usr_ret lr
mrc p15, 0, r0, c13, c0, 3 @ 0xffff0fe8 hardware TLS code
- .rep 4
+ kuser_pad __kuser_get_tls, 16
+ .rep 3
.word 0 @ 0xffff0ff0 software TLS value, then
.endr @ pad up to __kuser_helper_version
@@ -1036,14 +1044,16 @@
.globl __kuser_helper_end
__kuser_helper_end:
+#endif
+
THUMB( .thumb )
/*
* Vector stubs.
*
- * This code is copied to 0xffff0200 so we can use branches in the
- * vectors, rather than ldr's. Note that this code must not
- * exceed 0x300 bytes.
+ * This code is copied to 0xffff1000 so we can use branches in the
+ * vectors, rather than ldr's. Note that this code must not exceed
+ * a page size.
*
* Common stub entry macro:
* Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
@@ -1102,8 +1112,17 @@
1:
.endm
- .globl __stubs_start
+ .section .stubs, "ax", %progbits
__stubs_start:
+ @ This must be the first word
+ .word vector_swi
+
+vector_rst:
+ ARM( swi SYS_ERROR0 )
+ THUMB( svc #0 )
+ THUMB( nop )
+ b vector_und
+
/*
* Interrupt dispatcher
*/
@@ -1198,6 +1217,16 @@
.align 5
/*=============================================================================
+ * Address exception handler
+ *-----------------------------------------------------------------------------
+ * These aren't too critical.
+ * (they're not supposed to happen, and won't happen in 32-bit data mode).
+ */
+
+vector_addrexcptn:
+ b vector_addrexcptn
+
+/*=============================================================================
* Undefined FIQs
*-----------------------------------------------------------------------------
* Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
@@ -1210,47 +1239,22 @@
vector_fiq:
subs pc, lr, #4
-/*=============================================================================
- * Address exception handler
- *-----------------------------------------------------------------------------
- * These aren't too critical.
- * (they're not supposed to happen, and won't happen in 32-bit data mode).
- */
-
-vector_addrexcptn:
- b vector_addrexcptn
-
-/*
- * We group all the following data together to optimise
- * for CPUs with separate I & D caches.
- */
- .align 5
-
-.LCvswi:
- .word vector_swi
.krait_fixup:
.word msm_krait_need_wfe_fixup
- .globl __stubs_end
-__stubs_end:
+ .globl vector_fiq_offset
+ .equ vector_fiq_offset, vector_fiq
- .equ stubs_offset, __vectors_start + 0x200 - __stubs_start
-
- .globl __vectors_start
+ .section .vectors, "ax", %progbits
__vectors_start:
- ARM( swi SYS_ERROR0 )
- THUMB( svc #0 )
- THUMB( nop )
- W(b) vector_und + stubs_offset
- W(ldr) pc, .LCvswi + stubs_offset
- W(b) vector_pabt + stubs_offset
- W(b) vector_dabt + stubs_offset
- W(b) vector_addrexcptn + stubs_offset
- W(b) vector_irq + stubs_offset
- W(b) vector_fiq + stubs_offset
-
- .globl __vectors_end
-__vectors_end:
+ W(b) vector_rst
+ W(b) vector_und
+ W(ldr) pc, __vectors_start + 0x1000
+ W(b) vector_pabt
+ W(b) vector_dabt
+ W(b) vector_addrexcptn
+ W(b) vector_irq
+ W(b) vector_fiq
.data
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index ca852c5..f9f16ef 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -48,6 +48,11 @@
#include <asm/irq.h>
#include <asm/traps.h>
+#define FIQ_OFFSET ({ \
+ extern void *vector_fiq_offset; \
+ (unsigned)&vector_fiq_offset; \
+ })
+
static unsigned long no_fiq_insn;
/* Default reacquire function
@@ -80,14 +85,14 @@
void set_fiq_handler(void *start, unsigned int length)
{
-#if defined(CONFIG_CPU_USE_DOMAINS)
- memcpy((void *)0xffff001c, start, length);
-#else
- memcpy(vectors_page + 0x1c, start, length);
-#endif
- flush_icache_range(0xffff001c, 0xffff001c + length);
- if (!vectors_high())
- flush_icache_range(0x1c, 0x1c + length);
+ void *base = vectors_page;
+ unsigned offset = FIQ_OFFSET;
+
+ memcpy(base + offset, start, length);
+ if (!cache_is_vipt_nonaliasing())
+ flush_icache_range((unsigned long)base + offset, offset +
+ length);
+ flush_icache_range(0xffff0000 + offset, 0xffff0000 + offset + length);
}
int claim_fiq(struct fiq_handler *f)
@@ -123,14 +128,16 @@
while (current_fiq->fiq_op(current_fiq->dev_id, 0));
}
+static int fiq_start;
+
void enable_fiq(int fiq)
{
- enable_irq(fiq + FIQ_START);
+ enable_irq(fiq + fiq_start);
}
void disable_fiq(int fiq)
{
- disable_irq(fiq + FIQ_START);
+ disable_irq(fiq + fiq_start);
}
void fiq_set_type(int fiq, unsigned int type)
@@ -147,7 +154,9 @@
EXPORT_SYMBOL(disable_fiq);
EXPORT_SYMBOL(fiq_set_type);
-void __init init_FIQ(void)
+void __init init_FIQ(int start)
{
- no_fiq_insn = *(unsigned long *)0xffff001c;
+ unsigned offset = FIQ_OFFSET;
+ no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
+ fiq_start = start;
}
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 0241da1..2a3ab6e 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -116,7 +116,12 @@
static int
armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
{
- int mapping = (*event_map)[config];
+ int mapping;
+
+ if (config >= PERF_COUNT_HW_MAX)
+ return -EINVAL;
+
+ mapping = (*event_map)[config];
return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;
}
@@ -341,6 +346,9 @@
struct hw_perf_event fake_event = event->hw;
struct pmu *leader_pmu = event->group_leader->pmu;
+ if (is_software_event(event))
+ return 1;
+
if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF)
return 1;
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index ea3b4d8..c5fa883 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -652,10 +652,11 @@
}
#ifdef CONFIG_MMU
+#ifdef CONFIG_KUSER_HELPERS
/*
* The vectors page is always readable from user space for the
- * atomic helpers and the signal restart code. Insert it into the
- * gate_vma so that it is visible through ptrace and /proc/<pid>/mem.
+ * atomic helpers. Insert it into the gate_vma so that it is visible
+ * through ptrace and /proc/<pid>/mem.
*/
static struct vm_area_struct gate_vma;
@@ -684,14 +685,53 @@
{
return in_gate_area(NULL, addr);
}
+#define is_gate_vma(vma) ((vma) == &gate_vma)
+#else
+#define is_gate_vma(vma) 0
+#endif
const char *arch_vma_name(struct vm_area_struct *vma)
{
- if (vma == &gate_vma)
+ if (is_gate_vma(vma))
return "[vectors]";
+ else if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage)
+ return "[sigpage]";
else if (vma == get_user_timers_vma(NULL))
return "[timers]";
else
return NULL;
}
+
+static struct page *signal_page;
+extern struct page *get_signal_page(void);
+
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long addr;
+ int ret;
+
+ if (!signal_page)
+ signal_page = get_signal_page();
+ if (!signal_page)
+ return -ENOMEM;
+
+ down_write(&mm->mmap_sem);
+ addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+ if (IS_ERR_VALUE(addr)) {
+ ret = addr;
+ goto up_fail;
+ }
+
+ ret = install_special_mapping(mm, addr, PAGE_SIZE,
+ VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+ &signal_page);
+
+ if (ret == 0)
+ mm->context.sigpage = addr;
+
+ up_fail:
+ up_write(&mm->mmap_sem);
+ return ret;
+}
#endif
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index d68d1b6..e000e5e 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
#include <linux/errno.h>
+#include <linux/random.h>
#include <linux/signal.h>
#include <linux/personality.h>
#include <linux/freezer.h>
@@ -16,10 +17,10 @@
#include <asm/elf.h>
#include <asm/cacheflush.h>
+#include <asm/traps.h>
#include <asm/ucontext.h>
#include <asm/unistd.h>
#include <asm/vfp.h>
-
#include "signal.h"
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -44,7 +45,7 @@
#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
-const unsigned long sigreturn_codes[7] = {
+static const unsigned long sigreturn_codes[7] = {
MOV_R7_NR_SIGRETURN, SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
};
@@ -112,6 +113,8 @@
return ret;
}
+static unsigned long signal_return_offset;
+
#ifdef CONFIG_CRUNCH
static int preserve_crunch_context(struct crunch_sigframe __user *frame)
{
@@ -460,13 +463,20 @@
__put_user(sigreturn_codes[idx+1], rc+1))
return 1;
+#ifdef CONFIG_MMU
if (cpsr & MODE32_BIT) {
+ struct mm_struct *mm = current->mm;
+
/*
- * 32-bit code can use the new high-page
- * signal return code support.
+ * 32-bit code can use the signal return page
+ * except when the MPU has protected the vectors
+ * page from PL0
*/
- retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
- } else {
+ retcode = mm->context.sigpage + signal_return_offset +
+ (idx << 2) + thumb;
+ } else
+#endif
+ {
/*
* Ensure that the instruction cache sees
* the return code written onto the stack.
@@ -739,3 +749,33 @@
key_replace_session_keyring();
}
}
+
+struct page *get_signal_page(void)
+{
+ unsigned long ptr;
+ unsigned offset;
+ struct page *page;
+ void *addr;
+
+ page = alloc_pages(GFP_KERNEL, 0);
+
+ if (!page)
+ return NULL;
+
+ addr = page_address(page);
+
+ /* Give the signal return code some randomness */
+ offset = 0x200 + (get_random_int() & 0x7fc);
+ signal_return_offset = offset;
+
+ /*
+ * Copy signal return handlers into the vector page, and
+ * set sigreturn to be a pointer to these.
+ */
+ memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes));
+
+ ptr = (unsigned long)addr + offset;
+ flush_icache_range(ptr, ptr + sizeof(sigreturn_codes));
+
+ return page;
+}
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h
index 6fcfe83..a0dcf5f 100644
--- a/arch/arm/kernel/signal.h
+++ b/arch/arm/kernel/signal.h
@@ -10,5 +10,4 @@
#define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500)
#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes))
-extern const unsigned long sigreturn_codes[7];
extern const unsigned long syscall_restart_code[2];
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index b58a0fc..bd49b1f 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -35,8 +35,6 @@
#include <asm/tls.h>
#include <asm/system_misc.h>
-#include "signal.h"
-
#include <trace/events/exception.h>
static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
@@ -785,49 +783,55 @@
return;
}
-static void __init kuser_get_tls_init(unsigned long vectors)
+#ifdef CONFIG_KUSER_HELPERS
+static void __init kuser_init(void *vectors)
{
+ extern char __kuser_helper_start[], __kuser_helper_end[];
+ int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+
+ memcpy(vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+
/*
* vectors + 0xfe0 = __kuser_get_tls
* vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
*/
if (tls_emu || has_tls_reg)
- memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4);
+ memcpy(vectors + 0xfe0, vectors + 0xfe8, 4);
}
+#else
+static void __init kuser_init(void *vectors)
+{
+}
+#endif
void __init early_trap_init(void *vectors_base)
{
unsigned long vectors = (unsigned long)vectors_base;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
- extern char __kuser_helper_start[], __kuser_helper_end[];
- int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+ unsigned i;
vectors_page = vectors_base;
/*
+ * Poison the vectors page with an undefined instruction. This
+ * instruction is chosen to be undefined for both ARM and Thumb
+ * ISAs. The Thumb version is an undefined instruction with a
+ * branch back to the undefined instruction.
+ */
+ for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
+ ((u32 *)vectors_base)[i] = 0xe7fddef1;
+
+ /*
* Copy the vectors, stubs and kuser helpers (in entry-armv.S)
* into the vector page, mapped at 0xffff0000, and ensure these
* are visible to the instruction stream.
*/
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
- memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
- memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+ memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
- /*
- * Do processor specific fixups for the kuser helpers
- */
- kuser_get_tls_init(vectors);
+ kuser_init(vectors_base);
- /*
- * Copy signal return handlers into the vector page, and
- * set sigreturn to be a pointer to these.
- */
- memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
- sigreturn_codes, sizeof(sigreturn_codes));
- memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
- syscall_restart_code, sizeof(syscall_restart_code));
-
- flush_icache_range(vectors, vectors + PAGE_SIZE);
+ flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
}
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 0bf55ae..68c312b 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -151,6 +151,23 @@
#endif
__init_begin = .;
#endif
+ /*
+ * The vectors and stubs are relocatable code, and the
+ * only thing that matters is their relative offsets
+ */
+ __vectors_start = .;
+ .vectors 0 : AT(__vectors_start) {
+ *(.vectors)
+ }
+ . = __vectors_start + SIZEOF(.vectors);
+ __vectors_end = .;
+
+ __stubs_start = .;
+ .stubs 0x1000 : AT(__stubs_start) {
+ *(.stubs)
+ }
+ . = __stubs_start + SIZEOF(.stubs);
+ __stubs_end = .;
INIT_TEXT_SECTION(8)
.exit.text : {
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 696ddf9..87c2f8c 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -473,6 +473,7 @@
select MSM_JTAG_MM if CORESIGHT_ETM
select MSM_CPR_REGULATOR
select MSM_RPM_LOG
+ select MSM_IOMMU_SYNC
select MSM_RPM_STATS_LOG
config ARCH_MSM8226
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 910264e..552ed16 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -67,11 +67,14 @@
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2.2-fluid.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2.2-liquid.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2.2-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-fluid.dtb
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-liquid.dtb
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ac-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-pm8941-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-pm8941-fluid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-pm8941-liquid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ab-pm8941-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ac-pm8941-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ac-pm8941-liquid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ac-pm8941-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += msm8974pro-ac-pma8084-pm8941-mtp.dtb
# APQ8084
zreladdr-$(CONFIG_ARCH_APQ8084) := 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 3e488e3..7feb30d 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -273,10 +273,10 @@
[10] = { { 1036800, HFPLL, 1, 54 }, LVL_NOM, 950000, 5 },
[11] = { { 1113600, HFPLL, 1, 58 }, LVL_HIGH, 1050000, 6 },
[12] = { { 1190400, HFPLL, 1, 62 }, LVL_HIGH, 1050000, 6 },
- [13] = { { 1267200, HFPLL, 1, 66 }, LVL_HIGH, 1050000, 7 },
- [14] = { { 1344000, HFPLL, 1, 70 }, LVL_HIGH, 1050000, 7 },
- [15] = { { 1420800, HFPLL, 1, 74 }, LVL_HIGH, 1050000, 7 },
- [16] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 7 },
+ [13] = { { 1267200, HFPLL, 1, 66 }, LVL_HIGH, 1050000, 6 },
+ [14] = { { 1344000, HFPLL, 1, 70 }, LVL_HIGH, 1050000, 6 },
+ [15] = { { 1420800, HFPLL, 1, 74 }, LVL_HIGH, 1050000, 6 },
+ [16] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 6 },
[17] = { { 1574400, HFPLL, 1, 82 }, LVL_HIGH, 1050000, 7 },
[18] = { { 1651200, HFPLL, 1, 86 }, LVL_HIGH, 1050000, 7 },
[19] = { { 1728000, HFPLL, 1, 90 }, LVL_HIGH, 1050000, 8 },
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 7cfbd93..c4db727 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -101,6 +101,7 @@
* @asid: List of ASID and their usage count (index is ASID value).
* @ctx_attach_count: Count of how many context are attached.
* @bus_client : Bus client needed to vote for bus bandwidth.
+ * @needs_rem_spinlock : 1 if remote spinlock is needed, 0 otherwise
*
* A msm_iommu_drvdata holds the global driver data about a single piece
* of an IOMMU hardware instance.
@@ -125,6 +126,7 @@
int *asid;
unsigned int ctx_attach_count;
unsigned int bus_client;
+ int needs_rem_spinlock;
};
/**
@@ -146,8 +148,8 @@
int (*iommu_clk_on)(struct msm_iommu_drvdata *);
void (*iommu_clk_off)(struct msm_iommu_drvdata *);
void * (*iommu_lock_initialize)(void);
- void (*iommu_lock_acquire)(void);
- void (*iommu_lock_release)(void);
+ void (*iommu_lock_acquire)(unsigned int need_extra_lock);
+ void (*iommu_lock_release)(unsigned int need_extra_lock);
};
void msm_iommu_add_drv(struct msm_iommu_drvdata *drv);
@@ -277,32 +279,21 @@
}
#endif
-#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
-void msm_iommu_remote_p0_spin_lock(void);
-void msm_iommu_remote_p0_spin_unlock(void);
+#ifdef CONFIG_MSM_IOMMU_SYNC
+void msm_iommu_remote_p0_spin_lock(unsigned int need_lock);
+void msm_iommu_remote_p0_spin_unlock(unsigned int need_lock);
#define msm_iommu_remote_lock_init() _msm_iommu_remote_spin_lock_init()
-#define msm_iommu_remote_spin_lock() msm_iommu_remote_p0_spin_lock()
-#define msm_iommu_remote_spin_unlock() msm_iommu_remote_p0_spin_unlock()
+#define msm_iommu_remote_spin_lock(need_lock) \
+ msm_iommu_remote_p0_spin_lock(need_lock)
+#define msm_iommu_remote_spin_unlock(need_lock) \
+ msm_iommu_remote_p0_spin_unlock(need_lock)
#else
#define msm_iommu_remote_lock_init()
-#define msm_iommu_remote_spin_lock()
-#define msm_iommu_remote_spin_unlock()
+#define msm_iommu_remote_spin_lock(need_lock)
+#define msm_iommu_remote_spin_unlock(need_lock)
#endif
-/* Allows kgsl iommu driver to acquire lock */
-#define msm_iommu_lock() \
- do { \
- msm_iommu_mutex_lock(); \
- msm_iommu_remote_spin_lock(); \
- } while (0)
-
-#define msm_iommu_unlock() \
- do { \
- msm_iommu_remote_spin_unlock(); \
- msm_iommu_mutex_unlock(); \
- } while (0)
-
#ifdef CONFIG_MSM_IOMMU
/*
* Look up an IOMMU context device by its context name. NULL if none found.
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index de15be5..322061d 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -494,7 +494,7 @@
if (!lpass_status) {
pr_err("%s: kobject create failed\n", __func__);
ret = -ENOMEM;
- goto err_notif_modem;
+ goto err_create_kobj;
}
ret = sysfs_create_group(lpass_status, &attr_group);
@@ -507,6 +507,8 @@
return 0;
err_kobj:
kobject_put(lpass_status);
+err_create_kobj:
+ subsys_notif_unregister_notifier(drv->modem_notif_hdle, &mnb);
err_notif_modem:
subsys_notif_unregister_notifier(drv->wcnss_notif_hdle, &wnb);
err_notif_wcnss:
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index 1f04e76..d32dc4f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -2,7 +2,7 @@
*
* amrnb audio decoder device
*
- * Copyright (c) 2008-2009, 2011-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2013 The Linux Foundation. All rights reserved.
*
* Based on the mp3 native driver in arch/arm/mach-msm/qdsp5/audio_mp3.c
*
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index 743eee2..0eca74d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -2,7 +2,7 @@
*
* amrnb encoder device
*
- * Copyright (c) 2009, 2011-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009, 2011-2013 The Linux Foundation. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5/audio_in.c, which is
* Copyright (C) 2008 Google, Inc.
@@ -742,6 +742,7 @@
MM_DBG("\n");
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index 83a2633..cfda4b9 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -2,7 +2,7 @@
*
* qcelp audio input device
*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c,
* Copyright (C) 2008 Google, Inc.
@@ -732,6 +732,7 @@
MM_DBG("\n");
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index ae63f0d..f7295b7 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5/audio_mp3.c
*
@@ -644,6 +644,7 @@
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
mutex_lock(&audio->dsp_lock);
stats.byte_count = audio->byte_count;
stats.sample_count = audio->frame_count;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index 8e66939..cb3c3ea 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -503,6 +503,7 @@
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index 0f8956f..37a6726 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -778,6 +778,7 @@
MM_DBG("\n");
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/qdsp6/pcm_in.c b/arch/arm/mach-msm/qdsp6/pcm_in.c
index c6bddb8..288e1dc 100644
--- a/arch/arm/mach-msm/qdsp6/pcm_in.c
+++ b/arch/arm/mach-msm/qdsp6/pcm_in.c
@@ -141,6 +141,7 @@
}
case AUDIO_GET_CONFIG: {
struct msm_audio_config config;
+ memset(&config, 0, sizeof(config));
config.buffer_size = pcm->buffer_size;
config.buffer_count = 2;
config.sample_rate = pcm->sample_rate;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 33bbac0..5355de1 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -197,6 +197,7 @@
if (cmd == AUDIO_GET_STATS) {
struct msm_audio_stats stats;
+ memset(&stats, 0, sizeof(stats));
stats.byte_count = atomic_read(&audio->in_bytes);
stats.sample_count = atomic_read(&audio->in_samples);
if (copy_to_user((void *) arg, &stats, sizeof(stats)))
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 888cd5e..53bbe20 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -1035,56 +1035,64 @@
msm_soc_device = soc_device_to_device(soc_dev);
populate_soc_sysfs_files(msm_soc_device);
+
err = sysdev_class_register(&soc_sysdev_class);
if (err) {
pr_err("%s: sysdev_class_register fail (%d)\n",
__func__, err);
- return err;
+ goto socinfo_init_err;
}
+
err = sysdev_register(&soc_sys_device);
if (err) {
pr_err("%s: sysdev_register fail (%d)\n",
__func__, err);
- return err;
+ goto socinfo_init_err;
}
+
socinfo_create_files(&soc_sys_device, socinfo_v1_files,
ARRAY_SIZE(socinfo_v1_files));
if (socinfo->v1.format < 2)
- return err;
+ goto socinfo_init_err;
+
socinfo_create_files(&soc_sys_device, socinfo_v2_files,
ARRAY_SIZE(socinfo_v2_files));
if (socinfo->v1.format < 3)
- return err;
+ goto socinfo_init_err;
socinfo_create_files(&soc_sys_device, socinfo_v3_files,
ARRAY_SIZE(socinfo_v3_files));
if (socinfo->v1.format < 4)
- return err;
+ goto socinfo_init_err;
socinfo_create_files(&soc_sys_device, socinfo_v4_files,
ARRAY_SIZE(socinfo_v4_files));
if (socinfo->v1.format < 5)
- return err;
+ goto socinfo_init_err;
socinfo_create_files(&soc_sys_device, socinfo_v5_files,
ARRAY_SIZE(socinfo_v5_files));
if (socinfo->v1.format < 6)
- return err;
+ goto socinfo_init_err;
socinfo_create_files(&soc_sys_device, socinfo_v6_files,
ARRAY_SIZE(socinfo_v6_files));
if (socinfo->v1.format < 7)
- return err;
+ goto socinfo_init_err;
socinfo_create_files(&soc_sys_device, socinfo_v7_files,
ARRAY_SIZE(socinfo_v7_files));
return 0;
+
+socinfo_init_err:
+ kfree(soc_dev_attr);
+ return err;
}
arch_initcall(socinfo_init_sysdev);
diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c
index cf0e669..3e4fa84 100644
--- a/arch/arm/mach-rpc/irq.c
+++ b/arch/arm/mach-rpc/irq.c
@@ -163,6 +163,6 @@
}
}
- init_FIQ();
+ init_FIQ(FIQ_START);
}
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 194c5f6..7b9f754 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -436,24 +436,28 @@
select TLS_REG_EMUL if SMP || !MMU
select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
select CPU_USE_DOMAINS if MMU
+ select NEED_KUSER_HELPERS
config CPU_32v4
bool
select TLS_REG_EMUL if SMP || !MMU
select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
select CPU_USE_DOMAINS if MMU
+ select NEED_KUSER_HELPERS
config CPU_32v4T
bool
select TLS_REG_EMUL if SMP || !MMU
select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
select CPU_USE_DOMAINS if MMU
+ select NEED_KUSER_HELPERS
config CPU_32v5
bool
select TLS_REG_EMUL if SMP || !MMU
select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
select CPU_USE_DOMAINS if MMU
+ select NEED_KUSER_HELPERS
config CPU_32v6
bool
@@ -792,6 +796,7 @@
config TLS_REG_EMUL
bool
+ select NEED_KUSER_HELPERS
help
An SMP system using a pre-ARMv6 processor (there are apparently
a few prototypes like that in existence) and therefore access to
@@ -799,11 +804,43 @@
config NEEDS_SYSCALL_FOR_CMPXCHG
bool
+ select NEED_KUSER_HELPERS
help
SMP on a pre-ARMv6 processor? Well OK then.
Forget about fast user space cmpxchg support.
It is just not possible.
+config NEED_KUSER_HELPERS
+ bool
+
+config KUSER_HELPERS
+ bool "Enable kuser helpers in vector page" if !NEED_KUSER_HELPERS
+ default y
+ help
+ Warning: disabling this option may break user programs.
+
+ Provide kuser helpers in the vector page. The kernel provides
+ helper code to userspace in read only form at a fixed location
+ in the high vector page to allow userspace to be independent of
+ the CPU type fitted to the system. This permits binaries to be
+ run on ARMv4 through to ARMv7 without modification.
+
+ See Documentation/arm/kernel_user_helpers.txt for details.
+
+ However, the fixed address nature of these helpers can be used
+ by ROP (return orientated programming) authors when creating
+ exploits.
+
+ If all of the binaries and libraries which run on your platform
+ are built specifically for your platform, and make no use of
+ these helpers, then you can turn this option off to hinder
+ such exploits. However, in that case, if a binary or library
+ relying on those helpers is run, it will receive a SIGILL signal,
+ which will terminate the program.
+
+ Say N here only if you are absolutely certain that you do not
+ need these helpers; otherwise, the safe option is to say Y.
+
config DMA_CACHE_RWFO
bool "Enable read/write for ownership DMA cache maintenance"
depends on CPU_V6K && SMP
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 509f59d..a1a2e51 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1203,7 +1203,7 @@
/*
* Allocate the vector page early.
*/
- vectors = early_alloc(PAGE_SIZE);
+ vectors = early_alloc(PAGE_SIZE * 2);
early_trap_init(vectors);
@@ -1248,15 +1248,27 @@
map.pfn = __phys_to_pfn(virt_to_phys(vectors));
map.virtual = 0xffff0000;
map.length = PAGE_SIZE;
+#ifdef CONFIG_KUSER_HELPERS
map.type = MT_HIGH_VECTORS;
+#else
+ map.type = MT_LOW_VECTORS;
+#endif
create_mapping(&map);
if (!vectors_high()) {
map.virtual = 0;
+ map.length = PAGE_SIZE * 2;
map.type = MT_LOW_VECTORS;
create_mapping(&map);
}
+ /* Now create a kernel read-only mapping */
+ map.pfn += 1;
+ map.virtual = 0xffff0000 + PAGE_SIZE;
+ map.length = PAGE_SIZE;
+ map.type = MT_LOW_VECTORS;
+ create_mapping(&map);
+
/*
* Ask the machine support to map in the statically mapped devices.
*/
@@ -1485,7 +1497,7 @@
vm->addr = (void *)(vaddr & PAGE_MASK);
vm->size = PAGE_ALIGN(length + (vaddr & ~PAGE_MASK));
vm->phys_addr = __pfn_to_phys(pfn);
- vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
+ vm->flags = VM_LOWMEM | VM_ARM_STATIC_MAPPING;
vm->flags |= VM_ARM_MTYPE(type);
vm->caller = map_lowmem;
vm_area_add_early(vm++);
diff --git a/arch/arm/plat-mxc/avic.c b/arch/arm/plat-mxc/avic.c
index 689f81f..9091f03 100644
--- a/arch/arm/plat-mxc/avic.c
+++ b/arch/arm/plat-mxc/avic.c
@@ -199,7 +199,7 @@
#ifdef CONFIG_FIQ
/* Initialize FIQ */
- init_FIQ();
+ init_FIQ(FIQ_START);
#endif
printk(KERN_INFO "MXC IRQ initialized\n");
diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c
index 98308ec..5cebccf 100644
--- a/arch/arm/plat-mxc/tzic.c
+++ b/arch/arm/plat-mxc/tzic.c
@@ -180,7 +180,7 @@
#ifdef CONFIG_FIQ
/* Initialize FIQ */
- init_FIQ();
+ init_FIQ(FIQ_START);
#endif
pr_info("TrustZone Interrupt Controller (TZIC) initialized\n");
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index bc42c04..fe57bbb 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -533,7 +533,7 @@
int i;
#ifdef CONFIG_FIQ
- init_FIQ();
+ init_FIQ(FIQ_START);
#endif
irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
diff --git a/drivers/bif/bif-core.c b/drivers/bif/bif-core.c
index 7bc9af2..4ff7355 100644
--- a/drivers/bif/bif-core.c
+++ b/drivers/bif/bif-core.c
@@ -205,13 +205,14 @@
}
if (sdev->nvm_function) {
- pr_debug(" NVM function: pointer=0x%04X, task=%d, wr_buf_size=%d, nvm_base=0x%04X, nvm_size=%d\n",
+ pr_debug(" NVM function: pointer=0x%04X, task=%d, wr_buf_size=%d, nvm_base=0x%04X, nvm_size=%d, nvm_lock_offset=%d\n",
sdev->nvm_function->nvm_pointer,
sdev->nvm_function->slave_control_channel,
(sdev->nvm_function->write_buffer_size
? sdev->nvm_function->write_buffer_size : 0),
sdev->nvm_function->nvm_base_address,
- sdev->nvm_function->nvm_size);
+ sdev->nvm_function->nvm_size,
+ sdev->nvm_function->nvm_lock_offset);
if (sdev->nvm_function->object_count)
pr_debug(" NVM objects:\n");
i = 0;
@@ -448,8 +449,13 @@
rc = bdev->desc->ops->read_slave_registers(bdev, addr, buf,
len);
if (rc)
- pr_err("read_slave_registers failed, rc=%d\n", rc);
- return rc;
+ pr_debug("read_slave_registers failed, rc=%d\n", rc);
+ else
+ return rc;
+ /*
+ * Fall back on individual transactions if high level register
+ * read failed.
+ */
}
for (i = 0; i < len; i++) {
@@ -521,8 +527,13 @@
rc = bdev->desc->ops->write_slave_registers(bdev, addr, buf,
len);
if (rc)
- pr_err("write_slave_registers failed, rc=%d\n", rc);
- return rc;
+ pr_debug("write_slave_registers failed, rc=%d\n", rc);
+ else
+ return rc;
+ /*
+ * Fall back on individual transactions if high level register
+ * write failed.
+ */
}
rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_ERA, addr >> 8);
@@ -567,6 +578,233 @@
return rc;
}
+/* Perform a read-modify-write sequence on a single BIF slave register. */
+static int _bif_slave_masked_write(struct bif_slave_dev *sdev, u16 addr, u8 val,
+ u8 mask)
+{
+ int rc;
+ u8 reg;
+
+ rc = _bif_slave_read(sdev, addr, ®, 1);
+ if (rc)
+ return rc;
+
+ reg = (reg & ~mask) | (val & mask);
+
+ return _bif_slave_write(sdev, addr, ®, 1);
+}
+
+static int _bif_check_task(struct bif_slave_dev *sdev, unsigned int task)
+{
+ if (IS_ERR_OR_NULL(sdev)) {
+ pr_err("Invalid slave device handle=%ld\n", PTR_ERR(sdev));
+ return -EINVAL;
+ } else if (!sdev->bdev) {
+ pr_err("BIF controller has been removed\n");
+ return -ENXIO;
+ } else if (!sdev->slave_ctrl_function
+ || sdev->slave_ctrl_function->task_count == 0) {
+ pr_err("BIF slave does not support slave control\n");
+ return -ENODEV;
+ } else if (task >= sdev->slave_ctrl_function->task_count) {
+ pr_err("Requested task: %u greater than max: %u for this slave\n",
+ task, sdev->slave_ctrl_function->task_count);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int _bif_task_is_busy(struct bif_slave_dev *sdev, unsigned int task)
+{
+ int rc;
+ u16 addr;
+ u8 reg = 0;
+
+ rc = _bif_check_task(sdev, task);
+ if (rc) {
+ pr_err("Invalid slave device or task, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* Check the task busy state. */
+ addr = SLAVE_CTRL_FUNC_TASK_BUSY_ADDR(
+ sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+ rc = _bif_slave_read(sdev, addr, ®, 1);
+ if (rc) {
+ pr_err("BIF slave register read failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ return (reg & BIT(task % SLAVE_CTRL_TASKS_PER_SET)) ? 1 : 0;
+}
+
+static int _bif_enable_auto_task(struct bif_slave_dev *sdev, unsigned int task)
+{
+ int rc;
+ u16 addr;
+ u8 mask;
+
+ rc = _bif_check_task(sdev, task);
+ if (rc) {
+ pr_err("Invalid slave device or task, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* Enable the auto task within the slave */
+ mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
+ addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
+ sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+ if (task / SLAVE_CTRL_TASKS_PER_SET == 0) {
+ /* Set global auto task enable. */
+ mask |= BIT(0);
+ }
+ rc = _bif_slave_masked_write(sdev, addr, 0xFF, mask);
+ if (rc) {
+ pr_err("BIF slave register masked write failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* Set global auto task enable if task not in set 0. */
+ if (task / SLAVE_CTRL_TASKS_PER_SET != 0) {
+ addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
+ sdev->slave_ctrl_function->slave_ctrl_pointer, 0);
+ rc = _bif_slave_masked_write(sdev, addr, 0xFF, BIT(0));
+ if (rc) {
+ pr_err("BIF slave register masked write failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+static int _bif_disable_auto_task(struct bif_slave_dev *sdev, unsigned int task)
+{
+ int rc;
+ u16 addr;
+ u8 mask;
+
+ rc = _bif_check_task(sdev, task);
+ if (rc) {
+ pr_err("Invalid slave or task, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* Disable the auto task within the slave */
+ mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
+ addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
+ sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+ rc = _bif_slave_masked_write(sdev, addr, 0x00, mask);
+ if (rc) {
+ pr_err("BIF slave register masked write failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+/*
+ * The MIPI-BIF spec does not define a maximum time in which an NVM write must
+ * complete. The following delay and recheck count therefore represent
+ * arbitrary but reasonable values.
+ */
+#define NVM_WRITE_POLL_DELAY_MS 20
+#define NVM_WRITE_MAX_POLL_COUNT 50
+
+static int _bif_slave_nvm_raw_write(struct bif_slave_dev *sdev, u16 offset,
+ u8 *buf, int len)
+{
+ int rc = 0;
+ int write_len, poll_count, rc2;
+ u8 write_buf[3];
+
+ if (!sdev->nvm_function) {
+ pr_err("BIF slave has no NVM function\n");
+ return -ENODEV;
+ } else if (offset + len > sdev->nvm_function->nvm_size) {
+ pr_err("write offset + len = %d > NVM size = %d\n",
+ offset + len, sdev->nvm_function->nvm_size);
+ return -EINVAL;
+ } else if (offset < sdev->nvm_function->nvm_lock_offset) {
+ pr_err("write offset = %d < first writable offset = %d\n",
+ offset, sdev->nvm_function->nvm_lock_offset);
+ return -EINVAL;
+ }
+
+ rc = _bif_enable_auto_task(sdev,
+ sdev->nvm_function->slave_control_channel);
+ if (rc) {
+ pr_err("Failed to enable NVM auto task, rc=%d\n", rc);
+ return rc;
+ }
+
+ while (len > 0) {
+ write_len = sdev->nvm_function->write_buffer_size;
+ if (write_len == 0)
+ write_len = 256;
+ write_len = min(write_len, len);
+
+ write_buf[0] = offset >> 8;
+ write_buf[1] = offset;
+ write_buf[2] = (write_len == 256) ? 0 : write_len;
+
+ /* Write offset and size registers. */
+ rc = _bif_slave_write(sdev, sdev->nvm_function->nvm_pointer + 6,
+ write_buf, 3);
+ if (rc) {
+ pr_err("BIF slave write failed, rc=%d\n", rc);
+ goto done;
+ }
+
+ /* Write to NVM write buffer registers. */
+ rc = _bif_slave_write(sdev, sdev->nvm_function->nvm_pointer + 9,
+ buf, write_len);
+ if (rc) {
+ pr_err("BIF slave write failed, rc=%d\n", rc);
+ goto done;
+ }
+
+ /*
+ * Wait for completion of the NVM write which was auto-triggered
+ * by the register write of the last byte in the NVM write
+ * buffer.
+ */
+ poll_count = NVM_WRITE_MAX_POLL_COUNT;
+ do {
+ msleep(NVM_WRITE_POLL_DELAY_MS);
+ rc = _bif_task_is_busy(sdev,
+ sdev->nvm_function->slave_control_channel);
+ poll_count--;
+ } while (rc > 0 && poll_count > 0);
+
+ if (rc < 0) {
+ pr_err("Failed to check task state, rc=%d", rc);
+ goto done;
+ } else if (rc > 0) {
+ pr_err("BIF slave NVM write not completed after %d ms\n",
+ NVM_WRITE_POLL_DELAY_MS * NVM_WRITE_MAX_POLL_COUNT);
+ rc = -ETIMEDOUT;
+ goto done;
+ }
+
+ len -= write_len;
+ offset += write_len;
+ buf += write_len;
+ }
+
+done:
+ rc2 = _bif_disable_auto_task(sdev,
+ sdev->nvm_function->slave_control_channel);
+ if (rc2) {
+ pr_err("Failed to disable NVM auto task, rc=%d\n", rc2);
+ return rc2;
+ }
+
+ return rc;
+}
+
/* Takes a mutex if this consumer is not an exclusive bus user. */
static void bif_ctrl_lock(struct bif_ctrl *ctrl)
{
@@ -595,25 +833,53 @@
bif_ctrl_unlock(&slave->ctrl);
}
+/**
+ * bif_crc_ccitt() - calculate the CRC-CCITT CRC value of the data specified
+ * @buffer: Data to calculate the CRC of
+ * @len: Length of the data buffer in bytes
+ *
+ * MIPI-BIF specifies the usage of CRC-CCITT for BIF data objects. This
+ * function performs the CRC calculation while taking into account the bit
+ * ordering used by BIF.
+ */
+u16 bif_crc_ccitt(const u8 *buffer, unsigned int len)
+{
+ u16 crc = 0xFFFF;
+
+ while (len--) {
+ crc = crc_ccitt_byte(crc, bitrev8(*buffer));
+ buffer++;
+ }
+ return bitrev16(crc);
+}
+EXPORT_SYMBOL(bif_crc_ccitt);
+
+static u16 bif_object_crc_ccitt(const struct bif_object *object)
+{
+ u16 crc = 0xFFFF;
+ int i;
+
+ crc = crc_ccitt_byte(crc, bitrev8(object->type));
+ crc = crc_ccitt_byte(crc, bitrev8(object->version));
+ crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id >> 8));
+ crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id));
+ crc = crc_ccitt_byte(crc, bitrev8(object->length >> 8));
+ crc = crc_ccitt_byte(crc, bitrev8(object->length));
+
+ for (i = 0; i < object->length - 8; i++)
+ crc = crc_ccitt_byte(crc, bitrev8(object->data[i]));
+
+ return bitrev16(crc);
+}
+
static int bif_check_task(struct bif_slave *slave, unsigned int task)
{
if (IS_ERR_OR_NULL(slave)) {
- pr_err("Invalid slave handle.\n");
- return -EINVAL;
- } else if (!slave->sdev->bdev) {
- pr_err("BIF controller has been removed.\n");
- return -ENXIO;
- } else if (!slave->sdev->slave_ctrl_function
- || slave->sdev->slave_ctrl_function->task_count == 0) {
- pr_err("BIF slave does not support slave control.\n");
- return -ENODEV;
- } else if (task >= slave->sdev->slave_ctrl_function->task_count) {
- pr_err("Requested task: %u greater than max: %u for this slave\n",
- task, slave->sdev->slave_ctrl_function->task_count);
+ pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
return -EINVAL;
}
- return 0;
+ return _bif_check_task(slave->sdev, task);
}
/**
@@ -817,6 +1083,61 @@
EXPORT_SYMBOL(bif_trigger_task);
/**
+ * bif_enable_auto_task() - enable task auto triggering for the specified task
+ * @slave: BIF slave handle
+ * @task: BIF task inside of the slave to configure for automatic
+ * triggering. This corresponds to the slave control channel
+ * specified for a given BIF function inside of the slave.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_enable_auto_task(struct bif_slave *slave, unsigned int task)
+{
+ int rc;
+
+ if (IS_ERR_OR_NULL(slave)) {
+ pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
+ return -EINVAL;
+ }
+
+ bif_slave_ctrl_lock(slave);
+ rc = _bif_enable_auto_task(slave->sdev, task);
+ bif_slave_ctrl_unlock(slave);
+
+ return rc;
+}
+EXPORT_SYMBOL(bif_enable_auto_task);
+
+/**
+ * bif_disable_auto_task() - disable task auto triggering for the specified task
+ * @slave: BIF slave handle
+ * @task: BIF task inside of the slave to stop automatic triggering on.
+ * This corresponds to the slave control channel specified for a
+ * given BIF function inside of the slave.
+ *
+ * This function should be called after bif_enable_auto_task() in a paired
+ * fashion.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_disable_auto_task(struct bif_slave *slave, unsigned int task)
+{
+ int rc;
+
+ if (IS_ERR_OR_NULL(slave)) {
+ pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
+ return -EINVAL;
+ }
+
+ bif_slave_ctrl_lock(slave);
+ rc = _bif_disable_auto_task(slave->sdev, task);
+ bif_slave_ctrl_unlock(slave);
+
+ return rc;
+}
+EXPORT_SYMBOL(bif_disable_auto_task);
+
+/**
* bif_task_is_busy() - checks the state of a BIF slave task
* @slave: BIF slave handle
* @task: BIF task inside of the slave to trigger. This corresponds to
@@ -828,28 +1149,14 @@
int bif_task_is_busy(struct bif_slave *slave, unsigned int task)
{
int rc;
- u16 addr;
- u8 reg;
- rc = bif_check_task(slave, task);
- if (rc) {
- pr_err("Invalid slave or task, rc=%d\n", rc);
- return rc;
+ if (IS_ERR_OR_NULL(slave)) {
+ pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
+ return -EINVAL;
}
bif_slave_ctrl_lock(slave);
-
- /* Check the task busy state. */
- addr = SLAVE_CTRL_FUNC_TASK_BUSY_ADDR(
- slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
- rc = _bif_slave_read(slave->sdev, addr, ®, 1);
- if (rc) {
- pr_err("BIF slave register read failed, rc=%d\n", rc);
- goto done;
- }
-
- rc = (reg & BIT(task % SLAVE_CTRL_TASKS_PER_SET)) ? 1 : 0;
-done:
+ rc = _bif_task_is_busy(slave->sdev, task);
bif_slave_ctrl_unlock(slave);
return rc;
@@ -1258,16 +1565,29 @@
}
EXPORT_SYMBOL(bif_ctrl_put);
+static bool bif_slave_object_match(const struct bif_object *object,
+ const struct bif_match_criteria *criteria)
+{
+ return (object->type == criteria->obj_type)
+ && (object->version == criteria->obj_version
+ || !(criteria->match_mask & BIF_MATCH_OBJ_VERSION))
+ && (object->manufacturer_id == criteria->obj_manufacturer_id
+ || !(criteria->match_mask & BIF_MATCH_OBJ_MANUFACTURER_ID));
+}
+
/*
* Returns true if all parameters are matched, otherwise false.
* function_type and function_version mean that their exists some function in
* the slave which has the specified type and subtype. ctrl == NULL is treated
* as a wildcard.
*/
-static bool bif_slave_match(const struct bif_ctrl *ctrl,
+static bool bif_slave_match(struct bif_ctrl *ctrl,
struct bif_slave_dev *sdev, const struct bif_match_criteria *criteria)
{
int i, type, version;
+ struct bif_object *object;
+ bool function_found = false;
+ bool object_found = false;
if (ctrl && (ctrl->bdev != sdev->bdev))
return false;
@@ -1295,10 +1615,29 @@
if (type == criteria->function_type &&
(version == criteria->function_version
|| !(criteria->match_mask
- & BIF_MATCH_FUNCTION_VERSION)))
- return true;
+ & BIF_MATCH_FUNCTION_VERSION))) {
+ function_found = true;
+ break;
+ }
}
- return false;
+ if (!function_found)
+ return false;
+ }
+
+ if (criteria->match_mask & BIF_MATCH_OBJ_TYPE) {
+ if (!sdev->nvm_function)
+ return false;
+ bif_ctrl_lock(ctrl);
+ list_for_each_entry(object, &sdev->nvm_function->object_list,
+ list) {
+ if (bif_slave_object_match(object, criteria)) {
+ object_found = true;
+ break;
+ }
+ }
+ bif_ctrl_unlock(ctrl);
+ if (!object_found)
+ return false;
}
return true;
@@ -1311,7 +1650,7 @@
* @ctrl: BIF controller consumer handle
* @match_criteria: Matching criteria used to filter slaves
*/
-int bif_slave_match_count(const struct bif_ctrl *ctrl,
+int bif_slave_match_count(struct bif_ctrl *ctrl,
const struct bif_match_criteria *match_criteria)
{
struct bif_slave_dev *sdev;
@@ -1342,7 +1681,7 @@
*
* Returns a BIF slave handle if successful or an ERR_PTR if not.
*/
-struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+struct bif_slave *bif_slave_match_get(struct bif_ctrl *ctrl,
unsigned int id, const struct bif_match_criteria *match_criteria)
{
struct bif_slave_dev *sdev;
@@ -1431,6 +1770,511 @@
}
EXPORT_SYMBOL(bif_slave_find_function);
+static bool bif_object_match(const struct bif_object *object,
+ const struct bif_obj_match_criteria *criteria)
+{
+ return (object->type == criteria->type
+ || !(criteria->match_mask & BIF_OBJ_MATCH_TYPE))
+ && (object->version == criteria->version
+ || !(criteria->match_mask & BIF_OBJ_MATCH_VERSION))
+ && (object->manufacturer_id == criteria->manufacturer_id
+ || !(criteria->match_mask & BIF_OBJ_MATCH_MANUFACTURER_ID));
+}
+
+/**
+ * bif_object_match_count() - returns the number of objects associated with the
+ * specified BIF slave which fit the matching criteria
+ * @slave: BIF slave handle
+ * @match_criteria: Matching criteria used to filter objects
+ */
+int bif_object_match_count(struct bif_slave *slave,
+ const struct bif_obj_match_criteria *match_criteria)
+{
+ struct bif_object *object;
+ int count = 0;
+
+ if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(match_criteria)) {
+ pr_err("Invalid pointer input.\n");
+ return -EINVAL;
+ }
+
+ if (!slave->sdev->nvm_function)
+ return 0;
+
+ bif_slave_ctrl_lock(slave);
+ list_for_each_entry(object, &slave->sdev->nvm_function->object_list,
+ list) {
+ if (bif_object_match(object, match_criteria))
+ count++;
+ }
+ bif_slave_ctrl_unlock(slave);
+
+ return count;
+}
+EXPORT_SYMBOL(bif_object_match_count);
+
+/**
+ * bif_object_match_get() - get a BIF object handle for the id'th object found
+ * in the non-volatile memory of the specified BIF slave
+ * which fits the matching criteria
+ * @slave: BIF slave handle
+ * @id: Index into the set of matching objects
+ * @match_criteria: Matching criteria used to filter objects
+ *
+ * id must be in range [0, bif_object_match_count(slave, match_criteria) - 1].
+ *
+ * Returns a BIF object handle if successful or an ERR_PTR if not. This handle
+ * must be freed using bif_object_put() when it is no longer needed.
+ */
+struct bif_object *bif_object_match_get(struct bif_slave *slave,
+ unsigned int id, const struct bif_obj_match_criteria *match_criteria)
+{
+ struct bif_object *object;
+ struct bif_object *object_found = NULL;
+ struct bif_object *object_consumer = ERR_PTR(-ENODEV);
+ int count = 0;
+
+ if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(match_criteria)) {
+ pr_err("Invalid pointer input.\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!slave->sdev->nvm_function)
+ return object_consumer;
+
+ bif_slave_ctrl_lock(slave);
+ list_for_each_entry(object, &slave->sdev->nvm_function->object_list,
+ list) {
+ if (bif_object_match(object, match_criteria))
+ count++;
+ if (count == id + 1) {
+ object_found = object;
+ break;
+ }
+ }
+
+ if (object_found) {
+ object_consumer = kmemdup(object_found,
+ sizeof(*object_consumer), GFP_KERNEL);
+ if (!object_consumer) {
+ pr_err("out of memory\n");
+ object_consumer = ERR_PTR(-ENOMEM);
+ goto done;
+ }
+
+ object_consumer->data = kmemdup(object_found->data,
+ object_found->length - 8, GFP_KERNEL);
+ if (!object_consumer->data) {
+ pr_err("out of memory\n");
+ kfree(object_consumer);
+ object_consumer = ERR_PTR(-ENOMEM);
+ goto done;
+ }
+
+ /*
+ * Use prev pointer in consumer struct to point to original
+ * struct in the internal linked list.
+ */
+ object_consumer->list.prev = &object_found->list;
+ }
+
+done:
+ bif_slave_ctrl_unlock(slave);
+
+ return object_consumer;
+
+}
+EXPORT_SYMBOL(bif_object_match_get);
+
+/**
+ * bif_object_put() - frees the memory allocated for a BIF object pointer
+ * returned by bif_object_match_get()
+ * @object: BIF object to free
+ */
+void bif_object_put(struct bif_object *object)
+{
+ if (object)
+ kfree(object->data);
+ kfree(object);
+}
+EXPORT_SYMBOL(bif_object_put);
+
+/* Copies the contents of object into buf following MIPI-BIF formatting. */
+static void bif_object_flatten(u8 *buf, const struct bif_object *object)
+{
+ buf[0] = object->type;
+ buf[1] = object->version;
+ buf[2] = object->manufacturer_id >> 8;
+ buf[3] = object->manufacturer_id;
+ buf[4] = object->length >> 8;
+ buf[5] = object->length;
+ memcpy(&buf[6], object->data, object->length - 8);
+ buf[object->length - 2] = object->crc >> 8;
+ buf[object->length - 1] = object->crc;
+}
+
+/**
+ * bif_object_write() - writes a new BIF object at the end of the object list in
+ * the non-volatile memory of a slave
+ * @slave: BIF slave handle
+ * @type: Type of the object
+ * @version: Version of the object
+ * @manufacturer_id: Manufacturer ID number allocated by MIPI
+ * @data: Data contained in the object
+ * @data_len: Length of the data
+ *
+ * Returns 0 on success or errno on failure. This function will fail if the NVM
+ * lock points to an offset after the BIF object list terminator (0x00).
+ */
+int bif_object_write(struct bif_slave *slave, u8 type, u8 version,
+ u16 manufacturer_id, const u8 *data, int data_len)
+{
+ struct bif_object *object;
+ struct bif_object *tail_object;
+ struct bif_nvm_function *nvm;
+ int rc;
+ int add_null = 0;
+ u16 offset = 0;
+ u8 *buf;
+
+ if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(data)) {
+ pr_err("Invalid input pointer\n");
+ return -EINVAL;
+ }
+
+ nvm = slave->sdev->nvm_function;
+ if (!nvm) {
+ pr_err("BIF slave has no NVM function\n");
+ return -ENODEV;
+ }
+
+ bif_slave_ctrl_lock(slave);
+ if (nvm->object_count > 0) {
+ tail_object = list_entry(nvm->object_list.prev,
+ struct bif_object, list);
+ offset = tail_object->addr - nvm->nvm_base_address
+ + tail_object->length;
+ }
+
+ if (offset < nvm->nvm_lock_offset) {
+ pr_err("Cannot write BIF object to NVM because the end of the object list is locked (end=%d < lock=%d)\n",
+ offset, nvm->nvm_lock_offset);
+ rc = -EPERM;
+ goto error_unlock;
+ } else if (offset + data_len + 8 > nvm->nvm_size) {
+ pr_err("Cannot write BIF object to NVM because there is not enough remaining space (size=%d > remaining=%d)\n",
+ data_len + 8, nvm->nvm_size - offset);
+ rc = -EINVAL;
+ goto error_unlock;
+ }
+
+ if (offset + data_len + 8 < nvm->nvm_size)
+ add_null = 1;
+ object = kzalloc(sizeof(*object), GFP_KERNEL);
+ if (!object) {
+ pr_err("kzalloc failed\n");
+ rc = -ENOMEM;
+ goto error_unlock;
+ }
+
+ object->data = kzalloc(data_len, GFP_KERNEL);
+ if (!object->data) {
+ pr_err("kzalloc failed\n");
+ rc = -ENOMEM;
+ goto free_object;
+ }
+
+ buf = kzalloc(data_len + 8 + add_null, GFP_KERNEL);
+ if (!buf) {
+ pr_err("kzalloc failed\n");
+ rc = -ENOMEM;
+ goto free_data;
+ }
+
+ object->type = type;
+ object->version = version;
+ object->manufacturer_id = manufacturer_id;
+ object->length = data_len + 8;
+ memcpy(object->data, data, data_len);
+ object->crc = bif_object_crc_ccitt(object);
+ object->addr = offset + nvm->nvm_base_address;
+
+ bif_object_flatten(buf, object);
+ if (add_null)
+ buf[object->length] = BIF_OBJ_END_OF_LIST;
+
+ rc = _bif_slave_nvm_raw_write(slave->sdev, offset, buf,
+ object->length + add_null);
+ if (rc < 0) {
+ pr_err("NVM write failed, rc=%d\n", rc);
+ kfree(buf);
+ goto free_data;
+ }
+ kfree(buf);
+
+ list_add_tail(&object->list, &nvm->object_list);
+ nvm->object_count++;
+
+ bif_slave_ctrl_unlock(slave);
+
+ return rc;
+
+free_data:
+ kfree(object->data);
+free_object:
+ kfree(object);
+error_unlock:
+ bif_slave_ctrl_unlock(slave);
+
+ return rc;
+
+}
+EXPORT_SYMBOL(bif_object_write);
+
+/*
+ * Returns a pointer to the internal object referenced by a consumer object
+ * if it exists. Returns NULL if the internal object cannot be found.
+ */
+static struct bif_object *bif_object_consumer_search(
+ struct bif_nvm_function *nvm, const struct bif_object *consumer_object)
+{
+ struct bif_object *object = NULL;
+ struct bif_object *search_object;
+
+ /*
+ * Internal struct in object linked list is pointed to by consumer
+ * object list.prev.
+ */
+ search_object = list_entry(consumer_object->list.prev,
+ struct bif_object, list);
+
+ list_for_each_entry(object, &nvm->object_list, list) {
+ if (object == search_object)
+ break;
+ }
+
+ if (object != search_object)
+ return NULL;
+
+ return object;
+}
+
+/**
+ * bif_object_overwrite() - overwrites an existing BIF object found in the
+ * non-volatile memory of a slave
+ * @slave: BIF slave handle
+ * @object: Existing object in the slave to overwrite
+ * @type: Type of the object
+ * @version: Version of the object
+ * @manufacturer_id: Manufacturer ID number allocated by MIPI
+ * @data: Data contained in the object
+ * @data_len: Length of the data
+ *
+ * Returns 0 on success or errno on failure. The data stored within 'object'
+ * is updated to the new values upon success. The new data written to the
+ * object must have exactly the same length as the old data (i.e.
+ * data_len == object->length - 8).
+ *
+ * This function will fail if the NVM lock points to an offset after the
+ * beginning of the existing BIF object.
+ */
+int bif_object_overwrite(struct bif_slave *slave,
+ struct bif_object *object, u8 type, u8 version,
+ u16 manufacturer_id, const u8 *data, int data_len)
+{
+ struct bif_object *edit_object = NULL;
+ struct bif_nvm_function *nvm;
+ int rc;
+ u16 crc;
+ u8 *buf;
+
+ if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(object)
+ || IS_ERR_OR_NULL(data)) {
+ pr_err("Invalid input pointer\n");
+ return -EINVAL;
+ }
+
+ nvm = slave->sdev->nvm_function;
+ if (!nvm) {
+ pr_err("BIF slave has no NVM function\n");
+ return -ENODEV;
+ }
+
+ if (data_len + 8 != object->length) {
+ pr_err("New data length=%d is different from existing length=%d\n",
+ data_len, object->length - 8);
+ return -EINVAL;
+ }
+
+ bif_slave_ctrl_lock(slave);
+
+ edit_object = bif_object_consumer_search(nvm, object);
+ if (!edit_object) {
+ pr_err("BIF object not found within slave\n");
+ rc = -EINVAL;
+ goto error_unlock;
+ }
+
+ if (edit_object->addr - nvm->nvm_base_address < nvm->nvm_lock_offset) {
+ pr_err("Cannot overwrite BIF object in NVM because some portion of it is locked\n");
+ rc = -EPERM;
+ goto error_unlock;
+ }
+
+ buf = kzalloc(data_len + 8, GFP_KERNEL);
+ if (!buf) {
+ pr_err("kzalloc failed\n");
+ rc = -ENOMEM;
+ goto error_unlock;
+ }
+
+ buf[0] = type;
+ buf[1] = version;
+ buf[2] = manufacturer_id >> 8;
+ buf[3] = manufacturer_id;
+ buf[4] = (data_len + 8) >> 8;
+ buf[5] = data_len + 8;
+ memcpy(&buf[6], data, data_len);
+ crc = bif_crc_ccitt(buf, data_len + 6);
+ buf[data_len + 6] = crc >> 8;
+ buf[data_len + 7] = crc;
+
+ rc = _bif_slave_nvm_raw_write(slave->sdev,
+ object->addr - nvm->nvm_base_address, buf, data_len + 8);
+ if (rc < 0) {
+ pr_err("NVM write failed, rc=%d\n", rc);
+ kfree(buf);
+ goto error_unlock;
+ }
+ kfree(buf);
+
+ /* Update internal object struct. */
+ edit_object->type = type;
+ edit_object->version = version;
+ edit_object->manufacturer_id = manufacturer_id;
+ edit_object->length = data_len + 8;
+ memcpy(edit_object->data, data, data_len);
+ edit_object->crc = crc;
+
+ /* Update consumer object struct. */
+ object->type = type;
+ object->version = version;
+ object->manufacturer_id = manufacturer_id;
+ object->length = data_len + 8;
+ memcpy(object->data, data, data_len);
+ object->crc = crc;
+
+error_unlock:
+ bif_slave_ctrl_unlock(slave);
+
+ return rc;
+}
+EXPORT_SYMBOL(bif_object_overwrite);
+
+/**
+ * bif_object_delete() - deletes an existing BIF object found in the
+ * non-volatile memory of a slave. Objects found in the
+ * object list in the NVM of the slave are shifted forward
+ * in order to fill the hole left by the deleted object
+ * @slave: BIF slave handle
+ * @object: Existing object in the slave to delete
+ *
+ * Returns 0 on success or errno on failure. bif_object_put() must still be
+ * called after this function in order to free the memory in the consumer
+ * 'object' struct pointer.
+ *
+ * This function will fail if the NVM lock points to an offset after the
+ * beginning of the existing BIF object.
+ */
+int bif_object_delete(struct bif_slave *slave, const struct bif_object *object)
+{
+ struct bif_object *del_object = NULL;
+ struct bif_object *tail_object;
+ struct bif_nvm_function *nvm;
+ bool found = false;
+ int pos = 0;
+ int rc;
+ u8 *buf;
+
+ if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(object)) {
+ pr_err("Invalid input pointer\n");
+ return -EINVAL;
+ }
+
+ nvm = slave->sdev->nvm_function;
+ if (!nvm) {
+ pr_err("BIF slave has no NVM function\n");
+ return -ENODEV;
+ }
+
+ bif_slave_ctrl_lock(slave);
+
+ del_object = bif_object_consumer_search(nvm, object);
+ if (!del_object) {
+ pr_err("BIF object not found within slave\n");
+ rc = -EINVAL;
+ goto error_unlock;
+ }
+
+ if (del_object->addr - nvm->nvm_base_address < nvm->nvm_lock_offset) {
+ pr_err("Cannot delete BIF object in NVM because some portion of it is locked\n");
+ rc = -EPERM;
+ goto error_unlock;
+ }
+
+ buf = kmalloc(nvm->nvm_size, GFP_KERNEL);
+ if (!buf) {
+ pr_err("kzalloc failed\n");
+ rc = -ENOMEM;
+ goto error_unlock;
+ }
+
+ /*
+ * Copy the contents of objects after the one to be deleted into a flat
+ * array.
+ */
+ list_for_each_entry(tail_object, &nvm->object_list, list) {
+ if (found) {
+ bif_object_flatten(&buf[pos], tail_object);
+ pos += tail_object->length;
+ } else if (tail_object == del_object) {
+ found = true;
+ }
+ }
+
+ /* Add the list terminator. */
+ buf[pos++] = BIF_OBJ_END_OF_LIST;
+
+ rc = _bif_slave_nvm_raw_write(slave->sdev,
+ del_object->addr - nvm->nvm_base_address, buf, pos);
+ if (rc < 0) {
+ pr_err("NVM write failed, rc=%d\n", rc);
+ kfree(buf);
+ goto error_unlock;
+ }
+ kfree(buf);
+
+ /* Update the addresses of the objects after the one to be deleted. */
+ found = false;
+ list_for_each_entry(tail_object, &nvm->object_list, list) {
+ if (found)
+ tail_object->addr -= del_object->length;
+ else if (tail_object == del_object)
+ found = true;
+ }
+
+ list_del(&del_object->list);
+ kfree(del_object->data);
+ kfree(del_object);
+ nvm->object_count--;
+
+error_unlock:
+ bif_slave_ctrl_unlock(slave);
+
+ return rc;
+}
+EXPORT_SYMBOL(bif_object_delete);
+
/**
* bif_slave_read() - read contiguous memory values from a BIF slave
* @slave: BIF slave handle
@@ -1492,6 +2336,74 @@
EXPORT_SYMBOL(bif_slave_write);
/**
+ * bif_slave_nvm_raw_read() - read contiguous memory values from a BIF slave's
+ * non-volatile memory (NVM)
+ * @slave: BIF slave handle
+ * @offset: Offset from the beginning of BIF slave NVM to begin reading at
+ * @buf: Buffer to fill with memory values
+ * @len: Number of byte to read
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_slave_nvm_raw_read(struct bif_slave *slave, u16 offset, u8 *buf,
+ int len)
+{
+ if (IS_ERR_OR_NULL(slave)) {
+ pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
+ return -EINVAL;
+ } else if (IS_ERR_OR_NULL(buf)) {
+ pr_err("Invalid buffer pointer=%ld\n", PTR_ERR(buf));
+ return -EINVAL;
+ } else if (!slave->sdev->nvm_function) {
+ pr_err("BIF slave has no NVM function\n");
+ return -ENODEV;
+ } else if (offset + len > slave->sdev->nvm_function->nvm_size) {
+ pr_err("read offset + len = %d > NVM size = %d\n",
+ offset + len, slave->sdev->nvm_function->nvm_size);
+ return -EINVAL;
+ }
+
+ return bif_slave_read(slave,
+ slave->sdev->nvm_function->nvm_base_address + offset, buf, len);
+}
+EXPORT_SYMBOL(bif_slave_nvm_raw_read);
+
+/**
+ * bif_slave_nvm_raw_write() - write contiguous memory values to a BIF slave's
+ * non-volatile memory (NVM)
+ * @slave: BIF slave handle
+ * @offset: Offset from the beginning of BIF slave NVM to begin writing at
+ * @buf: Buffer containing values to write
+ * @len: Number of byte to write
+ *
+ * Note that this function does *not* respect the MIPI-BIF object data
+ * formatting specification. It can cause corruption of the object data list
+ * stored in NVM if used improperly.
+ *
+ * Returns 0 for success or errno if an error occurred.
+ */
+int bif_slave_nvm_raw_write(struct bif_slave *slave, u16 offset, u8 *buf,
+ int len)
+{
+ int rc;
+
+ if (IS_ERR_OR_NULL(slave)) {
+ pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
+ return -EINVAL;
+ } else if (IS_ERR_OR_NULL(buf)) {
+ pr_err("Invalid buffer pointer=%ld\n", PTR_ERR(buf));
+ return -EINVAL;
+ }
+
+ bif_slave_ctrl_lock(slave);
+ rc = _bif_slave_nvm_raw_write(slave->sdev, offset, buf, len);
+ bif_slave_ctrl_unlock(slave);
+
+ return rc;
+}
+EXPORT_SYMBOL(bif_slave_nvm_raw_write);
+
+/**
* bif_slave_is_present() - check if a slave is currently physically present
* in the system
* @slave: BIF slave handle
@@ -2032,45 +2944,6 @@
return rc;
}
-/**
- * bif_crc_ccitt() - calculate the CRC-CCITT CRC value of the data specified
- * @buffer: Data to calculate the CRC of
- * @len: Length of the data buffer in bytes
- *
- * MIPI-BIF specifies the usage of CRC-CCITT for BIF data objects. This
- * function performs the CRC calculation while taking into account the bit
- * ordering used by BIF.
- */
-u16 bif_crc_ccitt(const u8 *buffer, unsigned int len)
-{
- u16 crc = 0xFFFF;
-
- while (len--) {
- crc = crc_ccitt_byte(crc, bitrev8(*buffer));
- buffer++;
- }
- return bitrev16(crc);
-}
-EXPORT_SYMBOL(bif_crc_ccitt);
-
-static u16 bif_object_crc_ccitt(const struct bif_object *object)
-{
- u16 crc = 0xFFFF;
- int i;
-
- crc = crc_ccitt_byte(crc, bitrev8(object->type));
- crc = crc_ccitt_byte(crc, bitrev8(object->version));
- crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id >> 8));
- crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id));
- crc = crc_ccitt_byte(crc, bitrev8(object->length >> 8));
- crc = crc_ccitt_byte(crc, bitrev8(object->length));
-
- for (i = 0; i < object->length - 8; i++)
- crc = crc_ccitt_byte(crc, bitrev8(object->data[i]));
-
- return bitrev16(crc);
-}
-
/*
* Check if the specified function is an NVM function and if it is, then
* instantiate NVM function data for the slave and read all objects.
@@ -2079,7 +2952,7 @@
struct bif_ddb_l2_data *func)
{
int rc = 0;
- int data_len;
+ int data_len, read_size;
u8 buf[8], object_type;
struct bif_object *object;
struct bif_object *temp;
@@ -2109,12 +2982,21 @@
return rc;
}
- sdev->nvm_function->nvm_pointer = buf[0] << 8 | buf[1];
+ sdev->nvm_function->nvm_pointer = buf[0] << 8 | buf[1];
sdev->nvm_function->slave_control_channel = buf[2];
sdev->nvm_function->write_buffer_size = buf[3];
sdev->nvm_function->nvm_base_address = buf[4] << 8 | buf[5];
sdev->nvm_function->nvm_size = buf[6] << 8 | buf[7];
+ /* Read NVM lock offset */
+ rc = _bif_slave_read(sdev, sdev->nvm_function->nvm_pointer, buf, 2);
+ if (rc) {
+ pr_err("Slave memory read failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ sdev->nvm_function->nvm_lock_offset = buf[0] << 8 | buf[1];
+
INIT_LIST_HEAD(&sdev->nvm_function->object_list);
/* Read object list */
@@ -2125,8 +3007,7 @@
return rc;
}
- /* Object type == 0x00 corresponds to the end of the object list. */
- while (object_type != 0x00) {
+ while (object_type != BIF_OBJ_END_OF_LIST) {
object = kzalloc(sizeof(*object), GFP_KERNEL);
if (!object) {
pr_err("out of memory\n");
@@ -2178,15 +3059,20 @@
goto free_data;
}
- rc = _bif_slave_read(sdev, addr + 6 + data_len, buf, 3);
+ if ((object->length + addr) >= (sdev->nvm_function->nvm_size
+ + sdev->nvm_function->nvm_base_address))
+ read_size = 2;
+ else
+ read_size = 3;
+ rc = _bif_slave_read(sdev, addr + 6 + data_len, buf, read_size);
if (rc) {
pr_err("Slave memory read of object CRC failed; addr=0x%04X, len=%d, rc=%d\n",
- addr + 6 + data_len, 3, rc);
+ addr + 6 + data_len, read_size, rc);
goto free_data;
}
object->crc = buf[0] << 8 | buf[1];
- object_type = buf[2];
+ object_type = (read_size == 3) ? buf[2] : BIF_OBJ_END_OF_LIST;
sdev->nvm_function->object_count++;
crc = bif_object_crc_ccitt(object);
@@ -2336,6 +3222,12 @@
} else if (rc == 1) {
sdev->present = true;
sdev->bdev->selected_sdev = sdev;
+ rc = bif_parse_slave_data(sdev);
+ if (rc) {
+ pr_err("Failed to parse secondary slave data, rc=%d\n",
+ rc);
+ goto free_slave;
+ }
} else {
sdev->present = false;
sdev->bdev->selected_sdev = NULL;
@@ -2459,6 +3351,11 @@
sdev->present = true;
sdev->bdev->selected_sdev = sdev;
rc = bif_parse_slave_data(sdev);
+ if (rc) {
+ pr_err("Failed to parse secondary slave data, rc=%d\n",
+ rc);
+ return rc;
+ }
} else {
pr_err("Slave failed to respond to DILC bus command; its UID is thus unverified.\n");
sdev->unique_id_bits_known = 0;
diff --git a/drivers/bif/qpnp-bsi.c b/drivers/bif/qpnp-bsi.c
index 19a560a..e3f7d2f 100644
--- a/drivers/bif/qpnp-bsi.c
+++ b/drivers/bif/qpnp-bsi.c
@@ -170,7 +170,7 @@
#define QPNP_BSI_DEFAULT_VID_REF_UV 1800000
/* These have units of tau_bif. */
-#define QPNP_BSI_MAX_TRANSMIT_CYCLES 36
+#define QPNP_BSI_MAX_TRANSMIT_CYCLES 46
#define QPNP_BSI_MIN_RECEIVE_CYCLES 24
#define QPNP_BSI_MAX_BUS_QUERY_CYCLES 17
@@ -544,12 +544,6 @@
struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
int rc;
- rc = qpnp_bsi_clear_bsi_error(chip);
- if (rc)
- return rc;
-
- qpnp_bsi_clear_irq_flags(chip);
-
qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
@@ -563,6 +557,12 @@
if (rc)
return rc;
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
if (rc)
return rc;
@@ -578,12 +578,6 @@
struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
int rc, timeout;
- rc = qpnp_bsi_clear_bsi_error(chip);
- if (rc)
- return rc;
-
- qpnp_bsi_clear_irq_flags(chip);
-
qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
@@ -597,6 +591,12 @@
if (rc)
return rc;
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
if (rc)
return rc;
@@ -624,12 +624,6 @@
int rc, timeout;
u8 buf[3];
- rc = qpnp_bsi_clear_bsi_error(chip);
- if (rc)
- return rc;
-
- qpnp_bsi_clear_irq_flags(chip);
-
qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
@@ -643,6 +637,12 @@
if (rc)
return rc;
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, transaction, data);
if (rc)
return rc;
@@ -826,10 +826,10 @@
/*
* Send burst read length bus commands according to the following:
*
- * 256 --> RBL0
- * 0-255 = 16 * y + x --> RBEy and RBLx
- * RBE0 does not need to be sent
- * RBL0 does not need to be sent
+ * 1 --> No RBE or RBL
+ * 2 - 15 = x --> RBLx
+ * 16 - 255 = 16 * y + x --> RBEy and RBLx (RBL0 not sent)
+ * 256 --> RBL0
*/
if (burst_len == 256) {
rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_BC,
@@ -851,7 +851,7 @@
return rc;
}
- if (burst_len % 16) {
+ if (burst_len % 16 && burst_len > 1) {
rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_BC,
BIF_CMD_RBL + (burst_len % 16));
if (rc)
@@ -906,12 +906,6 @@
int rc, rc2, i, burst_len;
u8 buf[3];
- rc = qpnp_bsi_clear_bsi_error(chip);
- if (rc)
- return rc;
-
- qpnp_bsi_clear_irq_flags(chip);
-
qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_POLL);
rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
@@ -925,6 +919,12 @@
if (rc)
return rc;
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
while (len > 0) {
burst_len = min(len, 256);
@@ -1001,12 +1001,6 @@
unsigned long flags;
int rc, rc2, i;
- rc = qpnp_bsi_clear_bsi_error(chip);
- if (rc)
- return rc;
-
- qpnp_bsi_clear_irq_flags(chip);
-
qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_POLL);
rc = qpnp_bsi_set_bus_state(bdev, BIF_BUS_STATE_ACTIVE);
@@ -1020,6 +1014,12 @@
if (rc)
return rc;
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
rc = qpnp_bsi_issue_transaction(chip, BIF_TRANS_ERA, addr >> 8);
if (rc)
return rc;
@@ -1075,12 +1075,6 @@
struct qpnp_bsi_chip *chip = bdev_get_drvdata(bdev);
int rc;
- rc = qpnp_bsi_clear_bsi_error(chip);
- if (rc)
- return rc;
-
- qpnp_bsi_clear_irq_flags(chip);
-
qpnp_bsi_set_com_mode(chip, QPNP_BSI_COM_MODE_IRQ);
/*
@@ -1105,6 +1099,12 @@
*/
chip->state = BIF_BUS_STATE_INTERRUPT;
+ rc = qpnp_bsi_clear_bsi_error(chip);
+ if (rc)
+ return rc;
+
+ qpnp_bsi_clear_irq_flags(chip);
+
/* Send EINT bus command. */
rc = qpnp_bsi_issue_transaction_wait_for_tx(chip, BIF_TRANS_BC,
BIF_CMD_EINT);
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 5e2acfb..fc6df7b 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -151,6 +151,38 @@
If unsure, say 'N' here to avoid potential power penalty.
+config CORESIGHT_AUDIO_ETM
+ bool "Audio processor ETM trace support"
+ help
+ Enables support for ETM trace collection on audio processor using
+ CoreSight framework. Enabling this will allow turning on ETM tracing
+ on audio processor via sysfs by configuring the required CoreSight
+ components.
+
+config CORESIGHT_MODEM_ETM
+ bool "Modem processor ETM trace support"
+ help
+ Enables support for ETM trace collection on modem processor using
+ CoreSight framework. Enabling this will allow turning on ETM tracing
+ on modem processor via sysfs by configuring the required CoreSight
+ components.
+
+config CORESIGHT_WCN_ETM
+ bool "Wireless subsystem processor ETM trace support"
+ help
+ Enables support for ETM trace collection on wireless subsystem
+ processor using CoreSight framework. Enabling this will allow
+ turning on ETM tracing on wireless subsystem via sysfs by configuring
+ the required CoreSight components.
+
+config CORESIGHT_RPM_ETM
+ bool "RPM processor ETM trace support"
+ help
+ Enables support for ETM trace collection on RPM processor using
+ CoreSight framework. Enabling this will allow turning on ETM
+ tracing on RPM processor via sysfs by configuring the required
+ CoreSight components.
+
endif
config CORESIGHT_EVENT
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 23352a7..9d93a6c 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -13,4 +13,8 @@
obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
obj-$(CONFIG_CORESIGHT_ETM) += coresight-etm.o coresight-etm-cp14.o
+obj-$(CONFIG_CORESIGHT_AUDIO_ETM) += coresight-audio-etm.o
+obj-$(CONFIG_CORESIGHT_MODEM_ETM) += coresight-modem-etm.o
+obj-$(CONFIG_CORESIGHT_WCN_ETM) += coresight-wcn-etm.o
+obj-$(CONFIG_CORESIGHT_RPM_ETM) += coresight-rpm-etm.o
obj-$(CONFIG_CORESIGHT_EVENT) += coresight-event.o
diff --git a/drivers/coresight/coresight-audio-etm.c b/drivers/coresight/coresight-audio-etm.c
new file mode 100644
index 0000000..cdf44bf
--- /dev/null
+++ b/drivers/coresight/coresight-audio-etm.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+struct audio_etm_drvdata {
+ struct device *dev;
+ struct coresight_device *csdev;
+};
+
+static int audio_etm_enable(struct coresight_device *csdev)
+{
+ struct audio_etm_drvdata *drvdata =
+ dev_get_drvdata(csdev->dev.parent);
+
+ dev_info(drvdata->dev, "Audio ETM tracing enabled\n");
+ return 0;
+}
+
+
+static void audio_etm_disable(struct coresight_device *csdev)
+{
+ struct audio_etm_drvdata *drvdata =
+ dev_get_drvdata(csdev->dev.parent);
+
+ dev_info(drvdata->dev, "Audio ETM tracing disabled\n");
+}
+
+static const struct coresight_ops_source audio_etm_source_ops = {
+ .enable = audio_etm_enable,
+ .disable = audio_etm_disable,
+};
+
+static const struct coresight_ops audio_cs_ops = {
+ .source_ops = &audio_etm_source_ops,
+};
+
+static int audio_etm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct coresight_platform_data *pdata;
+ struct audio_etm_drvdata *drvdata;
+ struct coresight_desc *desc;
+
+ if (pdev->dev.of_node) {
+ pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ pdev->dev.platform_data = pdata;
+ }
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+ desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+ desc->ops = &audio_cs_ops;
+ desc->pdata = pdev->dev.platform_data;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ drvdata->csdev = coresight_register(desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ dev_info(dev, "Audio ETM initialized\n");
+ return 0;
+}
+
+static int audio_etm_remove(struct platform_device *pdev)
+{
+ struct audio_etm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ coresight_unregister(drvdata->csdev);
+ return 0;
+}
+
+static struct of_device_id audio_etm_match[] = {
+ {.compatible = "qcom,coresight-audio-etm"},
+ {}
+};
+
+static struct platform_driver audio_etm_driver = {
+ .probe = audio_etm_probe,
+ .remove = audio_etm_remove,
+ .driver = {
+ .name = "coresight-audio-etm",
+ .owner = THIS_MODULE,
+ .of_match_table = audio_etm_match,
+ },
+};
+
+int __init audio_etm_init(void)
+{
+ return platform_driver_register(&audio_etm_driver);
+}
+module_init(audio_etm_init);
+
+void __exit audio_etm_exit(void)
+{
+ platform_driver_unregister(&audio_etm_driver);
+}
+module_exit(audio_etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Audio ETM driver");
diff --git a/drivers/coresight/coresight-modem-etm.c b/drivers/coresight/coresight-modem-etm.c
new file mode 100644
index 0000000..4c8075c
--- /dev/null
+++ b/drivers/coresight/coresight-modem-etm.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+struct modem_etm_drvdata {
+ struct device *dev;
+ struct coresight_device *csdev;
+};
+
+static int modem_etm_enable(struct coresight_device *csdev)
+{
+ struct modem_etm_drvdata *drvdata =
+ dev_get_drvdata(csdev->dev.parent);
+
+ dev_info(drvdata->dev, "Modem ETM tracing enabled\n");
+ return 0;
+}
+
+
+static void modem_etm_disable(struct coresight_device *csdev)
+{
+ struct modem_etm_drvdata *drvdata =
+ dev_get_drvdata(csdev->dev.parent);
+
+ dev_info(drvdata->dev, "Modem ETM tracing disabled\n");
+}
+
+static const struct coresight_ops_source modem_etm_source_ops = {
+ .enable = modem_etm_enable,
+ .disable = modem_etm_disable,
+};
+
+static const struct coresight_ops modem_cs_ops = {
+ .source_ops = &modem_etm_source_ops,
+};
+
+static int modem_etm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct coresight_platform_data *pdata;
+ struct modem_etm_drvdata *drvdata;
+ struct coresight_desc *desc;
+
+ if (pdev->dev.of_node) {
+ pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ pdev->dev.platform_data = pdata;
+ }
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+ desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+ desc->ops = &modem_cs_ops;
+ desc->pdata = pdev->dev.platform_data;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ drvdata->csdev = coresight_register(desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ dev_info(dev, "Modem ETM initialized\n");
+ return 0;
+}
+
+static int modem_etm_remove(struct platform_device *pdev)
+{
+ struct modem_etm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ coresight_unregister(drvdata->csdev);
+ return 0;
+}
+
+static struct of_device_id modem_etm_match[] = {
+ {.compatible = "qcom,coresight-modem-etm"},
+ {}
+};
+
+static struct platform_driver modem_etm_driver = {
+ .probe = modem_etm_probe,
+ .remove = modem_etm_remove,
+ .driver = {
+ .name = "coresight-modem-etm",
+ .owner = THIS_MODULE,
+ .of_match_table = modem_etm_match,
+ },
+};
+
+int __init modem_etm_init(void)
+{
+ return platform_driver_register(&modem_etm_driver);
+}
+module_init(modem_etm_init);
+
+void __exit modem_etm_exit(void)
+{
+ platform_driver_unregister(&modem_etm_driver);
+}
+module_exit(modem_etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Modem ETM driver");
diff --git a/drivers/coresight/coresight-rpm-etm.c b/drivers/coresight/coresight-rpm-etm.c
new file mode 100644
index 0000000..e752e4f
--- /dev/null
+++ b/drivers/coresight/coresight-rpm-etm.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+struct rpm_etm_drvdata {
+ struct device *dev;
+ struct coresight_device *csdev;
+};
+
+static int rpm_etm_enable(struct coresight_device *csdev)
+{
+ struct rpm_etm_drvdata *drvdata =
+ dev_get_drvdata(csdev->dev.parent);
+
+ dev_info(drvdata->dev, "RPM ETM tracing enabled\n");
+ return 0;
+}
+
+
+static void rpm_etm_disable(struct coresight_device *csdev)
+{
+ struct rpm_etm_drvdata *drvdata =
+ dev_get_drvdata(csdev->dev.parent);
+
+ dev_info(drvdata->dev, "RPM ETM tracing disabled\n");
+}
+
+static const struct coresight_ops_source rpm_etm_source_ops = {
+ .enable = rpm_etm_enable,
+ .disable = rpm_etm_disable,
+};
+
+static const struct coresight_ops rpm_cs_ops = {
+ .source_ops = &rpm_etm_source_ops,
+};
+
+static int rpm_etm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct coresight_platform_data *pdata;
+ struct rpm_etm_drvdata *drvdata;
+ struct coresight_desc *desc;
+
+ if (pdev->dev.of_node) {
+ pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ pdev->dev.platform_data = pdata;
+ }
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+ desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+ desc->ops = &rpm_cs_ops;
+ desc->pdata = pdev->dev.platform_data;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ drvdata->csdev = coresight_register(desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ dev_info(dev, "RPM ETM initialized\n");
+ return 0;
+}
+
+static int rpm_etm_remove(struct platform_device *pdev)
+{
+ struct rpm_etm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ coresight_unregister(drvdata->csdev);
+ return 0;
+}
+
+static struct of_device_id rpm_etm_match[] = {
+ {.compatible = "qcom,coresight-rpm-etm"},
+ {}
+};
+
+static struct platform_driver rpm_etm_driver = {
+ .probe = rpm_etm_probe,
+ .remove = rpm_etm_remove,
+ .driver = {
+ .name = "coresight-rpm-etm",
+ .owner = THIS_MODULE,
+ .of_match_table = rpm_etm_match,
+ },
+};
+
+int __init rpm_etm_init(void)
+{
+ return platform_driver_register(&rpm_etm_driver);
+}
+module_init(rpm_etm_init);
+
+void __exit rpm_etm_exit(void)
+{
+ platform_driver_unregister(&rpm_etm_driver);
+}
+module_exit(rpm_etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight RPM ETM driver");
diff --git a/drivers/coresight/coresight-wcn-etm.c b/drivers/coresight/coresight-wcn-etm.c
new file mode 100644
index 0000000..44852fb
--- /dev/null
+++ b/drivers/coresight/coresight-wcn-etm.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+
+struct wcn_etm_drvdata {
+ struct device *dev;
+ struct coresight_device *csdev;
+};
+
+static int wcn_etm_enable(struct coresight_device *csdev)
+{
+ struct wcn_etm_drvdata *drvdata =
+ dev_get_drvdata(csdev->dev.parent);
+
+ dev_info(drvdata->dev, "Wireless ETM tracing enabled\n");
+ return 0;
+}
+
+
+static void wcn_etm_disable(struct coresight_device *csdev)
+{
+ struct wcn_etm_drvdata *drvdata =
+ dev_get_drvdata(csdev->dev.parent);
+
+ dev_info(drvdata->dev, "Wireless ETM tracing disabled\n");
+}
+
+static const struct coresight_ops_source wcn_etm_source_ops = {
+ .enable = wcn_etm_enable,
+ .disable = wcn_etm_disable,
+};
+
+static const struct coresight_ops wcn_cs_ops = {
+ .source_ops = &wcn_etm_source_ops,
+};
+
+static int wcn_etm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct coresight_platform_data *pdata;
+ struct wcn_etm_drvdata *drvdata;
+ struct coresight_desc *desc;
+
+ if (pdev->dev.of_node) {
+ pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ pdev->dev.platform_data = pdata;
+ }
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->type = CORESIGHT_DEV_TYPE_SOURCE;
+ desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+ desc->ops = &wcn_cs_ops;
+ desc->pdata = pdev->dev.platform_data;
+ desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
+ drvdata->csdev = coresight_register(desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ dev_info(dev, "Wireless ETM initialized\n");
+ return 0;
+}
+
+static int wcn_etm_remove(struct platform_device *pdev)
+{
+ struct wcn_etm_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ coresight_unregister(drvdata->csdev);
+ return 0;
+}
+
+static struct of_device_id wcn_etm_match[] = {
+ {.compatible = "qcom,coresight-wcn-etm"},
+ {}
+};
+
+static struct platform_driver wcn_etm_driver = {
+ .probe = wcn_etm_probe,
+ .remove = wcn_etm_remove,
+ .driver = {
+ .name = "coresight-wcn-etm",
+ .owner = THIS_MODULE,
+ .of_match_table = wcn_etm_match,
+ },
+};
+
+int __init wcn_etm_init(void)
+{
+ return platform_driver_register(&wcn_etm_driver);
+}
+module_init(wcn_etm_init);
+
+void __exit wcn_etm_exit(void)
+{
+ platform_driver_unregister(&wcn_etm_driver);
+}
+module_exit(wcn_etm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Wireless ETM driver");
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index b393b21..eb45bd6 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -3669,6 +3669,8 @@
}
}
for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+ if (ft_detect_regs[i] == 0)
+ continue;
if (curr_reg_val[i] != prev_reg_val[i])
fast_hang_detected = 0;
}
@@ -3730,8 +3732,12 @@
/* If hangs are not detected copy the current reg values
* to previous values and return no hang */
- for (i = 0; i < FT_DETECT_REGS_COUNT; i++)
- prev_reg_val[i] = curr_reg_val[i];
+ for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
+ if (ft_detect_regs[i] == 0)
+ continue;
+ prev_reg_val[i] = curr_reg_val[i];
+ }
+
return 0;
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index ceff923..8aec755 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1073,7 +1073,7 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int *link = 0;
unsigned int *cmds;
- unsigned int i;
+ unsigned int i, cmdflags;
struct adreno_context *drawctxt = NULL;
unsigned int start_index = 0;
int ret;
@@ -1095,6 +1095,8 @@
goto done;
}
+ cmdflags = (flags & KGSL_CMD_FLAGS_EOF);
+
/* process any profiling results that are available into the log_buf */
adreno_profile_process_results(device);
@@ -1161,7 +1163,7 @@
if (test_and_clear_bit(ADRENO_DEVICE_PWRON, &adreno_dev->priv) &&
test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
- flags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
+ cmdflags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) {
@@ -1178,7 +1180,7 @@
ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
drawctxt,
- flags,
+ cmdflags,
&link[0], (cmds - link));
if (ret)
goto done;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index ecda5a7..a06ebbf 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -72,16 +72,18 @@
static struct iommu_access_ops *iommu_access_ops;
-static void _iommu_lock(void)
+static void _iommu_lock(struct kgsl_iommu const *iommu)
{
if (iommu_access_ops && iommu_access_ops->iommu_lock_acquire)
- iommu_access_ops->iommu_lock_acquire();
+ iommu_access_ops->iommu_lock_acquire(
+ iommu->sync_lock_initialized);
}
-static void _iommu_unlock(void)
+static void _iommu_unlock(struct kgsl_iommu const *iommu)
{
if (iommu_access_ops && iommu_access_ops->iommu_lock_release)
- iommu_access_ops->iommu_lock_release();
+ iommu_access_ops->iommu_lock_release(
+ iommu->sync_lock_initialized);
}
struct remote_iommu_petersons_spinlock kgsl_iommu_sync_lock_vars;
@@ -906,6 +908,8 @@
return 0;
}
+#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
+
/*
* kgsl_get_sync_lock - Init Sync Lock between GPU and CPU
* @mmu - Pointer to mmu device
@@ -973,6 +977,12 @@
return status;
}
+#else
+static int kgsl_iommu_init_sync_lock(struct kgsl_mmu *mmu)
+{
+ return 0;
+}
+#endif
/*
* kgsl_iommu_sync_lock - Acquire Sync Lock between GPU and CPU
@@ -1643,7 +1653,7 @@
* changing pagetables we can use this lsb value of the pagetable w/o
* having to read it again
*/
- _iommu_lock();
+ _iommu_lock(iommu);
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
for (j = 0; j < iommu_unit->dev_count; j++) {
@@ -1682,7 +1692,7 @@
}
}
kgsl_iommu_lock_rb_in_tlb(mmu);
- _iommu_unlock();
+ _iommu_unlock(iommu);
/* For complete CFF */
kgsl_cffdump_setmem(mmu->device, mmu->setstate_memory.gpuaddr +
@@ -1788,12 +1798,12 @@
for (j = 0; j < iommu_unit->dev_count; j++) {
if (iommu_unit->dev[j].fault) {
kgsl_iommu_enable_clk(mmu, j);
- _iommu_lock();
+ _iommu_lock(iommu);
KGSL_IOMMU_SET_CTX_REG(iommu,
iommu_unit,
iommu_unit->dev[j].ctx_id,
RESUME, 1);
- _iommu_unlock();
+ _iommu_unlock(iommu);
iommu_unit->dev[j].fault = 0;
}
}
@@ -1912,7 +1922,7 @@
kgsl_idle(mmu->device);
/* Acquire GPU-CPU sync Lock here */
- _iommu_lock();
+ _iommu_lock(iommu);
if (flags & KGSL_MMUFLAGS_PTUPDATE) {
if (!msm_soc_version_supports_iommu_v0())
@@ -1979,7 +1989,7 @@
}
/* Release GPU-CPU sync Lock here */
- _iommu_unlock();
+ _iommu_unlock(iommu);
/* Disable smmu clock */
kgsl_iommu_disable_clk_on_ts(mmu, 0, false);
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index f49ff14..a325d54 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -304,6 +304,28 @@
return 0;
}
+static int mma8x5x_device_start(struct i2c_client *client)
+{
+ struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+
+ if (i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0))
+ goto err_out;
+ if (i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG,
+ pdata->mode))
+ goto err_out;
+
+ /* The BT(boot time) for mma8x5x is 1.55ms according to
+ *Freescale mma8450Q document. Document Number:MMA8450Q
+ *Rev: 9.1, 04/2012
+ */
+ usleep_range(1600, 2000);
+ return 0;
+
+err_out:
+ dev_err(&client->dev, "%s:start device failed", __func__);
+ return -EIO;
+}
+
static int mma8x5x_read_data(struct i2c_client *client,
struct mma8x5x_data_axis *data)
{
@@ -381,32 +403,73 @@
int ret;
unsigned long enable;
u8 val = 0;
+
ret = kstrtoul(buf, 10, &enable);
if (ret)
return ret;
mutex_lock(&pdata->data_lock);
enable = (enable > 0) ? 1 : 0;
- if (enable && pdata->active == MMA_STANDBY) {
- val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
- ret = i2c_smbus_write_byte_data(client,
- MMA8X5X_CTRL_REG1, val|0x01);
- if (!ret) {
+ if (enable) {
+ if (pdata->active & MMA_SHUTTEDDOWN) {
+ ret = mma8x5x_config_regulator(client, 1);
+ if (ret)
+ goto err_failed;
+
+ ret = mma8x5x_device_start(client);
+ if (ret)
+ goto err_failed;
+
+ pdata->active &= ~MMA_SHUTTEDDOWN;
+ }
+ if (pdata->active == MMA_STANDBY) {
+ val = i2c_smbus_read_byte_data(client,
+ MMA8X5X_CTRL_REG1);
+ if (val < 0) {
+ dev_err(dev, "read device state failed!");
+ ret = val;
+ goto err_failed;
+ }
+
+ ret = i2c_smbus_write_byte_data(client,
+ MMA8X5X_CTRL_REG1, val | 0x01);
+ if (ret) {
+ dev_err(dev, "change device state failed!");
+ goto err_failed;
+ }
pdata->active = MMA_ACTIVED;
- dev_dbg(dev,
- "%s:mma enable setting active.\n", __func__);
+ dev_dbg(dev, "%s:mma enable setting active.\n",
+ __func__);
}
- } else if (enable == 0 && pdata->active == MMA_ACTIVED) {
- val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
- ret = i2c_smbus_write_byte_data(client,
- MMA8X5X_CTRL_REG1, val & 0xFE);
- if (!ret) {
+ } else if (enable == 0) {
+ if (pdata->active == MMA_ACTIVED) {
+ val = i2c_smbus_read_byte_data(client,
+ MMA8X5X_CTRL_REG1);
+ if (val < 0) {
+ dev_err(dev, "read device state failed!");
+ ret = val;
+ goto err_failed;
+ }
+
+ ret = i2c_smbus_write_byte_data(client,
+ MMA8X5X_CTRL_REG1, val & 0xFE);
+ if (ret) {
+ dev_err(dev, "change device state failed!");
+ goto err_failed;
+ }
+
pdata->active = MMA_STANDBY;
- dev_dbg(dev,
- "%s:mma enable setting inactive.\n", __func__);
+ dev_dbg(dev, "%s:mma enable setting inactive.\n",
+ __func__);
}
+ if (!mma8x5x_config_regulator(client, 0))
+ pdata->active |= MMA_SHUTTEDDOWN;
}
mutex_unlock(&pdata->data_lock);
return count;
+
+err_failed:
+ mutex_unlock(&pdata->data_lock);
+ return ret;
}
static ssize_t mma8x5x_position_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -617,6 +680,8 @@
struct mma8x5x_data *pdata = i2c_get_clientdata(client);
if (pdata->active == MMA_ACTIVED)
mma8x5x_device_stop(client);
+ if (pdata->active & MMA_SHUTTEDDOWN)
+ return 0;
if (!mma8x5x_config_regulator(client, 0))
/* The highest bit sotres the power state */
pdata->active |= MMA_SHUTTEDDOWN;
@@ -628,22 +693,16 @@
int val = 0;
struct i2c_client *client = to_i2c_client(dev);
struct mma8x5x_data *pdata = i2c_get_clientdata(client);
+
+ /* No need to power on while device is shutdowned from standby state */
+ if (pdata->active == (MMA_SHUTTEDDOWN | MMA_STANDBY))
+ return 0;
if (pdata->active & MMA_SHUTTEDDOWN) {
if (mma8x5x_config_regulator(client, 1))
goto out;
- if (i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, 0))
+ if (mma8x5x_device_start(client))
goto out;
-
- if (i2c_smbus_write_byte_data(client, MMA8X5X_XYZ_DATA_CFG,
- pdata->mode))
- goto out;
-
- /* The BT(boot time) for mma8x5x is 1.55ms according to
- Freescale mma8450Q document. Document Number:MMA8450Q
- Rev: 9.1, 04/2012
- */
- usleep_range(1600, 2000);
pdata->active &= ~MMA_SHUTTEDDOWN;
}
if (pdata->active == MMA_ACTIVED) {
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index 367a987..aa50d44 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -336,7 +336,6 @@
input_report_abs(ip_dev, ABS_MT_PRESSURE, pressure);
} else {
input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0);
- input_report_abs(ip_dev, ABS_MT_PRESSURE, 0);
}
}
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 6324dff..8e70129 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -45,10 +45,22 @@
If unsure, say N here.
+# MSM IOMMU sync lock support
+config MSM_IOMMU_SYNC
+ bool "MSM IOMMU Sync Lock Support"
+ depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930 || ARCH_MSM8610) && MSM_IOMMU_V0
+ help
+ Say Y here if you want the IOMMU to grab a remote spinlock to ensure
+ synchronization between IOMMU accesses by CPU and other exectution
+ environments in the SoC.
+
+ If unsure, say N here.
+
# MSM IOMMU CPU-GPU sync programming support
config MSM_IOMMU_GPU_SYNC
bool "MSM IOMMU CPU-GPU Sync Support"
- depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930) && MSM_IOMMU_V0 && MSM_REMOTE_SPINLOCK_SFPB
+ depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_APQ8064 || ARCH_MSM8930) && MSM_IOMMU_V0
+ select MSM_IOMMU_SYNC
help
Say Y here if you want to synchronize access to IOMMU configuration
port between CPU and GPU. CPU will grab a remote spinlock before
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index 49bfdb8..99d071b 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -83,7 +83,7 @@
static struct msm_iommu_remote_lock msm_iommu_remote_lock;
-#ifdef CONFIG_MSM_IOMMU_GPU_SYNC
+#ifdef CONFIG_MSM_IOMMU_SYNC
static void _msm_iommu_remote_spin_lock_init(void)
{
msm_iommu_remote_lock.lock = smem_alloc(SMEM_SPINLOCK_ARRAY, 32);
@@ -91,8 +91,11 @@
sizeof(*msm_iommu_remote_lock.lock));
}
-void msm_iommu_remote_p0_spin_lock(void)
+void msm_iommu_remote_p0_spin_lock(unsigned int need_lock)
{
+ if (!need_lock)
+ return;
+
msm_iommu_remote_lock.lock->flag[PROC_APPS] = 1;
msm_iommu_remote_lock.lock->turn = 1;
@@ -103,8 +106,11 @@
cpu_relax();
}
-void msm_iommu_remote_p0_spin_unlock(void)
+void msm_iommu_remote_p0_spin_unlock(unsigned int need_lock)
{
+ if (!need_lock)
+ return;
+
smp_mb();
msm_iommu_remote_lock.lock->flag[PROC_APPS] = 0;
@@ -200,14 +206,16 @@
return msm_iommu_lock_initialize();
}
-static void _iommu_lock_acquire(void)
+static void _iommu_lock_acquire(unsigned int need_extra_lock)
{
- msm_iommu_lock();
+ msm_iommu_mutex_lock();
+ msm_iommu_remote_spin_lock(need_extra_lock);
}
-static void _iommu_lock_release(void)
+static void _iommu_lock_release(unsigned int need_extra_lock)
{
- msm_iommu_unlock();
+ msm_iommu_remote_spin_unlock(need_extra_lock);
+ msm_iommu_mutex_unlock();
}
struct iommu_access_ops iommu_access_ops_v0 = {
@@ -241,7 +249,7 @@
if (ret)
goto fail;
- msm_iommu_remote_spin_lock();
+ msm_iommu_remote_spin_lock(iommu_drvdata->needs_rem_spinlock);
asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
ctx_drvdata->num);
@@ -250,7 +258,7 @@
asid | (va & TLBIVA_VA));
mb();
- msm_iommu_remote_spin_unlock();
+ msm_iommu_remote_spin_unlock(iommu_drvdata->needs_rem_spinlock);
__disable_clocks(iommu_drvdata);
}
@@ -278,7 +286,7 @@
if (ret)
goto fail;
- msm_iommu_remote_spin_lock();
+ msm_iommu_remote_spin_lock(iommu_drvdata->needs_rem_spinlock);
asid = GET_CONTEXTIDR_ASID(iommu_drvdata->base,
ctx_drvdata->num);
@@ -286,7 +294,7 @@
SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, asid);
mb();
- msm_iommu_remote_spin_unlock();
+ msm_iommu_remote_spin_unlock(iommu_drvdata->needs_rem_spinlock);
__disable_clocks(iommu_drvdata);
}
@@ -318,13 +326,16 @@
mb();
}
-static void __program_context(void __iomem *base, void __iomem *glb_base,
+static void __program_context(struct msm_iommu_drvdata *iommu_drvdata,
int ctx, int ncb, phys_addr_t pgtable,
int redirect, int ttbr_split)
{
+ void __iomem *base = iommu_drvdata->base;
+ void __iomem *glb_base = iommu_drvdata->glb_base;
unsigned int prrr, nmrr;
int i, j, found;
- msm_iommu_remote_spin_lock();
+
+ msm_iommu_remote_spin_lock(iommu_drvdata->needs_rem_spinlock);
__reset_context(base, glb_base, ctx);
@@ -416,7 +427,7 @@
SET_M(base, ctx, 1);
mb();
- msm_iommu_remote_spin_unlock();
+ msm_iommu_remote_spin_unlock(iommu_drvdata->needs_rem_spinlock);
}
static int msm_iommu_domain_init(struct iommu_domain *domain, int flags)
@@ -526,7 +537,7 @@
if (ret)
goto unlock;
- __program_context(iommu_drvdata->base, iommu_drvdata->glb_base,
+ __program_context(iommu_drvdata,
ctx_drvdata->num, iommu_drvdata->ncb,
__pa(priv->pt.fl_table), priv->pt.redirect,
iommu_drvdata->ttbr_split);
@@ -577,7 +588,7 @@
if (ret)
goto unlock;
- msm_iommu_remote_spin_lock();
+ msm_iommu_remote_spin_lock(iommu_drvdata->needs_rem_spinlock);
SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num,
GET_CONTEXTIDR_ASID(iommu_drvdata->base, ctx_drvdata->num));
@@ -585,7 +596,7 @@
__reset_context(iommu_drvdata->base, iommu_drvdata->glb_base,
ctx_drvdata->num);
- msm_iommu_remote_spin_unlock();
+ msm_iommu_remote_spin_unlock(iommu_drvdata->needs_rem_spinlock);
__disable_clocks(iommu_drvdata);
@@ -1246,7 +1257,7 @@
if (ret)
goto fail;
- msm_iommu_remote_spin_lock();
+ msm_iommu_remote_spin_lock(iommu_drvdata->needs_rem_spinlock);
SET_V2PPR(base, ctx, va & V2Pxx_VA);
@@ -1262,7 +1273,7 @@
if (GET_FAULT(base, ctx))
ret = 0;
- msm_iommu_remote_spin_unlock();
+ msm_iommu_remote_spin_unlock(iommu_drvdata->needs_rem_spinlock);
__disable_clocks(iommu_drvdata);
fail:
@@ -1324,7 +1335,7 @@
if (ret)
goto fail;
- msm_iommu_remote_spin_lock();
+ msm_iommu_remote_spin_lock(drvdata->needs_rem_spinlock);
fsr = GET_FSR(base, num);
@@ -1357,7 +1368,7 @@
} else
ret = IRQ_NONE;
- msm_iommu_remote_spin_unlock();
+ msm_iommu_remote_spin_unlock(drvdata->needs_rem_spinlock);
__disable_clocks(drvdata);
fail:
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index b9c4cae..c81aa0ac 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -123,12 +123,12 @@
clk_disable_unprepare(drvdata->pclk);
}
-static void _iommu_lock_acquire(void)
+static void _iommu_lock_acquire(unsigned int need_extra_lock)
{
mutex_lock(&msm_iommu_lock);
}
-static void _iommu_lock_release(void)
+static void _iommu_lock_release(unsigned int need_extra_lock)
{
mutex_unlock(&msm_iommu_lock);
}
diff --git a/drivers/iommu/msm_iommu_dev-v0.c b/drivers/iommu/msm_iommu_dev-v0.c
index 2d0fba2..9382e52 100644
--- a/drivers/iommu/msm_iommu_dev-v0.c
+++ b/drivers/iommu/msm_iommu_dev-v0.c
@@ -216,6 +216,12 @@
drvdata->sec_id = -1;
drvdata->ttbr_split = 0;
+ drvdata->needs_rem_spinlock = of_property_read_bool(pdev->dev.of_node,
+ "qcom,msm-enable-remote-spinlock");
+
+ if (drvdata->needs_rem_spinlock)
+ pr_info("%s enabled remote spinlock\n", drvdata->name);
+
ret = of_platform_populate(pdev->dev.of_node,
msm_iommu_v0_ctx_match_table,
NULL, &pdev->dev);
diff --git a/drivers/iommu/msm_iommu_perfmon-v0.c b/drivers/iommu/msm_iommu_perfmon-v0.c
index 1073623..b08a9ec 100644
--- a/drivers/iommu/msm_iommu_perfmon-v0.c
+++ b/drivers/iommu/msm_iommu_perfmon-v0.c
@@ -176,9 +176,9 @@
goto out;
}
- iommu->ops->iommu_lock_acquire();
+ iommu->ops->iommu_lock_acquire(1);
iommu_pm_check_for_overflow(pmon);
- iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_lock_release(1);
mutex_unlock(&pmon->lock);
diff --git a/drivers/iommu/msm_iommu_perfmon-v1.c b/drivers/iommu/msm_iommu_perfmon-v1.c
index 7d6dd34..2b55184 100644
--- a/drivers/iommu/msm_iommu_perfmon-v1.c
+++ b/drivers/iommu/msm_iommu_perfmon-v1.c
@@ -151,9 +151,9 @@
goto out;
}
- iommu->ops->iommu_lock_acquire();
+ iommu->ops->iommu_lock_acquire(0);
iommu_pm_check_for_overflow(pmon);
- iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_lock_release(0);
mutex_unlock(&pmon->lock);
diff --git a/drivers/iommu/msm_iommu_perfmon.c b/drivers/iommu/msm_iommu_perfmon.c
index 958c6ca..503d4ab 100644
--- a/drivers/iommu/msm_iommu_perfmon.c
+++ b/drivers/iommu/msm_iommu_perfmon.c
@@ -188,11 +188,11 @@
if (event_class == MSM_IOMMU_PMU_NO_EVENT_CLASS) {
if (iommu->hw_ops->is_hw_access_OK(pmon)) {
- iommu->ops->iommu_lock_acquire();
+ iommu->ops->iommu_lock_acquire(1);
iommu->hw_ops->counter_disable(iommu, counter);
iommu->hw_ops->ovfl_int_disable(iommu, counter);
iommu->hw_ops->set_event_class(pmon, count_no, 0);
- iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_lock_release(1);
}
counter->overflow_count = 0;
counter->value = 0;
@@ -200,12 +200,12 @@
counter->overflow_count = 0;
counter->value = 0;
if (iommu->hw_ops->is_hw_access_OK(pmon)) {
- iommu->ops->iommu_lock_acquire();
+ iommu->ops->iommu_lock_acquire(1);
iommu->hw_ops->set_event_class(pmon, count_no,
event_class);
iommu->hw_ops->ovfl_int_enable(iommu, counter);
iommu->hw_ops->counter_enable(iommu, counter);
- iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_lock_release(1);
}
}
}
@@ -261,9 +261,9 @@
iommu->ops->iommu_clk_on(iommu_drvdata);
/* Reset counters in HW */
- iommu->ops->iommu_lock_acquire();
+ iommu->ops->iommu_lock_acquire(1);
iommu->hw_ops->reset_counters(&pmon->iommu);
- iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_lock_release(1);
/* Reset SW counters */
iommu_pm_reset_counts(pmon);
@@ -272,7 +272,7 @@
iommu_pm_set_all_counters(pmon);
- iommu->ops->iommu_lock_acquire();
+ iommu->ops->iommu_lock_acquire(1);
/* enable all counter group */
for (i = 0; i < pmon->num_groups; ++i)
@@ -280,7 +280,7 @@
/* enable global counters */
iommu->hw_ops->enable_pm(iommu);
- iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_lock_release(1);
pr_info("%s: TLB performance monitoring turned ON\n",
pmon->iommu.iommu_name);
@@ -295,7 +295,7 @@
pmon->enabled = 0;
- iommu->ops->iommu_lock_acquire();
+ iommu->ops->iommu_lock_acquire(1);
/* disable global counters */
iommu->hw_ops->disable_pm(iommu);
@@ -310,7 +310,7 @@
/* Update cached copy of counters before turning off power */
iommu_pm_read_all_counters(pmon);
- iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_lock_release(1);
iommu->ops->iommu_clk_off(iommu_drvdata);
iommu->ops->iommu_bus_vote(iommu_drvdata, 0);
iommu->ops->iommu_power_off(iommu_drvdata);
@@ -341,9 +341,9 @@
mutex_lock(&pmon->lock);
if (iommu->hw_ops->is_hw_access_OK(pmon)) {
- iommu->ops->iommu_lock_acquire();
+ iommu->ops->iommu_lock_acquire(1);
counter->value = iommu->hw_ops->read_counter(counter);
- iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_lock_release(1);
}
full_count = (unsigned long long) counter->value +
((unsigned long long)counter->overflow_count *
@@ -448,9 +448,9 @@
rv = kstrtoul(buf, 10, &cmd);
if (!rv && (cmd == 1)) {
if (iommu->hw_ops->is_hw_access_OK(pmon)) {
- iommu->ops->iommu_lock_acquire();
+ iommu->ops->iommu_lock_acquire(1);
iommu->hw_ops->reset_counters(&pmon->iommu);
- iommu->ops->iommu_lock_release();
+ iommu->ops->iommu_lock_release(1);
}
iommu_pm_reset_counts(pmon);
pr_info("TLB performance counters reset\n");
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 474efdf..5a1806e 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -194,7 +194,7 @@
struct msm_scm_fault_regs_dump *regs;
int tmp, ret = IRQ_HANDLED;
- iommu_access_ops->iommu_lock_acquire();
+ iommu_access_ops->iommu_lock_acquire(0);
BUG_ON(!pdev);
@@ -266,7 +266,7 @@
free_regs:
kfree(regs);
lock_release:
- iommu_access_ops->iommu_lock_release();
+ iommu_access_ops->iommu_lock_release(0);
return ret;
}
@@ -510,12 +510,12 @@
{
struct msm_iommu_priv *priv;
- iommu_access_ops->iommu_lock_acquire();
+ iommu_access_ops->iommu_lock_acquire(0);
priv = domain->priv;
domain->priv = NULL;
kfree(priv);
- iommu_access_ops->iommu_lock_release();
+ iommu_access_ops->iommu_lock_release(0);
}
static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
@@ -526,7 +526,7 @@
struct msm_iommu_ctx_drvdata *tmp_drvdata;
int ret = 0;
- iommu_access_ops->iommu_lock_acquire();
+ iommu_access_ops->iommu_lock_acquire(0);
priv = domain->priv;
if (!priv || !dev) {
@@ -581,12 +581,12 @@
ctx_drvdata->attached_domain = domain;
++iommu_drvdata->ctx_attach_count;
- iommu_access_ops->iommu_lock_release();
+ iommu_access_ops->iommu_lock_release(0);
msm_iommu_attached(dev->parent);
return ret;
fail:
- iommu_access_ops->iommu_lock_release();
+ iommu_access_ops->iommu_lock_release(0);
return ret;
}
@@ -598,7 +598,7 @@
msm_iommu_detached(dev->parent);
- iommu_access_ops->iommu_lock_acquire();
+ iommu_access_ops->iommu_lock_acquire(0);
if (!dev)
goto fail;
@@ -614,7 +614,7 @@
BUG_ON(iommu_drvdata->ctx_attach_count == 0);
--iommu_drvdata->ctx_attach_count;
fail:
- iommu_access_ops->iommu_lock_release();
+ iommu_access_ops->iommu_lock_release(0);
}
static int get_drvdata(struct iommu_domain *domain,
@@ -644,7 +644,7 @@
struct msm_iommu_ctx_drvdata *ctx_drvdata;
int ret = 0;
- iommu_access_ops->iommu_lock_acquire();
+ iommu_access_ops->iommu_lock_acquire(0);
ret = get_drvdata(domain, &iommu_drvdata, &ctx_drvdata);
if (ret)
@@ -655,7 +655,7 @@
va, pa, len);
iommu_access_ops->iommu_clk_off(iommu_drvdata);
fail:
- iommu_access_ops->iommu_lock_release();
+ iommu_access_ops->iommu_lock_release(0);
return ret;
}
@@ -666,7 +666,7 @@
struct msm_iommu_ctx_drvdata *ctx_drvdata;
int ret = -ENODEV;
- iommu_access_ops->iommu_lock_acquire();
+ iommu_access_ops->iommu_lock_acquire(0);
ret = get_drvdata(domain, &iommu_drvdata, &ctx_drvdata);
if (ret)
@@ -677,7 +677,7 @@
va, len);
iommu_access_ops->iommu_clk_off(iommu_drvdata);
fail:
- iommu_access_ops->iommu_lock_release();
+ iommu_access_ops->iommu_lock_release(0);
/* the IOMMU API requires us to return how many bytes were unmapped */
len = ret ? 0 : len;
@@ -692,7 +692,7 @@
struct msm_iommu_drvdata *iommu_drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata;
- iommu_access_ops->iommu_lock_acquire();
+ iommu_access_ops->iommu_lock_acquire(0);
ret = get_drvdata(domain, &iommu_drvdata, &ctx_drvdata);
if (ret)
@@ -702,7 +702,7 @@
va, sg, len);
iommu_access_ops->iommu_clk_off(iommu_drvdata);
fail:
- iommu_access_ops->iommu_lock_release();
+ iommu_access_ops->iommu_lock_release(0);
return ret;
}
@@ -714,7 +714,7 @@
struct msm_iommu_ctx_drvdata *ctx_drvdata;
int ret;
- iommu_access_ops->iommu_lock_acquire();
+ iommu_access_ops->iommu_lock_acquire(0);
ret = get_drvdata(domain, &iommu_drvdata, &ctx_drvdata);
if (ret)
@@ -725,7 +725,7 @@
iommu_access_ops->iommu_clk_off(iommu_drvdata);
fail:
- iommu_access_ops->iommu_lock_release();
+ iommu_access_ops->iommu_lock_release(0);
return 0;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 4aa423f..87bffde 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/delay.h>
+#include <linux/avtimer.h>
#include <media/v4l2-subdev.h>
#include <media/msmb_isp.h>
#include <mach/msm_bus.h>
@@ -35,6 +36,10 @@
#define MAX_INIT_FRAME_DROP 31
#define ISP_Q2 (1 << 2)
+#define AVTIMER_MSW_PHY_ADDR 0xFE05300C
+#define AVTIMER_LSW_PHY_ADDR 0xFE053008
+#define AVTIMER_ITERATION_CTR 16
+
#define VFE_PING_FLAG 0xFFFFFFFF
#define VFE_PONG_FLAG 0x0
@@ -69,6 +74,8 @@
struct msm_isp_timestamp {
/*Monotonic clock for v4l2 buffer*/
struct timeval buf_time;
+ /*Monotonic clock for VT */
+ struct timeval vt_time;
/*Wall clock for userspace event*/
struct timeval event_time;
};
@@ -263,7 +270,7 @@
uint32_t stream_handle;
uint8_t buf_divert;
enum msm_vfe_axi_stream_type stream_type;
-
+ uint32_t vt_enable;
uint32_t frame_based;
uint32_t framedrop_period;
uint32_t framedrop_pattern;
@@ -436,6 +443,9 @@
int dump_reg;
int vfe_clk_idx;
uint32_t vfe_open_cnt;
+ uint8_t vt_enable;
+ void __iomem *p_avtimer_msw;
+ void __iomem *p_avtimer_lsw;
};
#endif
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index f547b0e..4f3094a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -524,7 +524,16 @@
}
msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
-
+ stream_info->vt_enable = stream_cfg_cmd->vt_enable;
+ if (stream_info->vt_enable) {
+ vfe_dev->vt_enable = stream_info->vt_enable;
+ #ifdef CONFIG_MSM_AVTIMER
+ avcs_core_open();
+ avcs_core_disable_power_collapse(1);
+ #endif
+ vfe_dev->p_avtimer_lsw = ioremap(AVTIMER_LSW_PHY_ADDR, 4);
+ vfe_dev->p_avtimer_msw = ioremap(AVTIMER_MSW_PHY_ADDR, 4);
+ }
if (stream_info->num_planes > 1) {
msm_isp_axi_reserve_comp_mask(
&vfe_dev->axi_data, stream_info);
@@ -783,15 +792,21 @@
{
int rc;
struct msm_isp_event_data buf_event;
+ struct timeval *time_stamp;
uint32_t stream_idx = HANDLE_TO_IDX(stream_info->stream_handle);
uint32_t frame_id = vfe_dev->axi_data.
src_info[SRC_TO_INTF(stream_info->stream_src)].frame_id;
if (buf && ts) {
+ if (vfe_dev->vt_enable) {
+ time_stamp = &ts->vt_time;
+ } else {
+ time_stamp = &ts->buf_time;
+ }
if (stream_info->buf_divert) {
rc = vfe_dev->buf_mgr->ops->buf_divert(vfe_dev->buf_mgr,
buf->bufq_handle, buf->buf_idx,
- &ts->buf_time, frame_id);
+ time_stamp, frame_id);
/* Buf divert return value represent whether the buf
* can be diverted. A positive return value means
* other ISP hardware is still processing the frame.
@@ -800,7 +815,7 @@
buf_event.input_intf =
SRC_TO_INTF(stream_info->stream_src);
buf_event.frame_id = frame_id;
- buf_event.timestamp = ts->buf_time;
+ buf_event.timestamp = *time_stamp;
buf_event.u.buf_done.session_id =
stream_info->session_id;
buf_event.u.buf_done.stream_id =
@@ -817,7 +832,7 @@
} else {
vfe_dev->buf_mgr->ops->buf_done(vfe_dev->buf_mgr,
buf->bufq_handle, buf->buf_idx,
- &ts->buf_time, frame_id,
+ time_stamp, frame_id,
stream_info->runtime_output_format);
}
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index b024569..5f36a4a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -193,6 +193,32 @@
do_gettimeofday(&(time_stamp->event_time));
}
+static inline void msm_isp_get_vt_tstamp(struct vfe_device *vfe_dev,
+ struct msm_isp_timestamp *time_stamp)
+{
+ uint32_t avtimer_msw_1st = 0, avtimer_lsw = 0;
+ uint32_t avtimer_msw_2nd = 0;
+ uint8_t iter = 0;
+ if (!vfe_dev->p_avtimer_msw || !vfe_dev->p_avtimer_lsw) {
+ pr_err("%s: ioremap failed\n", __func__);
+ return;
+ }
+ do {
+ avtimer_msw_1st = msm_camera_io_r(vfe_dev->p_avtimer_msw);
+ avtimer_lsw = msm_camera_io_r(vfe_dev->p_avtimer_lsw);
+ avtimer_msw_2nd = msm_camera_io_r(vfe_dev->p_avtimer_msw);
+ } while ((avtimer_msw_1st != avtimer_msw_2nd)
+ && (iter++ < AVTIMER_ITERATION_CTR));
+ /*Just return if the MSW TimeStamps don't converge after
+ a few iterations Application needs to handle the zero TS values*/
+ if (iter >= AVTIMER_ITERATION_CTR) {
+ pr_err("%s: AVTimer MSW TS did not converge !!!\n", __func__);
+ return;
+ }
+ time_stamp->vt_time.tv_sec = avtimer_msw_1st;
+ time_stamp->vt_time.tv_usec = avtimer_lsw;
+}
+
int msm_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
struct v4l2_event_subscription *sub)
{
@@ -885,6 +911,8 @@
queue_cmd->vfeInterruptStatus0 = irq_status0;
queue_cmd->vfeInterruptStatus1 = irq_status1;
msm_isp_get_timestamp(&queue_cmd->ts);
+ if (vfe_dev->vt_enable)
+ msm_isp_get_vt_tstamp(vfe_dev, &queue_cmd->ts);
queue_cmd->cmd_used = 1;
vfe_dev->taskletq_idx =
(vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE;
@@ -998,6 +1026,9 @@
vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info;
vfe_dev->vfe_open_cnt++;
vfe_dev->taskletq_idx = 0;
+ vfe_dev->vt_enable = 0;
+ vfe_dev->p_avtimer_lsw = NULL;
+ vfe_dev->p_avtimer_msw = NULL;
mutex_unlock(&vfe_dev->core_mutex);
mutex_unlock(&vfe_dev->realtime_mutex);
return 0;
@@ -1024,6 +1055,14 @@
vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr);
vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
vfe_dev->vfe_open_cnt--;
+ if (vfe_dev->vt_enable) {
+ iounmap(vfe_dev->p_avtimer_lsw);
+ iounmap(vfe_dev->p_avtimer_msw);
+ #ifdef CONFIG_MSM_AVTIMER
+ avcs_core_disable_power_collapse(0);
+ #endif
+ vfe_dev->vt_enable = 0;
+ }
mutex_unlock(&vfe_dev->core_mutex);
mutex_unlock(&vfe_dev->realtime_mutex);
return 0;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index e011793..280a9a0 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -9,6 +9,7 @@
obj-$(CONFIG_IMX135) += imx135.o
obj-$(CONFIG_IMX134) += imx134.o
obj-$(CONFIG_OV8825) += ov8825.o
+obj-$(CONFIG_OV8865) += ov8865.o
obj-$(CONFIG_s5k4e1) += s5k4e1.o
obj-$(CONFIG_OV12830) += ov12830.o
obj-$(CONFIG_OV2720) += ov2720.o
@@ -18,4 +19,3 @@
obj-$(CONFIG_MT9M114) += mt9m114.o
obj-$(CONFIG_SP1628) += sp1628.o
obj-$(CONFIG_GC0339) += gc0339.o
-obj-$(CONFIG_OV8865) += ov8865.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
index 835230e..a10d60e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
@@ -33,7 +33,7 @@
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_STANDBY,
.config_val = GPIO_OUT_LOW,
- .delay = 20,
+ .delay = 0,
},
{
.seq_type = SENSOR_GPIO,
@@ -63,13 +63,13 @@
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 24000000,
- .delay = 10,
+ .delay = 5,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_STANDBY,
.config_val = GPIO_OUT_LOW,
- .delay = 20,
+ .delay = 0,
},
{
.seq_type = SENSOR_GPIO,
@@ -81,7 +81,7 @@
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_HIGH,
- .delay = 30,
+ .delay = 1,
},
{
.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 1dba2b6..e982feb 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -371,6 +371,9 @@
case HAL_BUFFER_MODE_RING:
buf_mode = HFI_BUFFER_MODE_RING;
break;
+ case HAL_BUFFER_MODE_DYNAMIC:
+ buf_mode = HFI_BUFFER_MODE_DYNAMIC;
+ break;
default:
dprintk(VIDC_ERR, "Invalid buffer mode :0x%x\n",
hal_buf_mode);
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 8cbce83..2bd038d 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -163,6 +163,38 @@
callback(VIDC_EVENT_CHANGE, &cmd_done);
}
+static void hfi_process_evt_release_buffer_ref(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_event_notify_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done = {0};
+ struct msm_vidc_cb_event event_notify = {0};
+
+ struct hfi_msg_release_buffer_ref_event_packet *data;
+
+ dprintk(VIDC_DBG, "RECEIVED:EVENT_NOTIFY - release_buffer_reference");
+ if (sizeof(struct hfi_msg_event_notify_packet)
+ > pkt->size) {
+ dprintk(VIDC_ERR, "hal_process_session_init_done:bad_pkt_size");
+ return;
+ }
+
+ data = (struct hfi_msg_release_buffer_ref_event_packet *)
+ pkt->rg_ext_event_data;
+
+ cmd_done.device_id = device_id;
+ cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
+ session_id;
+ cmd_done.status = VIDC_ERR_NONE;
+ cmd_done.size = sizeof(struct msm_vidc_cb_event);
+
+ event_notify.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE;
+ event_notify.packet_buffer = data->packet_buffer;
+ event_notify.exra_data_buffer = data->exra_data_buffer;
+ cmd_done.data = &event_notify;
+ callback(VIDC_EVENT_CHANGE, &cmd_done);
+}
+
static void hfi_process_sys_error(
msm_vidc_callback callback, u32 device_id)
{
@@ -180,7 +212,19 @@
cmd_done.device_id = device_id;
cmd_done.session_id = ((struct hal_session *) pkt->session_id)->
session_id;
- callback(SESSION_ERROR, &cmd_done);
+ dprintk(VIDC_INFO, "Received : SESSION_ERROR with event id : %d\n",
+ pkt->event_data1);
+ switch (pkt->event_data1) {
+ case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
+ case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
+ case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
+ dprintk(VIDC_INFO, "Non Fatal : HFI_EVENT_SESSION_ERROR\n");
+ break;
+ default:
+ dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR\n");
+ callback(SESSION_ERROR, &cmd_done);
+ break;
+ }
}
static void hfi_process_event_notify(
msm_vidc_callback callback, u32 device_id,
@@ -204,7 +248,7 @@
hfi_process_sys_error(callback, device_id);
break;
case HFI_EVENT_SESSION_ERROR:
- dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR");
+ dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR");
if (!validate_session_pkt(sessions, sess, session_lock))
hfi_process_session_error(callback, device_id, pkt);
break;
@@ -217,6 +261,10 @@
case HFI_EVENT_SESSION_PROPERTY_CHANGED:
dprintk(VIDC_INFO, "HFI_EVENT_SESSION_PROPERTY_CHANGED");
break;
+ case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
+ dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE\n");
+ hfi_process_evt_release_buffer_ref(callback, device_id, pkt);
+ break;
default:
dprintk(VIDC_WARN, "hal_process_event_notify:unkown_event_id");
break;
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index afd7200..81afd5c 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -27,7 +27,6 @@
#include "msm_vidc_internal.h"
#include "msm_vidc_debug.h"
#include "vidc_hfi_api.h"
-#include "msm_smem.h"
#include "vidc_hfi_api.h"
#include "msm_vidc_resources.h"
#include "msm_vidc_res_parse.h"
@@ -38,258 +37,44 @@
uint32_t msm_vidc_pwr_collapse_delay = 2000;
-struct buffer_info {
- struct list_head list;
- int type;
- int num_planes;
- int fd[VIDEO_MAX_PLANES];
- int buff_off[VIDEO_MAX_PLANES];
- int size[VIDEO_MAX_PLANES];
- u32 uvaddr[VIDEO_MAX_PLANES];
- u32 device_addr[VIDEO_MAX_PLANES];
- struct msm_smem *handle[VIDEO_MAX_PLANES];
-};
-
-struct msm_v4l2_vid_inst {
- struct msm_vidc_inst *vidc_inst;
- void *mem_client;
- struct list_head registered_bufs;
-};
-
static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
{
return container_of(filp->private_data,
struct msm_vidc_inst, event_handler);
}
-static inline struct msm_v4l2_vid_inst *get_v4l2_inst(struct file *filp,
- void *fh)
-{
- struct msm_vidc_inst *vidc_inst;
- vidc_inst = container_of(filp->private_data,
- struct msm_vidc_inst, event_handler);
- return (struct msm_v4l2_vid_inst *)vidc_inst->priv;
-}
-
-struct buffer_info *get_registered_buf(struct list_head *list,
- int fd, u32 buff_off, u32 size, int *plane)
-{
- struct buffer_info *temp;
- struct buffer_info *ret = NULL;
- int i;
- if (!list || fd < 0 || !plane) {
- dprintk(VIDC_ERR, "Invalid input\n");
- goto err_invalid_input;
- }
- *plane = 0;
- if (!list_empty(list)) {
- list_for_each_entry(temp, list, list) {
- for (i = 0; (i < temp->num_planes)
- && (i < VIDEO_MAX_PLANES); i++) {
- if (temp && temp->fd[i] == fd &&
- (CONTAINS(temp->buff_off[i],
- temp->size[i], buff_off)
- || CONTAINS(buff_off,
- size, temp->buff_off[i])
- || OVERLAPS(buff_off, size,
- temp->buff_off[i],
- temp->size[i]))) {
- dprintk(VIDC_DBG,
- "This memory region is already mapped\n");
- ret = temp;
- *plane = i;
- break;
- }
- }
- if (ret)
- break;
- }
- }
-err_invalid_input:
- return ret;
-}
-
-struct buffer_info *get_same_fd_buffer(struct list_head *list,
- int fd, int *plane)
-{
- struct buffer_info *temp;
- struct buffer_info *ret = NULL;
- int i;
- if (!list || fd < 0 || !plane) {
- dprintk(VIDC_ERR, "Invalid input\n");
- goto err_invalid_input;
- }
- *plane = 0;
- if (!list_empty(list)) {
- list_for_each_entry(temp, list, list) {
- for (i = 0; (i < temp->num_planes)
- && (i < VIDEO_MAX_PLANES); i++) {
- if (temp && temp->fd[i] == fd) {
- dprintk(VIDC_INFO,
- "Found same fd buffer\n");
- ret = temp;
- *plane = i;
- break;
- }
- }
- if (ret)
- break;
- }
- }
-err_invalid_input:
- return ret;
-}
-
-static struct buffer_info *device_to_uvaddr(
- struct list_head *list, u32 device_addr)
-{
- struct buffer_info *temp = NULL;
- int found = 0;
- int i;
- if (!list || !device_addr) {
- dprintk(VIDC_ERR, "Invalid input\n");
- goto err_invalid_input;
- }
- if (!list_empty(list)) {
- list_for_each_entry(temp, list, list) {
- for (i = 0; (i < temp->num_planes)
- && (i < VIDEO_MAX_PLANES); i++) {
- if (temp && temp->device_addr[i]
- == device_addr) {
- dprintk(VIDC_INFO,
- "Found same fd buffer\n");
- found = 1;
- break;
- }
- }
- if (found)
- break;
- }
- }
-err_invalid_input:
- return temp;
-}
-
static int msm_v4l2_open(struct file *filp)
{
- int rc = 0;
struct video_device *vdev = video_devdata(filp);
struct msm_video_device *vid_dev =
container_of(vdev, struct msm_video_device, vdev);
struct msm_vidc_core *core = video_drvdata(filp);
- struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
- GFP_KERNEL);
- if (!v4l2_inst) {
- dprintk(VIDC_ERR,
- "Failed to allocate memory for this instance\n");
- rc = -ENOMEM;
- goto fail_nomem;
- }
- v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION, &core->resources);
- if (!v4l2_inst->mem_client) {
- dprintk(VIDC_ERR, "Failed to create memory client\n");
- rc = -ENOMEM;
- goto fail_mem_client;
- }
+ struct msm_vidc_inst *vidc_inst;
- v4l2_inst->vidc_inst = msm_vidc_open(core->id, vid_dev->type);
- if (!v4l2_inst->vidc_inst) {
+ vidc_inst = msm_vidc_open(core->id, vid_dev->type);
+ if (!vidc_inst) {
dprintk(VIDC_ERR,
"Failed to create video instance, core: %d, type = %d\n",
core->id, vid_dev->type);
- rc = -ENOMEM;
- goto fail_open;
+ return -ENOMEM;
}
- INIT_LIST_HEAD(&v4l2_inst->registered_bufs);
- v4l2_inst->vidc_inst->priv = v4l2_inst;
clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
- filp->private_data = &(v4l2_inst->vidc_inst->event_handler);
- return rc;
-fail_open:
- msm_smem_delete_client(v4l2_inst->mem_client);
-fail_mem_client:
- kfree(v4l2_inst);
-fail_nomem:
- return rc;
-}
-static int msm_v4l2_release_buffers(struct msm_v4l2_vid_inst *v4l2_inst,
- int buffer_type)
-{
- struct list_head *ptr, *next;
- struct buffer_info *bi;
- struct v4l2_buffer buffer_info;
- struct v4l2_plane plane[VIDEO_MAX_PLANES];
- int rc = 0;
- int i;
- list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
- bi = list_entry(ptr, struct buffer_info, list);
- if (bi->type == buffer_type) {
- buffer_info.type = bi->type;
- for (i = 0; (i < bi->num_planes)
- && (i < VIDEO_MAX_PLANES); i++) {
- plane[i].reserved[0] = bi->fd[i];
- plane[i].reserved[1] = bi->buff_off[i];
- plane[i].length = bi->size[i];
- plane[i].m.userptr = bi->device_addr[i];
- buffer_info.m.planes = plane;
- dprintk(VIDC_DBG,
- "Releasing buffer: %d, %d, %d\n",
- buffer_info.m.planes[i].reserved[0],
- buffer_info.m.planes[i].reserved[1],
- buffer_info.m.planes[i].length);
- }
- buffer_info.length = bi->num_planes;
- rc = msm_vidc_release_buf(v4l2_inst->vidc_inst,
- &buffer_info);
- if (rc)
- dprintk(VIDC_ERR,
- "Failed Release buffer: %d, %d, %d\n",
- buffer_info.m.planes[0].reserved[0],
- buffer_info.m.planes[0].reserved[1],
- buffer_info.m.planes[0].length);
- list_del(&bi->list);
- for (i = 0; i < bi->num_planes; i++) {
- if (bi->handle[i])
- msm_smem_free(v4l2_inst->mem_client,
- bi->handle[i]);
- }
- kfree(bi);
- }
- }
- return rc;
+ filp->private_data = &(vidc_inst->event_handler);
+ return 0;
}
static int msm_v4l2_close(struct file *filp)
{
int rc = 0;
- struct list_head *ptr, *next;
- struct buffer_info *bi;
struct msm_vidc_inst *vidc_inst;
- struct msm_v4l2_vid_inst *v4l2_inst;
- int i;
vidc_inst = get_vidc_inst(filp, NULL);
- v4l2_inst = get_v4l2_inst(filp, NULL);
- rc = msm_v4l2_release_buffers(v4l2_inst,
+ rc = msm_vidc_release_buffers(vidc_inst,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc)
dprintk(VIDC_WARN,
"Failed in %s for release output buffers\n", __func__);
- list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
- bi = list_entry(ptr, struct buffer_info, list);
- if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- list_del(&bi->list);
- for (i = 0; (i < bi->num_planes)
- && (i < VIDEO_MAX_PLANES); i++) {
- if (bi->handle[i])
- msm_smem_free(v4l2_inst->mem_client,
- bi->handle[i]);
- }
- kfree(bi);
- }
- }
- msm_smem_delete_client(v4l2_inst->mem_client);
+
rc = msm_vidc_close(vidc_inst);
- kfree(v4l2_inst);
return rc;
}
@@ -339,11 +124,9 @@
struct v4l2_requestbuffers *b)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
- struct msm_v4l2_vid_inst *v4l2_inst;
int rc = 0;
- v4l2_inst = get_v4l2_inst(file, NULL);
if (b->count == 0)
- rc = msm_v4l2_release_buffers(v4l2_inst, b->type);
+ rc = msm_vidc_release_buffers(vidc_inst, b->type);
if (rc)
dprintk(VIDC_WARN,
"Failed in %s for release output buffers\n", __func__);
@@ -353,247 +136,19 @@
int msm_v4l2_prepare_buf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
- struct msm_smem *handle = NULL;
- struct buffer_info *binfo;
- struct buffer_info *temp;
- struct msm_vidc_inst *vidc_inst;
- struct msm_v4l2_vid_inst *v4l2_inst;
- int plane = 0;
- int i, rc = 0;
- struct hfi_device *hdev;
- enum hal_buffer buffer_type;
-
- vidc_inst = get_vidc_inst(file, fh);
- v4l2_inst = get_v4l2_inst(file, fh);
- if (!v4l2_inst || !vidc_inst || !vidc_inst->core
- || !vidc_inst->core->device) {
- rc = -EINVAL;
- goto exit;
- }
-
- hdev = vidc_inst->core->device;
-
- if (!v4l2_inst->mem_client) {
- dprintk(VIDC_ERR, "Failed to get memory client\n");
- rc = -ENOMEM;
- goto exit;
- }
- binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
- if (!binfo) {
- dprintk(VIDC_ERR, "Out of memory\n");
- rc = -ENOMEM;
- goto exit;
- }
- if (b->length > VIDEO_MAX_PLANES) {
- dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
- b->length, VIDEO_MAX_PLANES);
- rc = -EINVAL;
- goto exit;
- }
- for (i = 0; i < b->length; ++i) {
- if (EXTRADATA_IDX(b->length) &&
- (i == EXTRADATA_IDX(b->length)) &&
- !b->m.planes[i].length) {
- continue;
- }
- temp = get_registered_buf(&v4l2_inst->registered_bufs,
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length, &plane);
- if (temp) {
- dprintk(VIDC_DBG,
- "This memory region has already been prepared\n");
- rc = -EINVAL;
- kfree(binfo);
- goto exit;
- }
-
- if (vidc_inst->session_type == MSM_VIDC_DECODER) {
- if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- buffer_type = HAL_BUFFER_INPUT;
- else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
- buffer_type = HAL_BUFFER_OUTPUT;
- } else {
- /* FIXME in the future. See comment in msm_comm_get_\
- * domain_partition. Same problem here. */
- if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- buffer_type = HAL_BUFFER_OUTPUT;
- else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
- buffer_type = HAL_BUFFER_INPUT;
- }
-
- temp = get_same_fd_buffer(&v4l2_inst->registered_bufs,
- b->m.planes[i].reserved[0], &plane);
-
- if (temp) {
- binfo->type = b->type;
- binfo->fd[i] = b->m.planes[i].reserved[0];
- binfo->buff_off[i] = b->m.planes[i].reserved[1];
- binfo->size[i] = b->m.planes[i].length;
- binfo->uvaddr[i] = b->m.planes[i].m.userptr;
- binfo->device_addr[i] =
- temp->handle[plane]->device_addr + binfo->buff_off[i];
- binfo->handle[i] = NULL;
- } else {
- handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- buffer_type);
- if (!handle) {
- dprintk(VIDC_ERR,
- "Failed to get device buffer address\n");
- kfree(binfo);
- goto exit;
- }
- binfo->type = b->type;
- binfo->fd[i] = b->m.planes[i].reserved[0];
- binfo->buff_off[i] = b->m.planes[i].reserved[1];
- binfo->size[i] = b->m.planes[i].length;
- binfo->uvaddr[i] = b->m.planes[i].m.userptr;
- binfo->device_addr[i] =
- handle->device_addr + binfo->buff_off[i];
- binfo->handle[i] = handle;
- dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length);
- rc = msm_smem_cache_operations(v4l2_inst->mem_client,
- binfo->handle[i], SMEM_CACHE_CLEAN);
- if (rc)
- dprintk(VIDC_WARN,
- "CACHE Clean failed: %d, %d, %d\n",
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length);
- }
- b->m.planes[i].m.userptr = binfo->device_addr[i];
- }
- binfo->num_planes = b->length;
- list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
- rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
-exit:
- return rc;
+ return msm_vidc_prepare_buf(get_vidc_inst(file, fh), b);
}
int msm_v4l2_qbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
- struct msm_vidc_inst *vidc_inst;
- struct msm_v4l2_vid_inst *v4l2_inst;
- struct buffer_info *binfo;
- int plane = 0;
- int rc = 0;
- int i;
- if (b->length > VIDEO_MAX_PLANES) {
- dprintk(VIDC_ERR, "num planes exceeds max: %d\n",
- b->length);
- return -EINVAL;
- }
- vidc_inst = get_vidc_inst(file, fh);
- v4l2_inst = get_v4l2_inst(file, fh);
- for (i = 0; i < b->length; ++i) {
- if (EXTRADATA_IDX(b->length) &&
- (i == EXTRADATA_IDX(b->length)) &&
- !b->m.planes[i].length) {
- b->m.planes[i].m.userptr = 0;
- continue;
- }
- binfo = get_registered_buf(&v4l2_inst->registered_bufs,
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length, &plane);
- if (!binfo) {
- dprintk(VIDC_ERR,
- "This buffer is not registered: %d, %d, %d\n",
- b->m.planes[i].reserved[0],
- b->m.planes[i].reserved[1],
- b->m.planes[i].length);
- rc = -EINVAL;
- goto err_invalid_buff;
- }
- b->m.planes[i].m.userptr = binfo->device_addr[i];
- dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
- binfo->device_addr[i]);
-
- if ((vidc_inst->fmts[OUTPUT_PORT]->fourcc ==
- V4L2_PIX_FMT_HEVC_HYBRID) && binfo->handle[i] &&
- (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
- rc = msm_smem_cache_operations(v4l2_inst->mem_client,
- binfo->handle[i], SMEM_CACHE_INVALIDATE);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to INV caches: %d\n", rc);
- goto err_invalid_buff;
- }
- }
-
- if (binfo->handle[i] &&
- (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
- rc = msm_smem_cache_operations(v4l2_inst->mem_client,
- binfo->handle[i], SMEM_CACHE_CLEAN);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to clean caches: %d\n", rc);
- goto err_invalid_buff;
- }
- }
- }
- rc = msm_vidc_qbuf(v4l2_inst->vidc_inst, b);
-err_invalid_buff:
- return rc;
+ return msm_vidc_qbuf(get_vidc_inst(file, fh), b);
}
int msm_v4l2_dqbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
- int rc = 0;
- int i;
- struct msm_v4l2_vid_inst *v4l2_inst;
- struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
- struct buffer_info *buffer_info;
- if (b->length > VIDEO_MAX_PLANES) {
- dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
- b->length);
- return -EINVAL;
- }
- v4l2_inst = get_v4l2_inst(file, fh);
- rc = msm_vidc_dqbuf((void *)vidc_inst, b);
- if (rc) {
- dprintk(VIDC_DBG,
- "Failed to dqbuf, capability: %d, rc: %d\n",
- b->type, rc);
- goto fail_dq_buf;
- }
- for (i = 0; i < b->length; i++) {
- if (EXTRADATA_IDX(b->length) &&
- (i == EXTRADATA_IDX(b->length)) &&
- !b->m.planes[i].m.userptr) {
- continue;
- }
- buffer_info = device_to_uvaddr(
- &v4l2_inst->registered_bufs,
- b->m.planes[i].m.userptr);
- b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
- if (!b->m.planes[i].m.userptr) {
- dprintk(VIDC_ERR,
- "Failed to find user virtual address, 0x%lx, %d, %d\n",
- b->m.planes[i].m.userptr, b->type, i);
- rc = -EINVAL;
- goto fail_dq_buf;
- }
- if (buffer_info->handle[i] &&
- (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
- rc = msm_smem_cache_operations(v4l2_inst->mem_client,
- buffer_info->handle[i], SMEM_CACHE_INVALIDATE);
- if (rc) {
- dprintk(VIDC_ERR,
- "Failed to clean caches: %d\n", rc);
- goto fail_dq_buf;
- }
- }
- }
-fail_dq_buf:
- return rc;
+ return msm_vidc_dqbuf(get_vidc_inst(file, fh), b);
}
int msm_v4l2_streamon(struct file *file, void *fh,
@@ -629,12 +184,10 @@
static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
struct v4l2_decoder_cmd *dec)
{
- struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
int rc = 0;
- v4l2_inst = get_v4l2_inst(file, NULL);
if (dec->cmd == V4L2_DEC_CMD_STOP)
- rc = msm_v4l2_release_buffers(v4l2_inst,
+ rc = msm_vidc_release_buffers(vidc_inst,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc)
dprintk(VIDC_WARN,
@@ -645,12 +198,10 @@
static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc)
{
- struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
int rc = 0;
- v4l2_inst = get_v4l2_inst(file, NULL);
if (enc->cmd == V4L2_ENC_CMD_STOP)
- rc = msm_v4l2_release_buffers(v4l2_inst,
+ rc = msm_vidc_release_buffers(vidc_inst,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (rc)
dprintk(VIDC_WARN,
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 24cc809..ea91849 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -12,7 +12,7 @@
*/
#include <linux/slab.h>
-
+#include <mach/scm.h>
#include "msm_vidc_internal.h"
#include "msm_vidc_common.h"
#include "vidc_hfi_api.h"
@@ -24,6 +24,14 @@
#define MAX_NUM_OUTPUT_BUFFERS 6
#define DEFAULT_CONCEAL_COLOR 0x0
+#define TZ_INFO_GET_FEATURE_VERSION_ID 0x3
+#define TZ_DYNAMIC_BUFFER_FEATURE_ID 12
+#define TZ_FEATURE_VERSION(major, minor, patch) \
+ (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
+struct tz_get_feature_version {
+ u32 feature_id;
+};
+
enum msm_vdec_ctrl_cluster {
MSM_VDEC_CTRL_CLUSTER_MAX = 1 << 0,
};
@@ -72,6 +80,7 @@
static const char *const mpeg_vidc_video_alloc_mode_type[] = {
"Buffer Allocation Static",
"Buffer Allocation Ring Buffer",
+ "Buffer Allocation Dynamic Buffer"
};
static const char *const perf_level[] = {
@@ -255,15 +264,32 @@
.step = 0,
},
{
- .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE,
- .name = "Buffer allocation mode",
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT,
+ .name = "Buffer allocation mode for input",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
- .maximum = V4L2_MPEG_VIDC_VIDEO_RING,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
.default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
- (1 << V4L2_MPEG_VIDC_VIDEO_RING)
+ (1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
+ ),
+ .qmenu = mpeg_vidc_video_alloc_mode_type,
+ .step = 0,
+ .cluster = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT,
+ .name = "Buffer allocation mode for output",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_RING) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
),
.qmenu = mpeg_vidc_video_alloc_mode_type,
.step = 0,
@@ -818,7 +844,6 @@
return -EINVAL;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- struct hal_frame_size frame_sz;
fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
@@ -831,13 +856,6 @@
goto err_invalid_fmt;
}
inst->fmts[fmt->type] = fmt;
- frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
- frame_sz.width = inst->prop.width;
- frame_sz.height = inst->prop.height;
- dprintk(VIDC_DBG, "width = %d, height = %d\n",
- frame_sz.width, frame_sz.height);
- ret = msm_comm_try_set_prop(inst,
- HAL_PARAM_FRAME_SIZE, &frame_sz);
ret = ret || msm_comm_try_get_bufreqs(inst);
if (ret) {
for (i = 0; i < fmt->num_planes; ++i) {
@@ -1301,21 +1319,58 @@
inst->capability.width.max = DEFAULT_WIDTH;
inst->capability.buffer_mode[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
inst->capability.buffer_mode[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
inst->prop.fps = 30;
return rc;
}
+static inline enum buffer_mode_type get_buf_type(int val)
+{
+ switch (val) {
+ case V4L2_MPEG_VIDC_VIDEO_STATIC:
+ return HAL_BUFFER_MODE_STATIC;
+ case V4L2_MPEG_VIDC_VIDEO_RING:
+ return HAL_BUFFER_MODE_RING;
+ case V4L2_MPEG_VIDC_VIDEO_DYNAMIC:
+ return HAL_BUFFER_MODE_DYNAMIC;
+ default:
+ dprintk(VIDC_ERR, "%s: invalid buf type: %d", __func__, val);
+ }
+ return 0;
+}
+
+static int check_tz_dynamic_buffer_support(void)
+{
+ int rc = 0;
+ struct tz_get_feature_version tz_feature_id;
+ unsigned int resp = 0;
+
+ tz_feature_id.feature_id = TZ_DYNAMIC_BUFFER_FEATURE_ID;
+ rc = scm_call(SCM_SVC_INFO,
+ TZ_INFO_GET_FEATURE_VERSION_ID, &tz_feature_id,
+ sizeof(tz_feature_id), &resp, sizeof(resp));
+ if ((rc) || (resp != TZ_FEATURE_VERSION(1, 1, 0))) {
+ dprintk(VIDC_DBG,
+ "Dyamic buffer mode not supported, failed to get tz feature version id : %u, rc : %d, response : %u\n",
+ tz_feature_id.feature_id, rc, resp);
+ rc = -ENOTSUPP;
+ }
+ return rc;
+}
+
static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
{
int rc = 0;
struct hal_nal_stream_format_supported stream_format;
struct hal_enable_picture enable_picture;
- struct hal_enable hal_property;/*, prop;*/
+ struct hal_enable hal_property;
enum hal_property property_id = 0;
u32 property_val = 0;
void *pdata = NULL;
struct hfi_device *hdev;
struct hal_extradata_enable extra;
+ struct hal_buffer_alloc_mode alloc_mode;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
@@ -1404,15 +1459,17 @@
}
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE:
- {
- struct hal_buffer_alloc_mode mode;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT:
+ if (ctrl->val == V4L2_MPEG_VIDC_VIDEO_DYNAMIC) {
+ rc = -ENOTSUPP;
+ break;
+ }
property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
- mode.buffer_mode = ctrl->val;
- mode.buffer_type = HAL_BUFFER_INPUT;
- pdata = &mode;
+ alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+ alloc_mode.buffer_type = HAL_BUFFER_INPUT;
+ inst->buffer_mode_set[OUTPUT_PORT] = alloc_mode.buffer_mode;
+ pdata = &alloc_mode;
break;
- }
case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY:
{
property_id = HAL_PARAM_VDEC_FRAME_ASSEMBLY;
@@ -1420,6 +1477,28 @@
pdata = &hal_property;
break;
}
+ case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT:
+ property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
+ alloc_mode.buffer_mode = get_buf_type(ctrl->val);
+ if (!(alloc_mode.buffer_mode &
+ inst->capability.buffer_mode[CAPTURE_PORT])) {
+ dprintk(VIDC_DBG,
+ "buffer mode[%d] not supported for Capture Port\n",
+ ctrl->val);
+ rc = -ENOTSUPP;
+ break;
+ }
+ if ((alloc_mode.buffer_mode == HAL_BUFFER_MODE_DYNAMIC) &&
+ (inst->flags & VIDC_SECURE) &&
+ check_tz_dynamic_buffer_support()) {
+ rc = -ENOTSUPP;
+ break;
+ }
+ alloc_mode.buffer_type = HAL_BUFFER_OUTPUT;
+ pdata = &alloc_mode;
+ inst->buffer_mode_set[CAPTURE_PORT] = alloc_mode.buffer_mode;
+ break;
+
default:
break;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index c1a9ad0..9e8a639 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1953,6 +1953,8 @@
inst->prop.height = DEFAULT_HEIGHT;
inst->prop.width = DEFAULT_WIDTH;
inst->prop.fps = 15;
+ inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
+ inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 10a0eac..89fbc2a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -199,6 +199,478 @@
return -EINVAL;
}
+struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b, int idx, int *plane)
+{
+ struct buffer_info *temp;
+ struct buffer_info *ret = NULL;
+ int i;
+ struct list_head *list = &inst->registered_bufs;
+ int fd = b->m.planes[idx].reserved[0];
+ u32 buff_off = b->m.planes[idx].reserved[1];
+ u32 size = b->m.planes[idx].length;
+ u32 device_addr = b->m.planes[idx].m.userptr;
+
+ if (!list || fd < 0 || !plane) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ goto err_invalid_input;
+ }
+
+ *plane = 0;
+ mutex_lock(&inst->lock);
+ list_for_each_entry(temp, list, list) {
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp &&
+ ((fd == temp->fd[i]) ||
+ (device_addr == temp->device_addr[i])) &&
+ (CONTAINS(temp->buff_off[i],
+ temp->size[i], buff_off)
+ || CONTAINS(buff_off,
+ size, temp->buff_off[i])
+ || OVERLAPS(buff_off, size,
+ temp->buff_off[i],
+ temp->size[i]))) {
+ dprintk(VIDC_DBG,
+ "This memory region is already mapped\n");
+ ret = temp;
+ *plane = i;
+ break;
+ }
+ }
+ if (ret)
+ break;
+ }
+ mutex_unlock(&inst->lock);
+err_invalid_input:
+ return ret;
+}
+
+struct buffer_info *get_same_fd_buffer(struct msm_vidc_inst *inst,
+ struct list_head *list, int fd, int *plane)
+{
+ struct buffer_info *temp;
+ struct buffer_info *ret = NULL;
+ int i;
+ if (fd == 0)
+ return NULL;
+ if (!list || fd < 0 || !plane) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ goto err_invalid_input;
+ }
+ *plane = 0;
+ mutex_lock(&inst->lock);
+ list_for_each_entry(temp, list, list) {
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp && temp->fd[i] == fd) {
+ temp->same_fd_ref[i]++;
+ dprintk(VIDC_INFO,
+ "Found same fd buffer\n");
+ ret = temp;
+ *plane = i;
+ break;
+ }
+ }
+ if (ret)
+ break;
+ }
+ mutex_unlock(&inst->lock);
+err_invalid_input:
+ return ret;
+}
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst,
+ struct list_head *list, u32 device_addr)
+{
+ struct buffer_info *temp = NULL;
+ struct buffer_info *dummy = NULL;
+ int found = 0;
+ int i;
+ if (!list || !device_addr || !inst) {
+ dprintk(VIDC_ERR,
+ "Invalid input- list: %p device_addr: %u inst: %p\n",
+ list, device_addr, inst);
+ goto err_invalid_input;
+ }
+ mutex_lock(&inst->lock);
+ list_for_each_entry_safe(temp, dummy, list, list) {
+ for (i = 0; (i < temp->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (temp && !temp->inactive &&
+ temp->device_addr[i] == device_addr) {
+ dprintk(VIDC_INFO,
+ "Found same fd buffer\n");
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+ mutex_unlock(&inst->lock);
+err_invalid_input:
+ return temp;
+}
+
+static inline void populate_buf_info(struct buffer_info *binfo,
+ struct v4l2_buffer *b, u32 i)
+{
+ binfo->type = b->type;
+ binfo->fd[i] = b->m.planes[i].reserved[0];
+ binfo->buff_off[i] = b->m.planes[i].reserved[1];
+ binfo->size[i] = b->m.planes[i].length;
+ binfo->uvaddr[i] = b->m.planes[i].m.userptr;
+ binfo->num_planes = b->length;
+ binfo->memory = b->memory;
+ binfo->v4l2_index = b->index;
+ binfo->dequeued = false;
+ binfo->timestamp.tv_sec = b->timestamp.tv_sec;
+ binfo->timestamp.tv_usec = b->timestamp.tv_usec;
+ dprintk(VIDC_DBG, "%s: fd[%d] = %d b->index = %d",
+ __func__, i, binfo->fd[0], b->index);
+}
+
+static inline void repopulate_v4l2_buffer(struct v4l2_buffer *b,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ b->type = binfo->type;
+ b->length = binfo->num_planes;
+ b->memory = binfo->memory;
+ b->index = binfo->v4l2_index;
+ b->timestamp.tv_sec = binfo->timestamp.tv_sec;
+ b->timestamp.tv_usec = binfo->timestamp.tv_usec;
+ for (i = 0; i < binfo->num_planes; ++i) {
+ b->m.planes[i].reserved[0] = binfo->fd[i];
+ b->m.planes[i].reserved[1] = binfo->buff_off[i];
+ b->m.planes[i].length = binfo->size[i];
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
+ dprintk(VIDC_DBG, "%s %d %d %d %u\n", __func__, binfo->fd[i],
+ binfo->buff_off[i], binfo->size[i],
+ binfo->device_addr[i]);
+ }
+}
+
+static struct msm_smem *map_buffer(struct msm_vidc_inst *inst,
+ struct v4l2_plane *p, enum hal_buffer buffer_type)
+{
+ struct msm_smem *handle = NULL;
+ handle = msm_smem_user_to_kernel(inst->mem_client,
+ p->reserved[0],
+ p->reserved[1],
+ buffer_type);
+ if (!handle) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to get device buffer address\n", __func__);
+ return NULL;
+ }
+ if (msm_smem_cache_operations(inst->mem_client, handle,
+ SMEM_CACHE_CLEAN))
+ dprintk(VIDC_WARN,
+ "CACHE Clean failed: %d, %d, %d\n",
+ p->reserved[0],
+ p->reserved[1],
+ p->length);
+ return handle;
+}
+
+static inline enum hal_buffer get_hal_buffer_type(
+ struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return HAL_BUFFER_INPUT;
+ else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+ return HAL_BUFFER_OUTPUT;
+ } else {
+ /* FIXME in the future. See comment in msm_comm_get_\
+ * domain_partition. Same problem here. */
+ if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return HAL_BUFFER_OUTPUT;
+ else /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+ return HAL_BUFFER_INPUT;
+ }
+ return -EINVAL;
+}
+
+static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b,
+ struct msm_vidc_inst *inst)
+{
+ return ((b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+ (inst->buffer_mode_set[CAPTURE_PORT] ==
+ HAL_BUFFER_MODE_DYNAMIC));
+}
+
+
+static inline void save_v4l2_buffer(struct v4l2_buffer *b,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ for (i = 0; i < b->length; ++i) {
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ continue;
+ }
+ populate_buf_info(binfo, b, i);
+ }
+}
+
+int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct buffer_info *binfo = NULL;
+ struct buffer_info *temp = NULL;
+ int plane = 0;
+ int i = 0, rc = 0;
+
+ if (!b || !inst) {
+ dprintk(VIDC_ERR, "%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ dprintk(VIDC_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "Num planes exceeds max: %d, %d\n",
+ b->length, VIDEO_MAX_PLANES);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ dprintk(VIDC_DBG, "[MAP] Create binfo = %p fd = %d type = %d\n",
+ binfo, b->m.planes[0].reserved[0], b->type);
+
+ for (i = 0; i < b->length; ++i) {
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ continue;
+ }
+ temp = get_registered_buf(inst, b, i, &plane);
+ if (temp && !is_dynamic_output_buffer_mode(b, inst)) {
+ dprintk(VIDC_DBG,
+ "This memory region has already been prepared\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (temp && is_dynamic_output_buffer_mode(b, inst) &&
+ (i == 0)) {
+ /*
+ * Buffer is already present in registered list
+ * increment ref_count, populate new values of v4l2
+ * buffer in existing buffer_info struct.
+ *
+ * We will use the saved buffer info and queue it when
+ * we receive RELEASE_BUFFER_REFERENCE EVENT from f/w.
+ */
+ dprintk(VIDC_DBG, "[MAP] Buffer already prepared\n");
+ rc = buf_ref_get(inst, temp);
+ if (rc < 0)
+ return rc;
+ save_v4l2_buffer(b, temp);
+ rc = -EEXIST;
+ goto exit;
+ }
+
+ temp = get_same_fd_buffer(inst, &inst->registered_bufs,
+ b->m.planes[i].reserved[0], &plane);
+
+ populate_buf_info(binfo, b, i);
+ if (temp) {
+ binfo->device_addr[i] =
+ temp->handle[plane]->device_addr + binfo->buff_off[i];
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
+ binfo->mapped[i] = false;
+ } else {
+ if (inst->map_output_buffer) {
+ binfo->handle[i] =
+ map_buffer(inst, &b->m.planes[i],
+ get_hal_buffer_type(inst, b));
+ if (!binfo->handle[i]) {
+ rc = -EINVAL;
+ goto exit;
+ }
+ dprintk(VIDC_DBG,
+ "[MAP] - mapped handle[%d] = %p fd[%d] = %d",
+ i, binfo->handle[i], i, binfo->fd[i]);
+ binfo->mapped[i] = true;
+ binfo->device_addr[i] =
+ binfo->handle[i]->device_addr +
+ binfo->buff_off[i];
+ b->m.planes[i].m.userptr =
+ binfo->device_addr[i];
+ } else {
+ binfo->device_addr[i] =
+ b->m.planes[i].m.userptr;
+ }
+ dprintk(VIDC_DBG, "Registering buffer: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ }
+ /* We maintain one ref count for all planes*/
+ if ((i == 0) && is_dynamic_output_buffer_mode(b, inst)) {
+ rc = buf_ref_get(inst, binfo);
+ if (rc < 0)
+ return rc;
+ }
+ }
+ dprintk(VIDC_DBG, "[MAP] Adding binfo = %p to list\n", binfo);
+ mutex_lock(&inst->lock);
+ list_add_tail(&binfo->list, &inst->registered_bufs);
+ mutex_unlock(&inst->lock);
+ return 0;
+exit:
+ kfree(binfo);
+ return rc;
+}
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ struct buffer_info *temp = NULL;
+ struct buffer_info *dummy = NULL;
+ struct list_head *list;
+ bool found = false, keep_node = false;
+
+ if (!inst || !binfo) {
+ dprintk(VIDC_ERR, "%s invalid param: %p %p\n",
+ __func__, inst, binfo);
+ return -EINVAL;
+ }
+
+ mutex_lock(&inst->lock);
+ list = &inst->registered_bufs;
+ /*
+ * Make sure the buffer to be unmapped and deleted
+ * from the registered list is present in the list.
+ */
+ list_for_each_entry_safe(temp, dummy, list, list) {
+ if (temp == binfo) {
+ found = true;
+ break;
+ }
+ }
+
+ /*
+ * Free the buffer info only if
+ * - buffer info has not been deleted from registered list
+ * - vidc client has called dqbuf on the buffer
+ * - no references are held on the buffer
+ */
+ if (!found || !temp || !temp->pending_deletion || !temp->dequeued)
+ goto exit;
+
+ for (i = 0; i < temp->num_planes; i++) {
+ /*
+ * Unmap the handle only if the buffer has been mapped and no
+ * other buffer has a reference to this buffer.
+ * In case of buffers with same fd, we will map the buffer only
+ * once and subsequent buffers will refer to the mapped buffer's
+ * device address.
+ * For buffers which share the same fd, do not unmap and keep
+ * the buffer info in registered list.
+ */
+ if (temp->handle[i] && temp->mapped[i] &&
+ !temp->same_fd_ref[i]) {
+ dprintk(VIDC_DBG,
+ "[UNMAP] - handle[%d] = %p fd[%d] = %d",
+ i, temp->handle[i], i, temp->fd[i]);
+ msm_smem_free(inst->mem_client,
+ temp->handle[i]);
+ }
+
+ if (temp->same_fd_ref[i])
+ keep_node = true;
+ else {
+ temp->fd[i] = 0;
+ temp->handle[i] = 0;
+ temp->device_addr[i] = 0;
+ temp->uvaddr[i] = 0;
+ }
+ }
+ if (!keep_node) {
+ dprintk(VIDC_DBG, "[UNMAP] AND-FREED binfo: %p\n", temp);
+ list_del(&temp->list);
+ kfree(temp);
+ } else {
+ temp->inactive = true;
+ dprintk(VIDC_DBG, "[UNMAP] NOT-FREED binfo: %p\n", temp);
+ }
+exit:
+ mutex_unlock(&inst->lock);
+ return 0;
+}
+
+
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo)
+{
+ struct v4l2_buffer b = {0};
+ struct v4l2_plane plane[VIDEO_MAX_PLANES] = { {0} };
+
+ if (!binfo) {
+ dprintk(VIDC_ERR, "%s invalid param: %p\n", __func__, binfo);
+ return -EINVAL;
+ }
+ dprintk(VIDC_DBG, "%s fd[0] = %d\n", __func__, binfo->fd[0]);
+
+ b.m.planes = plane;
+ repopulate_v4l2_buffer(&b, binfo);
+
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_qbuf(inst, &b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_qbuf(inst, &b);
+
+ return -EINVAL;
+}
+
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo)
+{
+ int i = 0;
+ int rc = 0;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid inst: %p\n", __func__, inst);
+ return -EINVAL;
+ }
+
+ if (!inst->map_output_buffer)
+ return 0;
+
+ if (!binfo) {
+ dprintk(VIDC_ERR, "%s: invalid buffer info: %p\n",
+ __func__, inst);
+ return -EINVAL;
+ }
+
+ if (binfo->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return 0;
+
+
+ for (i = 0; i < binfo->num_planes; i++) {
+ if (binfo->handle[i]) {
+ rc = msm_smem_cache_operations(inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_INVALIDATE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to clean caches: %d\n",
+ __func__, rc);
+ return -EINVAL;
+ }
+ }
+ }
+ return 0;
+}
+
int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
{
struct msm_vidc_inst *inst = instance;
@@ -206,6 +678,19 @@
if (!inst || !b)
return -EINVAL;
+ if (is_dynamic_output_buffer_mode(b, inst)) {
+ dprintk(VIDC_ERR, "%s: not supported in dynamic buffer mode\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Map the buffer only for non-kernel clients*/
+ if (b->m.planes[0].reserved[0]) {
+ inst->map_output_buffer = true;
+ if (map_and_register_buf(inst, b))
+ return -EINVAL;
+ }
+
if (inst->session_type == MSM_VIDC_DECODER)
return msm_vdec_prepare_buf(instance, b);
if (inst->session_type == MSM_VIDC_ENCODER)
@@ -213,18 +698,58 @@
return -EINVAL;
}
-int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b)
+int msm_vidc_release_buffers(void *instance, int buffer_type)
{
+ struct list_head *ptr, *next;
struct msm_vidc_inst *inst = instance;
+ struct buffer_info *bi;
+ struct v4l2_buffer buffer_info;
+ struct v4l2_plane plane[VIDEO_MAX_PLANES];
+ int i, rc = 0;
- if (!inst || !b)
+ if (!inst)
return -EINVAL;
- if (inst->session_type == MSM_VIDC_DECODER)
- return msm_vdec_release_buf(instance, b);
- if (inst->session_type == MSM_VIDC_ENCODER)
- return msm_venc_release_buf(instance, b);
- return -EINVAL;
+ list_for_each_safe(ptr, next, &inst->registered_bufs) {
+ bi = list_entry(ptr, struct buffer_info, list);
+ if (bi->type == buffer_type) {
+ buffer_info.type = bi->type;
+ for (i = 0; (i < bi->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ plane[i].reserved[0] = bi->fd[i];
+ plane[i].reserved[1] = bi->buff_off[i];
+ plane[i].length = bi->size[i];
+ plane[i].m.userptr = bi->device_addr[i];
+ buffer_info.m.planes = plane;
+ dprintk(VIDC_DBG,
+ "Releasing buffer: %d, %d, %d\n",
+ buffer_info.m.planes[i].reserved[0],
+ buffer_info.m.planes[i].reserved[1],
+ buffer_info.m.planes[i].length);
+ }
+ buffer_info.length = bi->num_planes;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ rc = msm_vdec_release_buf(instance,
+ &buffer_info);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ rc = msm_venc_release_buf(instance,
+ &buffer_info);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed Release buffer: %d, %d, %d\n",
+ buffer_info.m.planes[0].reserved[0],
+ buffer_info.m.planes[0].reserved[1],
+ buffer_info.m.planes[0].length);
+ list_del(&bi->list);
+ for (i = 0; i < bi->num_planes; i++) {
+ if (bi->handle[i])
+ msm_smem_free(inst->mem_client,
+ bi->handle[i]);
+ }
+ kfree(bi);
+ }
+ }
+ return rc;
}
int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
@@ -246,29 +771,149 @@
int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
{
struct msm_vidc_inst *inst = instance;
+ struct buffer_info *binfo;
+ int plane = 0;
+ int rc = 0;
+ int i;
if (!inst || !b)
return -EINVAL;
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "num planes exceeds max: %d\n",
+ b->length);
+ return -EINVAL;
+ }
+
+ if (is_dynamic_output_buffer_mode(b, inst)) {
+ if (b->m.planes[0].reserved[0])
+ inst->map_output_buffer = true;
+
+ rc = map_and_register_buf(inst, b);
+ if (rc == -EEXIST)
+ return 0;
+ if (rc)
+ return rc;
+ }
+
+ for (i = 0; i < b->length; ++i) {
+ if (!inst->map_output_buffer)
+ continue;
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].length) {
+ b->m.planes[i].m.userptr = 0;
+ continue;
+ }
+
+ binfo = get_registered_buf(inst, b, i, &plane);
+ if (!binfo) {
+ dprintk(VIDC_ERR,
+ "This buffer is not registered: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ goto err_invalid_buff;
+ }
+ b->m.planes[i].m.userptr = binfo->device_addr[i];
+ dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
+ binfo->device_addr[i]);
+
+ if ((inst->fmts[OUTPUT_PORT]->fourcc ==
+ V4L2_PIX_FMT_HEVC_HYBRID) && binfo->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+ rc = msm_smem_cache_operations(inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_INVALIDATE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to inv caches: %d\n", rc);
+ goto err_invalid_buff;
+ }
+ }
+
+ if (binfo->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+ rc = msm_smem_cache_operations(inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to clean caches: %d\n", rc);
+ goto err_invalid_buff;
+ }
+ }
+ }
+
if (inst->session_type == MSM_VIDC_DECODER)
return msm_vdec_qbuf(instance, b);
if (inst->session_type == MSM_VIDC_ENCODER)
return msm_venc_qbuf(instance, b);
+
+err_invalid_buff:
return -EINVAL;
}
int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
{
struct msm_vidc_inst *inst = instance;
+ struct buffer_info *buffer_info = NULL;
+ int i = 0, rc = 0;
if (!inst || !b)
return -EINVAL;
+ if (b->length > VIDEO_MAX_PLANES) {
+ dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
+ b->length);
+ return -EINVAL;
+ }
+
if (inst->session_type == MSM_VIDC_DECODER)
- return msm_vdec_dqbuf(instance, b);
+ rc = msm_vdec_dqbuf(instance, b);
if (inst->session_type == MSM_VIDC_ENCODER)
- return msm_venc_dqbuf(instance, b);
- return -EINVAL;
+ rc = msm_venc_dqbuf(instance, b);
+
+ if (rc)
+ return rc;
+
+ for (i = 0; i < b->length; i++) {
+ if (!inst->map_output_buffer)
+ continue;
+ if (EXTRADATA_IDX(b->length) &&
+ (i == EXTRADATA_IDX(b->length)) &&
+ !b->m.planes[i].m.userptr) {
+ continue;
+ }
+ buffer_info = device_to_uvaddr(inst,
+ &inst->registered_bufs,
+ b->m.planes[i].m.userptr);
+
+ if (!buffer_info) {
+ dprintk(VIDC_ERR,
+ "%s no buffer info registered for buffer addr: 0x%lx\n",
+ __func__, b->m.planes[i].m.userptr);
+ return -EINVAL;
+ }
+
+ b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
+ if (!b->m.planes[i].m.userptr) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to find user virtual address, 0x%lx, %d, %d\n",
+ __func__, b->m.planes[i].m.userptr, b->type, i);
+ return -EINVAL;
+ }
+ }
+
+ if (is_dynamic_output_buffer_mode(b, inst)) {
+ mutex_lock(&inst->lock);
+ buffer_info->dequeued = true;
+ mutex_unlock(&inst->lock);
+ dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n",
+ buffer_info->fd[0]);
+ rc = unmap_and_deregister_buf(inst, buffer_info);
+ } else
+ rc = output_buffer_cache_invalidate(inst, buffer_info);
+
+ return rc;
}
int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
@@ -450,9 +1095,11 @@
INIT_LIST_HEAD(&inst->internalbufs);
INIT_LIST_HEAD(&inst->persistbufs);
INIT_LIST_HEAD(&inst->ctrl_clusters);
+ INIT_LIST_HEAD(&inst->registered_bufs);
init_waitqueue_head(&inst->kernel_event_queue);
inst->state = MSM_VIDC_CORE_UNINIT_DONE;
inst->core = core;
+ inst->map_output_buffer = false;
for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
@@ -495,7 +1142,7 @@
inst->debugfs_root =
msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
- setup_event_queue(inst, &core->vdev[core_id].vdev);
+ setup_event_queue(inst, &core->vdev[session_type].vdev);
mutex_lock(&core->sync_lock);
list_add_tail(&inst->list, &core->instances);
@@ -572,12 +1219,27 @@
struct msm_vidc_inst *temp;
struct msm_vidc_core *core;
struct list_head *ptr, *next;
+ struct buffer_info *bi;
int rc = 0;
int i;
if (!inst)
return -EINVAL;
+ list_for_each_safe(ptr, next, &inst->registered_bufs) {
+ bi = list_entry(ptr, struct buffer_info, list);
+ if (bi->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ list_del(&bi->list);
+ for (i = 0; (i < bi->num_planes)
+ && (i < VIDEO_MAX_PLANES); i++) {
+ if (bi->handle[i])
+ msm_smem_free(inst->mem_client,
+ bi->handle[i]);
+ }
+ kfree(bi);
+ }
+ }
+
core = inst->core;
mutex_lock(&core->sync_lock);
list_for_each_safe(ptr, next, &core->instances) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 0e0328a..780f2c4 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -31,6 +31,8 @@
V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT
#define V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT \
V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT
+#define V4L2_EVENT_RELEASE_BUFFER_REFERENCE \
+ V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE
#define NUM_MBS_PER_SEC(__height, __width, __fps) ({\
(__height >> 4) * (__width >> 4) * __fps; \
@@ -471,14 +473,72 @@
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
break;
+ case HAL_EVENT_RELEASE_BUFFER_REFERENCE:
+ {
+ struct v4l2_event buf_event = {0};
+ struct buffer_info *binfo = NULL;
+ u32 *ptr = NULL;
+
+ dprintk(VIDC_DBG,
+ "%s - inst: %p buffer: %p extra: %p\n",
+ __func__, inst,
+ event_notify->packet_buffer,
+ event_notify->exra_data_buffer);
+
+ /*
+ * Get the buffer_info entry for the
+ * device address.
+ */
+ binfo = device_to_uvaddr(inst,
+ &inst->registered_bufs,
+ (u32)event_notify->packet_buffer);
+ if (!binfo) {
+ dprintk(VIDC_ERR,
+ "%s buffer not found in registered list\n",
+ __func__);
+ return;
+ }
+
+ /* Fill event data to be sent to client*/
+ buf_event.type =
+ V4L2_EVENT_RELEASE_BUFFER_REFERENCE;
+ ptr = (u32 *)buf_event.u.data;
+ ptr[0] = binfo->fd[0];
+ ptr[1] = binfo->buff_off[0];
+
+ dprintk(VIDC_DBG,
+ "RELEASE REFERENCE EVENT FROM F/W - fd = %d offset = %d\n",
+ ptr[0], ptr[1]);
+
+ /* Decrement buffer reference count*/
+ buf_ref_put(inst, binfo);
+
+ /*
+ * Release buffer and remove from list
+ * if reference goes to zero.
+ */
+ if (unmap_and_deregister_buf(inst, binfo))
+ dprintk(VIDC_ERR,
+ "%s: buffer unmap failed\n", __func__);
+
+ /*send event to client*/
+ v4l2_event_queue_fh(&inst->event_handler,
+ &buf_event);
+ wake_up(&inst->kernel_event_queue);
+ return;
+ }
default:
break;
}
if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) {
+ dprintk(VIDC_DBG,
+ "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT\n");
inst->reconfig_height = event_notify->height;
inst->reconfig_width = event_notify->width;
inst->in_reconfig = true;
} else {
+ dprintk(VIDC_DBG,
+ "V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n");
inst->prop.height = event_notify->height;
inst->prop.width = event_notify->width;
}
@@ -807,6 +867,107 @@
}
}
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+ int cnt = 0;
+
+ if (!inst || !binfo)
+ return -EINVAL;
+
+ mutex_lock(&inst->lock);
+ atomic_inc(&binfo->ref_count);
+ cnt = atomic_read(&binfo->ref_count);
+ if (cnt > 2) {
+ dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+ cnt = -EINVAL;
+ }
+ dprintk(VIDC_DBG, "REF_GET[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+ mutex_unlock(&inst->lock);
+ return cnt;
+}
+
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo)
+{
+ int rc = 0;
+ int cnt;
+ bool release_buf = false;
+ bool qbuf_again = false;
+
+ if (!inst || !binfo)
+ return -EINVAL;
+
+ mutex_lock(&inst->lock);
+ atomic_dec(&binfo->ref_count);
+ cnt = atomic_read(&binfo->ref_count);
+ dprintk(VIDC_DBG, "REF_PUT[%d] fd[0] = %d\n", cnt, binfo->fd[0]);
+ if (cnt == 0)
+ release_buf = true;
+ else if (cnt == 1)
+ qbuf_again = true;
+ else {
+ dprintk(VIDC_ERR, "%s: invalid ref_cnt: %d\n", __func__, cnt);
+ cnt = -EINVAL;
+ }
+ mutex_unlock(&inst->lock);
+
+ if (cnt < 0)
+ return cnt;
+
+ rc = output_buffer_cache_invalidate(inst, binfo);
+ if (rc)
+ return rc;
+
+ if (release_buf) {
+ /*
+ * We can not delete binfo here as we need to set the user
+ * virtual address saved in binfo->uvaddr to the dequeued v4l2
+ * buffer.
+ *
+ * We will set the pending_deletion flag to true here and delete
+ * binfo from registered list in dqbuf after setting the uvaddr.
+ */
+ dprintk(VIDC_DBG, "fd[0] = %d -> pending_deletion = true\n",
+ binfo->fd[0]);
+ binfo->pending_deletion = true;
+ } else if (qbuf_again) {
+ rc = qbuf_dynamic_buf(inst, binfo);
+ if (!rc)
+ return rc;
+ }
+ return cnt;
+}
+
+static void handle_dynamic_buffer(struct msm_vidc_inst *inst,
+ u32 device_addr, u32 flags)
+{
+ struct buffer_info *binfo = NULL;
+
+ /*
+ * Update reference count and release OR queue back the buffer,
+ * only when firmware is not holding a reference.
+ */
+ if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+ binfo = device_to_uvaddr(inst, &inst->registered_bufs,
+ device_addr);
+ if (!binfo) {
+ dprintk(VIDC_ERR,
+ "%s buffer not found in registered list\n",
+ __func__);
+ return;
+ }
+ if (flags & HAL_BUFFERFLAG_READONLY) {
+ dprintk(VIDC_DBG,
+ "_F_B_D_ fd[0] = %d -> Reference with f/w",
+ binfo->fd[0]);
+ } else {
+ dprintk(VIDC_DBG,
+ "_F_B_D_ fd[0] = %d -> FBD_ref_released\n",
+ binfo->fd[0]);
+ buf_ref_put(inst, binfo);
+ }
+ }
+}
+
static void handle_fbd(enum command_response cmd, void *data)
{
struct msm_vidc_cb_data_done *response = data;
@@ -850,6 +1011,10 @@
}
vb->v4l2_buf.flags = 0;
+ handle_dynamic_buffer(inst, (u32)fill_buf_done->packet_buffer1,
+ fill_buf_done->flags1);
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_READONLY;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
@@ -2400,6 +2565,67 @@
msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE);
return;
}
+
+void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst)
+{
+ struct buffer_info *binfo = NULL, *dummy = NULL;
+ struct list_head *list = NULL;
+
+ if (inst->buffer_mode_set[CAPTURE_PORT] != HAL_BUFFER_MODE_DYNAMIC)
+ return;
+
+ /*
+ * dynamic buffer mode:- if flush is called during seek
+ * driver should not queue any new buffer it has been holding.
+ *
+ * Each dynamic o/p buffer can have one of following ref_count:
+ * ref_count : 0 - f/w has released reference and sent fbd back.
+ * The buffer has been returned back to client.
+ *
+ * ref_count : 1 - f/w is holding reference. f/w may have released
+ * fbd as read_only OR fbd is pending. f/w will
+ * release reference before sending flush_done.
+ *
+ * ref_count : 2 - f/w is holding reference, f/w has released fbd as
+ * read_only, which client has queued back to driver.
+ * driver holds this buffer and will queue back
+ * only when f/w releases the reference. During
+ * flush_done, f/w will release the reference but driver
+ * should not queue back the buffer to f/w.
+ * Flush all buffers with ref_count 2.
+ */
+ mutex_lock(&inst->lock);
+ if (!list_empty(&inst->registered_bufs)) {
+ struct v4l2_event buf_event = {0};
+ u32 *ptr = NULL;
+ list = &inst->registered_bufs;
+ list_for_each_entry_safe(binfo, dummy, list, list) {
+ if (binfo &&
+ (binfo->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+ (atomic_read(&binfo->ref_count) == 2)) {
+ atomic_dec(&binfo->ref_count);
+ buf_event.type =
+ V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER;
+ ptr = (u32 *)buf_event.u.data;
+ ptr[0] = binfo->fd[0];
+ ptr[1] = binfo->buff_off[0];
+ ptr[2] = binfo->uvaddr[0];
+ ptr[3] = (u32) binfo->timestamp.tv_sec;
+ ptr[4] = (u32) binfo->timestamp.tv_usec;
+ ptr[5] = binfo->v4l2_index;
+ dprintk(VIDC_DBG,
+ "released buffer held in driver before issuing flush: 0x%x fd[0]: %d\n",
+ binfo->device_addr[0], binfo->fd[0]);
+ /*send event to client*/
+ v4l2_event_queue_fh(&inst->event_handler,
+ &buf_event);
+ wake_up(&inst->kernel_event_queue);
+ }
+ }
+ }
+ mutex_unlock(&inst->lock);
+}
+
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags)
{
int rc = 0;
@@ -2475,6 +2701,9 @@
kfree(temp);
}
}
+
+ msm_comm_flush_dynamic_buffers(inst);
+
/*Do not send flush in case of session_error */
if (!(inst->state == MSM_VIDC_CORE_INVALID &&
core->state != VIDC_CORE_INVALID))
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 03136ae..25651c9 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -36,6 +36,10 @@
__buf.filled_size = 0; \
})
+#define DYNAMIC_BUF_OWNER(__binfo) ({ \
+ atomic_read(&__binfo->ref_count) == 2 ? "video driver" : "firmware";\
+})
+
static int core_info_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -193,6 +197,37 @@
return 0;
}
+static int publish_unreleased_reference(struct msm_vidc_inst *inst)
+{
+ struct buffer_info *temp = NULL;
+ struct buffer_info *dummy = NULL;
+ struct list_head *list = NULL;
+
+ if (!inst) {
+ dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
+ return -EINVAL;
+ }
+
+ list = &inst->registered_bufs;
+ mutex_lock(&inst->lock);
+ if (inst->buffer_mode_set[CAPTURE_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
+ list_for_each_entry_safe(temp, dummy, list, list) {
+ if (temp && temp->type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+ !temp->inactive && atomic_read(&temp->ref_count)) {
+ write_str(&dbg_buf,
+ "\tpending buffer: 0x%x fd[0] = %d ref_count = %d held by: %s\n",
+ temp->device_addr[0],
+ temp->fd[0],
+ atomic_read(&temp->ref_count),
+ DYNAMIC_BUF_OWNER(temp));
+ }
+ }
+ }
+ mutex_unlock(&inst->lock);
+ return 0;
+}
+
static ssize_t inst_info_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -221,6 +256,19 @@
write_str(
&dbg_buf, "type: %s\n", inst->fmts[i]->type == OUTPUT_PORT ?
"Output" : "Capture");
+ switch (inst->buffer_mode_set[i]) {
+ case HAL_BUFFER_MODE_STATIC:
+ write_str(&dbg_buf, "buffer mode : %s\n", "static");
+ break;
+ case HAL_BUFFER_MODE_RING:
+ write_str(&dbg_buf, "buffer mode : %s\n", "ring");
+ break;
+ case HAL_BUFFER_MODE_DYNAMIC:
+ write_str(&dbg_buf, "buffer mode : %s\n", "dynamic");
+ break;
+ default:
+ write_str(&dbg_buf, "buffer mode : unsupported\n");
+ }
for (j = 0; j < inst->fmts[i]->num_planes; j++)
write_str(&dbg_buf, "size for plane %d: %u\n", j,
inst->bufq[i].vb2_bufq.plane_sizes[j]);
@@ -235,6 +283,8 @@
write_str(&dbg_buf, "EBD Count: %d\n", inst->count.ebd);
write_str(&dbg_buf, "FTB Count: %d\n", inst->count.ftb);
write_str(&dbg_buf, "FBD Count: %d\n", inst->count.fbd);
+ publish_unreleased_reference(inst);
+
return simple_read_from_buffer(buf, count, ppos,
dbg_buf.ptr, dbg_buf.filled_size);
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 0a078bd..b17cb5a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -14,7 +14,9 @@
#ifndef _MSM_VIDC_INTERNAL_H_
#define _MSM_VIDC_INTERNAL_H_
+#include <linux/atomic.h>
#include <linux/list.h>
+#include <linux/time.h>
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/wait.h>
@@ -228,6 +230,9 @@
struct buf_count count;
enum msm_vidc_modes flags;
struct msm_vidc_core_capability capability;
+ enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
+ struct list_head registered_bufs;
+ bool map_output_buffer;
};
extern struct msm_vidc_drv *vidc_driver;
@@ -257,4 +262,35 @@
int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
+struct buffer_info {
+ struct list_head list;
+ int type;
+ int num_planes;
+ int fd[VIDEO_MAX_PLANES];
+ int buff_off[VIDEO_MAX_PLANES];
+ int size[VIDEO_MAX_PLANES];
+ u32 uvaddr[VIDEO_MAX_PLANES];
+ u32 device_addr[VIDEO_MAX_PLANES];
+ struct msm_smem *handle[VIDEO_MAX_PLANES];
+ enum v4l2_memory memory;
+ u32 v4l2_index;
+ bool pending_deletion;
+ atomic_t ref_count;
+ bool dequeued;
+ bool inactive;
+ bool mapped[VIDEO_MAX_PLANES];
+ int same_fd_ref[VIDEO_MAX_PLANES];
+ struct timeval timestamp;
+};
+
+struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst,
+ struct list_head *list, u32 device_addr);
+int buf_ref_get(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int buf_ref_put(struct msm_vidc_inst *inst, struct buffer_info *binfo);
+int output_buffer_cache_invalidate(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo);
+int qbuf_dynamic_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo);
+int unmap_and_deregister_buf(struct msm_vidc_inst *inst,
+ struct buffer_info *binfo);
#endif
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index af58e22..70b93ff0 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -19,6 +19,7 @@
#define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3)
#define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4)
+#define HFI_EVENT_RELEASE_BUFFER_REFERENCE (HFI_OX_BASE + 0x6)
#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES \
(HFI_OX_BASE + 0x1)
@@ -138,8 +139,10 @@
(HFI_PROPERTY_PARAM_OX_START + 0x008)
#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA \
(HFI_PROPERTY_PARAM_OX_START + 0x009)
-#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED \
+#define HFI_PROPERTY_PARAM_ERR_DETECTION_CODE_EXTRADATA \
(HFI_PROPERTY_PARAM_OX_START + 0x00A)
+#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED \
+ (HFI_PROPERTY_PARAM_OX_START + 0x00B)
#define HFI_PROPERTY_CONFIG_OX_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index e5d6040..1c9b71d 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -864,6 +864,7 @@
enum hal_event_type {
HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES,
HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES,
+ HAL_EVENT_RELEASE_BUFFER_REFERENCE,
HAL_UNUSED_SEQCHG = 0x10000000,
};
@@ -932,6 +933,8 @@
u32 height;
u32 width;
u32 hal_event_type;
+ u8 *packet_buffer;
+ u8 *exra_data_buffer;
};
/* Data callback structure */
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index b5c431e..6589a7cf 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -64,7 +64,12 @@
#define HFI_ERR_SESSION_STREAM_CORRUPT (HFI_COMMON_BASE + 0x100B)
#define HFI_ERR_SESSION_ENC_OVERFLOW (HFI_COMMON_BASE + 0x100C)
-#define HFI_ERR_SESSION_UNSUPPORTED_STREAM (HFI_COMMON_BASE + 0x100D)
+#define HFI_ERR_SESSION_UNSUPPORTED_STREAM (HFI_COMMON_BASE + 0x100D)
+#define HFI_ERR_SESSION_CMDSIZE (HFI_COMMON_BASE + 0x100E)
+#define HFI_ERR_SESSION_UNSUPPORT_CMD (HFI_COMMON_BASE + 0x100F)
+#define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE (HFI_COMMON_BASE + 0x1010)
+#define HFI_ERR_SESSION_BUFFERCOUNT_TOOSMALL (HFI_COMMON_BASE + 0x1011)
+#define HFI_ERR_SESSION_INVALID_SCALE_FACTOR (HFI_COMMON_BASE + 0x1012)
#define HFI_EVENT_SYS_ERROR (HFI_COMMON_BASE + 0x1)
#define HFI_EVENT_SESSION_ERROR (HFI_COMMON_BASE + 0x2)
@@ -844,6 +849,12 @@
u32 rg_ext_event_data[1];
};
+struct hfi_msg_release_buffer_ref_event_packet {
+ u8 *packet_buffer;
+ u8 *exra_data_buffer;
+ u32 output_tag;
+};
+
struct hfi_msg_sys_init_done_packet {
u32 size;
u32 packet_type;
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 317c6a9..d8abc6d 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -1451,23 +1451,23 @@
dev_err(dev, "Looking up %s property in node %s failed",
"qcom,cdc-dmic-sample-rate",
dev->of_node->full_name);
- dmic_sample_rate = TAIKO_DMIC_SAMPLE_RATE_UNDEFINED;
+ dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
}
- if (pdata->mclk_rate == TAIKO_MCLK_CLK_9P6HZ) {
- if ((dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_2P4MHZ) &&
- (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_3P2MHZ) &&
- (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_4P8MHZ) &&
- (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_UNDEFINED)) {
+ if (pdata->mclk_rate == WCD9XXX_MCLK_CLK_9P6HZ) {
+ if ((dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ) &&
+ (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_3P2MHZ) &&
+ (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ) &&
+ (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED)) {
dev_err(dev, "Invalid dmic rate %d for mclk %d\n",
dmic_sample_rate, pdata->mclk_rate);
ret = -EINVAL;
goto err;
}
- } else if (pdata->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ) {
- if ((dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_3P072MHZ) &&
- (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_4P096MHZ) &&
- (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_6P144MHZ) &&
- (dmic_sample_rate != TAIKO_DMIC_SAMPLE_RATE_UNDEFINED)) {
+ } else if (pdata->mclk_rate == WCD9XXX_MCLK_CLK_12P288MHZ) {
+ if ((dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_3P072MHZ) &&
+ (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ) &&
+ (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_6P144MHZ) &&
+ (dmic_sample_rate != WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED)) {
dev_err(dev, "Invalid dmic rate %d for mclk %d\n",
dmic_sample_rate, pdata->mclk_rate);
ret = -EINVAL;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 7cc1c9f..a30607c 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -434,6 +434,12 @@
if (copy_from_user(&req, (void __user *)argp, sizeof(req)))
return -EFAULT;
+ if ((req.ifd_data_fd <= 0) || (req.virt_sb_base == 0) ||
+ (req.sb_len == 0)) {
+ pr_err("Inavlid input(s)ion_fd(%d), sb_len(%d), vaddr(0x%x)\n",
+ req.ifd_data_fd, req.sb_len, req.virt_sb_base);
+ return -EFAULT;
+ }
/* Get the handle of the shared fd */
data->client.ihandle = ion_import_dma_buf(qseecom.ion_clnt,
req.ifd_data_fd);
@@ -615,6 +621,7 @@
if (ret)
pr_warning("Unable to vote for SFPB clock");
req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
+ load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
ret = __qseecom_check_app_exists(req);
@@ -963,9 +970,22 @@
pr_err("cmd buffer or response buffer is null\n");
return -EINVAL;
}
+ if (((uint32_t)req->cmd_req_buf < data->client.user_virt_sb_base) ||
+ ((uint32_t)req->cmd_req_buf >= (data->client.user_virt_sb_base +
+ data->client.sb_length))) {
+ pr_err("cmd buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
- if (req->cmd_req_len <= 0 ||
- req->resp_len <= 0 ||
+
+ if (((uint32_t)req->resp_buf < data->client.user_virt_sb_base) ||
+ ((uint32_t)req->resp_buf >= (data->client.user_virt_sb_base +
+ data->client.sb_length))){
+ pr_err("response buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
+
+ if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
req->cmd_req_len > data->client.sb_length ||
req->resp_len > data->client.sb_length) {
pr_err("cmd buffer length or "
@@ -1203,6 +1223,7 @@
void __user *argp)
{
int ret = 0;
+ int i;
struct qseecom_send_modfd_cmd_req req;
struct qseecom_send_cmd_req send_cmd_req;
@@ -1216,6 +1237,14 @@
send_cmd_req.resp_buf = req.resp_buf;
send_cmd_req.resp_len = req.resp_len;
+ /* validate offsets */
+ for (i = 0; i < MAX_ION_FD; i++) {
+ if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
+ pr_err("Invalid offset %d = 0x%x\n",
+ i, req.ifd_data[i].cmd_buf_offset);
+ return -EINVAL;
+ }
+ }
ret = __qseecom_update_cmd_buf(&req, false, data, false);
if (ret)
return ret;
@@ -1806,11 +1835,20 @@
void __user *argp)
{
struct qseecom_send_modfd_listener_resp resp;
+ int i;
if (copy_from_user(&resp, argp, sizeof(resp))) {
pr_err("copy_from_user failed");
return -EINVAL;
}
+ /* validate offsets */
+ for (i = 0; i < MAX_ION_FD; i++) {
+ if (resp.ifd_data[i].cmd_buf_offset >= resp.resp_len) {
+ pr_err("Invalid offset %d = 0x%x\n",
+ i, resp.ifd_data[i].cmd_buf_offset);
+ return -EINVAL;
+ }
+ }
__qseecom_update_cmd_buf(&resp, false, data, true);
qseecom.send_resp_flag = 1;
wake_up_interruptible(&qseecom.send_resp_wq);
@@ -2259,6 +2297,7 @@
}
req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
+ query_req.app_name[MAX_APP_NAME_SIZE-1] = '\0';
memcpy(req.app_name, query_req.app_name, MAX_APP_NAME_SIZE);
ret = __qseecom_check_app_exists(req);
@@ -2680,6 +2719,12 @@
switch (cmd) {
case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
+ if (data->type != QSEECOM_GENERIC) {
+ pr_err("reg lstnr req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
pr_debug("ioctl register_listener_req()\n");
atomic_inc(&data->ioctl_count);
data->type = QSEECOM_LISTENER_SERVICE;
@@ -2691,6 +2736,13 @@
break;
}
case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
+ if ((data->listener.id == 0) ||
+ (data->type != QSEECOM_LISTENER_SERVICE)) {
+ pr_err("unreg lstnr req: invalid handle (%d) lid(%d)\n",
+ data->type, data->listener.id);
+ ret = -EINVAL;
+ break;
+ }
pr_debug("ioctl unregister_listener_req()\n");
atomic_inc(&data->ioctl_count);
ret = qseecom_unregister_listener(data);
@@ -2701,6 +2753,13 @@
break;
}
case QSEECOM_IOCTL_SEND_CMD_REQ: {
+ if ((data->client.app_id == 0) ||
+ (data->type != QSEECOM_CLIENT_APP)) {
+ pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
+ data->type, data->client.app_id);
+ ret = -EINVAL;
+ break;
+ }
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
@@ -2713,6 +2772,13 @@
break;
}
case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
+ if ((data->client.app_id == 0) ||
+ (data->type != QSEECOM_CLIENT_APP)) {
+ pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
+ data->type, data->client.app_id);
+ ret = -EINVAL;
+ break;
+ }
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
@@ -2725,6 +2791,13 @@
break;
}
case QSEECOM_IOCTL_RECEIVE_REQ: {
+ if ((data->listener.id == 0) ||
+ (data->type != QSEECOM_LISTENER_SERVICE)) {
+ pr_err("receive req: invalid handle (%d), lid(%d)\n",
+ data->type, data->listener.id);
+ ret = -EINVAL;
+ break;
+ }
atomic_inc(&data->ioctl_count);
ret = qseecom_receive_req(data);
atomic_dec(&data->ioctl_count);
@@ -2734,6 +2807,13 @@
break;
}
case QSEECOM_IOCTL_SEND_RESP_REQ: {
+ if ((data->listener.id == 0) ||
+ (data->type != QSEECOM_LISTENER_SERVICE)) {
+ pr_err("send resp req: invalid handle (%d), lid(%d)\n",
+ data->type, data->listener.id);
+ ret = -EINVAL;
+ break;
+ }
atomic_inc(&data->ioctl_count);
ret = qseecom_send_resp();
atomic_dec(&data->ioctl_count);
@@ -2743,7 +2823,14 @@
break;
}
case QSEECOM_IOCTL_SET_MEM_PARAM_REQ: {
- data->type = QSEECOM_CLIENT_APP;
+ if ((data->type != QSEECOM_CLIENT_APP) &&
+ (data->type != QSEECOM_GENERIC) &&
+ (data->type != QSEECOM_SECURE_SERVICE)) {
+ pr_err("set mem param req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
ret = qseecom_set_client_mem_param(data, argp);
if (ret)
@@ -2752,6 +2839,13 @@
break;
}
case QSEECOM_IOCTL_LOAD_APP_REQ: {
+ if ((data->type != QSEECOM_GENERIC) &&
+ (data->type != QSEECOM_CLIENT_APP)) {
+ pr_err("load app req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
data->type = QSEECOM_CLIENT_APP;
pr_debug("LOAD_APP_REQ: qseecom_addr = 0x%x\n", (u32)data);
mutex_lock(&app_access_lock);
@@ -2772,6 +2866,13 @@
break;
}
case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
+ if ((data->client.app_id == 0) ||
+ (data->type != QSEECOM_CLIENT_APP)) {
+ pr_err("unload app req:invalid handle(%d) app_id(%d)\n",
+ data->type, data->client.app_id);
+ ret = -EINVAL;
+ break;
+ }
pr_debug("UNLOAD_APP: qseecom_addr = 0x%x\n", (u32)data);
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
@@ -2791,6 +2892,20 @@
break;
}
case QSEECOM_IOCTL_PERF_ENABLE_REQ:{
+ if ((data->type != QSEECOM_GENERIC) &&
+ (data->type != QSEECOM_CLIENT_APP)) {
+ pr_err("perf enable req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
+ if ((data->type == QSEECOM_CLIENT_APP) &&
+ (data->client.app_id == 0)) {
+ pr_err("perf enable req:invalid handle(%d) appid(%d)\n",
+ data->type, data->client.app_id);
+ ret = -EINVAL;
+ break;
+ }
atomic_inc(&data->ioctl_count);
ret = qsee_vote_for_clock(data, CLK_DFAB);
if (ret)
@@ -2802,13 +2917,33 @@
break;
}
case QSEECOM_IOCTL_PERF_DISABLE_REQ:{
+ if ((data->type != QSEECOM_SECURE_SERVICE) &&
+ (data->type != QSEECOM_CLIENT_APP)) {
+ pr_err("perf disable req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
+ if ((data->type == QSEECOM_CLIENT_APP) &&
+ (data->client.app_id == 0)) {
+ pr_err("perf disable: invalid handle (%d)app_id(%d)\n",
+ data->type, data->client.app_id);
+ ret = -EINVAL;
+ break;
+ }
atomic_inc(&data->ioctl_count);
- qsee_disable_clock_vote(data, CLK_DFAB);
- qsee_disable_clock_vote(data, CLK_SFPB);
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
atomic_dec(&data->ioctl_count);
break;
}
case QSEECOM_IOCTL_LOAD_EXTERNAL_ELF_REQ: {
+ if (data->type != QSEECOM_GENERIC) {
+ pr_err("load ext elf req: invalid client handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
data->type = QSEECOM_UNAVAILABLE_CLIENT_APP;
data->released = true;
mutex_lock(&app_access_lock);
@@ -2821,6 +2956,12 @@
break;
}
case QSEECOM_IOCTL_UNLOAD_EXTERNAL_ELF_REQ: {
+ if (data->type != QSEECOM_UNAVAILABLE_CLIENT_APP) {
+ pr_err("unload ext elf req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
data->released = true;
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
@@ -2842,9 +2983,15 @@
break;
}
case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
+ if (data->type != QSEECOM_GENERIC) {
+ pr_err("send cmd svc req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
data->type = QSEECOM_SECURE_SERVICE;
if (qseecom.qsee_version < QSEE_VERSION_03) {
- pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee version %u\n",
+ pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee ver %u\n",
qseecom.qsee_version);
return -EINVAL;
}
@@ -2856,8 +3003,14 @@
break;
}
case QSEECOM_IOCTL_CREATE_KEY_REQ: {
+ if (data->type != QSEECOM_GENERIC) {
+ pr_err("create key req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
if (qseecom.qsee_version < QSEE_VERSION_05) {
- pr_err("Create Key feature not supported in qsee version %u\n",
+ pr_err("Create Key feature unsupported: qsee ver %u\n",
qseecom.qsee_version);
return -EINVAL;
}
@@ -2873,8 +3026,14 @@
break;
}
case QSEECOM_IOCTL_WIPE_KEY_REQ: {
+ if (data->type != QSEECOM_GENERIC) {
+ pr_err("wipe key req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
if (qseecom.qsee_version < QSEE_VERSION_05) {
- pr_err("Wipe Key feature not supported in qsee version %u\n",
+ pr_err("Wipe Key feature unsupported in qsee ver %u\n",
qseecom.qsee_version);
return -EINVAL;
}
@@ -2889,6 +3048,12 @@
break;
}
case QSEECOM_IOCTL_SAVE_PARTITION_HASH_REQ: {
+ if (data->type != QSEECOM_GENERIC) {
+ pr_err("save part hash req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
data->released = true;
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
@@ -2898,6 +3063,12 @@
break;
}
case QSEECOM_IOCTL_IS_ES_ACTIVATED_REQ: {
+ if (data->type != QSEECOM_GENERIC) {
+ pr_err("ES activated req: invalid handle (%d)\n",
+ data->type);
+ ret = -EINVAL;
+ break;
+ }
data->released = true;
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
@@ -2907,6 +3078,13 @@
break;
}
case QSEECOM_IOCTL_SEND_MODFD_RESP: {
+ if ((data->listener.id == 0) ||
+ (data->type != QSEECOM_LISTENER_SERVICE)) {
+ pr_err("receive req: invalid handle (%d), lid(%d)\n",
+ data->type, data->listener.id);
+ ret = -EINVAL;
+ break;
+ }
/* Only one client allowed here at a time */
atomic_inc(&data->ioctl_count);
ret = qseecom_send_modfd_resp(data, argp);
@@ -2917,6 +3095,13 @@
break;
}
case QSEECOM_IOCTL_UNPROTECT_BUF: {
+ if ((data->listener.id == 0) ||
+ (data->type != QSEECOM_LISTENER_SERVICE)) {
+ pr_err("receive req: invalid handle (%d), lid(%d)\n",
+ data->type, data->listener.id);
+ ret = -EINVAL;
+ break;
+ }
/* Only one client allowed here at a time */
atomic_inc(&data->ioctl_count);
ret = qseecom_unprotect_buffer(argp);
@@ -2927,6 +3112,7 @@
break;
}
default:
+ pr_err("Invalid IOCTL: %d\n", cmd);
return -EINVAL;
}
return ret;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1e2d367..293033b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2688,13 +2688,19 @@
unsigned long mmc_get_max_frequency(struct mmc_host *host)
{
unsigned long freq;
+ unsigned char timing;
if (host->ops && host->ops->get_max_frequency) {
freq = host->ops->get_max_frequency(host);
goto out;
}
- switch (host->ios.timing) {
+ if (mmc_card_hs400(host->card))
+ timing = MMC_TIMING_MMC_HS400;
+ else
+ timing = host->ios.timing;
+
+ switch (timing) {
case MMC_TIMING_UHS_SDR50:
freq = UHS_SDR50_MAX_DTR;
break;
@@ -2707,6 +2713,9 @@
case MMC_TIMING_UHS_DDR50:
freq = UHS_DDR50_MAX_DTR;
break;
+ case MMC_TIMING_MMC_HS400:
+ freq = MMC_HS400_MAX_DTR;
+ break;
default:
mmc_host_clk_hold(host);
freq = host->ios.clock;
@@ -2747,6 +2756,9 @@
case MMC_TIMING_MMC_HS200:
freq = MMC_HIGH_52_MAX_DTR;
break;
+ case MMC_TIMING_MMC_HS400:
+ freq = MMC_HIGH_52_MAX_DTR;
+ break;
case MMC_TIMING_UHS_DDR50:
freq = UHS_DDR50_MAX_DTR / 2;
break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e1609cf..997e14b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1177,6 +1177,26 @@
return err;
}
+int mmc_set_clock_bus_speed(struct mmc_card *card, unsigned long freq)
+{
+ int err;
+
+ if (freq < MMC_HS400_MAX_DTR) {
+ /*
+ * Lower the clock and adjust the timing to be able
+ * to switch to HighSpeed mode
+ */
+ mmc_set_timing(card->host, MMC_TIMING_LEGACY);
+ mmc_set_clock(card->host, MMC_HIGH_26_MAX_DTR);
+
+ err = mmc_select_hs(card, &card->cached_ext_csd);
+ } else {
+ err = mmc_select_hs400(card, &card->cached_ext_csd);
+ }
+
+ return err;
+}
+
/**
* mmc_change_bus_speed() - Change MMC card bus frequency at runtime
* @host: pointer to mmc host structure
@@ -1219,7 +1239,13 @@
if (*freq < host->f_min)
*freq = host->f_min;
- mmc_set_clock(host, (unsigned int) (*freq));
+ if (mmc_card_hs400(card)) {
+ err = mmc_set_clock_bus_speed(card, *freq);
+ if (err)
+ goto out;
+ } else {
+ mmc_set_clock(host, (unsigned int) (*freq));
+ }
if ((mmc_card_hs400(card) || mmc_card_hs200(card))
&& card->host->ops->execute_tuning) {
@@ -1413,6 +1439,7 @@
err = mmc_get_ext_csd(card, &ext_csd);
if (err)
goto free_card;
+ memcpy(&card->cached_ext_csd, ext_csd, sizeof(card->ext_csd));
err = mmc_read_ext_csd(card, ext_csd);
if (err)
goto free_card;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 04ca7f8..64ad940 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -244,6 +244,7 @@
* @btc_disabled Flag to disable btc (disables hot and cold irqs)
* @max_voltage_mv: the max volts the batt should be charged up to
* @min_voltage_mv: min battery voltage before turning the FET on
+ * @batt_weak_voltage_mv: Weak battery voltage threshold
* @max_bat_chg_current: maximum battery charge current in mA
* @warm_bat_chg_ma: warm battery maximum charge current in mA
* @cool_bat_chg_ma: cool battery maximum charge current in mA
@@ -316,6 +317,7 @@
unsigned int safe_voltage_mv;
unsigned int max_voltage_mv;
unsigned int min_voltage_mv;
+ unsigned int batt_weak_voltage_mv;
int prev_usb_max_ma;
int set_vddmax_mv;
int delta_vddmax_mv;
@@ -850,7 +852,7 @@
#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
+#define QPNP_CHG_VINMIN_MASK 0x3F
#define QPNP_CHG_VINMIN_MIN_VAL 0x10
static int
qpnp_chg_vinmin_set(struct qpnp_chg_chip *chip, int voltage)
@@ -905,6 +907,26 @@
return vin_min_mv;
}
+#define QPNP_CHG_VBATWEAK_MIN_MV 2100
+#define QPNP_CHG_VBATWEAK_MAX_MV 3600
+#define QPNP_CHG_VBATWEAK_STEP_MV 100
+static int
+qpnp_chg_vbatweak_set(struct qpnp_chg_chip *chip, int vbatweak_mv)
+{
+ u8 temp;
+
+ if (vbatweak_mv < QPNP_CHG_VBATWEAK_MIN_MV
+ || vbatweak_mv > QPNP_CHG_VBATWEAK_MAX_MV)
+ return -EINVAL;
+
+ temp = (vbatweak_mv - QPNP_CHG_VBATWEAK_MIN_MV)
+ / QPNP_CHG_VBATWEAK_STEP_MV;
+
+ pr_debug("voltage=%d setting %02x\n", vbatweak_mv, temp);
+ return qpnp_chg_write(chip, &temp,
+ chip->chgr_base + CHGR_VBAT_WEAK, 1);
+}
+
static int
qpnp_chg_usb_iusbmax_get(struct qpnp_chg_chip *chip)
{
@@ -3665,6 +3687,8 @@
case SMBB_CHGR_SUBTYPE:
case SMBBP_CHGR_SUBTYPE:
case SMBCL_CHGR_SUBTYPE:
+ qpnp_chg_vbatweak_set(chip, chip->batt_weak_voltage_mv);
+
rc = qpnp_chg_vinmin_set(chip, chip->min_voltage_mv);
if (rc) {
pr_debug("failed setting min_voltage rc=%d\n", rc);
@@ -3987,6 +4011,7 @@
OF_PROP_READ(chip, hot_batt_p, "batt-hot-percentage", rc, 1);
OF_PROP_READ(chip, cold_batt_p, "batt-cold-percentage", rc, 1);
OF_PROP_READ(chip, soc_resume_limit, "resume-soc", rc, 1);
+ OF_PROP_READ(chip, batt_weak_voltage_mv, "vbatweak-mv", rc, 1);
if (rc)
return rc;
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 1b1ddf1..8f6168a 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -54,6 +54,7 @@
[MDP_YCRYCB_H2V1] = true,
[MDP_Y_CBCR_H2V1] = true,
[MDP_Y_CRCB_H2V1] = true,
+ [MDP_BGRX_8888] = true,
};
#define MAX_LIST_WINDOW 16
@@ -554,8 +555,9 @@
tmp_v =
(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
MDP_MAX_X_SCALE_FACTOR +
- (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) %
- MDP_MAX_X_SCALE_FACTOR ? 1 : 0;
+ ((MDP_SCALE_Q_FACTOR *
+ blit_op->dst.roi.height) %
+ MDP_MAX_X_SCALE_FACTOR ? 1 : 0);
/* move x location as roi width gets bigger */
blit_op->src.roi.x -= tmp_v - blit_op->src.roi.width;
@@ -565,8 +567,9 @@
tmp_v =
(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
MDP_MIN_X_SCALE_FACTOR +
- (MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) %
- MDP_MIN_X_SCALE_FACTOR ? 1 : 0;
+ ((MDP_SCALE_Q_FACTOR *
+ blit_op->dst.roi.height) %
+ MDP_MIN_X_SCALE_FACTOR ? 1 : 0);
/*
* we don't move x location for continuity of
diff --git a/drivers/video/msm/mdss/mdp3_ppp_data.c b/drivers/video/msm/mdss/mdp3_ppp_data.c
index ba2a369..e562ad3 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_data.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_data.c
@@ -36,6 +36,7 @@
[MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_SRC_REG,
[MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
[MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
+ [MDP_BGRX_8888] = MDP_RGBX_8888_SRC_REG,
};
const uint32_t out_cfg_lut[MDP_IMGTYPE_LIMIT] = {
@@ -55,6 +56,7 @@
[MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_DST_REG,
[MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
[MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
+ [MDP_BGRX_8888] = MDP_RGBX_8888_DST_REG,
};
const uint32_t pack_patt_lut[MDP_IMGTYPE_LIMIT] = {
@@ -62,8 +64,8 @@
[MDP_BGR_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
[MDP_RGB_888] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
[MDP_BGR_888] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
- [MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
- CLR_G, CLR_B, 8),
+ [MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B,
+ CLR_G, CLR_R, 8),
[MDP_RGBA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
CLR_G, CLR_B, 8),
[MDP_ARGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
@@ -82,6 +84,8 @@
CLR_CR, CLR_Y, CLR_CB, 8),
[MDP_Y_CBCR_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
[MDP_Y_CRCB_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
+ [MDP_BGRX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B,
+ CLR_G, CLR_R, 8),
};
const uint32_t dst_op_reg[MDP_IMGTYPE_LIMIT] = {
@@ -121,6 +125,7 @@
[MDP_Y_CRCB_H2V1] = 1,
[MDP_Y_CRCB_H2V2] = 1,
[MDP_YCRYCB_H2V1] = 2,
+ [MDP_BGRX_8888] = 4,
};
const bool per_pixel_alpha[MDP_IMGTYPE_LIMIT] = {
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
index a051037..eb01d00 100644
--- a/drivers/video/msm/mdss/mdp3_ppp_hwio.c
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -354,6 +354,7 @@
case MDP_ARGB_8888:
case MDP_XRGB_8888:
case MDP_RGBX_8888:
+ case MDP_BGRX_8888:
rgb = true;
default:
break;
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 3bf27e2..5857606 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -69,6 +69,8 @@
struct clk *mdp_clk[MDSS_MAX_CLK];
struct regulator *fs;
struct regulator *vdd_cx;
+ bool batfet_required;
+ struct regulator *batfet;
u32 max_mdp_clk_rate;
struct platform_device *pdev;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 8addec3..4ca0a3f 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -591,9 +591,6 @@
},
};
-static int unset_bl_level, bl_updated;
-static int bl_level_old;
-
static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
{
u32 temp = *bl_lvl;
@@ -615,11 +612,11 @@
* scaling fraction (x/1024)
*/
temp = (temp * mfd->bl_scale) / 1024;
-
- /*if less than minimum level, use min level*/
- if (temp < mfd->bl_min_lvl)
- temp = mfd->bl_min_lvl;
}
+ /*if less than minimum level, use min level*/
+ else if ((temp < mfd->bl_min_lvl) && (0 != temp))
+ temp = mfd->bl_min_lvl;
+
pr_debug("output = %d", temp);
(*bl_lvl) = temp;
@@ -632,11 +629,15 @@
int (*update_ad_input)(struct msm_fb_data_type *mfd);
u32 temp = bkl_lvl;
- if ((!mfd->panel_power_on || !bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
- unset_bl_level = bkl_lvl;
- return;
+ if (((!mfd->panel_power_on && mfd->dcm_state != DCM_ENTER)
+ || !mfd->bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
+ if (bkl_lvl < mfd->bl_min_lvl)
+ mfd->unset_bl_level = mfd->bl_min_lvl;
+ else
+ mfd->unset_bl_level = bkl_lvl;
+ return;
} else {
- unset_bl_level = 0;
+ mfd->unset_bl_level = 0;
}
pdata = dev_get_platdata(&mfd->pdev->dev);
@@ -652,13 +653,13 @@
* as well as setting bl_level to bkl_lvl even though the
* backlight has been set to the scaled value.
*/
- if (bl_level_old == temp) {
+ if (mfd->bl_level_old == temp) {
mfd->bl_level = bkl_lvl;
return;
}
pdata->set_backlight(pdata, temp);
mfd->bl_level = bkl_lvl;
- bl_level_old = temp;
+ mfd->bl_level_old = temp;
if (mfd->mdp.update_ad_input) {
update_ad_input = mfd->mdp.update_ad_input;
@@ -674,15 +675,15 @@
{
struct mdss_panel_data *pdata;
- if (unset_bl_level && !bl_updated) {
+ if (mfd->unset_bl_level && !mfd->bl_updated) {
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->set_backlight)) {
mutex_lock(&mfd->bl_lock);
- mfd->bl_level = unset_bl_level;
+ mfd->bl_level = mfd->unset_bl_level;
pdata->set_backlight(pdata, mfd->bl_level);
- bl_level_old = unset_bl_level;
+ mfd->bl_level_old = mfd->unset_bl_level;
mutex_unlock(&mfd->bl_lock);
- bl_updated = 1;
+ mfd->bl_updated = 1;
}
}
}
@@ -729,7 +730,7 @@
mfd->op_enable = false;
curr_pwr_state = mfd->panel_power_on;
mfd->panel_power_on = false;
- bl_updated = 0;
+ mfd->bl_updated = 0;
ret = mfd->mdp.off_fnc(mfd);
if (ret)
@@ -1718,7 +1719,7 @@
static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
struct mdp_buf_sync *buf_sync)
{
- int i, fence_cnt = 0, ret = 0;
+ int i, ret = 0;
int acq_fen_fd[MDP_MAX_FENCE_FD];
struct sync_fence *fence;
@@ -1745,10 +1746,9 @@
}
sync_pt_data->acq_fen[i] = fence;
}
- fence_cnt = i;
+ sync_pt_data->acq_fen_cnt = i;
if (ret)
goto buf_sync_err_1;
- sync_pt_data->acq_fen_cnt = fence_cnt;
if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
mdss_fb_wait_for_fence(sync_pt_data);
@@ -1799,7 +1799,7 @@
sync_pt_data->cur_rel_fence = NULL;
sync_pt_data->cur_rel_fen_fd = 0;
buf_sync_err_1:
- for (i = 0; i < fence_cnt; i++)
+ for (i = 0; i < sync_pt_data->acq_fen_cnt; i++)
sync_fence_put(sync_pt_data->acq_fen[i]);
sync_pt_data->acq_fen_cnt = 0;
mutex_unlock(&sync_pt_data->sync_mutex);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 1400bdd..256789d 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -140,6 +140,9 @@
u32 bl_level;
u32 bl_scale;
u32 bl_min_lvl;
+ u32 unset_bl_level;
+ u32 bl_updated;
+ u32 bl_level_old;
struct mutex bl_lock;
struct mutex lock;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_cec.c b/drivers/video/msm/mdss/mdss_hdmi_cec.c
index ecde0b9..410f2b3 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_cec.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_cec.c
@@ -350,7 +350,8 @@
(msg->operand[i] << 8) | frame_type);
while ((DSS_REG_R(io, HDMI_CEC_STATUS) & BIT(0)) &&
- line_check_retry--) {
+ line_check_retry) {
+ line_check_retry--;
DEV_DBG("%s: CEC line is busy(%d)\n", __func__,
line_check_retry);
schedule();
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index b000e2f..0074873 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -29,6 +29,9 @@
#define BUFF_SIZE_3D 128
+/* Support for first 5 EDID blocks */
+#define MAX_EDID_BLOCK_SIZE (0x80 * 5)
+
struct hdmi_edid_sink_data {
u32 disp_mode_list[HDMI_VFRMT_MAX];
u32 disp_3d_mode_list[HDMI_VFRMT_MAX];
@@ -52,6 +55,7 @@
int adb_size;
u8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE];
int sadb_size;
+ u8 edid_buf[MAX_EDID_BLOCK_SIZE];
struct hdmi_edid_sink_data sink_data;
struct hdmi_edid_init_data init_data;
@@ -352,11 +356,30 @@
} /* hdmi_edid_sysfs_rda_3d_modes */
static DEVICE_ATTR(edid_3d_modes, S_IRUGO, hdmi_edid_sysfs_rda_3d_modes, NULL);
+static ssize_t hdmi_common_rda_edid_raw_data(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hdmi_edid_ctrl *edid_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_EDID);
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(buf, edid_ctrl->edid_buf,
+ sizeof(edid_ctrl->edid_buf));
+
+ return sizeof(edid_ctrl->edid_buf);
+} /* hdmi_common_rda_edid_raw_data */
+static DEVICE_ATTR(edid_raw_data, S_IRUGO, hdmi_common_rda_edid_raw_data, NULL);
+
static struct attribute *hdmi_edid_fs_attrs[] = {
&dev_attr_edid_modes.attr,
&dev_attr_pa.attr,
&dev_attr_scan_info.attr,
&dev_attr_edid_3d_modes.attr,
+ &dev_attr_edid_raw_data.attr,
NULL,
};
@@ -1305,7 +1328,7 @@
int hdmi_edid_read(void *input)
{
/* EDID_BLOCK_SIZE[0x80] Each page size in the EDID ROM */
- u8 edid_buf[0x80 * 4];
+ u8 *edid_buf = NULL;
u32 cea_extension_ver = 0;
u32 num_of_cea_blocks = 0;
u32 ieee_reg_id = 0;
@@ -1319,12 +1342,14 @@
return -EINVAL;
}
+ edid_buf = edid_ctrl->edid_buf;
+
edid_ctrl->pt_scan_info = 0;
edid_ctrl->it_scan_info = 0;
edid_ctrl->ce_scan_info = 0;
edid_ctrl->present_3d = 0;
memset(&edid_ctrl->sink_data, 0, sizeof(edid_ctrl->sink_data));
- memset(edid_buf, 0, sizeof(edid_buf));
+ memset(edid_buf, 0, sizeof(edid_ctrl->edid_buf));
memset(edid_ctrl->audio_data_block, 0,
sizeof(edid_ctrl->audio_data_block));
memset(edid_ctrl->spkr_alloc_data_block, 0,
@@ -1391,7 +1416,7 @@
for (i = 1; i <= num_of_cea_blocks; i++) {
if (!(i % 2)) {
status = hdmi_edid_read_block(
- edid_ctrl, i, edid_buf+0x00);
+ edid_ctrl, i, edid_buf + (0x80 * i));
if (status) {
DEV_ERR("%s: read blk(%d) failed:%d\n",
__func__, i, status);
@@ -1399,7 +1424,7 @@
}
} else {
status = hdmi_edid_read_block(
- edid_ctrl, i, edid_buf+0x80);
+ edid_ctrl, i, edid_buf + (0x80 * i));
if (status) {
DEV_ERR("%s: read blk(%d) failed:%d\n",
__func__, i, status);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index 367c918..bf28e8c 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -17,6 +17,7 @@
#include <linux/stat.h>
#include "mdss_hdmi_hdcp.h"
+#include "video/msm_hdmi_hdcp_mgr.h"
#define HDCP_STATE_NAME (hdcp_state_name(hdcp_ctrl->hdcp_state))
@@ -31,7 +32,11 @@
#define HDCP_KEYS_STATE_RESERVED 7
struct hdmi_hdcp_ctrl {
+ u32 auth_retries;
+ u32 tp_msgid;
enum hdmi_hdcp_state hdcp_state;
+ struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
+ struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
struct delayed_work hdcp_auth_work;
struct work_struct hdcp_int_work;
struct completion r0_checked;
@@ -194,7 +199,7 @@
bool is_match;
bool stale_an = false;
struct dss_io_data *io;
- u8 aksv[5], bksv[5];
+ u8 aksv[5], *bksv = NULL;
u8 an[8];
u8 bcaps;
struct hdmi_tx_ddc_data ddc_data;
@@ -215,6 +220,8 @@
goto error;
}
+ bksv = hdcp_ctrl->current_tp.bksv;
+
io = hdcp_ctrl->init_data.core_io;
/* Fetch aksv from QFPROM, this info should be public. */
@@ -606,11 +613,12 @@
{
int rc, cnt, i;
struct hdmi_tx_ddc_data ddc_data;
- u32 timeout_count, down_stream_devices;
+ u32 timeout_count, down_stream_devices = 0;
+ u32 repeater_cascade_depth = 0;
u8 buf[0xFF];
- u8 ksv_fifo[5 * 127];
+ u8 *ksv_fifo = NULL;
u8 bcaps;
- u16 bstatus, max_devs_exceeded, max_cascade_exceeded;
+ u16 bstatus, max_devs_exceeded = 0, max_cascade_exceeded = 0;
u32 link0_status;
u32 ksv_bytes;
struct dss_io_data *io;
@@ -628,10 +636,13 @@
goto error;
}
+ ksv_fifo = hdcp_ctrl->current_tp.ksv_list;
+
io = hdcp_ctrl->init_data.core_io;
memset(buf, 0, sizeof(buf));
- memset(ksv_fifo, 0, sizeof(ksv_fifo));
+ memset(ksv_fifo, 0,
+ sizeof(hdcp_ctrl->current_tp.ksv_list));
/* Read BCAPS at offset 0x40 */
memset(&ddc_data, 0, sizeof(ddc_data));
@@ -652,6 +663,10 @@
DEV_DBG("%s: %s: BCAPS=%02x (%s)\n", __func__, HDCP_STATE_NAME, bcaps,
(bcaps & BIT(6)) ? "repeater" : "no repeater");
+ /* receiver (0), repeater (1) */
+ hdcp_ctrl->current_tp.ds_type =
+ (bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
+
/* if REPEATER (Bit 6), perform Part2 Authentication */
if (!(bcaps & BIT(6))) {
DEV_INFO("%s: %s: auth part II skipped, no repeater\n",
@@ -717,6 +732,9 @@
goto error;
}
+ /* Cascaded repeater depth */
+ repeater_cascade_depth = (bstatus >> 8) & 0x7;
+
/*
* HDCP Compliance 1B-05:
* Check if no. of devices connected to repeater
@@ -866,9 +884,46 @@
else
DEV_INFO("%s: %s: Authentication Part II successful\n",
__func__, HDCP_STATE_NAME);
+
+ /* Update topology information */
+ hdcp_ctrl->current_tp.dev_count = down_stream_devices;
+ hdcp_ctrl->current_tp.max_cascade_exceeded = max_cascade_exceeded;
+ hdcp_ctrl->current_tp.max_dev_exceeded = max_devs_exceeded;
+ hdcp_ctrl->current_tp.depth = repeater_cascade_depth;
+
return rc;
} /* hdmi_hdcp_authentication_part2 */
+static void hdmi_hdcp_cache_topology(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ memcpy((void *)&hdcp_ctrl->cached_tp,
+ (void *) &hdcp_ctrl->current_tp,
+ sizeof(hdcp_ctrl->cached_tp));
+}
+
+static void hdmi_hdcp_notify_topology(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ char a[16], b[16];
+ char *envp[] = {
+ [0] = "HDCP_MGR_EVENT=MSG_READY",
+ [1] = a,
+ [2] = b,
+ NULL,
+ };
+
+ snprintf(envp[1], 16, "%d", (int)DOWN_CHECK_TOPOLOGY);
+ snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX);
+ kobject_uevent_env(hdcp_ctrl->init_data.sysfs_kobj, KOBJ_CHANGE, envp);
+
+ DEV_DBG("%s Event Sent: %s msgID = %s srcID = %s\n", __func__,
+ envp[0], envp[1], envp[2]);
+}
+
static void hdmi_hdcp_int_work(struct work_struct *work)
{
struct hdmi_hdcp_ctrl *hdcp_ctrl = container_of(work,
@@ -928,7 +983,7 @@
goto error;
}
/* Disabling software DDC before going into part3 to make sure
- * there is no Arbitratioon between software and hardware for DDC */
+ * there is no Arbitration between software and hardware for DDC */
DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io,
HDMI_DDC_ARBITRATION) | (BIT(4)));
@@ -941,10 +996,14 @@
*/
mutex_lock(hdcp_ctrl->init_data.mutex);
if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
- if (rc)
+ if (rc) {
hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAIL;
- else
+ } else {
hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATED;
+ hdcp_ctrl->auth_retries = 0;
+ hdmi_hdcp_cache_topology(hdcp_ctrl);
+ hdmi_hdcp_notify_topology(hdcp_ctrl);
+ }
mutex_unlock(hdcp_ctrl->init_data.mutex);
/* Notify HDMI Tx controller of the result */
@@ -989,10 +1048,38 @@
return 0;
} /* hdmi_hdcp_authenticate */
+/*
+ * Only retries defined times then abort current authenticating process
+ * Send check_topology message to notify any hdcpmanager's client of non-
+ * hdcp authenticated data link so the client can tear down any active secure
+ * playback.
+ * Reduce hdcp link to regular hdmi data link with hdcp disabled so any
+ * un-secure like UI & menu still can be sent over HDMI and display.
+ */
+#define AUTH_RETRIES_TIME (30)
+static int hdmi_msm_if_abort_reauth(struct hdmi_hdcp_ctrl *hdcp_ctrl)
+{
+ int ret = 0;
+
+ if (!hdcp_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (++hdcp_ctrl->auth_retries == AUTH_RETRIES_TIME) {
+ hdmi_hdcp_off(hdcp_ctrl);
+ hdcp_ctrl->auth_retries = 0;
+ ret = -ERANGE;
+ }
+
+ return ret;
+}
+
int hdmi_hdcp_reauthenticate(void *input)
{
struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
struct dss_io_data *io;
+ u32 ret = 0;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -1001,13 +1088,19 @@
io = hdcp_ctrl->init_data.core_io;
-
if (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state) {
DEV_DBG("%s: %s: invalid state. returning\n", __func__,
HDCP_STATE_NAME);
return 0;
}
+ ret = hdmi_msm_if_abort_reauth(hdcp_ctrl);
+
+ if (ret) {
+ DEV_ERR("%s: abort reauthentication!\n", __func__);
+ return ret;
+ }
+
/*
* Disable HPD circuitry.
* This is needed to reset the HDCP cipher engine so that when we
@@ -1042,7 +1135,7 @@
queue_delayed_work(hdcp_ctrl->init_data.workq,
&hdcp_ctrl->hdcp_auth_work, HZ/2);
- return 0;
+ return ret;
} /* hdmi_hdcp_reauthenticate */
void hdmi_hdcp_off(void *input)
@@ -1192,10 +1285,76 @@
return ret;
} /* hdmi_hdcp_sysfs_rda_hdcp*/
+static ssize_t hdmi_hdcp_sysfs_rda_tp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ struct hdmi_hdcp_ctrl *hdcp_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP);
+
+ if (!hdcp_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (hdcp_ctrl->tp_msgid) {
+ case DOWN_CHECK_TOPOLOGY:
+ case DOWN_REQUEST_TOPOLOGY:
+ buf[MSG_ID_IDX] = hdcp_ctrl->tp_msgid;
+ buf[RET_CODE_IDX] = HDCP_AUTHED;
+ ret = HEADER_LEN;
+
+ memcpy(buf + HEADER_LEN, &hdcp_ctrl->cached_tp,
+ sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
+
+ ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
+
+ /* clear the flag once data is read back to user space*/
+ hdcp_ctrl->tp_msgid = -1;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+} /* hdmi_hdcp_sysfs_rda_tp*/
+
+static ssize_t hdmi_hdcp_sysfs_wta_tp(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int msgid = 0;
+ ssize_t ret = count;
+ struct hdmi_hdcp_ctrl *hdcp_ctrl =
+ hdmi_get_featuredata_from_sysfs_dev(dev, HDMI_TX_FEAT_HDCP);
+
+ if (!hdcp_ctrl || !buf) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ msgid = buf[0];
+
+ switch (msgid) {
+ case DOWN_CHECK_TOPOLOGY:
+ case DOWN_REQUEST_TOPOLOGY:
+ hdcp_ctrl->tp_msgid = msgid;
+ break;
+ /* more cases added here */
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+} /* hdmi_tx_sysfs_wta_hpd */
+
static DEVICE_ATTR(status, S_IRUGO, hdmi_hdcp_sysfs_rda_status, NULL);
+static DEVICE_ATTR(tp, S_IRUGO | S_IWUSR, hdmi_hdcp_sysfs_rda_tp,
+ hdmi_hdcp_sysfs_wta_tp);
+
static struct attribute *hdmi_hdcp_fs_attrs[] = {
&dev_attr_status.attr,
+ &dev_attr_tp.attr,
NULL,
};
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 7117779..0b64bbb 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -126,7 +126,13 @@
}
} /* hdmi_pm_name */
-static u8 hdmi_tx_avi_iframe_lut[][20] = {
+static DEFINE_MUTEX(avi_iframe_lut_lock);
+#define NUM_MODES_AVI 20
+#define SET_ITC_BIT(byte) (byte | 0x80)
+#define CLR_ITC_BIT(byte) (byte & 0x7F)
+#define CONFIG_CN_BITS(bits, byte) ((byte & ~(0x03 << 4)) | (bits << 4))
+
+static u8 hdmi_tx_avi_iframe_lut[][NUM_MODES_AVI] = {
{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10}, /*00*/
@@ -193,6 +199,55 @@
{20480, 247500} } },
};
+/* To statically config ITC bit from sysfs attribute */
+static int hdmi_tx_config_itc_bit(int itc)
+{
+ int ret = 0, loop = NUM_MODES_AVI;
+
+ if (mutex_lock_interruptible(&avi_iframe_lut_lock)) {
+ ret = -ERESTARTSYS;
+ goto signal_intr;
+ }
+
+ do {
+ --loop;
+ if (itc == 0)
+ hdmi_tx_avi_iframe_lut[2][loop] =
+ CLR_ITC_BIT(hdmi_tx_avi_iframe_lut[2][loop]);
+ if (itc == 1)
+ hdmi_tx_avi_iframe_lut[2][loop] =
+ SET_ITC_BIT(hdmi_tx_avi_iframe_lut[2][loop]);
+ } while (loop);
+
+ mutex_unlock(&avi_iframe_lut_lock);
+
+signal_intr:
+ return ret;
+}
+
+/* To configure CN0_1 bits from sysfs attribute */
+static int hdmi_tx_config_cn_bits(int cns)
+{
+ int ret = 0, loop = NUM_MODES_AVI;
+
+ if (mutex_lock_interruptible(&avi_iframe_lut_lock)) {
+ ret = -ERESTARTSYS;
+ goto signal_intr;
+ }
+
+ do {
+ --loop;
+ hdmi_tx_avi_iframe_lut[4][loop] =
+ CONFIG_CN_BITS(cns, hdmi_tx_avi_iframe_lut[4][loop]);
+ } while (loop);
+
+ mutex_unlock(&avi_iframe_lut_lock);
+
+signal_intr:
+ return ret;
+}
+
+
static bool hdmi_tx_is_cea_format(int mode)
{
bool cea_fmt;
@@ -544,6 +599,58 @@
return ret;
} /* hdmi_tx_sysfs_rda_product_description */
+static ssize_t hdmi_tx_sysfs_wta_avi_itc(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ int err = 0;
+ int itc = 0, rc = 0;
+
+ rc = kstrtoint(buf, 10, &itc);
+ if (rc) {
+ DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ return rc;
+ }
+
+ if (itc == 0 || itc == 1) {
+ if (hdmi_tx_config_itc_bit(itc))
+ ret = err;
+ else
+ DEV_DBG("%s: '%d is configured'!\n", __func__, itc);
+ } else {
+ DEV_ERR("%s: unknown ITC '%d', should be either 0 or 1\n",
+ __func__, itc);
+ }
+
+ return ret;
+} /* hdmi_tx_sysfs_wta_avi_itc */
+
+static ssize_t hdmi_tx_sysfs_wta_avi_cn0_1(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ int err = 0;
+ int cns = 0, rc = 0;
+
+ rc = kstrtoint(buf, 10, &cns);
+ if (rc) {
+ DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ return rc;
+ }
+
+ if (cns == 0 || cns == 1 || cns == 2 || cns == 3) {
+ if (hdmi_tx_config_cn_bits(cns))
+ ret = err;
+ else
+ DEV_DBG("%s: '%d is configured'!\n", __func__, cns);
+ } else {
+ DEV_ERR("%s: unknown CN '%d' should be either 0 or 1, 2 ,3\n",
+ __func__, cns);
+ }
+
+ return ret;
+} /* hdmi_tx_sysfs_wta_avi_cn0_1 */
+
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);
@@ -552,12 +659,16 @@
static DEVICE_ATTR(product_description, S_IRUGO | S_IWUSR,
hdmi_tx_sysfs_rda_product_description,
hdmi_tx_sysfs_wta_product_description);
+static DEVICE_ATTR(avi_itc, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_itc);
+static DEVICE_ATTR(avi_cn0_1, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_cn0_1);
static struct attribute *hdmi_tx_fs_attrs[] = {
&dev_attr_connected.attr,
&dev_attr_hpd.attr,
&dev_attr_vendor_name.attr,
&dev_attr_product_description.attr,
+ &dev_attr_avi_itc.attr,
+ &dev_attr_avi_cn0_1.attr,
NULL,
};
static struct attribute_group hdmi_tx_fs_attrs_group = {
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 4a4684b..db8a098 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1801,6 +1801,7 @@
struct mdss_data_type *mdata = platform_get_drvdata(pdev);
u32 data;
int rc;
+ struct property *prop = NULL;
rc = of_property_read_u32(pdev->dev.of_node, "qcom,mdss-rot-block-size",
&data);
@@ -1812,6 +1813,9 @@
"qcom,mdss-has-decimation");
mdata->has_wfd_blk = of_property_read_bool(pdev->dev.of_node,
"qcom,mdss-has-wfd-blk");
+ prop = of_find_property(pdev->dev.of_node, "batfet-supply", NULL);
+ mdata->batfet_required = prop ? true : false;
+
return 0;
}
@@ -1983,6 +1987,33 @@
return rc;
}
+void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable)
+{
+ if (!mdata->batfet_required)
+ return;
+
+ if (!mdata->batfet) {
+ if (enable) {
+ mdata->batfet = devm_regulator_get(&mdata->pdev->dev,
+ "batfet");
+ if (IS_ERR_OR_NULL(mdata->batfet)) {
+ pr_debug("unable to get batfet reg. rc=%d\n",
+ PTR_RET(mdata->batfet));
+ mdata->batfet = NULL;
+ return;
+ }
+ } else {
+ pr_debug("Batfet regulator disable w/o enable\n");
+ return;
+ }
+ }
+
+ if (enable)
+ regulator_enable(mdata->batfet);
+ else
+ regulator_disable(mdata->batfet);
+}
+
static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
{
if (!mdata->fs)
@@ -1993,6 +2024,7 @@
if (!mdata->fs_ena) {
regulator_enable(mdata->fs);
mdss_mdp_cx_ctrl(mdata, true);
+ mdss_mdp_batfet_ctrl(mdata, true);
}
mdata->fs_ena = true;
} else {
@@ -2001,6 +2033,7 @@
if (mdata->fs_ena) {
regulator_disable(mdata->fs);
mdss_mdp_cx_ctrl(mdata, false);
+ mdss_mdp_batfet_ctrl(mdata, false);
}
mdata->fs_ena = false;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index f9db498..0d2bccb 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -395,6 +395,7 @@
u32 splash_mem_addr;
u32 splash_mem_size;
+ u32 sd_enabled;
};
struct mdss_mdp_perf_params {
@@ -450,6 +451,7 @@
void (*fnc_ptr)(void *), void *arg);
void mdss_mdp_footswitch_ctrl_splash(int on);
+void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable);
int mdss_mdp_bus_scale_set_quota(u64 ab_quota, u64 ib_quota);
void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index f527c62..c2d9965 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -27,7 +27,7 @@
#include <mach/iommu_domains.h>
#include <mach/event_timer.h>
#include <mach/msm_bus.h>
-
+#include <mach/scm.h>
#include "mdss.h"
#include "mdss_debug.h"
#include "mdss_fb.h"
@@ -42,12 +42,38 @@
#define PP_CLK_CFG_OFF 0
#define PP_CLK_CFG_ON 1
+#define MEM_PROTECT_SD_CTRL 0xF
+
+struct sd_ctrl_req {
+ unsigned int enable;
+} __attribute__ ((__packed__));
+
static atomic_t ov_active_panels = ATOMIC_INIT(0);
static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd);
+static int mdss_mdp_overlay_sd_ctrl(struct msm_fb_data_type *mfd,
+ unsigned int enable)
+{
+ struct sd_ctrl_req request;
+ unsigned int resp = -1;
+ int ret = 0;
+ pr_debug("sd_ctrl %u\n", enable);
+
+ request.enable = enable;
+
+ ret = scm_call(SCM_SVC_MP, MEM_PROTECT_SD_CTRL,
+ &request, sizeof(request), &resp, sizeof(resp));
+ pr_debug("scm_call MEM_PROTECT_SD_CTRL(%u): ret=%d, resp=%x",
+ enable, ret, resp);
+ if (ret)
+ return ret;
+
+ return resp;
+}
+
static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
struct mdp_overlay *req)
{
@@ -777,8 +803,11 @@
int rc;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- if (mdp5_data->ctl->power_on)
+ if (mdp5_data->ctl->power_on) {
+ if (!mdp5_data->mdata->batfet)
+ mdss_mdp_batfet_ctrl(mdp5_data->mdata, true);
return 0;
+ }
pr_debug("starting fb%d overlay\n", mfd->index);
@@ -833,6 +862,7 @@
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
struct mdss_mdp_ctl *tmp;
int ret;
+ int sd_in_pipe = 0;
if (ctl->shared_lock)
mutex_lock(ctl->shared_lock);
@@ -848,6 +878,24 @@
mutex_unlock(ctl->shared_lock);
return ret;
}
+ /*
+ * check if there is a secure display session
+ */
+ list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
+ if (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION) {
+ sd_in_pipe |= 1;
+ pr_debug("Secure pipe: %u : %08X\n",
+ pipe->num, pipe->flags);
+ }
+ }
+ /*
+ * If there is no secure display session and sd_enabled, disable the
+ * secure display session
+ */
+ if (!sd_in_pipe && mdp5_data->sd_enabled) {
+ if (0 == mdss_mdp_overlay_sd_ctrl(mfd, 0))
+ mdp5_data->sd_enabled = 0;
+ }
if (data)
mdss_mdp_set_roi(ctl, data);
@@ -855,6 +903,16 @@
list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
struct mdss_mdp_data *buf;
/*
+ * When secure display is enabled, if there is a non secure
+ * display pipe, skip that
+ */
+ if ((mdp5_data->sd_enabled) &&
+ !(pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION)) {
+ pr_warn("Non secure pipe during secure display: %u: %08X, skip\n",
+ pipe->num, pipe->flags);
+ continue;
+ }
+ /*
* When external is connected and no dedicated wfd is present,
* reprogram DMA pipe before kickoff to clear out any previous
* block mode configuration.
@@ -920,6 +978,16 @@
ret = mdss_mdp_display_wait4comp(mdp5_data->ctl);
+ if (ret == 0) {
+ mutex_lock(&mfd->lock);
+ if (!mdp5_data->sd_enabled && (sd_in_pipe == 1)) {
+ ret = mdss_mdp_overlay_sd_ctrl(mfd, 1);
+ if (ret == 0)
+ mdp5_data->sd_enabled = 1;
+ }
+ mutex_unlock(&mfd->lock);
+ }
+
mdss_fb_update_notify_update(mfd);
commit_fail:
mdss_mdp_overlay_cleanup(mfd);
@@ -1147,6 +1215,7 @@
pr_debug("ov queue pnum=%d\n", pipe->num);
flags = (pipe->flags & MDP_SECURE_OVERLAY_SESSION);
+ flags |= (pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION);
src_data = &pipe->back_buf;
if (src_data->num_planes) {
diff --git a/include/linux/bif/consumer.h b/include/linux/bif/consumer.h
index e4c190e..a4579db 100644
--- a/include/linux/bif/consumer.h
+++ b/include/linux/bif/consumer.h
@@ -311,10 +311,11 @@
* @type: Object type
* @version: Object version
* @manufacturer_id: Manufacturer ID number allocated by MIPI
- * @length: Length of the entire object including header and CRC
+ * @length: Length of the entire object including header and CRC;
+ * data length == total length - 8.
* @data: Raw byte data found in the object
* @crc: CRC of the object calculated using CRC-CCITT
- * @list: Linked-list connection parameter
+ * @list: Linked-list connection parameter; internal use only
* @addr: BIF slave address correspond to the start of the object
*
* manufacturer_id == 0x0000 if MIPI type and version.
@@ -342,6 +343,8 @@
* is used to denote a 256 byte buffer.
* @nvm_base_address: BIF slave address where NVM begins
* @nvm_size: NVM size in bytes
+ * @nvm_lock_offset: Offset from the beginning of NVM of the first
+ * writable address
* @object_count: Number of BIF objects read from NVM
* @object_list: List of BIF objects read from NVM
*/
@@ -351,6 +354,7 @@
u8 write_buffer_size;
u16 nvm_base_address;
u16 nvm_size;
+ u16 nvm_lock_offset;
int object_count;
struct list_head object_list;
};
@@ -412,6 +416,9 @@
#define BIF_MATCH_FUNCTION_TYPE BIT(2)
#define BIF_MATCH_FUNCTION_VERSION BIT(3)
#define BIF_MATCH_IGNORE_PRESENCE BIT(4)
+#define BIF_MATCH_OBJ_TYPE BIT(5)
+#define BIF_MATCH_OBJ_VERSION BIT(6)
+#define BIF_MATCH_OBJ_MANUFACTURER_ID BIT(7)
/**
* struct bif_match_criteria - specifies the matching criteria that a BIF
@@ -428,6 +435,17 @@
* @ignore_presence: If true, then slaves that are currently not present
* will be successfully matched against. By default, only
* present slaves can be matched.
+ * @obj_type: Defines the type of a BIF object found in the
+ * non-volatile memory of a slave.
+ * @obj_version: Defines the version of a BIF object found in the
+ * non-volatile memory of a slave.
+ * @obj_manufacturer_id: Manufacturer ID of a BIF object found in the
+ * non-volatile memory of a slave.
+ *
+ * If function_type and function_verion are both specified, then they must both
+ * match for a single BIF function. If obj_type and obj_version or
+ * obj_manufacturer_id are specified, then all must match for a single BIF
+ * object.
*/
struct bif_match_criteria {
u32 match_mask;
@@ -436,6 +454,34 @@
u8 function_type;
u8 function_version;
bool ignore_presence;
+ u8 obj_type;
+ u8 obj_version;
+ u16 obj_manufacturer_id;
+};
+
+/* Mask values to be ORed for use in bif_obj_match_criteria.match_mask. */
+#define BIF_OBJ_MATCH_TYPE BIT(0)
+#define BIF_OBJ_MATCH_VERSION BIT(1)
+#define BIF_OBJ_MATCH_MANUFACTURER_ID BIT(2)
+
+/**
+ * struct bif_obj_match_criteria - specifies the matching criteria that a BIF
+ * consumer uses to find an appropriate BIF data object
+ * within a slave
+ * @match_mask: Mask value specifying which parameters to match upon.
+ * This value should be some ORed combination of
+ * BIF_OBJ_MATCH_* specified above.
+ * @type: Defines the type of the object. The type may be either
+ * MIPI or manufacturer defined.
+ * @version: Defines the version of the object. The version may be
+ * either MIPI or manufacturer defined.
+ * @manufacturer_id: Manufacturer ID number allocated by MIPI.
+ */
+struct bif_obj_match_criteria {
+ u32 match_mask;
+ u8 type;
+ u8 version;
+ u16 manufacturer_id;
};
/**
@@ -472,6 +518,8 @@
struct notifier_block *nb);
int bif_trigger_task(struct bif_slave *slave, unsigned int task);
+int bif_enable_auto_task(struct bif_slave *slave, unsigned int task);
+int bif_disable_auto_task(struct bif_slave *slave, unsigned int task);
int bif_task_is_busy(struct bif_slave *slave, unsigned int task);
int bif_ctrl_count(void);
@@ -481,10 +529,10 @@
int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl);
-int bif_slave_match_count(const struct bif_ctrl *ctrl,
+int bif_slave_match_count(struct bif_ctrl *ctrl,
const struct bif_match_criteria *match_criteria);
-struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+struct bif_slave *bif_slave_match_get(struct bif_ctrl *ctrl,
unsigned int id, const struct bif_match_criteria *match_criteria);
void bif_slave_put(struct bif_slave *slave);
@@ -500,9 +548,31 @@
int bif_slave_find_function(struct bif_slave *slave, u8 function, u8 *version,
u16 *function_pointer);
+int bif_object_match_count(struct bif_slave *slave,
+ const struct bif_obj_match_criteria *match_criteria);
+
+struct bif_object *bif_object_match_get(struct bif_slave *slave,
+ unsigned int id, const struct bif_obj_match_criteria *match_criteria);
+
+void bif_object_put(struct bif_object *object);
+
int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf, int len);
int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf, int len);
+int bif_slave_nvm_raw_read(struct bif_slave *slave, u16 offset, u8 *buf,
+ int len);
+int bif_slave_nvm_raw_write(struct bif_slave *slave, u16 offset, u8 *buf,
+ int len);
+
+int bif_object_write(struct bif_slave *slave, u8 type, u8 version, u16
+ manufacturer_id, const u8 *data, int data_len);
+
+int bif_object_overwrite(struct bif_slave *slave,
+ struct bif_object *object, u8 type, u8 version,
+ u16 manufacturer_id, const u8 *data, int data_len);
+
+int bif_object_delete(struct bif_slave *slave, const struct bif_object *object);
+
int bif_slave_is_present(struct bif_slave *slave);
int bif_slave_is_selected(struct bif_slave *slave);
@@ -534,6 +604,12 @@
static inline int bif_trigger_task(struct bif_slave *slave, unsigned int task)
{ return -EPERM; }
+static inline int bif_enable_auto_task(struct bif_slave *slave,
+ unsigned int task)
+{ return -EPERM; }
+static inline int bif_disable_auto_task(struct bif_slave *slave,
+ unsigned int task)
+{ return -EPERM; }
static inline int bif_task_is_busy(struct bif_slave *slave, unsigned int task)
{ return -EPERM; }
@@ -544,13 +620,14 @@
{ return ERR_PTR(-EPERM); }
static inline void bif_ctrl_put(struct bif_ctrl *ctrl) { return; }
-int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl) { return -EPERM; }
+static inline int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl)
+{ return -EPERM; }
-static inline int bif_slave_match_count(const struct bif_ctrl *ctrl,
+static inline int bif_slave_match_count(struct bif_ctrl *ctrl,
const struct bif_match_criteria *match_criteria)
{ return -EPERM; }
-static inline struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+static inline struct bif_slave *bif_slave_match_get(struct bif_ctrl *ctrl,
unsigned int id, const struct bif_match_criteria *match_criteria)
{ return ERR_PTR(-EPERM); }
@@ -571,6 +648,17 @@
u8 *version, u16 *function_pointer)
{ return -EPERM; }
+static inline int bif_object_match_count(struct bif_slave *slave,
+ const struct bif_obj_match_criteria *match_criteria)
+{ return -EPERM; }
+
+static inline struct bif_object *bif_object_match_get(struct bif_slave *slave,
+ unsigned int id, const struct bif_obj_match_criteria *match_criteria)
+{ return ERR_PTR(-EPERM); }
+
+static inline void bif_object_put(struct bif_object *object)
+{}
+
static inline int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf,
int len)
{ return -EPERM; }
@@ -578,18 +666,42 @@
int len)
{ return -EPERM; }
-int bif_slave_is_present(struct bif_slave *slave) { return -EPERM; }
-
-int bif_slave_is_selected(struct bif_slave *slave) { return -EPERM; }
-int bif_slave_select(struct bif_slave *slave) { return -EPERM; }
-
-int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data)
+static inline int bif_slave_nvm_raw_read(struct bif_slave *slave, u16 offset,
+ u8 *buf, int len)
{ return -EPERM; }
-int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
- u8 data, int *response)
+static inline int bif_slave_nvm_raw_write(struct bif_slave *slave, u16 offset,
+ u8 *buf, int len)
{ return -EPERM; }
-int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
- u8 data, bool *query_response)
+
+static inline int bif_object_write(struct bif_slave *slave, u8 type, u8 version,
+ u16 manufacturer_id, const u8 *data, int data_len)
+{ return -EPERM; }
+
+static inline int bif_object_overwrite(struct bif_slave *slave,
+ struct bif_object *object, u8 type, u8 version,
+ u16 manufacturer_id, const u8 *data, int data_len)
+{ return -EPERM; }
+
+static inline int bif_object_delete(struct bif_slave *slave,
+ const struct bif_object *object)
+{ return -EPERM; }
+
+static inline int bif_slave_is_present(struct bif_slave *slave)
+{ return -EPERM; }
+
+static inline int bif_slave_is_selected(struct bif_slave *slave)
+{ return -EPERM; }
+static inline int bif_slave_select(struct bif_slave *slave)
+{ return -EPERM; }
+
+static inline int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl,
+ int transaction, u8 data)
+{ return -EPERM; }
+static inline int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl,
+ int transaction, u8 data, int *response)
+{ return -EPERM; }
+static inline int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl,
+ int transaction, u8 data, bool *query_response)
{ return -EPERM; }
static inline void bif_ctrl_bus_lock(struct bif_ctrl *ctrl)
@@ -601,11 +713,14 @@
{ return 0; }
static inline int bif_ctrl_measure_rid(struct bif_ctrl *ctrl) { return -EPERM; }
-int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl) { return -EPERM; }
-int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns)
+static inline int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl)
{ return -EPERM; }
-int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl) { return -EPERM; }
-int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state)
+static inline int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns)
+{ return -EPERM; }
+static inline int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl)
+{ return -EPERM; }
+static inline int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl,
+ enum bif_bus_state state)
{ return -EPERM; }
#endif
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index b7ba6fb..ffbd732 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -69,20 +69,20 @@
#define TABLA_DCYCLE_3839 0xE
#define TABLA_DCYCLE_4095 0xF
-#define TAIKO_MCLK_CLK_12P288MHZ 12288000
-#define TAIKO_MCLK_CLK_9P6HZ 9600000
+#define WCD9XXX_MCLK_CLK_12P288MHZ 12288000
+#define WCD9XXX_MCLK_CLK_9P6HZ 9600000
/* Only valid for 9.6 MHz mclk */
-#define TAIKO_DMIC_SAMPLE_RATE_2P4MHZ 2400000
-#define TAIKO_DMIC_SAMPLE_RATE_3P2MHZ 3200000
-#define TAIKO_DMIC_SAMPLE_RATE_4P8MHZ 4800000
+#define WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ 2400000
+#define WCD9XXX_DMIC_SAMPLE_RATE_3P2MHZ 3200000
+#define WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ 4800000
/* Only valid for 12.288 MHz mclk */
-#define TAIKO_DMIC_SAMPLE_RATE_3P072MHZ 3072000
-#define TAIKO_DMIC_SAMPLE_RATE_4P096MHZ 4096000
-#define TAIKO_DMIC_SAMPLE_RATE_6P144MHZ 6144000
+#define WCD9XXX_DMIC_SAMPLE_RATE_3P072MHZ 3072000
+#define WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ 4096000
+#define WCD9XXX_DMIC_SAMPLE_RATE_6P144MHZ 6144000
-#define TAIKO_DMIC_SAMPLE_RATE_UNDEFINED 0
+#define WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED 0
struct wcd9xxx_amic {
/*legacy mode, txfe_enable and txfe_buff take 7 input
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 48268f0..a5fa304 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -302,16 +302,16 @@
* On nommu, vmalloc/vfree wrap through kmalloc/kfree directly, so there
* is no special casing required.
*/
+
+#ifdef CONFIG_MMU
+extern int is_vmalloc_addr(const void *x);
+#else
static inline int is_vmalloc_addr(const void *x)
{
-#ifdef CONFIG_MMU
- unsigned long addr = (unsigned long)x;
-
- return addr >= VMALLOC_START && addr < VMALLOC_END;
-#else
return 0;
-#endif
}
+#endif
+
#ifdef CONFIG_MMU
extern int is_vmalloc_or_module_addr(const void *x);
#else
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9d15908..d0ad3e4 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -391,6 +391,7 @@
unsigned int idle_timeout;
struct notifier_block reboot_notify;
bool issue_long_pon;
+ u8 cached_ext_csd;
};
/*
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 077b204..0c08421 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -187,6 +187,7 @@
#define MDP_BACKEND_COMPOSITION 0x00040000
#define MDP_BORDERFILL_SUPPORTED 0x00010000
#define MDP_SECURE_OVERLAY_SESSION 0x00008000
+#define MDP_SECURE_DISPLAY_OVERLAY_SESSION 0x00002000
#define MDP_OV_PIPE_FORCE_DMA 0x00004000
#define MDP_MEMORY_ID_TYPE_FB 0x00001000
#define MDP_BWC_EN 0x00000400
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index e1c096b..af206c7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -707,6 +707,7 @@
#define V4L2_QCOM_BUF_DROP_FRAME 0x100000
#define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x200000
#define V4L2_QCOM_BUF_FLAG_EOS 0x2000
+#define V4L2_QCOM_BUF_FLAG_READONLY 0x400000
/*
* O V E R L A Y P R E V I E W
@@ -1863,22 +1864,25 @@
V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1
};
-#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE \
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT \
(V4L2_CID_MPEG_MSM_VIDC_BASE+30)
+#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+31)
enum v4l2_mpeg_vidc_video_alloc_mode_type {
V4L2_MPEG_VIDC_VIDEO_STATIC = 0,
V4L2_MPEG_VIDC_VIDEO_RING = 1,
+ V4L2_MPEG_VIDC_VIDEO_DYNAMIC = 2,
};
#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY \
- (V4L2_CID_MPEG_MSM_VIDC_BASE+31)
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+32)
enum v4l2_mpeg_vidc_video_assembly {
V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE = 0,
V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE = 1,
};
#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL \
- (V4L2_CID_MPEG_MSM_VIDC_BASE+32)
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+33)
enum v4l2_mpeg_vidc_video_vp8_profile_level {
V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
@@ -2448,7 +2452,10 @@
(V4L2_EVENT_MSM_VIDC_START + 3)
#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE (V4L2_EVENT_MSM_VIDC_START + 4)
#define V4L2_EVENT_MSM_VIDC_SYS_ERROR (V4L2_EVENT_MSM_VIDC_START + 5)
-
+#define V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE \
+ (V4L2_EVENT_MSM_VIDC_START + 6)
+#define V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER \
+ (V4L2_EVENT_MSM_VIDC_START + 7)
/* Payload for V4L2_EVENT_VSYNC */
struct v4l2_event_vsync {
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 663bc05..7675a5c 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -14,6 +14,7 @@
#define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */
#define VM_VPAGES 0x00000010 /* buffer for pages was vmalloc'ed */
#define VM_UNLIST 0x00000020 /* vm_struct is not listed in vmlist */
+#define VM_LOWMEM 0x00000040 /* Tracking of direct mapped lowmem */
/* bits [20..32] reserved for arch specific ioremap internals */
/*
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 2164275..868be9f 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -28,7 +28,7 @@
int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
-int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_release_buffers(void *instance, int buffer_type);
int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 23b19b5..7b0ad14 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -129,6 +129,7 @@
struct msm_vfe_axi_stream_request_cmd {
uint32_t session_id;
uint32_t stream_id;
+ uint32_t vt_enable;
uint32_t output_format;/*Planar/RAW/Misc*/
enum msm_vfe_axi_stream_src stream_src; /*CAMIF/IDEAL/RDIs*/
struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
diff --git a/include/video/Kbuild b/include/video/Kbuild
index 53e13cb..fce6fd1 100644
--- a/include/video/Kbuild
+++ b/include/video/Kbuild
@@ -2,3 +2,4 @@
header-y += sisfb.h
header-y += uvesafb.h
header-y += msm_hdmi_modes.h
+header-y += msm_hdmi_hdcp_mgr.h
diff --git a/include/video/msm_hdmi_hdcp_mgr.h b/include/video/msm_hdmi_hdcp_mgr.h
new file mode 100644
index 0000000..7b8e7f5
--- /dev/null
+++ b/include/video/msm_hdmi_hdcp_mgr.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_HDMI_HDCP_MGR_H
+#define MSM_HDMI_HDCP_MGR_H
+
+enum DS_TYPE { /* type of downstream device */
+ DS_UNKNOWN,
+ DS_RECEIVER,
+ DS_REPEATER,
+};
+
+enum {
+ MSG_ID_IDX,
+ RET_CODE_IDX,
+ HEADER_LEN,
+};
+
+enum RET_CODE {
+ HDCP_NOT_AUTHED,
+ HDCP_AUTHED,
+ HDCP_DISABLE,
+};
+
+enum MSG_ID { /* List of functions expected to be called after it */
+ DOWN_CHECK_TOPOLOGY,
+ UP_REQUEST_TOPOLOGY,
+ UP_SEND_TOPOLOGY,
+ DOWN_REQUEST_TOPOLOGY,
+ MSG_NUM,
+};
+
+enum SOURCE_ID {
+ HDCP_V1_TX,
+ HDCP_V1_RX,
+ HDCP_V2_RX,
+ HDCP_V2_TX,
+ SRC_NUM,
+};
+
+/*
+ * how to parse sysfs params buffer
+ * from hdcp_tx driver.
+ */
+
+struct HDCP_V2V1_MSG_TOPOLOGY {
+ /* indicates downstream's type */
+ uint32_t ds_type;
+ uint8_t bksv[5];
+ uint8_t dev_count;
+ uint8_t depth;
+ uint8_t ksv_list[5 * 127];
+ uint32_t max_cascade_exceeded;
+ uint32_t max_dev_exceeded;
+};
+
+#endif /* MSM_HDMI_HDCP_MGR_H */
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index a2ab2ab..e174693 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -184,6 +184,36 @@
return ret;
}
+#ifdef ENABLE_VMALLOC_SAVING
+int is_vmalloc_addr(const void *x)
+{
+ struct rb_node *n;
+ struct vmap_area *va;
+ int ret = 0;
+
+ spin_lock(&vmap_area_lock);
+
+ for (n = rb_first(vmap_area_root); n; rb_next(n)) {
+ va = rb_entry(n, struct vmap_area, rb_node);
+ if (x >= va->va_start && x < va->va_end) {
+ ret = 1;
+ break;
+ }
+ }
+
+ spin_unlock(&vmap_area_lock);
+ return ret;
+}
+#else
+int is_vmalloc_addr(const void *x)
+{
+ unsigned long addr = (unsigned long)x;
+
+ return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+#endif
+EXPORT_SYMBOL(is_vmalloc_addr);
+
int is_vmalloc_or_module_addr(const void *x)
{
/*
@@ -2643,6 +2673,9 @@
if (v->flags & VM_VPAGES)
seq_printf(m, " vpages");
+ if (v->flags & VM_LOWMEM)
+ seq_printf(m, " lowmem");
+
show_numa_info(m, v);
seq_putc(m, '\n');
return 0;
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 577c1ed..17ed0d3 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -4600,6 +4600,9 @@
u8 flag = pdata->amic_settings.use_pdata;
u8 i = 0, j = 0;
u8 val_txfe = 0, value = 0;
+ u8 dmic_sample_rate_value = 0;
+ u8 dmic_b1_ctl_value = 0;
+ u8 anc_ctl_value = 0;
if (!pdata) {
dev_err(codec->dev, "%s: NULL pdata\n", __func__);
@@ -4693,6 +4696,78 @@
0x00 : 0x10);
snd_soc_update_bits(codec, TAPAN_A_MICB_3_CTL, 0x10, value);
+ /* Set the DMIC sample rate */
+ if (pdata->mclk_rate == TAPAN_MCLK_CLK_9P6MHZ) {
+ switch (pdata->dmic_sample_rate) {
+ case WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_4;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_4;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
+ break;
+ case WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_2;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_2;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_ON;
+ break;
+ case WCD9XXX_DMIC_SAMPLE_RATE_3P2MHZ:
+ case WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_3;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_3;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s Invalid sample rate %d for mclk %d\n",
+ __func__, pdata->dmic_sample_rate,
+ pdata->mclk_rate);
+ rc = -EINVAL;
+ goto done;
+ }
+ } else if (pdata->mclk_rate == TAPAN_MCLK_CLK_12P288MHZ) {
+ switch (pdata->dmic_sample_rate) {
+ case WCD9XXX_DMIC_SAMPLE_RATE_3P072MHZ:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_4;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_4;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
+ break;
+ case WCD9XXX_DMIC_SAMPLE_RATE_6P144MHZ:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_2;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_2;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_ON;
+ break;
+ case WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ:
+ case WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_3;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_3;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
+ break;
+ default:
+ dev_err(codec->dev,
+ "%s Invalid sample rate %d for mclk %d\n",
+ __func__, pdata->dmic_sample_rate,
+ pdata->mclk_rate);
+ rc = -EINVAL;
+ goto done;
+ }
+ } else {
+ dev_err(codec->dev, "%s MCLK is not set!\n", __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ snd_soc_update_bits(codec, TAPAN_A_CDC_TX1_DMIC_CTL,
+ 0x7, dmic_sample_rate_value);
+ snd_soc_update_bits(codec, TAPAN_A_CDC_TX2_DMIC_CTL,
+ 0x7, dmic_sample_rate_value);
+ snd_soc_update_bits(codec, TAPAN_A_CDC_TX3_DMIC_CTL,
+ 0x7, dmic_sample_rate_value);
+ snd_soc_update_bits(codec, TAPAN_A_CDC_TX4_DMIC_CTL,
+ 0x7, dmic_sample_rate_value);
+ snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_DMIC_B1_CTL,
+ 0xEE, dmic_b1_ctl_value);
+ snd_soc_update_bits(codec, TAPAN_A_CDC_ANC1_B2_CTL,
+ 0x1, anc_ctl_value);
+
done:
return rc;
}
@@ -4886,15 +4961,6 @@
{TAPAN_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
{TAPAN_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
- /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
- {TAPAN_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
- {TAPAN_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
- {TAPAN_A_CDC_TX3_DMIC_CTL, 0x7, 0x1},
- {TAPAN_A_CDC_TX4_DMIC_CTL, 0x7, 0x1},
-
- /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
- {TAPAN_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
-
/* Compander zone selection */
{TAPAN_A_CDC_COMP0_B4_CTL, 0x3F, 0x37},
{TAPAN_A_CDC_COMP1_B4_CTL, 0x3F, 0x37},
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 4ce9b4a..2beda38 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -248,21 +248,6 @@
#define TAIKO_I2S_MASTER_MODE_MASK 0x08
-#define TAIKO_DMIC_SAMPLE_RATE_DIV_2 0x0
-#define TAIKO_DMIC_SAMPLE_RATE_DIV_3 0x1
-#define TAIKO_DMIC_SAMPLE_RATE_DIV_4 0x2
-
-#define TAIKO_DMIC_B1_CTL_DIV_2 0x00
-#define TAIKO_DMIC_B1_CTL_DIV_3 0x22
-#define TAIKO_DMIC_B1_CTL_DIV_4 0x44
-
-#define TAIKO_DMIC_B2_CTL_DIV_2 0x00
-#define TAIKO_DMIC_B2_CTL_DIV_3 0x02
-#define TAIKO_DMIC_B2_CTL_DIV_4 0x04
-
-#define TAIKO_ANC_DMIC_X2_ON 0x1
-#define TAIKO_ANC_DMIC_X2_OFF 0x0
-
#define TAIKO_SLIM_CLOSE_TIMEOUT 1000
#define TAIKO_SLIM_IRQ_OVERFLOW (1 << 0)
#define TAIKO_SLIM_IRQ_UNDERFLOW (1 << 1)
@@ -5741,24 +5726,24 @@
/* Set the DMIC sample rate */
if (pdata->mclk_rate == TAIKO_MCLK_CLK_9P6MHZ) {
switch (pdata->dmic_sample_rate) {
- case TAIKO_DMIC_SAMPLE_RATE_2P4MHZ:
- dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_4;
- dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_4;
- dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_4;
- anc_ctl_value = TAIKO_ANC_DMIC_X2_OFF;
+ case WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_4;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_4;
+ dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_4;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
break;
- case TAIKO_DMIC_SAMPLE_RATE_4P8MHZ:
- dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_2;
- dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_2;
- dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_2;
- anc_ctl_value = TAIKO_ANC_DMIC_X2_ON;
+ case WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_2;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_2;
+ dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_2;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_ON;
break;
- case TAIKO_DMIC_SAMPLE_RATE_3P2MHZ:
- case TAIKO_DMIC_SAMPLE_RATE_UNDEFINED:
- dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_3;
- dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_3;
- dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_3;
- anc_ctl_value = TAIKO_ANC_DMIC_X2_OFF;
+ case WCD9XXX_DMIC_SAMPLE_RATE_3P2MHZ:
+ case WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_3;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_3;
+ dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_3;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
break;
default:
pr_err("%s Invalid sample rate %d for mclk %d\n",
@@ -5769,24 +5754,24 @@
}
} else if (pdata->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ) {
switch (pdata->dmic_sample_rate) {
- case TAIKO_DMIC_SAMPLE_RATE_3P072MHZ:
- dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_4;
- dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_4;
- dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_4;
- anc_ctl_value = TAIKO_ANC_DMIC_X2_OFF;
+ case WCD9XXX_DMIC_SAMPLE_RATE_3P072MHZ:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_4;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_4;
+ dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_4;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
break;
- case TAIKO_DMIC_SAMPLE_RATE_6P144MHZ:
- dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_2;
- dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_2;
- dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_2;
- anc_ctl_value = TAIKO_ANC_DMIC_X2_ON;
+ case WCD9XXX_DMIC_SAMPLE_RATE_6P144MHZ:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_2;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_2;
+ dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_2;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_ON;
break;
- case TAIKO_DMIC_SAMPLE_RATE_4P096MHZ:
- case TAIKO_DMIC_SAMPLE_RATE_UNDEFINED:
- dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_3;
- dmic_b1_ctl_value = TAIKO_DMIC_B1_CTL_DIV_3;
- dmic_b2_ctl_value = TAIKO_DMIC_B2_CTL_DIV_3;
- anc_ctl_value = TAIKO_ANC_DMIC_X2_OFF;
+ case WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ:
+ case WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED:
+ dmic_sample_rate_value = WCD9XXX_DMIC_SAMPLE_RATE_DIV_3;
+ dmic_b1_ctl_value = WCD9XXX_DMIC_B1_CTL_DIV_3;
+ dmic_b2_ctl_value = WCD9XXX_DMIC_B2_CTL_DIV_3;
+ anc_ctl_value = WCD9XXX_ANC_DMIC_X2_OFF;
break;
default:
pr_err("%s Invalid sample rate %d for mclk %d\n",
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index e63d36a..0239c86 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -37,6 +37,21 @@
#define WCD9XXX_CLSH_STATE_LO (0x01 << 3)
#define NUM_CLSH_STATES ((0x01 << 4) - 1)
+#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_2 0x0
+#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_3 0x1
+#define WCD9XXX_DMIC_SAMPLE_RATE_DIV_4 0x2
+
+#define WCD9XXX_DMIC_B1_CTL_DIV_2 0x00
+#define WCD9XXX_DMIC_B1_CTL_DIV_3 0x22
+#define WCD9XXX_DMIC_B1_CTL_DIV_4 0x44
+
+#define WCD9XXX_DMIC_B2_CTL_DIV_2 0x00
+#define WCD9XXX_DMIC_B2_CTL_DIV_3 0x02
+#define WCD9XXX_DMIC_B2_CTL_DIV_4 0x04
+
+#define WCD9XXX_ANC_DMIC_X2_ON 0x1
+#define WCD9XXX_ANC_DMIC_X2_OFF 0x0
+
/* Derived State: Bits 1 and 2 should be set for Headphone stereo */
#define WCD9XXX_CLSH_STATE_HPH_ST (WCD9XXX_CLSH_STATE_HPHL | \
WCD9XXX_CLSH_STATE_HPHR)
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index eea4316..7b29a11 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -1056,6 +1056,27 @@
mbhc->mbhc_data.micb_mv);
}
+/* To enable/disable bandgap and RC oscillator */
+static void wcd9xxx_mbhc_ctrl_clk_bandgap(struct wcd9xxx_mbhc *mbhc,
+ bool enable)
+{
+ if (enable) {
+ WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
+ wcd9xxx_resmgr_get_bandgap(mbhc->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ wcd9xxx_resmgr_get_clk_block(mbhc->resmgr,
+ WCD9XXX_CLK_RCO);
+ WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+ } else {
+ WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
+ wcd9xxx_resmgr_put_clk_block(mbhc->resmgr,
+ WCD9XXX_CLK_RCO);
+ wcd9xxx_resmgr_put_bandgap(mbhc->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+ }
+}
+
/* called only from interrupt which is under codec_resource_lock acquisition */
static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc,
bool is_cs_enable)
@@ -1093,15 +1114,6 @@
__func__);
}
- /*
- * Request BG and clock.
- * These will be released by wcd9xxx_cleanup_hs_polling
- */
- WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
- wcd9xxx_resmgr_get_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
- wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
- WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
-
snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x01);
/* Make sure CFILT is in fast mode, save current mode */
@@ -1212,11 +1224,6 @@
wcd9xxx_shutdown_hs_removal_detect(mbhc);
- /* Release clock and BG requested by wcd9xxx_mbhc_setup_hs_polling */
- WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
- wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
- wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
- WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
/* Disable external voltage source to micbias if present */
if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
@@ -1691,6 +1698,7 @@
BUG_ON(NUM_DCE_PLUG_INS_DETECT < 4);
+ wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
rt[0].swap_gnd = false;
rt[0].vddio = false;
rt[0].hwvalue = true;
@@ -1719,6 +1727,7 @@
type = wcd9xxx_cs_find_plug_type(mbhc, rt, ARRAY_SIZE(rt), highhph,
mbhc->event_state);
+ wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
pr_debug("%s: plug_type:%d\n", __func__, type);
return type;
@@ -1759,6 +1768,8 @@
*/
(void) wcd9xxx_pull_down_micbias(mbhc,
WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
+
+ wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, false);
rt[0].swap_gnd = false;
@@ -1798,6 +1809,7 @@
type = wcd9xxx_find_plug_type(mbhc, rt, ARRAY_SIZE(rt),
mbhc->event_state);
+ wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
pr_debug("%s: leave\n", __func__);
return type;
}
@@ -1986,6 +1998,8 @@
* only report the mic line
*/
wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET);
+ /* Button detection required RC oscillator */
+ wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
msleep(100);
/* if PA is already on, switch micbias source to VDDIO */
@@ -2320,6 +2334,9 @@
* extension cable is still plugged in
* report it as LINEOUT device
*/
+ if (mbhc->hph_status == SND_JACK_HEADSET)
+ wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc,
+ false);
wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT);
wcd9xxx_cleanup_hs_polling(mbhc);
wcd9xxx_enable_hs_detect(mbhc, 1,
@@ -2338,6 +2355,7 @@
wcd9xxx_switch_micbias(mbhc, 0);
wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADSET);
+ wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
wcd9xxx_cleanup_hs_polling(mbhc);
wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER |
MBHC_USE_HPHL_TRIGGER,
@@ -2876,6 +2894,7 @@
is_removed = true;
} else if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
wcd9xxx_pause_hs_polling(mbhc);
+ wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
wcd9xxx_cleanup_hs_polling(mbhc);
wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADSET);
is_removed = true;
@@ -4348,16 +4367,13 @@
*/
mutex_lock(&codec->mutex);
- WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
/*
* Fast(mbhc) mode bandagap doesn't need to be enabled explicitly
* since fast mode is set by MBHC hardware when override is on.
* Enable bandgap mode to avoid unnecessary RCO disable and enable
* during clock source change.
*/
- wcd9xxx_resmgr_get_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
- wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
- WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+ wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, true);
wcd9xxx_turn_onoff_override(mbhc, true);
pr_debug("%s: Setting impedance detection\n", __func__);
@@ -4405,10 +4421,7 @@
mutex_unlock(&codec->mutex);
- WCD9XXX_BG_CLK_LOCK(mbhc->resmgr);
- wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_AUDIO_MODE);
- wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
- WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+ wcd9xxx_mbhc_ctrl_clk_bandgap(mbhc, false);
wcd9xxx_turn_onoff_override(mbhc, false);
mbhc->mbhc_cb->compute_impedance(l, r, zl, zr);