Merge "msm: vidc: initialize venus hfi locks during hfi creation"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 0d3d3f7..aa24dc6 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -22,16 +22,13 @@
should be 1 for SVS corner
- regulator-max-microvolt: Maximum corner value as max constraint, which
should be 4 for SUPER_TURBO or 3 for TURBO
-- qcom,pvs-init-voltage: A list of integers whose length is equal to 2
- to the power of qcom,pvs-fuse[num-of-bits]. The
- location or 0-based index of an element in the
- list corresponds to the bin number. The value of
- each integer corresponds to the initial voltage
- of the PVS bin in turbo mode in microvolts.
-- qcom,pvs-corner-ceiling-slow: Ceiling voltages of all corners for APC_PVS_SLOW
-- qcom,pvs-corner-ceiling-nom: Ceiling voltages of all corners for APC_PVS_NOM
-- qcom,pvs-corner-ceiling-fast: Ceiling voltages of all corners for APC_PVS_FAST
- The ceiling voltages for each of above three
+- qcom,pvs-voltage-table: Array of triples in which each triple indicates the initial voltage
+ of the PVS bin in SVS, NOM and Turbo corner in microvolts.
+ The location or 0-based index of an triple in the
+ list corresponds to the bin number.
+- qcom,cpr-voltage-ceiling: Ceiling voltages of SVS, NOM and TURBO corners respectively
+- qcom,cpr-voltage-floor: Floor voltages of SVS, NOM and TURBO corners respectively
+ The ceiling voltages for each of above two
properties may look like this:
0 (SVS voltage): 1050000 uV
1 (NORMAL voltage): 1150000 uV
@@ -206,21 +203,6 @@
- qcom,cpr-uplift-speed-bin: The speed bin value corresponding to one type of processor which needs to apply the
pvs voltage uplift workaround.
This is required if cpr-fuse-uplift-disable-sel is present.
-- qcom,cpr-quot-adjust-table: Array of triples in which each triple indicates the speed bin of the CPU, the virtual
- corner to use and the quotient adjustment.
- The 3 elements in one triple are:
- [0]: => the speed bin of the CPU.
- [1]: => the virtual voltage corner to use.
- [2]: => the quotient adjustment for the corresponding virtual corner.
- If the speed bin in a triple is equal to the speed bin of the CPU, the adjustment would
- be subtracted from the quotient value of the voltage corner when the CPU is running at
- that virtual corner. Each virtual corner value must be in the range 1 to the number of
- elements in qcom,cpr-corner-map.
-- qcom,cpr-corner-map: Array of elements of fuse corner value for each virtual corner.
- The location or 1-based index of an element in the list corresponds to
- the virtual corner value. For example, the first element in the list is the fuse corner
- value that virtual corner 1 maps to.
- This is required if qcom,cpr-quot-adjust-table is present.
- qcom,cpr-quotient-adjustment: Array of three elements of CPR quotient adjustments for each corner.
The 3 quotient adjustments with index[0..2] are:
[0] => amount to add to the SVS quotient
@@ -233,6 +215,42 @@
Not Present: No such regulator.
- vdd-apc-optional-sec-supply: Present: Regulator of second highest priority to supply VDD APC power.
Not Present: No such regulator.
+- qcom,cpr-speed-bin-max-corners: Array of quintuples in which each quintuple maps a CPU speed bin and PVS version to
+ the maximum virtual voltage corner corresponding to the SVS, NORMAL and TURBO corners.
+ The 5 elements in one quintuple are:
+ [0]: => the speed bin of the CPU.
+ [1]: => the PVS version of the CPU.
+ [2]: => the max virtual voltage corner value corresponding to SVS corner for this speed bin.
+ [3]: => the max virtual voltage corner value corresponding to NORMAL corner for this speed bin.
+ [4]: => the max virtual voltage corner value corresponding to TURBO corner for this speed bin.
+ No CPR target quotient scaling is applied on chips which have a speed bin + PVS version
+ pair that does not appear in one of the quintuples in this property. If the property is
+ specified, then quotient scaling is enabled for the TURBO corner. If this property is
+ not specified, then no quotient scaling can take place.
+- qcom,cpr-corner-map: Array of elements of fuse corner value for each virtual corner.
+ The location or 1-based index of an element in the list corresponds to
+ the virtual corner value. For example, the first element in the list is the fuse corner
+ value that virtual corner 1 maps to.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,cpr-corner-frequency-map: Array of tuples in which a tuple describes a corner to application processor frequency
+ mapping.
+ The 2 elements in one tuple are:
+ [0]: => a virtual voltage corner.
+ [1]: => the application processor frequency in Hz corresponding to the virtual corner.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,pvs-version-fuse-sel: Array of 4 elements to indicate where to read the pvs version of the processor,
+ and the fuse reading method.
+ The 4 elements with index[0..3] are:
+ [0]: => the fuse row number of the selector;
+ [1]: => LSB bit position of the bits;
+ [2]: => the number of bits;
+ [3]: => fuse reading method, 0 for direct reading or 1 for SCM reading.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
+- qcom,cpr-quot-adjust-scaling-factor-max: The maximum allowed CPR target quotient scaling factor to use when
+ calculating the quotient adjustment for a given virtual voltage corner. It
+ corresponds to 'scaling' in this equation:
+ quot_adjust = (freq_turbo - freq_corner) * scaling / 1000.
+ This property is required if qcom,cpr-speed-bin-max-corners is present.
Example:
apc_vreg_corner: regulator@f9018000 {
@@ -243,23 +261,47 @@
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <3>;
+ regulator-max-microvolt = <12>;
qcom,pvs-fuse = <22 6 5 1>;
qcom,pvs-fuse-redun-sel = <22 24 3 2 1>;
qcom,pvs-fuse-redun = <22 27 5 1>;
- qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000
- 1310000 1300000 1290000 1280000
- 1270000 1260000 1250000 1240000
- 1230000 1220000 1210000 1200000
- 1190000 1180000 1170000 1160000
- 1150000 1140000 1140000 1140000
- 1140000 1140000 1140000 1140000
- 1140000 1140000 1140000 1140000>;
- qcom,pvs-corner-ceiling-slow = <1050000 1160000 1275000>;
- qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000>;
- qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000>;
+ qcom,pvs-voltage-table =
+ <1050000 1150000 1350000>,
+ <1050000 1150000 1340000>,
+ <1050000 1150000 1330000>,
+ <1050000 1150000 1320000>,
+ <1050000 1150000 1310000>,
+ <1050000 1150000 1300000>,
+ <1050000 1150000 1290000>,
+ <1050000 1150000 1280000>,
+ <1050000 1150000 1270000>,
+ <1050000 1140000 1260000>,
+ <1050000 1130000 1250000>,
+ <1050000 1120000 1240000>,
+ <1050000 1110000 1230000>,
+ <1050000 1100000 1220000>,
+ <1050000 1090000 1210000>,
+ <1050000 1080000 1200000>,
+ <1050000 1070000 1190000>,
+ <1050000 1060000 1180000>,
+ <1050000 1050000 1170000>,
+ <1050000 1050000 1160000>,
+ <1050000 1050000 1150000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>;
+ qcom,cpr-voltage-ceiling = <1050000 1150000 1280000>;
+ qcom,cpr-voltage-floor = <1050000 1050000 1100000>;
vdd-apc-supply = <&pm8226_s2>;
vdd-apc-optional-prim-supply = <&ncp6335d>;
vdd-apc-optional-sec-supply = <&fan53555>;
@@ -298,9 +340,25 @@
qcom,cpr-uplift-speed-bin = <1>;
qcom,speed-bin-fuse-sel = <22 0 3 0>;
qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3>;
- qcom,cpr-quot-adjust-table = <1 1 0>, <1 2 0>, <1 3 0>,
- <1 4 0>, <1 5 450>, <1 6 375>,
- <1 7 300>, <1 8 225>, <1 9 187>,
- <1 10 150>, <1 11 75>, <1 12 0>;
+ qcom,cpr-corner-frequency-map =
+ <1 300000000>,
+ <2 384000000>,
+ <3 600000000>,
+ <4 787200000>,
+ <5 998400000>,
+ <6 1094400000>,
+ <7 1190400000>,
+ <8 1305600000>,
+ <9 1344000000>,
+ <10 1401600000>,
+ <11 1497600000>,
+ <12 1593600000>;
+ qcom,pvs-version-fuse-sel = <22 4 2 0>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 1 2 4 7>,
+ <1 1 2 4 12>,
+ <2 1 2 4 10>,
+ <5 1 2 4 14>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <650>;
};
diff --git a/Documentation/devicetree/bindings/arm/msm/ext-buck-control.txt b/Documentation/devicetree/bindings/arm/msm/ext-buck-control.txt
new file mode 100644
index 0000000..37c0995
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/ext-buck-control.txt
@@ -0,0 +1,26 @@
+* MSM EXT BUCK REGULATOR CONTROL
+
+External buck regulator is used to power up the APC rail.
+This buck can be turn-on & turn-off by toggling a gpio
+line which is connected to buck enable pin. This driver
+control the external regulator behaviour with the help
+of RPM by sending the sleep and active sets when APPS
+decide to enter into low power state with RPM assisted.
+
+The required properties for EXT BUCK CONTROL are:
+
+- compatible: "qcom,ext-buck-control"
+
+The optional properties are:
+- qcom,gpio-num: Indicates the GPIO number which will turn-on and turn-off
+ the external buck.
+- qcom,settling-time-us: Indicates the settling time for the external buck to
+ get turn-on or turn-off. Settling time is calculated
+ in terms of QTIMER(19.2MHz) and the value is in us.
+
+Example:
+ qcom,ext-buck-control {
+ compatible = "qcom,ext-buck-control";
+ qcom,gpio-num = <50>;
+ qcom,settling-time-us = <2580>;
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/ext-buck-support.txt b/Documentation/devicetree/bindings/arm/msm/ext-buck-support.txt
deleted file mode 100644
index d7de2b7..0000000
--- a/Documentation/devicetree/bindings/arm/msm/ext-buck-support.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-* MSM EXT BUCK SUPPORT
-
-EXT BUCK SUPPORT driver is for supporting the external buck controlled by RPM.
-This driver sends active and sleep set votes when handshaking with rpm for
-supporting external buck by toggling a gpio to trun-on and turn-off external
-buck.
-
-The required properties for EXT BUCK SUPPORT are:
-
-- compatible: "qcom,ext-buck-support"
-
-The optional properties are:
-- qcom,gpio-num: Indicates the GPIO number which will turn-on and turn-off
- the external buck.
-- qcom,settling-time: Indicates the settling time for the external buck to
- get turn-on or turn-off. Settling time is calculated
- in terms of QTIMER(19.2MHz).
-
-Example:
- qcom,ext-buck-support {
- compatible = "qcom,ext-buck-support";
- qcom,gpio-num = <50>;
- qcom,settling-time = <2580>;
- };
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
index cda437a..e8b02cf 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-ctrl.txt
@@ -6,7 +6,8 @@
Required properties:
- compatible: Must be "qcom,mdss-dsi-ctrl"
- cell-index: Specifies the controller used among the two controllers.
-- reg: offset and length of the register set for the device.
+- reg: Offset and length of the register regions(s) for the device.
+- reg-names: A list of strings that map in order to the list of regs.
- vdd-supply: Phandle for vdd regulator device node.
- vddio-supply: Phandle for vdd-io regulator device node.
- vdda-supply: Phandle for vreg regulator device node.
@@ -52,7 +53,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>;
+ reg = <0xfd922800 0x600>,
+ <0xfd828000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
vdd-supply = <&pm8226_l15>;
vddio-supply = <&pm8226_l8>;
vdda-supply = <&pm8226_l4>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index ae6f8ef..02d6df9 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -254,6 +254,9 @@
mode. This master delay (t_init_delay as per DSI spec) should be sum
of DSI internal delay to reach fuctional after power up and minimum
delay required by panel to reach functional.
+- qcom,mdss-dsi-rx-eot-ignore: Boolean used to enable ignoring end of transmission packets.
+- qcom,mdss-dsi-tx-eot-append: Boolean used to enable appending end of transmission packets.
+- qcom,ulps-enabled: Boolean to enable support for Ultra Low Power State (ULPS) mode.
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -348,5 +351,8 @@
qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>;
qcom,mdss-dsi-lp11-init;
qcom,mdss-dsi-init-delay-us = <100>;
+ mdss-dsi-rx-eot-ignore;
+ mdss-dsi-tx-eot-append;
+ qcom,ulps-enabled;
};
};
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 656f3a4..ec5cfa5 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -71,6 +71,13 @@
This is used to override faulty hardware readings.
- qcom,strtstp-sleepwake: Boolean. Enables use of GPU SLUMBER instead of SLEEP for power savings
+- qcom,pm-qos-latency: Every time GPU wakes up from sleep, driver votes for
+ acceptable maximum latency to the pm-qos driver. This
+ voting demands that *CPU* can not go into a power save
+ state *if* the latency to bring CPU back into normal
+ state is more than this value.
+ Value is in microseconds.
+
The following properties are optional as collecting data via coresight might
not be supported for every chipset. The documentation for coresight
properties can be found in:
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
index d0c2b7d..ba61a2f 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -52,6 +52,12 @@
- goodix,cfg-data5 : Touch screen controller config data group 5. Ask vendor
to provide that.
- goodix,fw-name : Touch screen controller firmware file name.
+ - goodix,slide-wakeup : To specify slide-wakeup property is enabled or not.
+ - goodix,dbl-clk-wakeup : To specify dbl-clk-wakeup property is enabled or not.
+ - goodix,change-x2y : To specify change-x2y property is enabled or not.
+ - goodix,driver-send-cfg : To specify driver-send-cfg property is enabled or not.
+ - goodix,have-touch-key : To specify have-touch-key property is enabled or not.
+ - goodix,with-pen : To specify with-pen property is enabled or not.
Example:
i2c@f9927000 {
goodix@5d {
@@ -87,5 +93,7 @@
FF FF FF FF FF FF FF 22 22 22
22 22 22 FF 07 01];
goodix,fw_name = "gtp_fw.bin";
+ goodix,have-touch-key;
+ goodix,driver-send-cfg;
};
};
diff --git a/Documentation/devicetree/bindings/media/video/msm-eeprom.txt b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
index 6ed130c..6aa0a16 100644
--- a/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-eeprom.txt
@@ -57,6 +57,7 @@
- qcom,pageen%d : number %d page enable reg size, start address, address type,
data, data type, delay in ms. size 0 stand for not used.
- cam_vdig-supply : should contain regulator to be used for the digital vdd.
+- qcom,saddr%d : property should specify the slave address for block (%d).
Optional properties -EEPROM Camera Multimodule
- qcom,mm-data-support - Camera Multimodule data capability flag.
@@ -82,6 +83,7 @@
qcom,pageen1 = <1 0x0202 2 0x01 1 10>;
qcom,poll1 = <0 0x0 2 0 1 1>;
qcom,mem1 = <32 0x3000 2 0 1 0>;
+ qcom,saddr1 = <0x62>;
qcom,mm-data-support;
qcom,mm-data-compressed;
diff --git a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
index 8cef7f0..447c8c1 100644
--- a/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
+++ b/Documentation/devicetree/bindings/mtd/msm_qpic_nand.txt
@@ -13,11 +13,12 @@
Each partition is represented as a sub-node of the qcom,mtd-partitions device.
Each node's name represents the name of the corresponding partition.
-Required properties:
-- reg : The partition offset and size
-- label : The label / name for this partition.
+This is now completely optional as the partition information is avaialble from
+bootloader.
Optional properties:
+- reg : The partition offset and size
+- label : The label / name for this partition.
- read-only: This parameter, if present, indicates that this partition
should only be mounted read-only.
diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
index 2c06599..7af847c 100644
--- a/Documentation/devicetree/bindings/nfc/nfc-nci.txt
+++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
@@ -12,13 +12,12 @@
- qcom,clk-src-gpio: msm gpio clock,used ony if clock source is msm gpio
- qcom,clk-req-gpio: clk-req input gpio for MSM based clocks.
not used for pmic implementation
-- vlogic-supply: LDO for power supply
- interrupt-parent: Should be phandle for the interrupt controller
that services interrupts for this device.
- interrupts: Nfc read interrupt,gpio-clk-req interrupt
- qcom,clk-gpio: pmic or msm gpio on which bbclk2 signal is coming.
-LDO example:
+Example:
i2c@f9925000 { /* BLSP-1 QUP-3 */
nfc-nci@e {
@@ -31,7 +30,6 @@
interrupt-parent = <&msmgpio>;
interrupts = <77 0>;
qcom,clk-gpio = <&msmgpio 75 0x00>;
- vlogic-supply = <&pm8110_l14>;
};
};
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 83237f9..7b70369 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -36,6 +36,10 @@
to include it more than once.
- qcom,s3-debounce The debounce delay for stage3 reset trigger in
secs. The values range from 0 to 128.
+- qcom,s3-src The source for stage 3 reset. It can be one of
+ "kpdpwr", "resin", "kpdpwr-or-resin" or
+ "kpdpwr-and-resin". The default value is
+ "kpdpwr-and-resin".
All the below properties are in the sub-node section (properties of the child
node).
@@ -92,6 +96,7 @@
qcom,pon-dbc-delay = <15625>;
qcom,system-reset;
qcom,s3-debounce = <32>;
+ qcom,s3-src = "resin";
qcom,pon_1 {
qcom,pon-type = <0>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 50381a2..87ecc64 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -106,6 +106,10 @@
- qcom,vbatdet-maxerr-mv This property in mV is a hystersis value for the charge
resume voltage property qcom,vbatdet-delta-mv. If this
property is not defined it defaults to 50 mV.
+- qcom,parallel-ovp-mode When this option is enabled, it allows charging through both
+ DC and USB OVP FETs. Please note that this should only
+ be enabled in board designs with PM8941 which have DC_IN
+ and USB_IN connected via a short.
Sub node required structure:
- A qcom,chg node must be a child of an SPMI node that has specified
diff --git a/Documentation/devicetree/bindings/regulator/krait-regulator.txt b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
index 7c661fe..004c4df 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -22,7 +22,12 @@
the phase scaling factor eFuse address.
- qcom,pfm-threshold The power coeff threshold in abstract power units below which
pmic will be made to operate in PFM mode.
-
+- qcom,phase-scaling-factor-bits-pos indicates bit position of scaling factor data within the efuse
+ register.
+- qcom,valid-scaling-factor-versions This is an array holding four boolean values and indicates whether
+ the version read from efuses is valid.
+ The version is a two bit field and the value read from hardware is
+ used as an index in this array to check for validity.
Optional properties:
- qcom,use-phase-switching indicates whether the driver should add/shed phases on the PMIC
ganged regulator as cpus are hotplugged.
@@ -70,6 +75,9 @@
qcom,use-phase-switching;
qcom,use-phase-scaling-factor;
qcom,pfm-threshold = <376975>;
+ qcom,phase-scaling-factor-bits-pos = <18>;
+ qcom,valid-scaling-factor-versions = <0 1 1 0>;
+
#address-cells = <1>;
#size-cells = <1>;
ranges;
diff --git a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
index 64f2ddd..e199e55 100644
--- a/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
+++ b/Documentation/devicetree/bindings/slimbus/slim-msm-ctrl.txt
@@ -54,7 +54,11 @@
are to be used, so that application processor can query
logical address of the ported generic device to be used.
Other than PC, fields of EA are same across platforms.
-
+ -qcom,slim-mdm: This value indicates presence of slimbus component on
+ external mdm. This property enables the slimbus driver to
+ receive subsytem restart notification from mdm and follow
+ appropriate steps to ensure communication on the bus can be
+ resumed after mdm-restart.
Example:
slim@fe12f000 {
cell-index = <1>;
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
index e4e05d1..415a3ef 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -26,6 +26,12 @@
to set temperature thresholds and receive notification when the temperature
crosses a set threshold, read temperature and enable/set trip types supported
by the thermal framework.
+- qcom,meas-interval-timer-idx: If present select from the following timer index to choose
+ a preset configurable measurement interval timer value. The driver defaults
+ to timer 1 with a measurement interval of 1 second if the property is not present.
+ 0 : Select Timer 1 for a measurement polling interval of 1 second.
+ 1 : Select Timer 2 for a measurement polling interval of 500ms.
+ 2 : Select Timer 3 for a measurement polling interval of 4 seconds.
Client required property:
- qcom,<consumer name>-adc_tm : The phandle to the corresponding adc_tm device.
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 24f21b4..6562607 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -131,15 +131,24 @@
Required properties :
- compatible : should be "qcom,hsic-smsc-hub"
-- smsc,model-id : should be either <3503> or <4604> depending on hub model
-- smsc,<gpio-name>-gpio : handle to the GPIO node, see "gpios property"
- in Documentation/devicetree/bindings/gpio/gpio.txt.
- Required "gpio-name" is "reset" and optionally - "refclk", "int".
-- <supply-name>-supply: handle to the regulator device tree node
- Required "supply-name" is "hub_init" and optionally - "hub_vbus".
+- smsc,model-id : should be <3502>/<3503>/<4604> depending on hub model. It
+ will be 0 for standalone HSIC controller configuration.
+- smsc,reset-gpio: this output gpio is used to assert/de-assert the hub reset
- Sub node for "MSM HSIC EHCI controller".
Sub node has the required properties mentioned above.
+Optional properties :
+- smsc,int-gpio: this input gpio indicate HUB suspend status and signal remote
+ wakeup interrupt
+- smsc,refclk-gpio: this gpio is used to supply the reference clock
+- smsc,xo-clk-gio: this output gpio is used to control the external XO clock
+ which is supplied to the hub as a reference clock
+- hub-vbus-supply: this regulator is used to supply the power to
+ downstream ports
+- hub-int-supply: this regulator is used to bias the interrupt gpio
+- ext-hub-vddio-supply: this regulator is used to supply the power to one of
+ the hub's VDD.
+
Example SMSC HSIC HUB :
hsic_hub {
compatible = "qcom,hsic-smsc-hub";
@@ -148,8 +157,8 @@
smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
smsc,refclk-gpio = <&pm8941_gpios 16 0x00>;
smsc,int-gpio = <&msmgpio 50 0x00>;
- hub_int-supply = <&pm8941_l10>;
- hub_vbus-supply = <&pm8941_mvs1>;
+ hub-int-supply = <&pm8941_l10>;
+ hub-vbus-supply = <&pm8941_mvs1>;
hsic@f9a00000 {
compatible = "qcom,hsic-host";
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index 623a23c..7d3d435 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -93,6 +93,8 @@
enable this feature without proper bus voting.
-qcom,disable-retention-with-vdd-min: If present dont allow phy retention but allow
vdd min.
+- qcom,usbin-vadc: Corresponding vadc device's phandle to read usbin voltage using VADC.
+ This will be used to get value of usb power supply's VOLTAGE_NOW property.
Example HSUSB OTG controller device node :
usb@f9690000 {
@@ -120,6 +122,7 @@
qcom,disable-retention-with-vdd-min;
qcom,hsusb-otg-dpsehv-int = <49>;
qcom,hsusb-otg-dmsehv-int = <58>;
+ qcom,usbin-vadc = <&pm8226_vadc>;
qcom,msm_bus,name = "usb2";
qcom,msm_bus,num_cases = <2>;
qcom,msm_bus,active_only = <0>;
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index a7a646d..bfa9abe 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -58,6 +58,8 @@
for TX fifo allocation in QDSS composition
- qcom,dwc-ssphy-deemphasis-value: This property if present represents ss phy
deemphasis value to be used for overriding into SSPHY register.
+- qcom,usbin-vadc: Corresponding vadc device's phandle to read usbin voltage using VADC.
+ This will be used to get value of usb power supply's VOLTAGE_NOW property,
Sub nodes:
- Sub node for "DWC3- USB3 controller".
@@ -85,6 +87,7 @@
qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
qcom,dwc-usb3-msm-qdss-tx-fifo-size = <16384>;
qcom,dwc-ssphy-deemphasis-value = <26>;
+ qcom,usbin-vadc = <&pm8941_vadc>;
qcom,msm_bus,name = "usb3";
qcom,msm_bus,num_cases = <2>;
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index fd826d9..b94b587 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -8,6 +8,7 @@
apm Applied Micro Circuits Corporation (APM)
arm ARM Ltd.
atmel Atmel Corporation
+avago Avago Technologies
bosch Bosch Sensortec GmbH
capella Capella Microsystems, Inc.
cavium Cavium, Inc.
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index c7e24d9..8c76a6d 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -74,7 +74,7 @@
/* Dragonboard has an always-on VBUS supply for HSIC hub,
* providing a dummy regulator for the hub driver
*/
- hub_vbus-supply = <&vph_pwr_vreg>;
+ hub-vbus-supply = <&vph_pwr_vreg>;
hsic_host: hsic@f9a00000 {
compatible = "qcom,hsic-host";
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 0558ee5..41897da 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -39,6 +39,7 @@
qcom,pon-dbc-delay = <15625>;
qcom,system-reset;
qcom,s3-debounce = <32>;
+ qcom,s3-src = "kpdpwr-and-resin";
qcom,pon_1 {
qcom,pon-type = <0>;
@@ -50,10 +51,6 @@
qcom,pon-type = <1>;
qcom,pull-up = <1>;
linux,code = <114>;
- qcom,s1-timer = <6720>;
- qcom,s2-timer = <2000>;
- qcom,s2-type = <7>;
- qcom,support-reset = <1>;
};
qcom,pon_3 {
@@ -366,6 +363,7 @@
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
+ qcom,vadc-poll-eoc;
chan@8 {
label = "die_temp";
@@ -424,6 +422,7 @@
qcom,adc-bit-resolution = <16>;
qcom,adc-vdd-reference = <1800>;
qcom,iadc-vadc = <&pm8226_vadc>;
+ qcom,iadc-poll-eoc;
qcom,use-default-rds-trim = <0>;
chan@0 {
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index e678388..94a4e83 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -875,6 +875,7 @@
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <3>;
qcom,btm-channel-number = <0x68>;
+ qcom,meas-interval-timer-idx = <2>;
};
chan@8 {
diff --git a/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
index a99df65..3734273 100644
--- a/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
@@ -120,6 +120,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
sound-9302 {
@@ -137,6 +138,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-720p-mtp.dtsi b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
index 7f4f8fc..b4d9139 100644
--- a/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
@@ -110,6 +110,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
sound-9302 {
@@ -127,6 +128,7 @@
qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,cdc-us-euro-gpios = <&msmgpio 69 0>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-gpu.dtsi b/arch/arm/boot/dts/msm8226-gpu.dtsi
index 590f733..d1c3264 100644
--- a/arch/arm/boot/dts/msm8226-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8226-gpu.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -34,9 +34,9 @@
qcom,msm-bus,num-paths = <2>;
qcom,msm-bus,vectors-KBps =
<26 512 0 0>, <89 604 0 0>,
- <26 512 0 1600000>, <89 604 0 3200000>,
- <26 512 0 3200000>, <89 604 0 5120000>,
- <26 512 0 4256000>, <89 604 0 6400000>;
+ <26 512 800000 1600000>, <89 604 0 3200000>,
+ <26 512 1600000 3200000>, <89 604 0 5120000>,
+ <26 512 2128000 4256000>, <89 604 0 6400000>;
/* GDSC oxili regulators */
@@ -47,6 +47,9 @@
/* IOMMU Data */
iommu = <&kgsl_iommu>;
+ /* CPU latency parameter */
+ qcom,pm-qos-latency = <701>;
+
/* Power levels */
qcom,gpu-pwrlevels {
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 8a98d5c..2176d39 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -59,7 +59,7 @@
qcom,mdss-intf-off = <0x00000000 0x00021300>;
qcom,mdss-rot-block-size = <64>;
qcom,mdss-rotator-ot-limit = <2>;
- qcom,mdss-smp-mb-per-pipe = <4>;
+ qcom,mdss-smp-mb-per-pipe = <3>;
vdd-cx-supply = <&pm8226_s1_corner>;
qcom,vbif-settings = <0x004 0x00000001>,
@@ -95,7 +95,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>;
+ reg = <0xfd922800 0x600>,
+ <0xfd828000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
qcom,mdss-fb-map = <&mdss_fb0>;
qcom,mdss-mdp = <&mdss_mdp>;
vdd-supply = <&pm8226_l15>;
diff --git a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
index c3fcedb..42de953 100755
--- a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
@@ -125,6 +125,8 @@
FF FF FF FF FF FF FF FF FF FF
FF FF FF FF 3E 01];
goodix,fw_name = "gtp_fw.bin";
+ goodix,have-touch-key;
+ goodix,driver-send-cfg;
};
};
};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index a76c4df..5e890d3 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -19,7 +19,7 @@
regulator-name = "8226_s2";
reg = <0x1700 0x100>;
regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1275000>;
+ regulator-max-microvolt = <1350000>;
qcom,mode = "auto";
};
};
@@ -35,23 +35,46 @@
reg-names = "rbcpr", "rbcpr_clk", "efuse_addr";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
- regulator-min-microvolt = <1>;
- regulator-max-microvolt = <14>;
qcom,pvs-fuse-redun-sel = <22 24 3 2 0>;
qcom,pvs-fuse = <22 6 5 0>;
qcom,pvs-fuse-redun = <22 27 5 0>;
- qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
- 1275000 1260000 1245000 1230000 1215000
- 1200000 1185000 1170000 1155000 1140000
- 1140000 1140000 1140000 1140000 1140000
- 1150000 1140000 1140000 1140000 1140000
- 1140000 1140000 1140000 1275000 1275000
- 1275000 1275000>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
- qcom,pvs-corner-ceiling-nom = <1050000 1075000 1200000>;
- qcom,pvs-corner-ceiling-fast = <1050000 1050000 1100000>;
+ qcom,pvs-voltage-table =
+ <1050000 1150000 1350000>,
+ <1050000 1150000 1340000>,
+ <1050000 1150000 1330000>,
+ <1050000 1150000 1320000>,
+ <1050000 1150000 1310000>,
+ <1050000 1150000 1300000>,
+ <1050000 1150000 1290000>,
+ <1050000 1150000 1280000>,
+ <1050000 1150000 1270000>,
+ <1050000 1140000 1260000>,
+ <1050000 1130000 1250000>,
+ <1050000 1120000 1240000>,
+ <1050000 1110000 1230000>,
+ <1050000 1100000 1220000>,
+ <1050000 1090000 1210000>,
+ <1050000 1080000 1200000>,
+ <1050000 1070000 1190000>,
+ <1050000 1060000 1180000>,
+ <1050000 1050000 1170000>,
+ <1050000 1050000 1160000>,
+ <1050000 1050000 1150000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>,
+ <1050000 1050000 1140000>;
+ qcom,cpr-voltage-ceiling = <1050000 1150000 1280000>;
+ qcom,cpr-voltage-floor = <1050000 1050000 1100000>;
vdd-apc-supply = <&pm8226_s2>;
vdd-mx-supply = <&pm8226_l3_ao>;
@@ -63,14 +86,12 @@
qcom,cpr-timer-cons-up = <0>;
qcom,cpr-timer-cons-down = <2>;
qcom,cpr-irq-line = <0>;
- qcom,cpr-step-quotient = <15>;
- qcom,cpr-up-threshold = <0>;
- qcom,cpr-down-threshold = <10>;
+ qcom,cpr-step-quotient = <30>;
qcom,cpr-idle-clocks = <0>;
qcom,cpr-gcnt-time = <1>;
qcom,vdd-apc-step-up-limit = <1>;
qcom,vdd-apc-step-down-limit = <1>;
- qcom,cpr-apc-volt-step = <5000>;
+ qcom,cpr-apc-volt-step = <10000>;
qcom,cpr-fuse-redun-sel = <138 57 1 1 0>;
qcom,cpr-fuse-row = <138 0>;
@@ -91,15 +112,6 @@
qcom,cpr-uplift-max-volt = <1350000>;
qcom,cpr-uplift-speed-bin = <1>;
qcom,speed-bin-fuse-sel = <22 0 3 0>;
- qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3 3 3>;
- qcom,cpr-quot-adjust-table =
- <1 5 450>,
- <1 6 375>,
- <1 7 300>,
- <1 8 225>,
- <1 9 187>,
- <1 10 150>,
- <1 11 75>;
};
};
@@ -198,7 +210,7 @@
pm8226_l3: regulator-l3 {
regulator-name = "8226_l3";
regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1275000>;
+ regulator-max-microvolt = <1337500>;
status = "okay";
};
pm8226_l3_ao: regulator-3-ao {
@@ -206,7 +218,7 @@
regulator-name = "8226_l3_ao";
qcom,set = <1>;
regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1275000>;
+ regulator-max-microvolt = <1337500>;
status = "okay";
};
pm8226_l3_so: regulator-l3-so {
@@ -214,7 +226,7 @@
regulator-name = "8226_l3_so";
qcom,set = <2>;
regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1275000>;
+ regulator-max-microvolt = <1337500>;
qcom,init-voltage = <750000>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/msm8226-v1-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
index 6e79e8a..d59fab3 100644
--- a/arch/arm/boot/dts/msm8226-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
@@ -226,6 +226,9 @@
<0xff 191>, /* lpass_irq_out_apcs(3) */
<0xff 192>, /* lpass_irq_out_apcs(4) */
<0xff 194>, /* lpass_irq_out_apcs(6) */
+ <0xff 195>, /* SLIMbus slimbus_core_ee1_irq */
+ <0xff 196>, /* BAM-Lite - SlimBus */
+ <0xff 198>, /* coresight-tmc-etr interrupt */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
diff --git a/arch/arm/boot/dts/msm8226-v1.dtsi b/arch/arm/boot/dts/msm8226-v1.dtsi
index 7f2048f..b9455fb 100644
--- a/arch/arm/boot/dts/msm8226-v1.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -65,3 +65,63 @@
qcom,retain-periph;
qcom,retain-mem;
};
+
+&pm8226_s2 {
+ regulator-max-microvolt = <1275000>;
+};
+
+&pm8226_l3 {
+ regulator-max-microvolt = <1287500>;
+};
+
+&pm8226_l3_ao {
+ regulator-max-microvolt = <1287500>;
+};
+
+&pm8226_l3_so {
+ regulator-max-microvolt = <1287500>;
+};
+
+&apc_vreg_corner {
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <3>;
+ qcom,pvs-voltage-table =
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>;
+ qcom,cpr-voltage-ceiling = <1050000 1150000 1275000>;
+ qcom,cpr-voltage-floor = <1050000 1050000 1100000>;
+ qcom,cpr-step-quotient = <15>;
+ qcom,cpr-apc-volt-step = <5000>;
+ qcom,cpr-up-threshold = <0>;
+ qcom,cpr-down-threshold = <10>;
+};
diff --git a/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
index 77cc08c..d48f8b6 100644
--- a/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -21,6 +21,6 @@
qcom,board-id = <1 2>;
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
index 966ae2b..f73bac0 100644
--- a/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -21,6 +21,6 @@
qcom,board-id = <1 0>;
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-v2-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
index 7753562..bc8fe5d 100644
--- a/arch/arm/boot/dts/msm8226-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
@@ -238,6 +238,9 @@
<0xff 191>, /* lpass_irq_out_apcs(3) */
<0xff 192>, /* lpass_irq_out_apcs(4) */
<0xff 194>, /* lpass_irq_out_apcs(6) */
+ <0xff 195>, /* SLIMbus slimbus_core_ee1_irq */
+ <0xff 196>, /* BAM-Lite - SlimBus */
+ <0xff 198>, /* coresight-tmc-etr interrupt */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 5a670c2..14fe237 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -31,41 +31,34 @@
<223 0x20000>;
};
-&pm8226_l3 {
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1337500>;
-};
-
-&pm8226_l3_ao {
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1337500>;
-};
-
-&pm8226_l3_so {
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1337500>;
-};
-
-&pm8226_s2 {
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1330000>;
-};
-
&apc_vreg_corner {
- qcom,pvs-init-voltage = <1330000 1330000 1330000 1320000 1310000
- 1300000 1290000 1280000 1270000 1260000
- 1250000 1240000 1230000 1220000 1210000
- 1200000 1190000 1180000 1170000 1160000
- 1150000 1140000 1140000 1140000 1140000
- 1140000 1140000 1140000 1140000 1140000
- 1140000 1140000>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
- qcom,pvs-corner-ceiling-nom = <1050000 1080000 1200000>;
- qcom,pvs-corner-ceiling-fast = <1050000 1050000 1100000>;
- qcom,cpr-step-quotient = <30>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <14>;
qcom,cpr-up-threshold = <0>;
qcom,cpr-down-threshold = <5>;
- qcom,cpr-apc-volt-step = <10000>;
+ qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3 3 3>;
+ qcom,pvs-version-fuse-sel = <22 4 2 0>;
+ qcom,cpr-corner-frequency-map =
+ <1 300000000>,
+ <2 384000000>,
+ <3 600000000>,
+ <4 787200000>,
+ <5 998400000>,
+ <6 1094400000>,
+ <7 1190400000>,
+ <8 1305600000>,
+ <9 1344000000>,
+ <10 1401600000>,
+ <11 1497600000>,
+ <12 1593600000>,
+ <13 1689600000>,
+ <14 1785600000>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 2 2 4 7>,
+ <1 2 2 4 12>,
+ <2 2 2 4 10>,
+ <5 2 2 4 14>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <650>;
};
&msm_gpu {
@@ -78,6 +71,11 @@
reg = <0xf9011050 0x8>,
<0xfc4b80b0 0x8>;
reg-names = "rcg-base", "efuse";
+ qcom,speed0-bin-v0 =
+ < 0 0>,
+ < 384000000 2>,
+ < 787200000 4>,
+ <1190400000 7>;
qcom,speed0-bin-v2 =
< 0 0>,
< 384000000 2>,
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index e7d8a4d..cf8e3b3 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -282,8 +282,9 @@
qcom,hsusb-otg-phy-type = <2>;
qcom,hsusb-otg-mode = <1>;
qcom,hsusb-otg-otg-control = <2>;
+ qcom,hsusb-otg-disable-reset;
qcom,dp-manual-pullup;
- qcom,ahb-async-bridge-bypass;
+ qcom,usbin-vadc = <&pm8226_vadc>;
qcom,msm-bus,name = "usb";
qcom,msm-bus,num-cases = <3>;
@@ -301,35 +302,43 @@
qcom,streaming-func = "rndis";
};
- hsic_host: hsic@f9a00000 {
+ smsc_hub: hsic_hub {
status = "disabled";
- compatible = "qcom,hsic-host";
- reg = <0xf9a00000 0x400>;
- #address-cells = <0>;
- interrupt-parent = <&hsic_host>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 136 0
- 1 &intc 0 148 0
- 2 &msmgpio 115 0x8>;
- interrupt-names = "core_irq", "async_irq", "wakeup";
- hsic_vdd_dig-supply = <&pm8226_s1_corner>;
- HSIC_GDSC-supply = <&gdsc_usb_hsic>;
- hsic,strobe-gpio = <&msmgpio 115 0x00>;
- hsic,data-gpio = <&msmgpio 116 0x00>;
- hsic,ignore-cal-pad-config;
- hsic,strobe-pad-offset = <0x2050>;
- hsic,data-pad-offset = <0x2054>;
- qcom,phy-susp-sof-workaround;
- hsic,vdd-voltage-level = <1 5 7>;
+ compatible = "qcom,hsic-smsc-hub";
+ smsc,model-id = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
- qcom,msm-bus,name = "hsic";
- qcom,msm-bus,num-cases = <2>;
- qcom,msm-bus,num-paths = <1>;
- qcom,msm-bus,vectors-KBps =
+ hsic_host: hsic@f9a00000 {
+ compatible = "qcom,hsic-host";
+ reg = <0xf9a00000 0x400>;
+ #address-cells = <0>;
+ interrupt-parent = <&hsic_host>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 136 0
+ 1 &intc 0 148 0
+ 2 &msmgpio 115 0x8>;
+ interrupt-names = "core_irq", "async_irq", "wakeup";
+ hsic_vdd_dig-supply = <&pm8226_s1_corner>;
+ HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+ hsic,strobe-gpio = <&msmgpio 115 0x00>;
+ hsic,data-gpio = <&msmgpio 116 0x00>;
+ hsic,ignore-cal-pad-config;
+ hsic,strobe-pad-offset = <0x2050>;
+ hsic,data-pad-offset = <0x2054>;
+ qcom,phy-susp-sof-workaround;
+ hsic,vdd-voltage-level = <1 5 7>;
+
+ qcom,msm-bus,name = "hsic";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
<85 512 0 0>,
<85 512 40000 160000>;
+ };
};
wcd9xxx_intc: wcd9xxx-irq {
@@ -486,6 +495,10 @@
compatible = "qcom,msm-lsm-client";
};
+ qti,msm-pcm-loopback {
+ compatible = "qti,msm-pcm-loopback";
+ };
+
qcom,msm-dai-q6 {
compatible = "qcom,msm-dai-q6";
qcom,msm-dai-q6-sb-0-rx {
@@ -1013,9 +1026,9 @@
clock-names = "clk-4", "clk-5";
qcom,speed0-bin-v0 =
< 0 0>,
- < 384000000 2>,
- < 787200000 4>,
- <1190400000 7>;
+ < 384000000 1>,
+ < 787200000 2>,
+ <1190400000 3>;
cpu-vdd-supply = <&apc_vreg_corner>;
};
@@ -1251,8 +1264,8 @@
qcom,msm-bus,num-cases = <2>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps =
- <1 618 0 0>,
- <1 618 0 800>;
+ <54 618 0 0>,
+ <54 618 0 800>;
};
qcom,tz-log@fe805720 {
@@ -1508,6 +1521,7 @@
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <3>;
qcom,btm-channel-number = <0x48>;
+ qcom,meas-interval-timer-idx = <2>;
};
chan@8 {
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index 54c698c..d26d660 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -41,8 +41,8 @@
qcom,qport = <0>;
qcom,ws = <10000>;
qcom,mas-hw-id = <8>;
- qcom,prio1 = <2>;
- qcom,prio0 = <2>;
+ qcom,prio1 = <3>;
+ qcom,prio0 = <3>;
};
mas-vfe {
diff --git a/arch/arm/boot/dts/msm8610-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
index de480df..480ec11 100644
--- a/arch/arm/boot/dts/msm8610-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8610-gpu.dtsi
@@ -46,6 +46,9 @@
/* IOMMU Data */
iommu = <&gfx_iommu>;
+ /* CPU latency parameter */
+ qcom,pm-qos-latency = <701>;
+
/* Power levels */
qcom,gpu-pwrlevels {
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index c7fa9db..1554575 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -88,6 +88,8 @@
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];
+ goodix,have-touch-key;
+ goodix,driver-send-cfg;
};
};
gen-vkeys {
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 30c557d..6639668 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -42,16 +42,41 @@
qcom,pvs-fuse = <23 6 5 1>;
qcom,pvs-fuse-redun = <61 47 5 1>;
- qcom,pvs-init-voltage = <1275000 1275000 1275000 1275000 1275000
- 1275000 1275000 1275000 1275000 1275000
- 1275000 1275000 1275000 1275000 1275000
- 1275000 1275000 1275000 1275000 1275000
- 1275000 1275000 1275000 1275000 1275000
- 1275000 1275000 1275000 1275000 1275000
- 1275000 1275000>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1275000>;
- qcom,pvs-corner-ceiling-nom = <1050000 1075000 1275000>;
- qcom,pvs-corner-ceiling-fast = <1050000 1050000 1275000>;
+ qcom,pvs-voltage-table =
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>,
+ <1050000 1150000 1275000>;
+ qcom,cpr-voltage-ceiling = <1050000 1150000 1275000>;
+ qcom,cpr-voltage-floor = <1050000 1050000 1275000>;
vdd-apc-supply = <&pm8110_s2>;
vdd-mx-supply = <&pm8110_l3_ao>;
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index 5fb406b..dc1dc8b 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -227,6 +227,7 @@
<0xff 191>, /* lpass_irq_out_apcs(3) */
<0xff 192>, /* lpass_irq_out_apcs(4) */
<0xff 194>, /* lpass_irq_out_apcs(6) */
+ <0xff 198>, /* QDSS - u_qdss */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
diff --git a/arch/arm/boot/dts/msm8610-v1.dtsi b/arch/arm/boot/dts/msm8610-v1.dtsi
index 9d8c411..8965e93 100644
--- a/arch/arm/boot/dts/msm8610-v1.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1.dtsi
@@ -20,6 +20,7 @@
/include/ "msm8610-v1-pm.dtsi"
/ {
- qcom,msm-id = <147 0>, <165 0>, <161 0>, <162 0>,
- <163 0>, <164 0>, <166 0>;
+ qcom,msm-id = <147 1000>, <165 1000>, <161 1000>, <162 1000>,
+ <163 1000>, <164 1000>, <166 1000>, <225 1000>,
+ <226 1000>;
};
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 331e344..2859744 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -239,6 +239,7 @@
<0xff 191>, /* lpass_irq_out_apcs(3) */
<0xff 192>, /* lpass_irq_out_apcs(4) */
<0xff 194>, /* lpass_irq_out_apcs(6) */
+ <0xff 198>, /* QDSS - u_qdss */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
diff --git a/arch/arm/boot/dts/msm8610-v2.dtsi b/arch/arm/boot/dts/msm8610-v2.dtsi
index a1f466a..221598d 100644
--- a/arch/arm/boot/dts/msm8610-v2.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2.dtsi
@@ -21,5 +21,6 @@
/ {
qcom,msm-id = <147 0x10001>, <165 0x10001>, <161 0x10001>, <162 0x10001>,
- <163 0x10001>, <164 0x10001>, <166 0x10001>;
+ <163 0x10001>, <164 0x10001>, <166 0x10001>,
+ <225 0x10001>, <226 0x10001>;
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 61fa6bc..90e8fd6 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -765,6 +765,11 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <32773>;
};
+
+ qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
};
qcom,msm-pcm-hostless {
@@ -1168,6 +1173,7 @@
qcom,hw-settle-time = <2>;
qcom,fast-avg-setup = <3>;
qcom,btm-channel-number = <0x48>;
+ qcom,meas-interval-timer-idx = <2>;
};
chan@8 {
diff --git a/arch/arm/boot/dts/msm8926-v1-1080p-cdp.dts b/arch/arm/boot/dts/msm8926-v1-1080p-cdp.dts
index 1b6f971..1829a8e 100644
--- a/arch/arm/boot/dts/msm8926-v1-1080p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v1-1080p-cdp.dts
@@ -33,6 +33,6 @@
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-v1-720p-cdp.dts b/arch/arm/boot/dts/msm8926-v1-720p-cdp.dts
index 37da01c..2217f15 100644
--- a/arch/arm/boot/dts/msm8926-v1-720p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v1-720p-cdp.dts
@@ -33,6 +33,6 @@
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-v2-1080p-cdp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-cdp.dts
index a4ebbe1..7ab37cd 100644
--- a/arch/arm/boot/dts/msm8926-v2-1080p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-cdp.dts
@@ -33,6 +33,6 @@
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.dts
index 64e872b..d38b53f 100644
--- a/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-cdp.dts
@@ -33,6 +33,6 @@
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-mtp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-mtp.dts
index f9a3cd8..0a33976 100644
--- a/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-ext-buck-mtp.dts
@@ -21,3 +21,12 @@
compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
qcom,board-id = <8 3>;
};
+
+&smsc_hub {
+ status = "ok";
+ smsc,model-id = <3502>;
+ smsc,reset-gpio = <&msmgpio 114 0x00>;
+ smsc,int-gpio = <&msmgpio 9 0x00>;
+ smsc,xo-clk-gpio = <&msmgpio 8 0x00>;
+ hub-int-supply = <&pm8226_l6>;
+};
diff --git a/arch/arm/boot/dts/msm8926-v2-1080p-mtp.dts b/arch/arm/boot/dts/msm8926-v2-1080p-mtp.dts
index 1f0bab1..2466f8b 100644
--- a/arch/arm/boot/dts/msm8926-v2-1080p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-1080p-mtp.dts
@@ -21,3 +21,12 @@
compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
qcom,board-id = <8 2>;
};
+
+&smsc_hub {
+ status = "ok";
+ smsc,model-id = <3502>;
+ smsc,reset-gpio = <&msmgpio 114 0x00>;
+ smsc,int-gpio = <&msmgpio 9 0x00>;
+ smsc,xo-clk-gpio = <&msmgpio 8 0x00>;
+ hub-int-supply = <&pm8226_l6>;
+};
diff --git a/arch/arm/boot/dts/msm8926-v2-720p-cdp.dts b/arch/arm/boot/dts/msm8926-v2-720p-cdp.dts
index 1e6e197..5c5ad89 100644
--- a/arch/arm/boot/dts/msm8926-v2-720p-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-720p-cdp.dts
@@ -33,6 +33,6 @@
};
-&hsic_host {
+&smsc_hub {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926-v2-720p-mtp.dts b/arch/arm/boot/dts/msm8926-v2-720p-mtp.dts
index 59ad506..2c577cd 100644
--- a/arch/arm/boot/dts/msm8926-v2-720p-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-v2-720p-mtp.dts
@@ -21,3 +21,12 @@
compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
qcom,board-id = <8 0>;
};
+
+&smsc_hub {
+ status = "ok";
+ smsc,model-id = <3502>;
+ smsc,reset-gpio = <&msmgpio 114 0x00>;
+ smsc,int-gpio = <&msmgpio 9 0x00>;
+ smsc,xo-clk-gpio = <&msmgpio 8 0x00>;
+ hub-int-supply = <&pm8226_l6>;
+};
diff --git a/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi b/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi
index e5e496e..8a95116 100644
--- a/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi
+++ b/arch/arm/boot/dts/msm8926-v2-ext-buck.dtsi
@@ -52,5 +52,36 @@
};
&soc {
+ qcom,spm@f9012000 {
+ compatible = "qcom,spm-v2";
+ qcom,saw2-spm-cmd-pc-no-rpm = [00 32 10 e0 d0 6b c0 42 f0
+ 03 50 4e 02 02 c0 d0 12 e0 6b 02 32
+ 50 f0 0f];
+ qcom,saw2-spm-cmd-pc = [00 32 10 e0 d0 6b c0 42 f0
+ 07 50 4e 02 02 c0 d0 12 e0 6b 02 32
+ 50 f0 0f];
+ };
+
+ qcom,lpm-levels {
+ qcom,system-modes {
+ compatible = "qcom,system-modes";
+ qcom,system-modes@2 {
+ qcom,l2 = "l2_cache_pc";
+ qcom,latency-us = <13200>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ qcom,min-cpu-mode= "pc";
+ qcom,sync-cpus;
+ qcom,send-rpm-sleep-set;
+ };
+ };
+ };
+
+ qcom,ext-buck-control {
+ compatible = "qcom,ext-buck-control";
+ qcom,gpio-num = <50>;
+ qcom,settling-time-us = <9600>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8926-v2.dtsi b/arch/arm/boot/dts/msm8926-v2.dtsi
index 9d0c6db..1322573 100644
--- a/arch/arm/boot/dts/msm8926-v2.dtsi
+++ b/arch/arm/boot/dts/msm8926-v2.dtsi
@@ -80,6 +80,13 @@
&apc_vreg_corner {
/delete-property/ qcom,cpr-enable;
+ /delete-property/ qcom,cpr-fuse-cond-min-volt-sel;
+ /delete-property/ qcom,cpr-cond-min-voltage;
+ /delete-property/ qcom,cpr-fuse-uplift-sel;
+ /delete-property/ qcom,cpr-uplift-voltage;
+ /delete-property/ qcom,cpr-uplift-quotient;
+ /delete-property/ qcom,cpr-uplift-max-volt;
+ /delete-property/ qcom,cpr-uplift-speed-bin;
qcom,vdd-mx-vmax = <1287500>;
qcom,vdd-mx-vmin-method = <4>;
qcom,vdd-mx-corner-map = <1050000 1150000 1280000>;
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index c274d9f..e866286 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -39,6 +39,11 @@
reg = <0xf9011050 0x8>,
<0xfc4b80b0 0x8>;
reg-names = "rcg-base", "efuse";
+ qcom,speed0-bin-v0 =
+ < 0 0>,
+ < 384000000 2>,
+ < 787200000 4>,
+ <1190400000 7>;
qcom,speed0-bin-v1 =
< 0 0>,
< 384000000 2>,
@@ -127,42 +132,35 @@
};
};
-&pm8226_l3 {
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1350000>;
-};
-
-&pm8226_l3_ao {
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1350000>;
-};
-
-&pm8226_l3_so {
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1350000>;
-};
-
-&pm8226_s2 {
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1350000>;
-};
-
&apc_vreg_corner {
- qcom,pvs-init-voltage = <1350000 1340000 1330000 1320000 1310000
- 1300000 1290000 1280000 1270000 1260000
- 1250000 1240000 1230000 1220000 1210000
- 1200000 1190000 1180000 1170000 1160000
- 1150000 1140000 1140000 1140000 1140000
- 1140000 1140000 1140000 1140000 1140000
- 1140000 1140000>;
- qcom,pvs-corner-ceiling-slow = <1050000 1150000 1280000>;
- qcom,pvs-corner-ceiling-nom = <1050000 1080000 1200000>;
- qcom,pvs-corner-ceiling-fast = <1050000 1050000 1100000>;
- qcom,cpr-step-quotient = <30>;
qcom,cpr-up-threshold = <0>;
qcom,cpr-down-threshold = <2>;
- qcom,cpr-apc-volt-step = <10000>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <14>;
+ qcom,cpr-corner-map = <1 1 2 2 3 3 3 3 3 3 3 3 3 3>;
qcom,cpr-quotient-adjustment = <0 72 72>;
+ qcom,pvs-version-fuse-sel = <22 4 2 0>;
+ qcom,cpr-corner-frequency-map =
+ <1 300000000>,
+ <2 384000000>,
+ <3 600000000>,
+ <4 787200000>,
+ <5 998400000>,
+ <6 1094400000>,
+ <7 1190400000>,
+ <8 1305600000>,
+ <9 1344000000>,
+ <10 1401600000>,
+ <11 1497600000>,
+ <12 1593600000>,
+ <13 1689600000>,
+ <14 1785600000>;
+ qcom,cpr-speed-bin-max-corners =
+ <0 1 2 4 7>,
+ <1 1 2 4 12>,
+ <2 1 2 4 10>,
+ <5 1 2 4 14>;
+ qcom,cpr-quot-adjust-scaling-factor-max = <650>;
};
&tsens {
@@ -186,3 +184,9 @@
hsic,strobe-gpio = <&msmgpio 119 0x00>;
hsic,data-gpio = <&msmgpio 120 0x00>;
};
+
+&usb_otg {
+ /delete-property/ qcom,hsusb-otg-disable-reset;
+ qcom,ahb-async-bridge-bypass;
+};
+
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index da6d018..3b4c881 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -766,3 +766,26 @@
&dsi_jdi_1080_vid {
qcom,cont-splash-enabled;
};
+
+&dsi_dual_jdi_video_0 {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+ qcom,mdss-dsi-bl-pmic-bank-select = <7>;
+ qcom,cont-splash-enabled;
+};
+
+&dsi_dual_jdi_video_1 {
+ qcom,cont-splash-enabled;
+};
+
+&dsi_dual_jdi_cmd_0 {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+ qcom,mdss-dsi-bl-pmic-bank-select = <7>;
+ qcom,cont-splash-enabled;
+};
+
+&dsi_dual_jdi_cmd_1 {
+ qcom,cont-splash-enabled;
+};
+
diff --git a/arch/arm/boot/dts/msm8974-mdss-panels.dtsi b/arch/arm/boot/dts/msm8974-mdss-panels.dtsi
index d405bf8..c11ef0a 100644
--- a/arch/arm/boot/dts/msm8974-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss-panels.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -15,3 +15,7 @@
/include/ "dsi-panel-sharp-qhd-video.dtsi"
/include/ "dsi-panel-generic-720p-cmd.dtsi"
/include/ "dsi-panel-jdi-1080p-video.dtsi"
+/include/ "dsi-panel-jdi-dualmipi0-video.dtsi"
+/include/ "dsi-panel-jdi-dualmipi1-video.dtsi"
+/include/ "dsi-panel-jdi-dualmipi0-cmd.dtsi"
+/include/ "dsi-panel-jdi-dualmipi1-cmd.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 89f4af8..0e72446 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -113,7 +113,9 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->0";
cell-index = <0>;
- reg = <0xfd922800 0x600>;
+ reg = <0xfd922800 0x600>,
+ <0xfdf30000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
vdd-supply = <&pm8941_l22>;
vddio-supply = <&pm8941_l12>;
vdda-supply = <&pm8941_l2>;
@@ -169,12 +171,55 @@
compatible = "qcom,mdss-dsi-ctrl";
label = "MDSS DSI CTRL->1";
cell-index = <1>;
- reg = <0xfd922e00 0x600>;
+ reg = <0xfd922e00 0x600>,
+ <0xfdf30000 0x108>;
+ reg-names = "dsi_phys", "mmss_misc_phys";
vdd-supply = <&pm8941_l22>;
vddio-supply = <&pm8941_l12>;
vdda-supply = <&pm8941_l2>;
qcom,mdss-fb-map = <&mdss_fb0>;
qcom,mdss-mdp = <&mdss_mdp>;
+ qcom,platform-strength-ctrl = [ff 06];
+ qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
+ qcom,platform-regulator-settings = [07 09 03 00 20 00 01];
+ qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97
+ 00 00 00 00 05 00 00 01 97
+ 00 00 00 00 0a 00 00 01 97
+ 00 00 00 00 0f 00 00 01 97
+ 00 c0 00 00 00 00 00 01 bb];
+ qcom,platform-supply-entry1 {
+ qcom,supply-name = "vdd";
+ qcom,supply-min-voltage = <3000000>;
+ qcom,supply-max-voltage = <3000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <20>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <0>;
+ };
+ qcom,platform-supply-entry2 {
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <20>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <0>;
+ };
+ qcom,platform-supply-entry3 {
+ qcom,supply-name = "vdda";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-pre-on-sleep = <0>;
+ qcom,supply-post-on-sleep = <0>;
+ qcom,supply-pre-off-sleep = <0>;
+ qcom,supply-post-off-sleep = <0>;
+ };
};
mdss_hdmi_tx: qcom,hdmi_tx@fd922100 {
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 9b9202e..45b716a 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -288,7 +288,7 @@
rpm-regulator-ldoa11 {
status = "okay";
pm8941_l11: regulator-l11 {
- regulator-min-microvolt = <1300000>;
+ regulator-min-microvolt = <1225000>;
regulator-max-microvolt = <1350000>;
qcom,init-voltage = <1300000>;
status = "okay";
@@ -465,6 +465,8 @@
ranges;
qcom,pfm-threshold = <76>;
qcom,use-phase-scaling-factor;
+ qcom,phase-scaling-factor-bits-pos = <16>;
+ qcom,valid-scaling-factor-versions = <0 1 0 0>;
krait0_vreg: regulator@f9088000 {
compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 556e912..6146454 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -149,6 +149,10 @@
qcom,hsusb-otg-pnoc-errata-fix;
};
+&usb3 {
+ qcom,usbin-vadc = <&pm8941_vadc>;
+};
+
&gdsc_venus {
qcom,skip-logic-collapse;
qcom,retain-periph;
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 5607257..7e102fe 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -49,6 +49,10 @@
};
};
+&usb3 {
+ qcom,usbin-vadc = <&pm8941_vadc>;
+};
+
/* GPU overrides */
&msm_gpu {
/* Updated chip ID */
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
index b6a6fcb..5a01945 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,3 +20,8 @@
compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
qcom,board-id = <1 0>;
};
+
+&sdhc_1 {
+ 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-ab-pm8941-fluid-hbtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts
index f4f7968..6ba8b5e 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid-hbtp.dts
@@ -40,3 +40,8 @@
*/
status = "disabled";
};
+
+&sdhc_1 {
+ 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-ab-pm8941-fluid.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
index be298d1..010a4ad 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-fluid.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,3 +20,8 @@
compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
qcom,board-id = <3 0>;
};
+
+&sdhc_1 {
+ 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-ab-pm8941-liquid.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
index 49c3df0..0192f56 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-liquid.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,3 +20,8 @@
compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
qcom,board-id = <9 0>;
};
+
+&sdhc_1 {
+ 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-ab-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index d4bb37b..f80551e 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
@@ -22,5 +22,7 @@
};
&sdhc_1 {
+ 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 */
qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
index 3e0feda..08ef393 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,3 +20,8 @@
compatible = "qcom,msm8974-cdp", "qcom,msm8974", "qcom,cdp";
qcom,board-id = <1 0>;
};
+
+&sdhc_1 {
+ 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-liquid.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
index 7b88abe..8118e48 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-liquid.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -20,3 +20,8 @@
compatible = "qcom,msm8974-liquid", "qcom,msm8974", "qcom,liquid";
qcom,board-id = <9 0>;
};
+
+&sdhc_1 {
+ 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-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
index f79d361..76d0121 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -22,9 +22,6 @@
};
&sdhc_1 {
- 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 cdcfecb..694049a 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,7 +18,3 @@
<213 0x10000>,
<216 0x10000>;
};
-
-&sdhc_1 {
- reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
-};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
index dc438bb..bc7ecd2 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084-pm8941.dtsi
@@ -102,6 +102,7 @@
vbus_dwc3-supply = <&pm8941_mvs1>;
qcom,misc-ref = <&pm8941_misc>;
dwc_usb3-adc_tm = <&pm8941_adc_tm>;
+ qcom,usbin-vadc = <&pm8941_vadc>;
interrupt-map-mask = <0x0 0xffffffff>;
interrupt-map = <0x0 0 &intc 0 133 0
0x0 1 &spmi_bus 0x0 0x2 0x9 0x0>;
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi
index 4b7ed1d..46fae99 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-pma8084.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,7 +18,3 @@
<213 0x10000>,
<216 0x10000>;
};
-
-&sdhc_1 {
- reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
-};
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 34ae372..f735b65 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -242,6 +242,7 @@
<0xff 109>, /* ocmem_dm_nonsec_irq */
<0xff 126>, /* bam_irq[0] */
<0xff 140>, /* uart_dm_intr */
+ <0xff 146>, /* uart_dm_intr: blsp2_uart_2_irq */
<0xff 155>, /* sdcc_irq[0] */
<0xff 157>, /* sdcc_irq[0] */
<0xff 159>, /* sdcc_irq[0] */
@@ -376,4 +377,12 @@
reg = <0xfc000000 0x1a0000>;
qcom,start-offset = <0x190010>;
};
+
+ qcom,rpm-master-stats@fc428150 {
+ compatible = "qcom,rpm-master-stats";
+ reg = <0xfc428150 0x3200>;
+ qcom,masters = "APSS", "MPSS", "LPSS", "PRONTO";
+ qcom,master-stats-version = <2>;
+ qcom,master-offset = <2560>;
+ };
};
diff --git a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
index 8b13c9f..9c2be1a 100644
--- a/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm8941.dtsi
@@ -34,6 +34,8 @@
&krait_pdn {
qcom,use-phase-switching;
+ qcom,valid-scaling-factor-versions = <0 1 1 0>;
+
};
&krait0_vreg {
@@ -64,6 +66,10 @@
qcom,init-smps-mode = <0>; /* Allow AUTO mode for VDD_CX. */
};
+&usb3 {
+ qcom,usbin-vadc = <&pm8941_vadc>;
+};
+
&krait_regulator_pmic {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
old mode 100755
new mode 100644
index 552c559..680674d
--- a/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-mtp.dtsi
@@ -137,9 +137,6 @@
vdd-supply = <&pma8084_l20>;
vdd-io-supply = <&pma8084_s4>;
- 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-pma8084-regulator.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
index 79d7412..49bf4ea 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -267,7 +267,7 @@
rpm-regulator-ldoa11 {
status = "okay";
pma8084_l11: regulator-l11 {
- regulator-min-microvolt = <1300000>;
+ regulator-min-microvolt = <1225000>;
regulator-max-microvolt = <1300000>;
qcom,init-voltage = <1300000>;
status = "okay";
@@ -481,6 +481,8 @@
ranges;
qcom,pfm-threshold = <76>;
qcom,use-phase-scaling-factor;
+ qcom,phase-scaling-factor-bits-pos = <16>;
+ qcom,valid-scaling-factor-versions = <0 1 1 0>;
krait0_vreg: regulator@f9088000 {
compatible = "qcom,krait-regulator";
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
old mode 100755
new mode 100644
index f9cdb6e..a72ebb2
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -1755,3 +1755,10 @@
&gdsc_venus {
qcom,skip-logic-collapse;
};
+
+&sdhc_1 {
+ reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 384000000>;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+};
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index c7abf42..1ba8527 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -412,6 +412,8 @@
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=y
CONFIG_PPP=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index fe84f96..458faac 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -485,3 +485,5 @@
CONFIG_SENSORS_MMA8X5X=y
CONFIG_SENSORS_CAPELLA_CM36283=y
CONFIG_MSM_RDBG=m
+CONFIG_MOBICORE_SUPPORT=m
+CONFIG_MOBICORE_API=m
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index f1c285d..e72e5ff 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -276,6 +276,7 @@
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
CONFIG_TUN=y
@@ -540,8 +541,9 @@
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_XTS=y
CONFIG_NFC_QNCI=y
-CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCRYPTO=y
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 7814288..1a09188 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -893,6 +893,8 @@
hcpu, 1);
break;
case CPU_STARTING:
+ if (cpu_pmu && cpu_pmu->reset)
+ cpu_pmu->reset(NULL);
if (cpu_pmu && cpu_pmu->restore_pm_registers)
smp_call_function_single(cpu,
cpu_pmu->restore_pm_registers,
@@ -927,9 +929,8 @@
enable_irq_callback(&irq);
}
- if (cpu_pmu && cpu_pmu->reset) {
+ if (cpu_pmu) {
__get_cpu_var(from_idle) = 1;
- cpu_pmu->reset(NULL);
pmu = &cpu_pmu->pmu;
pmu->pmu_enable(pmu);
return NOTIFY_OK;
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index bd49b1f..3be4085 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/sched.h>
+#include <linux/bug.h>
#include <linux/atomic.h>
#include <asm/cacheflush.h>
@@ -765,6 +766,7 @@
asmlinkage void __div0(void)
{
printk("Division by zero in kernel.\n");
+ BUG_ON(PANIC_CORRUPTION);
dump_stack();
}
EXPORT_SYMBOL(__div0);
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index f2d65fe..b8444c1 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -339,7 +339,6 @@
select MSM_GPIOMUX
select MULTI_IRQ_HANDLER
select PM_DEVFREQ
- select MSM_DEVFREQ_CPUBW
select MSM_PIL
select MSM_NATIVE_RESTART
select MSM_RESTART_V2
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index fae2378..1c07e7d 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -297,7 +297,7 @@
obj-$(CONFIG_ARCH_MSM8610) += clock-dsi-8610.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += clock-local2.o clock-pll.o clock-krypton.o clock-rpm.o clock-voter.o
-obj-$(CONFIG_MSM_PM) += msm-pm.o pm-data.o ext-buck-support.o
+obj-$(CONFIG_MSM_PM) += msm-pm.o pm-data.o ext-buck-control.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 5882ebc..fe7de31 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <mach/board.h>
@@ -18,6 +19,12 @@
#include <mach/gpiomux.h>
#include <mach/socinfo.h>
+#define WLAN_CLK 44
+#define WLAN_SET 43
+#define WLAN_DATA0 42
+#define WLAN_DATA1 41
+#define WLAN_DATA2 40
+
#ifdef CONFIG_USB_EHCI_MSM_HSIC
static struct gpiomux_setting hsic_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
@@ -140,6 +147,18 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting gpio_i2c_config = {
.func = GPIOMUX_FUNC_3,
.drv = GPIOMUX_DRV_2MA,
@@ -542,6 +561,44 @@
},
};
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+ {
+ .gpio = 40,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 41,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 42,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 43,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 44,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+};
+
static struct gpiomux_setting gpio_suspend_config[] = {
{
.func = GPIOMUX_FUNC_GPIO, /* IN-NP */
@@ -884,3 +941,109 @@
msm_gpiomux_install(msm_hsic_configs, ARRAY_SIZE(msm_hsic_configs));
#endif
}
+
+static void wcnss_switch_to_gpio(void)
+{
+ /* Switch MUX to GPIO */
+ msm_gpiomux_install(wcnss_5gpio_interface,
+ ARRAY_SIZE(wcnss_5gpio_interface));
+
+ /* Ensure GPIO config */
+ gpio_direction_input(WLAN_DATA2);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_output(WLAN_SET, 0);
+ gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+ int count = 0;
+ u32 rf_cmd_and_addr = 0;
+ u32 rf_data_received = 0;
+ u32 rf_bit = 0;
+
+ wcnss_switch_to_gpio();
+
+ /* Reset the signal if it is already being used. */
+ gpio_set_value(WLAN_SET, 0);
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* We start with cmd_set high WLAN_SET = 1. */
+ gpio_set_value(WLAN_SET, 1);
+
+ gpio_direction_output(WLAN_DATA0, 1);
+ gpio_direction_output(WLAN_DATA1, 1);
+ gpio_direction_output(WLAN_DATA2, 1);
+
+ gpio_set_value(WLAN_DATA0, 0);
+ gpio_set_value(WLAN_DATA1, 0);
+ gpio_set_value(WLAN_DATA2, 0);
+
+ /* Prepare command and RF register address that need to sent out.
+ * Make sure that we send only 14 bits from LSB.
+ */
+ rf_cmd_and_addr = (((WLAN_RF_READ_REG_CMD) |
+ (rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+ WLAN_RF_READ_CMD_MASK);
+
+ for (count = 0; count < 5; count++) {
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ /* Send the data out WLAN_CLK = 1 */
+ gpio_set_value(WLAN_CLK, 1);
+ }
+
+ /* Pull down the clock signal */
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* Configure data pins to input IO pins */
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA2);
+
+ for (count = 0; count < 2; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+ }
+
+ rf_bit = 0;
+ for (count = 0; count < 6; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = gpio_get_value(WLAN_DATA0);
+ rf_data_received |= (rf_bit << (count * 3 + 0));
+
+ if (count != 5) {
+ rf_bit = gpio_get_value(WLAN_DATA1);
+ rf_data_received |= (rf_bit << (count * 3 + 1));
+
+ rf_bit = gpio_get_value(WLAN_DATA2);
+ rf_data_received |= (rf_bit << (count * 3 + 2));
+ }
+ }
+
+ gpio_set_value(WLAN_SET, 0);
+ wcnss_switch_to_5wire();
+
+ return rf_data_received;
+}
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 3539ad3..43646cd 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -75,6 +75,11 @@
return MEMTYPE_EBI1;
}
+static struct of_dev_auxdata msm_hsic_host_adata[] = {
+ OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+ {}
+};
+
static struct of_dev_auxdata msm8226_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
"msm_sdcc.1", NULL),
@@ -89,6 +94,8 @@
OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF9864900, \
"msm_sdcc.3", NULL),
OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+ OF_DEV_AUXDATA("qcom,hsic-smsc-hub", 0, "msm_smsc_hub",
+ msm_hsic_host_adata),
{}
};
@@ -160,7 +167,7 @@
NULL
};
-DT_MACHINE_START(MSM8226_DT, "Qualcomm MSM 8226 (Flattened Device Tree)")
+DT_MACHINE_START(MSM8226_DT, "Qualcomm MSM 8x26 / MSM 8x28 (Flattened Device Tree)")
.map_io = msm_map_msm8226_io,
.init_irq = msm_dt_init_irq,
.init_machine = msm8226_init,
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 2e12fc2..4234f2a 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <mach/board.h>
@@ -18,6 +19,12 @@
#include <mach/gpiomux.h>
#include <mach/socinfo.h>
+#define WLAN_CLK 27
+#define WLAN_SET 26
+#define WLAN_DATA0 25
+#define WLAN_DATA1 24
+#define WLAN_DATA2 23
+
static struct gpiomux_setting gpio_spi_config = {
.func = GPIOMUX_FUNC_1,
.drv = GPIOMUX_DRV_6MA,
@@ -112,6 +119,18 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting lcd_en_act_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
@@ -405,6 +424,44 @@
},
};
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+ {
+ .gpio = 23,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 24,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 25,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 26,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 27,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+};
+
static struct gpiomux_setting gpio_suspend_config[] = {
{
.func = GPIOMUX_FUNC_GPIO, /* IN-NP */
@@ -714,3 +771,109 @@
msm_gpiomux_install(msm_cdc_dmic_configs,
ARRAY_SIZE(msm_cdc_dmic_configs));
}
+
+static void wcnss_switch_to_gpio(void)
+{
+ /* Switch MUX to GPIO */
+ msm_gpiomux_install(wcnss_5gpio_interface,
+ ARRAY_SIZE(wcnss_5gpio_interface));
+
+ /* Ensure GPIO config */
+ gpio_direction_input(WLAN_DATA2);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_output(WLAN_SET, 0);
+ gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+ int count = 0;
+ u32 rf_cmd_and_addr = 0;
+ u32 rf_data_received = 0;
+ u32 rf_bit = 0;
+
+ wcnss_switch_to_gpio();
+
+ /* Reset the signal if it is already being used. */
+ gpio_set_value(WLAN_SET, 0);
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* We start with cmd_set high WLAN_SET = 1. */
+ gpio_set_value(WLAN_SET, 1);
+
+ gpio_direction_output(WLAN_DATA0, 1);
+ gpio_direction_output(WLAN_DATA1, 1);
+ gpio_direction_output(WLAN_DATA2, 1);
+
+ gpio_set_value(WLAN_DATA0, 0);
+ gpio_set_value(WLAN_DATA1, 0);
+ gpio_set_value(WLAN_DATA2, 0);
+
+ /* Prepare command and RF register address that need to sent out.
+ * Make sure that we send only 14 bits from LSB.
+ */
+ rf_cmd_and_addr = (((WLAN_RF_READ_REG_CMD) |
+ (rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+ WLAN_RF_READ_CMD_MASK);
+
+ for (count = 0; count < 5; count++) {
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ /* Send the data out WLAN_CLK = 1 */
+ gpio_set_value(WLAN_CLK, 1);
+ }
+
+ /* Pull down the clock signal */
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* Configure data pins to input IO pins */
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA2);
+
+ for (count = 0; count < 2; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+ }
+
+ rf_bit = 0;
+ for (count = 0; count < 6; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = gpio_get_value(WLAN_DATA0);
+ rf_data_received |= (rf_bit << (count * 3 + 0));
+
+ if (count != 5) {
+ rf_bit = gpio_get_value(WLAN_DATA1);
+ rf_data_received |= (rf_bit << (count * 3 + 1));
+
+ rf_bit = gpio_get_value(WLAN_DATA2);
+ rf_data_received |= (rf_bit << (count * 3 + 2));
+ }
+ }
+
+ gpio_set_value(WLAN_SET, 0);
+ wcnss_switch_to_5wire();
+
+ return rf_data_received;
+}
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index d175bb4..cd9b82e 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -136,7 +136,7 @@
NULL
};
-DT_MACHINE_START(MSM8610_DT, "Qualcomm MSM 8610 (Flattened Device Tree)")
+DT_MACHINE_START(MSM8610_DT, "Qualcomm MSM 8x10 / MSM 8x12 (Flattened Device Tree)")
.map_io = msm_map_msm8610_io,
.init_irq = msm_dt_init_irq,
.init_machine = msm8610_init,
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index cec1a8f..5d4d379 100755
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <mach/board.h>
@@ -20,6 +21,12 @@
#define KS8851_IRQ_GPIO 94
+#define WLAN_CLK 40
+#define WLAN_SET 39
+#define WLAN_DATA0 38
+#define WLAN_DATA1 37
+#define WLAN_DATA2 36
+
static struct gpiomux_setting ap2mdm_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -208,6 +215,18 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting wcnss_5gpio_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting wcnss_5gpio_active_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
static struct gpiomux_setting ath_gpio_active_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -1158,6 +1177,43 @@
},
};
+static struct msm_gpiomux_config wcnss_5gpio_interface[] = {
+ {
+ .gpio = 36,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 37,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 38,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 39,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+ {
+ .gpio = 40,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &wcnss_5gpio_active_cfg,
+ [GPIOMUX_SUSPENDED] = &wcnss_5gpio_suspend_cfg,
+ },
+ },
+};
static struct msm_gpiomux_config ath_gpio_configs[] = {
{
@@ -1467,3 +1523,109 @@
msm_gpiomux_install(apq8074_dragonboard_ts_config,
ARRAY_SIZE(apq8074_dragonboard_ts_config));
}
+
+static void wcnss_switch_to_gpio(void)
+{
+ /* Switch MUX to GPIO */
+ msm_gpiomux_install(wcnss_5gpio_interface,
+ ARRAY_SIZE(wcnss_5gpio_interface));
+
+ /* Ensure GPIO config */
+ gpio_direction_input(WLAN_DATA2);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_output(WLAN_SET, 0);
+ gpio_direction_output(WLAN_CLK, 0);
+}
+
+static void wcnss_switch_to_5wire(void)
+{
+ msm_gpiomux_install(wcnss_5wire_interface,
+ ARRAY_SIZE(wcnss_5wire_interface));
+}
+
+u32 wcnss_rf_read_reg(u32 rf_reg_addr)
+{
+ int count = 0;
+ u32 rf_cmd_and_addr = 0;
+ u32 rf_data_received = 0;
+ u32 rf_bit = 0;
+
+ wcnss_switch_to_gpio();
+
+ /* Reset the signal if it is already being used. */
+ gpio_set_value(WLAN_SET, 0);
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* We start with cmd_set high WLAN_SET = 1. */
+ gpio_set_value(WLAN_SET, 1);
+
+ gpio_direction_output(WLAN_DATA0, 1);
+ gpio_direction_output(WLAN_DATA1, 1);
+ gpio_direction_output(WLAN_DATA2, 1);
+
+ gpio_set_value(WLAN_DATA0, 0);
+ gpio_set_value(WLAN_DATA1, 0);
+ gpio_set_value(WLAN_DATA2, 0);
+
+ /* Prepare command and RF register address that need to sent out.
+ * Make sure that we send only 14 bits from LSB.
+ */
+ rf_cmd_and_addr = (((WLAN_RF_READ_REG_CMD) |
+ (rf_reg_addr << WLAN_RF_REG_ADDR_START_OFFSET)) &
+ WLAN_RF_READ_CMD_MASK);
+
+ for (count = 0; count < 5; count++) {
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA0, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA1, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ rf_bit = (rf_cmd_and_addr & 0x1);
+ gpio_set_value(WLAN_DATA2, rf_bit ? 1 : 0);
+ rf_cmd_and_addr = (rf_cmd_and_addr >> 1);
+
+ /* Send the data out WLAN_CLK = 1 */
+ gpio_set_value(WLAN_CLK, 1);
+ }
+
+ /* Pull down the clock signal */
+ gpio_set_value(WLAN_CLK, 0);
+
+ /* Configure data pins to input IO pins */
+ gpio_direction_input(WLAN_DATA0);
+ gpio_direction_input(WLAN_DATA1);
+ gpio_direction_input(WLAN_DATA2);
+
+ for (count = 0; count < 2; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+ }
+
+ rf_bit = 0;
+ for (count = 0; count < 6; count++) {
+ gpio_set_value(WLAN_CLK, 1);
+ gpio_set_value(WLAN_CLK, 0);
+
+ rf_bit = gpio_get_value(WLAN_DATA0);
+ rf_data_received |= (rf_bit << (count * 3 + 0));
+
+ if (count != 5) {
+ rf_bit = gpio_get_value(WLAN_DATA1);
+ rf_data_received |= (rf_bit << (count * 3 + 1));
+
+ rf_bit = gpio_get_value(WLAN_DATA2);
+ rf_data_received |= (rf_bit << (count * 3 + 2));
+ }
+ }
+
+ gpio_set_value(WLAN_SET, 0);
+ wcnss_switch_to_5wire();
+
+ return rf_data_received;
+}
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 798a33d..d1f8666 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -2583,17 +2583,6 @@
},
};
-static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
- .cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[MMSS_BASE],
- .c = {
- .dbg_name = "mmss_mmssnoc_bto_ahb_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
- },
-};
-
static struct branch_clk mmss_mmssnoc_axi_clk = {
.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
.has_sibling = 1,
@@ -2695,7 +2684,6 @@
#ifdef CONFIG_DEBUG_FS
static struct measure_mux_entry measure_mux_MMSS[] = {
- { &mmss_mmssnoc_bto_ahb_clk.c, MMSS_BASE, 0x0002 },
{ &mmss_misc_ahb_clk.c, MMSS_BASE, 0x0003 },
{ &mmss_mmssnoc_axi_clk.c, MMSS_BASE, 0x0004 },
{ &mmss_s0_axi_clk.c, MMSS_BASE, 0x0005 },
@@ -3395,6 +3383,8 @@
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+ "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd900000.qcom,mdss_mdp"),
CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd900000.qcom,mdss_mdp"),
@@ -3581,7 +3571,6 @@
CLK_LOOKUP("cam_gp1_clk", camss_gp1_clk.c, ""),
CLK_LOOKUP("iface_clk", camss_micro_ahb_clk.c, ""),
- CLK_LOOKUP("", mmss_mmssnoc_bto_ahb_clk.c, ""),
CLK_LOOKUP("", mmss_mmssnoc_axi_clk.c, ""),
CLK_LOOKUP("", mmss_s0_axi_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 8bd3bb5..e9c749a 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -2347,17 +2347,6 @@
},
};
-static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
- .cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[MMSS_BASE],
- .c = {
- .dbg_name = "mmss_mmssnoc_bto_ahb_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
- },
-};
-
static struct branch_clk oxili_ahb_clk = {
.cbcr_reg = OXILI_AHB_CBCR,
.bcr_reg = OXILI_AHB_BCR,
@@ -2991,7 +2980,6 @@
CLK_LOOKUP("core_clk", mdp_vsync_clk.c, ""),
CLK_LOOKUP("core_clk", mmss_misc_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", mmss_s0_axi_clk.c, ""),
- CLK_LOOKUP("core_clk", mmss_mmssnoc_bto_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", mmss_mmssnoc_axi_clk.c, ""),
CLK_LOOKUP("core_clk", vfe_clk.c, ""),
CLK_LOOKUP("core_clk", vfe_ahb_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index e8d1627..b42878d 100755
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -1546,7 +1546,7 @@
},
};
-/* This table is for MSM8974Pro AC SDCC1 */
+/* For MSM8974Pro SDCC1 */
static struct clk_freq_tbl ftbl_gcc_sdcc1_apps_clk_ac[] = {
F( 144000, cxo, 16, 3, 25),
F( 400000, cxo, 12, 1, 4),
@@ -1559,11 +1559,7 @@
F_END
};
-/*
- * This table is for:
- * 1) SDCC[1-4] on MSM8974Pro AB, MSM8974 v2 and before
- * 2) SDCC[2-4] on MSM8974Pro AC
- */
+/* For SDCC1 on MSM8974 v2 and SDCC[2-4] on all MSM8974 */
static struct clk_freq_tbl ftbl_gcc_sdcc1_4_apps_clk[] = {
F( 144000, cxo, 16, 3, 25),
F( 400000, cxo, 12, 1, 4),
@@ -4241,17 +4237,6 @@
},
};
-static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
- .cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[MMSS_BASE],
- .c = {
- .dbg_name = "mmss_mmssnoc_bto_ahb_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(mmss_mmssnoc_bto_ahb_clk.c),
- },
-};
-
static struct branch_clk mmss_mmssnoc_axi_clk = {
.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
.has_sibling = 1,
@@ -5091,6 +5076,10 @@
CLK_LOOKUP("pixel_clk", mdss_pclk1_clk.c, "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922800.qcom,mdss_dsi"),
CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922e00.qcom,mdss_dsi"),
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+ "fd922800.qcom,mdss_dsi"),
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c,
+ "fd922e00.qcom,mdss_dsi"),
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("alt_iface_clk", mdss_hdmi_ahb_clk.c,
"fd922100.qcom,hdmi_tx"),
@@ -5790,11 +5779,9 @@
ce2_clk_src.c.fmax[VDD_DIG_NOMINAL] = 150000000;
ce2_clk_src.freq_tbl = ftbl_gcc_ce2_pro_clk;
- if (cpu_is_msm8974pro_ac()) {
- sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOW] = 200000000;
- sdcc1_apps_clk_src.c.fmax[VDD_DIG_NOMINAL] = 400000000;
- sdcc1_apps_clk_src.freq_tbl = ftbl_gcc_sdcc1_apps_clk_ac;
- }
+ sdcc1_apps_clk_src.c.fmax[VDD_DIG_LOW] = 200000000;
+ sdcc1_apps_clk_src.c.fmax[VDD_DIG_NOMINAL] = 400000000;
+ sdcc1_apps_clk_src.freq_tbl = ftbl_gcc_sdcc1_apps_clk_ac;
vfe0_clk_src.c.fmax[VDD_DIG_LOW] = 150000000;
vfe0_clk_src.c.fmax[VDD_DIG_NOMINAL] = 320000000;
diff --git a/arch/arm/mach-msm/clock-a7.c b/arch/arm/mach-msm/clock-a7.c
index d09e4b6..a610a23 100644
--- a/arch/arm/mach-msm/clock-a7.c
+++ b/arch/arm/mach-msm/clock-a7.c
@@ -97,9 +97,7 @@
static int cortex_enable(struct mux_div_clk *md)
{
- u32 src_sel = parent_to_src_sel(md->parents, md->num_parents,
- md->c.parent);
- return cortex_set_config(md, src_sel, md->data.div);
+ return cortex_set_config(md, md->src_sel, md->data.div);
}
static void cortex_disable(struct mux_div_clk *md)
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index c245079..d952f82 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -117,7 +117,6 @@
#define CPR_INT_DEFAULT (CPR_INT_UP | CPR_INT_DOWN)
#define CPR_NUM_RING_OSC 8
-#define CPR_NUM_SAVE_REGS 10
/* RBCPR Clock Control Register */
#define RBCPR_CLK_SEL_MASK BIT(0)
@@ -166,12 +165,12 @@
void __iomem *efuse_base;
/* Process voltage parameters */
- u32 pvs_init_v[CPR_PVS_EFUSE_BINS_MAX];
- u32 pvs_corner_v[NUM_APC_PVS][CPR_FUSE_CORNER_MAX];
+ u32 pvs_corner_v[CPR_FUSE_CORNER_MAX];
/* Process voltage variables */
u32 pvs_bin;
- u32 process;
u32 speed_bin;
+ u32 pvs_version;
+
/* APC voltage regulator */
struct regulator *vdd_apc;
@@ -203,9 +202,6 @@
int *save_ctl;
int *save_irq;
- u32 save_regs[CPR_NUM_SAVE_REGS];
- u32 save_reg_val[CPR_NUM_SAVE_REGS];
-
/* Config parameters */
bool enable;
u32 ref_clk_khz;
@@ -224,6 +220,8 @@
int *corner_map;
u32 num_corners;
int *quot_adjust;
+
+ bool is_cpr_suspended;
};
#define CPR_DEBUG_MASK_IRQ BIT(0)
@@ -348,6 +346,22 @@
u32 val;
int fuse_corner = cpr_vreg->corner_map[corner];
+ if (cpr_vreg->is_cpr_suspended)
+ return;
+
+ /* Program Consecutive Up & Down */
+ val = ((cpr_vreg->timer_cons_down & RBIF_TIMER_ADJ_CONS_DOWN_MASK)
+ << RBIF_TIMER_ADJ_CONS_DOWN_SHIFT) |
+ (cpr_vreg->timer_cons_up & RBIF_TIMER_ADJ_CONS_UP_MASK);
+ cpr_masked_write(cpr_vreg, REG_RBIF_TIMER_ADJUST,
+ RBIF_TIMER_ADJ_CONS_UP_MASK |
+ RBIF_TIMER_ADJ_CONS_DOWN_MASK, val);
+ cpr_masked_write(cpr_vreg, REG_RBCPR_CTL,
+ RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN |
+ RBCPR_CTL_SW_AUTO_CONT_ACK_EN,
+ cpr_vreg->save_ctl[corner]);
+ cpr_irq_set(cpr_vreg, cpr_vreg->save_irq[corner]);
+
if (cpr_is_allowed(cpr_vreg) &&
(cpr_vreg->ceiling_volt[fuse_corner] >
cpr_vreg->floor_volt[fuse_corner]))
@@ -359,31 +373,21 @@
static void cpr_ctl_disable(struct cpr_regulator *cpr_vreg)
{
+ if (cpr_vreg->is_cpr_suspended)
+ return;
+
+ cpr_irq_set(cpr_vreg, 0);
+ cpr_ctl_modify(cpr_vreg, RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN |
+ RBCPR_CTL_SW_AUTO_CONT_ACK_EN, 0);
+ cpr_masked_write(cpr_vreg, REG_RBIF_TIMER_ADJUST,
+ RBIF_TIMER_ADJ_CONS_UP_MASK |
+ RBIF_TIMER_ADJ_CONS_DOWN_MASK, 0);
+ cpr_irq_clr(cpr_vreg);
+ cpr_write(cpr_vreg, REG_RBIF_CONT_ACK_CMD, 1);
+ cpr_write(cpr_vreg, REG_RBIF_CONT_NACK_CMD, 1);
cpr_ctl_modify(cpr_vreg, RBCPR_CTL_LOOP_EN, 0);
}
-static void cpr_regs_save(struct cpr_regulator *cpr_vreg)
-{
- int i, offset;
-
- for (i = 0; i < CPR_NUM_SAVE_REGS; i++) {
- offset = cpr_vreg->save_regs[i];
- cpr_vreg->save_reg_val[i] = cpr_read(cpr_vreg, offset);
- }
-}
-
-static void cpr_regs_restore(struct cpr_regulator *cpr_vreg)
-{
- int i, offset;
- u32 val;
-
- for (i = 0; i < CPR_NUM_SAVE_REGS; i++) {
- offset = cpr_vreg->save_regs[i];
- val = cpr_vreg->save_reg_val[i];
- cpr_write(cpr_vreg, offset, val);
- }
-}
-
static void cpr_corner_save(struct cpr_regulator *cpr_vreg, int corner)
{
cpr_vreg->save_ctl[corner] = cpr_read(cpr_vreg, REG_RBCPR_CTL);
@@ -495,8 +499,7 @@
vdd_mx = cpr_vreg->ceiling_volt[fuse_corner];
break;
case VDD_MX_VMIN_APC_SLOW_CORNER_CEILING:
- vdd_mx = cpr_vreg->pvs_corner_v[APC_PVS_SLOW]
- [CPR_FUSE_CORNER_TURBO];
+ vdd_mx = cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_TURBO];
break;
case VDD_MX_VMIN_MX_VMAX:
vdd_mx = cpr_vreg->vdd_mx_vmax;
@@ -842,8 +845,7 @@
cpr_ctl_disable(cpr_vreg);
new_volt = cpr_vreg->last_volt[corner];
} else {
- new_volt = cpr_vreg->pvs_corner_v
- [cpr_vreg->process][fuse_corner];
+ new_volt = cpr_vreg->pvs_corner_v[fuse_corner];
}
cpr_debug("[corner:%d, fuse_corner:%d] = %d uV\n", corner, fuse_corner,
@@ -892,12 +894,16 @@
{
cpr_debug("suspend\n");
+ mutex_lock(&cpr_vreg->cpr_mutex);
+
cpr_ctl_disable(cpr_vreg);
disable_irq(cpr_vreg->cpr_irq);
cpr_irq_clr(cpr_vreg);
- cpr_regs_save(cpr_vreg);
+ cpr_vreg->is_cpr_suspended = true;
+
+ mutex_unlock(&cpr_vreg->cpr_mutex);
return 0;
}
@@ -906,12 +912,15 @@
{
cpr_debug("resume\n");
- cpr_regs_restore(cpr_vreg);
+ mutex_lock(&cpr_vreg->cpr_mutex);
+
+ cpr_vreg->is_cpr_suspended = false;
cpr_irq_clr(cpr_vreg);
enable_irq(cpr_vreg->cpr_irq);
cpr_ctl_enable(cpr_vreg, cpr_vreg->corner);
+ mutex_unlock(&cpr_vreg->cpr_mutex);
return 0;
}
@@ -1008,21 +1017,6 @@
val |= RBCPR_CTL_SW_AUTO_CONT_ACK_EN;
cpr_write(cpr_vreg, REG_RBCPR_CTL, val);
- /* Registers to save & restore for suspend */
- cpr_vreg->save_regs[0] = REG_RBCPR_TIMER_INTERVAL;
- cpr_vreg->save_regs[1] = REG_RBCPR_STEP_QUOT;
- cpr_vreg->save_regs[2] = REG_RBIF_TIMER_ADJUST;
- cpr_vreg->save_regs[3] = REG_RBIF_LIMIT;
- cpr_vreg->save_regs[4] = REG_RBIF_SW_VLEVEL;
- cpr_vreg->save_regs[5] = REG_RBIF_IRQ_EN(cpr_vreg->irq_line);
- cpr_vreg->save_regs[6] = REG_RBCPR_CTL;
- cpr_vreg->save_regs[7] = REG_RBCPR_GCNT_TARGET
- (cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_SVS]);
- cpr_vreg->save_regs[8] = REG_RBCPR_GCNT_TARGET
- (cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_NORMAL]);
- cpr_vreg->save_regs[9] = REG_RBCPR_GCNT_TARGET
- (cpr_vreg->cpr_fuse_ro_sel[CPR_FUSE_CORNER_TURBO]);
-
cpr_irq_set(cpr_vreg, CPR_INT_DEFAULT);
val = cpr_read(cpr_vreg, REG_RBCPR_VERSION);
@@ -1067,7 +1061,7 @@
{
u32 uplift_voltage;
u32 uplift_max_volt = 0;
- int rc, i;
+ int rc;
rc = of_property_read_u32(of_node,
"qcom,cpr-uplift-voltage", &uplift_voltage);
@@ -1082,11 +1076,9 @@
return rc;
}
- for (i = 0; i < CPR_PVS_EFUSE_BINS_MAX; i++) {
- cpr_vreg->pvs_init_v[i] += uplift_voltage;
- if (cpr_vreg->pvs_init_v[i] > uplift_max_volt)
- cpr_vreg->pvs_init_v[i] = uplift_max_volt;
- }
+ cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO] += uplift_voltage;
+ if (cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO] > uplift_max_volt)
+ cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO] = uplift_max_volt;
return rc;
}
@@ -1096,11 +1088,11 @@
{
struct device_node *of_node = pdev->dev.of_node;
u64 efuse_bits;
- int rc, process;
+ int rc, i, stripe_size;
u32 pvs_fuse[4], pvs_fuse_redun_sel[5];
- u32 init_v;
bool redundant;
size_t pvs_bins;
+ u32 *tmp;
rc = of_property_read_u32_array(of_node, "qcom,pvs-fuse-redun-sel",
pvs_fuse_redun_sel, 5);
@@ -1135,13 +1127,26 @@
pvs_bins = 1 << pvs_fuse[2];
- rc = of_property_read_u32_array(of_node, "qcom,pvs-init-voltage",
- cpr_vreg->pvs_init_v, pvs_bins);
+ stripe_size = CPR_FUSE_CORNER_MAX - 1;
+ tmp = kzalloc(sizeof(u32) * pvs_bins * stripe_size, GFP_KERNEL);
+ if (!tmp) {
+ pr_err("memory alloc failed\n");
+ return -ENOMEM;
+ }
+
+ rc = of_property_read_u32_array(of_node, "qcom,pvs-voltage-table",
+ tmp, pvs_bins * stripe_size);
if (rc < 0) {
- pr_err("pvs-init-voltage missing: rc=%d\n", rc);
+ pr_err("pvs-voltage-table missing: rc=%d\n", rc);
+ kfree(tmp);
return rc;
}
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
+ cpr_vreg->pvs_corner_v[i] = tmp[cpr_vreg->pvs_bin *
+ stripe_size + i - 1];
+ kfree(tmp);
+
if (cpr_vreg->flags & FLAGS_UPLIFT_QUOT_VOLT) {
rc = cpr_voltage_uplift_wa_inc_volt(cpr_vreg, of_node);
if (rc < 0) {
@@ -1150,30 +1155,31 @@
}
}
- init_v = cpr_vreg->pvs_init_v[cpr_vreg->pvs_bin];
- for (process = NUM_APC_PVS - 1; process > APC_PVS_NO; process--) {
- if (init_v <= cpr_vreg->pvs_corner_v
- [process][CPR_FUSE_CORNER_TURBO])
- break;
- }
+ if (cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO] >
+ cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_TURBO])
+ cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_TURBO] =
+ cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO];
- if (process == APC_PVS_NO) {
- process = APC_PVS_SLOW;
- cpr_vreg->pvs_corner_v[process][CPR_FUSE_CORNER_TURBO] = init_v;
- cpr_vreg->ceiling_max = init_v;
- } else if (process == APC_PVS_FAST &&
- init_v < cpr_vreg->pvs_corner_v
- [APC_PVS_FAST][CPR_FUSE_CORNER_SVS]) {
- process = APC_PVS_SLOW;
- }
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_TURBO; i++)
+ if (cpr_vreg->pvs_corner_v[i] > cpr_vreg->ceiling_volt[i])
+ cpr_vreg->pvs_corner_v[i] = cpr_vreg->ceiling_volt[i];
+ else if (cpr_vreg->pvs_corner_v[i] < cpr_vreg->floor_volt[i])
+ cpr_vreg->pvs_corner_v[i] = cpr_vreg->floor_volt[i];
- pr_info("[row:%d] = 0x%llX, n_bits=%d, bin=%d (%d)",
- pvs_fuse[0], efuse_bits, pvs_fuse[2],
- cpr_vreg->pvs_bin, process);
- pr_info("pvs initial turbo voltage_= from %u to %u\n",
- init_v, cpr_vreg->pvs_corner_v[process][CPR_FUSE_CORNER_TURBO]);
+ cpr_vreg->ceiling_max = cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_TURBO];
- cpr_vreg->process = process;
+ pr_info("pvs voltage: [%d %d %d] uV\n",
+ cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_SVS],
+ cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_NORMAL],
+ cpr_vreg->pvs_corner_v[CPR_FUSE_CORNER_TURBO]);
+ pr_info("ceiling voltage: [%d %d %d] uV\n",
+ cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_SVS],
+ cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_NORMAL],
+ cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_TURBO]);
+ pr_info("floor voltage: [%d %d %d] uV\n",
+ cpr_vreg->floor_volt[CPR_FUSE_CORNER_SVS],
+ cpr_vreg->floor_volt[CPR_FUSE_CORNER_NORMAL],
+ cpr_vreg->floor_volt[CPR_FUSE_CORNER_TURBO]);
return 0;
}
@@ -1287,14 +1293,48 @@
return rc;
}
-static int cpr_get_of_corner_mappings(struct cpr_regulator *cpr_vreg,
+static void cpr_parse_pvs_version_fuse(struct cpr_regulator *cpr_vreg,
+ struct device_node *of_node)
+{
+ int rc;
+ u64 fuse_bits;
+ u32 fuse_sel[4];
+
+ rc = of_property_read_u32_array(of_node,
+ "qcom,pvs-version-fuse-sel", fuse_sel, 4);
+ if (!rc) {
+ fuse_bits = cpr_read_efuse_row(cpr_vreg,
+ fuse_sel[0], fuse_sel[3]);
+ cpr_vreg->pvs_version = (fuse_bits >> fuse_sel[1]) &
+ ((1 << fuse_sel[2]) - 1);
+ pr_info("[row: %d]: 0x%llx, pvs_version = %d\n",
+ fuse_sel[0], fuse_bits, cpr_vreg->pvs_version);
+ } else {
+ cpr_vreg->pvs_version = UINT_MAX;
+ }
+}
+
+/*
+ * cpr_get_corner_quot_adjustment() -- get the quot_adjust for each corner.
+ *
+ * Get the corner to fuse corner (SVS/NORMAL/TURBO) mappings and corner to
+ * APC clock frequency mappings from device tree.
+ * Calculate the quotient adjustment scaling factor for those corners mapping
+ * to the TURBO fuse corner.
+ * Calculate the quotient adjustment for each corner which map to the TURBO
+ * fuse corner.
+ */
+static int cpr_get_corner_quot_adjustment(struct cpr_regulator *cpr_vreg,
struct device *dev)
{
int rc = 0;
- int i, size, stripe_size;
+ int i, size;
struct property *prop;
- u32 *tmp;
bool corners_mapped;
+ u32 *tmp, *freq_mappings = NULL;
+ u32 scaling, max_factor;
+ u32 corner, turbo_corner = 0, normal_corner = 0, svs_corner = 0;
+ u32 freq_turbo, freq_normal, freq_corner;
prop = of_find_property(dev->of_node, "qcom,cpr-corner-map", NULL);
@@ -1309,81 +1349,182 @@
cpr_vreg->corner_map = devm_kzalloc(dev, sizeof(int) * (size + 1),
GFP_KERNEL);
if (!cpr_vreg->corner_map) {
- pr_err("Can't allocate cpr_vreg->corner_map memory\n");
+ pr_err("Can't allocate memory for cpr_vreg->corner_map\n");
return -ENOMEM;
}
cpr_vreg->num_corners = size;
+ cpr_vreg->quot_adjust = devm_kzalloc(dev,
+ sizeof(u32) * (cpr_vreg->num_corners + 1),
+ GFP_KERNEL);
+ if (!cpr_vreg->quot_adjust) {
+ pr_err("Can't allocate memory for cpr_vreg->quot_adjust\n");
+ return -ENOMEM;
+ }
+
if (!corners_mapped) {
for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
cpr_vreg->corner_map[i] = i;
+ return 0;
} else {
rc = of_property_read_u32_array(dev->of_node,
"qcom,cpr-corner-map", &cpr_vreg->corner_map[1], size);
if (rc) {
- pr_err("qcom,cpr-corner-map missing, rc = %d", rc);
+ pr_err("qcom,cpr-corner-map missing, rc = %d\n", rc);
return rc;
}
}
- cpr_vreg->quot_adjust = devm_kzalloc(dev,
- sizeof(int) * (cpr_vreg->num_corners + 1),
- GFP_KERNEL);
- if (!cpr_vreg->quot_adjust) {
- pr_err("Can't allocate cpr_vreg->quot_adjust memory\n");
+ prop = of_find_property(dev->of_node,
+ "qcom,cpr-speed-bin-max-corners", NULL);
+ if (!prop) {
+ cpr_debug("qcom,cpr-speed-bin-max-corner missing\n");
+ return 0;
+ }
+
+ size = prop->length / sizeof(u32);
+ tmp = kzalloc(size * sizeof(u32), GFP_KERNEL);
+ if (!tmp) {
+ pr_err("memory alloc failed\n");
return -ENOMEM;
}
-
- prop = of_find_property(dev->of_node, "qcom,cpr-quot-adjust-table",
- NULL);
-
- if (prop) {
- if (!corners_mapped) {
- pr_err("qcom,cpr-corner-map missing\n");
- return -EINVAL;
- }
-
- size = prop->length / sizeof(u32);
- tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- rc = of_property_read_u32_array(dev->of_node,
- "qcom,cpr-quot-adjust-table", tmp, size);
- if (rc) {
- pr_err("qcom,cpr-quot-adjust-table missing, rc = %d",
- rc);
- kfree(tmp);
- return rc;
- }
-
- stripe_size = sizeof(struct quot_adjust_info) / sizeof(int);
-
- if ((size % stripe_size) != 0) {
- pr_err("qcom,cpr-quot-adjust-table data is not correct");
- kfree(tmp);
- return -EINVAL;
- }
-
- for (i = 0; i < size; i += stripe_size) {
- if (tmp[i] == cpr_vreg->speed_bin) {
- if (tmp[i + 1] >= 1 &&
- tmp[i + 1] <=
- cpr_vreg->num_corners) {
- cpr_vreg->quot_adjust[tmp[i + 1]] =
- tmp[i + 2];
- } else {
- pr_err("qcom,cpr-quot-adjust-table data is not correct");
- kfree(tmp);
- return -EINVAL;
- }
- }
- }
-
+ rc = of_property_read_u32_array(dev->of_node,
+ "qcom,cpr-speed-bin-max-corners", tmp, size);
+ if (rc < 0) {
kfree(tmp);
+ pr_err("get cpr-speed-bin-max-corners failed, rc = %d\n", rc);
+ return rc;
}
+ cpr_parse_pvs_version_fuse(cpr_vreg, dev->of_node);
+
+ /*
+ * According to speed_bin && pvs_version, get the maximum
+ * corner corresponding to SVS/NORMAL/TURBO fuse corner.
+ */
+ for (i = 0; i < size; i += 5) {
+ if (tmp[i] == cpr_vreg->speed_bin &&
+ tmp[i + 1] == cpr_vreg->pvs_version) {
+ svs_corner = tmp[i + 2];
+ normal_corner = tmp[i + 3];
+ turbo_corner = tmp[i + 4];
+ break;
+ }
+ }
+ kfree(tmp);
+ /*
+ * Return success if the virtual corner values read from
+ * qcom,cpr-speed-bin-max-corners property are incorrect,
+ * which make sure the driver could continue run without
+ * error.
+ */
+ if (turbo_corner <= normal_corner ||
+ turbo_corner > cpr_vreg->num_corners) {
+ cpr_debug("turbo:%d should be larger than normal:%d\n",
+ turbo_corner, normal_corner);
+ return 0;
+ }
+
+ prop = of_find_property(dev->of_node,
+ "qcom,cpr-corner-frequency-map", NULL);
+ if (!prop) {
+ cpr_debug("qcom,cpr-corner-frequency-map missing\n");
+ return 0;
+ }
+
+ size = prop->length / sizeof(u32);
+ tmp = kzalloc(sizeof(u32) * size, GFP_KERNEL);
+ if (!tmp) {
+ pr_err("memory alloc failed\n");
+ return -ENOMEM;
+ }
+ rc = of_property_read_u32_array(dev->of_node,
+ "qcom,cpr-corner-frequency-map", tmp, size);
+ if (rc < 0) {
+ pr_err("get cpr-corner-frequency-map failed, rc = %d\n", rc);
+ kfree(tmp);
+ return rc;
+ }
+ freq_mappings = kzalloc(sizeof(u32) * (cpr_vreg->num_corners + 1),
+ GFP_KERNEL);
+ if (!freq_mappings) {
+ pr_err("memory alloc for freq_mappings failed!\n");
+ kfree(tmp);
+ return -ENOMEM;
+ }
+ for (i = 0; i < size; i += 2) {
+ corner = tmp[i];
+ if ((corner < 1) || (corner > cpr_vreg->num_corners)) {
+ pr_err("corner should be in 1~%d range: %d\n",
+ cpr_vreg->num_corners, corner);
+ continue;
+ }
+ freq_mappings[corner] = tmp[i + 1];
+ cpr_debug("Frequency at virtual corner %d is %d Hz.\n",
+ corner, freq_mappings[corner]);
+ }
+ kfree(tmp);
+
+ rc = of_property_read_u32(dev->of_node,
+ "qcom,cpr-quot-adjust-scaling-factor-max",
+ &max_factor);
+ if (rc < 0) {
+ cpr_debug("get cpr-quot-adjust-scaling-factor-max failed\n");
+ kfree(freq_mappings);
+ return 0;
+ }
+
+ /*
+ * Get the quot adjust scaling factor, according to:
+ * scaling =
+ * min(1000 * (QUOT(fused @turbo) - QUOT(fused @normal)) /
+ * (freq_turbo - freq_normal), max_factor)
+ *
+ * @QUOT(fused @turbo): quotient read from fuse for TURBO fuse corner;
+ * @QUOT(fused @normal): quotient read from fuse for NORMAL fuse corner;
+ * @freq_turbo: MHz, max frequency running at TURBO fuse corner;
+ * @freq_normal: MHz, max frequency running at NORMAL fuse corner.
+ */
+
+ freq_turbo = freq_mappings[turbo_corner];
+ freq_normal = freq_mappings[normal_corner];
+ if (freq_normal == 0 || freq_turbo <= freq_normal) {
+ pr_err("freq_turbo: %d should larger than freq_normal: %d\n",
+ freq_turbo, freq_normal);
+ kfree(freq_mappings);
+ return -EINVAL;
+ }
+ freq_turbo /= 1000000; /* MHz */
+ freq_normal /= 1000000;
+ scaling = 1000 *
+ (cpr_vreg->cpr_fuse_target_quot[CPR_FUSE_CORNER_TURBO] -
+ cpr_vreg->cpr_fuse_target_quot[CPR_FUSE_CORNER_NORMAL]) /
+ (freq_turbo - freq_normal);
+ scaling = min(scaling, max_factor);
+ pr_info("quotient adjustment scaling factor: %d.%03d\n",
+ scaling / 1000, scaling % 1000);
+
+ /*
+ * Walk through the corners mapped to the TURBO fuse corner and
+ * calculate the quotient adjustment for each one using the following
+ * formula:
+ * quot_adjust = (freq_turbo - freq_corner) * scaling / 1000
+ *
+ * @freq_turbo: MHz, max frequency running at TURBO fuse corner;
+ * @freq_corner: MHz, frequency running at a corner.
+ */
+ for (i = turbo_corner; i > normal_corner; i--) {
+ freq_corner = freq_mappings[i] / 1000000; /* MHz */
+ if (freq_corner > 0) {
+ cpr_vreg->quot_adjust[i] =
+ scaling * (freq_turbo - freq_corner) / 1000;
+ }
+ pr_info("adjusted quotient[%d] = %d\n", i,
+ (cpr_vreg->cpr_fuse_target_quot[cpr_vreg->corner_map[i]]
+ - cpr_vreg->quot_adjust[i]));
+ }
+ kfree(freq_mappings);
return 0;
}
@@ -1527,7 +1668,7 @@
}
}
- rc = cpr_get_of_corner_mappings(cpr_vreg, &pdev->dev);
+ rc = cpr_get_corner_quot_adjustment(cpr_vreg, &pdev->dev);
if (rc)
return rc;
@@ -1571,17 +1712,9 @@
if (!cpr_vreg->last_volt)
return -EINVAL;
- /* Construct CPR voltage limits */
- for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++) {
- cpr_vreg->floor_volt[i] =
- cpr_vreg->pvs_corner_v[APC_PVS_FAST][i];
- cpr_vreg->ceiling_volt[i] =
- cpr_vreg->pvs_corner_v[APC_PVS_SLOW][i];
- }
-
for (i = 1; i < size; i++) {
cpr_vreg->last_volt[i] = cpr_vreg->pvs_corner_v
- [cpr_vreg->process][cpr_vreg->corner_map[i]];
+ [cpr_vreg->corner_map[i]];
}
return 0;
@@ -1728,12 +1861,12 @@
cpr_vreg->efuse_addr = res->start;
len = res->end - res->start + 1;
- pr_info("efuse_addr = 0x%x (len=0x%x)\n", res->start, len);
+ pr_info("efuse_addr = %pa (len=0x%x)\n", &res->start, len);
cpr_vreg->efuse_base = ioremap(cpr_vreg->efuse_addr, len);
if (!cpr_vreg->efuse_base) {
- pr_err("Unable to map efuse_addr 0x%08x\n",
- cpr_vreg->efuse_addr);
+ pr_err("Unable to map efuse_addr %pa\n",
+ &cpr_vreg->efuse_addr);
return -EINVAL;
}
@@ -1818,33 +1951,22 @@
struct cpr_regulator *cpr_vreg)
{
struct device_node *of_node = pdev->dev.of_node;
- int rc, i, j;
+ int rc, i;
u32 min_uv = 0;
- rc = of_property_read_u32_array(of_node,
- "qcom,pvs-corner-ceiling-slow",
- &cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_FUSE_CORNER_SVS],
- CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
+ rc = of_property_read_u32_array(of_node, "qcom,cpr-voltage-ceiling",
+ &cpr_vreg->ceiling_volt[CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - 1);
if (rc < 0) {
- pr_err("pvs-corner-ceiling-slow missing: rc=%d\n", rc);
+ pr_err("cpr-voltage-ceiling missing: rc=%d\n", rc);
return rc;
}
- rc = of_property_read_u32_array(of_node,
- "qcom,pvs-corner-ceiling-nom",
- &cpr_vreg->pvs_corner_v[APC_PVS_NOM][CPR_FUSE_CORNER_SVS],
- CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
+ rc = of_property_read_u32_array(of_node, "qcom,cpr-voltage-floor",
+ &cpr_vreg->floor_volt[CPR_FUSE_CORNER_SVS],
+ CPR_FUSE_CORNER_MAX - 1);
if (rc < 0) {
- pr_err("pvs-corner-ceiling-norm missing: rc=%d\n", rc);
- return rc;
- }
-
- rc = of_property_read_u32_array(of_node,
- "qcom,pvs-corner-ceiling-fast",
- &cpr_vreg->pvs_corner_v[APC_PVS_FAST][CPR_FUSE_CORNER_SVS],
- CPR_FUSE_CORNER_MAX - CPR_FUSE_CORNER_SVS);
- if (rc < 0) {
- pr_err("pvs-corner-ceiling-fast missing: rc=%d\n", rc);
+ pr_err("cpr-voltage-floor missing: rc=%d\n", rc);
return rc;
}
@@ -1858,22 +1980,13 @@
if (cpr_vreg->flags & FLAGS_SET_MIN_VOLTAGE) {
of_property_read_u32(of_node, "qcom,cpr-cond-min-voltage",
&min_uv);
- for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++)
- for (j = CPR_FUSE_CORNER_SVS; j < CPR_FUSE_CORNER_MAX;
- j++)
- if (cpr_vreg->pvs_corner_v[i][j] < min_uv)
- cpr_vreg->pvs_corner_v[i][j] = min_uv;
- }
-
- /* Set ceiling max and use it for APC_PVS_NO */
- cpr_vreg->ceiling_max =
- cpr_vreg->pvs_corner_v[APC_PVS_SLOW][CPR_FUSE_CORNER_TURBO];
-
- for (i = APC_PVS_SLOW; i < NUM_APC_PVS; i++) {
- pr_info("[%d] [%d %d %d] uV\n", i,
- cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_SVS],
- cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_NORMAL],
- cpr_vreg->pvs_corner_v[i][CPR_FUSE_CORNER_TURBO]);
+ for (i = CPR_FUSE_CORNER_SVS; i < CPR_FUSE_CORNER_MAX; i++)
+ if (cpr_vreg->ceiling_volt[i] < min_uv) {
+ cpr_vreg->ceiling_volt[i] = min_uv;
+ cpr_vreg->floor_volt[i] = min_uv;
+ } else if (cpr_vreg->floor_volt[i] < min_uv) {
+ cpr_vreg->floor_volt[i] = min_uv;
+ }
}
return 0;
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index f1904de..c81720e 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -228,6 +228,9 @@
static unsigned int msm_cpufreq_get_freq(unsigned int cpu)
{
+ if (is_clk && is_sync)
+ cpu = 0;
+
if (is_clk)
return clk_get_rate(cpu_clk[cpu]) / 1000;
diff --git a/arch/arm/mach-msm/dfe-fsm9xxx.c b/arch/arm/mach-msm/dfe-fsm9xxx.c
index 66272d2..3470710 100644
--- a/arch/arm/mach-msm/dfe-fsm9xxx.c
+++ b/arch/arm/mach-msm/dfe-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -50,6 +50,8 @@
HH_IRQ_FIFO_SIZE) == \
(pdev)->irq_fifo_head)
+#define UINT32_MAX (0xFFFFFFFFU)
+
static struct hh_dev_node_info {
spinlock_t hh_lock;
char irq_fifo[HH_IRQ_FIFO_SIZE];
@@ -220,8 +222,9 @@
return -EFAULT;
if (!HH_OFFSET_VALID(param.offset))
return -EINVAL;
- if (param.num == 0)
- break;
+ if ((param.num == 0) ||
+ (param.num >= (UINT32_MAX / sizeof(unsigned int))))
+ return -EINVAL;
req_sz = sizeof(unsigned int) * param.num;
if (pdfi->array_num < param.num) {
@@ -270,8 +273,10 @@
if (copy_from_user(¶m, argp, sizeof param))
return -EFAULT;
- if (param.num == 0)
- break;
+ if ((param.num == 0) ||
+ (param.num >= (UINT32_MAX /
+ sizeof(struct dfe_command_entry))))
+ return -EINVAL;
req_sz = sizeof(struct dfe_command_entry) * param.num;
if (pdfi->cmd_num < param.num) {
diff --git a/arch/arm/mach-msm/ext-buck-support.c b/arch/arm/mach-msm/ext-buck-control.c
similarity index 88%
rename from arch/arm/mach-msm/ext-buck-support.c
rename to arch/arm/mach-msm/ext-buck-control.c
index 11f9e31..e0c349a 100644
--- a/arch/arm/mach-msm/ext-buck-support.c
+++ b/arch/arm/mach-msm/ext-buck-control.c
@@ -75,38 +75,40 @@
{
char *key = NULL;
int gpio_num;
- int settling_time;
+ int settling_time_us;
int ret = 0;
key = "qcom,gpio-num";
ret = of_property_read_u32(pdev->dev.of_node, key, &gpio_num);
if (ret) {
- pr_debug("%s: Cannot read %s from dt", __func__, key);
+ pr_err("%s: Cannot read %s from dt (ret:%d)\n",
+ __func__, key, ret);
return ret;
}
- key = "qcom,settling-time";
+ key = "qcom,settling-time-us";
ret = of_property_read_u32(pdev->dev.of_node, key,
- &settling_time);
+ &settling_time_us);
if (ret) {
- pr_debug("%s: Cannot read %s from dt", __func__, key);
+ pr_err("%s: Cannot read %s from dt (ret:%d)\n",
+ __func__, key, ret);
return ret;
}
- ret = msm_send_ext_buck_votes(gpio_num, settling_time);
+ ret = msm_send_ext_buck_votes(gpio_num, settling_time_us);
return ret;
}
static struct of_device_id msm_ext_buck_table[] = {
- {.compatible = "qcom,ext-buck-support"},
+ {.compatible = "qcom,ext-buck-control"},
{},
};
static struct platform_driver msm_ext_buck_driver = {
.probe = msm_ext_buck_probe,
.driver = {
- .name = "ext-buck-support",
+ .name = "ext-buck-control",
.owner = THIS_MODULE,
.of_match_table = msm_ext_buck_table,
},
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 89e3b51..c7f8b74 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -27,6 +27,12 @@
#include <linux/msm_ssbi.h>
#include <mach/msm_bus.h>
+#define WLAN_RF_REG_ADDR_START_OFFSET 0x3
+#define WLAN_RF_REG_DATA_START_OFFSET 0xf
+#define WLAN_RF_READ_REG_CMD 0x3
+#define WLAN_RF_WRITE_REG_CMD 0x2
+#define WLAN_RF_READ_CMD_MASK 0x3fff
+
struct msm_camera_io_ext {
uint32_t mdcphy;
uint32_t mdcsz;
@@ -677,4 +683,5 @@
extern phys_addr_t msm_shared_ram_phys; /* defined in arch/arm/mach-msm/io.c */
+u32 wcnss_rf_read_reg(u32 rf_reg_addr);
#endif
diff --git a/arch/arm/mach-msm/include/mach/camera2.h b/arch/arm/mach-msm/include/mach/camera2.h
index 0ce5213..7024045 100644
--- a/arch/arm/mach-msm/include/mach/camera2.h
+++ b/arch/arm/mach-msm/include/mach/camera2.h
@@ -119,11 +119,16 @@
uint32_t delay;
};
+struct eeprom_slave_add_t {
+ uint32_t addr;
+};
+
struct msm_eeprom_memory_map_t {
struct eeprom_map_t page;
struct eeprom_map_t pageen;
struct eeprom_map_t poll;
struct eeprom_map_t mem;
+ struct eeprom_slave_add_t saddr;
};
struct msm_eeprom_memory_block_t {
diff --git a/arch/arm/mach-msm/include/mach/kgsl.h b/arch/arm/mach-msm/include/mach/kgsl.h
index f398652..edfe6b4 100644
--- a/arch/arm/mach-msm/include/mach/kgsl.h
+++ b/arch/arm/mach-msm/include/mach/kgsl.h
@@ -91,6 +91,7 @@
struct coresight_device *csdev;
struct coresight_platform_data *coresight_pdata;
unsigned int chipid;
+ unsigned int pm_qos_latency;
};
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h b/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
index 1641e8c..4bcb0e7 100644
--- a/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
+++ b/arch/arm/mach-msm/include/mach/msm_qmi_interface.h
@@ -172,37 +172,44 @@
* qmi_connect_to_service() - Connect the QMI handle with a QMI service
* @handle: QMI handle to be connected with the QMI service.
* @service_id: Service id to identify the QMI service.
- * @instance_id: Instance id to identify the instance of the QMI service.
+ * @service_vers: Version to identify the compatibility.
+ * @service_ins: Instance id to identify the instance of the QMI service.
*
* @return: 0 on success, < 0 on error.
*/
int qmi_connect_to_service(struct qmi_handle *handle,
- uint32_t service_id, uint32_t instance_id);
+ uint32_t service_id,
+ uint32_t service_vers,
+ uint32_t service_ins);
/**
* qmi_svc_event_notifier_register() - Register a notifier block to receive
* events regarding a QMI service
* @service_id: Service ID to identify the QMI service.
- * @instance_id: Instance ID to identify the instance of the QMI service.
+ * @service_vers: Version to identify the compatibility.
+ * @service_ins: Instance ID to identify the instance of the QMI service.
* @nb: Notifier block used to receive the event.
*
* @return: 0 if successfully registered, < 0 on error.
*/
int qmi_svc_event_notifier_register(uint32_t service_id,
- uint32_t instance_id,
+ uint32_t service_vers,
+ uint32_t service_ins,
struct notifier_block *nb);
/**
* qmi_svc_event_notifier_unregister() - Unregister service event
* notifier block
* @service_id: Service ID to identify the QMI service.
- * @instance_id: Instance ID to identify the instance of the QMI service.
+ * @service_vers: Version to identify the compatibility.
+ * @service_ins: Instance ID to identify the instance of the QMI service.
* @nb: Notifier block registered to receive the events.
*
* @return: 0 if successfully registered, < 0 on error.
*/
int qmi_svc_event_notifier_unregister(uint32_t service_id,
- uint32_t instance_id,
+ uint32_t service_vers,
+ uint32_t service_ins,
struct notifier_block *nb);
#else
@@ -260,20 +267,23 @@
static inline int qmi_connect_to_service(struct qmi_handle *handle,
uint32_t service_id,
- uint32_t instance_id)
+ uint32_t service_vers,
+ uint32_t service_ins)
{
return -ENODEV;
}
static inline int qmi_svc_event_notifier_register(uint32_t service_id,
- uint32_t instance_id,
+ uint32_t service_vers,
+ uint32_t service_ins,
struct notifier_block *nb)
{
return -ENODEV;
}
static inline int qmi_svc_event_notifier_unregister(uint32_t service_id,
- uint32_t instance_id,
+ uint32_t service_vers,
+ uint32_t service_ins,
struct notifier_block *nb)
{
return -ENODEV;
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index 32d58d4..00aedb6 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -226,7 +226,6 @@
int process_dump(int, struct ocmem_handle *, unsigned long);
int ocmem_rdm_transfer(int, struct ocmem_map_list *,
unsigned long, int);
-int ocmem_clear(unsigned long, unsigned long);
unsigned long process_quota(int);
int ocmem_memory_off(int, unsigned long, unsigned long);
int ocmem_memory_on(int, unsigned long, unsigned long);
diff --git a/arch/arm/mach-msm/include/mach/usbdiag.h b/arch/arm/mach-msm/include/mach/usbdiag.h
index 15f4783..7457993 100644
--- a/arch/arm/mach-msm/include/mach/usbdiag.h
+++ b/arch/arm/mach-msm/include/mach/usbdiag.h
@@ -1,6 +1,6 @@
/* include/asm-arm/arch-msm/usbdiag.h
*
- * Copyright (c) 2008-2010, 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2010, 2012-2013,The Linux Foundation. All rights reserved.
*
* All source code in this file is licensed under the following license except
* where indicated.
@@ -54,7 +54,6 @@
void (*notify)(void *, unsigned, struct diag_request *));
void usb_diag_close(struct usb_diag_ch *ch);
int usb_diag_alloc_req(struct usb_diag_ch *ch, int n_write, int n_read);
-void usb_diag_free_req(struct usb_diag_ch *ch);
int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req);
int usb_diag_write(struct usb_diag_ch *ch, struct diag_request *d_req);
#else
@@ -71,9 +70,6 @@
{
return -ENODEV;
}
-static inline void usb_diag_free_req(struct usb_diag_ch *ch)
-{
-}
static inline
int usb_diag_read(struct usb_diag_ch *ch, struct diag_request *d_req)
{
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index f4456c0..a291b90 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -1443,11 +1443,17 @@
{
struct resource *res;
void __iomem *efuse;
- u32 efuse_data, efuse_version;
- bool scaling_factor_valid, use_efuse;
+ u32 efuse_data, efuse_version, efuse_version_data;
+ bool sf_valid, use_efuse;
+ int sf_pos, sf_mask;
+ struct device_node *node = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ int valid_sfs[4] = {0, 0, 0, 0};
+ int sf_versions_len;
+ int rc;
- use_efuse = of_property_read_bool(pdev->dev.of_node,
- "qcom,use-phase-scaling-factor");
+ use_efuse = of_property_read_bool(node,
+ "qcom,use-phase-scaling-factor");
/*
* Allow usage of the eFuse phase scaling factor if it is enabled in
* either device tree or by module parameter.
@@ -1462,6 +1468,7 @@
return -EINVAL;
}
+ /* Read efuse registers */
efuse = ioremap(res->start, 8);
if (!efuse) {
pr_err("could not map phase scaling eFuse address\n");
@@ -1469,25 +1476,47 @@
}
efuse_data = readl_relaxed(efuse);
- efuse_version = readl_relaxed(efuse + 4);
-
+ efuse_version_data = readl_relaxed(efuse + 4);
iounmap(efuse);
- scaling_factor_valid
- = ((efuse_version & PHASE_SCALING_EFUSE_VERSION_MASK) >>
- PHASE_SCALING_EFUSE_VERSION_POS)
- == PHASE_SCALING_EFUSE_VERSION_SET;
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,phase-scaling-factor-bits-pos",
+ &sf_pos);
+ if (rc < 0) {
+ dev_err(dev, "qcom,phase-scaling-factor-bits-pos missing rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
- if (scaling_factor_valid)
+ sf_mask = KRAIT_MASK(sf_pos + 2, sf_pos);
+
+ efuse_version
+ = ((efuse_version_data & PHASE_SCALING_EFUSE_VERSION_MASK) >>
+ PHASE_SCALING_EFUSE_VERSION_POS);
+
+ if (of_find_property(node, "qcom,valid-scaling-factor-versions",
+ &sf_versions_len)
+ && (sf_versions_len == 4 * sizeof(u32))) {
+ rc = of_property_read_u32_array(node,
+ "qcom,valid-scaling-factor-versions",
+ valid_sfs, 4);
+ sf_valid = (valid_sfs[efuse_version] == 1);
+ } else {
+ dev_err(dev, "qcom,valid-scaling-factor-versions missing or its size is incorrect rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ if (sf_valid)
pvreg->efuse_phase_scaling_factor
- = ((efuse_data & PHASE_SCALING_EFUSE_VALUE_MASK)
- >> PHASE_SCALING_EFUSE_VALUE_POS) + 1;
+ = ((efuse_data & sf_mask)
+ >> sf_pos) + 1;
else
pvreg->efuse_phase_scaling_factor = PHASE_SCALING_REF;
pr_info("eFuse phase scaling factor = %d/%d%s\n",
pvreg->efuse_phase_scaling_factor, PHASE_SCALING_REF,
- scaling_factor_valid ? "" : " (eFuse not blown)");
+ sf_valid ? "" : " (eFuse not blown)");
pr_info("initial phase scaling factor = %d/%d%s\n",
use_efuse_phase_scaling_factor
? pvreg->efuse_phase_scaling_factor : PHASE_SCALING_REF,
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 2370bec..7128017 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -754,7 +754,7 @@
do_div(time, 1000);
dev->last_residency = (int)time;
local_irq_enable();
- return index;
+ return idx;
}
static int lpm_suspend_enter(suspend_state_t state)
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index 5b351b4..1fbd077 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, 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
@@ -32,6 +32,7 @@
#include <linux/power_supply.h>
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
+#include <linux/mutex.h>
#include <asm/hardware/gic.h>
#include <asm/arch_timer.h>
#include <mach/gpio.h>
@@ -567,6 +568,9 @@
}
static void msm_mpm_sys_low_power_modes(bool allow)
{
+ static DEFINE_MUTEX(enable_xo_mutex);
+
+ mutex_lock(&enable_xo_mutex);
if (allow) {
if (xo_enabled) {
clk_disable_unprepare(xo_clk);
@@ -582,6 +586,7 @@
xo_enabled = true;
}
}
+ mutex_unlock(&enable_xo_mutex);
}
void msm_mpm_suspend_prepare(void)
diff --git a/arch/arm/mach-msm/msm-pm.c b/arch/arm/mach-msm/msm-pm.c
index 865cd0a..f9a9343 100644
--- a/arch/arm/mach-msm/msm-pm.c
+++ b/arch/arm/mach-msm/msm-pm.c
@@ -39,6 +39,7 @@
#include "scm-boot.h"
#include "spm.h"
#include "pm-boot.h"
+#include "clock.h"
#define CREATE_TRACE_POINTS
#include <mach/trace_msm_low_power.h>
@@ -452,8 +453,8 @@
if (!msm_pc_debug_counters)
return;
- cnt = readl_relaxed(msm_pc_debug_counters + cpu * 4 + offset * 4);
- writel_relaxed(++cnt, msm_pc_debug_counters + cpu * 4 + offset * 4);
+ cnt = readl_relaxed(msm_pc_debug_counters + cpu * 4 * MSM_PC_NUM_COUNTERS + offset * 4);
+ writel_relaxed(++cnt, msm_pc_debug_counters + cpu * 4 * MSM_PC_NUM_COUNTERS + offset * 4);
mb();
}
@@ -641,6 +642,14 @@
if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
+ /* This spews a lot of messages when a core is hotplugged. This
+ * information is most useful from last core going down during
+ * power collapse
+ */
+ if ((!from_idle && cpu_online(cpu))
+ || (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask))
+ clock_debug_print_enabled();
+
avsdscr = avs_get_avsdscr();
avscsr = avs_get_avscsr();
avs_set_avscsr(0); /* Disable AVS */
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index a76c29b..5747f79 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1932,13 +1932,9 @@
ports = hop->node_info->num_sports;
MSM_BUS_DBG("BIMC: ID: %d, Sports: %d\n", hop->node_info->priv_id,
ports);
- if (ports)
- bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
- else
- return;
for (i = 0; i < ports; i++) {
- sel_cd->slv[hop->node_info->slavep[i]].bw += bw;
+ sel_cd->slv[hop->node_info->slavep[i]].bw += add_bw;
sel_cd->slv[hop->node_info->slavep[i]].hw_id =
hop->node_info->slv_hw_id;
MSM_BUS_DBG("BIMC: Update slave_bw: ID: %d -> %llu\n",
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 626c5e8..0ffc194 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -364,7 +364,7 @@
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
void *sel_cdata;
- long rounded_rate;
+ long rounded_rate, cur_rate;
sel_cdata = fabric->cdata[ctx];
@@ -379,16 +379,20 @@
}
/* Enable clocks before accessing QoS registers */
- if (fabric->info.nodeclk[DUAL_CTX].clk)
+ if (fabric->info.nodeclk[DUAL_CTX].clk) {
if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
- rounded_rate = clk_round_rate(fabric->
- info.nodeclk[DUAL_CTX].clk, 1);
+ cur_rate = clk_get_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk);
+ rounded_rate = clk_round_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk,
+ cur_rate ? cur_rate : 1);
if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
rounded_rate))
MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
fabric->fabdev.id, rounded_rate);
clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+ }
}
if (info->iface_clk.clk)
@@ -514,22 +518,26 @@
struct msm_bus_inode_info *info, uint64_t req_clk, uint64_t req_bw)
{
struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
- long rounded_rate;
+ long rounded_rate, cur_rate;
if (fabdev->hw_algo.config_master == NULL)
return;
/* Enable clocks before accessing QoS registers */
- if (fabric->info.nodeclk[DUAL_CTX].clk)
+ if (fabric->info.nodeclk[DUAL_CTX].clk) {
if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
- rounded_rate = clk_round_rate(fabric->
- info.nodeclk[DUAL_CTX].clk, 1);
+ cur_rate = clk_get_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk);
+ rounded_rate = clk_round_rate(
+ fabric->info.nodeclk[DUAL_CTX].clk,
+ cur_rate ? cur_rate : 1);
if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
rounded_rate))
MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
fabric->fabdev.id, rounded_rate);
clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+ }
}
if (info->iface_clk.clk)
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
index 479826e..988d720 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -586,14 +586,8 @@
skip_mas_bw:
ports = hop->node_info->num_sports;
- if (ports == 0) {
- MSM_BUS_DBG("\nDIVIDE BY 0, hop: %d\n",
- hop->node_info->priv_id);
- return;
- }
- bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
for (i = 0; i < ports; i++) {
- sel_cd->slv[hop->node_info->slavep[i]].bw += bw;
+ sel_cd->slv[hop->node_info->slavep[i]].bw += add_bw;
sel_cd->slv[hop->node_info->slavep[i]].hw_id =
hop->node_info->slv_hw_id;
MSM_BUS_DBG("NOC: Update slave_bw for ID: %d -> %llu\n",
diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
index e2ff0f4..7c5adc1 100644
--- a/arch/arm/mach-msm/msm_qmi_interface.c
+++ b/arch/arm/mach-msm/msm_qmi_interface.c
@@ -33,6 +33,9 @@
#include "msm_qmi_interface_priv.h"
+#define BUILD_INSTANCE_ID(vers, ins) (((vers) & 0xFF) | (((ins) & 0xFF) << 8))
+#define LOOKUP_MASK 0xFFFFFFFF
+
static LIST_HEAD(svc_event_nb_list);
static DEFINE_MUTEX(svc_event_nb_list_lock);
static DEFINE_MUTEX(msm_qmi_init_lock);
@@ -625,12 +628,15 @@
EXPORT_SYMBOL(qmi_recv_msg);
int qmi_connect_to_service(struct qmi_handle *handle,
- uint32_t service_id, uint32_t instance_id)
+ uint32_t service_id,
+ uint32_t service_vers,
+ uint32_t service_ins)
{
struct msm_ipc_port_name svc_name;
struct msm_ipc_server_info svc_info;
struct msm_ipc_addr *svc_dest_addr;
int rc;
+ uint32_t instance_id;
if (!handle)
return -EINVAL;
@@ -642,12 +648,15 @@
return -ENOMEM;
}
+ instance_id = BUILD_INSTANCE_ID(service_vers, service_ins);
svc_name.service = service_id;
svc_name.instance = instance_id;
- rc = msm_ipc_router_lookup_server_name(&svc_name, &svc_info, 1, 0xFF);
+ rc = msm_ipc_router_lookup_server_name(&svc_name, &svc_info,
+ 1, LOOKUP_MASK);
if (rc <= 0) {
- pr_err("%s: Server not found\n", __func__);
+ pr_err("%s: Server %08x:%08x not found\n",
+ __func__, service_id, instance_id);
return -ENODEV;
}
svc_dest_addr->addrtype = MSM_IPC_ADDR_ID;
@@ -780,13 +789,16 @@
}
int qmi_svc_event_notifier_register(uint32_t service_id,
- uint32_t instance_id,
+ uint32_t service_vers,
+ uint32_t service_ins,
struct notifier_block *nb)
{
struct svc_event_nb *temp;
unsigned long flags;
int ret;
+ uint32_t instance_id;
+ instance_id = BUILD_INSTANCE_ID(service_vers, service_ins);
temp = find_and_add_svc_event_nb(service_id, instance_id);
if (!temp)
return -EFAULT;
@@ -810,13 +822,16 @@
EXPORT_SYMBOL(qmi_svc_event_notifier_register);
int qmi_svc_event_notifier_unregister(uint32_t service_id,
- uint32_t instance_id,
+ uint32_t service_vers,
+ uint32_t service_ins,
struct notifier_block *nb)
{
int ret;
struct svc_event_nb *temp;
unsigned long flags;
+ uint32_t instance_id;
+ instance_id = BUILD_INSTANCE_ID(service_vers, service_ins);
mutex_lock(&svc_event_nb_list_lock);
temp = find_svc_event_nb(service_id, instance_id);
if (!temp) {
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index c186a5e..f753391 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -51,6 +51,7 @@
static struct ocmem_hw_region *region_ctrl;
static struct mutex region_ctrl_lock;
static void *ocmem_base;
+static void *ocmem_vbase;
#define OCMEM_V1_MACROS 8
#define OCMEM_V1_MACRO_SZ (SZ_64K)
@@ -562,6 +563,13 @@
ocmem_write(0x0, ocmem_base + OC_GFX_MPU_END);
}
+int ocmem_clear(unsigned long start, unsigned long size)
+{
+ memset((ocmem_vbase + start), 0x4D4D434F, size);
+ mb();
+ return 0;
+}
+
static int do_lock(enum ocmem_client id, unsigned long offset,
unsigned long len, enum region_mode mode)
{
@@ -1144,6 +1152,7 @@
pdata = platform_get_drvdata(pdev);
ocmem_base = pdata->reg_base;
+ ocmem_vbase = pdata->vbase;
rc = ocmem_enable_core_clock();
diff --git a/arch/arm/mach-msm/ocmem_rdm.c b/arch/arm/mach-msm/ocmem_rdm.c
index 4ff7212..9eac050 100644
--- a/arch/arm/mach-msm/ocmem_rdm.c
+++ b/arch/arm/mach-msm/ocmem_rdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -149,38 +149,6 @@
return IRQ_HANDLED;
}
-#ifdef CONFIG_MSM_OCMEM_NONSECURE
-int ocmem_clear(unsigned long start, unsigned long size)
-{
- INIT_COMPLETION(dm_clear_event);
- /* Clear DM Mask */
- ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
- /* Clear DM Interrupts */
- ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);
- /* DM CLR offset */
- ocmem_write(start, dm_base + DM_CLR_OFFSET);
- /* DM CLR size */
- ocmem_write(size, dm_base + DM_CLR_SIZE);
- /* Wipe out memory as "OCMM" */
- ocmem_write(0x4D4D434F, dm_base + DM_CLR_PATTERN);
- /* The offset, size and pattern for clearing must be set
- * before triggering the clearing engine
- */
- mb();
- /* Trigger Data Clear */
- ocmem_write(DM_CLR_ENABLE, dm_base + DM_CLR_TRIGGER);
-
- wait_for_completion(&dm_clear_event);
-
- return 0;
-}
-#else
-int ocmem_clear(unsigned long start, unsigned long size)
-{
- return 0;
-}
-#endif
-
/* Lock during transfers */
int ocmem_rdm_transfer(int id, struct ocmem_map_list *clist,
unsigned long start, int direction)
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 05d3cef..3a87c78 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -46,6 +46,8 @@
"21 Perf: preserve registers across hotplug\n"
"22 msm: perf: fix formatting of trace entry\n"
"23 msm: perf: Fix cpu id logic in tracectr notifier\n"
+ "24 msm: perf: tracectr: Initialize cnts after hotplug\n"
+ "25 Perf: Reset pmu after hotplug\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/perf_trace_counters.c b/arch/arm/mach-msm/perf_trace_counters.c
index 0a679b1..8eb1244 100644
--- a/arch/arm/mach-msm/perf_trace_counters.c
+++ b/arch/arm/mach-msm/perf_trace_counters.c
@@ -21,21 +21,17 @@
DEFINE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts);
DEFINE_PER_CPU(u32[NUM_L2_PERCPU], previous_l2_cnts);
DEFINE_PER_CPU(u32, old_pid);
+DEFINE_PER_CPU(u32, hotplug_flag);
/* Reset per_cpu variables that store counter values uppn CPU hotplug */
static int tracectr_cpu_hotplug_notifier(struct notifier_block *self,
unsigned long action, void *hcpu)
{
int ret = NOTIFY_OK;
int cpu = (int)hcpu;
- int i;
- if ((action & (~CPU_TASKS_FROZEN)) == CPU_UP_PREPARE) {
- per_cpu(previous_ccnt, cpu) = 0;
- for (i = 0; i < NUM_L1_CTRS; i++)
- per_cpu(previous_l1_cnts[i], cpu) = 0;
- for (i = 0; i < NUM_L2_PERCPU; i++)
- per_cpu(previous_l2_cnts[i], cpu) = 0;
- }
+ if ((action & (~CPU_TASKS_FROZEN)) == CPU_STARTING)
+ per_cpu(hotplug_flag, cpu) = 1;
+
return ret;
}
@@ -43,6 +39,35 @@
.notifier_call = tracectr_cpu_hotplug_notifier,
};
+static void setup_prev_cnts(u32 cpu)
+{
+ int i;
+ u32 cnten_val;
+
+ /* Read PMCNTENSET */
+ asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(cnten_val));
+ /* Disable all the counters that were enabled */
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(cnten_val));
+ if (cnten_val & CC) {
+ /* Read value */
+ asm volatile("mrc p15, 0, %0, c9, c13, 0"
+ : "=r"(per_cpu(previous_ccnt, cpu)));
+ }
+
+ for (i = 0; i < NUM_L1_CTRS; i++) {
+ if (cnten_val & (1 << i)) {
+ /* Select */
+ asm volatile("mcr p15, 0, %0, c9, c12, 5"
+ : : "r"(i));
+ /* Read value */
+ asm volatile("mrc p15, 0, %0, c9, c13, 2"
+ : "=r"(per_cpu(previous_l1_cnts[i], cpu)));
+ }
+ }
+ /* Enable all the counters that were disabled */
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(cnten_val));
+}
+
static int tracectr_notifier(struct notifier_block *self, unsigned long cmd,
void *v)
{
@@ -54,9 +79,14 @@
return -EFAULT;
current_pid = thread->task->pid;
- if (per_cpu(old_pid, cpu) != -1)
- trace_sched_switch_with_ctrs(per_cpu(old_pid, cpu),
- current_pid);
+ if (per_cpu(old_pid, cpu) != -1) {
+ if (per_cpu(hotplug_flag, cpu) == 1) {
+ per_cpu(hotplug_flag, cpu) = 0;
+ setup_prev_cnts(cpu);
+ } else
+ trace_sched_switch_with_ctrs(per_cpu(old_pid, cpu),
+ current_pid);
+ }
per_cpu(old_pid, cpu) = current_pid;
return NOTIFY_OK;
}
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
index c4e52be..5614ddd 100644
--- a/arch/arm/mach-msm/pm-stats.c
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -225,6 +225,14 @@
stats[i].total_time = 0;
}
}
+ memset(suspend_stats.bucket,
+ 0, sizeof(suspend_stats.bucket));
+ memset(suspend_stats.min_time,
+ 0, sizeof(suspend_stats.min_time));
+ memset(suspend_stats.max_time,
+ 0, sizeof(suspend_stats.max_time));
+ suspend_stats.count = 0;
+ suspend_stats.total_time = 0;
spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
return count;
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index e7cec58..ab03712 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -393,6 +393,8 @@
[164] = MSM_CPU_8610,
[165] = MSM_CPU_8610,
[166] = MSM_CPU_8610,
+ [225] = MSM_CPU_8610,
+ [226] = MSM_CPU_8610,
/* 8064AB IDs */
[153] = MSM_CPU_8064AB,
@@ -676,6 +678,8 @@
char *buf)
{
uint32_t hw_subtype;
+ WARN_ONCE(1, "Deprecated, use platform_subtype_id instead\n");
+
if (!socinfo) {
pr_err("%s: No socinfo found!\n", __func__);
return 0;
@@ -705,6 +709,18 @@
}
static ssize_t
+socinfo_show_platform_subtype_id(struct sys_device *dev,
+ struct sysdev_attribute *attr,
+ char *buf)
+{
+ uint32_t hw_subtype;
+
+ hw_subtype = socinfo_get_platform_subtype();
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ hw_subtype);
+}
+
+static ssize_t
socinfo_show_pmic_model(struct sys_device *dev,
struct sysdev_attribute *attr,
char *buf)
@@ -827,6 +843,17 @@
}
static ssize_t
+msm_get_platform_subtype_id(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ uint32_t hw_subtype;
+ hw_subtype = socinfo_get_platform_subtype();
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ hw_subtype);
+}
+
+static ssize_t
msm_get_pmic_model(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -972,6 +999,8 @@
static struct sysdev_attribute socinfo_v6_files[] = {
_SYSDEV_ATTR(platform_subtype, 0444,
socinfo_show_platform_subtype, NULL),
+ _SYSDEV_ATTR(platform_subtype_id, 0444,
+ socinfo_show_platform_subtype_id, NULL),
};
static struct sysdev_attribute socinfo_v7_files[] = {
@@ -1057,6 +1086,13 @@
__ATTR(platform_subtype, S_IRUGO,
msm_get_platform_subtype, NULL);
+/* Platform Subtype String is being deprecated. Use Platform
+ * Subtype ID instead.
+ */
+static struct device_attribute msm_soc_attr_platform_subtype_id =
+ __ATTR(platform_subtype_id, S_IRUGO,
+ msm_get_platform_subtype_id, NULL);
+
static struct device_attribute msm_soc_attr_pmic_model =
__ATTR(pmic_model, S_IRUGO,
msm_get_pmic_model, NULL);
@@ -1150,6 +1186,8 @@
case 6:
device_create_file(msm_soc_device,
&msm_soc_attr_platform_subtype);
+ device_create_file(msm_soc_device,
+ &msm_soc_attr_platform_subtype_id);
case 5:
device_create_file(msm_soc_device,
&msm_soc_attr_accessory_chip);
diff --git a/block/blk-core.c b/block/blk-core.c
index 00eab3b..7afd6cf 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1221,8 +1221,9 @@
elv_completed_request(q, req);
- /* this is a bio leak */
- WARN_ON(req->bio != NULL);
+ /* this is a bio leak if the bio is not tagged with BIO_DONTFREE */
+ WARN_ON(req->bio && !bio_flagged(req->bio, BIO_DONTFREE));
+
/*
* Request may not have originated from ll_rw_blk. if not,
@@ -2274,6 +2275,15 @@
blk_account_io_completion(req, nr_bytes);
total_bytes = bio_nbytes = 0;
+
+ /*
+ * Check for this if flagged, Req based dm needs to perform
+ * post processing, hence dont end bios or request.DM
+ * layer takes care.
+ */
+ if (bio_flagged(req->bio, BIO_DONTFREE))
+ return false;
+
while ((bio = req->bio) != NULL) {
int nbytes;
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 885721f..606383a 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -547,9 +547,9 @@
VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
+ free_contig_range(pfn, count);
mutex_lock(&cma_mutex);
bitmap_clear(cma->bitmap, pfn - cma->base_pfn, count);
- free_contig_range(pfn, count);
mutex_unlock(&cma_mutex);
return true;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 028f045..8cc7515 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1870,7 +1870,6 @@
printk(KERN_DEBUG "diag: USB disconnected\n");
driver->usb_connected = 0;
driver->debug_flag = 1;
- usb_diag_free_req(driver->legacy_ch);
if (driver->logging_mode == USB_MODE) {
for (i = 0; i < NUM_SMD_DATA_CHANNELS; i++) {
driver->smd_data[i].in_busy_1 = 1;
@@ -2625,8 +2624,6 @@
diag_smd_destructor(&driver->smd_data[i]);
#ifdef CONFIG_DIAG_OVER_USB
- if (driver->usb_connected)
- usb_diag_free_req(driver->legacy_ch);
usb_diag_close(driver->legacy_ch);
#endif
platform_driver_unregister(&msm_smd_ch1_driver);
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index 143959b..142d15a 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -133,7 +133,6 @@
/* If the usb cable is being disconnected */
if (process_cable) {
diag_bridge[i].usb_connected = 0;
- usb_diag_free_req(diag_bridge[i].ch);
}
if (i == SMUX) {
@@ -383,8 +382,6 @@
for (i = 0; i < MAX_BRIDGES; i++) {
if (diag_bridge[i].enabled) {
#ifdef CONFIG_DIAG_OVER_USB
- if (diag_bridge[i].usb_connected)
- usb_diag_free_req(diag_bridge[i].ch);
usb_diag_close(diag_bridge[i].ch);
#endif
kfree(diag_bridge[i].usb_buf_out);
diff --git a/drivers/char/diag/diagfwd_sdio.c b/drivers/char/diag/diagfwd_sdio.c
index 7d4e0d5..ef56a1b 100644
--- a/drivers/char/diag/diagfwd_sdio.c
+++ b/drivers/char/diag/diagfwd_sdio.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -131,7 +131,6 @@
int diagfwd_disconnect_sdio(void)
{
- usb_diag_free_req(driver->mdm_ch);
if (driver->sdio_ch && (driver->logging_mode == USB_MODE)) {
driver->in_busy_sdio = 1;
diag_sdio_close();
@@ -280,10 +279,6 @@
void diagfwd_sdio_exit(void)
{
-#ifdef CONFIG_DIAG_OVER_USB
- if (driver->usb_connected)
- usb_diag_free_req(driver->mdm_ch);
-#endif
platform_driver_unregister(&msm_sdio_ch_driver);
#ifdef CONFIG_DIAG_OVER_USB
usb_diag_close(driver->mdm_ch);
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index f35ba53..0c7c9e0 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -177,6 +177,7 @@
bool byte_cntr_read_active;
wait_queue_head_t wq;
char *byte_cntr_node;
+ uint32_t mem_size;
};
static void tmc_wait_for_flush(struct tmc_drvdata *drvdata)
@@ -1310,6 +1311,32 @@
static DEVICE_ATTR(byte_cntr_value, S_IRUGO | S_IWUSR,
tmc_etr_show_byte_cntr_value, tmc_etr_store_byte_cntr_value);
+static ssize_t tmc_etr_show_mem_size(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val = drvdata->mem_size;
+
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t tmc_etr_store_mem_size(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+
+ drvdata->mem_size = val;
+ return size;
+}
+static DEVICE_ATTR(mem_size, S_IRUGO | S_IWUSR,
+ tmc_etr_show_mem_size, tmc_etr_store_mem_size);
+
static struct attribute *tmc_attrs[] = {
&dev_attr_trigger_cntr.attr,
NULL,
@@ -1322,6 +1349,7 @@
static struct attribute *tmc_etr_attrs[] = {
&dev_attr_out_mode.attr,
&dev_attr_byte_cntr_value.attr,
+ &dev_attr_mem_size.attr,
NULL,
};
diff --git a/drivers/cpufreq/cpu-boost.c b/drivers/cpufreq/cpu-boost.c
index f20510d..b4aec53 100644
--- a/drivers/cpufreq/cpu-boost.c
+++ b/drivers/cpufreq/cpu-boost.c
@@ -335,8 +335,6 @@
int cpu, ret;
struct cpu_sync *s;
- cpufreq_register_notifier(&boost_adjust_nb, CPUFREQ_POLICY_NOTIFIER);
-
cpu_boost_wq = alloc_workqueue("cpuboost_wq", WQ_HIGHPRI, 0);
if (!cpu_boost_wq)
return -EFAULT;
@@ -354,10 +352,11 @@
"boost_sync/%d", cpu);
set_cpus_allowed(s->thread, *cpumask_of(cpu));
}
+ cpufreq_register_notifier(&boost_adjust_nb, CPUFREQ_POLICY_NOTIFIER);
atomic_notifier_chain_register(&migration_notifier_head,
&boost_migration_nb);
-
ret = input_register_handler(&cpuboost_input_handler);
+
return 0;
}
late_initcall(cpu_boost_init);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 3aebaf0..48dc6ec 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -39,6 +39,7 @@
#include <crypto/authenc.h>
#include <crypto/scatterwalk.h>
#include <crypto/internal/hash.h>
+#include <crypto/internal/aead.h>
#include <mach/scm.h>
#include <linux/platform_data/qcom_crypto_device.h>
@@ -66,6 +67,8 @@
u32 aead_sha1_3des_dec;
u32 aead_ccm_aes_enc;
u32 aead_ccm_aes_dec;
+ u32 aead_rfc4309_ccm_aes_enc;
+ u32 aead_rfc4309_ccm_aes_dec;
u32 aead_op_success;
u32 aead_op_fail;
u32 aead_bad_msg;
@@ -231,6 +234,8 @@
/* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
#define QCRYPTO_MAX_IV_LENGTH 16
+#define QCRYPTO_CCM4309_NONCE_LEN 3
+
struct qcrypto_cipher_ctx {
u8 auth_key[QCRYPTO_MAX_KEY_SIZE];
u8 iv[QCRYPTO_MAX_IV_LENGTH];
@@ -244,10 +249,12 @@
struct crypto_priv *cp;
unsigned int flags;
struct crypto_engine *pengine; /* fixed engine assigned */
+ u8 ccm4309_nonce[QCRYPTO_CCM4309_NONCE_LEN];
};
struct qcrypto_cipher_req_ctx {
u8 *iv;
+ u8 rfc4309_iv[QCRYPTO_MAX_IV_LENGTH];
unsigned int ivsize;
int aead;
struct scatterlist asg; /* Formatted associated data sg */
@@ -736,7 +743,12 @@
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD CCM-AES decryption : %d\n",
pstat->aead_ccm_aes_dec);
-
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD RFC4309-CCM-AES encryption : %d\n",
+ pstat->aead_rfc4309_ccm_aes_enc);
+ len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD RFC4309-CCM-AES decryption : %d\n",
+ pstat->aead_rfc4309_ccm_aes_dec);
len += scnprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD operation success : %d\n",
pstat->aead_op_success);
@@ -1272,6 +1284,12 @@
uint32_t bytes = 0;
uint32_t num_sg = 0;
+ if (alen == 0) {
+ qreq->assoc = NULL;
+ qreq->assoclen = 0;
+ return 0;
+ }
+
qreq->assoc = kzalloc((alen + 0x64), GFP_ATOMIC);
if (!qreq->assoc) {
pr_err("qcrypto Memory allocation of adata FAIL, error %ld\n",
@@ -1455,7 +1473,10 @@
qreq.authkey = cipher_ctx->auth_key;
qreq.authklen = cipher_ctx->auth_key_len;
qreq.authsize = crypto_aead_authsize(aead);
- qreq.ivsize = crypto_aead_ivsize(aead);
+ if (qreq.mode == QCE_MODE_CCM)
+ qreq.ivsize = AES_BLOCK_SIZE;
+ else
+ qreq.ivsize = crypto_aead_ivsize(aead);
qreq.flags = cipher_ctx->flags;
if (qreq.mode == QCE_MODE_CCM) {
@@ -1502,8 +1523,9 @@
kzfree(qreq.assoc);
return -ENOMEM;
}
-
- memcpy((char *)rctx->data, qreq.assoc, qreq.assoclen);
+ if (qreq.assoclen)
+ memcpy((char *)rctx->data, qreq.assoc,
+ qreq.assoclen);
num_sg = qcrypto_count_sg(req->src, req->cryptlen);
bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg,
@@ -1845,6 +1867,29 @@
return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
}
+static int _qcrypto_aead_rfc4309_enc_aes_ccm(struct aead_request *req)
+{
+ struct qcrypto_cipher_req_ctx *rctx;
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct crypto_priv *cp = ctx->cp;
+ struct crypto_stat *pstat;
+
+ pstat = &_qcrypto_stat;
+
+ rctx = aead_request_ctx(req);
+ rctx->aead = 1;
+ rctx->alg = CIPHER_ALG_AES;
+ rctx->dir = QCE_ENCRYPT;
+ rctx->mode = QCE_MODE_CCM;
+ memset(rctx->rfc4309_iv, 0, sizeof(rctx->rfc4309_iv));
+ rctx->rfc4309_iv[0] = 3; /* L -1 */
+ memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3);
+ memcpy(&rctx->rfc4309_iv[4], req->iv, 8);
+ rctx->iv = rctx->rfc4309_iv;
+ pstat->aead_rfc4309_ccm_aes_enc++;
+ return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
+}
+
static int _qcrypto_enc_des_ecb(struct ablkcipher_request *req)
{
struct qcrypto_cipher_req_ctx *rctx;
@@ -2136,6 +2181,27 @@
return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
}
+static int _qcrypto_aead_rfc4309_dec_aes_ccm(struct aead_request *req)
+{
+ struct qcrypto_cipher_req_ctx *rctx;
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+ struct crypto_priv *cp = ctx->cp;
+ struct crypto_stat *pstat;
+
+ pstat = &_qcrypto_stat;
+ rctx = aead_request_ctx(req);
+ rctx->aead = 1;
+ rctx->alg = CIPHER_ALG_AES;
+ rctx->dir = QCE_DECRYPT;
+ rctx->mode = QCE_MODE_CCM;
+ memset(rctx->rfc4309_iv, 0, sizeof(rctx->rfc4309_iv));
+ rctx->rfc4309_iv[0] = 3; /* L -1 */
+ memcpy(&rctx->rfc4309_iv[1], ctx->ccm4309_nonce, 3);
+ memcpy(&rctx->rfc4309_iv[4], req->iv, 8);
+ rctx->iv = rctx->rfc4309_iv;
+ pstat->aead_rfc4309_ccm_aes_dec++;
+ return _qcrypto_queue_req(cp, ctx->pengine, &req->base);
+}
static int _qcrypto_aead_setauthsize(struct crypto_aead *authenc,
unsigned int authsize)
{
@@ -2166,6 +2232,24 @@
return 0;
}
+static int _qcrypto_aead_rfc4309_ccm_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ struct qcrypto_cipher_ctx *ctx = crypto_aead_ctx(authenc);
+
+ switch (authsize) {
+ case 8:
+ case 12:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+ ctx->authsize = authsize;
+ return 0;
+}
+
+
static int _qcrypto_aead_setkey(struct crypto_aead *tfm, const u8 *key,
unsigned int keylen)
{
@@ -2231,6 +2315,21 @@
return 0;
}
+static int _qcrypto_aead_rfc4309_ccm_setkey(struct crypto_aead *aead,
+ const u8 *key, unsigned int key_len)
+{
+ struct crypto_tfm *tfm = crypto_aead_tfm(aead);
+ struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ int ret;
+
+ if (key_len < QCRYPTO_CCM4309_NONCE_LEN)
+ return -EINVAL;
+ key_len -= QCRYPTO_CCM4309_NONCE_LEN;
+ memcpy(ctx->ccm4309_nonce, key + key_len, QCRYPTO_CCM4309_NONCE_LEN);
+ ret = _qcrypto_aead_ccm_setkey(aead, key, key_len);
+ return ret;
+};
+
static int _qcrypto_aead_encrypt_aes_cbc(struct aead_request *req)
{
struct qcrypto_cipher_req_ctx *rctx;
@@ -3762,7 +3861,7 @@
.cra_u = {
.aead = {
.ivsize = AES_BLOCK_SIZE,
- .maxauthsize = SHA1_DIGEST_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
.setkey = _qcrypto_aead_ccm_setkey,
.setauthsize = _qcrypto_aead_ccm_setauthsize,
.encrypt = _qcrypto_aead_encrypt_aes_ccm,
@@ -3772,6 +3871,31 @@
}
};
+static struct crypto_alg _qcrypto_aead_rfc4309_ccm_algo = {
+ .cra_name = "rfc4309(ccm(aes))",
+ .cra_driver_name = "qcrypto-rfc4309-aes-ccm",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct qcrypto_cipher_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_nivaead_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = _qcrypto_cra_aead_init,
+ .cra_exit = _qcrypto_cra_aead_exit,
+ .cra_u = {
+ .aead = {
+ .ivsize = 8,
+ .maxauthsize = 16,
+ .setkey = _qcrypto_aead_rfc4309_ccm_setkey,
+ .setauthsize = _qcrypto_aead_rfc4309_ccm_setauthsize,
+ .encrypt = _qcrypto_aead_rfc4309_enc_aes_ccm,
+ .decrypt = _qcrypto_aead_rfc4309_dec_aes_ccm,
+ .geniv = "seqiv",
+ }
+ }
+};
+
static int _qcrypto_probe(struct platform_device *pdev)
{
@@ -4078,6 +4202,36 @@
dev_info(&pdev->dev, "%s\n",
q_alg->cipher_alg.cra_driver_name);
}
+
+ q_alg = _qcrypto_cipher_alg_alloc(cp,
+ &_qcrypto_aead_rfc4309_ccm_algo);
+ if (IS_ERR(q_alg)) {
+ rc = PTR_ERR(q_alg);
+ goto err;
+ }
+
+ if (cp->ce_support.use_sw_aes_ccm_algo) {
+ rc = _qcrypto_prefix_alg_cra_name(
+ q_alg->cipher_alg.cra_name,
+ strlen(q_alg->cipher_alg.cra_name));
+ if (rc) {
+ dev_err(&pdev->dev,
+ "The algorithm name %s is too long.\n",
+ q_alg->cipher_alg.cra_name);
+ kfree(q_alg);
+ goto err;
+ }
+ }
+ rc = crypto_register_alg(&q_alg->cipher_alg);
+ if (rc) {
+ dev_err(&pdev->dev, "%s alg registration failed\n",
+ q_alg->cipher_alg.cra_driver_name);
+ kfree(q_alg);
+ } else {
+ list_add_tail(&q_alg->entry, &cp->alg_list);
+ dev_info(&pdev->dev, "%s\n",
+ q_alg->cipher_alg.cra_driver_name);
+ }
}
mutex_unlock(&cp->engine_lock);
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 9e49b3e..e13fb5f 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -125,14 +125,20 @@
cur_time = jiffies;
devfreq->time_in_state[lev] +=
cur_time - devfreq->last_stat_updated;
- if (freq != devfreq->previous_freq) {
- prev_lev = devfreq_get_freq_level(devfreq,
- devfreq->previous_freq);
+ devfreq->last_stat_updated = cur_time;
+
+ if (freq == devfreq->previous_freq)
+ return 0;
+
+ prev_lev = devfreq_get_freq_level(devfreq, devfreq->previous_freq);
+ if (prev_lev < 0)
+ return 0;
+
+ if (lev != prev_lev) {
devfreq->trans_table[(prev_lev *
devfreq->profile->max_state) + lev]++;
devfreq->total_trans++;
}
- devfreq->last_stat_updated = cur_time;
return 0;
}
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index 8d934df..6176df9 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -182,6 +182,7 @@
struct device_node *int_ctrl;
struct list_head chip_list;
struct dentry *dfs_dir;
+ bool chip_registered;
};
static LIST_HEAD(qpnp_pin_chips);
@@ -912,7 +913,7 @@
static int qpnp_pin_free_chip(struct qpnp_pin_chip *q_chip)
{
struct spmi_device *spmi = q_chip->spmi;
- int rc, i;
+ int i, rc = 0;
if (q_chip->chip_gpios)
for (i = 0; i < spmi->num_dev_node; i++)
@@ -921,10 +922,12 @@
mutex_lock(&qpnp_pin_chips_lock);
list_del(&q_chip->chip_list);
mutex_unlock(&qpnp_pin_chips_lock);
- rc = gpiochip_remove(&q_chip->gpio_chip);
- if (rc)
- dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
- __func__);
+ if (q_chip->chip_registered) {
+ rc = gpiochip_remove(&q_chip->gpio_chip);
+ if (rc)
+ dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
+ __func__);
+ }
kfree(q_chip->chip_gpios);
kfree(q_chip->pmic_pins);
kfree(q_chip);
@@ -1342,6 +1345,7 @@
goto err_probe;
}
+ q_chip->chip_registered = true;
/* now configure gpio config defaults if they exist */
for (i = 0; i < spmi->num_dev_node; i++) {
q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 6261d89..aa2551a 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -141,9 +141,11 @@
if (!ptr)
return -ENOMEM;
- memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
/*
- * invalidate the cache to pick up the zeroing
+ * We have to invalidate the cache here because there
+ * might be dirty lines to these physical pages (which
+ * we don't care about) that could get written out at
+ * any moment.
*/
for (k = 0; k < npages_to_vmap; k++) {
void *p = kmap_atomic(pages[i + k]);
@@ -154,6 +156,7 @@
outer_inv_range(phys, phys + PAGE_SIZE);
kunmap_atomic(p);
}
+ memset(ptr, 0, npages_to_vmap * PAGE_SIZE);
vunmap(ptr);
}
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index be1a89c..cfdd5f4 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -2,7 +2,7 @@
* drivers/gpu/ion/ion_system_heap.c
*
* Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, 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
@@ -34,7 +34,7 @@
__GFP_NO_KSWAPD) & ~__GFP_WAIT;
static unsigned int low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO |
__GFP_NOWARN);
-static const unsigned int orders[] = {8, 4, 0};
+static const unsigned int orders[] = {9, 8, 4, 0};
static const int num_orders = ARRAY_SIZE(orders);
static int order_to_index(unsigned int order)
{
@@ -362,7 +362,7 @@
struct ion_page_pool *pool;
gfp_t gfp_flags = low_order_gfp_flags;
- if (orders[i] > 4)
+ if (orders[i])
gfp_flags = high_order_gfp_flags;
pool = ion_page_pool_create(gfp_flags, orders[i]);
if (!pool)
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 7717829..7a92fe6 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1625,17 +1625,19 @@
goto err;
}
- ret = of_property_read_u32_array(child, "reg", reg_val, 2);
- if (ret) {
- KGSL_CORE_ERR("Unable to read KGSL IOMMU 'reg'\n");
+ if (!strcmp("gfx3d_user", ctxs[ctx_index].iommu_ctx_name)) {
+ ctxs[ctx_index].ctx_id = 0;
+ } else if (!strcmp("gfx3d_priv",
+ ctxs[ctx_index].iommu_ctx_name)) {
+ ctxs[ctx_index].ctx_id = 1;
+ } else if (!strcmp("gfx3d_spare",
+ ctxs[ctx_index].iommu_ctx_name)) {
+ ctxs[ctx_index].ctx_id = 2;
+ } else {
+ KGSL_CORE_ERR("dt: IOMMU context %s is invalid\n",
+ ctxs[ctx_index].iommu_ctx_name);
goto err;
}
- if (msm_soc_version_supports_iommu_v0())
- ctxs[ctx_index].ctx_id = (reg_val[0] -
- data->physstart) >> KGSL_IOMMU_CTX_SHIFT;
- else
- ctxs[ctx_index].ctx_id = ((reg_val[0] -
- data->physstart) >> KGSL_IOMMU_CTX_SHIFT) - 8;
ctx_index++;
}
@@ -1690,6 +1692,12 @@
if (ret)
goto err;
+ /* get pm-qos-latency from target, set it to default if not found */
+ if (adreno_of_read_property(pdev->dev.of_node, "qcom,pm-qos-latency",
+ &pdata->pm_qos_latency))
+ pdata->pm_qos_latency = 501;
+
+
if (adreno_of_read_property(pdev->dev.of_node, "qcom,idle-timeout",
&pdata->idle_timeout))
pdata->idle_timeout = HZ/12;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 0f1e01d..e2ea262 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -191,8 +191,6 @@
unsigned int fast_hang_detect;
unsigned int ft_policy;
unsigned int long_ib_detect;
- unsigned int long_ib;
- unsigned int long_ib_ts;
unsigned int ft_pf_policy;
unsigned int gpulist_index;
struct ocmem_buf *ocmem_hdl;
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 95e4017..48d0210 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -951,9 +951,6 @@
adreno_readreg(adreno_dev, ADRENO_REG_CP_ME_CNTL, ®);
reg |= (1 << 27) | (1 << 28);
adreno_writereg(adreno_dev, ADRENO_REG_CP_ME_CNTL, reg);
-
- /* Skip the PM dump for a timeout because it confuses people */
- set_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy);
}
adreno_readreg(adreno_dev, ADRENO_REG_CP_IB1_BASE, &base);
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 7656cd5..258cf94 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2014, 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
@@ -133,7 +133,6 @@
*/
struct adreno_context {
struct kgsl_context base;
- unsigned int ib_gpu_time_used;
unsigned int timestamp;
unsigned int internal_timestamp;
int state;
diff --git a/drivers/gpu/msm/adreno_profile.c b/drivers/gpu/msm/adreno_profile.c
index 079e120..26c8b69 100644
--- a/drivers/gpu/msm/adreno_profile.c
+++ b/drivers/gpu/msm/adreno_profile.c
@@ -1074,9 +1074,6 @@
*/
transfer_results(device, shared_buf_tail);
- /* check for any cleanup */
- check_close_profile(profile);
-
return 1;
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 9aae497..7bbbc35 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -1197,6 +1197,8 @@
pwrlevel.level = constraint;
}
+ device->pwrctrl.constraint.expires = jiffies +
+ device->pwrctrl.interval_timeout;
}
}
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 7d009ce..98fd731 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -28,7 +28,6 @@
#define KGSL_TIMEOUT_NONE 0
#define KGSL_TIMEOUT_DEFAULT 0xFFFFFFFF
#define KGSL_TIMEOUT_PART 50 /* 50 msec */
-#define KGSL_TIMEOUT_LONG_IB_DETECTION 2000 /* 2 sec*/
#define FIRST_TIMEOUT (HZ / 2)
@@ -723,4 +722,23 @@
return ret;
}
+/**
+ * kgsl_sysfs_store() - parse a string from a sysfs store function
+ * @buf: Incoming string to parse
+ * @ptr: Pointer to an unsigned int to store the value
+ */
+static inline int kgsl_sysfs_store(const char *buf, unsigned int *ptr)
+{
+ unsigned int val;
+ int rc;
+
+ rc = kstrtou32(buf, 0, &val);
+ if (rc)
+ return rc;
+
+ if (ptr)
+ *ptr = val;
+
+ return 0;
+}
#endif /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index e21fd88..ccd13d5 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -210,7 +210,7 @@
kgsl_event_func func, void *priv, void *owner)
{
struct kgsl_event *event;
- unsigned int queued, cur_ts;
+ unsigned int queued = 0, cur_ts;
struct kgsl_context *context = NULL;
BUG_ON(!mutex_is_locked(&device->mutex));
@@ -224,11 +224,21 @@
return -EINVAL;
}
- queued = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_QUEUED);
+ /*
+ * If the caller is creating their own timestamps, let them schedule
+ * events in the future. Otherwise only allow timestamps that have been
+ * queued.
+ */
+ if (context == NULL ||
+ ((context->flags & KGSL_CONTEXT_USER_GENERATED_TS) == 0)) {
- if (timestamp_cmp(ts, queued) > 0) {
- kgsl_context_put(context);
- return -EINVAL;
+ queued = kgsl_readtimestamp(device, context,
+ KGSL_TIMESTAMP_QUEUED);
+
+ if (timestamp_cmp(ts, queued) > 0) {
+ kgsl_context_put(context);
+ return -EINVAL;
+ }
}
cur_ts = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6b04aad..d64d0d3 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -85,16 +85,8 @@
return status;
}
-static void kgsl_destroy_pagetable(struct kref *kref)
+static void _kgsl_destroy_pagetable(struct kgsl_pagetable *pagetable)
{
- struct kgsl_pagetable *pagetable = container_of(kref,
- struct kgsl_pagetable, refcount);
- unsigned long flags;
-
- spin_lock_irqsave(&kgsl_driver.ptlock, flags);
- list_del(&pagetable->list);
- spin_unlock_irqrestore(&kgsl_driver.ptlock, flags);
-
pagetable_remove_sysfs_objects(pagetable);
kgsl_cleanup_pt(pagetable);
@@ -109,6 +101,29 @@
kfree(pagetable);
}
+static void kgsl_destroy_pagetable(struct kref *kref)
+{
+ struct kgsl_pagetable *pagetable = container_of(kref,
+ struct kgsl_pagetable, refcount);
+ unsigned long flags;
+
+ spin_lock_irqsave(&kgsl_driver.ptlock, flags);
+ list_del(&pagetable->list);
+ spin_unlock_irqrestore(&kgsl_driver.ptlock, flags);
+
+ _kgsl_destroy_pagetable(pagetable);
+}
+
+static void kgsl_destroy_pagetable_locked(struct kref *kref)
+{
+ struct kgsl_pagetable *pagetable = container_of(kref,
+ struct kgsl_pagetable, refcount);
+
+ list_del(&pagetable->list);
+
+ _kgsl_destroy_pagetable(pagetable);
+}
+
static inline void kgsl_put_pagetable(struct kgsl_pagetable *pagetable)
{
if (pagetable)
@@ -128,7 +143,7 @@
ret = pt;
break;
}
- kref_put(&pt->refcount, kgsl_destroy_pagetable);
+ kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
}
}
@@ -139,12 +154,12 @@
static struct kgsl_pagetable *
_get_pt_from_kobj(struct kobject *kobj)
{
- unsigned long ptname;
+ unsigned int ptname;
if (!kobj)
return NULL;
- if (sscanf(kobj->name, "%ld", &ptname) != 1)
+ if (kstrtou32(kobj->name, 0, &ptname))
return NULL;
return kgsl_get_pagetable(ptname);
@@ -328,10 +343,11 @@
if (kref_get_unless_zero(&pt->refcount)) {
if (mmu->mmu_ops->mmu_pt_equal(mmu, pt, pt_base)) {
ptid = (int) pt->name;
- kref_put(&pt->refcount, kgsl_destroy_pagetable);
+ kref_put(&pt->refcount,
+ kgsl_destroy_pagetable_locked);
break;
}
- kref_put(&pt->refcount, kgsl_destroy_pagetable);
+ kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
}
}
spin_unlock(&kgsl_driver.ptlock);
@@ -356,18 +372,18 @@
if ((addr & ~(PAGE_SIZE-1)) == pt->fault_addr) {
ret = 1;
kref_put(&pt->refcount,
- kgsl_destroy_pagetable);
+ kgsl_destroy_pagetable_locked);
break;
} else {
pt->fault_addr =
(addr & ~(PAGE_SIZE-1));
ret = 0;
kref_put(&pt->refcount,
- kgsl_destroy_pagetable);
+ kgsl_destroy_pagetable_locked);
break;
}
}
- kref_put(&pt->refcount, kgsl_destroy_pagetable);
+ kref_put(&pt->refcount, kgsl_destroy_pagetable_locked);
}
}
spin_unlock(&kgsl_driver.ptlock);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index c00e978..656d7e2 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -220,19 +220,18 @@
{
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- int ret, level;
+ int ret;
+ unsigned int level = 0;
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
- ret = sscanf(buf, "%d", &level);
- if (ret != 1)
- return count;
+ ret = kgsl_sysfs_store(buf, &level);
- if (level < 0)
- return count;
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
@@ -274,20 +273,17 @@
{
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- int ret, level, max_level;
+ int ret, max_level;
+ unsigned int level = 0;
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
- ret = sscanf(buf, "%d", &level);
- if (ret != 1)
- return count;
-
- /* If the use specifies a negative number, then don't change anything */
- if (level < 0)
- return count;
+ ret = kgsl_sysfs_store(buf, &level);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
@@ -329,20 +325,17 @@
const char *buf, size_t count)
{ struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- int ret, level, min_level;
+ int ret, min_level;
+ unsigned int level = 0;
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
- ret = sscanf(buf, "%d", &level);
- if (ret != 1)
- return count;
-
- /* Don't do anything on obviously incorrect values */
- if (level < 0)
- return count;
+ ret = kgsl_sysfs_store(buf, &level);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
if (level > pwr->num_pwrlevels - 2)
@@ -413,7 +406,7 @@
{
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- unsigned long val;
+ unsigned int val = 0;
int ret, level;
if (device == NULL)
@@ -421,9 +414,9 @@
pwr = &device->pwrctrl;
- ret = sscanf(buf, "%ld", &val);
- if (ret != 1)
- return count;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
level = _get_nearest_pwrlevel(pwr, val);
@@ -465,7 +458,7 @@
{
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
- unsigned long val;
+ unsigned int val = 0;
int ret, level;
if (device == NULL)
@@ -473,9 +466,9 @@
pwr = &device->pwrctrl;
- ret = sscanf(buf, "%ld", &val);
- if (ret != 1)
- return count;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
level = _get_nearest_pwrlevel(pwr, val);
@@ -502,22 +495,19 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- char temp[20];
- unsigned long val;
+ unsigned int val = 0;
struct kgsl_device *device = kgsl_device_from_dev(dev);
struct kgsl_pwrctrl *pwr;
const long div = 1000/HZ;
- int rc;
+ int ret;
if (device == NULL)
return 0;
pwr = &device->pwrctrl;
- snprintf(temp, sizeof(temp), "%.*s",
- (int)min(count, sizeof(temp) - 1), buf);
- rc = strict_strtoul(temp, 0, &val);
- if (rc)
- return rc;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
@@ -547,19 +537,16 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- char temp[20];
- unsigned long val;
+ unsigned int val = 0;
struct kgsl_device *device = kgsl_device_from_dev(dev);
- int rc;
+ int ret;
if (device == NULL)
return 0;
- snprintf(temp, sizeof(temp), "%.*s",
- (int)min(count, sizeof(temp) - 1), buf);
- rc = kstrtoul(temp, 0, &val);
- if (rc)
- return rc;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
device->pwrctrl.pm_qos_latency = val;
@@ -694,19 +681,16 @@
const char *buf, size_t count,
int flag)
{
- char temp[20];
- unsigned long val;
+ unsigned int val = 0;
struct kgsl_device *device = kgsl_device_from_dev(dev);
- int rc;
+ int ret;
if (device == NULL)
return 0;
- snprintf(temp, sizeof(temp), "%.*s",
- (int)min(count, sizeof(temp) - 1), buf);
- rc = kstrtoul(temp, 0, &val);
- if (rc)
- return rc;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
__force_on(device, flag, val);
@@ -772,19 +756,16 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- char temp[20];
- unsigned long val;
+ unsigned int val = 0;
struct kgsl_device *device = kgsl_device_from_dev(dev);
- int rc;
+ int ret;
if (device == NULL)
return 0;
- snprintf(temp, sizeof(temp), "%.*s",
- (int)min(count, sizeof(temp) - 1), buf);
- rc = kstrtoul(temp, 0, &val);
- if (rc)
- return rc;
+ ret = kgsl_sysfs_store(buf, &val);
+ if (ret)
+ return ret;
mutex_lock(&device->mutex);
device->pwrctrl.bus_control = val ? true : false;
@@ -1143,8 +1124,7 @@
pwr->pwrlevels[pwr->active_pwrlevel].
bus_freq);
- /* Set the CPU latency to 501usec to allow low latency PC modes */
- pwr->pm_qos_latency = 501;
+ pwr->pm_qos_latency = pdata->pm_qos_latency;
pm_runtime_enable(device->parentdev);
@@ -1569,7 +1549,10 @@
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
/* Order pwrrail/clk sequence based upon platform */
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
- kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel);
+
+ if (pwr->constraint.type == KGSL_CONSTRAINT_NONE)
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->active_pwrlevel);
+
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index c811b78..31c5229 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -51,6 +51,7 @@
unsigned int level;
} pwrlevel;
} hint;
+ unsigned long expires;
};
/**
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index acee4d4..0bb13a4 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -227,12 +227,25 @@
kgsl_pwrctrl_buslevel_update(device, true);
}
- kgsl_pwrctrl_pwrlevel_change(device, level);
+ /*
+ * The power constraints need an entire interval to do their magic, so
+ * skip changing the powerlevel if the time hasn't expired yet and the
+ * new level is less than the constraint
+ */
+ if ((pwr->constraint.type != KGSL_CONSTRAINT_NONE) &&
+ (!time_after(jiffies, pwr->constraint.expires)) &&
+ (level >= pwr->constraint.hint.pwrlevel.level))
+ *freq = cur_freq;
+ else {
+ /* Change the power level */
+ kgsl_pwrctrl_pwrlevel_change(device, level);
- /*Invalidate the constraint set */
- pwr->constraint.type = KGSL_CONSTRAINT_NONE;
+ /*Invalidate the constraint set */
+ pwr->constraint.type = KGSL_CONSTRAINT_NONE;
+ pwr->constraint.expires = 0;
- *freq = kgsl_pwrctrl_active_freq(pwr);
+ *freq = kgsl_pwrctrl_active_freq(pwr);
+ }
mutex_unlock(&device->mutex);
return 0;
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index d3adf84..c8ea471 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2014, 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
@@ -73,12 +73,12 @@
_get_priv_from_kobj(struct kobject *kobj)
{
struct kgsl_process_private *private;
- unsigned long name;
+ unsigned int name;
if (!kobj)
return NULL;
- if (sscanf(kobj->name, "%ld", &name) != 1)
+ if (kstrtou32(kobj->name, 0, &name))
return NULL;
list_for_each_entry(private, &kgsl_driver.process_list, list) {
@@ -255,13 +255,13 @@
const char *buf, size_t count)
{
int ret;
- unsigned int thresh;
- ret = sscanf(buf, "%d", &thresh);
- if (ret != 1)
- return count;
+ unsigned int thresh = 0;
+
+ ret = kgsl_sysfs_store(buf, &thresh);
+ if (ret)
+ return ret;
kgsl_driver.full_cache_threshold = thresh;
-
return count;
}
diff --git a/drivers/gud/Makefile b/drivers/gud/Makefile
index ef0e083..c415ad8 100644
--- a/drivers/gud/Makefile
+++ b/drivers/gud/Makefile
@@ -3,34 +3,35 @@
#
GUD_ROOT_FOLDER := drivers/gud
# add our modules to kernel.
-obj-$(CONFIG_MOBICORE_API) += mckernelapi.o
-obj-$(CONFIG_MOBICORE_SUPPORT) += mcdrvmodule.o
+obj-$(CONFIG_MOBICORE_API) += mcKernelApi.o
+obj-$(CONFIG_MOBICORE_SUPPORT) += mcDrvModule.o
-mcdrvmodule-objs := mobicore_driver/logging.o \
- mobicore_driver/ops.o \
- mobicore_driver/mem.o \
- mobicore_driver/api.o \
- mobicore_driver/main.o \
- mobicore_driver/pm.o
+mcDrvModule-objs := MobiCoreDriver/logging.o \
+ MobiCoreDriver/ops.o \
+ MobiCoreDriver/mem.o \
+ MobiCoreDriver/api.o \
+ MobiCoreDriver/pm.o \
+ MobiCoreDriver/main.o
-mckernelapi-objs := mobicore_kernelapi/main.o \
- mobicore_kernelapi/clientlib.o \
- mobicore_kernelapi/device.o \
- mobicore_kernelapi/session.o \
- mobicore_kernelapi/connection.o
+mcKernelApi-objs := MobiCoreKernelApi/main.o \
+ MobiCoreKernelApi/clientlib.o \
+ MobiCoreKernelApi/device.o \
+ MobiCoreKernelApi/session.o \
+ MobiCoreKernelApi/connection.o
# Release mode by default
-ccflags-y := -DNDEBUG -include $(PWD)/$(GUD_ROOT_FOLDER)/mobicore_driver/build_tag.h
+ccflags-y := -DNDEBUG -I$(GUD_ROOT_FOLDER)
ccflags-y += -Wno-declaration-after-statement
ccflags-$(CONFIG_MOBICORE_DEBUG) += -DDEBUG
ccflags-$(CONFIG_MOBICORE_VERBOSE) += -DDEBUG_VERBOSE
# Choose one platform from the folder
-MOBICORE_PLATFORM := $(shell (ls -1 $(PWD)/$(GUD_ROOT_FOLDER)/mobicore_driver/platforms | tail -1) )
+MOBICORE_PLATFORM := $(shell (ls -1 $(PWD)/$(GUD_ROOT_FOLDER)/MobiCoreDriver/platforms | tail -1) )
# Use the available platform folder
-ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_driver/platforms/$(MOBICORE_PLATFORM)
-
-
-ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_driver/public
-ccflags-y += -I$(GUD_ROOT_FOLDER)/mobicore_kernelapi/include
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreDriver/platforms/$(MOBICORE_PLATFORM)
+# MobiCore Driver includes
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreDriver/public
+# MobiCore KernelApi required incldes
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreKernelApi/include
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreKernelApi/public
diff --git a/drivers/gud/MobiCoreDriver/Makefile b/drivers/gud/MobiCoreDriver/Makefile
new file mode 100644
index 0000000..c17f35e
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/Makefile
@@ -0,0 +1,26 @@
+#
+# this makefile is called from the kernel make system. Thus we basically
+# add things to "obj-m" here.
+
+ifeq ($(MODE),release)
+ ccflags-y = -O2 -DNDEBUG
+else
+ ccflags-y = -DDEBUG
+endif # DEBUG/RELEASE
+
+# CFLAGS from the build script
+ifdef MOBICORE_CFLAGS
+ ccflags-y += $(MOBICORE_CFLAGS)
+endif
+#EXTRA_CFLAGS+=-DDEBUG_VERBOSE
+
+ccflags-y += -I$(M) -Wall -D__$(PLATFORM)__
+# add our module to kernel.
+obj-m += mcDrvModule.o
+
+mcDrvModule-objs :=logging.o ops.o mem.o api.o pm.o main.o
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \
+ Module.markers Module.symvers modules.order
+
diff --git a/drivers/gud/mobicore_driver/api.c b/drivers/gud/MobiCoreDriver/api.c
similarity index 80%
rename from drivers/gud/mobicore_driver/api.c
rename to drivers/gud/MobiCoreDriver/api.c
index b47383a0..e7fa8e2 100644
--- a/drivers/gud/mobicore_driver/api.c
+++ b/drivers/gud/MobiCoreDriver/api.c
@@ -14,23 +14,12 @@
#include "mem.h"
#include "debug.h"
-
-/*
- * Map a virtual memory buffer structure to Mobicore
- * @param instance
- * @param addr address of the buffer(NB it must be kernel virtual!)
- * @param len buffer length
- * @param handle pointer to handle
- * @param phys_wsm_l2_table pointer to physical L2 table(?)
- *
- * @return 0 if no error
- *
- */
int mobicore_map_vmem(struct mc_instance *instance, void *addr,
- uint32_t len, uint32_t *handle, uint32_t *phys)
+ uint32_t len, uint32_t *handle)
{
- return mc_register_wsm_l2(instance, (uint32_t)addr, len,
- handle, phys);
+ phys_addr_t phys;
+ return mc_register_wsm_mmu(instance, addr, len,
+ handle, &phys);
}
EXPORT_SYMBOL(mobicore_map_vmem);
@@ -44,7 +33,7 @@
*/
int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle)
{
- return mc_unregister_wsm_l2(instance, handle);
+ return mc_unregister_wsm_mmu(instance, handle);
}
EXPORT_SYMBOL(mobicore_unmap_vmem);
@@ -70,13 +59,11 @@
* @param requested_size size of the WSM
* @param handle pointer where the handle will be saved
* @param virt_kernel_addr pointer for the kernel virtual address
- * @param phys_addr pointer for the physical address
*
* @return error code or 0 for success
*/
int mobicore_allocate_wsm(struct mc_instance *instance,
- unsigned long requested_size, uint32_t *handle, void **virt_kernel_addr,
- void **phys_addr)
+ unsigned long requested_size, uint32_t *handle, void **virt_kernel_addr)
{
struct mc_buffer *buffer = NULL;
@@ -85,7 +72,6 @@
return -EFAULT;
*handle = buffer->handle;
- *phys_addr = buffer->phys;
*virt_kernel_addr = buffer->addr;
return 0;
}
@@ -117,3 +103,14 @@
}
EXPORT_SYMBOL(mobicore_release);
+/*
+ * Test if mobicore can sleep
+ *
+ * @return true if mobicore can sleep, false if it can't sleep
+ */
+bool mobicore_sleep_ready(void)
+{
+ return mc_sleep_ready();
+}
+EXPORT_SYMBOL(mobicore_sleep_ready);
+
diff --git a/drivers/gud/mobicore_driver/arm.h b/drivers/gud/MobiCoreDriver/arm.h
similarity index 100%
rename from drivers/gud/mobicore_driver/arm.h
rename to drivers/gud/MobiCoreDriver/arm.h
diff --git a/drivers/gud/MobiCoreDriver/build.sh b/drivers/gud/MobiCoreDriver/build.sh
new file mode 100644
index 0000000..db8410c
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/build.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# source the setup script
+if [ -z $COMP_PATH_ROOT ]; then
+ echo "The build environment is not set!"
+ echo "Trying to source setupDrivers.sh automatically!"
+ source ../setupDrivers.sh || exit 1
+fi
+
+ROOT_PATH=$(dirname $(readlink -f $0))
+# These folders need to be relative to the kernel dir or absolute!
+PLATFORM=EXYNOS_5410_STD
+CODE_INCLUDE=$(readlink -f $ROOT_PATH/Locals/Code)
+PLATFORM_INCLUDE="$CODE_INCLUDE/platforms/$PLATFORM"
+MOBICORE_DAEMON=$COMP_PATH_MobiCoreDriverLib/Public
+
+MOBICORE_CFLAGS="-I$MOBICORE_DRIVER/Public -I$MOBICORE_DAEMON -I$COMP_PATH_MobiCore/inc/Mci -I$COMP_PATH_MobiCore/inc -I${PLATFORM_INCLUDE}"
+
+# Clean first
+make -C $CODE_INCLUDE clean
+
+make -C $LINUX_PATH \
+ MODE=$MODE \
+ ARCH=arm \
+ CROSS_COMPILE=$CROSS_COMPILE \
+ M=$CODE_INCLUDE \
+ "MOBICORE_CFLAGS=$MOBICORE_CFLAGS" \
+ modules
diff --git a/drivers/gud/mobicore_driver/debug.h b/drivers/gud/MobiCoreDriver/debug.h
similarity index 89%
rename from drivers/gud/mobicore_driver/debug.h
rename to drivers/gud/MobiCoreDriver/debug.h
index 1f9a632..d29efef 100644
--- a/drivers/gud/mobicore_driver/debug.h
+++ b/drivers/gud/MobiCoreDriver/debug.h
@@ -15,7 +15,7 @@
extern struct device *mcd;
#define MCDRV_DBG_ERROR(dev, txt, ...) \
- dev_err(dev, "MobiCore %s() ### ERROR: " txt, \
+ dev_err(dev, "MobiCore %s() ### ERROR: " txt "\n", \
__func__, \
##__VA_ARGS__)
@@ -32,12 +32,12 @@
#endif
#define MCDRV_DBG(dev, txt, ...) \
- dev_info(dev, "MobiCore %s(): " txt, \
+ dev_info(dev, "MobiCore %s(): " txt "\n", \
__func__, \
##__VA_ARGS__)
#define MCDRV_DBG_WARN(dev, txt, ...) \
- dev_warn(dev, "MobiCore %s() WARNING: " txt, \
+ dev_warn(dev, "MobiCore %s() WARNING: " txt "\n", \
__func__, \
##__VA_ARGS__)
diff --git a/drivers/gud/mobicore_driver/fastcall.h b/drivers/gud/MobiCoreDriver/fastcall.h
similarity index 70%
rename from drivers/gud/mobicore_driver/fastcall.h
rename to drivers/gud/MobiCoreDriver/fastcall.h
index 1c90520..33538df 100644
--- a/drivers/gud/mobicore_driver/fastcall.h
+++ b/drivers/gud/MobiCoreDriver/fastcall.h
@@ -36,9 +36,10 @@
*/
#define MC_FC_INIT -1
#define MC_FC_INFO -2
-#define MC_FC_POWER -3
-#define MC_FC_DUMP -4
#define MC_FC_NWD_TRACE -31 /* Mem trace setup fastcall */
+#ifdef TBASE_CORE_SWITCHER
+#define MC_FC_SWITCH_CORE 0x84000005
+#endif
/*
@@ -96,6 +97,23 @@
} as_out;
};
+#ifdef TBASE_CORE_SWITCHER
+/* fast call switch Core parameters */
+union mc_fc_swich_core {
+ union fc_generic as_generic;
+ struct {
+ uint32_t cmd;
+ uint32_t core_id;
+ uint32_t rfu[2];
+ } as_in;
+ struct {
+ uint32_t resp;
+ uint32_t ret;
+ uint32_t state;
+ uint32_t ext_info;
+ } as_out;
+};
+#endif
/*
* _smc() - fast call to MobiCore
*
@@ -104,23 +122,22 @@
static inline long _smc(void *data)
{
int ret = 0;
- union fc_generic fc_generic;
if (data == NULL)
return -EPERM;
#ifdef MC_SMC_FASTCALL
{
- ret = smc_fastcall(data, sizeof(fc_generic));
+ ret = smc_fastcall(data, sizeof(union fc_generic));
}
#else
- memcpy(&fc_generic, data, sizeof(union fc_generic));
{
- /* SVC expect values in r0-r3 */
- register u32 reg0 __asm__("r0") = fc_generic.as_in.cmd;
- register u32 reg1 __asm__("r1") = fc_generic.as_in.param[0];
- register u32 reg2 __asm__("r2") = fc_generic.as_in.param[1];
- register u32 reg3 __asm__("r3") = fc_generic.as_in.param[2];
+ union fc_generic *fc_generic = data;
+ /* SMC expect values in r0-r3 */
+ register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd;
+ register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0];
+ register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1];
+ register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2];
__asm__ volatile (
#ifdef MC_ARCH_EXTENSION_SEC
@@ -131,13 +148,23 @@
"smc 0\n"
: "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
);
+#ifdef __ARM_VE_A9X4_QEMU__
+ /* Qemu does not return to the address following the SMC
+ instruction so we have to insert several nop instructions to
+ workaround this Qemu bug. */
+ __asm__ volatile (
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop"
+ );
+#endif
/* set response */
- fc_generic.as_out.resp = reg0;
- fc_generic.as_out.ret = reg1;
- fc_generic.as_out.param[0] = reg2;
- fc_generic.as_out.param[1] = reg3;
- memcpy(data, &fc_generic, sizeof(union fc_generic));
+ fc_generic->as_out.resp = reg0;
+ fc_generic->as_out.ret = reg1;
+ fc_generic->as_out.param[0] = reg2;
+ fc_generic->as_out.param[1] = reg3;
}
#endif
return ret;
diff --git a/drivers/gud/mobicore_driver/logging.c b/drivers/gud/MobiCoreDriver/logging.c
similarity index 95%
rename from drivers/gud/mobicore_driver/logging.c
rename to drivers/gud/MobiCoreDriver/logging.c
index 1f599f9..507c4ed 100644
--- a/drivers/gud/mobicore_driver/logging.c
+++ b/drivers/gud/MobiCoreDriver/logging.c
@@ -251,7 +251,7 @@
*/
long mobicore_log_setup(void)
{
- unsigned long phys_log_buf;
+ phys_addr_t phys_log_buf;
union fc_generic fc_log;
struct sched_param param = { .sched_priority = 1 };
@@ -300,11 +300,12 @@
memset(&fc_log, 0, sizeof(fc_log));
fc_log.as_in.cmd = MC_FC_NWD_TRACE;
- fc_log.as_in.param[0] = phys_log_buf;
- fc_log.as_in.param[1] = log_size;
+ fc_log.as_in.param[0] = (uint32_t)phys_log_buf;
+ fc_log.as_in.param[1] = (uint32_t)(((uint64_t)phys_log_buf) >> 32);
+ fc_log.as_in.param[2] = log_size;
- MCDRV_DBG(mcd, "fc_log virt=%p phys=%p ",
- log_buf, (void *)phys_log_buf);
+ MCDRV_DBG(mcd, "fc_log virt=%p phys=0x%llX",
+ log_buf, (u64)phys_log_buf);
mc_fastcall(&fc_log);
MCDRV_DBG(mcd, "fc_log out ret=0x%08x", fc_log.as_out.ret);
@@ -319,7 +320,7 @@
set_task_state(log_thread, TASK_INTERRUPTIBLE);
- MCDRV_DBG(mcd, "fc_log Logger version %u\n", log_buf->version);
+ MCDRV_DBG(mcd, "fc_log Logger version %u", log_buf->version);
return 0;
err_stop_kthread:
diff --git a/drivers/gud/mobicore_driver/logging.h b/drivers/gud/MobiCoreDriver/logging.h
similarity index 100%
rename from drivers/gud/mobicore_driver/logging.h
rename to drivers/gud/MobiCoreDriver/logging.h
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/MobiCoreDriver/main.c
similarity index 81%
rename from drivers/gud/mobicore_driver/main.c
rename to drivers/gud/MobiCoreDriver/main.c
index 0451452..ed2928a 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/MobiCoreDriver/main.c
@@ -112,12 +112,12 @@
int i;
struct page *page = virt_to_page(addr);
for (i = 0; i < (1<<order); i++) {
- MCDRV_DBG_VERBOSE(mcd, "free page at 0x%p\n", page);
- ClearPageReserved(page);
+ MCDRV_DBG_VERBOSE(mcd, "free page at 0x%p", page);
+ clear_bit(PG_reserved, &page->flags);
page++;
}
- MCDRV_DBG_VERBOSE(mcd, "freeing addr:%p, order:%x\n", addr, order);
+ MCDRV_DBG_VERBOSE(mcd, "freeing addr:%p, order:%x", addr, order);
free_pages((unsigned long)addr, order);
}
@@ -131,8 +131,9 @@
return -EINVAL;
MCDRV_DBG_VERBOSE(mcd,
- "handle=%u phys_addr=0x%p, virt_addr=0x%p len=%u\n",
- buffer->handle, buffer->phys, buffer->addr, buffer->len);
+ "handle=%u phys_addr=0x%llx, virt_addr=0x%p len=%u",
+ buffer->handle, (u64)buffer->phys,
+ buffer->addr, buffer->len);
if (!atomic_dec_and_test(&buffer->usage)) {
MCDRV_DBG_VERBOSE(mcd, "Could not free %u", buffer->handle);
@@ -147,7 +148,7 @@
}
static uint32_t mc_find_cont_wsm_addr(struct mc_instance *instance, void *uaddr,
- uint32_t *addr, uint32_t len)
+ void **addr, uint32_t len)
{
int ret = 0;
struct mc_buffer *buffer;
@@ -162,7 +163,7 @@
/* search for the given handle in the buffers list */
list_for_each_entry(buffer, &ctx.cont_bufs, list) {
if (buffer->uaddr == uaddr && buffer->len == len) {
- *addr = (uint32_t)buffer->addr;
+ *addr = buffer->addr;
goto found;
}
}
@@ -186,7 +187,7 @@
struct task_struct *peer = NULL;
bool ret = false;
- MCDRV_DBG(mcd, "Finding wsm for fd = %d\n", fd);
+ MCDRV_DBG_VERBOSE(mcd, "Finding wsm for fd = %d", fd);
if (!instance)
return false;
@@ -197,7 +198,7 @@
s = __get_socket(fp);
if (s) {
peer = get_pid_task(s->sk_peer_pid, PIDTYPE_PID);
- MCDRV_DBG(mcd, "Found pid for fd %d\n", peer->pid);
+ MCDRV_DBG_VERBOSE(mcd, "Found pid for fd %d", peer->pid);
}
if (peer) {
task_lock(peer);
@@ -209,11 +210,10 @@
if (!fp)
continue;
if (fp->private_data == instance) {
- MCDRV_DBG(mcd, "Found owner!");
+ MCDRV_DBG_VERBOSE(mcd, "Found owner!");
ret = true;
goto out;
}
-
}
} else {
MCDRV_DBG(mcd, "Owner not found!");
@@ -230,7 +230,7 @@
#endif
}
static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle,
- int32_t fd, uint32_t *phys, uint32_t *len)
+ int32_t fd, phys_addr_t *phys, uint32_t *len)
{
int ret = 0;
struct mc_buffer *buffer;
@@ -239,7 +239,7 @@
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
@@ -251,7 +251,7 @@
list_for_each_entry(buffer, &ctx.cont_bufs, list) {
if (buffer->handle == handle) {
if (mc_check_owner_fd(buffer->instance, fd)) {
- *phys = (uint32_t)buffer->phys;
+ *phys = buffer->phys;
*len = buffer->len;
goto found;
} else {
@@ -326,7 +326,7 @@
/* Something is not right if we end up here, better not
* clean the buffer so we just leak memory instead of
* creating security issues */
- MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped\n");
+ MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped");
return -EINVAL;
}
}
@@ -370,7 +370,7 @@
{
struct mc_buffer *cbuffer = NULL;
void *addr = 0;
- void *phys = 0;
+ phys_addr_t phys = 0;
unsigned int order;
unsigned long allocated_size;
int ret = 0;
@@ -379,13 +379,13 @@
return -EFAULT;
if (len == 0) {
- MCDRV_DBG_WARN(mcd, "cannot allocate size 0\n");
+ MCDRV_DBG_WARN(mcd, "cannot allocate size 0");
return -ENOMEM;
}
order = get_order(len);
if (order > MAX_ORDER) {
- MCDRV_DBG_WARN(mcd, "Buffer size too large\n");
+ MCDRV_DBG_WARN(mcd, "Buffer size too large");
return -ENOMEM;
}
allocated_size = (1 << order) * PAGE_SIZE;
@@ -398,23 +398,23 @@
if (cbuffer == NULL) {
MCDRV_DBG_WARN(mcd,
- "MMAP_WSM request: could not allocate buffer\n");
+ "MMAP_WSM request: could not allocate buffer");
ret = -ENOMEM;
goto unlock_instance;
}
mutex_lock(&ctx.bufs_lock);
- MCDRV_DBG_VERBOSE(mcd, "size %ld -> order %d --> %ld (2^n pages)\n",
+ MCDRV_DBG_VERBOSE(mcd, "size %ld -> order %d --> %ld (2^n pages)",
len, order, allocated_size);
addr = (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order);
if (addr == NULL) {
- MCDRV_DBG_WARN(mcd, "get_free_pages failed\n");
+ MCDRV_DBG_WARN(mcd, "get_free_pages failed");
ret = -ENOMEM;
goto err;
}
- phys = (void *)virt_to_phys(addr);
+ phys = virt_to_phys(addr);
cbuffer->handle = get_unique_id();
cbuffer->phys = phys;
cbuffer->addr = addr;
@@ -429,9 +429,11 @@
list_add(&cbuffer->list, &ctx.cont_bufs);
MCDRV_DBG_VERBOSE(mcd,
- "allocated phys=0x%p - 0x%p, size=%ld, kvirt=0x%p, h=%d\n",
- phys, (void *)((unsigned int)phys+allocated_size),
- allocated_size, addr, cbuffer->handle);
+ "allocated phys=0x%llx - 0x%llx, size=%ld, kvirt=0x%p"
+ ", h=%d",
+ (u64)phys,
+ (u64)(phys+allocated_size),
+ allocated_size, addr, cbuffer->handle);
*buffer = cbuffer;
goto unlock;
@@ -457,7 +459,7 @@
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
@@ -476,7 +478,7 @@
return ret;
}
-void *get_mci_base_phys(unsigned int len)
+static phys_addr_t get_mci_base_phys(unsigned int len)
{
if (ctx.mci_base.phys) {
return ctx.mci_base.phys;
@@ -487,45 +489,45 @@
ctx.mci_base.addr =
(void *)__get_free_pages(GFP_USER | __GFP_ZERO, order);
if (ctx.mci_base.addr == NULL) {
- MCDRV_DBG_WARN(mcd, "get_free_pages failed\n");
+ MCDRV_DBG_WARN(mcd, "get_free_pages failed");
memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
- return NULL;
+ return 0;
}
- ctx.mci_base.phys = (void *)virt_to_phys(ctx.mci_base.addr);
+ ctx.mci_base.phys = virt_to_phys(ctx.mci_base.addr);
return ctx.mci_base.phys;
}
}
/*
- * Create a l2 table from a virtual memory buffer which can be vmalloc
+ * Create a MMU table from a virtual memory buffer which can be vmalloc
* or user space virtual memory
*/
-int mc_register_wsm_l2(struct mc_instance *instance,
- uint32_t buffer, uint32_t len,
- uint32_t *handle, uint32_t *phys)
+int mc_register_wsm_mmu(struct mc_instance *instance,
+ void *buffer, uint32_t len,
+ uint32_t *handle, phys_addr_t *phys)
{
int ret = 0;
- struct mc_l2_table *table = NULL;
+ struct mc_mmu_table *table = NULL;
struct task_struct *task = current;
- uint32_t kbuff = 0x0;
+ void *kbuff = NULL;
if (WARN(!instance, "No instance data available"))
return -EFAULT;
if (len == 0) {
- MCDRV_DBG_ERROR(mcd, "len=0 is not supported!\n");
+ MCDRV_DBG_ERROR(mcd, "len=0 is not supported!");
return -EINVAL;
}
- MCDRV_DBG_VERBOSE(mcd, "buffer: %p, len=%08x\n", (void *)buffer, len);
+ MCDRV_DBG_VERBOSE(mcd, "buffer: %p, len=%08x", buffer, len);
- if (!mc_find_cont_wsm_addr(instance, (void *)buffer, &kbuff, len))
- table = mc_alloc_l2_table(instance, NULL, (void *)kbuff, len);
+ if (!mc_find_cont_wsm_addr(instance, buffer, &kbuff, len))
+ table = mc_alloc_mmu_table(instance, NULL, kbuff, len);
else
- table = mc_alloc_l2_table(instance, task, (void *)buffer, len);
+ table = mc_alloc_mmu_table(instance, task, buffer, len);
if (IS_ERR(table)) {
- MCDRV_DBG_ERROR(mcd, "new_used_l2_table() failed\n");
+ MCDRV_DBG_ERROR(mcd, "mc_alloc_mmu_table() failed");
return -EINVAL;
}
@@ -533,19 +535,19 @@
*handle = table->handle;
/* WARNING: daemon shouldn't know this either, but live with it */
if (is_daemon(instance))
- *phys = (uint32_t)table->phys;
+ *phys = table->phys;
else
*phys = 0;
- MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=%p\n",
- *handle, (void *)*phys);
+ MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=0x%llX",
+ *handle, (u64)(*phys));
- MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
return ret;
}
-int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle)
+int mc_unregister_wsm_mmu(struct mc_instance *instance, uint32_t handle)
{
int ret = 0;
@@ -553,11 +555,11 @@
return -EFAULT;
/* free table (if no further locks exist) */
- mc_free_l2_table(instance, handle);
+ mc_free_mmu_table(instance, handle);
return ret;
}
-/* Lock the object from handle, it could be a WSM l2 table or a cont buffer! */
+/* Lock the object from handle, it could be a WSM MMU table or a cont buffer! */
static int mc_lock_handle(struct mc_instance *instance, uint32_t handle)
{
int ret = 0;
@@ -566,14 +568,14 @@
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
mutex_lock(&instance->lock);
- ret = mc_lock_l2_table(instance, handle);
+ ret = mc_lock_mmu_table(instance, handle);
- /* Handle was not a l2 table but a cont buffer */
+ /* Handle was not a MMU table but a cont buffer */
if (ret == -EINVAL) {
/* Call the non locking variant! */
ret = __lock_buffer(instance, handle);
@@ -592,14 +594,14 @@
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
mutex_lock(&instance->lock);
- ret = mc_free_l2_table(instance, handle);
+ ret = mc_free_mmu_table(instance, handle);
- /* Not a l2 table, then it must be a buffer */
+ /* Not a MMU table, then it must be a buffer */
if (ret == -EINVAL) {
/* Call the non locking variant! */
ret = __free_buffer(instance, handle, true);
@@ -609,35 +611,31 @@
return ret;
}
-static uint32_t mc_find_wsm_l2(struct mc_instance *instance,
+static phys_addr_t mc_find_wsm_mmu(struct mc_instance *instance,
uint32_t handle, int32_t fd)
{
- uint32_t ret = 0;
-
if (WARN(!instance, "No instance data available"))
return 0;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return 0;
}
- ret = mc_find_l2_table(handle, fd);
-
- return ret;
+ return mc_find_mmu_table(handle, fd);
}
-static int mc_clean_wsm_l2(struct mc_instance *instance)
+static int mc_clean_wsm_mmu(struct mc_instance *instance)
{
if (WARN(!instance, "No instance data available"))
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
- mc_clean_l2_tables();
+ mc_clean_mmu_tables();
return 0;
}
@@ -646,19 +644,20 @@
{
struct mc_instance *instance = get_instance(file);
unsigned long len = vmarea->vm_end - vmarea->vm_start;
- void *paddr = (void *)(vmarea->vm_pgoff << PAGE_SHIFT);
+ phys_addr_t paddr = (vmarea->vm_pgoff << PAGE_SHIFT);
unsigned int pfn;
struct mc_buffer *buffer = 0;
int ret = 0;
- MCDRV_DBG_VERBOSE(mcd, "enter (vma start=0x%p, size=%ld, mci=%p)\n",
- (void *)vmarea->vm_start, len, ctx.mci_base.phys);
+ MCDRV_DBG_VERBOSE(mcd, "enter (vma start=0x%p, size=%ld, mci=0x%llX)",
+ (void *)vmarea->vm_start, len,
+ (u64)ctx.mci_base.phys);
if (WARN(!instance, "No instance data available"))
return -EFAULT;
if (len == 0) {
- MCDRV_DBG_ERROR(mcd, "cannot allocate size 0\n");
+ MCDRV_DBG_ERROR(mcd, "cannot allocate size 0");
return -ENOMEM;
}
if (paddr) {
@@ -722,7 +721,7 @@
vmarea->vm_page_prot);
}
- MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
return ret;
}
@@ -768,21 +767,24 @@
case MC_IO_REG_WSM:{
struct mc_ioctl_reg_wsm reg;
+ phys_addr_t phys;
if (copy_from_user(®, uarg, sizeof(reg)))
return -EFAULT;
- ret = mc_register_wsm_l2(instance, reg.buffer,
- reg.len, ®.handle, ®.table_phys);
+ ret = mc_register_wsm_mmu(instance, (void *)reg.buffer,
+ reg.len, ®.handle, &phys);
+ reg.table_phys = phys;
+
if (!ret) {
if (copy_to_user(uarg, ®, sizeof(reg))) {
ret = -EFAULT;
- mc_unregister_wsm_l2(instance, reg.handle);
+ mc_unregister_wsm_mmu(instance, reg.handle);
}
}
break;
}
case MC_IO_UNREG_WSM:
- ret = mc_unregister_wsm_l2(instance, (uint32_t)arg);
+ ret = mc_unregister_wsm_mmu(instance, (uint32_t)arg);
break;
case MC_IO_VERSION:
@@ -803,7 +805,7 @@
return -EFAULT;
map.handle = buffer->handle;
- map.phys_addr = (unsigned long)buffer->phys;
+ map.phys_addr = buffer->phys;
map.reused = 0;
if (copy_to_user(uarg, &map, sizeof(map)))
ret = -EFAULT;
@@ -812,7 +814,7 @@
break;
}
default:
- MCDRV_DBG_ERROR(mcd, "unsupported cmd=%d\n", cmd);
+ MCDRV_DBG_ERROR(mcd, "unsupported cmd=0x%x", cmd);
ret = -ENOIOCTLCMD;
break;
@@ -836,7 +838,7 @@
return -EFAULT;
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
@@ -856,8 +858,8 @@
return -EFAULT;
ctx.mcp = ctx.mci_base.addr + init.mcp_offset;
- ret = mc_init((uint32_t)ctx.mci_base.phys, init.nq_offset,
- init.nq_length, init.mcp_offset, init.mcp_length);
+ ret = mc_init(ctx.mci_base.phys, init.nq_length,
+ init.mcp_offset, init.mcp_length);
break;
}
case MC_IO_INFO: {
@@ -890,14 +892,14 @@
ret = mc_unlock_handle(instance, (uint32_t)arg);
break;
case MC_IO_CLEAN_WSM:
- ret = mc_clean_wsm_l2(instance);
+ ret = mc_clean_wsm_mmu(instance);
break;
case MC_IO_RESOLVE_WSM: {
- uint32_t phys;
+ phys_addr_t phys;
struct mc_ioctl_resolv_wsm wsm;
if (copy_from_user(&wsm, uarg, sizeof(wsm)))
return -EFAULT;
- phys = mc_find_wsm_l2(instance, wsm.handle, wsm.fd);
+ phys = mc_find_wsm_mmu(instance, wsm.handle, wsm.fd);
if (!phys)
return -EINVAL;
@@ -909,7 +911,8 @@
}
case MC_IO_RESOLVE_CONT_WSM: {
struct mc_ioctl_resolv_cont_wsm cont_wsm;
- uint32_t phys = 0, len = 0;
+ phys_addr_t phys = 0;
+ uint32_t len = 0;
if (copy_from_user(&cont_wsm, uarg, sizeof(cont_wsm)))
return -EFAULT;
ret = mc_find_cont_wsm(instance, cont_wsm.handle, cont_wsm.fd,
@@ -928,7 +931,7 @@
return -EFAULT;
map.reused = (ctx.mci_base.phys != 0);
- map.phys_addr = (unsigned long)get_mci_base_phys(map.len);
+ map.phys_addr = get_mci_base_phys(map.len);
if (!map.phys_addr) {
MCDRV_DBG_ERROR(mcd, "Failed to setup MCI buffer!");
return -EFAULT;
@@ -939,10 +942,6 @@
ret = 0;
break;
}
- case MC_IO_MAP_PWSM:{
- break;
- }
-
case MC_IO_LOG_SETUP: {
#ifdef MC_MEM_TRACES
ret = mobicore_log_setup();
@@ -985,27 +984,27 @@
return -EFAULT;
/* avoid debug output on non-error, because this is call quite often */
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
+ MCDRV_DBG_VERBOSE(mcd, "enter");
/* only the MobiCore Daemon is allowed to call this function */
if (WARN_ON(!is_daemon(instance))) {
- MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon\n");
+ MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
return -EPERM;
}
if (buffer_len < sizeof(unsigned int)) {
- MCDRV_DBG_ERROR(mcd, "invalid length\n");
+ MCDRV_DBG_ERROR(mcd, "invalid length");
return -EINVAL;
}
for (;;) {
if (wait_for_completion_interruptible(&ctx.isr_comp)) {
- MCDRV_DBG_VERBOSE(mcd, "read interrupted\n");
+ MCDRV_DBG_VERBOSE(mcd, "read interrupted");
return -ERESTARTSYS;
}
ssiq_counter = atomic_read(&ctx.isr_counter);
- MCDRV_DBG_VERBOSE(mcd, "ssiq_counter=%i, ctx.counter=%i\n",
+ MCDRV_DBG_VERBOSE(mcd, "ssiq_counter=%i, ctx.counter=%i",
ssiq_counter, ctx.evt_counter);
if (ssiq_counter != ctx.evt_counter) {
@@ -1017,12 +1016,12 @@
/* end loop if non-blocking */
if (file->f_flags & O_NONBLOCK) {
- MCDRV_DBG_ERROR(mcd, "non-blocking read\n");
+ MCDRV_DBG_ERROR(mcd, "non-blocking read");
return -EAGAIN;
}
if (signal_pending(current)) {
- MCDRV_DBG_VERBOSE(mcd, "received signal.\n");
+ MCDRV_DBG_VERBOSE(mcd, "received signal.");
return -ERESTARTSYS;
}
}
@@ -1031,7 +1030,7 @@
ret = copy_to_user(buffer, &ctx.evt_counter, sizeof(unsigned int));
if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "copy_to_user failed\n");
+ MCDRV_DBG_ERROR(mcd, "copy_to_user failed");
return -EFAULT;
}
@@ -1061,6 +1060,43 @@
return instance;
}
+#if defined(TBASE_CORE_SWITCHER) && defined(DEBUG)
+static ssize_t mc_fd_write(struct file *file, const char __user *buffer,
+ size_t buffer_len, loff_t *x)
+{
+ uint32_t cpu_new;
+ /* we only consider one digit */
+ char buf[2];
+ struct mc_instance *instance = get_instance(file);
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ /* Invalid data, nothing to do */
+ if (buffer_len < 1)
+ return -EINVAL;
+
+ /* Invalid data, nothing to do */
+ if (copy_from_user(buf, buffer, min(sizeof(buf), buffer_len)))
+ return -EFAULT;
+
+ if (buf[0] == 'n') {
+ mc_nsiq();
+ /* If it's a digit then switch cores */
+ } else if ((buf[0] >= '0') && (buf[0] <= '9')) {
+ cpu_new = buf[0] - '0';
+ if (cpu_new <= 8) {
+ MCDRV_DBG_VERBOSE(mcd, "Set Active Cpu: %d\n", cpu_new);
+ mc_switch_core(cpu_new);
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return buffer_len;
+}
+#endif
+
/*
* Release a mobicore instance object and all objects related to it
* @instance: instance
@@ -1074,7 +1110,7 @@
return -EFAULT;
mutex_lock(&instance->lock);
- mc_clear_l2_tables(instance);
+ mc_clear_mmu_tables(instance);
mutex_lock(&ctx.bufs_lock);
/* release all mapped data */
@@ -1112,7 +1148,7 @@
{
struct mc_instance *instance;
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
+ MCDRV_DBG_VERBOSE(mcd, "enter");
instance = mc_alloc_instance();
if (instance == NULL)
@@ -1141,7 +1177,7 @@
return -ENOMEM;
instance = get_instance(file);
- MCDRV_DBG(mcd, "accept this as MobiCore Daemon\n");
+ MCDRV_DBG(mcd, "accept this as MobiCore Daemon");
ctx.daemon_inst = instance;
ctx.daemon = current;
@@ -1172,7 +1208,7 @@
/* check if daemon closes us. */
if (is_daemon(instance)) {
- MCDRV_DBG_WARN(mcd, "WARNING: MobiCore Daemon died\n");
+ MCDRV_DBG_WARN(mcd, "MobiCore Daemon died");
ctx.daemon_inst = NULL;
ctx.daemon = NULL;
}
@@ -1183,7 +1219,7 @@
* ret is quite irrelevant here as most apps don't care about the
* return value from close() and it's quite difficult to recover
*/
- MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
return (int)ret;
}
@@ -1200,7 +1236,9 @@
/* signal the daemon */
complete(&ctx.isr_comp);
-
+#ifdef MC_MEM_TRACES
+ mobicore_log_read();
+#endif
return IRQ_HANDLED;
}
@@ -1221,6 +1259,9 @@
.release = mc_fd_release,
.unlocked_ioctl = mc_fd_user_ioctl,
.mmap = mc_fd_mmap,
+#if defined(TBASE_CORE_SWITCHER) && defined(DEBUG)
+ .write = mc_fd_write,
+#endif
};
static int create_devices(void)
@@ -1239,17 +1280,17 @@
ret = alloc_chrdev_region(&mc_dev_admin, 0, MC_DEV_MAX, "mobicore");
if (ret < 0) {
- MCDRV_DBG_ERROR(mcd, "failed to allocate char dev region\n");
+ MCDRV_DBG_ERROR(mcd, "failed to allocate char dev region");
goto error;
}
mc_dev_user = MKDEV(MAJOR(mc_dev_admin), 1);
- MCDRV_DBG_VERBOSE(mcd, "%s: dev %d", "mobicore", MAJOR(mc_dev_region));
+ MCDRV_DBG_VERBOSE(mcd, "%s: dev %d", "mobicore", MAJOR(mc_dev_admin));
/* First the ADMIN node */
ret = cdev_add(&mc_admin_cdev, mc_dev_admin, 1);
if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "admin device register failed\n");
+ MCDRV_DBG_ERROR(mcd, "admin device register failed");
goto error;
}
mc_admin_cdev.owner = THIS_MODULE;
@@ -1260,7 +1301,7 @@
ret = cdev_add(&mc_user_cdev, mc_dev_user, 1);
if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "user device register failed\n");
+ MCDRV_DBG_ERROR(mcd, "user device register failed");
goto error_unregister;
}
mc_user_cdev.owner = THIS_MODULE;
@@ -1301,13 +1342,13 @@
/* Hardware does not support ARM TrustZone -> Cannot continue! */
if (!has_security_extensions()) {
MCDRV_DBG_ERROR(mcd,
- "Hardware doesn't support ARM TrustZone!\n");
+ "Hardware doesn't support ARM TrustZone!");
return -ENODEV;
}
/* Running in secure mode -> Cannot load the driver! */
if (is_secure_mode()) {
- MCDRV_DBG_ERROR(mcd, "Running in secure MODE!\n");
+ MCDRV_DBG_ERROR(mcd, "Running in secure MODE!");
return -ENODEV;
}
@@ -1320,18 +1361,18 @@
/* initialize event counter for signaling of an IRQ to zero */
atomic_set(&ctx.isr_counter, 0);
- /* set up S-SIQ interrupt handler */
+ /* set up S-SIQ interrupt handler ************************/
ret = request_irq(MC_INTR_SSIQ, mc_ssiq_isr, IRQF_TRIGGER_RISING,
MC_ADMIN_DEVNODE, &ctx);
if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "interrupt request failed\n");
+ MCDRV_DBG_ERROR(mcd, "interrupt request failed");
goto err_req_irq;
}
#ifdef MC_PM_RUNTIME
ret = mc_pm_initialize(&ctx);
if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "Power Management init failed!\n");
+ MCDRV_DBG_ERROR(mcd, "Power Management init failed!");
goto free_isr;
}
#endif
@@ -1340,7 +1381,7 @@
if (ret != 0)
goto free_pm;
- ret = mc_init_l2_tables();
+ ret = mc_init_mmu_tables();
#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
ret = mc_pm_clock_initialize();
@@ -1361,7 +1402,7 @@
mutex_init(&ctx.bufs_lock);
memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
- MCDRV_DBG(mcd, "initialized\n");
+ MCDRV_DBG(mcd, "initialized");
return 0;
free_pm:
@@ -1381,12 +1422,12 @@
*/
static void __exit mobicore_exit(void)
{
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
+ MCDRV_DBG_VERBOSE(mcd, "enter");
#ifdef MC_MEM_TRACES
mobicore_log_free();
#endif
- mc_release_l2_tables();
+ mc_release_mmu_tables();
#ifdef MC_PM_RUNTIME
mc_pm_free();
@@ -1408,6 +1449,15 @@
MCDRV_DBG_VERBOSE(mcd, "exit");
}
+bool mc_sleep_ready(void)
+{
+#ifdef MC_PM_RUNTIME
+ return mc_pm_sleep_ready();
+#else
+ return true;
+#endif
+}
+
/* Linux Driver Module Macros */
module_init(mobicore_init);
module_exit(mobicore_exit);
diff --git a/drivers/gud/mobicore_driver/main.h b/drivers/gud/MobiCoreDriver/main.h
similarity index 89%
rename from drivers/gud/mobicore_driver/main.h
rename to drivers/gud/MobiCoreDriver/main.h
index 871191e..11e304c 100644
--- a/drivers/gud/mobicore_driver/main.h
+++ b/drivers/gud/MobiCoreDriver/main.h
@@ -52,7 +52,7 @@
/* virtual Userspace start address */
void *uaddr;
/* physical start address */
- void *phys;
+ phys_addr_t phys;
/* order of number of pages */
unsigned int order;
uint32_t len;
@@ -83,8 +83,8 @@
};
struct mc_sleep_mode {
- uint16_t SleepReq;
- uint16_t ReadyToSleep;
+ uint16_t sleep_req;
+ uint16_t ready_to_sleep;
};
/* MobiCore is idle. No scheduling required. */
@@ -129,14 +129,14 @@
int mc_release_instance(struct mc_instance *instance);
/*
- * mc_register_wsm_l2() - Create a L2 table from a virtual memory buffer which
+ * mc_register_wsm_mmu() - Create a MMU table from a virtual memory buffer which
* can be vmalloc or user space virtual memory
*/
-int mc_register_wsm_l2(struct mc_instance *instance,
- uint32_t buffer, uint32_t len,
- uint32_t *handle, uint32_t *phys);
+int mc_register_wsm_mmu(struct mc_instance *instance,
+ void *buffer, uint32_t len,
+ uint32_t *handle, phys_addr_t *phys);
/* Unregister the buffer mapped above */
-int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle);
+int mc_unregister_wsm_mmu(struct mc_instance *instance, uint32_t handle);
/* Allocate one mc_buffer of contiguous space */
int mc_get_buffer(struct mc_instance *instance,
@@ -147,4 +147,7 @@
/* Check if the other end of the fd owns instance */
bool mc_check_owner_fd(struct mc_instance *instance, int32_t fd);
+/* Test if sleep is possible */
+bool mc_sleep_ready(void);
+
#endif /* _MC_MAIN_H_ */
diff --git a/drivers/gud/MobiCoreDriver/mem.c b/drivers/gud/MobiCoreDriver/mem.c
new file mode 100644
index 0000000..2d92f74
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/mem.c
@@ -0,0 +1,743 @@
+/*
+ * MobiCore Driver Kernel Module.
+ *
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "main.h"
+#include "debug.h"
+#include "mem.h"
+
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/pagemap.h>
+#include <linux/device.h>
+
+#ifdef LPAE_SUPPORT
+#define MMU_TYPE_PAGE (3 << 0)
+#define MMU_BUFFERABLE (1 << 2) /* AttrIndx[0] */
+#define MMU_CACHEABLE (1 << 3) /* AttrIndx[1] */
+#define MMU_NS (1 << 5)
+#define MMU_AP_RW_ALL (1 << 6) /* AP[2:1], RW, at any privilege level */
+#define MMU_EXT_SHARED (3 << 8) /* SH[1:0], inner shareable */
+#define MMU_EXT_AF (1 << 10) /* Access Flag */
+#define MMU_EXT_NG (1 << 11)
+#define MMU_EXT_XN (((uint64_t)1) << 54) /* XN */
+#else
+#define MMU_TYPE_EXT (3 << 0) /* v5 */
+#define MMU_TYPE_SMALL (2 << 0)
+#define MMU_BUFFERABLE (1 << 2)
+#define MMU_CACHEABLE (1 << 3)
+#define MMU_EXT_AP0 (1 << 4)
+#define MMU_EXT_AP1 (2 << 4)
+#define MMU_EXT_TEX(x) ((x) << 6) /* v5 */
+#define MMU_EXT_SHARED (1 << 10) /* v6 */
+#define MMU_EXT_NG (1 << 11) /* v6 */
+#endif
+
+/* MobiCore memory context data */
+struct mc_mem_context mem_ctx;
+
+static inline void release_page(struct page *page)
+{
+ set_bit(PG_dirty, &page->flags);
+
+ page_cache_release(page);
+}
+
+static int lock_pages(struct task_struct *task, void *virt_start_page_addr,
+ int pages_no, struct page **pages)
+{
+ int locked_pages;
+
+ /* lock user pages, must hold the mmap_sem to do this. */
+ down_read(&(task->mm->mmap_sem));
+ locked_pages = get_user_pages(
+ task,
+ task->mm,
+ (unsigned long)virt_start_page_addr,
+ pages_no,
+ 1, /* write access */
+ 0,
+ pages,
+ NULL);
+ up_read(&(task->mm->mmap_sem));
+
+ /* check if we could lock all pages. */
+ if (locked_pages != pages_no) {
+ MCDRV_DBG_ERROR(mcd, "get_user_pages() failed, locked_pages=%d",
+ locked_pages);
+ if (locked_pages > 0) {
+ /* release all locked pages. */
+ release_pages(pages, locked_pages, 0);
+ }
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* Get kernel pointer to shared MMU table given a per-process reference */
+static void *get_mmu_table_kernel_virt(struct mc_mmu_table *table)
+{
+ if (WARN(!table, "Invalid MMU table"))
+ return NULL;
+
+ if (WARN(!table->set, "Invalid MMU table set"))
+ return NULL;
+
+ if (WARN(!table->set->kernel_virt, "Invalid MMU pointer"))
+ return NULL;
+
+ return &(table->set->kernel_virt->table[table->idx]);
+}
+
+static inline int in_use(struct mc_mmu_table *table)
+{
+ return atomic_read(&table->usage) > 0;
+}
+
+/*
+ * Search the list of used MMU tables and return the one with the handle.
+ * Assumes the table_lock is taken.
+ */
+struct mc_mmu_table *find_mmu_table(unsigned int handle)
+{
+ struct mc_mmu_table *table;
+
+ list_for_each_entry(table, &mem_ctx.mmu_tables, list) {
+ if (table->handle == handle)
+ return table;
+ }
+ return NULL;
+}
+
+/*
+ * Allocate a new MMU table store plus MMU_TABLES_PER_PAGE in the MMU free
+ * tables list. Assumes the table_lock is already taken by the caller above.
+ */
+static int alloc_mmu_table_store(void)
+{
+ unsigned long store;
+ struct mc_mmu_tables_set *mmutable_set;
+ struct mc_mmu_table *mmutable, *mmutable2;
+ struct page *page;
+ int ret = 0, i;
+ /* temp list for holding the MMU tables */
+ LIST_HEAD(temp);
+
+ store = get_zeroed_page(GFP_KERNEL);
+ if (!store)
+ return -ENOMEM;
+
+ /*
+ * Actually, locking is not necessary, because kernel
+ * memory is not supposed to get swapped out. But we
+ * play safe....
+ */
+ page = virt_to_page(store);
+ set_bit(PG_reserved, &page->flags);
+
+ /* add all the descriptors to the free descriptors list */
+ mmutable_set = kmalloc(sizeof(*mmutable_set), GFP_KERNEL | __GFP_ZERO);
+ if (mmutable_set == NULL) {
+ ret = -ENOMEM;
+ goto free_store;
+ }
+ /* initialize */
+ mmutable_set->kernel_virt = (void *)store;
+ mmutable_set->page = page;
+ mmutable_set->phys = virt_to_phys((void *)store);
+ /* the set is not yet used */
+ atomic_set(&mmutable_set->used_tables, 0);
+
+ /* init add to list. */
+ INIT_LIST_HEAD(&(mmutable_set->list));
+ list_add(&mmutable_set->list, &mem_ctx.mmu_tables_sets);
+
+ for (i = 0; i < MMU_TABLES_PER_PAGE; i++) {
+ /* allocate a WSM MMU descriptor */
+ mmutable = kmalloc(sizeof(*mmutable), GFP_KERNEL | __GFP_ZERO);
+ if (mmutable == NULL) {
+ ret = -ENOMEM;
+ MCDRV_DBG_ERROR(mcd, "out of memory");
+ /* Free the full temp list and the store in this case */
+ goto free_temp_list;
+ }
+
+ /* set set reference */
+ mmutable->set = mmutable_set;
+ mmutable->idx = i;
+ mmutable->virt = get_mmu_table_kernel_virt(mmutable);
+ mmutable->phys = mmutable_set->phys+i*sizeof(struct mmutable);
+ atomic_set(&mmutable->usage, 0);
+
+ /* add to temp list. */
+ INIT_LIST_HEAD(&mmutable->list);
+ list_add_tail(&mmutable->list, &temp);
+ }
+
+ /*
+ * If everything went ok then merge the temp list with the global
+ * free list
+ */
+ list_splice_tail(&temp, &mem_ctx.free_mmu_tables);
+ return 0;
+free_temp_list:
+ list_for_each_entry_safe(mmutable, mmutable2, &temp, list) {
+ kfree(mmutable);
+ }
+
+ list_del(&mmutable_set->list);
+
+free_store:
+ free_page(store);
+ return ret;
+}
+/*
+ * Get a MMU table from the free tables list or allocate a new one and
+ * initialize it. Assumes the table_lock is already taken.
+ */
+static struct mc_mmu_table *alloc_mmu_table(struct mc_instance *instance)
+{
+ int ret = 0;
+ struct mc_mmu_table *table = NULL;
+
+ if (list_empty(&mem_ctx.free_mmu_tables)) {
+ ret = alloc_mmu_table_store();
+ if (ret) {
+ MCDRV_DBG_ERROR(mcd, "Failed to allocate new store!");
+ return ERR_PTR(-ENOMEM);
+ }
+ /* if it's still empty something wrong has happened */
+ if (list_empty(&mem_ctx.free_mmu_tables)) {
+ MCDRV_DBG_ERROR(mcd,
+ "Free list not updated correctly!");
+ return ERR_PTR(-EFAULT);
+ }
+ }
+
+ /* get a WSM MMU descriptor */
+ table = list_first_entry(&mem_ctx.free_mmu_tables,
+ struct mc_mmu_table, list);
+ if (table == NULL) {
+ MCDRV_DBG_ERROR(mcd, "out of memory");
+ return ERR_PTR(-ENOMEM);
+ }
+ /* Move it to the used MMU tables list */
+ list_move_tail(&table->list, &mem_ctx.mmu_tables);
+
+ table->handle = get_unique_id();
+ table->owner = instance;
+
+ atomic_inc(&table->set->used_tables);
+ atomic_inc(&table->usage);
+
+ MCDRV_DBG_VERBOSE(mcd,
+ "chunkPhys=0x%llX, idx=%d",
+ (u64)table->set->phys, table->idx);
+
+ return table;
+}
+
+/*
+ * Frees the object associated with a MMU table. Initially the object is moved
+ * to the free tables list, but if all the 4 lists of the store are free
+ * then the store is also released.
+ * Assumes the table_lock is already taken.
+ */
+static void free_mmu_table(struct mc_mmu_table *table)
+{
+ struct mc_mmu_tables_set *mmutable_set;
+
+ if (WARN(!table, "Invalid table"))
+ return;
+
+ mmutable_set = table->set;
+ if (WARN(!mmutable_set, "Invalid table set"))
+ return;
+
+ list_move_tail(&table->list, &mem_ctx.free_mmu_tables);
+
+ /* if nobody uses this set, we can release it. */
+ if (atomic_dec_and_test(&mmutable_set->used_tables)) {
+ struct mc_mmu_table *tmp;
+
+ /* remove from list */
+ list_del(&mmutable_set->list);
+ /*
+ * All the MMU tables are in the free list for this set
+ * so we can just remove them from there
+ */
+ list_for_each_entry_safe(table, tmp, &mem_ctx.free_mmu_tables,
+ list) {
+ if (table->set == mmutable_set) {
+ list_del(&table->list);
+ kfree(table);
+ }
+ } /* end while */
+
+ /*
+ * We shouldn't recover from this since it was some data
+ * corruption before
+ */
+ BUG_ON(!mmutable_set->page);
+ clear_bit(PG_reserved, &(mmutable_set->page)->flags);
+
+
+ BUG_ON(!mmutable_set->kernel_virt);
+ free_page((unsigned long)mmutable_set->kernel_virt);
+
+ kfree(mmutable_set);
+ }
+}
+
+/*
+ * Create a MMU table in a WSM container that has been allocates previously.
+ * Assumes the table lock is already taken or there is no need to take like
+ * when first creating the MMU table the full list is locked.
+ *
+ * @task pointer to task owning WSM
+ * @wsm_buffer user space WSM start
+ * @wsm_len WSM length
+ * @table Pointer to MMU table details
+ */
+static int map_buffer(struct task_struct *task, void *wsm_buffer,
+ unsigned int wsm_len, struct mc_mmu_table *table)
+{
+ int ret = 0;
+ unsigned int i, nr_of_pages;
+ /* start address of the 4 KiB page of wsm_buffer */
+ void *virt_addr_page;
+ struct page *page;
+ struct mmutable *mmutable;
+ struct page **mmutable_as_array_of_pointers_to_page;
+ /* page offset in wsm buffer */
+ unsigned int offset;
+
+ if (WARN(!wsm_buffer, "Invalid WSM buffer pointer"))
+ return -EINVAL;
+
+ if (WARN(wsm_len == 0, "Invalid WSM buffer length"))
+ return -EINVAL;
+
+ if (WARN(!table, "Invalid mapping table for WSM"))
+ return -EINVAL;
+
+ /* no size > 1Mib supported */
+ if (wsm_len > SZ_1M) {
+ MCDRV_DBG_ERROR(mcd, "size > 1 MiB");
+ return -EINVAL;
+ }
+
+ MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x", wsm_buffer,
+ wsm_len);
+
+ /* calculate page usage */
+ virt_addr_page = (void *)(((unsigned long)(wsm_buffer)) & PAGE_MASK);
+ offset = (unsigned int) (((unsigned long)(wsm_buffer)) & (~PAGE_MASK));
+ nr_of_pages = PAGE_ALIGN(offset + wsm_len) / PAGE_SIZE;
+
+ MCDRV_DBG_VERBOSE(mcd, "virt addr page start=0x%p, pages=%d",
+ virt_addr_page, nr_of_pages);
+
+ /* MMU table can hold max 1MiB in 256 pages. */
+ if ((nr_of_pages * PAGE_SIZE) > SZ_1M) {
+ MCDRV_DBG_ERROR(mcd, "WSM paged exceed 1 MiB");
+ return -EINVAL;
+ }
+
+ mmutable = table->virt;
+ /*
+ * We use the memory for the MMU table to hold the pointer
+ * and convert them later. This works, as everything comes
+ * down to a 32 bit value.
+ */
+ mmutable_as_array_of_pointers_to_page = (struct page **)mmutable;
+
+ /* Request comes from user space */
+ if (task != NULL && !is_vmalloc_addr(wsm_buffer)) {
+ /*
+ * lock user page in memory, so they do not get swapped
+ * out.
+ * REV axh: Kernel 2.6.27 added a new get_user_pages_fast()
+ * function, maybe it is called fast_gup() in some versions.
+ * handle user process doing a fork().
+ * Child should not get things.
+ * http://osdir.com/ml/linux-media/2009-07/msg00813.html
+ * http://lwn.net/Articles/275808/
+ */
+ ret = lock_pages(task, virt_addr_page, nr_of_pages,
+ mmutable_as_array_of_pointers_to_page);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "lock_user_pages() failed");
+ return ret;
+ }
+ }
+ /* Request comes from kernel space(cont buffer) */
+ else if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
+ void *uaddr = wsm_buffer;
+ for (i = 0; i < nr_of_pages; i++) {
+ page = virt_to_page(uaddr);
+ if (!page) {
+ MCDRV_DBG_ERROR(mcd, "failed to map address");
+ return -EINVAL;
+ }
+ get_page(page);
+ mmutable_as_array_of_pointers_to_page[i] = page;
+ uaddr += PAGE_SIZE;
+ }
+ }
+ /* Request comes from kernel space(vmalloc buffer) */
+ else {
+ void *uaddr = wsm_buffer;
+ for (i = 0; i < nr_of_pages; i++) {
+ page = vmalloc_to_page(uaddr);
+ if (!page) {
+ MCDRV_DBG_ERROR(mcd, "failed to map address");
+ return -EINVAL;
+ }
+ get_page(page);
+ mmutable_as_array_of_pointers_to_page[i] = page;
+ uaddr += PAGE_SIZE;
+ }
+ }
+
+ table->pages = nr_of_pages;
+
+ /*
+ * create MMU Table entries.
+ * used_mmutable->table contains a list of page pointers here.
+ * For a proper cleanup we have to ensure that the following
+ * code either works and used_mmutable contains a valid MMU table
+ * - or fails and used_mmutable->table contains the list of page
+ * pointers.
+ * Any mixed contents will make cleanup difficult.
+ * Fill the table in reverse order as the table is used as input and
+ * output.
+ */
+ i = MC_ARM_MMU_TABLE_ENTRIES-1;
+ do {
+ if (i < nr_of_pages) {
+#ifdef LPAE_SUPPORT
+ uint64_t pte;
+#elif defined(CONFIG_ARM_LPAE) && !defined(LPAE_SUPPORT)
+ /* Nwd supports 64bit addresses, SWD only 32bit */
+ uint64_t pte64;
+ uint32_t pte;
+#else
+ uint32_t pte;
+#endif
+ page = mmutable_as_array_of_pointers_to_page[i];
+
+ /*
+ * create MMU table entry, see ARM MMU docu for details
+ * about flags stored in the lowest 12 bits.
+ * As a side reference, the Article
+ * "ARM's multiply-mapped memory mess"
+ * found in the collection at
+ * http://lwn.net/Articles/409032/
+ * is also worth reading.
+ */
+#ifdef LPAE_SUPPORT
+ pte = page_to_phys(page);
+ pte |= MMU_EXT_XN
+ | MMU_EXT_NG
+ | MMU_EXT_AF
+ | MMU_AP_RW_ALL
+ | MMU_NS
+ | MMU_CACHEABLE | MMU_BUFFERABLE
+ | MMU_TYPE_PAGE;
+#elif defined(CONFIG_ARM_LPAE) && !defined(LPAE_SUPPORT)
+ /*
+ * NWD uses 64bit addresses but SWD can handle only
+ * short descriptors
+ * and physical addresses not bigger than 4GB
+ */
+ pte64 = page_to_phys(page);
+ if ((pte64 >> 32) != 0) {
+ MCDRV_DBG_ERROR(mcd,
+ "physical addresses bigger than 4GB not supported");
+ return -EINVAL;
+ }
+ pte = (uint32_t)pte64;
+ pte |= MMU_EXT_AP1 | MMU_EXT_AP0
+ | MMU_CACHEABLE | MMU_BUFFERABLE
+ | MMU_TYPE_SMALL | MMU_TYPE_EXT | MMU_EXT_NG;
+#else
+ pte = page_to_phys(page);
+ pte |= MMU_EXT_AP1 | MMU_EXT_AP0
+ | MMU_CACHEABLE | MMU_BUFFERABLE
+ | MMU_TYPE_SMALL | MMU_TYPE_EXT | MMU_EXT_NG;
+#endif /* LPAE_SUPPORT */
+ /*
+ * Linux uses different mappings for SMP systems(the
+ * sharing flag is set for the pte. In order not to
+ * confuse things too much in Mobicore make sure the
+ * shared buffers have the same flags.
+ * This should also be done in SWD side
+ */
+#ifdef CONFIG_SMP
+#ifdef LPAE_SUPPORT
+ pte |= MMU_EXT_SHARED;
+#else
+ pte |= MMU_EXT_SHARED | MMU_EXT_TEX(1);
+#endif /* LPAE_SUPPORT */
+#endif /* CONFIG_SMP */
+
+ mmutable->table_entries[i] = pte;
+ MCDRV_DBG_VERBOSE(mcd, "MMU entry %d: 0x%llx", i,
+ (u64)(pte));
+ } else {
+ /* ensure rest of table is empty */
+ mmutable->table_entries[i] = 0;
+ }
+ } while (i-- != 0);
+
+ return ret;
+}
+
+/*
+ * Remove a MMU table in a WSM container. Afterwards the container may be
+ * released. Assumes the table_lock and the lock is taken.
+ */
+static void unmap_buffers(struct mc_mmu_table *table)
+{
+ struct mmutable *mmutable;
+ int i;
+
+ if (WARN_ON(!table))
+ return;
+
+ /* found the table, now release the resources. */
+ MCDRV_DBG_VERBOSE(mcd,
+ "clear MMU table, phys_base=0x%llX,nr_of_pages=%d",
+ (u64)table->phys, table->pages);
+
+ mmutable = table->virt;
+
+ /* release all locked user space pages */
+ for (i = 0; i < table->pages; i++) {
+ /* convert physical entries from MMU table to page pointers */
+ struct page *page;
+ page = phys_to_page(mmutable->table_entries[i]);
+ release_page(page);
+ }
+
+ /* remember that all pages have been freed */
+ table->pages = 0;
+}
+
+/* Delete a used MMU table. Assumes the table_lock and the lock is taken */
+static void unmap_mmu_table(struct mc_mmu_table *table)
+{
+ /* Check if it's not locked by other processes too! */
+ if (!atomic_dec_and_test(&table->usage))
+ return;
+
+ /* release if Nwd and Swd/MC do no longer use it. */
+ unmap_buffers(table);
+ free_mmu_table(table);
+}
+
+int mc_free_mmu_table(struct mc_instance *instance, uint32_t handle)
+{
+ struct mc_mmu_table *table;
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_mmu_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_VERBOSE(mcd, "entry not found");
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+ if (instance != table->owner && !is_daemon(instance)) {
+ MCDRV_DBG_ERROR(mcd, "instance does no own it");
+ ret = -EPERM;
+ goto err_unlock;
+ }
+ /* free table (if no further locks exist) */
+ unmap_mmu_table(table);
+err_unlock:
+ mutex_unlock(&mem_ctx.table_lock);
+
+ return ret;
+}
+
+int mc_lock_mmu_table(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+ struct mc_mmu_table *table = NULL;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_mmu_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_VERBOSE(mcd, "entry not found %u", handle);
+ ret = -EINVAL;
+ goto table_err;
+ }
+ if (instance != table->owner && !is_daemon(instance)) {
+ MCDRV_DBG_ERROR(mcd, "instance does no own it");
+ ret = -EPERM;
+ goto table_err;
+ }
+
+ /* lock entry */
+ atomic_inc(&table->usage);
+table_err:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ret;
+}
+/*
+ * Allocate MMU table and map buffer into it.
+ * That is, create respective table entries.
+ */
+struct mc_mmu_table *mc_alloc_mmu_table(struct mc_instance *instance,
+ struct task_struct *task, void *wsm_buffer, unsigned int wsm_len)
+{
+ int ret = 0;
+ struct mc_mmu_table *table;
+
+ if (WARN(!instance, "No instance data available"))
+ return ERR_PTR(-EFAULT);
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = alloc_mmu_table(instance);
+ if (IS_ERR(table)) {
+ MCDRV_DBG_ERROR(mcd, "alloc_mmu_table() failed");
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ /* create the MMU page for the WSM */
+ ret = map_buffer(task, wsm_buffer, wsm_len, table);
+
+ if (ret != 0) {
+ MCDRV_DBG_ERROR(mcd, "map_buffer() failed");
+ unmap_mmu_table(table);
+ goto err_no_mem;
+ }
+ MCDRV_DBG_VERBOSE(mcd,
+ "mapped buffer %p to table with handle %d @ 0x%llX",
+ wsm_buffer, table->handle, (u64)table->phys);
+
+ mutex_unlock(&mem_ctx.table_lock);
+ return table;
+err_no_mem:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ERR_PTR(ret);
+}
+
+phys_addr_t mc_find_mmu_table(uint32_t handle, int32_t fd)
+{
+ phys_addr_t ret = 0;
+ struct mc_mmu_table *table = NULL;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_mmu_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_ERROR(mcd, "entry not found %u", handle);
+ ret = 0;
+ goto table_err;
+ }
+
+ /* It's safe here not to lock the instance since the owner of
+ * the table will be cleared only with the table lock taken */
+ if (!mc_check_owner_fd(table->owner, fd)) {
+ MCDRV_DBG_ERROR(mcd, "not valid owner %u", handle);
+ ret = 0;
+ goto table_err;
+ }
+
+ ret = table->phys;
+table_err:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ret;
+}
+
+void mc_clean_mmu_tables(void)
+{
+ struct mc_mmu_table *table, *tmp;
+
+ mutex_lock(&mem_ctx.table_lock);
+ /* Check if some WSM is orphaned. */
+ list_for_each_entry_safe(table, tmp, &mem_ctx.mmu_tables, list) {
+ if (table->owner == NULL) {
+ MCDRV_DBG(mcd,
+ "cleariM MMU: p=0x%llX pages=%d",
+ (u64)table->phys,
+ table->pages);
+ unmap_mmu_table(table);
+ }
+ }
+ mutex_unlock(&mem_ctx.table_lock);
+}
+
+void mc_clear_mmu_tables(struct mc_instance *instance)
+{
+ struct mc_mmu_table *table, *tmp;
+
+ mutex_lock(&mem_ctx.table_lock);
+ /* Check if some WSM is still in use. */
+ list_for_each_entry_safe(table, tmp, &mem_ctx.mmu_tables, list) {
+ if (table->owner == instance) {
+ MCDRV_DBG(mcd, "release WSM MMU: p=0x%llX pages=%d",
+ (u64)table->phys,
+ table->pages);
+ /* unlock app usage and free or mark it as orphan */
+ table->owner = NULL;
+ unmap_mmu_table(table);
+ }
+ }
+ mutex_unlock(&mem_ctx.table_lock);
+}
+
+int mc_init_mmu_tables(void)
+{
+ /* init list for WSM MMU chunks. */
+ INIT_LIST_HEAD(&mem_ctx.mmu_tables_sets);
+
+ /* MMU table descriptor list. */
+ INIT_LIST_HEAD(&mem_ctx.mmu_tables);
+
+ /* MMU free table descriptor list. */
+ INIT_LIST_HEAD(&mem_ctx.free_mmu_tables);
+
+ mutex_init(&mem_ctx.table_lock);
+
+ return 0;
+}
+
+void mc_release_mmu_tables(void)
+{
+ struct mc_mmu_table *table;
+ /* Check if some WSM is still in use. */
+ list_for_each_entry(table, &mem_ctx.mmu_tables, list) {
+ WARN(1, "WSM MMU still in use: phys=0x%llX ,nr_of_pages=%d",
+ (u64)table->phys, table->pages);
+ }
+}
diff --git a/drivers/gud/MobiCoreDriver/mem.h b/drivers/gud/MobiCoreDriver/mem.h
new file mode 100644
index 0000000..5c9006a
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/mem.h
@@ -0,0 +1,139 @@
+/*
+ * MobiCore driver module.(interface to the secure world SWD)
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MC_MEM_H_
+#define _MC_MEM_H_
+
+#ifdef LPAE_SUPPORT
+/*
+ * Number of page table entries in one MMU table. This is ARM specific, an
+ * MMU table covers 2 MiB by using 512 entries referring to 4KiB pages each.
+ */
+#define MC_ARM_MMU_TABLE_ENTRIES 512
+
+/* ARM level 3 (MMU) table with 512 entries. Size: 4k */
+struct mmutable {
+ uint64_t table_entries[MC_ARM_MMU_TABLE_ENTRIES];
+};
+
+/* There is 1 table in each page. */
+#define MMU_TABLES_PER_PAGE 1
+#else
+/*
+ * MobiCore specific page tables for world shared memory.
+ * Linux uses shadow page tables, see arch/arm/include/asm/pgtable-2level.
+ * MobiCore uses the default ARM format.
+ *
+ * Number of page table entries in one MMU table. This is ARM specific, an
+ * MMU table covers 1 MiB by using 256 entries referring to 4KiB pages each.
+ */
+#define MC_ARM_MMU_TABLE_ENTRIES 256
+
+/* ARM level 2 (MMU) table with 256 entries. Size: 1k */
+struct mmutable {
+ uint32_t table_entries[MC_ARM_MMU_TABLE_ENTRIES];
+};
+
+/* There are 4 tables in each page. */
+#define MMU_TABLES_PER_PAGE 4
+#endif
+
+/* Store for four MMU tables in one 4kb page*/
+struct mc_mmu_table_store {
+ struct mmutable table[MMU_TABLES_PER_PAGE];
+};
+
+/* Usage and maintenance information about mc_mmu_table_store */
+struct mc_mmu_tables_set {
+ struct list_head list;
+ /* kernel virtual address */
+ struct mc_mmu_table_store *kernel_virt;
+ /* physical address */
+ phys_addr_t phys;
+ /* pointer to page struct */
+ struct page *page;
+ /* How many pages from this set are used */
+ atomic_t used_tables;
+};
+
+/*
+ * MMU table allocated to the Daemon or a TLC describing a world shared
+ * buffer.
+ * When users map a malloc()ed area into SWd, a MMU table is allocated.
+ * In addition, the area of maximum 1MB virtual address space is mapped into
+ * the MMU table and a handle for this table is returned to the user.
+ */
+struct mc_mmu_table {
+ struct list_head list;
+ /* Table lock */
+ struct mutex lock;
+ /* handle as communicated to user mode */
+ unsigned int handle;
+ /* Number of references kept to this MMU table */
+ atomic_t usage;
+ /* owner of this MMU table */
+ struct mc_instance *owner;
+ /* set describing where our MMU table is stored */
+ struct mc_mmu_tables_set *set;
+ /* index into MMU table set */
+ unsigned int idx;
+ /* size of buffer */
+ unsigned int pages;
+ /* virtual address*/
+ void *virt;
+ /* physical address */
+ phys_addr_t phys;
+};
+
+/* MobiCore Driver Memory context data. */
+struct mc_mem_context {
+ struct mc_instance *daemon_inst;
+ /* Backing store for MMU tables */
+ struct list_head mmu_tables_sets;
+ /* Bookkeeping for used MMU tables */
+ struct list_head mmu_tables;
+ /* Bookkeeping for free MMU tables */
+ struct list_head free_mmu_tables;
+ /* semaphore to synchronize access to above lists */
+ struct mutex table_lock;
+};
+
+/*
+ * Allocate MMU table and map buffer into it.
+ * That is, create respective table entries.
+ */
+struct mc_mmu_table *mc_alloc_mmu_table(struct mc_instance *instance,
+ struct task_struct *task, void *wsm_buffer, unsigned int wsm_len);
+
+/* Delete all the MMU tables associated with an instance */
+void mc_clear_mmu_tables(struct mc_instance *instance);
+
+/* Release all orphaned MMU tables */
+void mc_clean_mmu_tables(void);
+
+/* Delete a used MMU table. */
+int mc_free_mmu_table(struct mc_instance *instance, uint32_t handle);
+
+/*
+ * Lock a MMU table - the daemon adds +1 to refcount of the MMU table
+ * marking it in use by SWD so it doesn't get released when the TLC dies.
+ */
+int mc_lock_mmu_table(struct mc_instance *instance, uint32_t handle);
+
+/* Return the phys address of MMU table. */
+phys_addr_t mc_find_mmu_table(uint32_t handle, int32_t fd);
+/* Release all used MMU tables to Linux memory space */
+void mc_release_mmu_tables(void);
+
+/* Initialize all MMU tables structure */
+int mc_init_mmu_tables(void);
+
+#endif /* _MC_MEM_H_ */
diff --git a/drivers/gud/MobiCoreDriver/ops.c b/drivers/gud/MobiCoreDriver/ops.c
new file mode 100644
index 0000000..96b4f4f
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/ops.c
@@ -0,0 +1,398 @@
+/*
+ * MobiCore Driver Kernel Module.
+ *
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ * <-- Copyright Trustonic Limited 2013 -->
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/cpu.h>
+
+#include "main.h"
+#include "fastcall.h"
+#include "ops.h"
+#include "mem.h"
+#include "pm.h"
+#include "debug.h"
+
+/* MobiCore context data */
+static struct mc_context *ctx;
+#ifdef TBASE_CORE_SWITCHER
+static uint32_t active_cpu;
+
+static int mobicore_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu);
+static struct notifier_block mobicore_cpu_notifer = {
+ .notifier_call = mobicore_cpu_callback,
+};
+#endif
+
+static inline long smc(union fc_generic *fc)
+{
+ /* If we request sleep yields must be filtered out as they
+ * make no sense */
+ if (ctx->mcp)
+ if (ctx->mcp->flags.sleep_mode.sleep_req) {
+ if (fc->as_in.cmd == MC_SMC_N_YIELD)
+ return MC_FC_RET_ERR_INVALID;
+ }
+ return _smc(fc);
+}
+
+struct fastcall_work {
+#ifdef MC_FASTCALL_WORKER_THREAD
+ struct kthread_work work;
+#else
+ struct work_struct work;
+#endif
+ void *data;
+};
+
+#ifdef MC_FASTCALL_WORKER_THREAD
+static void fastcall_work_func(struct kthread_work *work);
+#else
+static void fastcall_work_func(struct work_struct *work);
+#endif
+
+
+#ifdef MC_FASTCALL_WORKER_THREAD
+
+static struct task_struct *fastcall_thread;
+static DEFINE_KTHREAD_WORKER(fastcall_worker);
+
+bool mc_fastcall(void *data)
+{
+ struct fastcall_work fc_work = {
+ KTHREAD_WORK_INIT(fc_work.work, fastcall_work_func),
+ .data = data,
+ };
+
+ if (!queue_kthread_work(&fastcall_worker, &fc_work.work))
+ return false;
+ flush_kthread_work(&fc_work.work);
+ return true;
+}
+
+int mc_fastcall_init(struct mc_context *context)
+{
+ int ret = 0;
+ ctx = context;
+
+ fastcall_thread = kthread_create(kthread_worker_fn, &fastcall_worker,
+ "mc_fastcall");
+ if (IS_ERR(fastcall_thread)) {
+ ret = PTR_ERR(fastcall_thread);
+ fastcall_thread = NULL;
+ MCDRV_DBG_ERROR(mcd, "cannot create fastcall wq (%d)", ret);
+ return ret;
+ }
+
+ wake_up_process(fastcall_thread);
+
+ /* this thread MUST run on CPU 0 at startup */
+ set_cpus_allowed(fastcall_thread, CPU_MASK_CPU0);
+#ifdef TBASE_CORE_SWITCHER
+ register_cpu_notifier(&mobicore_cpu_notifer);
+#endif
+ return 0;
+}
+
+void mc_fastcall_destroy(void)
+{
+ if (!IS_ERR_OR_NULL(fastcall_thread)) {
+ kthread_stop(fastcall_thread);
+ fastcall_thread = NULL;
+ }
+}
+#else
+
+bool mc_fastcall(void *data)
+{
+ struct fastcall_work work = {
+ .data = data,
+ };
+ INIT_WORK(&work.work, fastcall_work_func);
+ if (!schedule_work_on(0, &work.work))
+ return false;
+ flush_work(&work.work);
+ return true;
+}
+
+int mc_fastcall_init(struct mc_context *context)
+{
+ ctx = context;
+ return 0;
+};
+
+void mc_fastcall_destroy(void) {};
+#endif
+
+#ifdef MC_FASTCALL_WORKER_THREAD
+static void fastcall_work_func(struct kthread_work *work)
+#else
+static void fastcall_work_func(struct work_struct *work)
+#endif
+{
+ struct fastcall_work *fc_work =
+ container_of(work, struct fastcall_work, work);
+ union fc_generic *fc_generic = fc_work->data;
+#ifdef TBASE_CORE_SWITCHER
+ uint32_t cpu_swap = 0, new_cpu;
+ uint32_t cpu_id[] = CPU_IDS;
+#endif
+
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ mc_pm_clock_enable();
+#endif
+
+
+ if (fc_generic == NULL)
+ return;
+#ifdef TBASE_CORE_SWITCHER
+ if (fc_generic->as_in.cmd == MC_FC_SWITCH_CORE) {
+ cpu_swap = 1;
+ new_cpu = fc_generic->as_in.param[0];
+ fc_generic->as_in.param[0] = cpu_id[fc_generic->as_in.param[0]];
+ }
+#endif
+ smc(fc_work->data);
+#ifdef TBASE_CORE_SWITCHER
+ if (cpu_swap) {
+ if (fc_generic->as_out.ret == 0) {
+ cpumask_t cpu;
+ active_cpu = new_cpu;
+ MCDRV_DBG(mcd, "CoreSwap ok %d -> %d\n",
+ raw_smp_processor_id(), active_cpu);
+ cpumask_clear(&cpu);
+ cpumask_set_cpu(active_cpu, &cpu);
+#ifdef MC_FASTCALL_WORKER_THREAD
+ set_cpus_allowed(fastcall_thread, cpu);
+#endif
+ } else {
+ MCDRV_DBG(mcd, "CoreSwap failed %d -> %d\n",
+ raw_smp_processor_id(),
+ fc_generic->as_in.param[0]);
+ }
+ }
+#endif
+#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
+ mc_pm_clock_disable();
+#endif
+}
+
+int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info)
+{
+ int ret = 0;
+ union mc_fc_info fc_info;
+
+ MCDRV_DBG_VERBOSE(mcd, "enter");
+
+ memset(&fc_info, 0, sizeof(fc_info));
+ fc_info.as_in.cmd = MC_FC_INFO;
+ fc_info.as_in.ext_info_id = ext_info_id;
+
+ MCDRV_DBG(mcd, "<- cmd=0x%08x, ext_info_id=0x%08x",
+ fc_info.as_in.cmd, fc_info.as_in.ext_info_id);
+
+ mc_fastcall(&(fc_info.as_generic));
+
+ MCDRV_DBG(mcd,
+ "-> r=0x%08x ret=0x%08x state=0x%08x "
+ "ext_info=0x%08x",
+ fc_info.as_out.resp,
+ fc_info.as_out.ret,
+ fc_info.as_out.state,
+ fc_info.as_out.ext_info);
+
+ ret = convert_fc_ret(fc_info.as_out.ret);
+
+ *state = fc_info.as_out.state;
+ *ext_info = fc_info.as_out.ext_info;
+
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
+
+ return ret;
+}
+
+#ifdef TBASE_CORE_SWITCHER
+int mc_switch_core(uint32_t core_num)
+{
+ int32_t ret = 0;
+ union mc_fc_swich_core fc_switch_core;
+
+ if (!cpu_online(core_num))
+ return 1;
+
+ MCDRV_DBG_VERBOSE(mcd, "enter\n");
+
+ memset(&fc_switch_core, 0, sizeof(fc_switch_core));
+ fc_switch_core.as_in.cmd = MC_FC_SWITCH_CORE;
+
+ if (core_num < COUNT_OF_CPUS)
+ fc_switch_core.as_in.core_id = core_num;
+ else
+ fc_switch_core.as_in.core_id = 0;
+
+ MCDRV_DBG(
+ mcd, "<- cmd=0x%08x, core_num=0x%08x, "
+ "active_cpu=0x%08x, active_cpu=0x%08x\n",
+ fc_switch_core.as_in.cmd,
+ fc_switch_core.as_in.core_id,
+ core_num, active_cpu);
+ mc_fastcall(&(fc_switch_core.as_generic));
+
+ ret = convert_fc_ret(fc_switch_core.as_out.ret);
+
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
+
+ return ret;
+}
+
+void mc_cpu_offfline(int cpu)
+{
+ if (active_cpu == cpu) {
+ int i;
+ /* Chose the first online CPU and switch! */
+ for_each_online_cpu(i) {
+ if (i == cpu) {
+ MCDRV_DBG(mcd, "Skipping CPU %d\n", cpu);
+ continue;
+ }
+ MCDRV_DBG(mcd, "CPU %d is dying, switching to %d\n",
+ cpu, i);
+ mc_switch_core(i);
+ break;
+ }
+ } else {
+ MCDRV_DBG(mcd, "not active CPU, no action taken\n");
+ }
+}
+
+static int mobicore_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ switch (action) {
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ dev_info(mcd, "Cpu %u is going to die\n", cpu);
+ mc_cpu_offfline(cpu);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ dev_info(mcd, "Cpu %u is dead\n", cpu);
+ break;
+ }
+ return NOTIFY_OK;
+}
+#endif
+
+/* Yield to MobiCore */
+int mc_yield(void)
+{
+ int ret = 0;
+ union fc_generic yield;
+
+ MCDRV_DBG_VERBOSE(mcd, "enter");
+ memset(&yield, 0, sizeof(yield));
+ yield.as_in.cmd = MC_SMC_N_YIELD;
+ mc_fastcall(&yield);
+ ret = convert_fc_ret(yield.as_out.ret);
+
+ return ret;
+}
+
+/* call common notify */
+int mc_nsiq(void)
+{
+ int ret = 0;
+ union fc_generic nsiq;
+ MCDRV_DBG_VERBOSE(mcd, "enter");
+ memset(&nsiq, 0, sizeof(nsiq));
+ nsiq.as_in.cmd = MC_SMC_N_SIQ;
+ mc_fastcall(&nsiq);
+ ret = convert_fc_ret(nsiq.as_out.ret);
+ return ret;
+}
+
+/* call common notify */
+int _nsiq(void)
+{
+ int ret = 0;
+ union fc_generic nsiq;
+ MCDRV_DBG_VERBOSE(mcd, "enter");
+ memset(&nsiq, 0, sizeof(nsiq));
+ nsiq.as_in.cmd = MC_SMC_N_SIQ;
+ _smc(&nsiq);
+ ret = convert_fc_ret(nsiq.as_out.ret);
+ return ret;
+}
+
+/* Call the INIT fastcall to setup MobiCore initialization */
+int mc_init(phys_addr_t base, uint32_t nq_length,
+ uint32_t mcp_offset, uint32_t mcp_length)
+{
+ int ret = 0;
+ union mc_fc_init fc_init;
+ uint64_t base_addr = (uint64_t)base;
+ uint32_t base_high = (uint32_t)(base_addr >> 32);
+
+ MCDRV_DBG_VERBOSE(mcd, "enter");
+
+ memset(&fc_init, 0, sizeof(fc_init));
+
+ fc_init.as_in.cmd = MC_FC_INIT;
+ /* base address of mci buffer 4KB aligned */
+ fc_init.as_in.base = (uint32_t)base_addr;
+ /* notification buffer start/length [16:16] [start, length] */
+ fc_init.as_in.nq_info = ((base_high && 0xFFFF) << 16) |
+ (nq_length & 0xFFFF);
+ /* mcp buffer start/length [16:16] [start, length] */
+ fc_init.as_in.mcp_info = (mcp_offset << 16) | (mcp_length & 0xFFFF);
+
+ /*
+ * Set KMOD notification queue to start of MCI
+ * mciInfo was already set up in mmap
+ */
+ MCDRV_DBG(mcd,
+ "cmd=0x%08x, base=0x%08x,nq_info=0x%08x, mcp_info=0x%08x",
+ fc_init.as_in.cmd, fc_init.as_in.base, fc_init.as_in.nq_info,
+ fc_init.as_in.mcp_info);
+ mc_fastcall(&fc_init.as_generic);
+ MCDRV_DBG(mcd, "out cmd=0x%08x, ret=0x%08x", fc_init.as_out.resp,
+ fc_init.as_out.ret);
+
+ ret = convert_fc_ret(fc_init.as_out.ret);
+
+ MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
+
+ return ret;
+}
+
+/* Return MobiCore driver version */
+uint32_t mc_get_version(void)
+{
+ MCDRV_DBG(mcd, "MobiCore driver version is %i.%i",
+ MCDRVMODULEAPI_VERSION_MAJOR,
+ MCDRVMODULEAPI_VERSION_MINOR);
+
+ return MC_VERSION(MCDRVMODULEAPI_VERSION_MAJOR,
+ MCDRVMODULEAPI_VERSION_MINOR);
+}
diff --git a/drivers/gud/mobicore_driver/ops.h b/drivers/gud/MobiCoreDriver/ops.h
similarity index 78%
rename from drivers/gud/mobicore_driver/ops.h
rename to drivers/gud/MobiCoreDriver/ops.h
index 910c1f4..f04eb3e 100644
--- a/drivers/gud/mobicore_driver/ops.h
+++ b/drivers/gud/MobiCoreDriver/ops.h
@@ -21,10 +21,13 @@
uint32_t mc_get_version(void);
int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info);
-int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length,
- uint32_t mcp_offset, uint32_t mcp_length);
+int mc_init(phys_addr_t base, uint32_t nq_length, uint32_t mcp_offset,
+ uint32_t mcp_length);
+#ifdef TBASE_CORE_SWITCHER
+int mc_switch_core(uint32_t core_num);
+#endif
-void mc_fastcall(void *data);
+bool mc_fastcall(void *data);
int mc_fastcall_init(struct mc_context *context);
void mc_fastcall_destroy(void);
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h
similarity index 85%
rename from drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
rename to drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h
index 7854fc5..72ea3ed 100644
--- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
+++ b/drivers/gud/MobiCoreDriver/platforms/MSM8960_SURF_STD/platform.h
@@ -36,20 +36,12 @@
}
/* Enable mobicore mem traces */
-/* #define MC_MEM_TRACES */
+#define MC_MEM_TRACES
/* Enable the use of vm_unamp instead of the deprecated do_munmap
* and other 3.7 features
*/
-#ifndef CONFIG_ARCH_MSM8960
#define MC_VM_UNMAP
-#endif
-
-
-#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM8226)
-/* Perform clock enable/disable */
-#define MC_CRYPTO_CLOCK_MANAGEMENT
-#endif
/* Enable Power Management for Crypto Engine */
#define MC_CRYPTO_CLOCK_MANAGEMENT
diff --git a/drivers/gud/mobicore_driver/pm.c b/drivers/gud/MobiCoreDriver/pm.c
similarity index 66%
rename from drivers/gud/mobicore_driver/pm.c
rename to drivers/gud/MobiCoreDriver/pm.c
index 55a1ef7..40365ef 100644
--- a/drivers/gud/mobicore_driver/pm.c
+++ b/drivers/gud/MobiCoreDriver/pm.c
@@ -46,7 +46,7 @@
if (!ctx->mcp)
return false;
- if (!ctx->mcp->flags.sleep_mode.ReadyToSleep & READY_TO_SLEEP)
+ if (!(ctx->mcp->flags.sleep_mode.ready_to_sleep & READY_TO_SLEEP))
return false;
return true;
@@ -57,7 +57,7 @@
if (!ctx->mcp)
return;
- ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
+ ctx->mcp->flags.sleep_mode.sleep_req = REQ_TO_SLEEP;
_nsiq();
}
DECLARE_WORK(suspend_work, mc_suspend_handler);
@@ -66,9 +66,9 @@
{
MCDRV_DBG(mcd, "MobiCore IDLE=%d!", flags->schedule);
MCDRV_DBG(mcd,
- "MobiCore Request Sleep=%d!", flags->sleep_mode.SleepReq);
+ "MobiCore Request Sleep=%d!", flags->sleep_mode.sleep_req);
MCDRV_DBG(mcd,
- "MobiCore Sleep Ready=%d!", flags->sleep_mode.ReadyToSleep);
+ "MobiCore Sleep Ready=%d!", flags->sleep_mode.ready_to_sleep);
}
static int mc_suspend_notifier(struct notifier_block *nb,
@@ -96,12 +96,12 @@
*/
dump_sleep_params(&mcp->flags);
if (!sleep_ready()) {
- ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
+ ctx->mcp->flags.sleep_mode.sleep_req = REQ_TO_SLEEP;
schedule_work_on(0, &suspend_work);
flush_work(&suspend_work);
if (!sleep_ready()) {
dump_sleep_params(&mcp->flags);
- ctx->mcp->flags.sleep_mode.SleepReq = 0;
+ ctx->mcp->flags.sleep_mode.sleep_req = 0;
MCDRV_DBG_ERROR(mcd, "MobiCore can't SLEEP!");
return NOTIFY_BAD;
}
@@ -109,7 +109,7 @@
break;
case PM_POST_SUSPEND:
MCDRV_DBG(mcd, "Resume MobiCore system!");
- ctx->mcp->flags.sleep_mode.SleepReq = 0;
+ ctx->mcp->flags.sleep_mode.sleep_req = 0;
break;
default:
break;
@@ -121,57 +121,6 @@
.notifier_call = mc_suspend_notifier,
};
-#ifdef MC_BL_NOTIFIER
-
-static int bL_switcher_notifier_handler(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- unsigned int mpidr, cpu, cluster;
- struct mc_mcp_buffer *mcp = ctx->mcp;
-
- if (!mcp)
- return 0;
-
- asm volatile ("mrc\tp15, 0, %0, c0, c0, 5" : "=r" (mpidr));
- cpu = mpidr & 0x3;
- cluster = (mpidr >> 8) & 0xf;
- MCDRV_DBG(mcd, "%s switching!!, cpu: %u, Out=%u\n",
- (event == SWITCH_ENTER ? "Before" : "After"), cpu, cluster);
-
- if (cpu != 0)
- return 0;
-
- switch (event) {
- case SWITCH_ENTER:
- if (!sleep_ready()) {
- ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
- _nsiq();
- /* By this time we should be ready for sleep or we are
- * in the middle of something important */
- if (!sleep_ready()) {
- dump_sleep_params(&mcp->flags);
- MCDRV_DBG(mcd,
- "MobiCore: Don't allow switch!\n");
- ctx->mcp->flags.sleep_mode.SleepReq = 0;
- return -EPERM;
- }
- }
- break;
- case SWITCH_EXIT:
- ctx->mcp->flags.sleep_mode.SleepReq = 0;
- break;
- default:
- MCDRV_DBG(mcd, "MobiCore: Unknown switch event!\n");
- }
-
- return 0;
-}
-
-static struct notifier_block switcher_nb = {
- .notifier_call = bL_switcher_notifier_handler,
-};
-#endif
-
int mc_pm_initialize(struct mc_context *context)
{
int ret = 0;
@@ -180,12 +129,7 @@
ret = register_pm_notifier(&mc_notif_block);
if (ret)
- MCDRV_DBG_ERROR(mcd, "device pm register failed\n");
-#ifdef MC_BL_NOTIFIER
- if (register_bL_swicher_notifier(&switcher_nb))
- MCDRV_DBG_ERROR(mcd,
- "Failed to register to bL_switcher_notifier\n");
-#endif
+ MCDRV_DBG_ERROR(mcd, "device pm register failed");
return ret;
}
@@ -194,15 +138,16 @@
{
int ret = unregister_pm_notifier(&mc_notif_block);
if (ret)
- MCDRV_DBG_ERROR(mcd, "device pm unregister failed\n");
-#ifdef MC_BL_NOTIFIER
- ret = unregister_bL_swicher_notifier(&switcher_nb);
- if (ret)
- MCDRV_DBG_ERROR(mcd, "device bl unregister failed\n");
-#endif
+ MCDRV_DBG_ERROR(mcd, "device pm unregister failed");
return ret;
}
+bool mc_pm_sleep_ready(void)
+{
+ if (ctx == 0)
+ return true;
+ return sleep_ready();
+}
#endif /* MC_PM_RUNTIME */
#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
@@ -215,7 +160,7 @@
mc_ce_core_clk = clk_get(mcd, "core_clk");
if (IS_ERR(mc_ce_core_clk)) {
ret = PTR_ERR(mc_ce_core_clk);
- MCDRV_DBG_ERROR(mcd, "cannot get core clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot get core clock");
goto error;
}
/* Get Interface clk */
@@ -223,7 +168,7 @@
if (IS_ERR(mc_ce_iface_clk)) {
clk_put(mc_ce_core_clk);
ret = PTR_ERR(mc_ce_iface_clk);
- MCDRV_DBG_ERROR(mcd, "cannot get iface clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot get iface clock");
goto error;
}
/* Get AXI clk */
@@ -232,7 +177,7 @@
clk_put(mc_ce_iface_clk);
clk_put(mc_ce_core_clk);
ret = PTR_ERR(mc_ce_bus_clk);
- MCDRV_DBG_ERROR(mcd, "cannot get AXI bus clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot get AXI bus clock");
goto error;
}
return ret;
@@ -263,17 +208,17 @@
rc = clk_prepare_enable(mc_ce_core_clk);
if (rc) {
- MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot enable clock");
} else {
rc = clk_prepare_enable(mc_ce_iface_clk);
if (rc) {
clk_disable_unprepare(mc_ce_core_clk);
- MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot enable clock");
} else {
rc = clk_prepare_enable(mc_ce_bus_clk);
if (rc) {
clk_disable_unprepare(mc_ce_iface_clk);
- MCDRV_DBG_ERROR(mcd, "cannot enable clock\n");
+ MCDRV_DBG_ERROR(mcd, "cannot enable clock");
}
}
}
diff --git a/drivers/gud/mobicore_driver/pm.h b/drivers/gud/MobiCoreDriver/pm.h
similarity index 94%
rename from drivers/gud/mobicore_driver/pm.h
rename to drivers/gud/MobiCoreDriver/pm.h
index 332da34..b71c603 100644
--- a/drivers/gud/mobicore_driver/pm.h
+++ b/drivers/gud/MobiCoreDriver/pm.h
@@ -13,10 +13,6 @@
#define _MC_PM_H_
#include "main.h"
-#ifdef MC_BL_NOTIFIER
-#include <asm/bL_switcher.h>
-#endif
-
#define NO_SLEEP_REQ 0
#define REQ_TO_SLEEP 1
@@ -39,5 +35,7 @@
int mc_pm_clock_enable(void);
/* Disable secure crypto clocks */
void mc_pm_clock_disable(void);
+/* Test if sleep is possible */
+bool mc_pm_sleep_ready(void);
#endif /* _MC_PM_H_ */
diff --git a/drivers/gud/mobicore_driver/public/mc_kernel_api.h b/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
similarity index 89%
rename from drivers/gud/mobicore_driver/public/mc_kernel_api.h
rename to drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
index cca0636..15fd4a2 100644
--- a/drivers/gud/mobicore_driver/public/mc_kernel_api.h
+++ b/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
@@ -35,13 +35,12 @@
* @requested_size: memory size requested in bytes
* @handle: pointer to handle
* @kernel_virt_addr: virtual user start address
- * @phys_addr: physical start address
*
* Returns 0 if OK
*/
int mobicore_allocate_wsm(struct mc_instance *instance,
unsigned long requested_size, uint32_t *handle,
- void **virt_kernel_addr, void **phys_addr);
+ void **virt_kernel_addr);
/*
* mobicore_free() - Free a WSM buffer allocated with mobicore_allocate_wsm
@@ -58,12 +57,11 @@
* @addr: address of the buffer (NB it must be kernel virtual!)
* @len: buffer length (in bytes)
* @handle: unique handle
- * @phys: pointer for physical address of L2 table
*
* Returns 0 if no error
*/
int mobicore_map_vmem(struct mc_instance *instance, void *addr,
- uint32_t len, uint32_t *handle, uint32_t *phys);
+ uint32_t len, uint32_t *handle);
/*
* mobicore_unmap_vmem() - Unmap a virtual memory buffer from MobiCore
@@ -74,4 +72,12 @@
*/
int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle);
+/*
+ * mobicore_sleep_ready() - Test if mobicore can sleep
+ *
+ * Returns true if mobicore can sleep, false if it can't sleep
+ */
+bool mobicore_sleep_ready(void);
+
+
#endif /* _MC_KERNEL_API_H_ */
diff --git a/drivers/gud/mobicore_driver/public/mc_linux.h b/drivers/gud/MobiCoreDriver/public/mc_linux.h
similarity index 81%
rename from drivers/gud/mobicore_driver/public/mc_linux.h
rename to drivers/gud/MobiCoreDriver/public/mc_linux.h
index af027dc..98e7af1 100644
--- a/drivers/gud/mobicore_driver/public/mc_linux.h
+++ b/drivers/gud/MobiCoreDriver/public/mc_linux.h
@@ -1,7 +1,7 @@
/*
* The MobiCore Driver Kernel Module is a Linux device driver, which represents
* the command proxy on the lowest layer to the secure world (Swd). Additional
- * services like memory allocation via mmap and generation of a L2 tables for
+ * services like memory allocation via mmap and generation of a MMU tables for
* given virtual memory are also supported. IRQ functionality receives
* information from the SWd in the non secure world (NWd).
* As customary the driver is handled as linux device driver with "open",
@@ -55,8 +55,6 @@
* INIT request data to SWD
*/
struct mc_ioctl_init {
- /* notification buffer start/length [16:16] [start, length] */
- uint32_t nq_offset;
/* length of notification queue */
uint32_t nq_length;
/* mcp buffer start/length [16:16] [start, length] */
@@ -76,8 +74,7 @@
};
/*
- * Data exchange structure of the MC_IO_MAP_WSM, MC_IO_MAP_MCI, and
- * MC_IO_MAP_PWSM commands.
+ * Data exchange structure of the MC_IO_MAP_WSM and MC_IO_MAP_MCI commands.
*
* Allocate a contiguous memory buffer for a process.
* The physical address can be used as for later calls to mmap.
@@ -86,19 +83,19 @@
* already. I.e. Daemon was restarted.
*/
struct mc_ioctl_map {
- size_t len; /* Buffer length */
- uint32_t handle; /* WSM handle */
- unsigned long addr; /* Virtual address */
- unsigned long phys_addr;/* physical address of WSM (or NULL) */
- bool reused; /* if WSM memory was reused, or new allocated */
+ size_t len; /* Buffer length */
+ uint32_t handle; /* WSM handle */
+ uint64_t phys_addr; /* physical address of WSM (or 0) */
+ unsigned long addr; /* Virtual address */
+ bool reused; /* if WSM memory was reused, or new allocated */
};
/*
* Data exchange structure of the MC_IO_REG_WSM command.
*
- * Allocates a physical L2 table and maps the buffer into this page.
- * Returns the physical address of the L2 table.
- * The page alignment will be created and the appropriated pSize and pOffsetL2
+ * Allocates a physical MMU table and maps the buffer into this page.
+ * Returns the physical address of the MMU table.
+ * The page alignment will be created and the appropriated pSize and pOffsetMMU
* will be modified to the used values.
*/
struct mc_ioctl_reg_wsm {
@@ -106,19 +103,7 @@
uint32_t len; /* size of the virtual address space */
uint32_t pid; /* process id */
uint32_t handle; /* driver handle for locked memory */
- uint32_t table_phys; /* physical address of the L2 table */
-};
-
-
-/*
- * Data exchange structure of the MC_DRV_MODULE_FC_EXECUTE ioctl command.
- * internal, unsupported
- */
-struct mc_ioctl_execute {
- /* base address of mobicore binary */
- uint32_t phys_start_addr;
- /* length of DDR area */
- uint32_t length;
+ uint64_t table_phys; /* physical address of the MMU table */
};
/*
@@ -127,10 +112,10 @@
struct mc_ioctl_resolv_cont_wsm {
/* driver handle for buffer */
uint32_t handle;
- /* base address of memory */
- uint32_t phys;
/* length memory */
uint32_t length;
+ /* base address of memory */
+ uint64_t phys;
/* fd to owner of the buffer */
int32_t fd;
};
@@ -144,7 +129,7 @@
/* fd to owner of the buffer */
int32_t fd;
/* base address of memory */
- uint32_t phys;
+ uint64_t phys;
};
@@ -180,28 +165,24 @@
*/
#define MC_IO_FREE _IO(MC_IOC_MAGIC, 5)
/*
- * Creates a L2 Table of the given base address and the size of the
+ * Creates a MMU Table of the given base address and the size of the
* data.
- * Parameter: mc_ioctl_app_reg_wsm_l2_params
+ * Parameter: mc_ioctl_reg_wsm
*/
#define MC_IO_REG_WSM _IOWR(MC_IOC_MAGIC, 6, struct mc_ioctl_reg_wsm)
#define MC_IO_UNREG_WSM _IO(MC_IOC_MAGIC, 7)
#define MC_IO_LOCK_WSM _IO(MC_IOC_MAGIC, 8)
#define MC_IO_UNLOCK_WSM _IO(MC_IOC_MAGIC, 9)
-#define MC_IO_EXECUTE _IOWR(MC_IOC_MAGIC, 10, struct mc_ioctl_execute)
/*
* Allocate contiguous memory for a process for later mapping with mmap.
- * MC_DRV_KMOD_MMAP_WSM usual operation, pages are registered in
+ * MC_IO_MAP_WSM usual operation, pages are registered in
* device structure and freed later.
- * MC_DRV_KMOD_MMAP_MCI get Instance of MCI, allocates or mmaps
+ * MC_IO_MAP_MCI get Instance of MCI, allocates or mmaps
* the MCI to daemon
- * MC_DRV_KMOD_MMAP_PERSISTENTWSM special operation, without
- * registration of pages
*/
#define MC_IO_MAP_WSM _IOWR(MC_IOC_MAGIC, 11, struct mc_ioctl_map)
#define MC_IO_MAP_MCI _IOWR(MC_IOC_MAGIC, 12, struct mc_ioctl_map)
-#define MC_IO_MAP_PWSM _IOWR(MC_IOC_MAGIC, 13, struct mc_ioctl_map)
/*
* Clean orphaned WSM buffers. Only available to the daemon and should
@@ -215,7 +196,7 @@
#define MC_IO_CLEAN_WSM _IO(MC_IOC_MAGIC, 14)
/*
- * Get L2 phys address of a buffer handle allocated to the user.
+ * Get MMU phys address of a buffer handle allocated to the user.
* Only available to the daemon.
*/
#define MC_IO_RESOLVE_WSM _IOWR(MC_IOC_MAGIC, 15, \
diff --git a/drivers/gud/mobicore_driver/public/version.h b/drivers/gud/MobiCoreDriver/public/version.h
similarity index 100%
rename from drivers/gud/mobicore_driver/public/version.h
rename to drivers/gud/MobiCoreDriver/public/version.h
diff --git a/drivers/gud/MobiCoreKernelApi/Makefile b/drivers/gud/MobiCoreKernelApi/Makefile
new file mode 100644
index 0000000..9b37eea
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/Makefile
@@ -0,0 +1,52 @@
+#
+# this makefile is called from the kernel make syste
+ifeq ($(MODE),release)
+ ccflags-y += -O2 -DNDEBUG
+else # DEBUG
+ # "-O" is needed to expand inlines
+ ccflags-y += -O -g3 -DDEBUG
+endif # DEBUG/RELEASE
+
+ifdef MOBICORE_CFLAGS
+ ccflags-y +=$(MOBICORE_CFLAGS)
+endif
+
+#Set the extra symbols
+ifdef MCDRV_SYMBOLS_FILE
+ KBUILD_EXTRA_SYMBOLS=$(MCDRV_SYMBOLS_FILE)
+endif
+
+ifeq ($(PLATFORM), ARM_VE_A9X4_QEMU)
+ ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+ifeq ($(PLATFORM), MSM8974_SURF_STD)
+ ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+ifeq ($(PLATFORM), EXYNOS_5422_STD)
+ ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+ifeq ($(PLATFORM), EXYNOS_5430_STD)
+ ccflags-y += -DMC_NETLINK_COMPAT_V37
+endif
+
+#EXTRA_CFLAGS += -DDEBUG -DDEBUG_VERBOSE
+#EXTRA_CFLAGS += -Wno-declaration-after-statement
+ccflags-y += -Wno-declaration-after-statement
+# add our module to kernel.
+obj-m += mcKernelApi.o
+
+mcKernelApi-objs := main.o clientlib.o device.o session.o connection.o
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \
+ Module.markers Module.symvers modules.order
+
+depend .depend dep:
+ $(CC) $(CFLAGS) -M *.c > .depend
+
+ifeq (.depend,$(wildcard .depend))
+ include .depend
+endif
diff --git a/drivers/gud/MobiCoreKernelApi/build.sh b/drivers/gud/MobiCoreKernelApi/build.sh
new file mode 100644
index 0000000..86fe1b8
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/build.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+if [ -z $COMP_PATH_ROOT ]; then
+ echo "The build environment is not set!"
+ echo "Trying to source setupDrivers.sh automatically!"
+ source ../setupDrivers.sh || exit 1
+fi
+
+ROOT_PATH=$(dirname $(readlink -f $BASH_SOURCE))
+# These folders need to be relative to the kernel dir or absolute!
+PLATFORM=EXYNOS_4X12_STD
+CODE_INCLUDE=$(readlink -f $ROOT_PATH/Locals/Code)
+
+MOBICORE_DRIVER=$COMP_PATH_MobiCoreDriverMod
+MOBICORE_DAEMON=$COMP_PATH_MobiCoreDriverLib/Public
+MOBICORE_CFLAGS="-I$MOBICORE_DRIVER/Public -I$MOBICORE_DAEMON -I$COMP_PATH_MobiCore/inc/Mci -I$COMP_PATH_MobiCore/inc -I$CODE_INCLUDE/include -I$CODE_INCLUDE/public"
+MCDRV_SYMBOLS_FILE="$COMP_PATH_ROOT/MobiCoreDriverMod/Locals/Code/Module.symvers"
+
+if [ ! -f $MCDRV_SYMBOLS_FILE ]; then
+ echo "Please build the Mobicore Driver Module first!"
+ echo "Otherwise you will see warnings of missing symbols"
+fi
+
+# Clean first
+make -C $CODE_INCLUDE clean
+
+make -C $LINUX_PATH \
+ MODE=$MODE \
+ ARCH=arm \
+ CROSS_COMPILE=$CROSS_COMPILE \
+ M=$CODE_INCLUDE \
+ "MOBICORE_CFLAGS=$MOBICORE_CFLAGS" \
+ MCDRV_SYMBOLS_FILE=$MCDRV_SYMBOLS_FILE \
+ modules
diff --git a/drivers/gud/mobicore_kernelapi/clientlib.c b/drivers/gud/MobiCoreKernelApi/clientlib.c
similarity index 95%
rename from drivers/gud/mobicore_kernelapi/clientlib.c
rename to drivers/gud/MobiCoreKernelApi/clientlib.c
index 16b52e5..65b4a1c 100644
--- a/drivers/gud/mobicore_kernelapi/clientlib.c
+++ b/drivers/gud/MobiCoreKernelApi/clientlib.c
@@ -25,6 +25,7 @@
/* device list */
LIST_HEAD(devices);
+atomic_t device_usage = ATOMIC_INIT(0);
static struct mcore_device_t *resolve_device_id(uint32_t device_id)
{
@@ -71,14 +72,20 @@
do {
struct mcore_device_t *device = resolve_device_id(device_id);
if (device != NULL) {
- MCDRV_DBG_ERROR(mc_kapi,
- "Device %d already opened", device_id);
- mc_result = MC_DRV_ERR_INVALID_OPERATION;
+ MCDRV_DBG(mc_kapi,
+ "Device %d already opened\n", device_id);
+ atomic_inc(&device_usage);
+ mc_result = MC_DRV_OK;
break;
}
/* Open new connection to device */
dev_con = connection_new();
+ if (dev_con == NULL) {
+ mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+ break;
+ }
+
if (!connection_connect(dev_con, MC_DAEMON_PID)) {
MCDRV_DBG_ERROR(
mc_kapi,
@@ -144,6 +151,10 @@
/* there is no payload to read */
device = mcore_device_create(device_id, dev_con);
+ if (device == NULL) {
+ mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+ break;
+ }
if (!mcore_device_open(device, MC_DRV_MOD_DEVNODE_FULLPATH)) {
mcore_device_cleanup(device);
MCDRV_DBG_ERROR(mc_kapi,
@@ -154,6 +165,7 @@
}
add_device(device);
+ atomic_inc(&device_usage);
} while (false);
@@ -177,6 +189,12 @@
mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
break;
}
+ /* Check if it's not used by other modules */
+ if (!atomic_dec_and_test(&device_usage)) {
+ mc_result = MC_DRV_OK;
+ break;
+ }
+
struct connection *dev_con = device->connection;
/* Return if not all sessions have been closed */
@@ -274,12 +292,12 @@
}
struct connection *dev_con = device->connection;
- /* Get the physical address of the given TCI */
+ /* Get the wsm of the given TCI */
struct wsm *wsm =
mcore_device_find_contiguous_wsm(device, tci);
if (wsm == NULL) {
MCDRV_DBG_ERROR(mc_kapi,
- "Could not resolve TCI phy address ");
+ "Could not resolve TCI address ");
mc_result = MC_DRV_ERR_INVALID_PARAMETER;
break;
}
@@ -292,14 +310,14 @@
}
/* Prepare open session command */
- struct mc_drv_cmd_open_session_t cmdOpenSession = {
+ struct mc_drv_cmd_open_session_t cmd_open_session = {
{
MC_DRV_CMD_OPEN_SESSION
},
{
session->device_id,
*uuid,
- (uint32_t)(wsm->phys_addr) & 0xFFF,
+ (uint32_t)(wsm->virt_addr) & 0xFFF,
wsm->handle,
len
}
@@ -307,9 +325,9 @@
/* Transmit command data */
int len = connection_write_data(dev_con,
- &cmdOpenSession,
- sizeof(cmdOpenSession));
- if (len != sizeof(cmdOpenSession)) {
+ &cmd_open_session,
+ sizeof(cmd_open_session));
+ if (len != sizeof(cmd_open_session)) {
MCDRV_DBG_ERROR(mc_kapi,
"CMD_OPEN_SESSION writeData failed %d",
len);
@@ -370,6 +388,10 @@
/* Set up second channel for notifications */
struct connection *session_connection = connection_new();
+ if (session_connection == NULL) {
+ mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+ break;
+ }
if (!connection_connect(session_connection, MC_DAEMON_PID)) {
MCDRV_DBG_ERROR(
@@ -422,9 +444,13 @@
/* there is no payload. */
/* Session established, new session object must be created */
- mcore_device_create_new_session(device,
- session->session_id,
- session_connection);
+ if (!mcore_device_create_new_session(device,
+ session->session_id,
+ session_connection)) {
+ connection_cleanup(session_connection);
+ mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+ break;
+ }
} while (false);
@@ -706,7 +732,6 @@
MCDRV_DBG_VERBOSE(mc_kapi, "===%s()===", __func__);
do {
-
/* Get the device associated wit the given session */
device = resolve_device_id(device_id);
if (device == NULL) {
@@ -805,7 +830,7 @@
{
session->session_id,
bulk_buf->handle,
- (uint32_t)bulk_buf->phys_addr_wsm_l2,
+ 0,
(uint32_t)(bulk_buf->virt_addr) & 0xFFF,
bulk_buf->len
}
@@ -819,8 +844,8 @@
/* Read command response */
struct mc_drv_response_header_t rsp_header;
int len = connection_read_datablock(dev_con,
- &rsp_header,
- sizeof(rsp_header));
+ &rsp_header,
+ sizeof(rsp_header));
if (len != sizeof(rsp_header)) {
MCDRV_DBG_ERROR(mc_kapi,
"CMD_MAP_BULK_BUF readRsp failed %d",
diff --git a/drivers/gud/mobicore_kernelapi/common.h b/drivers/gud/MobiCoreKernelApi/common.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/common.h
rename to drivers/gud/MobiCoreKernelApi/common.h
diff --git a/drivers/gud/mobicore_kernelapi/connection.c b/drivers/gud/MobiCoreKernelApi/connection.c
similarity index 96%
rename from drivers/gud/mobicore_kernelapi/connection.c
rename to drivers/gud/MobiCoreKernelApi/connection.c
index 03288a0..0372b82 100644
--- a/drivers/gud/mobicore_kernelapi/connection.c
+++ b/drivers/gud/MobiCoreKernelApi/connection.c
@@ -28,6 +28,10 @@
struct connection *conn;
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+ if (conn == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return NULL;
+ }
conn->sequence_magic = mcapi_unique_id();
mutex_init(&conn->data_lock);
sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE);
@@ -36,14 +40,6 @@
return conn;
}
-struct connection *connection_create(int socket_descriptor, pid_t dest)
-{
- struct connection *conn = connection_new();
-
- conn->peer_pid = dest;
- return conn;
-}
-
void connection_cleanup(struct connection *conn)
{
if (!conn)
diff --git a/drivers/gud/mobicore_kernelapi/connection.h b/drivers/gud/MobiCoreKernelApi/connection.h
similarity index 95%
rename from drivers/gud/mobicore_kernelapi/connection.h
rename to drivers/gud/MobiCoreKernelApi/connection.h
index 6c3ff00..57e783b 100644
--- a/drivers/gud/mobicore_kernelapi/connection.h
+++ b/drivers/gud/MobiCoreKernelApi/connection.h
@@ -44,7 +44,6 @@
};
struct connection *connection_new(void);
-struct connection *connection_create(int socket_descriptor, pid_t dest);
void connection_cleanup(struct connection *conn);
bool connection_connect(struct connection *conn, pid_t dest);
size_t connection_read_datablock(struct connection *conn, void *buffer,
diff --git a/drivers/gud/mobicore_kernelapi/device.c b/drivers/gud/MobiCoreKernelApi/device.c
similarity index 85%
rename from drivers/gud/mobicore_kernelapi/device.c
rename to drivers/gud/MobiCoreKernelApi/device.c
index a176322..04db4c3 100644
--- a/drivers/gud/mobicore_kernelapi/device.c
+++ b/drivers/gud/MobiCoreKernelApi/device.c
@@ -18,16 +18,18 @@
#include "device.h"
#include "common.h"
-struct wsm *wsm_create(void *virt_addr, uint32_t len, uint32_t handle,
- void *phys_addr)
+static struct wsm *wsm_create(void *virt_addr, uint32_t len, uint32_t handle)
{
struct wsm *wsm;
wsm = kzalloc(sizeof(*wsm), GFP_KERNEL);
+ if (wsm == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return NULL;
+ }
wsm->virt_addr = virt_addr;
wsm->len = len;
wsm->handle = handle;
- wsm->phys_addr = phys_addr;
return wsm;
}
@@ -37,11 +39,15 @@
struct mcore_device_t *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return NULL;
+ }
dev->device_id = device_id;
dev->connection = connection;
INIT_LIST_HEAD(&dev->session_vector);
- INIT_LIST_HEAD(&dev->wsm_l2_vector);
+ INIT_LIST_HEAD(&dev->wsm_mmu_vector);
return dev;
}
@@ -63,7 +69,7 @@
}
/* Free all allocated WSM descriptors */
- list_for_each_safe(pos, q, &dev->wsm_l2_vector) {
+ list_for_each_safe(pos, q, &dev->wsm_mmu_vector) {
wsm = list_entry(pos, struct wsm, list);
list_del(pos);
kfree(wsm);
@@ -74,7 +80,7 @@
kfree(dev);
}
-bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName)
+bool mcore_device_open(struct mcore_device_t *dev, const char *device_name)
{
dev->instance = mobicore_open();
return (dev->instance != NULL);
@@ -102,6 +108,8 @@
}
struct session *session =
session_create(session_id, dev->instance, connection);
+ if (session == NULL)
+ return false;
list_add_tail(&(session->list), &(dev->session_vector));
return true;
}
@@ -154,16 +162,19 @@
/* Allocate shared memory */
void *virt_addr;
uint32_t handle;
- void *phys_addr;
int ret = mobicore_allocate_wsm(dev->instance, len, &handle,
- &virt_addr, &phys_addr);
+ &virt_addr);
if (ret != 0)
break;
- /* Register (vaddr,paddr) with device */
- wsm = wsm_create(virt_addr, len, handle, phys_addr);
+ /* Register (vaddr) with device */
+ wsm = wsm_create(virt_addr, len, handle);
+ if (wsm == NULL) {
+ mobicore_free_wsm(dev->instance, handle);
+ break;
+ }
- list_add_tail(&(wsm->list), &(dev->wsm_l2_vector));
+ list_add_tail(&(wsm->list), &(dev->wsm_mmu_vector));
} while (0);
@@ -177,7 +188,7 @@
struct wsm *tmp;
struct list_head *pos;
- list_for_each(pos, &dev->wsm_l2_vector) {
+ list_for_each(pos, &dev->wsm_mmu_vector) {
tmp = list_entry(pos, struct wsm, list);
if (tmp == wsm) {
ret = true;
@@ -205,7 +216,7 @@
struct wsm *wsm;
struct list_head *pos;
- list_for_each(pos, &dev->wsm_l2_vector) {
+ list_for_each(pos, &dev->wsm_mmu_vector) {
wsm = list_entry(pos, struct wsm, list);
if (virt_addr == wsm->virt_addr)
return wsm;
diff --git a/drivers/gud/mobicore_kernelapi/device.h b/drivers/gud/MobiCoreKernelApi/device.h
similarity index 95%
rename from drivers/gud/mobicore_kernelapi/device.h
rename to drivers/gud/MobiCoreKernelApi/device.h
index 16626bd..c795ee8 100644
--- a/drivers/gud/mobicore_kernelapi/device.h
+++ b/drivers/gud/MobiCoreKernelApi/device.h
@@ -21,7 +21,7 @@
struct mcore_device_t {
/* MobiCore Trustlet session associated with the device */
struct list_head session_vector;
- struct list_head wsm_l2_vector; /* WSM L2 Table */
+ struct list_head wsm_mmu_vector; /* WSM L2 or L3 Table */
uint32_t device_id; /* Device identifier */
struct connection *connection; /* The device connection */
@@ -36,7 +36,7 @@
void mcore_device_cleanup(struct mcore_device_t *dev);
-bool mcore_device_open(struct mcore_device_t *dev, const char *deviceName);
+bool mcore_device_open(struct mcore_device_t *dev, const char *device_name);
void mcore_device_close(struct mcore_device_t *dev);
bool mcore_device_has_sessions(struct mcore_device_t *dev);
bool mcore_device_create_new_session(
diff --git a/drivers/gud/mobicore_kernelapi/include/mcinq.h b/drivers/gud/MobiCoreKernelApi/include/mcinq.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/include/mcinq.h
rename to drivers/gud/MobiCoreKernelApi/include/mcinq.h
diff --git a/drivers/gud/mobicore_kernelapi/include/mcuuid.h b/drivers/gud/MobiCoreKernelApi/include/mcuuid.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/include/mcuuid.h
rename to drivers/gud/MobiCoreKernelApi/include/mcuuid.h
diff --git a/drivers/gud/mobicore_kernelapi/main.c b/drivers/gud/MobiCoreKernelApi/main.c
similarity index 97%
rename from drivers/gud/mobicore_kernelapi/main.c
rename to drivers/gud/MobiCoreKernelApi/main.c
index 8943c26..5da3ef7 100644
--- a/drivers/gud/mobicore_kernelapi/main.c
+++ b/drivers/gud/MobiCoreKernelApi/main.c
@@ -150,6 +150,10 @@
dev_info(mc_kapi, "Mobicore API module initialized!\n");
mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
+ if (mod_ctx == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return -ENOMEM;
+ }
#ifdef MC_NETLINK_COMPAT_V37
mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK,
&cfg);
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h
similarity index 100%
rename from drivers/gud/mobicore_kernelapi/public/mobicore_driver_api.h
rename to drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
similarity index 99%
rename from drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
rename to drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
index eaf7e6c..993d581 100644
--- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
+++ b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
@@ -171,7 +171,7 @@
struct mc_drv_cmd_map_bulk_mem_payload_t {
uint32_t session_id;
uint32_t handle;
- uint32_t phys_addr_l2;
+ uint32_t rfu;
uint32_t offset_payload;
uint32_t len_bulk_mem;
};
diff --git a/drivers/gud/mobicore_kernelapi/session.c b/drivers/gud/MobiCoreKernelApi/session.c
similarity index 86%
rename from drivers/gud/mobicore_kernelapi/session.c
rename to drivers/gud/MobiCoreKernelApi/session.c
index dae2c00..2ea50e8 100644
--- a/drivers/gud/mobicore_kernelapi/session.c
+++ b/drivers/gud/MobiCoreKernelApi/session.c
@@ -14,15 +14,18 @@
#include "session.h"
struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
- void *virt_addr, uint32_t len, uint32_t handle, void *phys_addr_wsm_l2)
+ void *virt_addr, uint32_t len, uint32_t handle)
{
struct bulk_buffer_descriptor *desc;
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ if (desc == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return NULL;
+ }
desc->virt_addr = virt_addr;
desc->len = len;
desc->handle = handle;
- desc->phys_addr_wsm_l2 = phys_addr_wsm_l2;
return desc;
}
@@ -33,6 +36,10 @@
struct session *session;
session = kzalloc(sizeof(*session), GFP_KERNEL);
+ if (session == NULL) {
+ MCDRV_DBG_ERROR(mc_kapi, "Allocation failure");
+ return NULL;
+ }
session->session_id = session_id;
session->instance = instance;
session->notification_connection = connection;
@@ -47,19 +54,14 @@
{
struct bulk_buffer_descriptor *bulk_buf_descr;
struct list_head *pos, *q;
- unsigned int phys_addr_wsm_l2;
/* Unmap still mapped buffers */
list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
bulk_buf_descr =
list_entry(pos, struct bulk_buffer_descriptor, list);
- phys_addr_wsm_l2 =
- (unsigned int)bulk_buf_descr->phys_addr_wsm_l2;
-
MCDRV_DBG_VERBOSE(mc_kapi,
- "Phys Addr of L2 Table = 0x%X, handle= %d",
- phys_addr_wsm_l2,
+ "handle= %d",
bulk_buf_descr->handle);
/* ignore any error, as we cannot do anything in this case. */
@@ -110,11 +112,10 @@
* Prepare the interface structure for memory registration in
* Kernel Module
*/
- uint32_t l2_table_phys;
uint32_t handle;
int ret = mobicore_map_vmem(session->instance, buf, len,
- &handle, &l2_table_phys);
+ &handle);
if (ret != 0) {
MCDRV_DBG_ERROR(mc_kapi,
@@ -123,15 +124,15 @@
break;
}
- MCDRV_DBG_VERBOSE(mc_kapi,
- "Phys Addr of L2 Table = 0x%X, handle=%d",
- (unsigned int)l2_table_phys, handle);
+ MCDRV_DBG_VERBOSE(mc_kapi, "handle=%d", handle);
/* Create new descriptor */
bulk_buf_descr =
- bulk_buffer_descriptor_create(buf, len,
- handle,
- (void *)l2_table_phys);
+ bulk_buffer_descriptor_create(buf, len, handle);
+ if (bulk_buf_descr == NULL) {
+ mobicore_unmap_vmem(session->instance, handle);
+ break;
+ }
/* Add to vector of descriptors */
list_add_tail(&(bulk_buf_descr->list),
@@ -165,8 +166,7 @@
MCDRV_DBG_ERROR(mc_kapi, "Virtual Address not found");
ret = false;
} else {
- MCDRV_DBG_VERBOSE(mc_kapi, "WsmL2 phys=0x%X, handle=%d",
- (unsigned int)bulk_buf->phys_addr_wsm_l2,
+ MCDRV_DBG_VERBOSE(mc_kapi, "Wsm handle=%d",
bulk_buf->handle);
/* ignore any error, as we cannot do anything */
diff --git a/drivers/gud/mobicore_kernelapi/session.h b/drivers/gud/MobiCoreKernelApi/session.h
similarity index 96%
rename from drivers/gud/mobicore_kernelapi/session.h
rename to drivers/gud/MobiCoreKernelApi/session.h
index 4a834e5..edcadcd 100644
--- a/drivers/gud/mobicore_kernelapi/session.h
+++ b/drivers/gud/MobiCoreKernelApi/session.h
@@ -19,9 +19,6 @@
uint32_t len; /* Length of the Bulk buffer */
uint32_t handle;
- /* The physical address of the L2 table of the Bulk buffer*/
- void *phys_addr_wsm_l2;
-
/* The list param for using the kernel lists*/
struct list_head list;
};
@@ -29,8 +26,7 @@
struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
void *virt_addr,
uint32_t len,
- uint32_t handle,
- void *phys_addr_wsm_l2
+ uint32_t handle
);
/*
diff --git a/drivers/gud/mobicore_kernelapi/wsm.h b/drivers/gud/MobiCoreKernelApi/wsm.h
similarity index 74%
rename from drivers/gud/mobicore_kernelapi/wsm.h
rename to drivers/gud/MobiCoreKernelApi/wsm.h
index f8a107c..3a1767d 100644
--- a/drivers/gud/mobicore_kernelapi/wsm.h
+++ b/drivers/gud/MobiCoreKernelApi/wsm.h
@@ -17,17 +17,7 @@
void *virt_addr;
uint32_t len;
uint32_t handle;
- void *phys_addr;
struct list_head list;
};
-struct wsm *wsm_create(
- void *virt_addr,
- uint32_t len,
- uint32_t handle,
-
- /* NULL this may be unknown, so is can be omitted */
- void *phys_addr
-);
-
#endif /* _MC_KAPI_WSM_H_ */
diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/build_tag.h
similarity index 96%
rename from drivers/gud/mobicore_driver/build_tag.h
rename to drivers/gud/build_tag.h
index 4a24275..18faf5a 100644
--- a/drivers/gud/mobicore_driver/build_tag.h
+++ b/drivers/gud/build_tag.h
@@ -26,4 +26,4 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define MOBICORE_COMPONENT_BUILD_TAG \
- "*** t-base-202_V001 ###"
+ "*** t-base-300-QC-8974-Android-V001 ###"
diff --git a/drivers/gud/mobicore_driver/mem.c b/drivers/gud/mobicore_driver/mem.c
deleted file mode 100644
index 33c51b6..0000000
--- a/drivers/gud/mobicore_driver/mem.c
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * MobiCore Driver Kernel Module.
- *
- * This module is written as a Linux device driver.
- * This driver represents the command proxy on the lowest layer, from the
- * secure world to the non secure world, and vice versa.
- * This driver is located in the non secure world (Linux).
- * This driver offers IOCTL commands, for access to the secure world, and has
- * the interface from the secure world to the normal world.
- * The access to the driver is possible with a file descriptor,
- * which has to be created by the fd = open(/dev/mobicore) command.
- *
- * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- * <-- Copyright Trustonic Limited 2013 -->
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include "main.h"
-#include "debug.h"
-#include "mem.h"
-
-#include <linux/highmem.h>
-#include <linux/slab.h>
-#include <linux/kthread.h>
-#include <linux/pagemap.h>
-#include <linux/device.h>
-
-
-/* MobiCore memory context data */
-struct mc_mem_context mem_ctx;
-
-/* convert L2 PTE to page pointer */
-static inline struct page *l2_pte_to_page(pte_t pte)
-{
- unsigned long phys_page_addr = ((unsigned long)pte & PAGE_MASK);
- unsigned int pfn = phys_page_addr >> PAGE_SHIFT;
- struct page *page = pfn_to_page(pfn);
- return page;
-}
-
-/* convert page pointer to L2 PTE */
-static inline pte_t page_to_l2_pte(struct page *page)
-{
- unsigned long pfn = page_to_pfn(page);
- unsigned long phys_addr = (pfn << PAGE_SHIFT);
- pte_t pte = (pte_t)(phys_addr & PAGE_MASK);
- return pte;
-}
-
-static inline void release_page(struct page *page)
-{
- SetPageDirty(page);
-
- page_cache_release(page);
-}
-
-static int lock_pages(struct task_struct *task, void *virt_start_page_addr,
- int pages_no, struct page **pages)
-{
- int locked_pages;
-
- /* lock user pages, must hold the mmap_sem to do this. */
- down_read(&(task->mm->mmap_sem));
- locked_pages = get_user_pages(
- task,
- task->mm,
- (unsigned long)virt_start_page_addr,
- pages_no,
- 1, /* write access */
- 0,
- pages,
- NULL);
- up_read(&(task->mm->mmap_sem));
-
- /* check if we could lock all pages. */
- if (locked_pages != pages_no) {
- MCDRV_DBG_ERROR(mcd, "get_user_pages() failed, locked_pages=%d",
- locked_pages);
- if (locked_pages > 0) {
- /* release all locked pages. */
- release_pages(pages, locked_pages, 0);
- }
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/* Get kernel pointer to shared L2 table given a per-process reference */
-struct l2table *get_l2_table_kernel_virt(struct mc_l2_table *table)
-{
- if (WARN(!table, "Invalid L2 table"))
- return NULL;
-
- if (WARN(!table->set, "Invalid L2 table set"))
- return NULL;
-
- if (WARN(!table->set->kernel_virt, "Invalid L2 pointer"))
- return NULL;
-
- return &(table->set->kernel_virt->table[table->idx]);
-}
-
-/* Get physical address of a shared L2 table given a per-process reference */
-struct l2table *get_l2_table_phys(struct mc_l2_table *table)
-{
- if (WARN(!table, "Invalid L2 table"))
- return NULL;
- if (WARN(!table->set, "Invalid L2 table set"))
- return NULL;
- if (WARN(!table->set->kernel_virt, "Invalid L2 phys pointer"))
- return NULL;
-
- return &(table->set->phys->table[table->idx]);
-}
-
-static inline int in_use(struct mc_l2_table *table)
-{
- return atomic_read(&table->usage) > 0;
-}
-
-/*
- * Search the list of used l2 tables and return the one with the handle.
- * Assumes the table_lock is taken.
- */
-struct mc_l2_table *find_l2_table(unsigned int handle)
-{
- struct mc_l2_table *table;
-
- list_for_each_entry(table, &mem_ctx.l2_tables, list) {
- if (table->handle == handle)
- return table;
- }
- return NULL;
-}
-
-/*
- * Allocate a new l2 table store plus L2_TABLES_PER_PAGE in the l2 free tables
- * list. Assumes the table_lock is already taken by the caller above.
- */
-static int alloc_table_store(void)
-{
- unsigned long store;
- struct mc_l2_tables_set *l2table_set;
- struct mc_l2_table *l2table, *l2table2;
- struct page *page;
- int ret = 0, i;
- /* temp list for holding the l2 tables */
- LIST_HEAD(temp);
-
- store = get_zeroed_page(GFP_KERNEL);
- if (!store)
- return -ENOMEM;
-
- /*
- * Actually, locking is not necessary, because kernel
- * memory is not supposed to get swapped out. But we
- * play safe....
- */
- page = virt_to_page(store);
- SetPageReserved(page);
-
- /* add all the descriptors to the free descriptors list */
- l2table_set = kmalloc(sizeof(*l2table_set), GFP_KERNEL | __GFP_ZERO);
- if (l2table_set == NULL) {
- ret = -ENOMEM;
- goto free_store;
- }
- /* initialize */
- l2table_set->kernel_virt = (void *)store;
- l2table_set->page = page;
- l2table_set->phys = (void *)virt_to_phys((void *)store);
- /* the set is not yet used */
- atomic_set(&l2table_set->used_tables, 0);
-
- /* init add to list. */
- INIT_LIST_HEAD(&(l2table_set->list));
- list_add(&l2table_set->list, &mem_ctx.l2_tables_sets);
-
- for (i = 0; i < L2_TABLES_PER_PAGE; i++) {
- /* allocate a WSM L2 descriptor */
- l2table = kmalloc(sizeof(*l2table), GFP_KERNEL | __GFP_ZERO);
- if (l2table == NULL) {
- ret = -ENOMEM;
- MCDRV_DBG_ERROR(mcd, "out of memory\n");
- /* Free the full temp list and the store in this case */
- goto free_temp_list;
- }
-
- /* set set reference */
- l2table->set = l2table_set;
- l2table->idx = i;
- l2table->virt = get_l2_table_kernel_virt(l2table);
- l2table->phys = (unsigned long)get_l2_table_phys(l2table);
- atomic_set(&l2table->usage, 0);
-
- /* add to temp list. */
- INIT_LIST_HEAD(&l2table->list);
- list_add_tail(&l2table->list, &temp);
- }
-
- /*
- * If everything went ok then merge the temp list with the global
- * free list
- */
- list_splice_tail(&temp, &mem_ctx.free_l2_tables);
- return 0;
-free_temp_list:
- list_for_each_entry_safe(l2table, l2table2, &temp, list) {
- kfree(l2table);
- }
-
- list_del(&l2table_set->list);
-
-free_store:
- free_page(store);
- return ret;
-
-}
-/*
- * Get a l2 table from the free tables list or allocate a new one and
- * initialize it. Assumes the table_lock is already taken.
- */
-static struct mc_l2_table *alloc_l2_table(struct mc_instance *instance)
-{
- int ret = 0;
- struct mc_l2_table *table = NULL;
-
- if (list_empty(&mem_ctx.free_l2_tables)) {
- ret = alloc_table_store();
- if (ret) {
- MCDRV_DBG_ERROR(mcd, "Failed to allocate new store!");
- return ERR_PTR(-ENOMEM);
- }
- /* if it's still empty something wrong has happened */
- if (list_empty(&mem_ctx.free_l2_tables)) {
- MCDRV_DBG_ERROR(mcd,
- "Free list not updated correctly!");
- return ERR_PTR(-EFAULT);
- }
- }
-
- /* get a WSM L2 descriptor */
- table = list_first_entry(&mem_ctx.free_l2_tables,
- struct mc_l2_table, list);
- if (table == NULL) {
- MCDRV_DBG_ERROR(mcd, "out of memory\n");
- return ERR_PTR(-ENOMEM);
- }
- /* Move it to the used l2 tables list */
- list_move_tail(&table->list, &mem_ctx.l2_tables);
-
- table->handle = get_unique_id();
- table->owner = instance;
-
- atomic_inc(&table->set->used_tables);
- atomic_inc(&table->usage);
-
- MCDRV_DBG_VERBOSE(mcd,
- "chunkPhys=%p,idx=%d", table->set->phys, table->idx);
-
- return table;
-}
-
-/*
- * Frees the object associated with a l2 table. Initially the object is moved
- * to the free tables list, but if all the 4 lists of the store are free
- * then the store is also released.
- * Assumes the table_lock is already taken.
- */
-static void free_l2_table(struct mc_l2_table *table)
-{
- struct mc_l2_tables_set *l2table_set;
-
- if (WARN(!table, "Invalid table"))
- return;
-
- l2table_set = table->set;
- if (WARN(!l2table_set, "Invalid table set"))
- return;
-
- list_move_tail(&table->list, &mem_ctx.free_l2_tables);
-
- /* if nobody uses this set, we can release it. */
- if (atomic_dec_and_test(&l2table_set->used_tables)) {
- struct mc_l2_table *tmp;
-
- /* remove from list */
- list_del(&l2table_set->list);
- /*
- * All the l2 tables are in the free list for this set
- * so we can just remove them from there
- */
- list_for_each_entry_safe(table, tmp, &mem_ctx.free_l2_tables,
- list) {
- if (table->set == l2table_set) {
- list_del(&table->list);
- kfree(table);
- }
- } /* end while */
-
- /*
- * We shouldn't recover from this since it was some data
- * corruption before
- */
- BUG_ON(!l2table_set->page);
- ClearPageReserved(l2table_set->page);
-
- BUG_ON(!l2table_set->kernel_virt);
- free_page((unsigned long)l2table_set->kernel_virt);
-
- kfree(l2table_set);
- }
-}
-
-/*
- * Create a L2 table in a WSM container that has been allocates previously.
- * Assumes the table lock is already taken or there is no need to take like
- * when first creating the l2 table the full list is locked.
- *
- * @task pointer to task owning WSM
- * @wsm_buffer user space WSM start
- * @wsm_len WSM length
- * @table Pointer to L2 table details
- */
-static int map_buffer(struct task_struct *task, void *wsm_buffer,
- unsigned int wsm_len, struct mc_l2_table *table)
-{
- int ret = 0;
- unsigned int i, nr_of_pages;
- /* start address of the 4 KiB page of wsm_buffer */
- void *virt_addr_page;
- struct page *page;
- struct l2table *l2table;
- struct page **l2table_as_array_of_pointers_to_page;
- /* page offset in wsm buffer */
- unsigned int offset;
-
- if (WARN(!wsm_buffer, "Invalid WSM buffer pointer"))
- return -EINVAL;
-
- if (WARN(wsm_len == 0, "Invalid WSM buffer length"))
- return -EINVAL;
-
- if (WARN(!table, "Invalid mapping table for WSM"))
- return -EINVAL;
-
- /* no size > 1Mib supported */
- if (wsm_len > SZ_1M) {
- MCDRV_DBG_ERROR(mcd, "size > 1 MiB\n");
- return -EINVAL;
- }
-
- MCDRV_DBG_VERBOSE(mcd, "WSM addr=0x%p, len=0x%08x\n", wsm_buffer,
- wsm_len);
-
-
- /* calculate page usage */
- virt_addr_page = (void *)(((unsigned long)(wsm_buffer)) & PAGE_MASK);
- offset = (unsigned int) (((unsigned long)(wsm_buffer)) & (~PAGE_MASK));
- nr_of_pages = PAGE_ALIGN(offset + wsm_len) / PAGE_SIZE;
-
- MCDRV_DBG_VERBOSE(mcd, "virt addr page start=0x%p, pages=%d\n",
- virt_addr_page, nr_of_pages);
-
- /* L2 table can hold max 1MiB in 256 pages. */
- if ((nr_of_pages * PAGE_SIZE) > SZ_1M) {
- MCDRV_DBG_ERROR(mcd, "WSM paged exceed 1 MiB\n");
- return -EINVAL;
- }
-
- l2table = table->virt;
- /*
- * We use the memory for the L2 table to hold the pointer
- * and convert them later. This works, as everything comes
- * down to a 32 bit value.
- */
- l2table_as_array_of_pointers_to_page = (struct page **)l2table;
-
- /* Request comes from user space */
- if (task != NULL && !is_vmalloc_addr(wsm_buffer)) {
- /*
- * lock user page in memory, so they do not get swapped
- * out.
- * REV axh: Kernel 2.6.27 added a new get_user_pages_fast()
- * function, maybe it is called fast_gup() in some versions.
- * handle user process doing a fork().
- * Child should not get things.
- * http://osdir.com/ml/linux-media/2009-07/msg00813.html
- * http://lwn.net/Articles/275808/
- */
- ret = lock_pages(task, virt_addr_page, nr_of_pages,
- l2table_as_array_of_pointers_to_page);
- if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "lock_user_pages() failed\n");
- return ret;
- }
- }
- /* Request comes from kernel space(cont buffer) */
- else if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
- void *uaddr = wsm_buffer;
- for (i = 0; i < nr_of_pages; i++) {
- page = virt_to_page(uaddr);
- if (!page) {
- MCDRV_DBG_ERROR(mcd, "failed to map address");
- return -EINVAL;
- }
- get_page(page);
- l2table_as_array_of_pointers_to_page[i] = page;
- uaddr += PAGE_SIZE;
- }
- }
- /* Request comes from kernel space(vmalloc buffer) */
- else {
- void *uaddr = wsm_buffer;
- for (i = 0; i < nr_of_pages; i++) {
- page = vmalloc_to_page(uaddr);
- if (!page) {
- MCDRV_DBG_ERROR(mcd, "failed to map address");
- return -EINVAL;
- }
- get_page(page);
- l2table_as_array_of_pointers_to_page[i] = page;
- uaddr += PAGE_SIZE;
- }
- }
-
- table->pages = nr_of_pages;
-
- /*
- * create L2 Table entries.
- * used_l2table->table contains a list of page pointers here.
- * For a proper cleanup we have to ensure that the following
- * code either works and used_l2table contains a valid L2 table
- * - or fails and used_l2table->table contains the list of page
- * pointers.
- * Any mixed contents will make cleanup difficult.
- */
- for (i = 0; i < nr_of_pages; i++) {
- pte_t pte;
- page = l2table_as_array_of_pointers_to_page[i];
-
- /*
- * create L2 table entry, see ARM MMU docu for details
- * about flags stored in the lowest 12 bits.
- * As a side reference, the Article
- * "ARM's multiply-mapped memory mess"
- * found in the collection at
- * http://lwn.net/Articles/409032/
- * is also worth reading.
- */
- pte = page_to_l2_pte(page)
- | PTE_EXT_AP1 | PTE_EXT_AP0
- | PTE_CACHEABLE | PTE_BUFFERABLE
- | PTE_TYPE_SMALL | PTE_TYPE_EXT | PTE_EXT_NG;
- /*
- * Linux uses different mappings for SMP systems(the
- * sharing flag is set for the pte. In order not to
- * confuse things too much in Mobicore make sure the
- * shared buffers have the same flags.
- * This should also be done in SWD side
- */
-#ifdef CONFIG_SMP
- pte |= PTE_EXT_SHARED | PTE_EXT_TEX(1);
-#endif
-
- l2table->table_entries[i] = pte;
- MCDRV_DBG_VERBOSE(mcd, "L2 entry %d: 0x%08x\n", i,
- (unsigned int)(pte));
- }
-
- /* ensure rest of table is empty */
- while (i < 255)
- l2table->table_entries[i++] = (pte_t)0;
-
-
- return ret;
-}
-
-/*
- * Remove a L2 table in a WSM container. Afterwards the container may be
- * released. Assumes the table_lock and the lock is taken.
- */
-static void unmap_buffers(struct mc_l2_table *table)
-{
- struct l2table *l2table;
- int i;
-
- if (WARN_ON(!table))
- return;
-
- /* found the table, now release the resources. */
- MCDRV_DBG_VERBOSE(mcd, "clear L2 table, phys_base=%p, nr_of_pages=%d\n",
- (void *)table->phys, table->pages);
-
- l2table = table->virt;
-
- /* release all locked user space pages */
- for (i = 0; i < table->pages; i++) {
- /* convert physical entries from L2 table to page pointers */
- pte_t pte = l2table->table_entries[i];
- struct page *page = l2_pte_to_page(pte);
- release_page(page);
- }
-
- /* remember that all pages have been freed */
- table->pages = 0;
-}
-
-/* Delete a used l2 table. Assumes the table_lock and the lock is taken */
-static void unmap_l2_table(struct mc_l2_table *table)
-{
- /* Check if it's not locked by other processes too! */
- if (!atomic_dec_and_test(&table->usage))
- return;
-
- /* release if Nwd and Swd/MC do no longer use it. */
- unmap_buffers(table);
- free_l2_table(table);
-}
-
-int mc_free_l2_table(struct mc_instance *instance, uint32_t handle)
-{
- struct mc_l2_table *table;
- int ret = 0;
-
- if (WARN(!instance, "No instance data available"))
- return -EFAULT;
-
- mutex_lock(&mem_ctx.table_lock);
- table = find_l2_table(handle);
-
- if (table == NULL) {
- MCDRV_DBG_VERBOSE(mcd, "entry not found");
- ret = -EINVAL;
- goto err_unlock;
- }
- if (instance != table->owner && !is_daemon(instance)) {
- MCDRV_DBG_ERROR(mcd, "instance does no own it");
- ret = -EPERM;
- goto err_unlock;
- }
- /* free table (if no further locks exist) */
- unmap_l2_table(table);
-err_unlock:
- mutex_unlock(&mem_ctx.table_lock);
-
- return ret;
-}
-
-int mc_lock_l2_table(struct mc_instance *instance, uint32_t handle)
-{
- int ret = 0;
- struct mc_l2_table *table = NULL;
-
- if (WARN(!instance, "No instance data available"))
- return -EFAULT;
-
- mutex_lock(&mem_ctx.table_lock);
- table = find_l2_table(handle);
-
- if (table == NULL) {
- MCDRV_DBG_VERBOSE(mcd, "entry not found %u\n", handle);
- ret = -EINVAL;
- goto table_err;
- }
- if (instance != table->owner && !is_daemon(instance)) {
- MCDRV_DBG_ERROR(mcd, "instance does no own it\n");
- ret = -EPERM;
- goto table_err;
- }
-
- /* lock entry */
- atomic_inc(&table->usage);
-table_err:
- mutex_unlock(&mem_ctx.table_lock);
- return ret;
-}
-/*
- * Allocate L2 table and map buffer into it.
- * That is, create respective table entries.
- * Must hold Semaphore mem_ctx.wsm_l2_sem
- */
-struct mc_l2_table *mc_alloc_l2_table(struct mc_instance *instance,
- struct task_struct *task, void *wsm_buffer, unsigned int wsm_len)
-{
- int ret = 0;
- struct mc_l2_table *table;
-
- if (WARN(!instance, "No instance data available"))
- return ERR_PTR(-EFAULT);
-
- mutex_lock(&mem_ctx.table_lock);
- table = alloc_l2_table(instance);
- if (IS_ERR(table)) {
- MCDRV_DBG_ERROR(mcd, "allocate_used_l2_table() failed\n");
- ret = -ENOMEM;
- goto err_no_mem;
- }
-
- /* create the L2 page for the WSM */
- ret = map_buffer(task, wsm_buffer, wsm_len, table);
-
- if (ret != 0) {
- MCDRV_DBG_ERROR(mcd, "map_buffer() failed\n");
- unmap_l2_table(table);
- goto err_no_mem;
- }
- MCDRV_DBG(mcd, "mapped buffer %p to table with handle %d @ %lx",
- wsm_buffer, table->handle, table->phys);
-
- mutex_unlock(&mem_ctx.table_lock);
- return table;
-err_no_mem:
- mutex_unlock(&mem_ctx.table_lock);
- return ERR_PTR(ret);
-}
-
-uint32_t mc_find_l2_table(uint32_t handle, int32_t fd)
-{
- uint32_t ret = 0;
- struct mc_l2_table *table = NULL;
-
- mutex_lock(&mem_ctx.table_lock);
- table = find_l2_table(handle);
-
- if (table == NULL) {
- MCDRV_DBG_ERROR(mcd, "entry not found %u\n", handle);
- ret = 0;
- goto table_err;
- }
-
- /* It's safe here not to lock the instance since the owner of
- * the table will be cleared only with the table lock taken */
- if (!mc_check_owner_fd(table->owner, fd)) {
- MCDRV_DBG_ERROR(mcd, "not valid owner%u\n", handle);
- ret = 0;
- goto table_err;
- }
-
- ret = table->phys;
-table_err:
- mutex_unlock(&mem_ctx.table_lock);
- return ret;
-}
-
-void mc_clean_l2_tables(void)
-{
- struct mc_l2_table *table, *tmp;
-
- mutex_lock(&mem_ctx.table_lock);
- /* Check if some WSM is orphaned. */
- list_for_each_entry_safe(table, tmp, &mem_ctx.l2_tables, list) {
- if (table->owner == NULL) {
- MCDRV_DBG(mcd,
- "clearing orphaned WSM L2: p=%lx pages=%d\n",
- table->phys, table->pages);
- unmap_l2_table(table);
- }
- }
- mutex_unlock(&mem_ctx.table_lock);
-}
-
-void mc_clear_l2_tables(struct mc_instance *instance)
-{
- struct mc_l2_table *table, *tmp;
-
- mutex_lock(&mem_ctx.table_lock);
- /* Check if some WSM is still in use. */
- list_for_each_entry_safe(table, tmp, &mem_ctx.l2_tables, list) {
- if (table->owner == instance) {
- MCDRV_DBG(mcd, "release WSM L2: p=%lx pages=%d\n",
- table->phys, table->pages);
- /* unlock app usage and free or mark it as orphan */
- table->owner = NULL;
- unmap_l2_table(table);
- }
- }
- mutex_unlock(&mem_ctx.table_lock);
-}
-
-int mc_init_l2_tables(void)
-{
- /* init list for WSM L2 chunks. */
- INIT_LIST_HEAD(&mem_ctx.l2_tables_sets);
-
- /* L2 table descriptor list. */
- INIT_LIST_HEAD(&mem_ctx.l2_tables);
-
- /* L2 table descriptor list. */
- INIT_LIST_HEAD(&mem_ctx.free_l2_tables);
-
- mutex_init(&mem_ctx.table_lock);
-
- return 0;
-}
-
-void mc_release_l2_tables()
-{
- struct mc_l2_table *table;
- /* Check if some WSM is still in use. */
- list_for_each_entry(table, &mem_ctx.l2_tables, list) {
- WARN(1, "WSM L2 still in use: phys=%lx ,nr_of_pages=%d\n",
- table->phys, table->pages);
- }
-}
diff --git a/drivers/gud/mobicore_driver/mem.h b/drivers/gud/mobicore_driver/mem.h
deleted file mode 100644
index 397a6cc..0000000
--- a/drivers/gud/mobicore_driver/mem.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * MobiCore driver module.(interface to the secure world SWD)
- *
- * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- * <-- Copyright Trustonic Limited 2013 -->
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _MC_MEM_H_
-#define _MC_MEM_H_
-
-#define FREE_FROM_SWD 1
-#define FREE_FROM_NWD 0
-
-#define LOCKED_BY_APP (1U << 0)
-#define LOCKED_BY_MC (1U << 1)
-
-/*
- * MobiCore specific page tables for world shared memory.
- * Linux uses shadow page tables, see arch/arm/include/asm/pgtable-2level.
- * MobiCore uses the default ARM format.
- *
- * Number of page table entries in one L2 table. This is ARM specific, an
- * L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each.
- */
-#define MC_ARM_L2_TABLE_ENTRIES 256
-
-/* ARM level 2 (L2) table with 256 entries. Size: 1k */
-struct l2table {
- pte_t table_entries[MC_ARM_L2_TABLE_ENTRIES];
-};
-
-/* Number of pages for L2 tables. There are 4 table in each page. */
-#define L2_TABLES_PER_PAGE 4
-
-/* Store for four L2 tables in one 4kb page*/
-struct mc_l2_table_store {
- struct l2table table[L2_TABLES_PER_PAGE];
-};
-
-/* Usage and maintenance information about mc_l2_table_store */
-struct mc_l2_tables_set {
- struct list_head list;
- /* kernel virtual address */
- struct mc_l2_table_store *kernel_virt;
- /* physical address */
- struct mc_l2_table_store *phys;
- /* pointer to page struct */
- struct page *page;
- /* How many pages from this set are used */
- atomic_t used_tables;
-};
-
-/*
- * L2 table allocated to the Daemon or a TLC describing a world shared buffer.
- * When users map a malloc()ed area into SWd, a L2 table is allocated.
- * In addition, the area of maximum 1MB virtual address space is mapped into
- * the L2 table and a handle for this table is returned to the user.
- */
-struct mc_l2_table {
- struct list_head list;
- /* Table lock */
- struct mutex lock;
- /* handle as communicated to user mode */
- unsigned int handle;
- /* Number of references kept to this l2 table */
- atomic_t usage;
- /* owner of this L2 table */
- struct mc_instance *owner;
- /* set describing where our L2 table is stored */
- struct mc_l2_tables_set *set;
- /* index into L2 table set */
- unsigned int idx;
- /* size of buffer */
- unsigned int pages;
- /* virtual address*/
- void *virt;
- unsigned long phys;
-};
-
-/* MobiCore Driver Memory context data. */
-struct mc_mem_context {
- struct mc_instance *daemon_inst;
- /* Backing store for L2 tables */
- struct list_head l2_tables_sets;
- /* Bookkeeping for used L2 tables */
- struct list_head l2_tables;
- /* Bookkeeping for free L2 tables */
- struct list_head free_l2_tables;
- /* semaphore to synchronize access to above lists */
- struct mutex table_lock;
-};
-
-/*
- * Allocate L2 table and map buffer into it.
- * That is, create respective table entries.
- */
-struct mc_l2_table *mc_alloc_l2_table(struct mc_instance *instance,
- struct task_struct *task, void *wsm_buffer, unsigned int wsm_len);
-
-/* Delete all the l2 tables associated with an instance */
-void mc_clear_l2_tables(struct mc_instance *instance);
-
-/* Release all orphaned L2 tables */
-void mc_clean_l2_tables(void);
-
-/* Delete a used l2 table. */
-int mc_free_l2_table(struct mc_instance *instance, uint32_t handle);
-
-/*
- * Lock a l2 table - the daemon adds +1 to refcount of the L2 table
- * marking it in use by SWD so it doesn't get released when the TLC dies.
- */
-int mc_lock_l2_table(struct mc_instance *instance, uint32_t handle);
-/* Unlock l2 table. */
-int mc_unlock_l2_table(struct mc_instance *instance, uint32_t handle);
-/* Return the phys address of l2 table. */
-uint32_t mc_find_l2_table(uint32_t handle, int32_t fd);
-/* Release all used l2 tables to Linux memory space */
-void mc_release_l2_tables(void);
-
-/* Initialize all l2 tables structure */
-int mc_init_l2_tables(void);
-
-#endif /* _MC_MEM_H_ */
diff --git a/drivers/gud/mobicore_driver/ops.c b/drivers/gud/mobicore_driver/ops.c
deleted file mode 100644
index 9d4af72..0000000
--- a/drivers/gud/mobicore_driver/ops.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * MobiCore Driver Kernel Module.
- *
- * This module is written as a Linux device driver.
- * This driver represents the command proxy on the lowest layer, from the
- * secure world to the non secure world, and vice versa.
- * This driver is located in the non secure world (Linux).
- * This driver offers IOCTL commands, for access to the secure world, and has
- * the interface from the secure world to the normal world.
- * The access to the driver is possible with a file descriptor,
- * which has to be created by the fd = open(/dev/mobicore) command.
- *
- * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
- * <-- Copyright Trustonic Limited 2013 -->
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kthread.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/cpu.h>
-
-#include "main.h"
-#include "fastcall.h"
-#include "ops.h"
-#include "mem.h"
-#include "pm.h"
-#include "debug.h"
-
-/* MobiCore context data */
-static struct mc_context *ctx;
-
-static inline long smc(union fc_generic *fc)
-{
- /* If we request sleep yields must be filtered out as they
- * make no sense */
- if (ctx->mcp)
- if (ctx->mcp->flags.sleep_mode.SleepReq) {
- if (fc->as_in.cmd == MC_SMC_N_YIELD)
- return MC_FC_RET_ERR_INVALID;
- }
- return _smc(fc);
-}
-
-#ifdef MC_FASTCALL_WORKER_THREAD
-
-static struct task_struct *fastcall_thread;
-static DEFINE_KTHREAD_WORKER(fastcall_worker);
-
-struct fastcall_work {
- struct kthread_work work;
- void *data;
-};
-
-static void fastcall_work_func(struct kthread_work *work)
-{
- struct fastcall_work *fc_work =
- container_of(work, struct fastcall_work, work);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
- mc_pm_clock_enable();
-#endif
-
- smc(fc_work->data);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
- mc_pm_clock_disable();
-#endif
-}
-
-void mc_fastcall(void *data)
-{
- struct fastcall_work fc_work = {
- KTHREAD_WORK_INIT(fc_work.work, fastcall_work_func),
- .data = data,
- };
-
- queue_kthread_work(&fastcall_worker, &fc_work.work);
- flush_kthread_work(&fc_work.work);
-}
-
-int mc_fastcall_init(struct mc_context *context)
-{
- int ret = 0;
-
- ctx = context;
-
- fastcall_thread = kthread_create(kthread_worker_fn, &fastcall_worker,
- "mc_fastcall");
- if (IS_ERR(fastcall_thread)) {
- ret = PTR_ERR(fastcall_thread);
- fastcall_thread = NULL;
- MCDRV_DBG_ERROR(mcd, "cannot create fastcall wq (%d)\n", ret);
- return ret;
- }
-
- /* this thread MUST run on CPU 0 */
- kthread_bind(fastcall_thread, 0);
- wake_up_process(fastcall_thread);
-
- return 0;
-}
-
-void mc_fastcall_destroy(void)
-{
- if (!IS_ERR_OR_NULL(fastcall_thread)) {
- kthread_stop(fastcall_thread);
- fastcall_thread = NULL;
- }
-}
-#else
-
-struct fastcall_work_struct {
- struct work_struct work;
- void *data;
-};
-
-static void fastcall_work_func(struct work_struct *work)
-{
- struct fastcall_work_struct *fc_work =
- container_of(work, struct fastcall_work_struct, work);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
- mc_pm_clock_enable();
-#endif
-
- smc(fc_work->data);
-
-#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
- mc_pm_clock_disable();
-#endif
-}
-
-void mc_fastcall(void *data)
-{
- struct fastcall_work_struct work = {
- .data = data,
- };
- INIT_WORK(&work.work, fastcall_work_func);
- schedule_work_on(0, &work.work);
-
- flush_work(&work.work);
-}
-
-int mc_fastcall_init(struct mc_context *context)
-{
- ctx = context;
- return 0;
-};
-
-void mc_fastcall_destroy(void) {};
-#endif
-
-int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info)
-{
- int ret = 0;
- union mc_fc_info fc_info;
-
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
-
- memset(&fc_info, 0, sizeof(fc_info));
- fc_info.as_in.cmd = MC_FC_INFO;
- fc_info.as_in.ext_info_id = ext_info_id;
-
- MCDRV_DBG(mcd, "fc_info <- cmd=0x%08x, ext_info_id=0x%08x\n",
- fc_info.as_in.cmd, fc_info.as_in.ext_info_id);
-
- mc_fastcall(&(fc_info.as_generic));
-
- MCDRV_DBG(mcd,
- "fc_info -> r=0x%08x ret=0x%08x state=0x%08x ext_info=0x%08x",
- fc_info.as_out.resp,
- fc_info.as_out.ret,
- fc_info.as_out.state,
- fc_info.as_out.ext_info);
-
- ret = convert_fc_ret(fc_info.as_out.ret);
-
- *state = fc_info.as_out.state;
- *ext_info = fc_info.as_out.ext_info;
-
- MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-/* Yield to MobiCore */
-int mc_yield(void)
-{
- int ret = 0;
- union fc_generic yield;
-
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
-
- memset(&yield, 0, sizeof(yield));
- yield.as_in.cmd = MC_SMC_N_YIELD;
- mc_fastcall(&yield);
- ret = convert_fc_ret(yield.as_out.ret);
-
- return ret;
-}
-
-/* call common notify */
-int mc_nsiq(void)
-{
- int ret = 0;
- union fc_generic nsiq;
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
-
- memset(&nsiq, 0, sizeof(nsiq));
- nsiq.as_in.cmd = MC_SMC_N_SIQ;
- mc_fastcall(&nsiq);
- ret = convert_fc_ret(nsiq.as_out.ret);
-
- return ret;
-}
-
-/* call common notify */
-int _nsiq(void)
-{
- int ret = 0;
- union fc_generic nsiq;
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
-
- memset(&nsiq, 0, sizeof(nsiq));
- nsiq.as_in.cmd = MC_SMC_N_SIQ;
- _smc(&nsiq);
- ret = convert_fc_ret(nsiq.as_out.ret);
-
- return ret;
-}
-
-/* Call the INIT fastcall to setup MobiCore initialization */
-int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length,
- uint32_t mcp_offset, uint32_t mcp_length)
-{
- int ret = 0;
- union mc_fc_init fc_init;
-
- MCDRV_DBG_VERBOSE(mcd, "enter\n");
-
- memset(&fc_init, 0, sizeof(fc_init));
-
- fc_init.as_in.cmd = MC_FC_INIT;
- /* base address of mci buffer 4KB aligned */
- fc_init.as_in.base = base;
- /* notification buffer start/length [16:16] [start, length] */
- fc_init.as_in.nq_info = (nq_offset << 16) | (nq_length & 0xFFFF);
- /* mcp buffer start/length [16:16] [start, length] */
- fc_init.as_in.mcp_info = (mcp_offset << 16) | (mcp_length & 0xFFFF);
-
- /*
- * Set KMOD notification queue to start of MCI
- * mciInfo was already set up in mmap
- */
- MCDRV_DBG(mcd,
- "cmd=0x%08x, base=0x%08x,nq_info=0x%08x, mcp_info=0x%08x\n",
- fc_init.as_in.cmd, fc_init.as_in.base, fc_init.as_in.nq_info,
- fc_init.as_in.mcp_info);
-
- mc_fastcall(&fc_init.as_generic);
-
- MCDRV_DBG(mcd, "out cmd=0x%08x, ret=0x%08x\n", fc_init.as_out.resp,
- fc_init.as_out.ret);
-
- ret = convert_fc_ret(fc_init.as_out.ret);
-
- MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret);
-
- return ret;
-}
-
-/* Return MobiCore driver version */
-uint32_t mc_get_version(void)
-{
- MCDRV_DBG(mcd, "MobiCore driver version is %i.%i\n",
- MCDRVMODULEAPI_VERSION_MAJOR,
- MCDRVMODULEAPI_VERSION_MINOR);
-
- return MC_VERSION(MCDRVMODULEAPI_VERSION_MAJOR,
- MCDRVMODULEAPI_VERSION_MINOR);
-}
diff --git a/drivers/gud/setupDrivers.sh b/drivers/gud/setupDrivers.sh
new file mode 100644
index 0000000..8f877b7
--- /dev/null
+++ b/drivers/gud/setupDrivers.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+export COMP_PATH_ROOT=$(dirname $(readlink -f $BASH_SOURCE)) #set this to the absolute path of the folder containing this file
+
+# This part has to be set by the customer
+# To be set, absolute path of kernel folder
+export LINUX_PATH=
+# To be set, absolute path! CROSS_COMPILE variable needed by kernel eg /home/user/arm-2009q3/bin/arm-none-linux-gnueabi-
+export CROSS_COMPILE=
+# To be set, build mode debug or release
+export MODE=debug
+# To be set, the absolute path to the Linux Android NDK
+export NDK_PATH=
+
+# Global variables needed by build scripts
+export COMP_PATH_Logwrapper=$COMP_PATH_ROOT/Logwrapper/Out
+export COMP_PATH_MobiCore=$COMP_PATH_ROOT/MobiCore/Out
+export COMP_PATH_MobiCoreDriverMod=$COMP_PATH_ROOT/mobicore_driver/Out
+export COMP_PATH_MobiCoreDriverLib=$COMP_PATH_ROOT/daemon/Out
+export COMP_PATH_AndroidNdkLinux=$NDK_PATH
\ No newline at end of file
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index d708d94..a605720 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -26,8 +26,8 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
-#include <linux/input-polldev.h>
#include <linux/sensors.h>
+#include <linux/input.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
#include <linux/irq.h>
@@ -44,8 +44,6 @@
#define POLL_INTERVAL_MAX 10000
#define POLL_INTERVAL 100 /* msecs */
-/* if sensor is standby ,set POLL_STOP_TIME to slow down the poll */
-#define POLL_STOP_TIME 10000
#define INPUT_FUZZ 32
#define INPUT_FLAT 32
#define INPUT_DATA_DIVIDER 16
@@ -81,6 +79,7 @@
#define MMA_INT_ROUTING_CFG 0x01
#define MMA_POWER_CFG_MASK 0xFE
+#define MMA_ODR_MASK 0x38
struct sensor_regulator {
struct regulator *vreg;
@@ -189,7 +188,7 @@
};
struct mma8x5x_data {
struct i2c_client *client;
- struct input_polled_dev *poll_dev;
+ struct delayed_work dwork;
struct input_dev *idev;
struct mutex data_lock;
struct sensors_classdev cdev;
@@ -229,7 +228,6 @@
{{ 0, 1, 0}, { 1, 0, 0}, {0, 0, -1} },
{{ 1, 0, 0}, { 0, -1, 0}, {0, 0, -1} },
};
-static struct mma8x5x_data *drv_data;
static int mma8x5x_config_regulator(struct i2c_client *client, bool on)
{
int rc = 0, i;
@@ -408,7 +406,7 @@
if (result < 0)
goto out;
- val = (u8)result | val;
+ val = ((u8)result & ~MMA_ODR_MASK) | val;
result = i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1,
(val & MMA_POWER_CFG_MASK));
if (result < 0)
@@ -487,32 +485,27 @@
static void mma8x5x_report_data(struct mma8x5x_data *pdata)
{
- struct input_polled_dev *poll_dev = pdata->poll_dev;
struct mma8x5x_data_axis data;
+
mutex_lock(&pdata->data_lock);
- if ((pdata->active & MMA_STATE_MASK) == MMA_STANDBY) {
- poll_dev->poll_interval = POLL_STOP_TIME;
- /* if standby ,set as 10s to slow the poll. */
- goto out;
- } else {
- if (poll_dev->poll_interval == POLL_STOP_TIME)
- poll_dev->poll_interval = pdata->poll_delay;
- }
if (mma8x5x_read_data(pdata->client, &data) != 0)
goto out;
mma8x5x_data_convert(pdata, &data);
- input_report_abs(poll_dev->input, ABS_X, data.x);
- input_report_abs(poll_dev->input, ABS_Y, data.y);
- input_report_abs(poll_dev->input, ABS_Z, data.z);
- input_sync(poll_dev->input);
+ input_report_abs(pdata->idev, ABS_X, data.x);
+ input_report_abs(pdata->idev, ABS_Y, data.y);
+ input_report_abs(pdata->idev, ABS_Z, data.z);
+ input_sync(pdata->idev);
out:
mutex_unlock(&pdata->data_lock);
}
-static void mma8x5x_dev_poll(struct input_polled_dev *dev)
+static void mma8x5x_dev_poll(struct work_struct *work)
{
- struct mma8x5x_data *pdata = (struct mma8x5x_data *)dev->private;
+ struct mma8x5x_data *pdata = container_of((struct delayed_work *)work,
+ struct mma8x5x_data, dwork);
mma8x5x_report_data(pdata);
+ schedule_delayed_work(&pdata->dwork,
+ msecs_to_jiffies(pdata->poll_delay));
}
static irqreturn_t mma8x5x_interrupt(int vec, void *data)
@@ -577,12 +570,18 @@
dev_err(&client->dev, "change device state failed!");
goto err_failed;
}
+
+ schedule_delayed_work(&pdata->dwork,
+ msecs_to_jiffies(pdata->poll_delay));
+
pdata->active = MMA_ACTIVED;
dev_dbg(&client->dev, "%s:mma enable setting active.\n",
__func__);
}
} else if (enable == 0) {
if (pdata->active == MMA_ACTIVED) {
+ cancel_delayed_work_sync(&pdata->dwork);
+
val = i2c_smbus_read_byte_data(client,
MMA8X5X_CTRL_REG1);
if (val < 0) {
@@ -616,7 +615,7 @@
static ssize_t mma8x5x_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
struct i2c_client *client;
u8 val;
int enable;
@@ -641,7 +640,7 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
struct i2c_client *client;
int ret;
unsigned long enable;
@@ -663,7 +662,7 @@
static ssize_t mma8x5x_position_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
int position = 0;
if (!pdata) {
@@ -680,7 +679,7 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
int position;
int ret;
@@ -714,7 +713,6 @@
} else {
mutex_lock(&pdata->data_lock);
pdata->poll_delay = delay_ms;
- pdata->poll_dev->poll_interval = pdata->poll_delay;
mutex_unlock(&pdata->data_lock);
}
@@ -724,7 +722,7 @@
static ssize_t mma8x5x_poll_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
if (!pdata) {
dev_err(dev, "Invalid driver private data!");
@@ -738,7 +736,7 @@
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct mma8x5x_data *pdata = drv_data;
+ struct mma8x5x_data *pdata = dev_get_drvdata(dev);
int delay;
int ret;
@@ -825,7 +823,6 @@
struct input_dev *idev;
struct mma8x5x_data *pdata;
struct i2c_adapter *adapter;
- struct input_polled_dev *poll_dev;
adapter = to_i2c_adapter(client->dev.parent);
/* power on the device */
result = mma8x5x_config_regulator(client, 1);
@@ -836,7 +833,7 @@
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA);
if (!result)
- goto err_out;
+ goto err_check_id;
chip_id = i2c_smbus_read_byte_data(client, MMA8X5X_WHO_AM_I);
@@ -846,14 +843,14 @@
chip_id, MMA8451_ID, MMA8452_ID, MMA8453_ID,
MMA8652_ID, MMA8653_ID);
result = -EINVAL;
- goto err_out;
+ goto err_check_id;
}
/* set the private data */
pdata = kzalloc(sizeof(struct mma8x5x_data), GFP_KERNEL);
if (!pdata) {
result = -ENOMEM;
dev_err(&client->dev, "alloc data memory error!\n");
- goto err_out;
+ goto err_check_id;
}
if (client->dev.of_node) {
@@ -867,12 +864,10 @@
}
/* Initialize the MMA8X5X chip */
- drv_data = pdata;
pdata->client = client;
pdata->chip_id = chip_id;
pdata->mode = MODE_2G;
- pdata->poll_delay = POLL_STOP_TIME;
- pdata->poll_dev = NULL;
+ pdata->poll_delay = POLL_INTERVAL;
mutex_init(&pdata->data_lock);
i2c_set_clientdata(client, pdata);
@@ -894,29 +889,9 @@
if (result) {
dev_err(&client->dev,
"set_direction for irq gpio failed\n");
- goto err_set_direction;
+ goto err_set_gpio_direction;
}
}
- idev = input_allocate_device();
- if (!idev) {
- result = -ENOMEM;
- dev_err(&client->dev, "alloc input device failed!\n");
- goto err_alloc_poll_device;
- }
- input_set_drvdata(idev, pdata);
- idev->name = ACCEL_INPUT_DEV_NAME;
- idev->uniq = mma8x5x_id2name(pdata->chip_id);
- idev->id.bustype = BUS_I2C;
- idev->evbit[0] = BIT_MASK(EV_ABS);
- input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
- input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
- input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
- result = input_register_device(idev);
- if (result) {
- dev_err(&client->dev, "register input device failed!\n");
- goto err_register_device;
- }
- pdata->idev = idev;
device_init_wakeup(&client->dev, true);
enable_irq_wake(client->irq);
result = request_threaded_irq(client->irq, NULL,
@@ -930,34 +905,29 @@
}
mma8x5x_device_int_init(client);
} else {
- /* create the input poll device */
- poll_dev = input_allocate_polled_device();
- if (!poll_dev) {
- result = -ENOMEM;
- dev_err(&client->dev, "alloc poll device failed!\n");
- goto err_alloc_poll_device;
- }
- pdata->poll_dev = poll_dev;
- pdata->idev = NULL;
- poll_dev->poll = mma8x5x_dev_poll;
- poll_dev->poll_interval = POLL_STOP_TIME;
- poll_dev->poll_interval_min = POLL_INTERVAL_MIN;
- poll_dev->poll_interval_max = POLL_INTERVAL_MAX;
- poll_dev->private = pdata;
- idev = poll_dev->input;
- idev->name = ACCEL_INPUT_DEV_NAME;
- idev->uniq = mma8x5x_id2name(pdata->chip_id);
- idev->id.bustype = BUS_I2C;
- idev->evbit[0] = BIT_MASK(EV_ABS);
- input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
- input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
- input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
- result = input_register_polled_device(pdata->poll_dev);
- if (result) {
- dev_err(&client->dev, "register poll device failed!\n");
- goto err_register_device;
- }
+ INIT_DELAYED_WORK(&pdata->dwork, mma8x5x_dev_poll);
}
+ idev = input_allocate_device();
+ if (!idev) {
+ result = -ENOMEM;
+ dev_err(&client->dev, "alloc input device failed!\n");
+ goto err_alloc_poll_device;
+ }
+ input_set_drvdata(idev, pdata);
+ idev->name = ACCEL_INPUT_DEV_NAME;
+ idev->uniq = mma8x5x_id2name(pdata->chip_id);
+ idev->id.bustype = BUS_I2C;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+ input_set_abs_params(idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
+ input_set_abs_params(idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
+ input_set_abs_params(idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
+ result = input_register_device(idev);
+ if (result) {
+ dev_err(&client->dev, "register input device failed!\n");
+ goto err_register_device;
+ }
+ pdata->idev = idev;
+
result = sysfs_create_group(&idev->dev.kobj, &mma8x5x_attr_group);
if (result) {
dev_err(&client->dev, "create device file failed!\n");
@@ -983,23 +953,20 @@
err_create_class_sysfs:
sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group);
err_create_sysfs:
- input_unregister_polled_device(pdata->poll_dev);
+ input_unregister_device(idev);
+err_register_device:
+ input_free_device(idev);
+err_alloc_poll_device:
err_register_irq:
if (pdata->use_int)
device_init_wakeup(&client->dev, false);
-err_register_device:
- if (pdata->use_int)
- input_free_device(idev);
- else
- input_free_polled_device(pdata->poll_dev);
-err_alloc_poll_device:
-err_set_direction:
+err_set_gpio_direction:
if (gpio_is_valid(pdata->int_pin) && pdata->use_int)
gpio_free(pdata->int_pin);
err_request_gpio:
err_parse_dt:
kfree(pdata);
-err_out:
+err_check_id:
mma8x5x_config_regulator(client, 0);
err_power_on:
return result;
@@ -1007,14 +974,22 @@
static int __devexit mma8x5x_remove(struct i2c_client *client)
{
struct mma8x5x_data *pdata = i2c_get_clientdata(client);
- struct input_polled_dev *poll_dev;
+ struct input_dev *idev;
+
mma8x5x_device_stop(client);
if (pdata) {
- poll_dev = pdata->poll_dev;
- input_unregister_polled_device(poll_dev);
- input_free_polled_device(poll_dev);
+ idev = pdata->idev;
+ sysfs_remove_group(&idev->dev.kobj, &mma8x5x_attr_group);
+ if (pdata->use_int) {
+ device_init_wakeup(&client->dev, false);
+ if (gpio_is_valid(pdata->int_pin))
+ gpio_free(pdata->int_pin);
+ }
+ input_unregister_device(idev);
+ input_free_device(idev);
kfree(pdata);
}
+ mma8x5x_config_regulator(client, 0);
return 0;
}
@@ -1026,8 +1001,10 @@
if (pdata->use_int && pdata->active == MMA_ACTIVED)
return 0;
- if (pdata->active == MMA_ACTIVED)
+ if (pdata->active == MMA_ACTIVED) {
mma8x5x_device_stop(client);
+ cancel_delayed_work_sync(&pdata->dwork);
+ }
if (pdata->active & MMA_SHUTTEDDOWN)
return 0;
if (!mma8x5x_config_regulator(client, 0))
@@ -1058,6 +1035,8 @@
if (pdata->active == MMA_ACTIVED) {
val = i2c_smbus_read_byte_data(client, MMA8X5X_CTRL_REG1);
i2c_smbus_write_byte_data(client, MMA8X5X_CTRL_REG1, val|0x01);
+ schedule_delayed_work(&pdata->dwork,
+ msecs_to_jiffies(pdata->poll_delay));
}
return 0;
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index 91d787f..0d75869 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -77,12 +77,6 @@
#define GTP_MAX_TOUCH 5
#define GTP_ESD_CHECK_CIRCLE_MS 2000
-#if GTP_HAVE_TOUCH_KEY
-static const u16 touch_key_array[] = {KEY_MENU, KEY_HOMEPAGE, KEY_BACK};
-#define GTP_MAX_KEY_NUM (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
-
-#endif
-
static void gtp_int_sync(struct goodix_ts_data *ts, int ms);
static int gtp_i2c_test(struct i2c_client *client);
static int goodix_power_off(struct goodix_ts_data *ts);
@@ -105,15 +99,14 @@
static int gtp_init_ext_watchdog(struct i2c_client *client);
#endif
-#if GTP_SLIDE_WAKEUP
-enum doze_status {
+enum doze {
DOZE_DISABLED = 0,
DOZE_ENABLED = 1,
DOZE_WAKEUP = 2,
};
-static enum doze_status = DOZE_DISABLED;
+static enum doze doze_status = DOZE_DISABLED;
static s8 gtp_enter_doze(struct goodix_ts_data *ts);
-#endif
+
bool init_done;
static u8 chip_gt9xxs; /* true if ic is gt9xxs, like gt915s */
u8 grp_cfg_version;
@@ -163,11 +156,11 @@
dev_err(&client->dev, "I2C retry: %d\n", retries + 1);
}
if (retries == GTP_I2C_RETRY_5) {
-#if GTP_SLIDE_WAKEUP
- /* reset chip would quit doze mode */
- if (DOZE_ENABLED == doze_status)
- return ret;
-#endif
+ if (ts->pdata->slide_wakeup)
+ /* reset chip would quit doze mode */
+ if (DOZE_ENABLED == doze_status)
+ return ret;
+
if (init_done)
gtp_reset_guitar(ts, 10);
else
@@ -209,10 +202,10 @@
dev_err(&client->dev, "I2C retry: %d\n", retries + 1);
}
if ((retries == GTP_I2C_RETRY_5)) {
-#if GTP_SLIDE_WAKEUP
- if (DOZE_ENABLED == doze_status)
- return ret;
-#endif
+ if (ts->pdata->slide_wakeup)
+ if (DOZE_ENABLED == doze_status)
+ return ret;
+
if (init_done)
gtp_reset_guitar(ts, 10);
else
@@ -278,24 +271,25 @@
*********************************************************/
int gtp_send_cfg(struct goodix_ts_data *ts)
{
- int ret;
-#if GTP_DRIVER_SEND_CFG
- int retry = 0;
+ int ret = 0;
+ int retry;
- if (ts->fixed_cfg) {
- dev_dbg(&ts->client->dev,
- "Ic fixed config, no config sent!");
- ret = 2;
- } else {
- for (retry = 0; retry < GTP_I2C_RETRY_5; retry++) {
- ret = gtp_i2c_write(ts->client,
- ts->config_data,
- GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
- if (ret > 0)
- break;
+ if (ts->pdata->driver_send_cfg) {
+ if (ts->fixed_cfg) {
+ dev_dbg(&ts->client->dev,
+ "Ic fixed config, no config sent!");
+ ret = 2;
+ } else {
+ for (retry = 0; retry < GTP_I2C_RETRY_5; retry++) {
+ ret = gtp_i2c_write(ts->client,
+ ts->config_data,
+ GTP_CONFIG_MAX_LENGTH +
+ GTP_ADDR_LENGTH);
+ if (ret > 0)
+ break;
+ }
}
}
-#endif
return ret;
}
@@ -355,9 +349,8 @@
static void gtp_touch_down(struct goodix_ts_data *ts, int id, int x, int y,
int w)
{
-#if GTP_CHANGE_X2Y
- swap(x, y);
-#endif
+ if (ts->pdata->change_x2y)
+ swap(x, y);
input_mt_slot(ts->input_dev, id);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
@@ -402,9 +395,7 @@
u8 finger = 0;
static u16 pre_touch;
static u8 pre_key;
-#if GTP_WITH_PEN
static u8 pre_pen;
-#endif
u8 key_value = 0;
u8 *coor_data = NULL;
s32 input_x = 0;
@@ -414,10 +405,7 @@
s32 i = 0;
int ret = -1;
struct goodix_ts_data *ts = NULL;
-
-#if GTP_SLIDE_WAKEUP
u8 doze_buf[3] = {0x81, 0x4B};
-#endif
ts = container_of(work, struct goodix_ts_data, work);
#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
@@ -425,55 +413,59 @@
return;
#endif
-#if GTP_SLIDE_WAKEUP
- if (DOZE_ENABLED == doze_status) {
- ret = gtp_i2c_read(ts->client, doze_buf, 3);
- if (ret > 0) {
- if (doze_buf[2] == 0xAA) {
- dev_dbg(&ts->client->dev,
- "Slide(0xAA) To Light up the screen!");
- doze_status = DOZE_WAKEUP;
- input_report_key(
- ts->input_dev, KEY_POWER, 1);
- input_sync(ts->input_dev);
- input_report_key(
- ts->input_dev, KEY_POWER, 0);
- input_sync(ts->input_dev);
- /* clear 0x814B */
- doze_buf[2] = 0x00;
- gtp_i2c_write(ts->client, doze_buf, 3);
- } else if (doze_buf[2] == 0xBB) {
- dev_dbg(&ts->client->dev,
- "Slide(0xBB) To Light up the screen!");
- doze_status = DOZE_WAKEUP;
- input_report_key(ts->input_dev, KEY_POWER, 1);
- input_sync(ts->input_dev);
- input_report_key(ts->input_dev, KEY_POWER, 0);
- input_sync(ts->input_dev);
- /* clear 0x814B*/
- doze_buf[2] = 0x00;
- gtp_i2c_write(ts->client, doze_buf, 3);
- } else if (0xC0 == (doze_buf[2] & 0xC0)) {
- dev_dbg(&ts->client->dev,
- "double click to light up the screen!");
- doze_status = DOZE_WAKEUP;
- input_report_key(ts->input_dev, KEY_POWER, 1);
- input_sync(ts->input_dev);
- input_report_key(ts->input_dev, KEY_POWER, 0);
- input_sync(ts->input_dev);
- /* clear 0x814B */
- doze_buf[2] = 0x00;
- gtp_i2c_write(ts->client, doze_buf, 3);
- } else {
- gtp_enter_doze(ts);
+ if (ts->pdata->slide_wakeup) {
+ if (DOZE_ENABLED == doze_status) {
+ ret = gtp_i2c_read(ts->client, doze_buf, 3);
+ if (ret > 0) {
+ if (doze_buf[2] == 0xAA) {
+ dev_dbg(&ts->client->dev,
+ "Slide(0xAA) To Light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(
+ ts->input_dev, KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(
+ ts->input_dev, KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ /* clear 0x814B */
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ } else if (doze_buf[2] == 0xBB) {
+ dev_dbg(&ts->client->dev,
+ "Slide(0xBB) To Light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(ts->input_dev,
+ KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(ts->input_dev,
+ KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ /* clear 0x814B*/
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ } else if (0xC0 == (doze_buf[2] & 0xC0)) {
+ dev_dbg(&ts->client->dev,
+ "double click to light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(ts->input_dev,
+ KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(ts->input_dev,
+ KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ /* clear 0x814B */
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ } else {
+ gtp_enter_doze(ts);
+ }
}
- }
- if (ts->use_irq)
- gtp_irq_enable(ts);
+ if (ts->use_irq)
+ gtp_irq_enable(ts);
- return;
+ return;
+ }
}
-#endif
ret = gtp_i2c_read(ts->client, point_data, 12);
if (ret < 0) {
@@ -514,15 +506,16 @@
pre_key = key_value;
-#if GTP_WITH_PEN
- if (pre_pen && (touch_num == 0)) {
- dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!");
- input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
- input_mt_slot(ts->input_dev, 5);
- input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
- pre_pen = 0;
+ if (ts->pdata->with_pen) {
+ if (pre_pen && (touch_num == 0)) {
+ dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!");
+ input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+ input_mt_slot(ts->input_dev, 5);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+ pre_pen = 0;
+ }
}
-#endif
+
if (pre_touch || touch_num) {
s32 pos = 0;
u16 touch_index = 0;
@@ -530,45 +523,45 @@
coor_data = &point_data[3];
if (touch_num) {
id = coor_data[pos] & 0x0F;
-#if GTP_WITH_PEN
- id = coor_data[pos];
- if (id == 128) {
- dev_dbg(&ts->client->dev,
- "Pen touch DOWN(Slot)!");
- input_x = coor_data[pos + 1]
- | (coor_data[pos + 2] << 8);
- input_y = coor_data[pos + 3]
- | (coor_data[pos + 4] << 8);
- input_w = coor_data[pos + 5]
- | (coor_data[pos + 6] << 8);
+ if (ts->pdata->with_pen) {
+ id = coor_data[pos];
+ if (id == 128) {
+ dev_dbg(&ts->client->dev,
+ "Pen touch DOWN(Slot)!");
+ input_x = coor_data[pos + 1]
+ | (coor_data[pos + 2] << 8);
+ input_y = coor_data[pos + 3]
+ | (coor_data[pos + 4] << 8);
+ input_w = coor_data[pos + 5]
+ | (coor_data[pos + 6] << 8);
- input_report_key(ts->input_dev,
- BTN_TOOL_PEN, 1);
- input_mt_slot(ts->input_dev, 5);
- input_report_abs(ts->input_dev,
- ABS_MT_TRACKING_ID, 5);
- input_report_abs(ts->input_dev,
- ABS_MT_POSITION_X, input_x);
- input_report_abs(ts->input_dev,
- ABS_MT_POSITION_Y, input_y);
- input_report_abs(ts->input_dev,
- ABS_MT_TOUCH_MAJOR, input_w);
- dev_dbg(&ts->client->dev,
- "Pen/Stylus: (%d, %d)[%d]",
- input_x, input_y, input_w);
- pre_pen = 1;
- pre_touch = 0;
+ input_report_key(ts->input_dev,
+ BTN_TOOL_PEN, 1);
+ input_mt_slot(ts->input_dev, 5);
+ input_report_abs(ts->input_dev,
+ ABS_MT_TRACKING_ID, 5);
+ input_report_abs(ts->input_dev,
+ ABS_MT_POSITION_X, input_x);
+ input_report_abs(ts->input_dev,
+ ABS_MT_POSITION_Y, input_y);
+ input_report_abs(ts->input_dev,
+ ABS_MT_TOUCH_MAJOR, input_w);
+ dev_dbg(&ts->client->dev,
+ "Pen/Stylus: (%d, %d)[%d]",
+ input_x, input_y, input_w);
+ pre_pen = 1;
+ pre_touch = 0;
+ }
}
-#endif
touch_index |= (0x01<<id);
}
for (i = 0; i < GTP_MAX_TOUCH; i++) {
-#if GTP_WITH_PEN
- if (pre_pen == 1)
- break;
-#endif
+ if (ts->pdata->with_pen)
+ if (pre_pen == 1)
+ break;
+
if (touch_index & (0x01<<i)) {
input_x = coor_data[pos + 1] |
coor_data[pos + 2] << 8;
@@ -673,7 +666,6 @@
}
#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB)
-#if GTP_SLIDE_WAKEUP
/*******************************************************
Function:
Enter doze mode for sliding wakeup.
@@ -690,9 +682,9 @@
(u8)(GTP_REG_SLEEP >> 8),
(u8)GTP_REG_SLEEP, 8};
-#if GTP_DBL_CLK_WAKEUP
- i2c_control_buf[2] = 0x09;
-#endif
+ if (ts->pdata->dbl_clk_wakeup)
+ i2c_control_buf[2] = 0x09;
+
gtp_irq_disable(ts);
while (retry++ < GTP_I2C_RETRY_3) {
@@ -721,7 +713,6 @@
gtp_irq_enable(ts);
return ret;
}
-#else
/**
* gtp_enter_sleep - Enter sleep mode
* @ts: driver private data
@@ -767,7 +758,6 @@
return ret;
}
}
-#endif /* !GTP_SLIDE_WAKEUP */
/*******************************************************
Function:
@@ -813,33 +803,33 @@
"Wakeup sleep send config success.");
} else {
err_retry:
-#if GTP_SLIDE_WAKEUP
- /* wakeup not by slide */
- if (DOZE_WAKEUP != doze_status)
- gtp_reset_guitar(ts, 10);
- else
- /* wakeup by slide */
- doze_status = DOZE_DISABLED;
-#else
- if (chip_gt9xxs == 1) {
- gtp_reset_guitar(ts, 10);
+ if (ts->pdata->slide_wakeup) { /* wakeup not by slide */
+ if (DOZE_WAKEUP != doze_status)
+ gtp_reset_guitar(ts, 10);
+ else
+ /* wakeup by slide */
+ doze_status = DOZE_DISABLED;
} else {
- ret = gpio_direction_output(ts->pdata->irq_gpio, 1);
- usleep(5000);
+ if (chip_gt9xxs == 1) {
+ gtp_reset_guitar(ts, 10);
+ } else {
+ ret = gpio_direction_output(
+ ts->pdata->irq_gpio, 1);
+ usleep(5000);
+ }
}
-#endif
ret = gtp_i2c_test(ts->client);
if (ret == 2) {
dev_dbg(&ts->client->dev, "GTP wakeup sleep.");
-#if (!GTP_SLIDE_WAKEUP)
- if (chip_gt9xxs == 0) {
- gtp_int_sync(ts, 25);
- msleep(20);
+ if (!ts->pdata->slide_wakeup) {
+ if (chip_gt9xxs == 0) {
+ gtp_int_sync(ts, 25);
+ msleep(20);
#if GTP_ESD_PROTECT
- gtp_init_ext_watchdog(ts->client);
+ gtp_init_ext_watchdog(ts->client);
#endif
+ }
}
-#endif
return ret;
}
gtp_reset_guitar(ts, 20);
@@ -863,123 +853,126 @@
static int gtp_init_panel(struct goodix_ts_data *ts)
{
struct i2c_client *client = ts->client;
- unsigned char *config_data;
+ unsigned char *config_data = NULL;
int ret = -EIO;
-
-#if GTP_DRIVER_SEND_CFG
int i;
u8 check_sum = 0;
u8 opr_buf[16];
u8 sensor_id = 0;
- for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++)
- dev_dbg(&client->dev, "Config Groups(%d) Lengths: %d",
- i, ts->pdata->config_data_len[i]);
+ if (ts->pdata->driver_send_cfg) {
+ for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++)
+ dev_dbg(&client->dev, "Config Groups(%d) Lengths: %d",
+ i, ts->pdata->config_data_len[i]);
- ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
- if (SUCCESS == ret) {
- if (opr_buf[0] != 0xBE) {
- ts->fw_error = 1;
+ ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
+ if (SUCCESS == ret) {
+ if (opr_buf[0] != 0xBE) {
+ ts->fw_error = 1;
+ dev_err(&client->dev,
+ "Firmware error, no config sent!");
+ return -EINVAL;
+ }
+ }
+
+ for (i = 1; i < GOODIX_MAX_CFG_GROUP; i++) {
+ if (ts->pdata->config_data_len[i])
+ break;
+ }
+
+ if (i == GOODIX_MAX_CFG_GROUP) {
+ sensor_id = 0;
+ } else {
+ ret = gtp_i2c_read_dbl_check(ts->client,
+ GTP_REG_SENSOR_ID, &sensor_id, 1);
+ if (SUCCESS == ret) {
+ if (sensor_id >= GOODIX_MAX_CFG_GROUP) {
+ dev_err(&client->dev,
+ "Invalid sensor_id(0x%02X), No Config Sent!",
+ sensor_id);
+ return -EINVAL;
+ }
+ } else {
+ dev_err(&client->dev,
+ "Failed to get sensor_id, No config sent!");
+ return -EINVAL;
+ }
+ }
+
+ dev_info(&client->dev, "Sensor ID selected: %d", sensor_id);
+
+ if (ts->pdata->config_data_len[sensor_id] <
+ GTP_CONFIG_MIN_LENGTH ||
+ !ts->pdata->config_data[sensor_id]) {
dev_err(&client->dev,
- "Firmware error, no config sent!");
+ "Sensor_ID(%d) matches with NULL or invalid config group!\n",
+ sensor_id);
return -EINVAL;
}
- }
- for (i = 1; i < GOODIX_MAX_CFG_GROUP; i++) {
- if (ts->pdata->config_data_len[i])
- break;
- }
- if (i == GOODIX_MAX_CFG_GROUP) {
- sensor_id = 0;
- } else {
- ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
- &sensor_id, 1);
- if (SUCCESS == ret) {
- if (sensor_id >= GOODIX_MAX_CFG_GROUP) {
- dev_err(&client->dev,
- "Invalid sensor_id(0x%02X), No Config Sent!",
- sensor_id);
- return -EINVAL;
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+ &opr_buf[0], 1);
+ if (ret == SUCCESS) {
+ if (opr_buf[0] < 90) {
+ /* backup group config version */
+ grp_cfg_version =
+ ts->pdata->
+ config_data[sensor_id][GTP_ADDR_LENGTH];
+ ts->pdata->
+ config_data[sensor_id][GTP_ADDR_LENGTH]
+ = 0x00;
+ ts->fixed_cfg = 0;
+ } else {
+ /* treated as fixed config, not send config */
+ dev_warn(&client->dev,
+ "Ic fixed config with config version(%d, 0x%02X)",
+ opr_buf[0], opr_buf[0]);
+ ts->fixed_cfg = 1;
}
} else {
dev_err(&client->dev,
- "Failed to get sensor_id, No config sent!");
+ "Failed to get ic config version!No config sent!");
return -EINVAL;
}
- }
- dev_info(&client->dev, "Sensor ID selected: %d", sensor_id);
-
- if (ts->pdata->config_data_len[sensor_id] < GTP_CONFIG_MIN_LENGTH ||
- !ts->pdata->config_data[sensor_id]) {
- dev_err(&client->dev,
- "Sensor_ID(%d) matches with NULL or invalid config group!\n",
- sensor_id);
- return -EINVAL;
- }
-
- ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
- &opr_buf[0], 1);
- if (ret == SUCCESS) {
- if (opr_buf[0] < 90) {
- /* backup group config version */
- grp_cfg_version =
- ts->pdata->config_data[sensor_id][GTP_ADDR_LENGTH];
- ts->pdata->config_data[sensor_id][GTP_ADDR_LENGTH] =
- 0x00;
- ts->fixed_cfg = 0;
- } else {
- /* treated as fixed config, not send config */
- dev_warn(&client->dev,
- "Ic fixed config with config version(%d, 0x%02X)",
- opr_buf[0], opr_buf[0]);
- ts->fixed_cfg = 1;
- }
- } else {
- dev_err(&client->dev,
- "Failed to get ic config version!No config sent!");
- return -EINVAL;
- }
-
- config_data = ts->pdata->config_data[sensor_id];
- ts->config_data = ts->pdata->config_data[sensor_id];
- ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id];
+ config_data = ts->pdata->config_data[sensor_id];
+ ts->config_data = ts->pdata->config_data[sensor_id];
+ ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id];
#if GTP_CUSTOM_CFG
- config_data[RESOLUTION_LOC] =
- (unsigned char)(GTP_MAX_WIDTH && 0xFF);
- config_data[RESOLUTION_LOC + 1] =
- (unsigned char)(GTP_MAX_WIDTH >> 8);
- config_data[RESOLUTION_LOC + 2] =
- (unsigned char)(GTP_MAX_HEIGHT && 0xFF);
- config_data[RESOLUTION_LOC + 3] =
- (unsigned char)(GTP_MAX_HEIGHT >> 8);
+ config_data[RESOLUTION_LOC] =
+ (unsigned char)(GTP_MAX_WIDTH && 0xFF);
+ config_data[RESOLUTION_LOC + 1] =
+ (unsigned char)(GTP_MAX_WIDTH >> 8);
+ config_data[RESOLUTION_LOC + 2] =
+ (unsigned char)(GTP_MAX_HEIGHT && 0xFF);
+ config_data[RESOLUTION_LOC + 3] =
+ (unsigned char)(GTP_MAX_HEIGHT >> 8);
- if (GTP_INT_TRIGGER == 0)
- config_data[TRIGGER_LOC] &= 0xfe;
- else if (GTP_INT_TRIGGER == 1)
- config_data[TRIGGER_LOC] |= 0x01;
+ if (GTP_INT_TRIGGER == 0)
+ config_data[TRIGGER_LOC] &= 0xfe;
+ else if (GTP_INT_TRIGGER == 1)
+ config_data[TRIGGER_LOC] |= 0x01;
#endif /* !GTP_CUSTOM_CFG */
- check_sum = 0;
- for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
- check_sum += config_data[i];
+ check_sum = 0;
+ for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+ check_sum += config_data[i];
- config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
+ config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
-#else /* DRIVER NOT SEND CONFIG */
- ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
- ret = gtp_i2c_read(ts->client, config_data,
+ } else { /* DRIVER NOT SEND CONFIG */
+ ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
+ ret = gtp_i2c_read(ts->client, config_data,
ts->gtp_cfg_len + GTP_ADDR_LENGTH);
- if (ret < 0) {
- dev_err(&client->dev,
+ if (ret < 0) {
+ dev_err(&client->dev,
"Read Config Failed, Using DEFAULT Resolution & INT Trigger!\n");
- ts->abs_x_max = GTP_MAX_WIDTH;
- ts->abs_y_max = GTP_MAX_HEIGHT;
- ts->int_trigger_type = GTP_INT_TRIGGER;
- }
-#endif /* !DRIVER NOT SEND CONFIG */
+ ts->abs_x_max = GTP_MAX_WIDTH;
+ ts->abs_y_max = GTP_MAX_HEIGHT;
+ ts->int_trigger_type = GTP_INT_TRIGGER;
+ }
+ } /* !DRIVER NOT SEND CONFIG */
if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) {
ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8)
@@ -1213,9 +1206,7 @@
{
int ret;
char phys[PHY_BUF_SIZE];
-#if GTP_HAVE_TOUCH_KEY
int index = 0;
-#endif
ts->input_dev = input_allocate_device();
if (ts->input_dev == NULL) {
@@ -1230,27 +1221,24 @@
__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
input_mt_init_slots(ts->input_dev, 10);/* in case of "out of memory" */
-
- for (index = 0; index < ts->pdata->num_button; index++) {
- input_set_capability(ts->input_dev,
+ if (ts->pdata->have_touch_key) {
+ for (index = 0; index < ts->pdata->num_button; index++) {
+ input_set_capability(ts->input_dev,
EV_KEY, ts->pdata->button_map[index]);
+ }
}
+ if (ts->pdata->slide_wakeup)
+ input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
-#if GTP_SLIDE_WAKEUP
- input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
-#endif
+ if (ts->pdata->with_pen) { /* pen support */
+ __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+ __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
+ }
-#if GTP_WITH_PEN
- /* pen support */
- __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
- __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
- __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
-#endif
-
-#if GTP_CHANGE_X2Y
- swap(ts->abs_x_max, ts->abs_y_max);
-#endif
+ if (ts->pdata->change_x2y)
+ swap(ts->abs_x_max, ts->abs_y_max);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
0, ts->abs_x_max, 0, 0);
@@ -1850,6 +1838,25 @@
pdata->enable_power_off = of_property_read_bool(np,
"goodix,enable-power-off");
+
+ pdata->have_touch_key = of_property_read_bool(np,
+ "goodix,have-touch-key");
+
+ pdata->driver_send_cfg = of_property_read_bool(np,
+ "goodix,driver-send-cfg");
+
+ pdata->change_x2y = of_property_read_bool(np,
+ "goodix,change-x2y");
+
+ pdata->with_pen = of_property_read_bool(np,
+ "goodix,with-pen");
+
+ pdata->slide_wakeup = of_property_read_bool(np,
+ "goodix,slide-wakeup");
+
+ pdata->dbl_clk_wakeup = of_property_read_bool(np,
+ "goodix,dbl_clk_wakeup");
+
/* reset, irq gpio info */
pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
0, &pdata->reset_gpio_flags);
@@ -2113,8 +2120,6 @@
#endif
if (ts->use_irq)
free_irq(client->irq, ts);
- else
- hrtimer_cancel(&ts->timer);
cancel_work_sync(&ts->work);
flush_workqueue(ts->goodix_wq);
destroy_workqueue(ts->goodix_wq);
@@ -2178,8 +2183,6 @@
if (ts) {
if (ts->use_irq)
free_irq(client->irq, ts);
- else
- hrtimer_cancel(&ts->timer);
cancel_work_sync(&ts->work);
flush_workqueue(ts->goodix_wq);
@@ -2237,23 +2240,21 @@
gtp_esd_switch(ts->client, SWITCH_OFF);
#endif
-#if GTP_SLIDE_WAKEUP
- ret = gtp_enter_doze(ts);
-#else
- if (ts->use_irq)
- gtp_irq_disable(ts);
- else
- hrtimer_cancel(&ts->timer);
+ if (ts->pdata->slide_wakeup) {
+ ret = gtp_enter_doze(ts);
+ } else {
+ if (ts->use_irq)
+ gtp_irq_disable(ts);
- for (i = 0; i < GTP_MAX_TOUCH; i++)
- gtp_touch_up(ts, i);
+ for (i = 0; i < GTP_MAX_TOUCH; i++)
+ gtp_touch_up(ts, i);
- input_sync(ts->input_dev);
+ input_sync(ts->input_dev);
- ret = gtp_enter_sleep(ts);
-#endif
- if (ret < 0)
- dev_err(&ts->client->dev, "GTP early suspend failed.\n");
+ ret = gtp_enter_sleep(ts);
+ if (ret < 0)
+ dev_err(&ts->client->dev, "GTP early suspend failed.\n");
+ }
/* to avoid waking up while not sleeping,
* delay 48 + 10ms to ensure reliability
*/
@@ -2285,18 +2286,14 @@
mutex_lock(&ts->lock);
ret = gtp_wakeup_sleep(ts);
-#if GTP_SLIDE_WAKEUP
- doze_status = DOZE_DISABLED;
-#endif
+ if (ts->pdata->slide_wakeup)
+ doze_status = DOZE_DISABLED;
if (ret <= 0)
dev_err(&ts->client->dev, "GTP resume failed.\n");
if (ts->use_irq)
gtp_irq_enable(ts);
- else
- hrtimer_start(&ts->timer,
- ktime_set(1, 0), HRTIMER_MODE_REL);
#if GTP_ESD_PROTECT
gtp_esd_switch(ts->client, SWITCH_ON);
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index 0ba6895..3cedf26 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -63,6 +63,12 @@
u8 *config_data[GOODIX_MAX_CFG_GROUP];
u32 button_map[MAX_BUTTONS];
u8 num_button;
+ bool have_touch_key;
+ bool driver_send_cfg;
+ bool change_x2y;
+ bool with_pen;
+ bool slide_wakeup;
+ bool dbl_clk_wakeup;
};
struct goodix_ts_data {
spinlock_t irq_lock;
@@ -111,16 +117,7 @@
/***************************PART1:ON/OFF define*******************************/
#define GTP_CUSTOM_CFG 0
-#define GTP_CHANGE_X2Y 0
-#define GTP_DRIVER_SEND_CFG 1
-#define GTP_HAVE_TOUCH_KEY 1
#define GTP_ESD_PROTECT 0
-#define GTP_WITH_PEN 0
-
-/* This cannot work when enable-power-off is on */
-#define GTP_SLIDE_WAKEUP 0
-/* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
-#define GTP_DBL_CLK_WAKEUP 0
#define GTP_IRQ_TAB {\
IRQ_TYPE_EDGE_RISING,\
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 9208599..d87520f 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -619,7 +619,7 @@
for (i = 0; i < num_wled_strings; i++) {
rc = qpnp_led_masked_write(led,
WLED_FULL_SCALE_REG(led->base, i),
- WLED_MAX_CURR_MASK, led->max_current);
+ WLED_MAX_CURR_MASK, (u8)led->max_current);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Write max current failure (%d)\n",
@@ -689,7 +689,8 @@
static int qpnp_mpp_set(struct qpnp_led_data *led)
{
- int rc, val;
+ int rc;
+ u8 val;
int duty_us;
if (led->cdev.brightness) {
@@ -1604,7 +1605,7 @@
rc = qpnp_led_masked_write(led,
WLED_FULL_SCALE_REG(led->base, i), WLED_MAX_CURR_MASK,
- led->max_current);
+ (u8)led->max_current);
if (rc) {
dev_err(&led->spmi_dev->dev,
"WLED max current reg write failed(%d)\n", rc);
@@ -2445,8 +2446,8 @@
static int __devinit qpnp_mpp_init(struct qpnp_led_data *led)
{
- int rc, val;
-
+ int rc;
+ u8 val;
if (led->max_current < LED_MPP_CURRENT_MIN ||
led->max_current > LED_MPP_CURRENT_MAX) {
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 10f122a..67df573 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -237,6 +237,23 @@
If unsure, say N.
+config DM_REQ_CRYPT
+ tristate "Crypt target support"
+ depends on BLK_DEV_DM
+ select XTS
+ select CRYPTO_XTS
+ ---help---
+ This request based device-mapper target allows you to create a device that
+ transparently encrypts the data on it. You'll need to activate
+ the ciphers you're going to use in the cryptoapi configuration.
+ The DM REQ CRYPT operates on requests (bigger payloads) to utilize
+ crypto hardware better.
+
+ To compile this code as a module, choose M here: the module will
+ be called dm-req-crypt.
+
+ If unsure, say N.
+
config DM_SNAPSHOT
tristate "Snapshot target"
depends on BLK_DEV_DM
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 8b2e0df..7b16079 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -43,7 +43,7 @@
obj-$(CONFIG_DM_RAID) += dm-raid.o
obj-$(CONFIG_DM_THIN_PROVISIONING) += dm-thin-pool.o
obj-$(CONFIG_DM_VERITY) += dm-verity.o
-
+obj-$(CONFIG_DM_REQ_CRYPT) += dm-req-crypt.o
ifeq ($(CONFIG_DM_UEVENT),y)
dm-mod-objs += dm-uevent.o
endif
diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c
new file mode 100644
index 0000000..ab21404
--- /dev/null
+++ b/drivers/md/dm-req-crypt.c
@@ -0,0 +1,752 @@
+/* Copyright (c) 2014, 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/completion.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/mempool.h>
+#include <linux/slab.h>
+#include <linux/crypto.h>
+#include <linux/workqueue.h>
+#include <linux/backing-dev.h>
+#include <linux/atomic.h>
+#include <linux/scatterlist.h>
+#include <crypto/scatterwalk.h>
+#include <asm/page.h>
+#include <asm/unaligned.h>
+#include <crypto/hash.h>
+#include <crypto/md5.h>
+#include <crypto/algapi.h>
+#include <mach/qcrypto.h>
+
+#include <linux/device-mapper.h>
+
+
+#define DM_MSG_PREFIX "req-crypt"
+
+#define MAX_SG_LIST 1024
+#define REQ_DM_512_KB (512*1024)
+#define MAX_ENCRYPTION_BUFFERS 1
+#define MIN_IOS 16
+#define MIN_POOL_PAGES 32
+#define KEY_SIZE_XTS 64
+#define AES_XTS_IV_LEN 16
+
+#define DM_REQ_CRYPT_ERROR -1
+
+struct req_crypt_result {
+ struct completion completion;
+ int err;
+};
+
+struct dm_dev *dev;
+static struct kmem_cache *_req_crypt_io_pool;
+sector_t start_sector_orig;
+struct workqueue_struct *req_crypt_queue;
+mempool_t *req_io_pool;
+mempool_t *req_page_pool;
+struct crypto_ablkcipher *tfm;
+
+struct req_dm_crypt_io {
+ struct work_struct work;
+ struct request *cloned_request;
+ int error;
+ atomic_t pending;
+ struct timespec start_time;
+};
+
+static void req_crypt_cipher_complete
+ (struct crypto_async_request *req, int err);
+
+
+static void req_crypt_inc_pending(struct req_dm_crypt_io *io)
+{
+ atomic_inc(&io->pending);
+}
+
+static void req_crypt_dec_pending_encrypt(struct req_dm_crypt_io *io)
+{
+ int error = 0;
+ struct request *clone = NULL;
+
+ if (io) {
+ error = io->error;
+ if (io->cloned_request) {
+ clone = io->cloned_request;
+ } else {
+ DMERR("%s io->cloned_request is NULL\n",
+ __func__);
+ /*
+ * If Clone is NULL we cannot do anything,
+ * this should never happen
+ */
+ BUG();
+ }
+ } else {
+ DMERR("%s io is NULL\n", __func__);
+ /*
+ * If Clone is NULL we cannot do anything,
+ * this should never happen
+ */
+ BUG();
+ }
+
+ atomic_dec(&io->pending);
+
+ if (error < 0)
+ dm_kill_unmapped_request(clone, error);
+ else
+ dm_dispatch_request(clone);
+}
+
+static void req_crypt_dec_pending_decrypt(struct req_dm_crypt_io *io)
+{
+ int error = 0;
+ struct request *clone = NULL;
+
+ if (io) {
+ error = io->error;
+ if (io->cloned_request) {
+ clone = io->cloned_request;
+ } else {
+ DMERR("%s io->cloned_request is NULL\n",
+ __func__);
+ /*
+ * If Clone is NULL we cannot do anything,
+ * this should never happen
+ */
+ BUG();
+ }
+ } else {
+ DMERR("%s io is NULL\n",
+ __func__);
+ /*
+ * If Clone is NULL we cannot do anything,
+ * this should never happen
+ */
+ BUG();
+ }
+
+ /* Should never get here if io or Clone is NULL */
+ dm_end_request(clone, error);
+ atomic_dec(&io->pending);
+ mempool_free(io, req_io_pool);
+}
+
+/*
+ * The callback that will be called by the worker queue to perform Decryption
+ * for reads and use the dm function to complete the bios and requests.
+ */
+static void req_cryptd_crypt_read_convert(struct req_dm_crypt_io *io)
+{
+ struct request *clone = NULL;
+ int error = 0;
+ int total_sg_len = 0, rc = 0, total_bytes_in_req = 0;
+ struct ablkcipher_request *req = NULL;
+ struct req_crypt_result result;
+ struct scatterlist *req_sg_read = NULL;
+ int err = 0;
+ struct req_iterator iter2;
+ struct bio_vec *bvec = NULL;
+ u8 IV[AES_XTS_IV_LEN];
+
+ if (io) {
+ error = io->error;
+ if (io->cloned_request) {
+ clone = io->cloned_request;
+ } else {
+ DMERR("%s io->cloned_request is NULL\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto submit_request;
+ }
+ } else {
+ DMERR("%s io is NULL\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto submit_request;
+ }
+
+ req_crypt_inc_pending(io);
+
+ if (error != 0) {
+ err = error;
+ goto submit_request;
+ }
+
+ req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+ if (!req) {
+ DMERR("%s ablkcipher request allocation failed\n", __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ req_crypt_cipher_complete, &result);
+ init_completion(&result.completion);
+ qcrypto_cipher_set_flag(req,
+ QCRYPTO_CTX_USE_PIPE_KEY | QCRYPTO_CTX_XTS_DU_SIZE_512B);
+ crypto_ablkcipher_clear_flags(tfm, ~0);
+ crypto_ablkcipher_setkey(tfm, NULL, KEY_SIZE_XTS);
+
+ req_sg_read = kzalloc(sizeof(struct scatterlist) *
+ MAX_SG_LIST, GFP_KERNEL);
+ if (!req_sg_read) {
+ DMERR("%s req_sg_read allocation failed\n",
+ __func__);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ total_sg_len = blk_rq_map_sg(clone->q, clone, req_sg_read);
+ if ((total_sg_len <= 0) || (total_sg_len > MAX_SG_LIST)) {
+ DMERR("%s Request Error%d", __func__, total_sg_len);
+ err = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+
+ /* total bytes to copy */
+ bvec = NULL;
+ rq_for_each_segment(bvec, clone, iter2) {
+ total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
+ }
+
+ memset(IV, 0, AES_XTS_IV_LEN);
+ memcpy(IV, &clone->__sector, sizeof(sector_t));
+
+ ablkcipher_request_set_crypt(req, req_sg_read, req_sg_read,
+ total_bytes_in_req, (void *) IV);
+
+ rc = crypto_ablkcipher_decrypt(req);
+
+ switch (rc) {
+ case 0:
+ break;
+
+ case -EBUSY:
+ /*
+ * Lets make this synchronous request by waiting on
+ * in progress as well
+ */
+ case -EINPROGRESS:
+ wait_for_completion_io(&result.completion);
+ if (result.err) {
+ DMERR("%s error = %d encrypting the request\n",
+ __func__, result.err);
+ err = DM_REQ_CRYPT_ERROR;
+ }
+ break;
+
+ default:
+ err = DM_REQ_CRYPT_ERROR;
+ break;
+ }
+
+ablkcipher_req_alloc_failure:
+
+ if (req)
+ ablkcipher_request_free(req);
+
+ kfree(req_sg_read);
+
+submit_request:
+ io->error = err;
+ req_crypt_dec_pending_decrypt(io);
+}
+
+/*
+ * The callback that will be called by the worker queue to perform Encryption
+ * for writes and submit the request using the elevelator.
+ */
+static void req_cryptd_crypt_write_convert(struct req_dm_crypt_io *io)
+{
+ struct request *clone = NULL;
+ struct bio *bio_src = NULL;
+ unsigned int total_sg_len_req_in = 0, total_sg_len_req_out = 0,
+ total_bytes_in_req = 0, error = DM_MAPIO_REMAPPED, rc = 0;
+ struct req_iterator iter;
+ struct ablkcipher_request *req = NULL;
+ struct req_crypt_result result;
+ struct bio_vec *bvec = NULL;
+ struct scatterlist *req_sg_in = NULL;
+ struct scatterlist *req_sg_out = NULL;
+ int copy_bio_sector_to_req = 0;
+ gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
+ struct page *page = NULL;
+ u8 IV[AES_XTS_IV_LEN];
+ int remaining_size = 0;
+
+ if (io) {
+ if (io->cloned_request) {
+ clone = io->cloned_request;
+ } else {
+ DMERR("%s io->cloned_request is NULL\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto submit_request;
+ }
+ } else {
+ DMERR("%s io is NULL\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto submit_request;
+ }
+
+ req_crypt_inc_pending(io);
+
+ req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+ if (!req) {
+ DMERR("%s ablkcipher request allocation failed\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ req_crypt_cipher_complete, &result);
+
+ init_completion(&result.completion);
+ qcrypto_cipher_set_flag(req,
+ QCRYPTO_CTX_USE_PIPE_KEY | QCRYPTO_CTX_XTS_DU_SIZE_512B);
+ crypto_ablkcipher_clear_flags(tfm, ~0);
+ crypto_ablkcipher_setkey(tfm, NULL, KEY_SIZE_XTS);
+
+ req_sg_in = kzalloc(sizeof(struct scatterlist) * MAX_SG_LIST,
+ GFP_KERNEL);
+ if (!req_sg_in) {
+ DMERR("%s req_sg_in allocation failed\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ req_sg_out = kzalloc(sizeof(struct scatterlist) * MAX_SG_LIST,
+ GFP_KERNEL);
+ if (!req_sg_out) {
+ DMERR("%s req_sg_out allocation failed\n",
+ __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ total_sg_len_req_in = blk_rq_map_sg(clone->q, clone, req_sg_in);
+ if ((total_sg_len_req_in <= 0) ||
+ (total_sg_len_req_in > MAX_SG_LIST)) {
+ DMERR("%s Request Error%d", __func__, total_sg_len_req_in);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+
+ rq_for_each_segment(bvec, clone, iter) {
+try_again:
+ if (bvec->bv_len > remaining_size) {
+ page = NULL;
+ page = mempool_alloc(req_page_pool, gfp_mask);
+ if (!page) {
+ DMERR("%s Crypt page alloc failed", __func__);
+ congestion_wait(BLK_RW_ASYNC, HZ/100);
+ goto try_again;
+ }
+ bvec->bv_page = page;
+ bvec->bv_offset = 0;
+ total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
+ remaining_size = PAGE_SIZE - bvec->bv_len;
+ if (remaining_size < 0)
+ BUG();
+ } else {
+ bvec->bv_page = page;
+ bvec->bv_offset = PAGE_SIZE - remaining_size;
+ remaining_size = remaining_size - bvec->bv_len;
+ total_bytes_in_req = total_bytes_in_req + bvec->bv_len;
+ }
+ }
+
+ total_sg_len_req_out = blk_rq_map_sg(clone->q, clone, req_sg_out);
+ if ((total_sg_len_req_out <= 0) ||
+ (total_sg_len_req_out > MAX_SG_LIST)) {
+ DMERR("%s Request Error %d", __func__, total_sg_len_req_out);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ memset(IV, 0, AES_XTS_IV_LEN);
+ memcpy(IV, &clone->__sector, sizeof(sector_t));
+
+ ablkcipher_request_set_crypt(req, req_sg_in, req_sg_out,
+ total_bytes_in_req, (void *) IV);
+
+ rc = crypto_ablkcipher_encrypt(req);
+
+ switch (rc) {
+ case 0:
+ break;
+
+ case -EBUSY:
+ /*
+ * Lets make this synchronous request by waiting on
+ * in progress as well
+ */
+ case -EINPROGRESS:
+ wait_for_completion_interruptible(&result.completion);
+ if (result.err) {
+ DMERR("%s error = %d encrypting the request\n",
+ __func__, result.err);
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+ break;
+
+ default:
+ error = DM_REQ_CRYPT_ERROR;
+ goto ablkcipher_req_alloc_failure;
+ }
+
+ __rq_for_each_bio(bio_src, clone) {
+ if (copy_bio_sector_to_req == 0) {
+ clone->buffer = bio_data(bio_src);
+ copy_bio_sector_to_req++;
+ }
+ blk_queue_bounce(clone->q, &bio_src);
+ }
+
+
+ablkcipher_req_alloc_failure:
+ if (req)
+ ablkcipher_request_free(req);
+
+
+ kfree(req_sg_in);
+
+ kfree(req_sg_out);
+
+submit_request:
+ io->error = error;
+ req_crypt_dec_pending_encrypt(io);
+}
+
+/* Queue callback function that will get triggered */
+static void req_cryptd_crypt(struct work_struct *work)
+{
+ struct req_dm_crypt_io *io =
+ container_of(work, struct req_dm_crypt_io, work);
+
+ if (rq_data_dir(io->cloned_request) == WRITE)
+ req_cryptd_crypt_write_convert(io);
+ else if (rq_data_dir(io->cloned_request) == READ)
+ req_cryptd_crypt_read_convert(io);
+ else
+ DMERR("%s received non-write request for Clone %u\n",
+ __func__, (unsigned int)io->cloned_request);
+}
+
+static void req_cryptd_queue_crypt(struct req_dm_crypt_io *io)
+{
+ INIT_WORK(&io->work, req_cryptd_crypt);
+ queue_work(req_crypt_queue, &io->work);
+}
+
+/*
+ * Cipher complete callback, this is triggered by the Linux crypto api once
+ * the operation is done. This signals the waiting thread that the crypto
+ * operation is complete.
+ */
+static void req_crypt_cipher_complete(struct crypto_async_request *req, int err)
+{
+ struct req_crypt_result *res = req->data;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ res->err = err;
+ complete(&res->completion);
+}
+
+/*
+ * If bio->bi_dev is a partition, remap the location
+ */
+static inline void req_crypt_blk_partition_remap(struct bio *bio)
+{
+ struct block_device *bdev = bio->bi_bdev;
+
+ if (bio_sectors(bio) && bdev != bdev->bd_contains) {
+ struct hd_struct *p = bdev->bd_part;
+
+ bio->bi_sector += p->start_sect;
+ bio->bi_bdev = bdev->bd_contains;
+ }
+}
+
+/*
+ * The endio function is called from ksoftirqd context (atomic).
+ * For write operations the new pages created form the mempool
+ * is freed and returned. * For read operations, decryption is
+ * required, since this is called in a atomic * context, the
+ * request is sent to a worker queue to complete decryptiona and
+ * free the request once done.
+ */
+static int req_crypt_endio(struct dm_target *ti, struct request *clone,
+ int error, union map_info *map_context)
+{
+ int err = 0;
+ struct req_iterator iter1;
+ struct bio_vec *bvec = NULL;
+ struct req_dm_crypt_io *req_io = map_context->ptr;
+
+ /* If it is a write request, do nothing just return. */
+ bvec = NULL;
+ if (rq_data_dir(clone) == WRITE) {
+ rq_for_each_segment(bvec, clone, iter1) {
+ if (bvec->bv_offset == 0) {
+ mempool_free(bvec->bv_page, req_page_pool);
+ bvec->bv_page = NULL;
+ } else
+ bvec->bv_page = NULL;
+ }
+ mempool_free(req_io, req_io_pool);
+ goto submit_request;
+ } else if (rq_data_dir(clone) == READ) {
+ req_io->error = error;
+ req_cryptd_queue_crypt(req_io);
+ err = DM_ENDIO_INCOMPLETE;
+ goto submit_request;
+ }
+
+submit_request:
+ return err;
+}
+
+/*
+ * This function is called with interrupts disabled
+ * The function remaps the clone for the underlying device.
+ * If it is a write request, it calls into the worker queue to
+ * encrypt the data
+ * and submit the request directly using the elevator
+ * For a read request no pre-processing is required the request
+ * is returned to dm once mapping is done
+ */
+
+static int req_crypt_map(struct dm_target *ti, struct request *clone,
+ union map_info *map_context)
+{
+ struct req_dm_crypt_io *req_io = NULL;
+ int error = DM_MAPIO_REMAPPED, copy_bio_sector_to_req = 0;
+ struct bio *bio_src = NULL;
+
+ req_io = mempool_alloc(req_io_pool, GFP_NOWAIT);
+ if (!req_io) {
+ DMERR("%s req_io allocation failed\n", __func__);
+ error = DM_REQ_CRYPT_ERROR;
+ goto submit_request;
+ }
+
+ /* Save the clone in the req_io, the callback to the worker
+ * queue will get the req_io
+ */
+ req_io->cloned_request = clone;
+ map_context->ptr = req_io;
+ atomic_set(&req_io->pending, 0);
+
+ /* Get the queue of the underlying original device */
+ clone->q = bdev_get_queue(dev->bdev);
+ clone->rq_disk = dev->bdev->bd_disk;
+
+ __rq_for_each_bio(bio_src, clone) {
+ bio_src->bi_bdev = dev->bdev;
+ /* Currently the way req-dm works is that once the underlying
+ * device driver completes the request by calling into the
+ * block layer. The block layer completes the bios (clones) and
+ * then the cloned request. This is undesirable for req-dm-crypt
+ * hence added a flag BIO_DONTFREE, this flag will ensure that
+ * blk layer does not complete the cloned bios before completing
+ * the request. When the crypt endio is called, post-processsing
+ * is done and then the dm layer will complete the bios (clones)
+ * and free them.
+ */
+ bio_src->bi_flags |= 1 << BIO_DONTFREE;
+
+ /*
+ * If this device has partitions, remap block n
+ * of partition p to block n+start(p) of the disk.
+ */
+ req_crypt_blk_partition_remap(bio_src);
+ if (copy_bio_sector_to_req == 0) {
+ clone->__sector = bio_src->bi_sector;
+ clone->buffer = bio_data(bio_src);
+ copy_bio_sector_to_req++;
+ }
+ blk_queue_bounce(clone->q, &bio_src);
+ }
+
+ if (rq_data_dir(clone) == READ) {
+ error = DM_MAPIO_REMAPPED;
+ goto submit_request;
+ } else if (rq_data_dir(clone) == WRITE) {
+ req_cryptd_queue_crypt(req_io);
+ error = DM_MAPIO_SUBMITTED;
+ goto submit_request;
+ } else {
+ error = DM_REQ_CRYPT_ERROR;
+ DMERR("%s Unknown request\n", __func__);
+ }
+
+submit_request:
+ return error;
+
+}
+
+static int req_crypt_status(struct dm_target *ti, status_type_t type,
+ char *result, unsigned maxlen)
+{
+ return 0;
+}
+
+static void req_crypt_dtr(struct dm_target *ti)
+{
+ if (req_crypt_queue)
+ destroy_workqueue(req_crypt_queue);
+ if (req_io_pool)
+ mempool_destroy(req_io_pool);
+ if (req_page_pool)
+ mempool_destroy(req_page_pool);
+ if (tfm)
+ crypto_free_ablkcipher(tfm);
+}
+
+
+/*
+ * Construct an encryption mapping:
+ * <cipher> <key> <iv_offset> <dev_path> <start>
+ */
+static int req_crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+ unsigned long long tmpll;
+ char dummy;
+
+ if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &dev)) {
+ DMERR(" %s Device Lookup failed\n", __func__);
+ return DM_REQ_CRYPT_ERROR;
+ }
+
+ if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
+ DMERR("%s Invalid device sector\n", __func__);
+ return DM_REQ_CRYPT_ERROR;
+ }
+ start_sector_orig = tmpll;
+
+ req_crypt_queue = alloc_workqueue("req_cryptd",
+ WQ_HIGHPRI |
+ WQ_CPU_INTENSIVE|
+ WQ_MEM_RECLAIM,
+ 1);
+ if (!req_crypt_queue) {
+ DMERR("%s req_crypt_queue not allocated\n", __func__);
+ return DM_REQ_CRYPT_ERROR;
+ }
+
+ /* Allocate the crypto alloc blk cipher and keep the handle */
+ tfm = crypto_alloc_ablkcipher("qcom-xts(aes)", 0, 0);
+ if (IS_ERR(tfm)) {
+ DMERR("%s ablkcipher tfm allocation failed : error = %lu\n",
+ __func__, PTR_ERR(tfm));
+ return DM_REQ_CRYPT_ERROR;
+ }
+
+ req_io_pool = mempool_create_slab_pool(MIN_IOS, _req_crypt_io_pool);
+ if (!req_io_pool) {
+ DMERR("%s req_io_pool not allocated\n", __func__);
+ return DM_REQ_CRYPT_ERROR;
+ }
+
+ req_page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
+ if (!req_page_pool) {
+ DMERR("%s req_page_pool not allocated\n", __func__);
+ return DM_REQ_CRYPT_ERROR;
+ }
+
+ return 0;
+}
+
+static void req_crypt_postsuspend(struct dm_target *ti)
+{
+}
+
+static int req_crypt_preresume(struct dm_target *ti)
+{
+ return 0;
+}
+
+static void req_crypt_resume(struct dm_target *ti)
+{
+}
+
+/* Message interface
+ * key set <key>
+ * key wipe
+ */
+static int req_crypt_message(struct dm_target *ti, unsigned argc, char **argv)
+{
+ return 0;
+}
+
+static int req_crypt_iterate_devices(struct dm_target *ti,
+ iterate_devices_callout_fn fn, void *data)
+{
+ return fn(ti, dev, start_sector_orig, ti->len, data);
+}
+
+static struct target_type req_crypt_target = {
+ .name = "req-crypt",
+ .version = {1, 0, 0},
+ .module = THIS_MODULE,
+ .ctr = req_crypt_ctr,
+ .dtr = req_crypt_dtr,
+ .map_rq = req_crypt_map,
+ .rq_end_io = req_crypt_endio,
+ .status = req_crypt_status,
+ .postsuspend = req_crypt_postsuspend,
+ .preresume = req_crypt_preresume,
+ .resume = req_crypt_resume,
+ .message = req_crypt_message,
+ .iterate_devices = req_crypt_iterate_devices,
+};
+
+static int __init req_dm_crypt_init(void)
+{
+ int r;
+
+ _req_crypt_io_pool = KMEM_CACHE(req_dm_crypt_io, 0);
+ if (!_req_crypt_io_pool)
+ return -ENOMEM;
+
+ r = dm_register_target(&req_crypt_target);
+ if (r < 0)
+ DMERR("register failed %d", r);
+
+ return r;
+}
+
+static void __exit req_dm_crypt_exit(void)
+{
+ kmem_cache_destroy(_req_crypt_io_pool);
+ dm_unregister_target(&req_crypt_target);
+}
+
+module_init(req_dm_crypt_init);
+module_exit(req_dm_crypt_exit);
+
+MODULE_DESCRIPTION(DM_NAME " target for request based transparent encryption / decryption");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index e24143c..5d240d1 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -775,7 +775,7 @@
* Complete the clone and the original request.
* Must be called without queue lock.
*/
-static void dm_end_request(struct request *clone, int error)
+void dm_end_request(struct request *clone, int error)
{
int rw = rq_data_dir(clone);
struct dm_rq_target_io *tio = clone->end_io_data;
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 6f9eb94..7d97c26 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -140,6 +140,8 @@
for (p = 0; p < entity->num_pads; p++) {
struct media_pad_desc pad;
+
+ memset(&pad, 0, sizeof(pad));
media_device_kpad_to_upad(&entity->pads[p], &pad);
if (copy_to_user(&links.pads[p], &pad, sizeof(pad)))
return -EFAULT;
@@ -157,6 +159,7 @@
if (entity->links[l].source->entity != entity)
continue;
+ memset(&link, 0, sizeof(link));
media_device_kpad_to_upad(entity->links[l].source,
&link.source);
media_device_kpad_to_upad(entity->links[l].sink,
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 3f7ba6b..43cdcbb 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -673,12 +673,22 @@
return rc;
}
+#ifdef CONFIG_COMPAT
+long camera_v4l2_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+#endif
static struct v4l2_file_operations camera_v4l2_fops = {
.owner = THIS_MODULE,
.open = camera_v4l2_open,
.poll = camera_v4l2_poll,
.release = camera_v4l2_close,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = camera_v4l2_compat_ioctl,
+#endif
};
int camera_init_v4l2(struct device *dev, unsigned int *session)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index a85f853..f9855c0 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -188,7 +188,6 @@
mapped_info->handle,
buf_mgr->iommu_domain_num, 0);
ion_free(buf_mgr->client, mapped_info->handle);
-
list_del_init(&buf_pending->list);
kfree(buf_pending);
break;
@@ -309,6 +308,9 @@
struct msm_isp_buffer *temp_buf_info;
struct msm_isp_bufq *bufq = NULL;
struct vb2_buffer *vb2_buf = NULL;
+ struct buffer_cmd *buf_pending = NULL;
+ struct msm_isp_buffer_mapped_info *mped_info_tmp1;
+ struct msm_isp_buffer_mapped_info *mped_info_tmp2;
bufq = msm_isp_get_bufq(buf_mgr, bufq_handle);
if (!bufq) {
pr_err("%s: Invalid bufq\n", __func__);
@@ -348,9 +350,22 @@
list_for_each_entry(temp_buf_info, &bufq->head, list) {
if (temp_buf_info->state ==
MSM_ISP_BUFFER_STATE_QUEUED) {
- /* found one buf */
- list_del_init(&temp_buf_info->list);
- *buf_info = temp_buf_info;
+
+ list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) {
+ if (!buf_pending)
+ break;
+ mped_info_tmp1 = buf_pending->mapped_info;
+ mped_info_tmp2 = &temp_buf_info->mapped_info[0];
+
+ if (mped_info_tmp1 == mped_info_tmp2
+ && (mped_info_tmp1->len == mped_info_tmp2->len)
+ && (mped_info_tmp1->paddr == mped_info_tmp2->paddr)) {
+ /* found one buf */
+ list_del_init(&temp_buf_info->list);
+ *buf_info = temp_buf_info;
+ break;
+ }
+ }
break;
}
}
@@ -359,9 +374,22 @@
bufq->session_id, bufq->stream_id);
if (vb2_buf) {
if (vb2_buf->v4l2_buf.index < bufq->num_bufs) {
- *buf_info =
- &bufq->bufs[vb2_buf->v4l2_buf.index];
- (*buf_info)->vb2_buf = vb2_buf;
+
+ list_for_each_entry(buf_pending, &buf_mgr->buffer_q, list) {
+ if (!buf_pending)
+ break;
+ mped_info_tmp1 = buf_pending->mapped_info;
+ mped_info_tmp2 =
+ &bufq->bufs[vb2_buf->v4l2_buf.index].mapped_info[0];
+
+ if (mped_info_tmp1 == mped_info_tmp2
+ && (mped_info_tmp1->len == mped_info_tmp2->len)
+ && (mped_info_tmp1->paddr == mped_info_tmp2->paddr)) {
+ *buf_info = &bufq->bufs[vb2_buf->v4l2_buf.index];
+ (*buf_info)->vb2_buf = vb2_buf;
+ break;
+ }
+ }
} else {
pr_err("%s: Incorrect buf index %d\n",
__func__, vb2_buf->v4l2_buf.index);
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 d33d34b..334a293 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -459,6 +459,7 @@
uint8_t vt_enable;
void __iomem *p_avtimer_msw;
void __iomem *p_avtimer_lsw;
+ uint8_t ignore_error;
};
#endif
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 044f6f1..eb05015 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -176,15 +176,15 @@
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts)
{
+ uint32_t cnt;
if (!(irq_status0 & 0x1F))
return;
if (irq_status0 & BIT(0)) {
ISP_DBG("%s: SOF IRQ\n", __func__);
- if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
- && vfe_dev->axi_data.src_info[VFE_PIX_0].
- pix_stream_count == 0) {
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count;
+ if (cnt > 0) {
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
if (vfe_dev->axi_data.stream_update)
msm_isp_axi_stream_update(vfe_dev);
msm_isp_update_framedrop_reg(vfe_dev);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index d53d7f6..e443e9a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -370,15 +370,16 @@
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts)
{
+ int cnt;
+
if (!(irq_status0 & 0xF))
return;
if (irq_status0 & (1 << 0)) {
ISP_DBG("%s: SOF IRQ\n", __func__);
- if (vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count > 0
- && vfe_dev->axi_data.src_info[VFE_PIX_0].
- pix_stream_count == 0) {
- msm_isp_sof_notify(vfe_dev, VFE_PIX_0, ts);
+ cnt = vfe_dev->axi_data.src_info[VFE_PIX_0].raw_stream_count;
+ if (cnt > 0) {
+ msm_isp_sof_notify(vfe_dev, VFE_RAW_0, ts);
if (vfe_dev->axi_data.stream_update)
msm_isp_axi_stream_update(vfe_dev);
msm_isp_update_framedrop_reg(vfe_dev);
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 0264d6d..206620c 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
@@ -81,6 +81,10 @@
return rc;
switch (stream_cfg_cmd->output_format) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -167,6 +171,10 @@
uint32_t size = 0;
struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg;
switch (stream_info->output_format) {
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
@@ -444,7 +452,7 @@
sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
sof_event.timestamp = ts->event_time;
sof_event.mono_timestamp = ts->buf_time;
- msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
+ msm_isp_send_event(vfe_dev, ISP_EVENT_SOF + frame_src, &sof_event);
}
void msm_isp_calculate_framedrop(
@@ -1215,6 +1223,8 @@
msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
stream_info->state = ACTIVE;
}
+ vfe_dev->axi_data.src_info[
+ SRC_TO_INTF(stream_info->stream_src)].frame_id = 0;
}
msm_isp_update_stream_bandwidth(vfe_dev);
vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev, wm_reload_mask);
@@ -1228,16 +1238,6 @@
update_camif_state(vfe_dev, camif_update);
}
- if (vfe_dev->axi_data.src_info[VFE_RAW_0].raw_stream_count > 0) {
- vfe_dev->axi_data.src_info[VFE_RAW_0].frame_id = 0;
- }
- else if (vfe_dev->axi_data.src_info[VFE_RAW_1].raw_stream_count > 0) {
- vfe_dev->axi_data.src_info[VFE_RAW_1].frame_id = 0;
- }
- else if (vfe_dev->axi_data.src_info[VFE_RAW_2].raw_stream_count > 0) {
- vfe_dev->axi_data.src_info[VFE_RAW_2].frame_id = 0;
- }
-
if (wait_for_complete)
rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
@@ -1308,11 +1308,13 @@
msm_isp_update_rdi_output_count(vfe_dev, stream_cfg_cmd);
cur_stream_cnt = msm_isp_get_curr_stream_cnt(vfe_dev);
if (cur_stream_cnt == 0) {
+ vfe_dev->ignore_error = 1;
if (camif_update == DISABLE_CAMIF_IMMEDIATELY) {
vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
}
vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, ISP_RST_SOFT);
vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
+ vfe_dev->ignore_error = 0;
}
for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
@@ -1389,7 +1391,10 @@
return -EINVAL;
}
if (stream_info->state == ACTIVE &&
- stream_info->stream_type == BURST_STREAM) {
+ stream_info->stream_type == BURST_STREAM &&
+ (1 != update_cmd->num_streams ||
+ UPDATE_STREAM_FRAMEDROP_PATTERN !=
+ update_cmd->update_type)) {
pr_err("%s: Cannot update active burst stream\n",
__func__);
return -EINVAL;
@@ -1416,7 +1421,10 @@
msm_isp_get_framedrop_period(
update_info->skip_pattern);
stream_info->runtime_init_frame_drop = 0;
- stream_info->framedrop_pattern = 0x1;
+ if (update_info->skip_pattern == SKIP_ALL)
+ stream_info->framedrop_pattern = 0x0;
+ else
+ stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
vfe_dev->hw_info->vfe_ops.axi_ops.
cfg_framedrop(vfe_dev, stream_info);
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 057e87f..ffe0b9c 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
@@ -806,6 +806,12 @@
case V4L2_PIX_FMT_NV61:
val = CAL_WORD(pixel_per_line, 1, 8);
break;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ val = CAL_WORD(pixel_per_line, 2, 8);
+ break;
/*TD: Add more image format*/
default:
msm_isp_print_fourcc_error(__func__, output_format);
@@ -995,7 +1001,8 @@
error_mask1 &= irq_status1;
irq_status0 &= ~error_mask0;
irq_status1 &= ~error_mask1;
- if ((error_mask0 != 0) || (error_mask1 != 0))
+ if (!vfe_dev->ignore_error &&
+ ((error_mask0 != 0) || (error_mask1 != 0)))
msm_isp_update_error_info(vfe_dev, error_mask0, error_mask1);
if ((irq_status0 == 0) && (irq_status1 == 0) &&
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index ef8b996..7805930 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -127,31 +127,63 @@
}
static int32_t msm_actuator_init_focus(struct msm_actuator_ctrl_t *a_ctrl,
- uint16_t size, enum msm_actuator_data_type type,
- struct reg_settings_t *settings)
+ uint16_t size, struct reg_settings_t *settings)
{
int32_t rc = -EFAULT;
int32_t i = 0;
CDBG("Enter\n");
for (i = 0; i < size; i++) {
- switch (type) {
- case MSM_ACTUATOR_BYTE_DATA:
- rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write(
- &a_ctrl->i2c_client,
- settings[i].reg_addr,
- settings[i].reg_data, MSM_CAMERA_I2C_BYTE_DATA);
- break;
- case MSM_ACTUATOR_WORD_DATA:
- rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write(
- &a_ctrl->i2c_client,
- settings[i].reg_addr,
- settings[i].reg_data, MSM_CAMERA_I2C_WORD_DATA);
- break;
- default:
- pr_err("Unsupport data type: %d\n", type);
- break;
+ switch (settings[i].i2c_operation) {
+ case MSM_ACT_WRITE: {
+ switch (settings[i].data_type) {
+ case MSM_ACTUATOR_BYTE_DATA:
+ rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+ &a_ctrl->i2c_client,
+ settings[i].reg_addr,
+ settings[i].reg_data,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ break;
+ case MSM_ACTUATOR_WORD_DATA:
+ rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write(
+ &a_ctrl->i2c_client,
+ settings[i].reg_addr,
+ settings[i].reg_data,
+ MSM_CAMERA_I2C_WORD_DATA);
+ break;
+ default:
+ pr_err("Unsupport data type: %d\n",
+ settings[i].i2c_operation);
+ break;
+ }
}
+ case MSM_ACT_POLL: {
+ switch (settings[i].data_type) {
+ case MSM_ACTUATOR_BYTE_DATA:
+ rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll(
+ &a_ctrl->i2c_client,
+ settings[i].reg_addr,
+ settings[i].reg_data,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ break;
+ case MSM_ACTUATOR_WORD_DATA:
+ rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_poll(
+ &a_ctrl->i2c_client,
+ settings[i].reg_addr,
+ settings[i].reg_data,
+ MSM_CAMERA_I2C_WORD_DATA);
+ break;
+ default:
+ pr_err("Unsupport data type: %d\n",
+ settings[i].i2c_operation);
+ break;
+ }
+ }
+ }
+
+ if (0 != settings[i].delay)
+ msleep(settings[i].delay);
+
if (rc < 0)
break;
}
@@ -544,7 +576,6 @@
}
rc = a_ctrl->func_tbl->actuator_init_focus(a_ctrl,
set_info->actuator_params.init_setting_size,
- a_ctrl->i2c_data_type,
init_settings);
kfree(init_settings);
if (rc < 0) {
@@ -644,6 +675,7 @@
.i2c_write_table_w_microdelay =
msm_camera_cci_i2c_write_table_w_microdelay,
.i2c_util = msm_sensor_cci_i2c_util,
+ .i2c_poll = msm_camera_cci_i2c_poll,
};
static struct msm_camera_i2c_fn_t msm_sensor_qup_func_tbl = {
@@ -654,6 +686,7 @@
.i2c_write_seq_table = msm_camera_qup_i2c_write_seq_table,
.i2c_write_table_w_microdelay =
msm_camera_qup_i2c_write_table_w_microdelay,
+ .i2c_poll = msm_camera_qup_i2c_poll,
};
static int msm_actuator_open(struct v4l2_subdev *sd,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
index 7ec9a49..772b12e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 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
@@ -31,7 +31,7 @@
int32_t (*actuator_init_step_table)(struct msm_actuator_ctrl_t *,
struct msm_actuator_set_info_t *);
int32_t (*actuator_init_focus)(struct msm_actuator_ctrl_t *,
- uint16_t, enum msm_actuator_data_type, struct reg_settings_t *);
+ uint16_t, struct reg_settings_t *);
int32_t (*actuator_set_default_focus) (struct msm_actuator_ctrl_t *,
struct msm_actuator_move_params_t *);
int32_t (*actuator_move_focus) (struct msm_actuator_ctrl_t *,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 981c210..8662657 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -457,9 +457,8 @@
break;
}
for (i = 0; i < csid_params.lut_params.num_cid; i++) {
- vc_cfg = kzalloc(csid_params.lut_params.num_cid *
- sizeof(struct msm_camera_csid_vc_cfg),
- GFP_KERNEL);
+ vc_cfg = kzalloc(sizeof(struct msm_camera_csid_vc_cfg),
+ GFP_KERNEL);
if (!vc_cfg) {
pr_err("%s: %d failed\n", __func__, __LINE__);
for (i--; i >= 0; i--)
@@ -469,8 +468,7 @@
}
if (copy_from_user(vc_cfg,
(void *)csid_params.lut_params.vc_cfg[i],
- (csid_params.lut_params.num_cid *
- sizeof(struct msm_camera_csid_vc_cfg)))) {
+ sizeof(struct msm_camera_csid_vc_cfg))) {
pr_err("%s: %d failed\n", __func__, __LINE__);
kfree(vc_cfg);
for (i--; i >= 0; i--)
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 5c0e6d5..7649a40 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -284,13 +284,23 @@
int j;
struct msm_eeprom_memory_map_t *emap = block->map;
uint8_t *memptr = block->mapdata;
+ struct msm_eeprom_board_info *eb_info = NULL;
if (!e_ctrl) {
pr_err("%s e_ctrl is NULL", __func__);
return -EINVAL;
}
+ eb_info = e_ctrl->eboard_info;
for (j = 0; j < block->num_map; j++) {
+ if (emap[j].saddr.addr) {
+ eb_info->i2c_slaveaddr = emap[j].saddr.addr;
+ e_ctrl->i2c_client.cci_client->sid =
+ eb_info->i2c_slaveaddr >> 1;
+ pr_err("qcom,slave-addr = 0x%X\n",
+ eb_info->i2c_slaveaddr);
+ }
+
if (emap[j].page.valid_size) {
e_ctrl->i2c_client.addr_type = emap[j].page.addr_t;
rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
@@ -405,6 +415,12 @@
goto ERROR;
}
+ snprintf(property, PROPERTY_MAXSIZE, "qcom,saddr%d", i);
+ rc = of_property_read_u32_array(of, property,
+ (uint32_t *) &map[i].saddr.addr, 1);
+ if (rc < 0)
+ CDBG("%s: saddr not needed - block %d\n", __func__, i);
+
snprintf(property, PROPERTY_MAXSIZE, "qcom,mem%d", i);
rc = of_property_read_u32_array(of, property,
(uint32_t *) &map[i].mem, count);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
index e233b8d..36f3b61 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/gc0339.c
@@ -407,6 +407,10 @@
for (i = 0; i < SUB_MODULE_MAX; i++)
cdata->cfg.sensor_info.subdev_id[i] =
s_ctrl->sensordata->sensor_info->subdev_id[i];
+ cdata->cfg.sensor_info.is_mount_angle_valid =
+ s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
+ cdata->cfg.sensor_info.sensor_mount_angle =
+ s_ctrl->sensordata->sensor_info->sensor_mount_angle;
CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
cdata->cfg.sensor_info.sensor_name);
CDBG("%s:%d session id %d\n", __func__, __LINE__,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
index 2b1024e..c7e0cb5 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
@@ -1781,6 +1781,10 @@
for (i = 0; i < SUB_MODULE_MAX; i++)
cdata->cfg.sensor_info.subdev_id[i] =
s_ctrl->sensordata->sensor_info->subdev_id[i];
+ cdata->cfg.sensor_info.is_mount_angle_valid =
+ s_ctrl->sensordata->sensor_info->is_mount_angle_valid;
+ cdata->cfg.sensor_info.sensor_mount_angle =
+ s_ctrl->sensordata->sensor_info->sensor_mount_angle;
CDBG("%s:%d sensor name %s\n", __func__, __LINE__,
cdata->cfg.sensor_info.sensor_name);
CDBG("%s:%d session id %d\n", __func__, __LINE__,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
index 1fb113d..cc301ae 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_dt_util.c
@@ -356,7 +356,8 @@
struct msm_sensor_power_setting *ps;
struct msm_sensor_power_setting *power_setting;
- uint16_t *power_setting_size;
+ uint16_t *power_setting_size, size = 0;
+ bool need_reverse = 0;
if (!power_info)
return -EINVAL;
@@ -508,6 +509,39 @@
i, ps[i].delay);
}
kfree(array);
+
+ size = *power_setting_size;
+
+ if (NULL != ps && 0 != size)
+ need_reverse = 1;
+
+ power_info->power_down_setting =
+ kzalloc(sizeof(*ps) * size, GFP_KERNEL);
+
+ if (!power_info->power_down_setting) {
+ pr_err("%s failed %d\n", __func__, __LINE__);
+ rc = -ENOMEM;
+ goto ERROR1;
+ }
+
+ memcpy(power_info->power_down_setting,
+ ps, sizeof(*ps) * size);
+
+ power_info->power_down_setting_size = size;
+
+ if (need_reverse) {
+ int c, end = size - 1;
+ struct msm_sensor_power_setting power_down_setting_t;
+ for (c = 0; c < size/2; c++) {
+ power_down_setting_t =
+ power_info->power_down_setting[c];
+ power_info->power_down_setting[c] =
+ power_info->power_down_setting[end];
+ power_info->power_down_setting[end] =
+ power_down_setting_t;
+ end--;
+ }
+ }
return rc;
ERROR2:
kfree(array);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
index 763c131..1bceb51 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 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
@@ -117,4 +117,8 @@
struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type);
+int32_t msm_camera_qup_i2c_poll(struct msm_camera_i2c_client *client,
+ uint32_t addr, uint16_t data,
+ enum msm_camera_i2c_data_type data_type);
+
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 71ad080..ea7d670 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -21,7 +21,7 @@
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
#define MIN_NUM_OUTPUT_BUFFERS 4
-#define MAX_NUM_OUTPUT_BUFFERS 6
+#define MAX_NUM_OUTPUT_BUFFERS VIDEO_MAX_FRAME
#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8080
#define TZ_DYNAMIC_BUFFER_FEATURE_ID 12
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 4424c1f..d8b608437 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -125,6 +125,14 @@
"Turbo"
};
+static const char *const intra_refresh_modes[] = {
+ "None",
+ "Cyclic",
+ "Adaptive",
+ "Cyclic Adaptive",
+ "Random"
+};
+
enum msm_venc_ctrl_cluster {
MSM_VENC_CTRL_CLUSTER_QP = 1 << 0,
MSM_VENC_CTRL_CLUSTER_INTRA_PERIOD = 1 << 1,
@@ -566,6 +574,7 @@
(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE) |
(1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM)
),
+ .qmenu = intra_refresh_modes,
.cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
},
{
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 59a1ec0..9dbecfb 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -525,7 +525,7 @@
if ((i == 0) && is_dynamic_output_buffer_mode(b, inst)) {
rc = buf_ref_get(inst, binfo);
if (rc < 0)
- return rc;
+ goto exit;
}
dprintk(VIDC_DBG,
"%s: [MAP] binfo = %p, handle[%d] = %p, device_addr = 0x%x, fd = %d, offset = %d, mapped = %d\n",
@@ -683,7 +683,8 @@
return -EINVAL;
}
} else
- dprintk(VIDC_ERR, "%s: WARN: NULL handle", __func__);
+ dprintk(VIDC_DBG, "%s: NULL handle for plane %d\n",
+ __func__, i);
}
return 0;
}
@@ -813,6 +814,10 @@
int msm_vidc_encoder_cmd(void *instance, struct v4l2_encoder_cmd *enc)
{
struct msm_vidc_inst *inst = instance;
+ if (!inst || !inst->core || !enc) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return -EINVAL;
+ }
if (inst->session_type == MSM_VIDC_ENCODER)
return msm_venc_cmd(instance, enc);
return -EINVAL;
@@ -821,6 +826,10 @@
int msm_vidc_decoder_cmd(void *instance, struct v4l2_decoder_cmd *dec)
{
struct msm_vidc_inst *inst = instance;
+ if (!inst || !inst->core || !dec) {
+ dprintk(VIDC_ERR, "%s invalid params\n", __func__);
+ return -EINVAL;
+ }
if (inst->session_type == MSM_VIDC_DECODER)
return msm_vdec_cmd(instance, dec);
return -EINVAL;
@@ -961,6 +970,13 @@
}
}
+ if (!buffer_info && inst->map_output_buffer) {
+ dprintk(VIDC_ERR,
+ "%s: error - no buffer info found in registered list\n",
+ __func__);
+ return -EINVAL;
+ }
+
if (is_dynamic_output_buffer_mode(b, inst)) {
mutex_lock(&inst->lock);
buffer_info->dequeued = true;
@@ -1327,7 +1343,6 @@
mutex_lock(&inst->lock);
}
mutex_unlock(&inst->lock);
- msm_smem_delete_client(inst->mem_client);
debugfs_remove_recursive(inst->debugfs_root);
}
}
@@ -1385,7 +1400,9 @@
for (i = 0; i < MAX_PORT_NUM; i++)
vb2_queue_release(&inst->bufq[i].vb2_bufq);
+ msm_smem_delete_client(inst->mem_client);
pr_info(VIDC_DBG_TAG "Closed video instance: %p\n", VIDC_INFO, inst);
kfree(inst);
+
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 95afa2a..70114de 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -390,7 +390,8 @@
&inst->completions[SESSION_MSG_INDEX(cmd)],
msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
if (!rc) {
- dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
+ dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n",
+ SESSION_MSG_INDEX(cmd));
msm_comm_recover_from_session_error(inst);
rc = -EIO;
} else {
@@ -1472,7 +1473,8 @@
&core->completions[SYS_MSG_INDEX(RELEASE_RESOURCE_DONE)],
msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
if (!rc) {
- dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
+ dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n",
+ SYS_MSG_INDEX(RELEASE_RESOURCE_DONE));
rc = -EIO;
}
release_ocmem_failed:
@@ -1494,7 +1496,8 @@
&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)],
msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
if (!rc) {
- dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n", rc);
+ dprintk(VIDC_ERR, "Wait interrupted or timeout: %d\n",
+ SYS_MSG_INDEX(SYS_INIT_DONE));
rc = -EIO;
goto exit;
} else {
@@ -2574,7 +2577,8 @@
msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
if (!rc) {
dprintk(VIDC_ERR,
- "Wait interrupted or timeout: %d\n", rc);
+ "Wait interrupted or timeout: %d\n",
+ SESSION_MSG_INDEX(SESSION_PROPERTY_INFO));
inst->state = MSM_VIDC_CORE_INVALID;
msm_comm_recover_from_session_error(inst);
rc = -EIO;
@@ -3316,10 +3320,24 @@
rc = msm_vidc_load_supported(inst);
if (!rc && inst->capability.capability_set) {
- rc = call_hfi_op(hdev, capability_check,
- inst->fmts[OUTPUT_PORT]->fourcc,
- inst->prop.width[CAPTURE_PORT], &capability->width.max,
- &capability->height.max);
+ if (inst->prop.width[CAPTURE_PORT] < capability->width.min ||
+ inst->prop.height[CAPTURE_PORT] <
+ capability->height.min) {
+ dprintk(VIDC_ERR,
+ "Unsupported WxH = (%u)x(%u), min supported is - (%u)x(%u)\n",
+ inst->prop.width[CAPTURE_PORT],
+ inst->prop.height[CAPTURE_PORT],
+ capability->width.min,
+ capability->height.min);
+ rc = -ENOTSUPP;
+ }
+ if (!rc) {
+ rc = call_hfi_op(hdev, capability_check,
+ inst->fmts[OUTPUT_PORT]->fourcc,
+ inst->prop.width[CAPTURE_PORT],
+ &capability->width.max,
+ &capability->height.max);
+ }
if (!rc && (inst->prop.height[CAPTURE_PORT]
* inst->prop.width[CAPTURE_PORT] >
@@ -3337,7 +3355,6 @@
inst->state = MSM_VIDC_CORE_INVALID;
mutex_unlock(&inst->sync_lock);
msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
- wake_up(&inst->kernel_event_queue);
}
return rc;
}
@@ -3388,7 +3405,7 @@
msecs_to_jiffies(msm_vidc_hw_rsp_timeout));
if (!rc) {
dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
- __func__, rc);
+ __func__, SESSION_MSG_INDEX(SESSION_ABORT_DONE));
msm_comm_generate_sys_error(inst);
} else
change_inst_state(inst, MSM_VIDC_CLOSE_DONE);
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index e70635d..5404af6 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -554,6 +554,10 @@
new_session = (struct hal_session *)
kzalloc(sizeof(struct hal_session), GFP_KERNEL);
+ if (!new_session) {
+ dprintk(VIDC_ERR, "new session fail: Out of memory\n");
+ return NULL;
+ }
new_session->session_id = (u32) session_id;
if (session_type == 1)
new_session->is_decoder = 0;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index d1710b7..d6000c9 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -3475,9 +3475,15 @@
&smem_block_size);
if (smem_table_ptr &&
((smem_image_index_venus + version_string_size) <=
- smem_block_size))
+ smem_block_size)) {
memcpy(version_info, smem_table_ptr + smem_image_index_venus,
version_string_size);
+ } else {
+ dprintk(VIDC_ERR,
+ "%s: failed to read version info from smem table\n",
+ __func__);
+ return -EINVAL;
+ }
while (version_info[i++] != 'V' && i < version_string_size)
;
diff --git a/drivers/media/platform/msm/wfd/mdp-5-subdev.c b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
index 97204ae..a28cb1a 100644
--- a/drivers/media/platform/msm/wfd/mdp-5-subdev.c
+++ b/drivers/media/platform/msm/wfd/mdp-5-subdev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 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
@@ -208,6 +208,7 @@
return -EINVAL;
}
+ msm_fb_writeback_iommu_ref(inst->mdp, true);
if (inst->secure) {
rc = msm_ion_secure_buffer(mmap->ion_client,
mregion->ion_handle, VIDEO_PIXEL, 0);
@@ -231,12 +232,15 @@
!inst->secure ? "non" : "", rc);
goto iommu_fail;
}
+ msm_fb_writeback_iommu_ref(inst->mdp, false);
return 0;
iommu_fail:
if (inst->secure)
msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
secure_fail:
+ msm_fb_writeback_iommu_ref(inst->mdp, false);
+
return rc;
}
@@ -251,10 +255,10 @@
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
-
inst = mmap->cookie;
mregion = mmap->mregion;
+ msm_fb_writeback_iommu_ref(inst->mdp, true);
domain = msm_fb_get_iommu_domain(inst->mdp,
inst->secure ? MDP_IOMMU_DOMAIN_CP :
MDP_IOMMU_DOMAIN_NS);
@@ -264,6 +268,7 @@
if (inst->secure)
msm_ion_unsecure_buffer(mmap->ion_client, mregion->ion_handle);
+ msm_fb_writeback_iommu_ref(inst->mdp, false);
return 0;
}
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 99f6b5a..efafa23 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -164,13 +164,14 @@
uint32_t qsee_perf_client;
struct qseecom_clk qsee;
struct qseecom_clk ce_drv;
- struct cdev cdev;
bool support_bus_scaling;
uint32_t cumulative_mode;
enum qseecom_bandwidth_request_mode current_mode;
struct timer_list bw_scale_down_timer;
struct work_struct bw_inactive_req_ws;
+ struct cdev cdev;
+ bool timer_running;
};
struct qseecom_client_handle {
@@ -490,6 +491,7 @@
__qseecom_set_msm_bus_request(INACTIVE);
pr_debug("current_mode = %d, cumulative_mode = %d\n",
qseecom.current_mode, qseecom.cumulative_mode);
+ qseecom.timer_running = false;
mutex_unlock(&qsee_bw_mutex);
mutex_unlock(&app_access_lock);
return;
@@ -501,6 +503,25 @@
return;
}
+static void __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
+{
+ struct qseecom_clk *qclk;
+ mutex_lock(&clk_access_lock);
+ if (ce == CLK_QSEE)
+ qclk = &qseecom.qsee;
+ else
+ qclk = &qseecom.ce_drv;
+
+ if (qclk->clk_access_cnt == 0) {
+ mutex_unlock(&clk_access_lock);
+ return;
+ }
+ qclk->clk_access_cnt--;
+ mutex_unlock(&clk_access_lock);
+ return;
+}
+
+
static int qseecom_scale_bus_bandwidth_timer(uint32_t mode, uint32_t duration)
{
int32_t ret = 0;
@@ -515,13 +536,12 @@
} else {
request_mode = mode;
}
+
__qseecom_set_msm_bus_request(request_mode);
-
- del_timer_sync(&(qseecom.bw_scale_down_timer));
- qseecom.bw_scale_down_timer.expires = jiffies +
- msecs_to_jiffies(duration);
- add_timer(&(qseecom.bw_scale_down_timer));
-
+ if (qseecom.timer_running) {
+ __qseecom_decrease_clk_ref_count(CLK_QSEE);
+ del_timer_sync(&(qseecom.bw_scale_down_timer));
+ }
mutex_unlock(&qsee_bw_mutex);
return ret;
}
@@ -582,6 +602,14 @@
{
if (!qseecom.support_bus_scaling)
qsee_disable_clock_vote(data, CLK_SFPB);
+ else {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom.bw_scale_down_timer.expires = jiffies +
+ msecs_to_jiffies(QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
+ add_timer(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = true;
+ mutex_unlock(&qsee_bw_mutex);
+ }
return;
}
@@ -1061,16 +1089,13 @@
return -EINVAL;
}
- if (((uint32_t)req_ptr->cmd_req_buf <
- data_ptr->client.user_virt_sb_base)
- || ((uint32_t)req_ptr->cmd_req_buf >=
- (data_ptr->client.user_virt_sb_base +
- data_ptr->client.sb_length))) {
- pr_err("cmd buffer address not within shared bufffer\n");
+ /* Clients need to ensure req_buf is at base offset of shared buffer */
+ if ((uint32_t)req_ptr->cmd_req_buf !=
+ data_ptr->client.user_virt_sb_base) {
+ pr_err("cmd buf not pointing to base offset of shared buffer\n");
return -EINVAL;
}
-
if (((uint32_t)req_ptr->resp_buf < data_ptr->client.user_virt_sb_base)
|| ((uint32_t)req_ptr->resp_buf >=
(data_ptr->client.user_virt_sb_base +
@@ -1089,8 +1114,6 @@
(uint32_t)req_ptr->resp_buf));
send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
- pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
- ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
return ret;
}
@@ -1115,6 +1138,21 @@
return -EINVAL;
}
+ if (data->client.sb_virt == NULL) {
+ pr_err("sb_virt null\n");
+ return -EINVAL;
+ }
+
+ if (data->client.user_virt_sb_base == 0) {
+ pr_err("user_virt_sb_base is null\n");
+ return -EINVAL;
+ }
+
+ if (data->client.sb_length == 0) {
+ pr_err("sb_length is 0\n");
+ return -EINVAL;
+ }
+
data->type = QSEECOM_SECURE_SERVICE;
switch (req.cmd_id) {
@@ -1164,7 +1202,16 @@
if (!qseecom.support_bus_scaling) {
qsee_disable_clock_vote(data, CLK_DFAB);
qsee_disable_clock_vote(data, CLK_SFPB);
+ } else {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom.bw_scale_down_timer.expires = jiffies +
+ msecs_to_jiffies(
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ add_timer(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = true;
+ mutex_unlock(&qsee_bw_mutex);
}
+
goto exit;
}
@@ -1188,6 +1235,18 @@
ret = -EINVAL;
break;
}
+ if (!qseecom.support_bus_scaling) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ } else {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom.bw_scale_down_timer.expires = jiffies +
+ msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ add_timer(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = true;
+ mutex_unlock(&qsee_bw_mutex);
+ }
+
exit:
return ret;
}
@@ -2024,6 +2083,14 @@
qseecom_scale_bus_bandwidth_timer(INACTIVE,
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
ret = __qseecom_send_cmd(data, &req);
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom.bw_scale_down_timer.expires = jiffies +
+ msecs_to_jiffies(QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ add_timer(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = true;
+ mutex_unlock(&qsee_bw_mutex);
+ }
atomic_dec(&data->ioctl_count);
mutex_unlock(&app_access_lock);
@@ -3148,6 +3215,15 @@
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
atomic_inc(&data->ioctl_count);
ret = qseecom_send_cmd(data, argp);
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom.bw_scale_down_timer.expires = jiffies +
+ msecs_to_jiffies(
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ add_timer(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = true;
+ mutex_unlock(&qsee_bw_mutex);
+ }
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -3171,7 +3247,15 @@
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
atomic_inc(&data->ioctl_count);
ret = qseecom_send_modfd_cmd(data, argp);
- atomic_dec(&data->ioctl_count);
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ qseecom.bw_scale_down_timer.expires = jiffies +
+ msecs_to_jiffies(
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ add_timer(&(qseecom.bw_scale_down_timer));
+ qseecom.timer_running = true;
+ mutex_unlock(&qsee_bw_mutex);
+ } atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
if (ret)
@@ -3820,6 +3904,7 @@
/* register client for bus scaling */
if (pdev->dev.of_node) {
+ qseecom.pdev->of_node = pdev->dev.of_node;
qseecom.support_bus_scaling =
of_property_read_bool((&pdev->dev)->of_node,
"qcom,support-bus-scaling");
@@ -3924,6 +4009,7 @@
qseecom.bw_scale_down_timer.function =
qseecom_scale_bus_bandwidth_timer_callback;
}
+ qseecom.timer_running = false;
qseecom.qsee_perf_client = msm_bus_scale_register_client(
qseecom_platform_support);
@@ -4014,6 +4100,83 @@
return ret;
}
+static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret = 0;
+ struct qseecom_clk *qclk;
+ qclk = &qseecom.qsee;
+
+ if (qseecom.cumulative_mode != INACTIVE) {
+ ret = __qseecom_set_msm_bus_request(INACTIVE);
+ if (ret)
+ pr_err("Fail to scale down bus\n");
+ }
+ mutex_lock(&clk_access_lock);
+ if (qclk->clk_access_cnt) {
+ if (qclk->ce_clk != NULL)
+ clk_disable_unprepare(qclk->ce_clk);
+ if (qclk->ce_core_clk != NULL)
+ clk_disable_unprepare(qclk->ce_core_clk);
+ if (qclk->ce_bus_clk != NULL)
+ clk_disable_unprepare(qclk->ce_bus_clk);
+ }
+ mutex_unlock(&clk_access_lock);
+ return 0;
+}
+
+static int qseecom_resume(struct platform_device *pdev)
+{
+ int mode = 0;
+ int ret = 0;
+ struct qseecom_clk *qclk;
+ qclk = &qseecom.qsee;
+
+ if (qseecom.cumulative_mode >= HIGH)
+ mode = HIGH;
+ else
+ mode = qseecom.cumulative_mode;
+
+ if (qseecom.cumulative_mode != INACTIVE) {
+ ret = __qseecom_set_msm_bus_request(mode);
+ if (ret)
+ pr_err("Fail to scale down bus\n");
+ }
+
+ mutex_lock(&clk_access_lock);
+ if (qclk->clk_access_cnt) {
+
+ ret = clk_prepare_enable(qclk->ce_core_clk);
+ if (ret) {
+ pr_err("Unable to enable/prepare CE core clk\n");
+ qclk->clk_access_cnt = 0;
+ goto err;
+ }
+
+ ret = clk_prepare_enable(qclk->ce_clk);
+ if (ret) {
+ pr_err("Unable to enable/prepare CE iface clk\n");
+ qclk->clk_access_cnt = 0;
+ goto ce_clk_err;
+ }
+
+ ret = clk_prepare_enable(qclk->ce_bus_clk);
+ if (ret) {
+ pr_err("Unable to enable/prepare CE bus clk\n");
+ qclk->clk_access_cnt = 0;
+ goto ce_bus_clk_err;
+ }
+ }
+ mutex_unlock(&clk_access_lock);
+ return 0;
+
+ce_bus_clk_err:
+ clk_disable_unprepare(qclk->ce_clk);
+ce_clk_err:
+ clk_disable_unprepare(qclk->ce_core_clk);
+err:
+ mutex_unlock(&clk_access_lock);
+ return -EIO;
+}
static struct of_device_id qseecom_match[] = {
{
.compatible = "qcom,qseecom",
@@ -4024,6 +4187,8 @@
static struct platform_driver qseecom_plat_driver = {
.probe = qseecom_probe,
.remove = qseecom_remove,
+ .suspend = qseecom_suspend,
+ .resume = qseecom_resume,
.driver = {
.name = "qseecom",
.owner = THIS_MODULE,
diff --git a/drivers/misc/smsc_hub.c b/drivers/misc/smsc_hub.c
index 6f98dc7..e89451a 100644
--- a/drivers/misc/smsc_hub.c
+++ b/drivers/misc/smsc_hub.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -36,6 +36,7 @@
struct clk *ref_clk;
struct regulator *hsic_hub_reg;
struct regulator *int_pad_reg, *hub_vbus_reg;
+ bool enabled;
};
static struct hsic_hub *smsc_hub;
static struct platform_driver smsc_hub_driver;
@@ -191,6 +192,14 @@
{
int ret;
+ /*
+ * xo_clk_gpio controls an external xo clock which feeds
+ * the hub reference clock. When this gpio is present,
+ * assume that no other clocks are required.
+ */
+ if (hub->pdata->xo_clk_gpio)
+ return 0;
+
if (!init) {
if (!IS_ERR(hub->ref_clk))
clk_disable_unprepare(hub->ref_clk);
@@ -257,6 +266,15 @@
dev_err(hub->dev, "gpio request failed (CLK GPIO)\n");
}
+ if (pdata->xo_clk_gpio) {
+ ret = devm_gpio_request(hub->dev, pdata->xo_clk_gpio,
+ "HSIC_HUB_XO_CLK");
+ if (ret < 0) {
+ dev_err(hub->dev, "gpio request failed(XO CLK GPIO)\n");
+ return ret;
+ }
+ }
+
if (pdata->int_gpio) {
ret = devm_gpio_request(hub->dev, pdata->int_gpio,
"HSIC_HUB_INT");
@@ -266,7 +284,7 @@
}
/* Enable LDO if required for external pull-up */
- smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub_int");
+ smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub-int");
if (IS_ERR(smsc_hub->int_pad_reg)) {
dev_dbg(hub->dev, "unable to get ext hub_int reg\n");
} else {
@@ -298,6 +316,9 @@
{
int ret;
+ if (!of_get_property(hub->dev->of_node, "ext-hub-vddio-supply", NULL))
+ return 0;
+
if (!init) {
if (!IS_ERR(smsc_hub->hsic_hub_reg)) {
regulator_disable(smsc_hub->hsic_hub_reg);
@@ -308,7 +329,7 @@
return 0;
}
- smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "EXT_HUB_VDDIO");
+ smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "ext-hub-vddio");
if (IS_ERR(smsc_hub->hsic_hub_reg)) {
dev_dbg(hub->dev, "unable to get ext hub vddcx\n");
} else {
@@ -345,6 +366,124 @@
return ret;
}
+
+static int smsc_hub_enable(struct hsic_hub *hub)
+{
+ struct smsc_hub_platform_data *pdata = hub->pdata;
+ struct of_dev_auxdata *hsic_host_auxdata = dev_get_platdata(hub->dev);
+ struct device_node *node = hub->dev->of_node;
+ int ret;
+
+ ret = gpio_direction_output(pdata->xo_clk_gpio, 1);
+ if (ret < 0) {
+ dev_err(hub->dev, "fail to enable xo clk\n");
+ return ret;
+ }
+
+ ret = gpio_direction_output(pdata->hub_reset, 0);
+ if (ret < 0) {
+ dev_err(hub->dev, "fail to assert reset\n");
+ goto disable_xo;
+ }
+ udelay(5);
+ ret = gpio_direction_output(pdata->hub_reset, 1);
+ if (ret < 0) {
+ dev_err(hub->dev, "fail to de-assert reset\n");
+ goto disable_xo;
+ }
+
+ ret = of_platform_populate(node, NULL, hsic_host_auxdata,
+ hub->dev);
+ if (ret < 0) {
+ dev_err(smsc_hub->dev, "fail to add child with %d\n",
+ ret);
+ goto reset;
+ }
+
+ pm_runtime_allow(hub->dev);
+
+ return 0;
+
+reset:
+ gpio_direction_output(pdata->hub_reset, 0);
+disable_xo:
+ gpio_direction_output(pdata->xo_clk_gpio, 0);
+
+ return ret;
+}
+
+static int sms_hub_remove_child(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ /*
+ * Runtime PM is disabled before the driver's remove method
+ * is called. So resume the device before unregistering
+ * the device. Don't worry about the PM usage counter as
+ * the device will be freed.
+ */
+ pm_runtime_get_sync(dev);
+ of_device_unregister(pdev);
+
+ return 0;
+}
+
+static int smsc_hub_disable(struct hsic_hub *hub)
+{
+ struct smsc_hub_platform_data *pdata = hub->pdata;
+
+ pm_runtime_forbid(hub->dev);
+ device_for_each_child(hub->dev, NULL, sms_hub_remove_child);
+ gpio_direction_output(pdata->hub_reset, 0);
+ gpio_direction_output(pdata->xo_clk_gpio, 0);
+
+ return 0;
+}
+
+static ssize_t smsc_hub_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", smsc_hub->enabled ?
+ "enabled" : "disabled");
+}
+
+static ssize_t smsc_hub_enable_store(struct device *dev,
+ struct device_attribute *attr, const char
+ *buf, size_t size)
+{
+
+ bool enable;
+ int val;
+ int ret = size;
+
+ if (sscanf(buf, "%d", &val) == 1) {
+ enable = !!val;
+ } else {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (smsc_hub->enabled == enable)
+ goto out;
+
+ if (enable)
+ ret = smsc_hub_enable(smsc_hub);
+ else
+ ret = smsc_hub_disable(smsc_hub);
+
+ pr_debug("smsc hub %s status %d\n", enable ?
+ "Enable" : "Disable", ret);
+ if (!ret) {
+ ret = size;
+ smsc_hub->enabled = enable;
+ }
+out:
+ return ret;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, smsc_hub_enable_show,
+ smsc_hub_enable_store);
+
struct smsc_hub_platform_data *msm_hub_dt_to_pdata(
struct platform_device *pdev)
{
@@ -365,6 +504,8 @@
return ERR_PTR(rc);
} else {
pdata->model_id = temp_val;
+ if (pdata->model_id == 0)
+ return pdata;
}
pdata->hub_reset = of_get_named_gpio(node, "smsc,reset-gpio", 0);
@@ -379,6 +520,10 @@
if (pdata->int_gpio < 0)
pdata->int_gpio = 0;
+ pdata->xo_clk_gpio = of_get_named_gpio(node, "smsc,xo-clk-gpio", 0);
+ if (pdata->xo_clk_gpio < 0)
+ pdata->xo_clk_gpio = 0;
+
return pdata;
}
@@ -406,6 +551,12 @@
return -ENODEV;
}
+ if (pdata->model_id == 0) {
+ dev_dbg(&pdev->dev, "standalone HSIC config enabled\n");
+ return of_platform_populate(node, NULL,
+ hsic_host_auxdata, &pdev->dev);
+ }
+
if (!pdata->hub_reset)
return -EINVAL;
@@ -416,11 +567,14 @@
smsc_hub->dev = &pdev->dev;
smsc_hub->pdata = pdata;
- smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev, "hub_vbus");
- ret = PTR_ERR(smsc_hub->hub_vbus_reg);
- if (ret == -EPROBE_DEFER) {
- dev_dbg(&pdev->dev, "failed to get hub_vbus\n");
- return ret;
+ if (of_get_property(pdev->dev.of_node, "hub-vbus-supply", NULL)) {
+ smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev,
+ "hub-vbus");
+ ret = PTR_ERR(smsc_hub->hub_vbus_reg);
+ if (ret == -EPROBE_DEFER) {
+ dev_dbg(&pdev->dev, "failed to get hub_vbus\n");
+ return ret;
+ }
}
ret = msm_hsic_hub_init_vdd(smsc_hub, 1);
@@ -439,6 +593,16 @@
goto uninit_clock;
}
+ if (pdata->model_id == SMSC3502_ID) {
+ ret = device_create_file(&pdev->dev, &dev_attr_enable);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "fail to create sysfs file\n");
+ goto uninit_gpio;
+ }
+ pm_runtime_forbid(&pdev->dev);
+ goto done;
+ }
+
gpio_direction_output(pdata->hub_reset, 0);
/*
* Hub reset should be asserted for minimum 2microsec
@@ -447,7 +611,7 @@
udelay(5);
gpio_direction_output(pdata->hub_reset, 1);
- if (!IS_ERR(smsc_hub->hub_vbus_reg)) {
+ if (!IS_ERR_OR_NULL(smsc_hub->hub_vbus_reg)) {
ret = regulator_enable(smsc_hub->hub_vbus_reg);
if (ret) {
dev_err(&pdev->dev, "unable to enable hub_vbus\n");
@@ -501,10 +665,13 @@
goto uninit_gpio;
}
+ smsc_hub->enabled = true;
+
if (!smsc_hub->client)
dev_err(&pdev->dev,
"failed to connect to smsc_hub through I2C\n");
+done:
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@@ -524,7 +691,12 @@
{
const struct smsc_hub_platform_data *pdata;
+ if (!smsc_hub)
+ return 0;
+
pdata = smsc_hub->pdata;
+ if (pdata->model_id == SMSC3502_ID)
+ device_remove_file(&pdev->dev, &dev_attr_enable);
if (smsc_hub->client) {
i2c_unregister_device(smsc_hub->client);
smsc_hub->client = NULL;
@@ -532,7 +704,7 @@
}
pm_runtime_disable(&pdev->dev);
- if (!IS_ERR(smsc_hub->hub_vbus_reg))
+ if (!IS_ERR_OR_NULL(smsc_hub->hub_vbus_reg))
regulator_disable(smsc_hub->hub_vbus_reg);
msm_hsic_hub_init_gpio(smsc_hub, 0);
msm_hsic_hub_init_clock(smsc_hub, 0);
@@ -553,13 +725,19 @@
{
int ret = 0;
+ if (!smsc_hub || !smsc_hub->enabled)
+ return 0;
+
if (smsc_hub->xo_handle) {
ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_OFF);
if (ret) {
pr_err("%s: failed to devote for TCXO\n"
"D1 buffer%d\n", __func__, ret);
}
+ } else if (smsc_hub->pdata->xo_clk_gpio) {
+ gpio_direction_output(smsc_hub->pdata->xo_clk_gpio, 0);
}
+
return ret;
}
@@ -567,13 +745,19 @@
{
int ret = 0;
+ if (!smsc_hub || !smsc_hub->enabled)
+ return 0;
+
if (smsc_hub->xo_handle) {
ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
if (ret) {
pr_err("%s: failed to vote for TCXO\n"
"D1 buffer%d\n", __func__, ret);
}
+ } else if (smsc_hub->pdata->xo_clk_gpio) {
+ gpio_direction_output(smsc_hub->pdata->xo_clk_gpio, 1);
}
+
return ret;
}
#endif
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 6add807..6de1cde 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -198,9 +198,13 @@
{
int ret;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- struct mmc_card *card = md->queue.card;
+ struct mmc_card *card;
int locked = 0;
+ if (!md)
+ return -EINVAL;
+
+ card = md->queue.card;
if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
locked = 2;
else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
@@ -226,6 +230,8 @@
return count;
md = mmc_blk_get(dev_to_disk(dev));
+ if (!md)
+ return -EINVAL;
card = md->queue.card;
mmc_rpm_hold(card->host, &card->dev);
@@ -265,6 +271,9 @@
int ret;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ if (!md)
+ return -EINVAL;
+
ret = snprintf(buf, PAGE_SIZE, "%d",
get_disk_ro(dev_to_disk(dev)) ^
md->read_only);
@@ -279,6 +288,10 @@
char *end;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
unsigned long set = simple_strtoul(buf, &end, 0);
+
+ if (!md)
+ return -EINVAL;
+
if (end == buf) {
ret = -EINVAL;
goto out;
@@ -299,6 +312,8 @@
int num_wr_reqs_to_start_packing;
int ret;
+ if (!md)
+ return -EINVAL;
num_wr_reqs_to_start_packing = md->queue.num_wr_reqs_to_start_packing;
ret = snprintf(buf, PAGE_SIZE, "%d\n", num_wr_reqs_to_start_packing);
@@ -314,9 +329,13 @@
{
int value;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- struct mmc_card *card = md->queue.card;
+ struct mmc_card *card;
int ret = count;
+ if (!md)
+ return -EINVAL;
+
+ card = md->queue.card;
if (!card) {
ret = -EINVAL;
goto exit;
@@ -348,9 +367,13 @@
struct device_attribute *attr, char *buf)
{
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- struct mmc_card *card = md->queue.card;
+ struct mmc_card *card;
int ret;
+ if (!md)
+ return -EINVAL;
+
+ card = md->queue.card;
if (!card)
ret = -EINVAL;
else
@@ -368,10 +391,14 @@
{
int value;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- struct mmc_card *card = md->queue.card;
+ struct mmc_card *card;
unsigned int card_size;
int ret = count;
+ if (!md)
+ return -EINVAL;
+
+ card = md->queue.card;
if (!card) {
ret = -EINVAL;
goto exit;
@@ -409,6 +436,8 @@
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
int ret;
+ if (!md)
+ return -EINVAL;
ret = snprintf(buf, PAGE_SIZE, "%d\n", md->queue.no_pack_for_random);
mmc_blk_put(md);
@@ -422,9 +451,13 @@
{
int value;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- struct mmc_card *card = md->queue.card;
+ struct mmc_card *card;
int ret = count;
+ if (!md)
+ return -EINVAL;
+
+ card = md->queue.card;
if (!card) {
ret = -EINVAL;
goto exit;
@@ -772,7 +805,7 @@
/* make sure this is a rpmb partition */
if ((!md) || (!(md->area_type & MMC_BLK_DATA_AREA_RPMB))) {
err = -EINVAL;
- goto cmd_done;
+ return err;
}
idata = mmc_blk_ioctl_rpmb_copy_from_user(ic_ptr);
@@ -2605,15 +2638,13 @@
struct mmc_host *host = card->host;
unsigned long flags;
+ if (req && !mq->mqrq_prev->req) {
+ mmc_rpm_hold(host, &card->dev);
#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
if (mmc_bus_needs_resume(card->host)) {
mmc_resume_bus(card->host);
- mmc_blk_set_blksize(md, card);
}
#endif
-
- if (req && !mq->mqrq_prev->req) {
- mmc_rpm_hold(host, &card->dev);
/* claim host only for the first request */
mmc_claim_host(card->host);
if (card->ext_csd.bkops_en)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c496077..1feb26b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -983,6 +983,10 @@
*/
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
+ if (mmc_bus_needs_resume(host))
+ mmc_resume_bus(host);
+#endif
__mmc_start_req(host, mrq);
mmc_wait_for_req_done(host, mrq);
}
@@ -2011,9 +2015,6 @@
host->bus_ops->resume(host);
}
- if (host->bus_ops->detect && !host->bus_dead)
- host->bus_ops->detect(host);
-
mmc_bus_put(host);
printk("%s: Deferred resume completed\n", mmc_hostname(host));
return 0;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 885d0d2..63952e7 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -340,6 +340,8 @@
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
mmc_select_card_type(card);
+ card->ext_csd.raw_drive_strength = ext_csd[EXT_CSD_DRIVE_STRENGTH];
+
card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
card->ext_csd.raw_erase_timeout_mult =
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 3648d88..d4d7c18 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -851,6 +851,7 @@
((*rocr & 0x41000000) == 0x41000000)) {
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
if (err) {
+ mmc_power_cycle(host);
ocr &= ~SD_OCR_S18R;
goto try_again;
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 32f5220..822548e 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1503,7 +1503,8 @@
mrq->cmd->error = -EIO;
if (mrq->data)
mrq->data->error = -EIO;
- tasklet_schedule(&host->finish_tasklet);
+ mmc_request_done(host->mmc, mrq);
+ sdhci_runtime_pm_put(host);
return;
}
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 0fde9fc..40d3d9f 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1224,7 +1224,11 @@
mtd = open_mtd_device(p->name);
if (IS_ERR(mtd)) {
err = PTR_ERR(mtd);
- goto out_detach;
+ ubi_err("cannot open mtd %s, error %d", p->name, err);
+ /* See comment below re-ubi_is_module(). */
+ if (ubi_is_module())
+ goto out_detach;
+ continue;
}
mutex_lock(&ubi_devices_mutex);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 7c1a9bf..444e4ff 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -712,6 +712,9 @@
if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) {
dbg_wl("no WL needed: min used EC %d, max free EC %d",
e1->ec, e2->ec);
+
+ /* Give the unused PEB back */
+ wl_tree_add(e2, &ubi->free);
goto out_cancel;
}
paranoid_check_in_wl_tree(ubi, e1, &ubi->used);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 38c70a3..3558f28 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -36,6 +36,7 @@
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/qpnp/qpnp-adc.h>
+#include <mach/board.h>
#include <mach/msm_smd.h>
#include <mach/msm_iomap.h>
#include <mach/subsystem_restart.h>
@@ -591,6 +592,14 @@
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
+ reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_err("PRONTO_PLL_STATUS %08x\n", reg);
+
+ reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET;
+ reg4 = readl_relaxed(reg_addr);
+ pr_err("PMU_CPU_CMD_RCGR %08x\n", reg4);
+
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PRONTO_PMU_COM_GDSCR %08x\n",
@@ -639,10 +648,6 @@
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
- reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
- reg = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PRONTO_PLL_STATUS %08x\n", __func__, reg);
-
tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
@@ -716,10 +721,6 @@
reg3 = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PMU_WLAN_AHB_CBCR %08x\n", __func__, reg3);
- reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET;
- reg4 = readl_relaxed(reg_addr);
- pr_info_ratelimited("%s: PMU_CPU_CMD_RCGR %08x\n", __func__, reg4);
-
if ((reg & PRONTO_PMU_WLAN_BCR_BLK_ARES) ||
(reg2 & PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE) ||
(!(reg4 & PRONTO_PMU_CPU_AHB_CMD_RCGR_ROOT_EN)) ||
@@ -748,6 +749,22 @@
EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
#ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE
+static void wcnss_log_iris_regs(void)
+{
+ int i;
+ u32 reg_val;
+ u32 regs_array[] = {
+ 0x04, 0x05, 0x11, 0x1e, 0x40, 0x48,
+ 0x49, 0x4b, 0x00, 0x01, 0x4d};
+
+ pr_info("IRIS Registers [address] : value\n");
+
+ for (i = 0; i < ARRAY_SIZE(regs_array); i++) {
+ reg_val = wcnss_rf_read_reg(regs_array[i]);
+ pr_info("[0x%08x] : 0x%08x\n", regs_array[i], reg_val);
+ }
+}
+
void wcnss_log_debug_regs_on_bite(void)
{
struct platform_device *pdev = wcnss_get_platform_device();
@@ -768,10 +785,12 @@
clk_rate = clk_get_rate(measure);
pr_debug("wcnss: clock frequency is: %luHz\n", clk_rate);
- if (clk_rate)
+ if (clk_rate) {
wcnss_pronto_log_debug_regs();
- else
+ } else {
pr_err("clock frequency is zero, cannot access PMU or other registers\n");
+ wcnss_log_iris_regs();
+ }
}
}
#endif
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index c6192ed..a44c06c 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -1397,18 +1397,6 @@
gpio_set_value(platform_data->dis_gpio, 1);
goto err_nfcc_not_present;
}
- regulators.regulator = regulator_get(&client->dev, regulators.name);
- if (IS_ERR(regulators.regulator)) {
- r = PTR_ERR(regulators.regulator);
- pr_err("regulator get of %s failed (%d)\n", regulators.name, r);
- } else {
- /* Enable the regulator */
- r = regulator_enable(regulators.regulator);
- if (r) {
- pr_err("vreg %s enable failed (%d)\n",
- regulators.name, r);
- }
- }
logging_level = 0;
/* request irq. The irq is set whenever the chip has data available
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index 9bfb77d..297c152 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -223,9 +223,3 @@
unsigned int reg;
};
#endif
-/* enable LDO */
-struct vregs_info {
- const char * const name;
- struct regulator *regulator;
-};
-struct vregs_info regulators = {"vlogic", NULL};
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 507d02c..0ef2639 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -52,8 +52,15 @@
#define QPNP_PON_PS_HOLD_RST_CTL2(base) (base + 0x5B)
#define QPNP_PON_WD_RST_S2_CTL(base) (base + 0x56)
#define QPNP_PON_WD_RST_S2_CTL2(base) (base + 0x57)
-#define QPNP_PON_TRIGGER_EN(base) (base + 0x80)
+#define QPNP_PON_S3_SRC(base) (base + 0x74)
#define QPNP_PON_S3_DBC_CTL(base) (base + 0x75)
+#define QPNP_PON_TRIGGER_EN(base) (base + 0x80)
+
+#define QPNP_PON_S3_SRC_KPDPWR 0
+#define QPNP_PON_S3_SRC_RESIN 1
+#define QPNP_PON_S3_SRC_KPDPWR_OR_RESIN 2
+#define QPNP_PON_S3_SRC_KPDPWR_AND_RESIN 3
+#define QPNP_PON_S3_SRC_MASK 0x3
#define QPNP_PON_WARM_RESET_TFT BIT(4)
@@ -990,7 +997,17 @@
"Unable to config pon reset\n");
goto unreg_input_dev;
}
+ } else {
+ /* disable S2 reset */
+ rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
+ QPNP_PON_S2_CNTL_EN, 0);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to disable S2 reset\n");
+ goto unreg_input_dev;
+ }
}
+
rc = qpnp_pon_request_irqs(pon, cfg);
if (rc) {
dev_err(&pon->spmi->dev, "Unable to request-irq's\n");
@@ -1019,6 +1036,8 @@
u32 delay = 0, s3_debounce = 0;
int rc, sys_reset, index;
u8 pon_sts = 0;
+ const char *s3_src;
+ u8 s3_src_reg;
pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
GFP_KERNEL);
@@ -1119,6 +1138,32 @@
}
}
+ /* program s3 source */
+ s3_src = "kpdpwr-and-resin";
+ rc = of_property_read_string(pon->spmi->dev.of_node,
+ "qcom,s3-src", &s3_src);
+ if (rc && rc != -EINVAL) {
+ dev_err(&pon->spmi->dev, "Unable to read s3 timer\n");
+ return rc;
+ }
+
+ if (!strcmp(s3_src, "kpdpwr"))
+ s3_src_reg = QPNP_PON_S3_SRC_KPDPWR;
+ else if (!strcmp(s3_src, "resin"))
+ s3_src_reg = QPNP_PON_S3_SRC_RESIN;
+ else if (!strcmp(s3_src, "kpdpwr-or-resin"))
+ s3_src_reg = QPNP_PON_S3_SRC_KPDPWR_OR_RESIN;
+ else /* default combination */
+ s3_src_reg = QPNP_PON_S3_SRC_KPDPWR_AND_RESIN;
+
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_S3_SRC(pon->base),
+ QPNP_PON_S3_SRC_MASK, s3_src_reg);
+ if (rc) {
+ dev_err(&spmi->dev,
+ "Unable to program s3 source\n");
+ return rc;
+ }
+
dev_set_drvdata(&spmi->dev, pon);
INIT_DELAYED_WORK(&pon->bark_work, bark_work_func);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 2559ff9..a0d9a24 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -130,6 +130,7 @@
struct bms_irq {
unsigned int irq;
unsigned long disabled;
+ bool ready;
};
struct bms_wakeup_source {
@@ -393,7 +394,7 @@
static void enable_bms_irq(struct bms_irq *irq)
{
- if (__test_and_clear_bit(0, &irq->disabled)) {
+ if (irq->ready && __test_and_clear_bit(0, &irq->disabled)) {
enable_irq(irq->irq);
pr_debug("enabled irq %d\n", irq->irq);
}
@@ -401,7 +402,7 @@
static void disable_bms_irq(struct bms_irq *irq)
{
- if (!__test_and_set_bit(0, &irq->disabled)) {
+ if (irq->ready && !__test_and_set_bit(0, &irq->disabled)) {
disable_irq(irq->irq);
pr_debug("disabled irq %d\n", irq->irq);
}
@@ -409,7 +410,7 @@
static void disable_bms_irq_nosync(struct bms_irq *irq)
{
- if (!__test_and_set_bit(0, &irq->disabled)) {
+ if (irq->ready && !__test_and_set_bit(0, &irq->disabled)) {
disable_irq_nosync(irq->irq);
pr_debug("disabled irq %d\n", irq->irq);
}
@@ -605,12 +606,14 @@
temp_current = div_s64((vsense_uv * 1000000LL),
(int)chip->r_sense_uohm);
+ *result_ua = temp_current;
rc = qpnp_iadc_comp_result(chip->iadc_dev, &temp_current);
if (rc)
pr_debug("error compensation failed: %d\n", rc);
+ pr_debug("%d uA err compensated ibat=%llduA\n",
+ *result_ua, temp_current);
*result_ua = temp_current;
- pr_debug("err compensated ibat=%duA\n", *result_ua);
return 0;
}
@@ -3884,6 +3887,7 @@
pr_err("Unable to request " #irq_name " irq: %d\n", rc);\
return -ENXIO; \
} \
+ chip->irq_name##_irq.ready = true; \
} while (0)
static int bms_request_irqs(struct qpnp_bms_chip *chip)
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 3561788..0870202 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -114,6 +114,9 @@
#define USB_OCP_CLR 0x53
#define BAT_IF_TEMP_STATUS 0x09
#define BOOST_ILIM 0x78
+#define USB_SPARE 0xDF
+#define DC_COMP_OVR1 0xE9
+#define CHGR_COMP_OVR1 0xEE
#define REG_OFFSET_PERP_SUBTYPE 0x05
@@ -318,6 +321,8 @@
bool ibat_calibration_enabled;
bool aicl_settled;
bool use_external_rsense;
+ bool fastchg_on;
+ bool parallel_ovp_mode;
unsigned int bpd_detection;
unsigned int max_bat_chg_current;
unsigned int warm_bat_chg_ma;
@@ -384,6 +389,8 @@
bool power_stage_workaround_enable;
};
+static void
+qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip);
static struct of_device_id qpnp_charger_match_table[] = {
{ .compatible = QPNP_CHARGER_DEV_NAME, },
@@ -904,21 +911,21 @@
return rc;
}
-#define QPNP_CHG_VINMIN_MIN_MV 4200
+#define QPNP_CHG_VINMIN_MIN_MV 4000
#define QPNP_CHG_VINMIN_HIGH_MIN_MV 5600
#define QPNP_CHG_VINMIN_HIGH_MIN_VAL 0x2B
#define QPNP_CHG_VINMIN_MAX_MV 9600
#define QPNP_CHG_VINMIN_STEP_MV 50
#define QPNP_CHG_VINMIN_STEP_HIGH_MV 200
#define QPNP_CHG_VINMIN_MASK 0x3F
-#define QPNP_CHG_VINMIN_MIN_VAL 0x10
+#define QPNP_CHG_VINMIN_MIN_VAL 0x0C
static int
qpnp_chg_vinmin_set(struct qpnp_chg_chip *chip, int voltage)
{
u8 temp;
- if (voltage < QPNP_CHG_VINMIN_MIN_MV
- || voltage > QPNP_CHG_VINMIN_MAX_MV) {
+ if ((voltage < QPNP_CHG_VINMIN_MIN_MV)
+ || (voltage > QPNP_CHG_VINMIN_MAX_MV)) {
pr_err("bad mV=%d asked to set\n", voltage);
return -EINVAL;
}
@@ -1010,10 +1017,68 @@
return iusbmax_ma;
}
+#define ILIMIT_OVR_0 0x02
+static int
+override_dcin_ilimit(struct qpnp_chg_chip *chip, bool override)
+{
+ int rc;
+
+ pr_debug("override %d\n", override);
+ rc = qpnp_chg_masked_write(chip,
+ chip->dc_chgpth_base + SEC_ACCESS,
+ 0xA5,
+ 0xA5, 1);
+ rc |= qpnp_chg_masked_write(chip,
+ chip->dc_chgpth_base + DC_COMP_OVR1,
+ 0xFF,
+ override ? ILIMIT_OVR_0 : 0, 1);
+ if (rc) {
+ pr_err("Failed to override dc ilimit rc = %d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+#define DUAL_PATH_EN BIT(7)
+static int
+switch_parallel_ovp_mode(struct qpnp_chg_chip *chip, bool enable)
+{
+ int rc = 0;
+
+ if (!chip->usb_chgpth_base || !chip->dc_chgpth_base)
+ return rc;
+
+ pr_debug("enable %d\n", enable);
+ rc = override_dcin_ilimit(chip, 1);
+ udelay(10);
+
+ /* enable/disable dual path mode */
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + SEC_ACCESS,
+ 0xA5,
+ 0xA5, 1);
+ rc |= qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + USB_SPARE,
+ 0xFF,
+ enable ? DUAL_PATH_EN : 0, 1);
+ if (rc) {
+ pr_err("Failed to turn on usb ovp rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = override_dcin_ilimit(chip, 0);
+ return rc;
+}
+
#define USB_SUSPEND_BIT BIT(0)
static int
qpnp_chg_usb_suspend_enable(struct qpnp_chg_chip *chip, int enable)
{
+ /* Turn off DC OVP FET when going into USB suspend */
+ if (chip->parallel_ovp_mode && enable)
+ switch_parallel_ovp_mode(chip, 0);
+
return qpnp_chg_masked_write(chip,
chip->usb_chgpth_base + CHGR_USB_USB_SUSP,
USB_SUSPEND_BIT,
@@ -1779,43 +1844,96 @@
return IRQ_HANDLED;
}
-static irqreturn_t
-qpnp_chg_chgr_chg_fastchg_irq_handler(int irq, void *_chip)
+static int qpnp_chg_is_fastchg_on(struct qpnp_chg_chip *chip)
{
- struct qpnp_chg_chip *chip = _chip;
u8 chgr_sts;
int rc;
qpnp_chg_irq_wake_disable(&chip->chg_fastchg);
rc = qpnp_chg_read(chip, &chgr_sts, INT_RT_STS(chip->chgr_base), 1);
- if (rc)
- pr_err("failed to read interrupt sts %d\n", rc);
+ if (rc) {
+ pr_err("failed to read interrupt status %d\n", rc);
+ return rc;
+ }
+ pr_debug("chgr_sts 0x%x\n", chgr_sts);
+ return (chgr_sts & FAST_CHG_ON_IRQ) ? 1 : 0;
+}
- pr_debug("FAST_CHG IRQ triggered\n");
- chip->chg_done = false;
- if (chip->bat_if_base) {
- pr_debug("psy changed batt_psy\n");
- power_supply_changed(&chip->batt_psy);
+#define VBATDET_BYPASS 0x01
+static int
+bypass_vbatdet_comp(struct qpnp_chg_chip *chip, bool bypass)
+{
+ int rc;
+
+ pr_debug("bypass %d\n", bypass);
+ rc = qpnp_chg_masked_write(chip,
+ chip->chgr_base + SEC_ACCESS,
+ 0xA5,
+ 0xA5, 1);
+ rc |= qpnp_chg_masked_write(chip,
+ chip->chgr_base + CHGR_COMP_OVR1,
+ 0xFF,
+ bypass ? VBATDET_BYPASS : 0, 1);
+ if (rc) {
+ pr_err("Failed to bypass vbatdet comp rc = %d\n", rc);
+ return rc;
}
- pr_debug("psy changed usb_psy\n");
- power_supply_changed(chip->usb_psy);
+ return rc;
+}
- if (chip->dc_chgpth_base) {
- pr_debug("psy changed dc_psy\n");
- power_supply_changed(&chip->dc_psy);
- }
+static irqreturn_t
+qpnp_chg_chgr_chg_fastchg_irq_handler(int irq, void *_chip)
+{
+ struct qpnp_chg_chip *chip = _chip;
+ bool fastchg_on = false;
- if (chip->resuming_charging) {
- chip->resuming_charging = false;
- qpnp_chg_set_appropriate_vbatdet(chip);
- }
+ fastchg_on = qpnp_chg_is_fastchg_on(chip);
- if (!chip->charging_disabled) {
- schedule_delayed_work(&chip->eoc_work,
- msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
- pm_stay_awake(chip->dev);
+ pr_debug("FAST_CHG IRQ triggered, fastchg_on: %d\n", fastchg_on);
+
+ if (chip->fastchg_on ^ fastchg_on) {
+ chip->fastchg_on = fastchg_on;
+ if (chip->bat_if_base) {
+ pr_debug("psy changed batt_psy\n");
+ power_supply_changed(&chip->batt_psy);
+ }
+
+ pr_debug("psy changed usb_psy\n");
+ power_supply_changed(chip->usb_psy);
+
+ if (chip->dc_chgpth_base) {
+ pr_debug("psy changed dc_psy\n");
+ power_supply_changed(&chip->dc_psy);
+ }
+
+ if (fastchg_on) {
+ chip->chg_done = false;
+ bypass_vbatdet_comp(chip, 1);
+ if (chip->bat_is_warm || chip->bat_is_cool) {
+ qpnp_chg_set_appropriate_vddmax(chip);
+ qpnp_chg_set_appropriate_battery_current(chip);
+ }
+
+ if (chip->resuming_charging) {
+ chip->resuming_charging = false;
+ qpnp_chg_set_appropriate_vbatdet(chip);
+ }
+
+ if (!chip->charging_disabled) {
+ schedule_delayed_work(&chip->eoc_work,
+ msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ pm_stay_awake(chip->dev);
+ }
+ if (chip->parallel_ovp_mode)
+ switch_parallel_ovp_mode(chip, 1);
+ } else {
+ if (chip->parallel_ovp_mode)
+ switch_parallel_ovp_mode(chip, 0);
+ if (!chip->bat_is_warm && !chip->bat_is_cool)
+ bypass_vbatdet_comp(chip, 0);
+ }
}
qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
@@ -1931,6 +2049,9 @@
if (qpnp_chg_is_otg_en_set(chip))
return 0;
+ if (chip->parallel_ovp_mode)
+ switch_parallel_ovp_mode(chip, 0);
+
if (chip->type == SMBBP) {
rc = qpnp_chg_masked_write(chip,
chip->boost_base + BOOST_ILIM,
@@ -2340,7 +2461,7 @@
pr_debug("Unable to read batt temperature rc=%d\n", rc);
return 0;
}
- pr_debug("get_bat_temp %d %lld\n",
+ pr_debug("get_bat_temp %d, %lld\n",
results.adc_code, results.physical);
return (int)results.physical;
@@ -2682,6 +2803,25 @@
return 0;
}
+static void
+qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
+{
+ unsigned int chg_current = chip->max_bat_chg_current;
+
+ if (chip->bat_is_cool)
+ chg_current = min(chg_current, chip->cool_bat_chg_ma);
+
+ if (chip->bat_is_warm)
+ chg_current = min(chg_current, chip->warm_bat_chg_ma);
+
+ if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation)
+ chg_current = min(chg_current,
+ chip->thermal_mitigation[chip->therm_lvl_sel]);
+
+ pr_debug("setting %d mA\n", chg_current);
+ qpnp_chg_ibatmax_set(chip, chg_current);
+}
+
static int
qpnp_chg_vddsafe_set(struct qpnp_chg_chip *chip, int voltage)
{
@@ -2890,25 +3030,6 @@
}
static void
-qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
-{
- unsigned int chg_current = chip->max_bat_chg_current;
-
- if (chip->bat_is_cool)
- chg_current = min(chg_current, chip->cool_bat_chg_ma);
-
- if (chip->bat_is_warm)
- chg_current = min(chg_current, chip->warm_bat_chg_ma);
-
- if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation)
- chg_current = min(chg_current,
- chip->thermal_mitigation[chip->therm_lvl_sel]);
-
- pr_debug("setting %d mA\n", chg_current);
- qpnp_chg_ibatmax_set(chip, chg_current);
-}
-
-static void
qpnp_batt_system_temp_level_set(struct qpnp_chg_chip *chip, int lvl_sel)
{
if (lvl_sel >= 0 && lvl_sel < chip->thermal_levels) {
@@ -3437,7 +3558,7 @@
state == ADC_TM_WARM_STATE ? "warm" : "cool");
if (state == ADC_TM_WARM_STATE) {
- if (temp > chip->warm_bat_decidegc) {
+ if (temp >= chip->warm_bat_decidegc) {
/* Normal to warm */
bat_warm = true;
bat_cool = false;
@@ -3445,7 +3566,7 @@
chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC;
chip->adc_param.state_request =
ADC_TM_COOL_THR_ENABLE;
- } else if (temp >
+ } else if (temp >=
chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC){
/* Cool to normal */
bat_warm = false;
@@ -3457,7 +3578,7 @@
ADC_TM_HIGH_LOW_THR_ENABLE;
}
} else {
- if (temp < chip->cool_bat_decidegc) {
+ if (temp <= chip->cool_bat_decidegc) {
/* Normal to cool */
bat_warm = false;
bat_cool = true;
@@ -3465,7 +3586,7 @@
chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC;
chip->adc_param.state_request =
ADC_TM_WARM_THR_ENABLE;
- } else if (temp <
+ } else if (temp <=
chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC){
/* Warm to normal */
bat_warm = false;
@@ -3482,9 +3603,6 @@
chip->bat_is_cool = bat_cool;
chip->bat_is_warm = bat_warm;
- if (bat_cool || bat_warm)
- chip->resuming_charging = false;
-
/**
* set appropriate voltages and currents.
*
@@ -3492,9 +3610,25 @@
* driver will not resume with SoC. Only vbatdet is used to
* determine resume of charging.
*/
- qpnp_chg_set_appropriate_vddmax(chip);
- qpnp_chg_set_appropriate_battery_current(chip);
- qpnp_chg_set_appropriate_vbatdet(chip);
+ if (bat_cool || bat_warm) {
+ chip->resuming_charging = false;
+ qpnp_chg_set_appropriate_vbatdet(chip);
+
+ /* To avoid ARB, only vbatdet is configured in
+ * warm/cold zones. Once vbat < vbatdet the
+ * appropriate vddmax/ibatmax adjustments will
+ * be made in the fast charge interrupt. */
+ bypass_vbatdet_comp(chip, 1);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ qpnp_chg_charge_en(chip, chip->charging_disabled);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ } else {
+ bypass_vbatdet_comp(chip, 0);
+ /* restore normal parameters */
+ qpnp_chg_set_appropriate_vbatdet(chip);
+ qpnp_chg_set_appropriate_vddmax(chip);
+ qpnp_chg_set_appropriate_battery_current(chip);
+ }
}
pr_debug("warm %d, cool %d, low = %d deciDegC, high = %d deciDegC\n",
@@ -3977,7 +4111,8 @@
rc |= devm_request_irq(chip->dev, chip->chg_fastchg.irq,
qpnp_chg_chgr_chg_fastchg_irq_handler,
- IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
"fast-chg-on", chip);
if (rc < 0) {
pr_err("Can't request %d fast-chg-on: %d\n",
@@ -4623,6 +4758,9 @@
chip->ibat_calibration_enabled =
of_property_read_bool(chip->spmi->dev.of_node,
"qcom,ibat-calibration-enabled");
+ chip->parallel_ovp_mode =
+ of_property_read_bool(chip->spmi->dev.of_node,
+ "qcom,parallel-ovp-mode");
of_get_property(chip->spmi->dev.of_node, "qcom,thermal-mitigation",
&(chip->thermal_levels));
diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c
index bfbae78..d64b577 100644
--- a/drivers/rtc/qpnp-rtc.c
+++ b/drivers/rtc/qpnp-rtc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-13, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -102,6 +102,7 @@
int rc;
unsigned long secs, irq_flags;
u8 value[4], reg = 0, alarm_enabled = 0, ctrl_reg;
+ u8 rtc_disabled = 0, rtc_ctrl_reg;
struct qpnp_rtc *rtc_dd = dev_get_drvdata(dev);
rtc_tm_to_time(tm, &secs);
@@ -152,6 +153,22 @@
* write operation
*/
+ /* Disable RTC H/w before writing on RTC register*/
+ rtc_ctrl_reg = rtc_dd->rtc_ctrl_reg;
+ if (rtc_ctrl_reg & BIT_RTC_ENABLE) {
+ rtc_disabled = 1;
+ rtc_ctrl_reg &= ~BIT_RTC_ENABLE;
+ rc = qpnp_write_wrapper(rtc_dd, &rtc_ctrl_reg,
+ rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1);
+ if (rc) {
+ dev_err(dev,
+ "Disabling of RTC control reg failed"
+ " with error:%d\n", rc);
+ goto rtc_rw_fail;
+ }
+ rtc_dd->rtc_ctrl_reg = rtc_ctrl_reg;
+ }
+
/* Clear WDATA[0] */
reg = 0x0;
rc = qpnp_write_wrapper(rtc_dd, ®,
@@ -177,6 +194,20 @@
goto rtc_rw_fail;
}
+ /* Enable RTC H/w after writing on RTC register*/
+ if (rtc_disabled) {
+ rtc_ctrl_reg |= BIT_RTC_ENABLE;
+ rc = qpnp_write_wrapper(rtc_dd, &rtc_ctrl_reg,
+ rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1);
+ if (rc) {
+ dev_err(dev,
+ "Enabling of RTC control reg failed"
+ " with error:%d\n", rc);
+ goto rtc_rw_fail;
+ }
+ rtc_dd->rtc_ctrl_reg = rtc_ctrl_reg;
+ }
+
if (alarm_enabled) {
ctrl_reg |= BIT_RTC_ALARM_ENABLE;
rc = qpnp_write_wrapper(rtc_dd, &ctrl_reg,
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 6e7a815..c662a2b 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -345,10 +345,12 @@
*/
if (!(txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG))
msgv = msm_slim_get_ctrl(dev);
+ if (msgv >= 0)
+ dev->state = MSM_CTRL_AWAKE;
mutex_lock(&dev->tx_lock);
if (dev->state == MSM_CTRL_ASLEEP ||
((!(txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)) &&
- dev->state == MSM_CTRL_SLEEPING)) {
+ dev->state == MSM_CTRL_IDLE)) {
dev_err(dev->dev, "runtime or system PM suspended state");
mutex_unlock(&dev->tx_lock);
if (msgv >= 0)
@@ -1452,6 +1454,10 @@
#ifdef CONFIG_PM_RUNTIME
static int msm_slim_runtime_idle(struct device *device)
{
+ struct platform_device *pdev = to_platform_device(device);
+ struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+ if (dev->state == MSM_CTRL_AWAKE)
+ dev->state = MSM_CTRL_IDLE;
dev_dbg(device, "pm_runtime: idle...\n");
pm_request_autosuspend(device);
return -EAGAIN;
@@ -1470,7 +1476,6 @@
struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
int ret;
dev_dbg(device, "pm_runtime: suspending...\n");
- dev->state = MSM_CTRL_SLEEPING;
ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
if (ret) {
dev_err(device, "clk pause not entered:%d", ret);
@@ -1500,10 +1505,12 @@
static int msm_slim_suspend(struct device *dev)
{
- int ret = 0;
- if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
- struct platform_device *pdev = to_platform_device(dev);
- struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
+ int ret = -EBUSY;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
+ if (!pm_runtime_enabled(dev) ||
+ (!pm_runtime_suspended(dev) &&
+ cdev->state == MSM_CTRL_IDLE)) {
dev_dbg(dev, "system suspend");
ret = msm_slim_runtime_suspend(dev);
if (!ret) {
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index e65c8cf..0f8f1dd 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -83,6 +83,7 @@
};
static int ngd_slim_runtime_resume(struct device *device);
+static int ngd_slim_power_up(struct msm_slim_ctrl *dev);
static irqreturn_t ngd_slim_interrupt(int irq, void *d)
{
@@ -91,25 +92,25 @@
u32 stat = readl_relaxed(ngd + NGD_INT_STAT);
u32 pstat;
- if (stat & NGD_INT_TX_MSG_SENT) {
+ if ((stat & NGD_INT_MSG_BUF_CONTE) ||
+ (stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
+ (stat & NGD_INT_TX_NACKED_2)) {
+ writel_relaxed(stat, ngd + NGD_INT_CLR);
+ dev->err = -EIO;
+
+ dev_err(dev->dev, "NGD interrupt error:0x%x, err:%d", stat,
+ dev->err);
+ /* Guarantee that error interrupts are cleared */
+ mb();
+ if (dev->wr_comp)
+ complete(dev->wr_comp);
+
+ } else if (stat & NGD_INT_TX_MSG_SENT) {
writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
/* Make sure interrupt is cleared */
mb();
if (dev->wr_comp)
complete(dev->wr_comp);
- } else if ((stat & NGD_INT_MSG_BUF_CONTE) ||
- (stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
- (stat & NGD_INT_TX_NACKED_2)) {
- dev_err(dev->dev, "NGD interrupt error:0x%x", stat);
- writel_relaxed(stat, ngd + NGD_INT_CLR);
- /* Guarantee that error interrupts are cleared */
- mb();
- if (((stat & NGD_INT_TX_NACKED_2) ||
- (stat & NGD_INT_MSG_TX_INVAL))) {
- dev->err = -EIO;
- if (dev->wr_comp)
- complete(dev->wr_comp);
- }
}
if (stat & NGD_INT_RX_MSG_RCVD) {
u32 rx_buf[10];
@@ -180,6 +181,41 @@
return 0;
}
+static int mdm_ssr_notify_cb(struct notifier_block *n, unsigned long code,
+ void *_cmd)
+{
+ struct msm_slim_mdm *mdm = container_of(n, struct msm_slim_mdm, nb);
+ struct msm_slim_ctrl *dev = container_of(mdm, struct msm_slim_ctrl,
+ mdm);
+ int ret;
+
+ switch (code) {
+ case SUBSYS_BEFORE_SHUTDOWN:
+ /* make sure runtime-pm doesn't suspend during modem SSR */
+ pm_runtime_get_noresume(dev->dev);
+ break;
+ case SUBSYS_AFTER_POWERUP:
+ ret = msm_slim_qmi_check_framer_request(dev);
+ dev_err(dev->dev,
+ "%s:SLIM %lu external_modem SSR notify cb, ret %d",
+ __func__, code, ret);
+ /*
+ * Next codec transaction will reinit the HW
+ * if it was suspended
+ */
+ if (pm_runtime_suspended(dev->dev) ||
+ dev->state >= MSM_CTRL_ASLEEP) {
+ break;
+ } else {
+ ngd_slim_power_up(dev);
+ msm_slim_put_ctrl(dev);
+ }
+ default:
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
static int ngd_get_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn,
u8 *tid, struct completion *done)
{
@@ -229,9 +265,13 @@
u8 txn_mt;
u16 txn_mc = txn->mc;
u8 wbuf[SLIM_MSGQ_BUF_LEN];
+ bool report_sat = false;
+ if (txn->mc == SLIM_USR_MC_REPORT_SATELLITE &&
+ txn->mt == SLIM_MSG_MT_SRC_REFERRED_USER)
+ report_sat = true;
if (!pm_runtime_enabled(dev->dev) && dev->state == MSM_CTRL_ASLEEP &&
- txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
+ report_sat == false) {
/*
* Counter-part of system-suspend when runtime-pm is not enabled
* This way, resume can be left empty and device will be put in
@@ -243,7 +283,7 @@
}
if ((txn->mc == (SLIM_MSG_CLK_PAUSE_SEQ_FLG |
SLIM_MSG_MC_RECONFIGURE_NOW)) &&
- dev->state <= MSM_CTRL_SLEEPING) {
+ dev->state <= MSM_CTRL_IDLE) {
msm_slim_disconnect_endp(dev, &dev->rx_msgq,
&dev->use_rx_msgqs);
msm_slim_disconnect_endp(dev, &dev->tx_msgq,
@@ -259,7 +299,7 @@
return 0;
}
/* If txn is tried when controller is down, wait for ADSP to boot */
- if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE) {
+ if (!report_sat) {
if (dev->state == MSM_CTRL_DOWN) {
u8 mc = (u8)txn->mc;
int timeout;
@@ -305,12 +345,24 @@
if (!timeout && dev->state == MSM_CTRL_DOWN)
return -ETIMEDOUT;
}
- msm_slim_get_ctrl(dev);
+ ret = msm_slim_get_ctrl(dev);
+ /*
+ * Runtime-pm's callbacks are not called until runtime-pm's
+ * error status is cleared
+ * Setting runtime status to suspended clears the error
+ * It also makes HW status cosistent with what SW has it here
+ */
+ if (ret == -ENETRESET && dev->state == MSM_CTRL_DOWN) {
+ pm_runtime_set_suspended(dev->dev);
+ msm_slim_put_ctrl(dev);
+ return -EREMOTEIO;
+ } else if (ret >= 0) {
+ dev->state = MSM_CTRL_AWAKE;
+ }
}
mutex_lock(&dev->tx_lock);
- if (txn->mc != SLIM_USR_MC_REPORT_SATELLITE &&
- (dev->state != MSM_CTRL_AWAKE)) {
+ if (report_sat == false && dev->state != MSM_CTRL_AWAKE) {
dev_err(dev->dev, "controller not ready");
mutex_unlock(&dev->tx_lock);
msm_slim_put_ctrl(dev);
@@ -387,11 +439,13 @@
puc = ((u8 *)pbuf) + 2;
if (txn->rbuf)
*(puc++) = txn->tid;
- if ((txn->mt == SLIM_MSG_MT_CORE) &&
+ if (((txn->mt == SLIM_MSG_MT_CORE) &&
((txn->mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
txn->mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
(txn->mc >= SLIM_MSG_MC_REQUEST_VALUE &&
- txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) {
+ txn->mc <= SLIM_MSG_MC_CHANGE_VALUE))) ||
+ (txn->mc == SLIM_USR_MC_REPEAT_CHANGE_VALUE &&
+ txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER)) {
*(puc++) = (txn->ec & 0xFF);
*(puc++) = (txn->ec >> 8)&0xFF;
}
@@ -491,11 +545,49 @@
}
ngd_xfer_err:
mutex_unlock(&dev->tx_lock);
- if (txn_mc != SLIM_USR_MC_REPORT_SATELLITE)
+ if (!report_sat)
msm_slim_put_ctrl(dev);
return ret ? ret : dev->err;
}
+static int ngd_user_msg(struct slim_controller *ctrl, u8 la, u8 mt, u8 mc,
+ struct slim_ele_access *msg, u8 *buf, u8 len)
+{
+ struct slim_msg_txn txn;
+
+ if (mt != SLIM_MSG_MT_DEST_REFERRED_USER ||
+ mc != SLIM_USR_MC_REPEAT_CHANGE_VALUE) {
+ return -EPROTONOSUPPORT;
+ }
+ if (len > SLIM_MAX_VE_SLC_BYTES ||
+ msg->start_offset > MSM_SLIM_VE_MAX_MAP_ADDR)
+ return -EINVAL;
+ if (len <= 4) {
+ txn.ec = len - 1;
+ } else if (len <= 8) {
+ if (len & 0x1)
+ return -EINVAL;
+ txn.ec = ((len >> 1) + 1);
+ } else {
+ if (len & 0x3)
+ return -EINVAL;
+ txn.ec = ((len >> 2) + 3);
+ }
+ txn.ec |= (0x8 | ((msg->start_offset & 0xF) << 4));
+ txn.ec |= ((msg->start_offset & 0xFF0) << 4);
+
+ txn.la = la;
+ txn.mt = mt;
+ txn.mc = mc;
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.len = len;
+ txn.rl = len + 6;
+ txn.wbuf = buf;
+ txn.rbuf = NULL;
+ txn.comp = msg->comp;
+ return ngd_xfer_msg(ctrl, &txn);
+}
+
static int ngd_xferandwait_ack(struct slim_controller *ctrl,
struct slim_msg_txn *txn)
{
@@ -507,17 +599,12 @@
ret = -ETIMEDOUT;
else
ret = txn->ec;
- } else if (ret == -EREMOTEIO &&
- (txn->mc == SLIM_USR_MC_CHAN_CTRL ||
- txn->mc == SLIM_USR_MC_DISCONNECT_PORT)) {
- /* HW restarting, channel/port removal should succeed */
- return 0;
}
if (ret) {
- pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
+ if (ret != -EREMOTEIO || txn->mc != SLIM_USR_MC_CHAN_CTRL)
+ pr_err("master msg:0x%x,tid:%d ret:%d", txn->mc,
txn->tid, ret);
- WARN(1, "timeout during xfer and wait");
mutex_lock(&ctrl->m_ctrl);
ctrl->txnt[txn->tid] = NULL;
mutex_unlock(&ctrl->m_ctrl);
@@ -642,7 +729,10 @@
txn.mc = SLIM_USR_MC_CHAN_CTRL;
txn.rl = txn.len + 4;
ret = ngd_xferandwait_ack(ctrl, &txn);
- if (ret)
+ /* HW restarting, channel removal should succeed */
+ if (ret == -EREMOTEIO)
+ return 0;
+ else if (ret)
return ret;
txn.mc = SLIM_USR_MC_RECONFIG_NOW;
@@ -758,6 +848,7 @@
ret = ngd_xfer_msg(&dev->ctrl, &txn);
if (!ret) {
enum msm_ctrl_state prev_state = dev->state;
+ pr_info("SLIM SAT: capability exchange successful");
dev->state = MSM_CTRL_AWAKE;
if (prev_state >= MSM_CTRL_ASLEEP)
complete(&dev->reconf);
@@ -829,7 +920,7 @@
static int ngd_slim_power_up(struct msm_slim_ctrl *dev)
{
void __iomem *ngd;
- int timeout, ret;
+ int timeout, ret = 0;
enum msm_ctrl_state cur_state = dev->state;
u32 laddr;
u32 ngd_int = (NGD_INT_TX_NACKED_2 |
@@ -844,10 +935,13 @@
pr_err("slimbus QMI init timed out");
}
- ret = msm_slim_qmi_power_request(dev, true);
- if (ret) {
- pr_err("SLIM QMI power request failed:%d", ret);
- return ret;
+ /* No need to vote if contorller is not in low power mode */
+ if (cur_state == MSM_CTRL_DOWN || cur_state == MSM_CTRL_ASLEEP) {
+ ret = msm_slim_qmi_power_request(dev, true);
+ if (ret) {
+ pr_err("SLIM QMI power request failed:%d", ret);
+ return ret;
+ }
}
if (!dev->ver) {
dev->ver = readl_relaxed(dev->base);
@@ -858,14 +952,35 @@
laddr = readl_relaxed(ngd + NGD_STATUS);
if (laddr & NGD_LADDR) {
/*
+ * external MDM restart case where ADSP itself was active framer
+ * For example, modem restarted when playback was active
+ */
+ if (cur_state == MSM_CTRL_AWAKE) {
+ pr_err("SLIM MDM restart: ADSP active framer:NO OP");
+ return 0;
+ }
+ /*
* ADSP power collapse case, where HW wasn't reset.
* Reconnect BAM pipes if disconnected
*/
ngd_slim_setup_msg_path(dev);
return 0;
- } else if (cur_state != MSM_CTRL_DOWN) {
- pr_info("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
+ } else if (cur_state == MSM_CTRL_ASLEEP) {
+ pr_debug("ADSP P.C. CTRL state:%d NGD not enumerated:0x%x",
dev->state, laddr);
+ } else if (cur_state == MSM_CTRL_IDLE || cur_state == MSM_CTRL_AWAKE) {
+ /*
+ * external MDM SSR when only voice call is in progress.
+ * ADSP will reset slimbus HW. disconnect BAM pipes so that
+ * they can be connected after capability message is received.
+ * Set device state to ASLEEP to be synchronous with the HW
+ */
+ pr_err("SLIM MDM restart: MDM active framer: reinit HW");
+ dev->state = MSM_CTRL_ASLEEP;
+ msm_slim_disconnect_endp(dev, &dev->rx_msgq,
+ &dev->use_rx_msgqs);
+ msm_slim_disconnect_endp(dev, &dev->tx_msgq,
+ &dev->use_tx_msgqs);
}
/* ADSP SSR scenario, need to disconnect pipe before connecting */
if (dev->use_rx_msgqs == MSM_MSGQ_DOWN) {
@@ -896,7 +1011,7 @@
timeout = wait_for_completion_timeout(&dev->reconf, HZ);
if (!timeout) {
- pr_err("failed to received master capability");
+ pr_err("Failed to receive master capability");
return -ETIMEDOUT;
}
if (cur_state == MSM_CTRL_DOWN)
@@ -999,11 +1114,13 @@
container_of(work, struct msm_slim_ctrl, slave_notify);
struct slim_controller *ctrl = &dev->ctrl;
struct slim_device *sbdev;
+ struct list_head *pos, *next;
int i;
slim_framer_booted(ctrl);
mutex_lock(&ctrl->m_ctrl);
- list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
+ list_for_each_safe(pos, next, &ctrl->devs) {
int ret = 0;
+ sbdev = list_entry(pos, struct slim_device, dev_list);
mutex_unlock(&ctrl->m_ctrl);
for (i = 0; i < LADDR_RETRY; i++) {
ret = slim_get_logical_addr(sbdev, sbdev->e_addr,
@@ -1058,6 +1175,7 @@
struct resource *irq, *bam_irq;
enum apr_subsys_state q6_state;
bool rxreg_access = false;
+ bool slim_mdm = false;
q6_state = apr_get_q6_state();
if (q6_state == APR_SUBSYS_DOWN) {
@@ -1126,6 +1244,8 @@
&dev->pdata.apps_pipes);
of_property_read_u32(pdev->dev.of_node, "qcom,ea-pc",
&dev->pdata.eapc);
+ slim_mdm = of_property_read_bool(pdev->dev.of_node,
+ "qcom,slim-mdm");
} else {
dev->ctrl.nr = pdev->id;
}
@@ -1145,6 +1265,7 @@
dev->ctrl.get_laddr = ngd_get_laddr;
dev->ctrl.allocbw = ngd_allocbw;
dev->ctrl.xfer_msg = ngd_xfer_msg;
+ dev->ctrl.xfer_user_msg = ngd_user_msg;
dev->ctrl.wakeup = ngd_clk_pause_wakeup;
dev->ctrl.alloc_port = msm_alloc_port;
dev->ctrl.dealloc_port = msm_dealloc_port;
@@ -1195,12 +1316,23 @@
pm_runtime_set_suspended(dev->dev);
pm_runtime_enable(dev->dev);
+ if (slim_mdm) {
+ dev->mdm.nb.notifier_call = mdm_ssr_notify_cb;
+ dev->mdm.ssr = subsys_notif_register_notifier("external_modem",
+ &dev->mdm.nb);
+ if (IS_ERR_OR_NULL(dev->mdm.ssr))
+ dev_err(dev->dev,
+ "subsys_notif_register_notifier failed %p",
+ dev->mdm.ssr);
+ }
+
INIT_WORK(&dev->slave_notify, ngd_laddr_lookup);
INIT_WORK(&dev->qmi.ssr_down, ngd_adsp_down);
INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
dev->qmi.nb.notifier_call = ngd_qmi_available;
pm_runtime_get_noresume(dev->dev);
ret = qmi_svc_event_notifier_register(SLIMBUS_QMI_SVC_ID,
+ SLIMBUS_QMI_SVC_V1,
SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
if (ret) {
pr_err("Slimbus QMI service registration failed:%d", ret);
@@ -1228,6 +1360,7 @@
err_thread_create_failed:
qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
+ SLIMBUS_QMI_SVC_V1,
SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
qmi_register_failed:
free_irq(dev->irq, dev);
@@ -1247,8 +1380,11 @@
struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
ngd_slim_enable(dev, false);
qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
+ SLIMBUS_QMI_SVC_V1,
SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
pm_runtime_disable(&pdev->dev);
+ if (!IS_ERR_OR_NULL(dev->mdm.ssr))
+ subsys_notif_unregister_notifier(dev->mdm.ssr, &dev->mdm.nb);
free_irq(dev->irq, dev);
slim_del_controller(&dev->ctrl);
kthread_stop(dev->rx_msgq_thread);
@@ -1261,6 +1397,10 @@
#ifdef CONFIG_PM_RUNTIME
static int ngd_slim_runtime_idle(struct device *device)
{
+ struct platform_device *pdev = to_platform_device(device);
+ struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
+ if (dev->state == MSM_CTRL_AWAKE)
+ dev->state = MSM_CTRL_IDLE;
dev_dbg(device, "pm_runtime: idle...\n");
pm_request_autosuspend(device);
return -EAGAIN;
@@ -1280,8 +1420,11 @@
if (dev->state >= MSM_CTRL_ASLEEP)
ret = slim_ctrl_clk_pause(&dev->ctrl, true, 0);
if (ret) {
- dev_err(device, "clk pause not exited:%d", ret);
- dev->state = MSM_CTRL_ASLEEP;
+ /* Did SSR cause this clock pause failure */
+ if (dev->state != MSM_CTRL_DOWN)
+ dev->state = MSM_CTRL_ASLEEP;
+ else
+ dev_err(device, "HW wakeup attempt during SSR");
} else {
dev->state = MSM_CTRL_AWAKE;
}
@@ -1294,7 +1437,6 @@
struct platform_device *pdev = to_platform_device(device);
struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
int ret = 0;
- dev->state = MSM_CTRL_SLEEPING;
ret = slim_ctrl_clk_pause(&dev->ctrl, false, SLIM_CLK_UNSPECIFIED);
if (ret) {
if (ret != -EBUSY)
@@ -1309,7 +1451,11 @@
static int ngd_slim_suspend(struct device *dev)
{
int ret = -EBUSY;
- if (!pm_runtime_enabled(dev) || !pm_runtime_suspended(dev)) {
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_slim_ctrl *cdev = platform_get_drvdata(pdev);
+ if (!pm_runtime_enabled(dev) ||
+ (!pm_runtime_suspended(dev) &&
+ cdev->state == MSM_CTRL_IDLE)) {
dev_dbg(dev, "system suspend");
ret = ngd_slim_runtime_suspend(dev);
/*
diff --git a/drivers/slimbus/slim-msm.c b/drivers/slimbus/slim-msm.c
index 37bc883..8589b9f 100644
--- a/drivers/slimbus/slim-msm.c
+++ b/drivers/slimbus/slim-msm.c
@@ -69,7 +69,7 @@
if (ref <= 0)
dev_err(dev->dev, "reference count mismatch:%d", ref);
else
- pm_runtime_put(dev->dev);
+ pm_runtime_put_sync(dev->dev);
#endif
}
@@ -305,7 +305,7 @@
}
enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
- u8 pn, u8 **done_buf, u32 *done_len)
+ u8 pn, phys_addr_t *done_buf, u32 *done_len)
{
struct msm_slim_ctrl *dev = slim_get_ctrldata(ctr);
struct sps_iovec sio;
@@ -313,7 +313,7 @@
if (done_len)
*done_len = 0;
if (done_buf)
- *done_buf = NULL;
+ *done_buf = 0;
if (!dev->pipes[pn].connected)
return SLIM_P_DISCONNECT;
ret = sps_get_iovec(dev->pipes[pn].sps, &sio);
@@ -321,7 +321,7 @@
if (done_len)
*done_len = sio.size;
if (done_buf)
- *done_buf = (u8 *)sio.addr;
+ *done_buf = (phys_addr_t)sio.addr;
}
dev_dbg(dev->dev, "get iovec returned %d\n", ret);
return SLIM_P_INPROGRESS;
@@ -346,7 +346,7 @@
complete(comp);
}
-int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, u8 *iobuf,
+int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
u32 len, struct completion *comp)
{
struct sps_register_event sreg;
@@ -366,7 +366,7 @@
dev_dbg(dev->dev, "sps register event error:%x\n", ret);
return ret;
}
- ret = sps_transfer_one(dev->pipes[pn].sps, (u32)iobuf, len, comp,
+ ret = sps_transfer_one(dev->pipes[pn].sps, iobuf, len, comp,
SPS_IOVEC_FLAG_INT);
dev_dbg(dev->dev, "sps submit xfer error code:%x\n", ret);
if (!ret) {
@@ -392,7 +392,7 @@
struct sps_pipe *pipe = endpoint->sps;
int ix = (buf - (u8 *)mem->base) / SLIM_MSGQ_BUF_LEN;
- u32 phys_addr = mem->phys_base + (SLIM_MSGQ_BUF_LEN * ix);
+ phys_addr_t phys_addr = mem->phys_base + (SLIM_MSGQ_BUF_LEN * ix);
for (ret = 0; ret < ((len + 3) >> 2); ret++)
pr_debug("BAM TX buf[%d]:0x%x", ret, ((u32 *)buf)[ret]);
@@ -425,7 +425,7 @@
}
/* Calculate buffer index */
- dev->tx_idx = (iovec.addr - mem->phys_base) / SLIM_MSGQ_BUF_LEN;
+ dev->tx_idx = ((int)(iovec.addr - mem->phys_base)) / SLIM_MSGQ_BUF_LEN;
return (u32 *)((u8 *)mem->base + (dev->tx_idx * SLIM_MSGQ_BUF_LEN));
}
@@ -500,9 +500,9 @@
/* Rx message queue buffers are 4 bytes in length */
u8 *virt_addr = mem->base + (4 * ix);
- u32 phys_addr = mem->phys_base + (4 * ix);
+ phys_addr_t phys_addr = mem->phys_base + (4 * ix);
- pr_debug("index:%d, phys:0x%x, virt:0x%p\n", ix, phys_addr, virt_addr);
+ pr_debug("index:%d, virt:0x%p\n", ix, virt_addr);
ret = sps_transfer_one(pipe, phys_addr, 4, virt_addr, flags);
if (ret)
@@ -884,11 +884,14 @@
#define SLIMBUS_QMI_SELECT_INSTANCE_RESP_V01 0x0020
#define SLIMBUS_QMI_POWER_REQ_V01 0x0021
#define SLIMBUS_QMI_POWER_RESP_V01 0x0021
+#define SLIMBUS_QMI_CHECK_FRAMER_STATUS_REQ 0x0022
+#define SLIMBUS_QMI_CHECK_FRAMER_STATUS_RESP 0x0022
#define SLIMBUS_QMI_POWER_REQ_MAX_MSG_LEN 7
#define SLIMBUS_QMI_POWER_RESP_MAX_MSG_LEN 7
#define SLIMBUS_QMI_SELECT_INSTANCE_REQ_MAX_MSG_LEN 14
#define SLIMBUS_QMI_SELECT_INSTANCE_RESP_MAX_MSG_LEN 7
+#define SLIMBUS_QMI_CHECK_FRAMER_STAT_RESP_MAX_MSG_LEN 7
enum slimbus_mode_enum_type_v01 {
/* To force a 32 bit signed enum. Do not change or use*/
@@ -936,6 +939,13 @@
struct qmi_response_type_v01 resp;
};
+struct slimbus_chkfrm_resp_msg {
+ /* Mandatory */
+ /* Result Code */
+ struct qmi_response_type_v01 resp;
+};
+
+
static struct elem_info slimbus_select_inst_req_msg_v01_ei[] = {
{
.data_type = QMI_UNSIGNED_4_BYTE,
@@ -1042,6 +1052,27 @@
},
};
+static struct elem_info slimbus_chkfrm_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct slimbus_chkfrm_resp_msg, resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .elem_len = 0,
+ .elem_size = 0,
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x00,
+ .offset = 0,
+ .ei_array = NULL,
+ },
+};
+
static void msm_slim_qmi_recv_msg(struct kthread_work *work)
{
int rc;
@@ -1174,6 +1205,7 @@
}
rc = qmi_connect_to_service(handle, SLIMBUS_QMI_SVC_ID,
+ SLIMBUS_QMI_SVC_V1,
SLIMBUS_QMI_INS_ID);
if (rc < 0) {
pr_err("%s: QMI server not found\n", __func__);
@@ -1231,3 +1263,32 @@
return msm_slim_qmi_send_power_request(dev, &req);
}
+
+int msm_slim_qmi_check_framer_request(struct msm_slim_ctrl *dev)
+{
+ struct slimbus_chkfrm_resp_msg resp = { { 0, 0 } };
+ struct msg_desc req_desc, resp_desc;
+ int rc;
+
+ req_desc.msg_id = SLIMBUS_QMI_CHECK_FRAMER_STATUS_REQ;
+ req_desc.max_msg_len = 0;
+ req_desc.ei_array = NULL;
+
+ resp_desc.msg_id = SLIMBUS_QMI_CHECK_FRAMER_STATUS_RESP;
+ resp_desc.max_msg_len = SLIMBUS_QMI_CHECK_FRAMER_STAT_RESP_MAX_MSG_LEN;
+ resp_desc.ei_array = slimbus_chkfrm_resp_msg_v01_ei;
+
+ rc = qmi_send_req_wait(dev->qmi.handle, &req_desc, NULL, 0,
+ &resp_desc, &resp, sizeof(resp), 5000);
+ if (rc < 0) {
+ dev_err(dev->dev, "%s: QMI send req failed %d\n", __func__, rc);
+ return rc;
+ }
+ /* Check the response */
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ dev_err(dev->dev, "%s: QMI request failed 0x%x (%s)\n",
+ __func__, resp.resp.result, get_qmi_error(&resp.resp));
+ return -EREMOTEIO;
+ }
+ return 0;
+}
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index b5c41ed..2327b38 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -16,6 +16,7 @@
#include <linux/irq.h>
#include <linux/kthread.h>
#include <mach/msm_qmi_interface.h>
+#include <mach/subsystem_notif.h>
/* Per spec.max 40 bytes per received message */
#define SLIM_MSGQ_BUF_LEN 40
@@ -36,6 +37,10 @@
#define SLIM_USR_MC_CONNECT_SINK 0x2D
#define SLIM_USR_MC_DISCONNECT_PORT 0x2E
+#define SLIM_USR_MC_REPEAT_CHANGE_VALUE 0x0
+#define MSM_SLIM_VE_MAX_MAP_ADDR 0xFFF
+#define SLIM_MAX_VE_SLC_BYTES 16
+
#define MSM_SLIM_AUTOSUSPEND MSEC_PER_SEC
/*
@@ -82,7 +87,8 @@
/* Slimbus QMI service */
#define SLIMBUS_QMI_SVC_ID 0x0301
-#define SLIMBUS_QMI_INS_ID 1
+#define SLIMBUS_QMI_SVC_V1 1
+#define SLIMBUS_QMI_INS_ID 0
#define PGD_THIS_EE(r, v) ((v) ? PGD_THIS_EE_V2(r) : PGD_THIS_EE_V1(r))
#define PGD_PORT(r, p, v) ((v) ? PGD_PORT_V2(r, p) : PGD_PORT_V1(r, p))
@@ -168,7 +174,7 @@
enum msm_ctrl_state {
MSM_CTRL_AWAKE,
- MSM_CTRL_SLEEPING,
+ MSM_CTRL_IDLE,
MSM_CTRL_ASLEEP,
MSM_CTRL_DOWN,
};
@@ -205,6 +211,11 @@
struct work_struct ssr_up;
};
+struct msm_slim_mdm {
+ struct notifier_block nb;
+ void *ssr;
+};
+
struct msm_slim_pdata {
u32 apps_pipes;
u32 eapc;
@@ -253,6 +264,7 @@
struct work_struct slave_notify;
struct msm_slim_qmi qmi;
struct msm_slim_pdata pdata;
+ struct msm_slim_mdm mdm;
};
struct msm_sat_chan {
@@ -298,8 +310,8 @@
void msm_dealloc_port(struct slim_controller *ctrl, u8 pn);
int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn);
enum slim_port_err msm_slim_port_xfer_status(struct slim_controller *ctr,
- u8 pn, u8 **done_buf, u32 *done_len);
-int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, u8 *iobuf,
+ u8 pn, phys_addr_t *done_buf, u32 *done_len);
+int msm_slim_port_xfer(struct slim_controller *ctrl, u8 pn, phys_addr_t iobuf,
u32 len, struct completion *comp);
int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg);
u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len);
@@ -317,4 +329,5 @@
void msm_slim_qmi_exit(struct msm_slim_ctrl *dev);
int msm_slim_qmi_init(struct msm_slim_ctrl *dev, bool apps_is_master);
int msm_slim_qmi_power_request(struct msm_slim_ctrl *dev, bool active);
+int msm_slim_qmi_check_framer_request(struct msm_slim_ctrl *dev);
#endif
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 96fe2a8..fecf5ec 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -288,37 +288,29 @@
static void slim_report(struct work_struct *work)
{
- u8 laddr;
- int ret, i;
struct slim_driver *sbdrv;
struct slim_device *sbdev =
container_of(work, struct slim_device, wd);
- struct slim_controller *ctrl = sbdev->ctrl;
if (!sbdev->dev.driver)
return;
/* check if device-up or down needs to be called */
- mutex_lock(&ctrl->m_ctrl);
- /* address no longer valid, means device reported absent */
- for (i = 0; i < ctrl->num_dev; i++) {
- if (sbdev->laddr == ctrl->addrt[i].laddr &&
- ctrl->addrt[i].valid == false &&
- sbdev->notified)
- break;
- }
- mutex_unlock(&ctrl->m_ctrl);
+ if ((!sbdev->reported && !sbdev->notified) ||
+ (sbdev->reported && sbdev->notified))
+ return;
+
sbdrv = to_slim_driver(sbdev->dev.driver);
- if (i < ctrl->num_dev) {
+ /*
+ * address no longer valid, means device reported absent, whereas
+ * address valid, means device reported present
+ */
+ if (sbdev->notified && !sbdev->reported) {
sbdev->notified = false;
if (sbdrv->device_down)
sbdrv->device_down(sbdev);
- return;
- }
- if (sbdev->notified || !sbdrv)
- return;
- ret = slim_get_logical_addr(sbdev, sbdev->e_addr, 6, &laddr);
- if (!ret) {
+ } else if (!sbdev->notified && sbdev->reported) {
sbdev->notified = true;
- sbdrv->device_up(sbdev);
+ if (sbdrv->device_up)
+ sbdrv->device_up(sbdev);
}
}
@@ -643,6 +635,7 @@
ctrl->addrt[i].valid = false;
}
mutex_unlock(&ctrl->m_ctrl);
+ sbdev->reported = false;
queue_work(ctrl->wq, &sbdev->wd);
}
EXPORT_SYMBOL(slim_report_absent);
@@ -696,9 +689,12 @@
mutex_lock(&ctrl->m_ctrl);
txn = ctrl->txnt[tid];
- if (txn == NULL) {
- dev_err(&ctrl->dev, "Got response to invalid TID:%d, len:%d",
+ if (txn == NULL || txn->rbuf == NULL) {
+ if (txn == NULL)
+ dev_err(&ctrl->dev, "Got response to invalid TID:%d, len:%d",
tid, len);
+ else
+ dev_err(&ctrl->dev, "Invalid client buffer passed\n");
mutex_unlock(&ctrl->m_ctrl);
return;
}
@@ -801,6 +797,8 @@
u8 i = 0;
bool exists = false;
struct slim_device *sbdev;
+ struct list_head *pos, *next;
+
mutex_lock(&ctrl->m_ctrl);
/* already assigned */
if (ctrl_getlogical_addr(ctrl, e_addr, e_len, &i) == 0) {
@@ -850,10 +848,12 @@
pr_info("slimbus:%d laddr:0x%x, EAPC:0x%x:0x%x", ctrl->nr, *laddr,
e_addr[1], e_addr[2]);
mutex_lock(&ctrl->m_ctrl);
- list_for_each_entry(sbdev, &ctrl->devs, dev_list) {
+ list_for_each_safe(pos, next, &ctrl->devs) {
+ sbdev = list_entry(pos, struct slim_device, dev_list);
if (memcmp(sbdev->e_addr, e_addr, 6) == 0) {
struct slim_driver *sbdrv;
sbdev->laddr = *laddr;
+ sbdev->reported = true;
if (sbdev->dev.driver) {
sbdrv = to_slim_driver(sbdev->dev.driver);
if (sbdrv->device_up)
@@ -1107,6 +1107,28 @@
EXPORT_SYMBOL_GPL(slim_xfer_msg);
/*
+ * User message:
+ * slim_user_msg: Send user message that is interpreted by destination device
+ * @sb: Client handle sending the message
+ * @la: Destination device for this user message
+ * @mt: Message Type (Soruce-referred, or Destination-referred)
+ * @mc: Message Code
+ * @msg: Message structure (start offset, number of bytes) to be sent
+ * @buf: data buffer to be sent
+ * @len: data buffer size in bytes
+ */
+int slim_user_msg(struct slim_device *sb, u8 la, u8 mt, u8 mc,
+ struct slim_ele_access *msg, u8 *buf, u8 len)
+{
+ if (!sb || !sb->ctrl || !msg || mt == SLIM_MSG_MT_CORE)
+ return -EINVAL;
+ if (!sb->ctrl->xfer_user_msg)
+ return -EPROTONOSUPPORT;
+ return sb->ctrl->xfer_user_msg(sb->ctrl, la, mt, mc, msg, buf, len);
+}
+EXPORT_SYMBOL(slim_user_msg);
+
+/*
* slim_alloc_mgrports: Allocate port on manager side.
* @sb: device/client handle.
* @req: Port request type.
@@ -1462,7 +1484,7 @@
* Client will call slim_port_get_xfer_status to get error and/or number of
* bytes transferred if used asynchronously.
*/
-int slim_port_xfer(struct slim_device *sb, u32 ph, u8 *iobuf, u32 len,
+int slim_port_xfer(struct slim_device *sb, u32 ph, phys_addr_t iobuf, u32 len,
struct completion *comp)
{
struct slim_controller *ctrl = sb->ctrl;
@@ -1492,7 +1514,7 @@
* processed from the multiple transfers.
*/
enum slim_port_err slim_port_get_xfer_status(struct slim_device *sb, u32 ph,
- u8 **done_buf, u32 *done_len)
+ phys_addr_t *done_buf, u32 *done_len)
{
struct slim_controller *ctrl = sb->ctrl;
u8 pn = SLIM_HDL_TO_PORT(ph);
@@ -1505,7 +1527,7 @@
*/
if (la != SLIM_LA_MANAGER) {
if (done_buf)
- *done_buf = NULL;
+ *done_buf = 0;
if (done_len)
*done_len = 0;
return SLIM_P_NOT_OWNED;
@@ -1553,7 +1575,8 @@
for (j = *len - 1; j > i; j--)
arr[j] = arr[j - 1];
arr[i] = slc;
- ctrl->sched.usedslots += sl;
+ if (!ctrl->allocbw)
+ ctrl->sched.usedslots += sl;
return;
}
@@ -2659,7 +2682,8 @@
u32 sl = slc->seglen << slc->rootexp;
if (slc->coeff == SLIM_COEFF_3)
sl *= 3;
- ctrl->sched.usedslots -= sl;
+ if (!ctrl->allocbw)
+ ctrl->sched.usedslots -= sl;
slim_remove_ch(ctrl, slc);
slc->state = SLIM_CH_DEFINED;
}
@@ -2680,7 +2704,8 @@
if (revert || slc->def > 0) {
if (slc->coeff == SLIM_COEFF_3)
sl *= 3;
- ctrl->sched.usedslots += sl;
+ if (!ctrl->allocbw)
+ ctrl->sched.usedslots += sl;
if (revert)
slc->def++;
slc->state = SLIM_CH_ACTIVE;
@@ -2774,7 +2799,8 @@
u32 sl = slc->seglen << slc->rootexp;
if (slc->coeff == SLIM_COEFF_3)
sl *= 3;
- ctrl->sched.usedslots -= sl;
+ if (!ctrl->allocbw)
+ ctrl->sched.usedslots -= sl;
slc->state = SLIM_CH_PENDING_REMOVAL;
}
list_for_each_entry(pch, &sb->mark_suspend, pending) {
@@ -3036,7 +3062,7 @@
pch = list_entry(pos,
struct slim_pending_ch,
pending);
- if (pch->chan == slc->chan) {
+ if (pch->chan == chan) {
list_del(&pch->pending);
kfree(pch);
add_mark_removal = false;
@@ -3129,8 +3155,15 @@
*/
if (ctrl->clk_state == SLIM_CLK_PAUSED && ctrl->wakeup)
ret = ctrl->wakeup(ctrl);
+ /*
+ * If wakeup fails, make sure that next attempt can succeed.
+ * Since we already consumed pause_comp, complete it so
+ * that next wakeup isn't blocked forever
+ */
if (!ret)
ctrl->clk_state = SLIM_CLK_ACTIVE;
+ else
+ complete(&ctrl->pause_comp);
mutex_unlock(&ctrl->m_ctrl);
return ret;
} else {
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 891eb2f..73513ec 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -1769,6 +1769,18 @@
int ret = 0;
uint32_t cpu;
+ for_each_possible_cpu(cpu) {
+ cpus[cpu].cpu = cpu;
+ cpus[cpu].offline = 0;
+ cpus[cpu].user_offline = 0;
+ cpus[cpu].hotplug_thresh_clear = false;
+ cpus[cpu].max_freq = false;
+ cpus[cpu].user_max_freq = UINT_MAX;
+ cpus[cpu].user_min_freq = 0;
+ cpus[cpu].limited_max_freq = UINT_MAX;
+ cpus[cpu].limited_min_freq = 0;
+ cpus[cpu].freq_thresh_clear = false;
+ }
BUG_ON(!pdata);
tsens_get_max_sensor_num(&max_tsens_num);
memcpy(&msm_thermal_info, pdata, sizeof(struct msm_thermal_data));
@@ -1779,10 +1791,6 @@
return -EINVAL;
enabled = 1;
- for_each_possible_cpu(cpu) {
- cpus[cpu].limited_max_freq = UINT_MAX;
- cpus[cpu].limited_min_freq = 0;
- }
ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
CPUFREQ_POLICY_NOTIFIER);
if (ret)
@@ -2433,10 +2441,6 @@
}
for_each_possible_cpu(cpu) {
- cpus[cpu].cpu = cpu;
- cpus[cpu].offline = 0;
- cpus[cpu].user_offline = 0;
- cpus[cpu].hotplug_thresh_clear = false;
ret = of_property_read_string_index(node, key, cpu,
&cpus[cpu].sensor_type);
if (ret)
@@ -2470,7 +2474,6 @@
{
char *key = NULL;
int ret = 0;
- uint32_t cpu;
key = "qcom,freq-mitigation-temp";
ret = of_property_read_u32(node, key, &data->freq_mitig_temp_degc);
@@ -2494,14 +2497,6 @@
goto PROBE_FREQ_EXIT;
freq_mitigation_enabled = 1;
- for_each_possible_cpu(cpu) {
- cpus[cpu].max_freq = false;
- cpus[cpu].user_max_freq = UINT_MAX;
- cpus[cpu].user_min_freq = 0;
- cpus[cpu].limited_max_freq = UINT_MAX;
- cpus[cpu].limited_min_freq = 0;
- cpus[cpu].freq_thresh_clear = false;
- }
PROBE_FREQ_EXIT:
if (ret) {
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index efb87a9..eb647fa 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -471,16 +471,30 @@
struct qpnp_adc_tm_chip *chip, uint32_t btm_chan,
struct qpnp_vadc_chan_properties *chan_prop)
{
- int rc;
- u8 meas_interval_timer2 = 0;
+ int rc, chan_idx = 0, i = 0;
+ bool chan_found = false;
+ u8 meas_interval_timer2 = 0, timer_interval_store = 0;
uint32_t btm_chan_idx = 0;
- /* Configure kernel clients to timer1 */
- switch (chan_prop->timer_select) {
+ while (i < chip->max_channels_available) {
+ if (chip->sensor[i].btm_channel_num == btm_chan) {
+ chan_idx = i;
+ chan_found = true;
+ i++;
+ } else
+ i++;
+ }
+
+ if (!chan_found) {
+ pr_err("Channel not found\n");
+ return -EINVAL;
+ }
+
+ switch (chip->sensor[chan_idx].timer_select) {
case ADC_MEAS_TIMER_SELECT1:
rc = qpnp_adc_tm_write_reg(chip,
QPNP_ADC_TM_MEAS_INTERVAL_CTL,
- chan_prop->meas_interval1);
+ chip->sensor[chan_idx].meas_interval);
if (rc < 0) {
pr_err("timer1 configure failed\n");
return rc;
@@ -495,9 +509,10 @@
pr_err("timer2 configure read failed\n");
return rc;
}
- meas_interval_timer2 |=
- (chan_prop->meas_interval2 <<
- QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
+ timer_interval_store = chip->sensor[chan_idx].meas_interval;
+ timer_interval_store <<= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT;
+ timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK;
+ meas_interval_timer2 |= timer_interval_store;
rc = qpnp_adc_tm_write_reg(chip,
QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
meas_interval_timer2);
@@ -514,8 +529,9 @@
pr_err("timer3 read failed\n");
return rc;
}
- chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
- meas_interval_timer2 |= chan_prop->meas_interval2;
+ timer_interval_store = chip->sensor[chan_idx].meas_interval;
+ timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK;
+ meas_interval_timer2 |= timer_interval_store;
rc = qpnp_adc_tm_write_reg(chip,
QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
meas_interval_timer2);
@@ -535,7 +551,18 @@
pr_err("Invalid btm channel idx\n");
return rc;
}
- adc_tm_data[btm_chan_idx].meas_interval_ctl = chan_prop->timer_select;
+ rc = qpnp_adc_tm_write_reg(chip,
+ adc_tm_data[btm_chan_idx].meas_interval_ctl,
+ chip->sensor[chan_idx].timer_select);
+ if (rc < 0) {
+ pr_err("TM channel timer configure failed\n");
+ return rc;
+ }
+
+ pr_debug("timer select:%d, timer_value_within_select:%d, channel:%x\n",
+ chip->sensor[chan_idx].timer_select,
+ chip->sensor[chan_idx].meas_interval,
+ btm_chan);
return rc;
}
@@ -954,10 +981,6 @@
chip->adc->adc_channels[channel].fast_avg_setup;
chip->adc->amux_prop->mode_sel =
ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
- chip->adc->amux_prop->chan_prop->timer_select =
- ADC_MEAS_TIMER_SELECT1;
- chip->adc->amux_prop->chan_prop->meas_interval1 =
- ADC_MEAS1_INTERVAL_1S;
chip->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
chip->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
chip->adc->amux_prop->chan_prop->tm_channel_select =
@@ -1673,8 +1696,6 @@
chip->adc->adc_channels[dt_index].fast_avg_setup;
chip->adc->amux_prop->mode_sel =
ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
- chip->adc->amux_prop->chan_prop->meas_interval1 =
- ADC_MEAS1_INTERVAL_1S;
adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, param,
&chip->adc->amux_prop->chan_prop->low_thr,
&chip->adc->amux_prop->chan_prop->high_thr);
@@ -1682,8 +1703,6 @@
chip->adc->amux_prop->chan_prop);
chip->adc->amux_prop->chan_prop->tm_channel_select =
chip->sensor[dt_index].btm_channel_num;
- chip->adc->amux_prop->chan_prop->timer_select =
- ADC_MEAS_TIMER_SELECT1;
chip->adc->amux_prop->chan_prop->state_request =
param->state_request;
rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
@@ -1880,7 +1899,7 @@
for_each_child_of_node(node, child) {
char name[25];
- int btm_channel_num;
+ int btm_channel_num, timer_select = 0;
rc = of_property_read_u32(child,
"qcom,btm-channel-number", &btm_channel_num);
@@ -1888,6 +1907,28 @@
pr_err("Invalid btm channel number\n");
goto fail;
}
+ rc = of_property_read_u32(child,
+ "qcom,meas-interval-timer-idx", &timer_select);
+ if (rc) {
+ pr_debug("Default to timer1 with interval of 1 sec\n");
+ chip->sensor[sen_idx].timer_select =
+ ADC_MEAS_TIMER_SELECT1;
+ chip->sensor[sen_idx].meas_interval =
+ ADC_MEAS1_INTERVAL_1S;
+ } else {
+ if (timer_select >= ADC_MEAS_TIMER_NUM) {
+ pr_err("Invalid timer selection number\n");
+ goto fail;
+ }
+ chip->sensor[sen_idx].timer_select = timer_select;
+ if (timer_select == ADC_MEAS_TIMER_SELECT2)
+ chip->sensor[sen_idx].meas_interval =
+ ADC_MEAS2_INTERVAL_500MS;
+ if (timer_select == ADC_MEAS_TIMER_SELECT3)
+ chip->sensor[sen_idx].meas_interval =
+ ADC_MEAS3_INTERVAL_4S;
+ }
+
chip->sensor[sen_idx].btm_channel_num = btm_channel_num;
chip->sensor[sen_idx].vadc_channel_num =
chip->adc->adc_channels[sen_idx].channel_num;
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 066419f..4058bec 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -3,7 +3,7 @@
* MSM 7k High speed uart driver
*
* Copyright (c) 2008 Google Inc.
- * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2014, The Linux Foundation. All rights reserved.
* Modified: Nick Pelly <npelly@google.com>
*
* All source code in this file is licensed under the following license
@@ -94,7 +94,6 @@
#define MSM_HS_DBG(x...) do { \
if (hs_serial_debug_mask >= DBG_LEV) { \
- pr_debug(x); \
if (ipc_msm_hs_log_ctxt) \
ipc_log_string(ipc_msm_hs_log_ctxt, x); \
} \
@@ -102,7 +101,6 @@
#define MSM_HS_INFO(x...) do { \
if (hs_serial_debug_mask >= INFO_LEV) {\
- pr_info(x); \
if (ipc_msm_hs_log_ctxt) \
ipc_log_string(ipc_msm_hs_log_ctxt, x); \
} \
@@ -141,7 +139,7 @@
FLUSH_NONE,
FLUSH_DATA_READY,
FLUSH_DATA_INVALID, /* values after this indicate invalid data */
- FLUSH_IGNORE = FLUSH_DATA_INVALID,
+ FLUSH_IGNORE,
FLUSH_STOP,
FLUSH_SHUTDOWN,
};
@@ -205,6 +203,8 @@
struct delayed_work flip_insert_work;
struct tasklet_struct tlet;
struct msm_hs_sps_ep_conn_data prod;
+ bool rx_cmd_queued;
+ bool rx_cmd_exec;
};
enum buffer_states {
NONE_PENDING = 0x0,
@@ -271,6 +271,8 @@
int rx_count_callback;
bool rx_bam_inprogress;
unsigned int *reg_ptr;
+ wait_queue_head_t bam_disconnect_wait;
+
};
unsigned int regmap_nonblsp[UART_DM_LAST] = {
@@ -344,7 +346,6 @@
#define BLSP_UART_CLK_FMAX 63160000
static struct dentry *debug_base;
-static struct msm_hs_port q_uart_port[UARTDM_NR];
static struct platform_driver msm_serial_hs_platform_driver;
static struct uart_driver msm_hs_driver;
static struct uart_ops msm_hs_ops;
@@ -352,6 +353,7 @@
static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr);
static void flip_insert_work(struct work_struct *work);
static void msm_hs_bus_voting(struct msm_hs_port *msm_uport, unsigned int vote);
+static struct msm_hs_port *msm_hs_get_hs_port(int port_index);
#define UARTDM_TO_MSM(uart_port) \
container_of((uart_port), struct msm_hs_port, uport)
@@ -424,6 +426,7 @@
}
}
msm_uport->clk_state = MSM_HS_CLK_ON;
+ MSM_HS_DBG("%s: Clock ON successful\n", __func__);
}
@@ -432,71 +435,98 @@
static void msm_hs_clock_unvote(struct msm_hs_port *msm_uport)
{
- int rc = atomic_dec_return(&msm_uport->clk_count);
+ int rc = atomic_read(&msm_uport->clk_count);
- if (rc < 0) {
- msm_hs_bus_voting(msm_uport, BUS_RESET);
+ if (rc <= 0) {
WARN(rc, "msm_uport->clk_count < 0!");
dev_err(msm_uport->uport.dev,
- "%s: Clocks count invalid [%d]\n", __func__,
- atomic_read(&msm_uport->clk_count));
+ "%s: Clocks count invalid [%d]\n", __func__, rc);
return;
}
+ rc = atomic_dec_return(&msm_uport->clk_count);
if (0 == rc) {
- msm_hs_bus_voting(msm_uport, BUS_RESET);
/* Turn off the core clk and iface clk*/
clk_disable_unprepare(msm_uport->clk);
if (msm_uport->pclk)
clk_disable_unprepare(msm_uport->pclk);
+ /* Unvote the PNOC clock */
+ msm_hs_bus_voting(msm_uport, BUS_RESET);
msm_uport->clk_state = MSM_HS_CLK_OFF;
+ MSM_HS_DBG("%s: Clock OFF successful\n", __func__);
}
}
+/* Check if the uport line number matches with user id stored in pdata.
+ * User id information is stored during initialization. This function
+ * ensues that the same device is selected */
+
+static struct msm_hs_port *get_matching_hs_port(struct platform_device *pdev)
+{
+ struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
+ struct msm_hs_port *msm_uport = msm_hs_get_hs_port(pdev->id);
+
+ if ((!msm_uport) || (msm_uport->uport.line != pdev->id
+ && msm_uport->uport.line != pdata->userid)) {
+ MSM_HS_ERR("uport line number mismatch!");
+ WARN_ON(1);
+ return NULL;
+ }
+
+ return msm_uport;
+}
+
static ssize_t show_clock(struct device *dev, struct device_attribute *attr,
char *buf)
{
int state = 1;
+ ssize_t ret = 0;
enum msm_hs_clk_states_e clk_state;
unsigned long flags;
-
struct platform_device *pdev = container_of(dev, struct
platform_device, dev);
- struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
+ struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
- spin_lock_irqsave(&msm_uport->uport.lock, flags);
- clk_state = msm_uport->clk_state;
- spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
+ /* This check should not fail */
+ if (msm_uport) {
+ spin_lock_irqsave(&msm_uport->uport.lock, flags);
+ clk_state = msm_uport->clk_state;
+ spin_unlock_irqrestore(&msm_uport->uport.lock, flags);
- if (clk_state <= MSM_HS_CLK_OFF)
- state = 0;
+ if (clk_state <= MSM_HS_CLK_OFF)
+ state = 0;
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", state);
+ }
- return snprintf(buf, PAGE_SIZE, "%d\n", state);
+ return ret;
}
static ssize_t set_clock(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int state;
+ ssize_t ret = 0;
struct platform_device *pdev = container_of(dev, struct
platform_device, dev);
- struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
+ struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
- state = buf[0] - '0';
- switch (state) {
- case 0: {
- msm_hs_request_clock_off(&msm_uport->uport);
- break;
+ /* This check should not fail */
+ if (msm_uport) {
+ state = buf[0] - '0';
+ switch (state) {
+ case 0:
+ msm_hs_request_clock_off(&msm_uport->uport);
+ ret = count;
+ break;
+ case 1:
+ msm_hs_request_clock_on(&msm_uport->uport);
+ ret = count;
+ break;
+ default:
+ ret = -EINVAL;
+ }
}
- case 1: {
- msm_hs_request_clock_on(&msm_uport->uport);
- break;
- }
- default: {
- return -EINVAL;
- }
- }
- return count;
+ return ret;
}
static DEVICE_ATTR(clock, S_IWUSR | S_IRUGO, show_clock, set_clock);
@@ -583,22 +613,33 @@
*/
static void dump_uart_hs_registers(struct msm_hs_port *msm_uport)
{
- msm_hs_clock_vote(msm_uport);
- MSM_HS_DBG("============= UART Registers ================\n");
- MSM_HS_DBG("UART_DM_MR1:%x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_MR1));
- MSM_HS_DBG("UART_DM_MR2:%x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_MR2));
- MSM_HS_DBG("UART_DM_IPR:%x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_IPR));
- MSM_HS_DBG("UART_DM_RFWR:%x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_RFWR));
- MSM_HS_DBG("UART_DM_SR:%x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_SR));
- MSM_HS_DBG("UART_DM_IMR: %x\n", msm_hs_read(&(msm_uport->uport),
- UART_DM_IMR));
- MSM_HS_DBG("=============================================\n");
- msm_hs_clock_unvote(msm_uport);
+ struct uart_port *uport = &(msm_uport->uport);
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ return;
+ }
+
+ MSM_HS_DBG(
+ "MR1:%x MR2:%x TFWR:%x RFWR:%x DMEN:%x IMR:%x MISR:%x NCF_TX:%x\n",
+ msm_hs_read(uport, UART_DM_MR1),
+ msm_hs_read(uport, UART_DM_MR2),
+ msm_hs_read(uport, UART_DM_TFWR),
+ msm_hs_read(uport, UART_DM_RFWR),
+ msm_hs_read(uport, UART_DM_DMEN),
+ msm_hs_read(uport, UART_DM_IMR),
+ msm_hs_read(uport, UART_DM_MISR),
+ msm_hs_read(uport, UART_DM_NCF_TX));
+ MSM_HS_INFO("SR:%x ISR:%x DMRX:%x RX_SNAP:%x TXFS:%x RXFS:%x\n",
+ msm_hs_read(uport, UART_DM_SR),
+ msm_hs_read(uport, UART_DM_ISR),
+ msm_hs_read(uport, UART_DM_DMRX),
+ msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP),
+ msm_hs_read(uport, UART_DM_TXFS),
+ msm_hs_read(uport, UART_DM_RXFS));
+ MSM_HS_DBG("clk_req_state:0x%x rx.flush:%u\n",
+ msm_uport->clk_req_off_state,
+ msm_uport->rx.flush);
+ MSM_HS_DBG("clk_state:%d", msm_uport->clk_state);
}
static void msm_hs_release_port(struct uart_port *port)
@@ -742,9 +783,11 @@
return -EINVAL;
}
- msm_uport = &q_uart_port[pdev->id];
- dev = msm_uport->uport.dev;
+ msm_uport = get_matching_hs_port(pdev);
+ if (!msm_uport)
+ return -EINVAL;
+ dev = msm_uport->uport.dev;
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_clock.attr);
debugfs_remove(msm_uport->loopback_dir);
@@ -1096,6 +1139,10 @@
struct msm_hs_rx *rx = &msm_uport->rx;
struct sps_pipe *sps_pipe_handle = rx->prod.pipe_handle;
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ return;
+ }
mutex_lock(&msm_uport->clk_mutex);
msm_hs_write(uport, UART_DM_IMR, 0);
@@ -1109,6 +1156,8 @@
data = msm_hs_read(uport, UART_DM_MR1);
data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
msm_hs_write(uport, UART_DM_MR1, data);
+ /* set RFR_N to high */
+ msm_hs_write(uport, UART_DM_CR, RFR_HIGH);
/*
* Disable Rx channel of UARTDM
@@ -1195,10 +1244,12 @@
msm_hs_write(uport, UART_DM_CR, RESET_RX);
msm_hs_write(uport, UART_DM_CR, RESET_TX);
+ /* Issue TX BAM Start IFC command */
+ msm_hs_write(uport, UART_DM_CR, START_TX_BAM_IFC);
if (msm_uport->rx.flush == FLUSH_NONE) {
wake_lock(&msm_uport->rx.wake_lock);
- msm_uport->rx.flush = FLUSH_IGNORE;
+ msm_uport->rx.flush = FLUSH_DATA_INVALID;
/*
* Before using dmov APIs make sure that
* previous writel are completed. Hence
@@ -1215,6 +1266,7 @@
MSM_HS_ERR("%s(): sps_disconnect failed\n",
__func__);
msm_hs_spsconnect_rx(uport);
+ msm_uport->rx.flush = FLUSH_IGNORE;
msm_serial_hs_rx_tlet((unsigned long) &rx->tlet);
} else {
msm_uport->rx_discard_flush_issued = true;
@@ -1237,12 +1289,12 @@
* UART Core would trigger RFR if it is not having any space with
* RX FIFO.
*/
+ /* Pulling RFR line high */
+ msm_hs_write(uport, UART_DM_CR, RFR_LOW);
data = msm_hs_read(uport, UART_DM_MR1);
data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
- if (c_cflag & CRTSCTS) {
data |= UARTDM_MR1_CTS_CTL_BMSK;
data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
- }
msm_hs_write(uport, UART_DM_MR1, data);
msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
@@ -1265,6 +1317,7 @@
msm_hs_clock_vote(msm_uport);
data = msm_hs_read(uport, UART_DM_SR);
msm_hs_clock_unvote(msm_uport);
+ MSM_HS_DBG("%s(): SR Reg Read 0x%x", __func__, data);
if (data & UARTDM_SR_TXEMT_BMSK)
ret = TIOCSER_TEMT;
@@ -1300,6 +1353,9 @@
wake_lock_timeout(&msm_uport->rx.wake_lock, HZ / 2);
msm_uport->rx.flush = FLUSH_SHUTDOWN;
+ MSM_HS_DBG("%s: Calling Completion\n", __func__);
+ wake_up(&msm_uport->bam_disconnect_wait);
+ MSM_HS_DBG("%s: Done Completion\n", __func__);
wake_up(&msm_uport->rx.wait);
}
@@ -1316,16 +1372,19 @@
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
unsigned int data;
- /* disable dlink */
- data = msm_hs_read(uport, UART_DM_DMEN);
- if (is_blsp_uart(msm_uport))
- data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
- else
- data &= ~UARTDM_RX_DM_EN_BMSK;
- msm_hs_write(uport, UART_DM_DMEN, data);
+ MSM_HS_DBG("In %s():\n", __func__);
+ if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
+ /* disable dlink */
+ data = msm_hs_read(uport, UART_DM_DMEN);
+ if (is_blsp_uart(msm_uport))
+ data &= ~UARTDM_RX_BAM_ENABLE_BMSK;
+ else
+ data &= ~UARTDM_RX_DM_EN_BMSK;
+ msm_hs_write(uport, UART_DM_DMEN, data);
- /* calling DMOV or CLOCK API. Hence mb() */
- mb();
+ /* calling DMOV or CLOCK API. Hence mb() */
+ mb();
+ }
/* Disable the receiver */
if (msm_uport->rx.flush == FLUSH_NONE) {
wake_lock(&msm_uport->rx.wake_lock);
@@ -1352,7 +1411,7 @@
int aligned_tx_count;
dma_addr_t src_addr;
dma_addr_t aligned_src_addr;
- u32 flags = SPS_IOVEC_FLAG_EOT;
+ u32 flags = SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
struct msm_hs_tx *tx = &msm_uport->tx;
struct circ_buf *tx_buf = &msm_uport->uport.state->xmit;
@@ -1360,6 +1419,12 @@
if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) {
msm_hs_stop_tx_locked(uport);
+ if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
+ MSM_HS_DBG("%s(): Clock off requested calling WQ",
+ __func__);
+ queue_work(msm_uport->hsuart_wq,
+ &msm_uport->clock_off_w);
+ }
return;
}
@@ -1385,10 +1450,9 @@
dma_sync_single_for_device(uport->dev, aligned_src_addr,
aligned_tx_count, DMA_TO_DEVICE);
- if (is_blsp_uart(msm_uport)) {
- /* Issue TX BAM Start IFC command */
- msm_hs_write(uport, UART_DM_CR, START_TX_BAM_IFC);
- } else {
+ if (is_blsp_uart(msm_uport))
+ tx->tx_count = tx_count;
+ else {
tx->command_ptr->num_rows =
(((tx_count + 15) >> 4) << 16) |
((tx_count + 15) >> 4);
@@ -1399,18 +1463,16 @@
*tx->command_ptr_ptr = CMD_PTR_LP |
DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
+ /* Save tx_count to use in Callback */
+ tx->tx_count = tx_count;
+ msm_hs_write(uport, UART_DM_NCF_TX, tx_count);
+ msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK;
+ msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
+ /* Calling next DMOV API. Hence mb() here. */
+ mb();
+
}
- /* Save tx_count to use in Callback */
- tx->tx_count = tx_count;
- msm_hs_write(uport, UART_DM_NCF_TX, tx_count);
-
- /* Disable the tx_ready interrupt */
- msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK;
- msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
- /* Calling next DMOV API. Hence mb() here. */
- mb();
-
msm_uport->tx.flush = FLUSH_NONE;
if (is_blsp_uart(msm_uport)) {
@@ -1439,6 +1501,16 @@
unsigned int buffer_pending = msm_uport->rx.buffer_pending;
unsigned int data;
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ return;
+ }
+ if (rx->rx_cmd_exec) {
+ MSM_HS_DBG("%s: Rx Cmd got executed, wait for rx_tlet\n",
+ __func__);
+ rx->flush = FLUSH_IGNORE;
+ return;
+ }
msm_uport->rx.buffer_pending = 0;
if (buffer_pending && hs_serial_debug_mask)
MSM_HS_ERR("Error: rx started in buffer state = %x",
@@ -1447,8 +1519,6 @@
msm_hs_write(uport, UART_DM_CR, RESET_STALE_INT);
msm_hs_write(uport, UART_DM_DMRX, UARTDM_RX_BUF_SIZE);
msm_hs_write(uport, UART_DM_CR, STALE_EVENT_ENABLE);
- msm_uport->imr_reg |= UARTDM_ISR_RXLEV_BMSK;
-
/*
* Enable UARTDM Rx Interface as previously it has been
* disable in set_termios before configuring baud rate.
@@ -1488,10 +1558,8 @@
sps_transfer_one(sps_pipe_handle, rx->rbuffer,
UARTDM_RX_BUF_SIZE, msm_uport, flags);
msm_uport->rx_bam_inprogress = false;
+ msm_uport->rx.rx_cmd_queued = true;
wake_up(&msm_uport->rx.wait);
- } else {
- msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel,
- &msm_uport->rx.xfer);
}
MSM_HS_DBG("%s:Enqueue Rx Cmd\n", __func__);
dump_uart_hs_registers(msm_uport);
@@ -1551,7 +1619,7 @@
static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr)
{
int retval;
- int rx_count;
+ int rx_count = 0;
unsigned long status;
unsigned long flags;
unsigned int error_f = 0;
@@ -1571,6 +1639,9 @@
notify = &msm_uport->notify;
rx = &msm_uport->rx;
+ msm_uport->rx.rx_cmd_queued = false;
+ msm_uport->rx.rx_cmd_exec = false;
+
status = msm_hs_read(uport, UART_DM_SR);
spin_lock_irqsave(&uport->lock, flags);
@@ -1619,29 +1690,30 @@
}
}
- if (error_f)
- msm_hs_write(uport, UART_DM_CR, RESET_ERROR_STATUS);
-
- if (msm_uport->clk_req_off_state == CLK_REQ_OFF_FLUSH_ISSUED)
- msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_FLUSHED;
+ if (error_f) {
+ if (msm_uport->clk_state == MSM_HS_CLK_ON)
+ msm_hs_write(uport, UART_DM_CR, RESET_ERROR_STATUS);
+ else
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ }
flush = msm_uport->rx.flush;
if (flush == FLUSH_IGNORE)
- if (!msm_uport->rx.buffer_pending)
+ if (!msm_uport->rx.buffer_pending) {
+ MSM_HS_DBG("%s: calling start_rx_locked\n", __func__);
msm_hs_start_rx_locked(uport);
-
- if (flush == FLUSH_STOP) {
- msm_uport->rx.flush = FLUSH_SHUTDOWN;
- wake_up(&msm_uport->rx.wait);
- }
+ }
if (flush >= FLUSH_DATA_INVALID)
goto out;
if (is_blsp_uart(msm_uport)) {
rx_count = msm_uport->rx_count_callback;
} else {
- rx_count = msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP);
- /* order the read of rx.buffer */
- rmb();
+ if (msm_uport->clk_state == MSM_HS_CLK_ON) {
+ rx_count = msm_hs_read(uport, UART_DM_RX_TOTAL_SNAP);
+ /* order the read of rx.buffer */
+ rmb();
+ } else
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
}
MSM_HS_DBG("%s():[UART_RX]<%d>\n", __func__, rx_count);
@@ -1656,24 +1728,21 @@
retval << 5 | (rx_count - retval) << 16;
}
}
-
- MSM_HS_DBG("%s() read rx buffer complete", __func__);
- /* order the read of rx.buffer and the start of next rx xfer */
- wmb();
-
- if (!msm_uport->rx.buffer_pending) {
+ if (!msm_uport->rx.buffer_pending && !msm_uport->rx.rx_cmd_queued) {
if (is_blsp_uart(msm_uport)) {
msm_uport->rx.flush = FLUSH_NONE;
msm_uport->rx_bam_inprogress = true;
sps_pipe_handle = rx->prod.pipe_handle;
+ MSM_HS_DBG("Queing bam descriptor\n");
/* Queue transfer request to SPS */
sps_transfer_one(sps_pipe_handle, rx->rbuffer,
UARTDM_RX_BUF_SIZE, msm_uport, sps_flags);
msm_uport->rx_bam_inprogress = false;
+ msm_uport->rx.rx_cmd_queued = true;
wake_up(&msm_uport->rx.wait);
- } else {
+
+ } else
msm_hs_start_rx_locked(uport);
- }
}
out:
if (msm_uport->rx.buffer_pending) {
@@ -1695,8 +1764,12 @@
{
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ }
if (msm_uport->tx.tx_ready_int_en == 0) {
- msm_uport->tx.tx_ready_int_en = 1;
+ if (!is_blsp_uart(msm_uport))
+ msm_uport->tx.tx_ready_int_en = 1;
if (msm_uport->tx.dma_in_flight == 0)
msm_hs_submit_tx_locked(uport);
}
@@ -1718,11 +1791,12 @@
((struct sps_event_notify *)notify)->user;
msm_uport->notify = *notify;
- MSM_HS_DBG("%s: sps ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x\n",
- __func__, notify->event_id,
- notify->data.transfer.iovec.addr,
- notify->data.transfer.iovec.size,
- notify->data.transfer.iovec.flags);
+ MSM_HS_DBG("%s: ev_id=%d, addr=0x%x, size=0x%x, flags=0x%x, line=%d\n",
+ __func__, notify->event_id,
+ notify->data.transfer.iovec.addr,
+ notify->data.transfer.iovec.size,
+ notify->data.transfer.iovec.flags,
+ msm_uport->uport.line);
tasklet_schedule(&msm_uport->tx.tlet);
}
@@ -1756,6 +1830,35 @@
unsigned long flags;
struct msm_hs_port *msm_uport = container_of((struct tasklet_struct *)
tlet_ptr, struct msm_hs_port, tx.tlet);
+ struct uart_port *uport = &msm_uport->uport;
+ struct circ_buf *tx_buf = &uport->state->xmit;
+ struct msm_hs_tx *tx = &msm_uport->tx;
+
+ /*
+ * Do the work buffer related work in BAM
+ * mode that is equivalent to legacy mode
+ */
+
+ if (!msm_uport->tty_flush_receive)
+ tx_buf->tail = (tx_buf->tail +
+ tx->tx_count) & ~UART_XMIT_SIZE;
+ else
+ msm_uport->tty_flush_receive = false;
+
+ tx->dma_in_flight = 0;
+
+ uport->icount.tx += tx->tx_count;
+
+ /*
+ * Calling to send next chunk of data
+ * If the circ buffer is empty, we stop
+ * If the clock off was requested, the clock
+ * off sequence is kicked off
+ */
+ msm_hs_submit_tx_locked(uport);
+
+ if (uart_circ_chars_pending(tx_buf) < WAKEUP_CHARS)
+ uart_write_wakeup(uport);
spin_lock_irqsave(&(msm_uport->uport.lock), flags);
if (msm_uport->tx.flush == FLUSH_STOP) {
@@ -1765,10 +1868,14 @@
return;
}
- msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
- msm_hs_write(&(msm_uport->uport), UART_DM_IMR, msm_uport->imr_reg);
- /* Calling clk API. Hence mb() requires. */
- mb();
+ /* TX_READY_BMSK only if non BAM mode */
+ if (!is_blsp_uart(msm_uport)) {
+ msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
+ msm_hs_write(&(msm_uport->uport), UART_DM_IMR,
+ msm_uport->imr_reg);
+ /* Calling clk API. Hence mb() requires. */
+ mb();
+ }
spin_unlock_irqrestore(&(msm_uport->uport.lock), flags);
MSM_HS_DBG("In %s()\n", __func__);
@@ -1804,6 +1911,7 @@
if (msm_uport->rx.flush == FLUSH_NONE) {
spin_lock_irqsave(&uport->lock, flags);
msm_uport->rx_count_callback = notify->data.transfer.iovec.size;
+ msm_uport->rx.rx_cmd_exec = true;
spin_unlock_irqrestore(&uport->lock, flags);
tasklet_schedule(&msm_uport->rx.tlet);
}
@@ -1873,7 +1981,12 @@
{
unsigned int set_rts;
unsigned int data;
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s:Failed.Clocks are OFF\n", __func__);
+ return;
+ }
/* RTS is active low */
set_rts = TIOCM_RTS & mctrl ? 0 : 1;
@@ -1911,6 +2024,11 @@
{
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s:Failed.Clocks are OFF\n", __func__);
+ return;
+ }
+
/* Enable DELTA_CTS Interrupt */
msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK;
msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
@@ -1935,6 +2053,12 @@
static void msm_hs_break_ctl(struct uart_port *uport, int ctl)
{
unsigned long flags;
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ return;
+ }
spin_lock_irqsave(&uport->lock, flags);
msm_hs_write(uport, UART_DM_CR, ctl ? START_BREAK : STOP_BREAK);
@@ -1967,6 +2091,12 @@
/* Handle CTS changes (Called from interrupt handler) */
static void msm_hs_handle_delta_cts_locked(struct uart_port *uport)
{
+ struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+
+ if (msm_uport->clk_state != MSM_HS_CLK_ON) {
+ MSM_HS_WARN("%s: Failed.Clocks are OFF\n", __func__);
+ return;
+ }
/* clear interrupt */
msm_hs_write(uport, UART_DM_CR, RESET_CTS);
/* Calling CLOCK API. Hence mb() requires here. */
@@ -1986,60 +2116,47 @@
{
unsigned long sr_status;
unsigned long flags;
- int ret;
+ unsigned int data;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
struct circ_buf *tx_buf = &uport->state->xmit;
mutex_lock(&msm_uport->clk_mutex);
spin_lock_irqsave(&uport->lock, flags);
+ MSM_HS_DBG("In %s:\n", __func__);
/* Cancel if tx tty buffer is not empty, dma is in flight,
- * or tx fifo is not empty */
+ * or tx fifo is not empty
+ */
if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF ||
!uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight ||
msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) {
spin_unlock_irqrestore(&uport->lock, flags);
mutex_unlock(&msm_uport->clk_mutex);
+ if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
+ msm_uport->clk_state = MSM_HS_CLK_ON;
+ /* Pulling RFR line high */
+ msm_hs_write(uport, UART_DM_CR, RFR_LOW);
+ /* Enable auto RFR */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+ mb();
+ }
+ MSM_HS_DBG("%s(): clkstate %d", __func__, msm_uport->clk_state);
return -1;
}
- /* Make sure the uart is finished with the last byte */
- sr_status = msm_hs_read(uport, UARTDM_SR);
+ /* Make sure the uart is finished with the last byte,
+ * use BFamily Register
+ */
+ sr_status = msm_hs_read(uport, UART_DM_SR);
if (!(sr_status & UARTDM_SR_TXEMT_BMSK)) {
spin_unlock_irqrestore(&uport->lock, flags);
mutex_unlock(&msm_uport->clk_mutex);
+ MSM_HS_DBG("%s(): SR TXEMT fail %lx", __func__, sr_status);
return 0; /* retry */
}
- /* Make sure forced RXSTALE flush complete */
- switch (msm_uport->clk_req_off_state) {
- case CLK_REQ_OFF_START:
- msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED;
-
- if (!is_blsp_uart(msm_uport)) {
- msm_hs_write(uport, UART_DM_CR, FORCE_STALE_EVENT);
- /*
- * Before returning make sure that device writel
- * completed. Hence mb() requires here.
- */
- mb();
- }
- spin_unlock_irqrestore(&uport->lock, flags);
- mutex_unlock(&msm_uport->clk_mutex);
- return 0; /* RXSTALE flush not complete - retry */
- case CLK_REQ_OFF_RXSTALE_ISSUED:
- case CLK_REQ_OFF_FLUSH_ISSUED:
- spin_unlock_irqrestore(&uport->lock, flags);
- if (is_blsp_uart(msm_uport)) {
- msm_uport->clk_req_off_state =
- CLK_REQ_OFF_RXSTALE_FLUSHED;
- }
- mutex_unlock(&msm_uport->clk_mutex);
- return 0; /* RXSTALE flush not complete - retry */
- case CLK_REQ_OFF_RXSTALE_FLUSHED:
- break; /* continue */
- }
-
if (msm_uport->rx.flush != FLUSH_SHUTDOWN) {
if (msm_uport->rx.flush == FLUSH_NONE) {
msm_hs_stop_rx_locked(uport);
@@ -2047,24 +2164,23 @@
msm_uport->rx_discard_flush_issued = true;
}
+ MSM_HS_DBG("%s: rx.flush %d clk_state %d\n", __func__,
+ msm_uport->rx.flush, msm_uport->clk_state);
spin_unlock_irqrestore(&uport->lock, flags);
- if (msm_uport->rx_discard_flush_issued) {
- MSM_HS_DBG("%s(): wainting for flush completion.\n",
- __func__);
- ret = wait_event_timeout(msm_uport->rx.wait,
- msm_uport->rx_discard_flush_issued == false,
- RX_FLUSH_COMPLETE_TIMEOUT);
- if (!ret)
- MSM_HS_ERR("%s(): Flush complete pending.\n",
- __func__);
- }
-
mutex_unlock(&msm_uport->clk_mutex);
return 0; /* come back later to really clock off */
}
spin_unlock_irqrestore(&uport->lock, flags);
+ /* Pulling RFR line high */
+ msm_hs_write(uport, UART_DM_CR, RFR_LOW);
+ /* Enable auto RFR */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+ mb();
+
/* we really want to clock off */
msm_hs_clock_unvote(msm_uport);
@@ -2077,8 +2193,6 @@
spin_unlock_irqrestore(&uport->lock, flags);
- /* Reset PNOC Bus Scaling */
- msm_hs_bus_voting(msm_uport, BUS_RESET);
mutex_unlock(&msm_uport->clk_mutex);
return 1;
@@ -2142,11 +2256,6 @@
mb();
MSM_HS_DBG("%s:Stal Interrupt\n", __func__);
- if (msm_uport->clk_req_off_state ==
- CLK_REQ_OFF_RXSTALE_ISSUED)
- msm_uport->clk_req_off_state =
- CLK_REQ_OFF_FLUSH_ISSUED;
-
if (!is_blsp_uart(msm_uport) && (rx->flush == FLUSH_NONE)) {
rx->flush = FLUSH_DATA_READY;
msm_dmov_flush(msm_uport->dma_rx_channel, 1);
@@ -2170,7 +2279,8 @@
/* Complete DMA TX transactions and submit new transactions */
/* Do not update tx_buf.tail if uart_flush_buffer already
- called in serial core */
+ * called in serial core
+ */
if (!msm_uport->tty_flush_receive)
tx_buf->tail = (tx_buf->tail +
tx->tx_count) & ~UART_XMIT_SIZE;
@@ -2207,37 +2317,57 @@
return IRQ_HANDLED;
}
-/*
- * Find UART device port using its port index value.
+/* The following two functions provide interfaces to get the underlying
+ * port structure (struct uart_port or struct msm_hs_port) given
+ * the port index. msm_hs_get_uart port is called by clients.
+ * The function msm_hs_get_hs_port is for internal use
*/
+
struct uart_port *msm_hs_get_uart_port(int port_index)
{
- int i;
+ struct uart_state *state = msm_hs_driver.state + port_index;
- for (i = 0; i < UARTDM_NR; i++) {
- if (q_uart_port[i].uport.line == port_index)
- return &q_uart_port[i].uport;
- }
+ /* The uart_driver structure stores the states in an array.
+ * Thus the corresponding offset from the drv->state returns
+ * the state for the uart_port that is requested
+ */
+ if (port_index == state->uart_port->line)
+ return state->uart_port;
return NULL;
}
EXPORT_SYMBOL(msm_hs_get_uart_port);
+static struct msm_hs_port *msm_hs_get_hs_port(int port_index)
+{
+ struct uart_port *uport = msm_hs_get_uart_port(port_index);
+ if (uport)
+ return UARTDM_TO_MSM(uport);
+ return NULL;
+}
+
/* request to turn off uart clock once pending TX is flushed */
void msm_hs_request_clock_off(struct uart_port *uport) {
unsigned long flags;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
+ int data;
spin_lock_irqsave(&uport->lock, flags);
if (msm_uport->clk_state == MSM_HS_CLK_ON) {
msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF;
- msm_uport->clk_req_off_state = CLK_REQ_OFF_START;
- msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK;
- msm_hs_write(uport, UART_DM_IMR, msm_uport->imr_reg);
- /*
- * Complete device write before retuning back.
- * Hence mb() requires here.
- */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ /*disable auto ready-for-receiving */
+ data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+ mb();
+ /* set RFR_N to high */
+ msm_hs_write(uport, UART_DM_CR, RFR_HIGH);
+
+ data = msm_hs_read(uport, UART_DM_SR);
+ MSM_HS_DBG("%s(): TXEMT, queuing clock off work\n",
+ __func__);
+ queue_work(msm_uport->hsuart_wq, &msm_uport->clock_off_w);
+
mb();
}
spin_unlock_irqrestore(&uport->lock, flags);
@@ -2254,6 +2384,15 @@
mutex_lock(&msm_uport->clk_mutex);
spin_lock_irqsave(&uport->lock, flags);
+ if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) {
+ /* Pulling RFR line high */
+ msm_hs_write(uport, UART_DM_CR, RFR_LOW);
+ /* Enable auto RFR */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data |= UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+ mb();
+ }
switch (msm_uport->clk_state) {
case MSM_HS_CLK_OFF:
wake_lock(&msm_uport->dma_wake_lock);
@@ -2263,7 +2402,7 @@
ret = msm_hs_clock_vote(msm_uport);
if (ret) {
- dev_err(uport->dev, "Clock ON Failure"
+ MSM_HS_INFO("Clock ON Failure"
"For UART CLK Stalling HSUART\n");
break;
}
@@ -2271,6 +2410,22 @@
spin_lock_irqsave(&uport->lock, flags);
/* else fall-through */
case MSM_HS_CLK_REQUEST_OFF:
+ hrtimer_cancel(&msm_uport->clk_off_timer);
+ if (msm_uport->rx.flush == FLUSH_STOP) {
+ spin_unlock_irqrestore(&uport->lock, flags);
+ MSM_HS_DBG("%s:Calling wait forxcompletion\n",
+ __func__);
+ ret = wait_event_timeout(msm_uport->bam_disconnect_wait,
+ msm_uport->rx.flush == FLUSH_SHUTDOWN, 300);
+ if (!ret)
+ MSM_HS_ERR("BAM Disconnect not happened\n");
+ spin_lock_irqsave(&uport->lock, flags);
+ MSM_HS_DBG("%s:DONE wait for completion\n", __func__);
+ }
+ MSM_HS_DBG("%s:clock state %d\n\n", __func__,
+ msm_uport->clk_state);
+ if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF)
+ msm_uport->clk_state = MSM_HS_CLK_ON;
if (msm_uport->rx.flush == FLUSH_STOP ||
msm_uport->rx.flush == FLUSH_SHUTDOWN) {
msm_hs_write(uport, UART_DM_CR, RESET_RX);
@@ -2283,7 +2438,8 @@
/* Complete above device write. Hence mb() here. */
mb();
}
- hrtimer_try_to_cancel(&msm_uport->clk_off_timer);
+
+ MSM_HS_DBG("%s: rx.flush %d\n", __func__, msm_uport->rx.flush);
if (msm_uport->rx.flush == FLUSH_SHUTDOWN) {
if (is_blsp_uart(msm_uport)) {
spin_unlock_irqrestore(&uport->lock, flags);
@@ -2294,7 +2450,7 @@
}
if (msm_uport->rx.flush == FLUSH_STOP)
msm_uport->rx.flush = FLUSH_IGNORE;
- msm_uport->clk_state = MSM_HS_CLK_ON;
+
break;
case MSM_HS_CLK_ON:
break;
@@ -2318,7 +2474,8 @@
spin_lock_irqsave(&uport->lock, flags);
if (msm_uport->clk_state == MSM_HS_CLK_OFF) {
/* ignore the first irq - it is a pending irq that occured
- * before enable_irq() */
+ * before enable_irq()
+ */
if (msm_uport->wakeup.ignore)
msm_uport->wakeup.ignore = 0;
else
@@ -2327,7 +2484,8 @@
if (wakeup) {
/* the uart was clocked off during an rx, wake up and
- * optionally inject char into tty rx */
+ * optionally inject char into tty rx
+ */
spin_unlock_irqrestore(&uport->lock, flags);
msm_hs_request_clock_on(uport);
spin_lock_irqsave(&uport->lock, flags);
@@ -2507,6 +2665,7 @@
}
}
+ msm_hs_write(uport, UARTDM_BCR_ADDR, 0x003F);
/* Set auto RFR Level */
data = msm_hs_read(uport, UART_DM_MR1);
data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
@@ -2548,6 +2707,7 @@
/* Initialize the tx */
tx->tx_ready_int_en = 0;
tx->dma_in_flight = 0;
+ rx->rx_cmd_exec = false;
msm_uport->tty_flush_receive = false;
MSM_HS_DBG("%s: Setting tty_flush_receive to false\n", __func__);
@@ -2572,7 +2732,7 @@
msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK;
/* TXLEV on empty TX fifo */
- msm_hs_write(uport, UART_DM_TFWR, 0);
+ msm_hs_write(uport, UART_DM_TFWR, 4);
/*
* Complete all device write related configuration before
* queuing RX request. Hence mb() requires here.
@@ -2606,17 +2766,12 @@
}
disable_irq(msm_uport->wakeup.irq);
}
-
- msm_hs_clock_vote(msm_uport);
-
spin_lock_irqsave(&uport->lock, flags);
msm_hs_start_rx_locked(uport);
spin_unlock_irqrestore(&uport->lock, flags);
- msm_hs_clock_unvote(msm_uport);
-
pm_runtime_enable(uport->dev);
return 0;
@@ -2652,6 +2807,7 @@
init_waitqueue_head(&rx->wait);
init_waitqueue_head(&tx->wait);
+ init_waitqueue_head(&msm_uport->bam_disconnect_wait);
wake_lock_init(&rx->wake_lock, WAKE_LOCK_SUSPEND, "msm_serial_hs_rx");
wake_lock_init(&msm_uport->dma_wake_lock, WAKE_LOCK_SUSPEND,
"msm_serial_hs_dma");
@@ -2932,7 +3088,6 @@
sps_config->mode = SPS_MODE_SRC;
sps_config->src_pipe_index = msm_uport->bam_rx_ep_pipe_index;
sps_config->dest_pipe_index = 0;
- sps_config->options = SPS_O_DESC_DONE;
} else {
/* For UART consumer transfer, source is system memory
where as destination is UART peripheral */
@@ -2941,9 +3096,9 @@
sps_config->mode = SPS_MODE_DEST;
sps_config->src_pipe_index = 0;
sps_config->dest_pipe_index = msm_uport->bam_tx_ep_pipe_index;
- sps_config->options = SPS_O_EOT;
}
+ sps_config->options = SPS_O_EOT | SPS_O_DESC_DONE | SPS_O_AUTO_ENABLE;
sps_config->event_thresh = 0x10;
/* Allocate maximum descriptor fifo size */
@@ -2963,12 +3118,11 @@
if (is_producer) {
sps_event->callback = msm_hs_sps_rx_callback;
- sps_event->options = SPS_O_DESC_DONE;
} else {
sps_event->callback = msm_hs_sps_tx_callback;
- sps_event->options = SPS_O_EOT;
}
+ sps_event->options = SPS_O_DESC_DONE | SPS_O_EOT;
sps_event->user = (void *)msm_uport;
/* Now save the sps pipe handle */
@@ -3070,6 +3224,7 @@
int core_irqres, bam_irqres, wakeup_irqres;
struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
const struct of_device_id *match;
+ unsigned long data;
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
@@ -3112,7 +3267,9 @@
return -EINVAL;
}
- msm_uport = &q_uart_port[pdev->id];
+ msm_uport = devm_kzalloc(&pdev->dev, sizeof(struct msm_hs_port),
+ GFP_KERNEL);
+ msm_uport->uport.type = PORT_UNKNOWN;
uport = &msm_uport->uport;
uport->dev = &pdev->dev;
@@ -3325,6 +3482,17 @@
*/
mb();
+ /*
+ * Set RX_BREAK_ZERO_CHAR_OFF and RX_ERROR_CHAR_OFF
+ * so any rx_break and character having parity of framing
+ * error don't enter inside UART RX FIFO.
+ */
+ data = msm_hs_read(uport, UART_DM_MR2);
+ data |= (UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF |
+ UARTDM_MR2_RX_ERROR_CHAR_OFF);
+ msm_hs_write(uport, UART_DM_MR2, data);
+ mb();
+
msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
hrtimer_init(&msm_uport->clk_off_timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
@@ -3374,17 +3542,12 @@
static int __init msm_serial_hs_init(void)
{
int ret;
- int i;
ipc_msm_hs_log_ctxt = ipc_log_context_create(IPC_MSM_HS_LOG_PAGES,
"msm_serial_hs");
if (!ipc_msm_hs_log_ctxt)
MSM_HS_WARN("%s: error creating logging context", __func__);
- /* Init all UARTS as non-configured */
- for (i = 0; i < UARTDM_NR; i++)
- q_uart_port[i].uport.type = PORT_UNKNOWN;
-
ret = uart_register_driver(&msm_hs_driver);
if (unlikely(ret)) {
MSM_HS_WARN("%s failed to load\n", __func__);
@@ -3475,12 +3638,12 @@
*/
mb();
+ msm_hs_clock_unvote(msm_uport);
if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
/* to balance clk_state */
msm_hs_clock_unvote(msm_uport);
wake_unlock(&msm_uport->dma_wake_lock);
}
- msm_hs_clock_unvote(msm_uport);
msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
dma_unmap_single(uport->dev, msm_uport->tx.dma_base,
@@ -3524,8 +3687,13 @@
{
struct platform_device *pdev = container_of(dev, struct
platform_device, dev);
- struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
- msm_hs_request_clock_on(&msm_uport->uport);
+ struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
+
+ /* This check should not fail
+ * During probe, we set uport->line to either pdev->id or userid */
+ if (msm_uport)
+ msm_hs_request_clock_on(&msm_uport->uport);
+
return 0;
}
@@ -3533,8 +3701,12 @@
{
struct platform_device *pdev = container_of(dev, struct
platform_device, dev);
- struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
- msm_hs_request_clock_off(&msm_uport->uport);
+ struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);
+
+ /* This check should not fail
+ * During probe, we set uport->line to either pdev->id or userid */
+ if (msm_uport)
+ msm_hs_request_clock_off(&msm_uport->uport);
return 0;
}
diff --git a/drivers/usb/class/ccid_bridge.c b/drivers/usb/class/ccid_bridge.c
index a3e100a..05483fd 100644
--- a/drivers/usb/class/ccid_bridge.c
+++ b/drivers/usb/class/ccid_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 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
@@ -34,7 +34,7 @@
#define CCID_BRIDGE_MSG_SZ 512
#define CCID_BRIDGE_OPEN_TIMEOUT 500 /* msec */
#define CCID_CONTROL_TIMEOUT 500 /* msec */
-#define CCID_BRIDGE_MSG_TIMEOUT 500 /* msec */
+#define CCID_BRIDGE_MSG_TIMEOUT 1000 /* msec */
struct ccid_bridge {
struct usb_device *udev;
@@ -698,6 +698,7 @@
}
usb_set_intfdata(intf, ccid);
+ usb_enable_autosuspend(ccid->udev);
mutex_lock(&ccid->open_mutex);
ccid->intf = intf;
@@ -752,6 +753,7 @@
}
ccid->intf = NULL;
+ usb_put_dev(ccid->udev);
mutex_unlock(&ccid->event_mutex);
mutex_unlock(&ccid->read_mutex);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 667a8a2..0e371d5 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -217,6 +217,7 @@
struct qpnp_adc_tm_chip *adc_tm_dev;
struct delayed_work init_adc_work;
bool id_adc_detect;
+ struct qpnp_vadc_chip *vadc_dev;
u8 dcd_retries;
u32 bus_perf_client;
struct msm_bus_scale_pdata *bus_scale_table;
@@ -2258,6 +2259,27 @@
return IRQ_HANDLED;
}
+static int
+get_prop_usbin_voltage_now(struct dwc3_msm *mdwc)
+{
+ int rc = 0;
+ struct qpnp_vadc_result results;
+
+ if (IS_ERR_OR_NULL(mdwc->vadc_dev)) {
+ mdwc->vadc_dev = qpnp_get_vadc(mdwc->dev, "usbin");
+ if (IS_ERR(mdwc->vadc_dev))
+ return PTR_ERR(mdwc->vadc_dev);
+ }
+
+ rc = qpnp_vadc_read(mdwc->vadc_dev, USBIN, &results);
+ if (rc) {
+ pr_err("Unable to read usbin rc=%d\n", rc);
+ return 0;
+ } else {
+ return results.physical;
+ }
+}
+
static int dwc3_msm_power_get_property_usb(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -2283,6 +2305,9 @@
case POWER_SUPPLY_PROP_TYPE:
val->intval = psy->type;
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = get_prop_usbin_voltage_now(mdwc);
+ break;
default:
return -EINVAL;
}
@@ -2391,6 +2416,7 @@
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_TYPE,
POWER_SUPPLY_PROP_SCOPE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
};
static void dwc3_init_adc_work(struct work_struct *w);
@@ -2635,6 +2661,30 @@
pm_runtime_put(mdwc->dev);
}
break;
+ case MSM_USB_EXT_CHG_VOLTAGE_INFO:
+ if (get_user(val, (int __user *)arg)) {
+ pr_err("%s: get_user failed\n\n", __func__);
+ ret = -EFAULT;
+ break;
+ }
+
+ if (val == USB_REQUEST_5V)
+ pr_debug("%s:voting 5V voltage request\n", __func__);
+ else if (val == USB_REQUEST_9V)
+ pr_debug("%s:voting 9V voltage request\n", __func__);
+ break;
+ case MSM_USB_EXT_CHG_RESULT:
+ if (get_user(val, (int __user *)arg)) {
+ pr_err("%s: get_user failed\n\n", __func__);
+ ret = -EFAULT;
+ break;
+ }
+
+ if (!val)
+ pr_debug("%s:voltage request successful\n", __func__);
+ else
+ pr_debug("%s:voltage request failed\n", __func__);
+ break;
default:
ret = -EINVAL;
}
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index effe0fd..16f961e 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -26,6 +26,7 @@
#include <linux/usb/gadget.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
+#include <linux/kmemleak.h>
static DEFINE_SPINLOCK(ch_lock);
static LIST_HEAD(usb_diag_ch_list);
@@ -354,28 +355,6 @@
}
/**
- * usb_diag_free_req() - Free USB requests
- * @ch: Channel handler
- *
- * This function free read and write USB requests for the interface
- * associated with this channel.
- *
- */
-void usb_diag_free_req(struct usb_diag_ch *ch)
-{
- struct diag_context *ctxt = ch->priv_usb;
- unsigned long flags;
-
- if (ctxt) {
- spin_lock_irqsave(&ctxt->lock, flags);
- free_reqs(ctxt);
- spin_unlock_irqrestore(&ctxt->lock, flags);
- }
-
-}
-EXPORT_SYMBOL(usb_diag_free_req);
-
-/**
* usb_diag_alloc_req() - Allocate USB requests
* @ch: Channel handler
* @n_write: Number of requests for Tx
@@ -403,6 +382,7 @@
req = usb_ep_alloc_request(ctxt->in, GFP_ATOMIC);
if (!req)
goto fail;
+ kmemleak_not_leak(req);
req->complete = diag_write_complete;
list_add_tail(&req->list, &ctxt->write_pool);
}
@@ -411,6 +391,7 @@
req = usb_ep_alloc_request(ctxt->out, GFP_ATOMIC);
if (!req)
goto fail;
+ kmemleak_not_leak(req);
req->complete = diag_read_complete;
list_add_tail(&req->list, &ctxt->read_pool);
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ad09139..0a82e58 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1013,9 +1013,6 @@
}
xhci = hcd_to_xhci(hcd);
- if (xhci->xhc_state & XHCI_STATE_HALTED)
- return -ENODEV;
-
if (check_virt_dev) {
if (!udev->slot_id || !xhci->devs[udev->slot_id]) {
printk(KERN_DEBUG "xHCI %s called with unaddressed "
@@ -1031,6 +1028,9 @@
}
}
+ if (xhci->xhc_state & XHCI_STATE_HALTED)
+ return -ENODEV;
+
return 1;
}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 3fa508c..15a9ab0 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -41,6 +41,7 @@
#include <linux/mfd/pm8xxx/pm8921-charger.h>
#include <linux/mfd/pm8xxx/misc.h>
#include <linux/mhl_8334.h>
+#include <linux/qpnp/qpnp-adc.h>
#include <mach/scm.h>
#include <mach/clk.h>
@@ -3645,6 +3646,27 @@
return count;
}
+static int
+otg_get_prop_usbin_voltage_now(struct msm_otg *motg)
+{
+ int rc = 0;
+ struct qpnp_vadc_result results;
+
+ if (IS_ERR_OR_NULL(motg->vadc_dev)) {
+ motg->vadc_dev = qpnp_get_vadc(motg->phy.dev, "usbin");
+ if (IS_ERR(motg->vadc_dev))
+ return PTR_ERR(motg->vadc_dev);
+ }
+
+ rc = qpnp_vadc_read(motg->vadc_dev, USBIN, &results);
+ if (rc) {
+ pr_err("Unable to read usbin rc=%d\n", rc);
+ return 0;
+ } else {
+ return results.physical;
+ }
+}
+
static int otg_power_get_property_usb(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -3674,6 +3696,9 @@
case POWER_SUPPLY_PROP_HEALTH:
val->intval = motg->usbin_health;
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = otg_get_prop_usbin_voltage_now(motg);
+ break;
default:
return -EINVAL;
}
@@ -3744,6 +3769,7 @@
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_TYPE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
};
const struct file_operations msm_otg_bus_fops = {
@@ -4027,6 +4053,30 @@
pm_runtime_put(motg->phy.dev);
}
break;
+ case MSM_USB_EXT_CHG_VOLTAGE_INFO:
+ if (get_user(val, (int __user *)arg)) {
+ pr_err("%s: get_user failed\n\n", __func__);
+ ret = -EFAULT;
+ break;
+ }
+
+ if (val == USB_REQUEST_5V)
+ pr_debug("%s:voting 5V voltage request\n", __func__);
+ else if (val == USB_REQUEST_9V)
+ pr_debug("%s:voting 9V voltage request\n", __func__);
+ break;
+ case MSM_USB_EXT_CHG_RESULT:
+ if (get_user(val, (int __user *)arg)) {
+ pr_err("%s: get_user failed\n\n", __func__);
+ ret = -EFAULT;
+ break;
+ }
+
+ if (!val)
+ pr_debug("%s:voltage request successful\n", __func__);
+ else
+ pr_debug("%s:voltage request failed\n", __func__);
+ break;
default:
ret = -EINVAL;
}
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index ca7f199..884f7f2 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -1216,6 +1216,13 @@
mutex_unlock(&ctrl_pdata->mutex);
return ret;
}
+ pinfo->panel_power_on = 1;
+ ret = mdss_dsi_panel_reset(pdata, 1);
+ if (ret) {
+ pr_err("%s: Panel reset failed\n", __func__);
+ mutex_unlock(&ctrl_pdata->mutex);
+ return ret;
+ }
msm_dsi_ahb_ctrl(1);
msm_dsi_prepare_clocks();
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index ccde545..bc76fd0 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -66,6 +66,7 @@
if (enable) {
dsi_ctrl_gpio_request(ctrl_pdata);
mdss_dsi_panel_reset(pdata, 1);
+ pdata->panel_info.panel_power_on = 1;
rc = ctrl_pdata->on(pdata);
if (rc)
pr_err("dsi_panel_handler panel on failed %d\n", rc);
@@ -73,6 +74,7 @@
if (dsi_intf.op_mode_config)
dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
rc = ctrl_pdata->off(pdata);
+ pdata->panel_info.panel_power_on = 0;
mdss_dsi_panel_reset(pdata, 0);
dsi_ctrl_gpio_free(ctrl_pdata);
}
@@ -202,75 +204,23 @@
{
int rc = 0;
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
- rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
- if (rc)
- goto gpio_request_err4;
-
- ctrl_pdata->disp_en_gpio_requested = 1;
- }
-
- if (gpio_is_valid(ctrl_pdata->rst_gpio)) {
- rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
- if (rc)
- goto gpio_request_err3;
-
- ctrl_pdata->rst_gpio_requested = 1;
- }
-
if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
if (rc)
- goto gpio_request_err2;
-
- ctrl_pdata->disp_te_gpio_requested = 1;
+ ctrl_pdata->disp_te_gpio_requested = 0;
+ else
+ ctrl_pdata->disp_te_gpio_requested = 1;
}
- if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
- rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
- if (rc)
- goto gpio_request_err1;
-
- ctrl_pdata->mode_gpio_requested = 1;
- }
-
- return rc;
-
-gpio_request_err1:
- if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
- gpio_free(ctrl_pdata->disp_te_gpio);
-gpio_request_err2:
- if (gpio_is_valid(ctrl_pdata->rst_gpio))
- gpio_free(ctrl_pdata->rst_gpio);
-gpio_request_err3:
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
-gpio_request_err4:
- ctrl_pdata->disp_en_gpio_requested = 0;
- ctrl_pdata->rst_gpio_requested = 0;
- ctrl_pdata->disp_te_gpio_requested = 0;
- ctrl_pdata->mode_gpio_requested = 0;
return rc;
}
void dsi_ctrl_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
- if (ctrl_pdata->disp_en_gpio_requested) {
- gpio_free(ctrl_pdata->disp_en_gpio);
- ctrl_pdata->disp_en_gpio_requested = 0;
- }
- if (ctrl_pdata->rst_gpio_requested) {
- gpio_free(ctrl_pdata->rst_gpio);
- ctrl_pdata->rst_gpio_requested = 0;
- }
if (ctrl_pdata->disp_te_gpio_requested) {
gpio_free(ctrl_pdata->disp_te_gpio);
ctrl_pdata->disp_te_gpio_requested = 0;
}
- if (ctrl_pdata->mode_gpio_requested) {
- gpio_free(ctrl_pdata->mode_gpio);
- ctrl_pdata->mode_gpio_requested = 0;
- }
}
static int dsi_parse_vreg(struct device *dev, struct dss_module_power *mp)
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 0cf1093..9f608b8 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -1849,7 +1849,8 @@
static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata)
{
struct mdss_panel_info *panel_info = &pdata->panel_info;
- int ab, ib, rc;
+ u64 ab, ib;
+ int rc;
pr_debug("mdp3__continuous_splash_on\n");
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index e4d8d0f..1111aeb 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -343,8 +343,8 @@
int rc = 0;
if (status) {
struct mdss_panel_info *panel_info = mfd->panel_info;
- int ab = 0;
- int ib = 0;
+ u64 ab = 0;
+ u64 ib = 0;
ab = panel_info->xres * panel_info->yres * 4;
ab *= panel_info->mipi.frame_rate;
ib = (ab * 3) / 2;
@@ -792,16 +792,16 @@
if (panel && panel->set_backlight)
panel->set_backlight(panel, 0);
- rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
- if (rc) {
- pr_err("fail to stop the MDP3 dma\n");
- goto reset_error;
- }
-
rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
if (rc)
pr_err("fail to turn off panel\n");
+ rc = mdp3_dma->stop(mdp3_dma, mdp3_session->intf);
+ if (rc) {
+ pr_err("fail to stop the MDP3 dma %d\n", rc);
+ goto reset_error;
+ }
+
rc = mdp3_put_mdp_dsi_clk();
if (rc) {
pr_err("fail to release mdp clocks\n");
@@ -1011,7 +1011,11 @@
panel = mdp3_session->panel;
if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
pr_debug("continuous splash screen, IOMMU not attached\n");
- mdp3_ctrl_reset(mfd);
+ rc = mdp3_ctrl_reset(mfd);
+ if (rc) {
+ pr_err("fail to reset display\n");
+ return -EINVAL;
+ }
reset_done = true;
}
@@ -1092,7 +1096,11 @@
if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
pr_debug("continuous splash screen, IOMMU not attached\n");
- mdp3_ctrl_reset(mfd);
+ rc = mdp3_ctrl_reset(mfd);
+ if (rc) {
+ pr_err("fail to reset display\n");
+ return;
+ }
}
mutex_lock(&mdp3_session->lock);
@@ -1608,6 +1616,43 @@
return rc;
}
+static int mdp3_overlay_prepare(struct msm_fb_data_type *mfd,
+ struct mdp_overlay_list __user *user_ovlist)
+{
+ struct mdp_overlay_list ovlist;
+ struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
+ struct mdp_overlay *req;
+ int rc;
+
+ if (!mdp3_session)
+ return -ENODEV;
+
+ req = &mdp3_session->req_overlay;
+
+ if (copy_from_user(&ovlist, user_ovlist, sizeof(ovlist)))
+ return -EFAULT;
+
+ if (ovlist.num_overlays != 1) {
+ pr_err("OV_PREPARE failed: only 1 overlay allowed\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(req, ovlist.overlay_list[0], sizeof(*req)))
+ return -EFAULT;
+
+ rc = mdp3_overlay_set(mfd, req);
+ if (!IS_ERR_VALUE(rc)) {
+ if (copy_to_user(ovlist.overlay_list[0], req, sizeof(*req)))
+ return -EFAULT;
+ }
+
+ if (put_user(IS_ERR_VALUE(rc) ? 0 : 1,
+ &user_ovlist->processed_overlays))
+ return -EFAULT;
+
+ return rc;
+}
+
static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd,
u32 cmd, void __user *argp)
{
@@ -1707,6 +1752,9 @@
if (rc)
pr_err("OVERLAY_PLAY failed (%d)\n", rc);
break;
+ case MSMFB_OVERLAY_PREPARE:
+ rc = mdp3_overlay_prepare(mfd, argp);
+ break;
default:
break;
}
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index 800c4b3..993a36f 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -18,7 +18,7 @@
#include "mdp3_hwio.h"
#define DMA_STOP_POLL_SLEEP_US 1000
-#define DMA_STOP_POLL_TIMEOUT_US 32000
+#define DMA_STOP_POLL_TIMEOUT_US 200000
#define DMA_HISTO_RESET_TIMEOUT_MS 40
#define DMA_LUT_CONFIG_MASK 0xfffffbe8
#define DMA_CCS_CONFIG_MASK 0xfffffc17
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 8cc29da8..7e590b3a 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -272,11 +272,11 @@
int ret = 1;
/*
- * wait 40 ms for ppp operation to complete before declaring
+ * wait 200 ms for ppp operation to complete before declaring
* the MDP hung
*/
ret = wait_for_completion_timeout(
- &ppp_stat->ppp_comp, msecs_to_jiffies(40));
+ &ppp_stat->ppp_comp, msecs_to_jiffies(200));
if (!ret)
pr_err("%s: Timed out waiting for the MDP.\n",
__func__);
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index ada1281..7e6faa8 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -192,6 +192,7 @@
int handoff_pending;
struct mdss_prefill_data prefill_data;
+ bool ulps;
};
extern struct mdss_data_type *mdss_res;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 44cc4a2..7b4b065 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -27,8 +27,6 @@
#include "mdss_dsi.h"
#include "mdss_debug.h"
-static unsigned char *mdss_dsi_base;
-
static int mdss_dsi_regulator_init(struct platform_device *pdev)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
@@ -74,13 +72,25 @@
goto error;
}
- if (pdata->panel_info.panel_power_on == 0)
- mdss_dsi_panel_reset(pdata, 1);
-
+ if (!pdata->panel_info.mipi.lp11_init) {
+ ret = mdss_dsi_panel_reset(pdata, 1);
+ if (ret) {
+ pr_err("%s: Panel reset failed. rc=%d\n",
+ __func__, ret);
+ if (msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 0))
+ pr_err("Disable vregs failed\n");
+ goto error;
+ }
+ }
} else {
-
- mdss_dsi_panel_reset(pdata, 0);
-
+ ret = mdss_dsi_panel_reset(pdata, 0);
+ if (ret) {
+ pr_err("%s: Panel reset failed. rc=%d\n",
+ __func__, ret);
+ goto error;
+ }
ret = msm_dss_enable_vreg(
ctrl_pdata->power_data.vreg_config,
ctrl_pdata->power_data.num_vreg, 0);
@@ -298,7 +308,7 @@
if (!pdata->panel_info.panel_power_on) {
pr_warn("%s:%d Panel already off.\n", __func__, __LINE__);
- return -EPERM;
+ return 0;
}
pdata->panel_info.panel_power_on = 0;
@@ -316,20 +326,10 @@
/* disable DSI controller */
mdss_dsi_controller_cfg(0, pdata);
- mdss_dsi_clk_ctrl(ctrl_pdata, 0);
-
- ret = mdss_dsi_enable_bus_clocks(ctrl_pdata);
- if (ret) {
- pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
- ret);
- mdss_dsi_panel_power_on(pdata, 0);
- return ret;
- }
-
/* disable DSI phy */
- mdss_dsi_phy_enable(ctrl_pdata, 0);
+ mdss_dsi_phy_disable(ctrl_pdata);
- mdss_dsi_disable_bus_clocks(ctrl_pdata);
+ mdss_dsi_clk_ctrl(ctrl_pdata, 0);
ret = mdss_dsi_panel_power_on(pdata, 0);
if (ret) {
@@ -347,63 +347,22 @@
return ret;
}
-int mdss_dsi_on(struct mdss_panel_data *pdata)
+static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata)
{
- int ret = 0;
- u32 clk_rate;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo;
struct mipi_panel_info *mipi;
+ u32 clk_rate;
u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height;
u32 ystride, bpp, data, dst_bpp;
u32 dummy_xres, dummy_yres;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
u32 hsync_period, vsync_period;
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- if (pdata->panel_info.panel_power_on) {
- pr_warn("%s:%d Panel already on.\n", __func__, __LINE__);
- return 0;
- }
-
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
- pr_debug("%s+: ctrl=%p ndx=%d\n",
- __func__, ctrl_pdata, ctrl_pdata->ndx);
-
pinfo = &pdata->panel_info;
- ret = msm_dss_enable_vreg(ctrl_pdata->power_data.vreg_config,
- ctrl_pdata->power_data.num_vreg, 1);
- if (ret) {
- pr_err("%s:Failed to enable vregs. rc=%d\n", __func__, ret);
- return ret;
- }
-
- pdata->panel_info.panel_power_on = 1;
-
- if (!pdata->panel_info.mipi.lp11_init)
- mdss_dsi_panel_reset(pdata, 1);
-
- ret = mdss_dsi_enable_bus_clocks(ctrl_pdata);
- if (ret) {
- pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
- ret);
- mdss_dsi_panel_power_on(pdata, 0);
- pdata->panel_info.panel_power_on = 0;
- return ret;
- }
-
- mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
- mdss_dsi_phy_init(pdata);
- mdss_dsi_disable_bus_clocks(ctrl_pdata);
-
- mdss_dsi_clk_ctrl(ctrl_pdata, 1);
-
clk_rate = pdata->panel_info.clk_rate;
clk_rate = min(clk_rate, pdata->panel_info.clk_max);
@@ -433,7 +392,7 @@
vsync_period = vspw + vbp + height + dummy_yres + vfp;
hsync_period = hspw + hbp + width + dummy_xres + hfp;
- mipi = &pdata->panel_info.mipi;
+ mipi = &pdata->panel_info.mipi;
if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24,
((hspw + hbp + width + dummy_xres) << 16 |
@@ -471,19 +430,195 @@
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x64, data);
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data);
}
+}
+static inline bool __mdss_dsi_ulps_feature_enabled(
+ struct mdss_panel_data *pdata)
+{
+ return pdata->panel_info.ulps_feature_enabled;
+}
+
+static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+ int enable)
+{
+ int ret = 0;
+ struct mdss_panel_data *pdata = NULL;
+ u32 lane_status = 0;
+
+ if (!ctrl_pdata) {
+ pr_err("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = &ctrl_pdata->panel_data;
+
+ if (!__mdss_dsi_ulps_feature_enabled(pdata)) {
+ pr_debug("%s: ULPS feature not supported. enable=%d\n",
+ __func__, enable);
+ return -ENOTSUPP;
+ }
+
+ if (enable && !ctrl_pdata->ulps) {
+ /* No need to configure ULPS mode when entering suspend state */
+ if (!pdata->panel_info.panel_power_on) {
+ pr_err("%s: panel off. returning\n", __func__);
+ goto error;
+ }
+
+ if (__mdss_dsi_clk_enabled(ctrl_pdata)) {
+ pr_err("%s: cannot enter ulps mode if dsi clocks are on\n",
+ __func__);
+ ret = -EPERM;
+ goto error;
+ }
+
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ /*
+ * ULPS Entry Request.
+ * Wait for a short duration to ensure that the lanes
+ * enter ULP state.
+ */
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F);
+ usleep(100);
+
+ /* Enable MMSS DSI Clamps */
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x3FF);
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x83FF);
+
+ wmb();
+
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1);
+ /* disable DSI controller */
+ mdss_dsi_controller_cfg(0, pdata);
+
+ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8),
+ mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+ ctrl_pdata->ulps = true;
+ } else if (ctrl_pdata->ulps) {
+ mdss_dsi_phy_init(pdata);
+
+ __mdss_dsi_ctrl_setup(pdata);
+ mdss_dsi_sw_reset(pdata);
+ mdss_dsi_host_init(pdata);
+ mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode,
+ pdata);
+
+ /* Disable MMSS DSI Clamps */
+ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x0);
+
+ /*
+ * ULPS Exit Request
+ * Hardware requirement is to wait for at least 1ms
+ */
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x1F00);
+ usleep(1000);
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0);
+
+ /*
+ * Wait for a short duration before enabling
+ * data transmission
+ */
+ usleep(100);
+
+ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8),
+ ctrl_pdata->ulps = false;
+ }
+
+ pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__,
+ lane_status, enable ? "enabled" : "disabled");
+
+error:
+ return ret;
+}
+
+static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
+ int enable)
+{
+ int rc;
+ struct mdss_dsi_ctrl_pdata *sctrl = NULL;
+
+ if (ctrl->flags & DSI_FLAG_CLOCK_MASTER)
+ sctrl = mdss_dsi_ctrl_slave(ctrl);
+
+ if (sctrl) {
+ pr_debug("%s: configuring ulps (%s) for slave ctrl\n",
+ __func__, (enable ? "on" : "off"));
+ rc = mdss_dsi_ulps_config_sub(sctrl, enable);
+ if (rc)
+ return rc;
+ }
+
+ pr_debug("%s: configuring ulps (%s) for master ctrl\n",
+ __func__, (enable ? "on" : "off"));
+ return mdss_dsi_ulps_config_sub(ctrl, enable);
+}
+
+int mdss_dsi_on(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+ struct mdss_panel_info *pinfo;
+ struct mipi_panel_info *mipi;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ if (pdata->panel_info.panel_power_on) {
+ pr_warn("%s:%d Panel already on.\n", __func__, __LINE__);
+ return 0;
+ }
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ pr_debug("%s+: ctrl=%p ndx=%d\n",
+ __func__, ctrl_pdata, ctrl_pdata->ndx);
+
+ pinfo = &pdata->panel_info;
+ mipi = &pdata->panel_info.mipi;
+
+ ret = mdss_dsi_panel_power_on(pdata, 1);
+ if (ret) {
+ pr_err("%s:Panel power on failed. rc=%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = mdss_dsi_bus_clk_start(ctrl_pdata);
+ if (ret) {
+ pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
+ ret);
+ ret = mdss_dsi_panel_power_on(pdata, 0);
+ if (ret) {
+ pr_err("%s: Panel reset failed. rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ pdata->panel_info.panel_power_on = 0;
+ return ret;
+ }
+ pdata->panel_info.panel_power_on = 1;
+
+ mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
+ mdss_dsi_phy_init(pdata);
+ mdss_dsi_bus_clk_stop(ctrl_pdata);
+
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+
+ __mdss_dsi_ctrl_setup(pdata);
mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(mipi, pdata);
+ mdss_dsi_host_init(pdata);
/*
* Issue hardware reset line after enabling the DSI clocks and data
* data lanes for LP11 init
*/
- if (pdata->panel_info.mipi.lp11_init)
+ if (mipi->lp11_init)
mdss_dsi_panel_reset(pdata, 1);
- if (pdata->panel_info.mipi.init_delay)
- usleep(pdata->panel_info.mipi.init_delay);
+ if (mipi->init_delay)
+ usleep(mipi->init_delay);
if (mipi->force_clk_lane_hs) {
u32 tmp;
@@ -557,6 +692,17 @@
panel_data);
mipi = &pdata->panel_info.mipi;
+ if (__mdss_dsi_ulps_feature_enabled(pdata) &&
+ (ctrl_pdata->ulps)) {
+ /* Disable ULPS mode before blanking the panel */
+ ret = mdss_dsi_ulps_config(ctrl_pdata, 0);
+ if (ret) {
+ pr_err("%s: failed to exit ULPS mode. rc=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
if (pdata->panel_info.type == MIPI_CMD_PANEL) {
@@ -603,7 +749,7 @@
"Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state);
mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(mipi, pdata);
+ mdss_dsi_host_init(pdata);
mdss_dsi_op_mode_config(mipi->mode, pdata);
if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
@@ -810,6 +956,9 @@
case MDSS_EVENT_ENABLE_PARTIAL_UPDATE:
rc = mdss_dsi_ctl_partial_update(pdata);
break;
+ case MDSS_EVENT_DSI_ULPS_CTRL:
+ rc = mdss_dsi_ulps_config(ctrl_pdata, (int)arg);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -850,35 +999,39 @@
static struct device_node *mdss_dsi_find_panel_of_node(
struct platform_device *pdev, char *panel_cfg)
{
- int l;
- int ctrl_id = -1;
- char *panel_name;
+ int len, i;
+ int ctrl_id = pdev->id - 1;
+ char panel_name[MDSS_MAX_PANEL_LEN];
+ char ctrl_id_stream[3] = "0:";
+ char *stream = NULL, *pan = NULL;
struct device_node *dsi_pan_node = NULL, *mdss_node = NULL;
- l = strlen(panel_cfg);
- if (!l) {
+ len = strlen(panel_cfg);
+ if (!len) {
/* no panel cfg chg, parse dt */
pr_debug("%s:%d: no cmd line cfg present\n",
__func__, __LINE__);
- dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
+ goto end;
} else {
- if (panel_cfg[0] == '0') {
- pr_debug("%s:%d: DSI ctrl 1\n", __func__, __LINE__);
- ctrl_id = 0;
- } else if (panel_cfg[0] == '1') {
- pr_debug("%s:%d: DSI ctrl 2\n", __func__, __LINE__);
- ctrl_id = 1;
+ if (ctrl_id == 1)
+ strlcpy(ctrl_id_stream, "1:", 3);
+
+ stream = strnstr(panel_cfg, ctrl_id_stream, len);
+ if (!stream) {
+ pr_err("controller config is not present\n");
+ goto end;
}
- if ((pdev->id - 1) != ctrl_id) {
- pr_err("%s:%d:pdev_ID=[%d]\n",
- __func__, __LINE__, pdev->id);
- return NULL;
+ stream += 2;
+
+ pan = strnchr(stream, strlen(stream), ':');
+ if (!pan) {
+ strlcpy(panel_name, stream, MDSS_MAX_PANEL_LEN);
+ } else {
+ for (i = 0; (stream + i) < pan; i++)
+ panel_name[i] = *(stream + i);
+ panel_name[i] = 0;
}
- /*
- * skip first two chars '<dsi_ctrl_id>' and
- * ':' to get to the panel name
- */
- panel_name = panel_cfg + 2;
+
pr_debug("%s:%d:%s:%s\n", __func__, __LINE__,
panel_cfg, panel_name);
@@ -895,9 +1048,12 @@
if (!dsi_pan_node) {
pr_err("%s: invalid pan node, selecting prim panel\n",
__func__);
- dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
+ goto end;
}
+ return dsi_pan_node;
}
+end:
+ dsi_pan_node = mdss_dsi_pref_prim_panel(pdev);
return dsi_pan_node;
}
@@ -909,7 +1065,6 @@
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct device_node *dsi_pan_node = NULL;
char panel_cfg[MDSS_MAX_PANEL_LEN];
- struct resource *mdss_dsi_mres;
const char *ctrl_name;
bool cmd_cfg_cont_splash = true;
@@ -959,30 +1114,13 @@
else
pdev->id = 2;
- mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mdss_dsi_mres) {
- pr_err("%s:%d unable to get the MDSS resources",
- __func__, __LINE__);
- rc = -ENOMEM;
- goto error_no_mem;
- }
-
- mdss_dsi_base = ioremap(mdss_dsi_mres->start,
- resource_size(mdss_dsi_mres));
- if (!mdss_dsi_base) {
- pr_err("%s:%d unable to remap dsi resources",
- __func__, __LINE__);
- rc = -ENOMEM;
- goto error_no_mem;
- }
-
rc = of_platform_populate(pdev->dev.of_node,
NULL, NULL, &pdev->dev);
if (rc) {
dev_err(&pdev->dev,
"%s: failed to add child nodes, rc=%d\n",
__func__, rc);
- goto error_ioremap;
+ goto error_no_mem;
}
/* Parse the regulator information */
@@ -1029,8 +1167,6 @@
of_node_put(dsi_pan_node);
error_vreg:
mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
-error_ioremap:
- iounmap(mdss_dsi_base);
error_no_mem:
devm_kfree(&pdev->dev, ctrl_pdata);
@@ -1053,7 +1189,7 @@
pr_err("%s: failed to de-init vregs\n", __func__);
mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->power_data);
mfd = platform_get_drvdata(pdev);
- iounmap(mdss_dsi_base);
+ msm_dss_iounmap(&ctrl_pdata->mmss_misc_io);
return 0;
}
@@ -1112,6 +1248,13 @@
pr_info("%s: dsi base=%x size=%x\n",
__func__, (int)ctrl->ctrl_base, ctrl->reg_size);
+ rc = msm_dss_ioremap_byname(pdev, &ctrl->mmss_misc_io,
+ "mmss_misc_phys");
+ if (rc) {
+ pr_err("%s:%d mmss_misc IO remap failed\n", __func__, __LINE__);
+ return rc;
+ }
+
return 0;
}
@@ -1249,18 +1392,9 @@
ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
"qcom,platform-enable-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+ if (!gpio_is_valid(ctrl_pdata->disp_en_gpio))
pr_err("%s:%d, Disp_en gpio not specified\n",
__func__, __LINE__);
- } else {
- rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
- if (rc) {
- pr_err("request reset gpio failed, rc=%d\n",
- rc);
- gpio_free(ctrl_pdata->disp_en_gpio);
- return -ENODEV;
- }
- }
if (pinfo->type == MIPI_CMD_PANEL) {
ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
@@ -1277,7 +1411,6 @@
if (rc) {
pr_err("request TE gpio failed, rc=%d\n",
rc);
- gpio_free(ctrl_pdata->disp_te_gpio);
return -ENODEV;
}
rc = gpio_tlmm_config(GPIO_CFG(
@@ -1307,44 +1440,18 @@
ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
"qcom,platform-reset-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
+ if (!gpio_is_valid(ctrl_pdata->rst_gpio))
pr_err("%s:%d, reset gpio not specified\n",
__func__, __LINE__);
- } else {
- rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
- if (rc) {
- pr_err("request reset gpio failed, rc=%d\n",
- rc);
- gpio_free(ctrl_pdata->rst_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
- return -ENODEV;
- }
- }
if (pinfo->mode_gpio_state != MODE_GPIO_NOT_VALID) {
ctrl_pdata->mode_gpio = of_get_named_gpio(
ctrl_pdev->dev.of_node,
"qcom,platform-mode-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->mode_gpio)) {
+ if (!gpio_is_valid(ctrl_pdata->mode_gpio))
pr_info("%s:%d, mode gpio not specified\n",
__func__, __LINE__);
- } else {
- rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
- if (rc) {
- pr_err("request panel mode gpio failed,rc=%d\n",
- rc);
- gpio_free(ctrl_pdata->mode_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
- if (gpio_is_valid(ctrl_pdata->rst_gpio))
- gpio_free(ctrl_pdata->rst_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
- gpio_free(ctrl_pdata->disp_te_gpio);
- return -ENODEV;
- }
- }
}
if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) {
@@ -1395,10 +1502,6 @@
rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
if (rc) {
pr_err("%s: unable to register MIPI DSI panel\n", __func__);
- if (ctrl_pdata->rst_gpio)
- gpio_free(ctrl_pdata->rst_gpio);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_free(ctrl_pdata->disp_en_gpio);
return rc;
}
@@ -1453,7 +1556,6 @@
static void __exit mdss_dsi_driver_cleanup(void)
{
- iounmap(mdss_dsi_base);
platform_driver_unregister(&mdss_dsi_ctrl_driver);
}
module_exit(mdss_dsi_driver_cleanup);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index b89a935..57b0e75 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -227,6 +227,8 @@
#define DSI_EV_MDP_FIFO_UNDERFLOW 0x0002
#define DSI_EV_MDP_BUSY_RELEASE 0x80000000
+#define DSI_FLAG_CLOCK_MASTER 0x80000000
+
struct mdss_dsi_ctrl_pdata {
int ndx; /* panel_num */
int (*on) (struct mdss_panel_data *pdata);
@@ -236,11 +238,15 @@
int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
struct mdss_panel_data panel_data;
unsigned char *ctrl_base;
+ struct dss_io_data mmss_misc_io;
int reg_size;
u32 clk_cnt;
+ int clk_cnt_sub;
+ u32 flags;
struct clk *mdp_core_clk;
struct clk *ahb_clk;
struct clk *axi_clk;
+ struct clk *mmss_misc_ahb_clk;
struct clk *byte_clk;
struct clk *esc_clk;
struct clk *pixel_clk;
@@ -252,10 +258,7 @@
int disp_en_gpio;
int disp_te_gpio;
int mode_gpio;
- int rst_gpio_requested;
- int disp_en_gpio_requested;
int disp_te_gpio_requested;
- int mode_gpio_requested;
int bklt_ctrl; /* backlight ctrl */
int pwm_period;
int pwm_pmic_gpio;
@@ -286,6 +289,8 @@
struct mutex mutex;
struct mutex cmd_mutex;
+ bool ulps;
+
struct dsi_buf tx_buf;
struct dsi_buf rx_buf;
};
@@ -299,8 +304,7 @@
int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_cmd_desc *cmds, int rlen);
-void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
- struct mdss_panel_data *pdata);
+void mdss_dsi_host_init(struct mdss_panel_data *pdata);
void mdss_dsi_op_mode_config(int mode,
struct mdss_panel_data *pdata);
void mdss_dsi_cmd_mode_ctrl(int enable);
@@ -308,13 +312,20 @@
void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl);
-int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
+void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
+int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl);
+int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl,
int enable);
void mdss_dsi_controller_cfg(int enable,
struct mdss_panel_data *pdata);
void mdss_dsi_sw_reset(struct mdss_panel_data *pdata);
+struct mdss_dsi_ctrl_pdata *mdss_dsi_ctrl_slave(
+ struct mdss_dsi_ctrl_pdata *ctrl);
+
irqreturn_t mdss_dsi_isr(int irq, void *ptr);
void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
@@ -326,8 +337,8 @@
void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
-void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
-void mdss_dsi_phy_enable(struct mdss_dsi_ctrl_pdata *ctrl, int on);
+int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
+void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
void mdss_dsi_cmd_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl);
@@ -340,6 +351,7 @@
int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
void mdss_dsi_cmdlist_kickoff(int intf);
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
+bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index bd156fc..c2fbc1a 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -92,6 +92,10 @@
ctrl_list[ctrl->ndx] = ctrl; /* keep it */
+ if (ctrl->shared_pdata.broadcast_enable)
+ if (ctrl->ndx == DSI_CTRL_1)
+ ctrl->flags |= DSI_FLAG_CLOCK_MASTER;
+
if (mdss_register_irq(ctrl->dsi_hw))
pr_err("%s: mdss_register_irq failed.\n", __func__);
@@ -117,6 +121,22 @@
}
}
+struct mdss_dsi_ctrl_pdata *mdss_dsi_ctrl_slave(
+ struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ int ndx;
+ struct mdss_dsi_ctrl_pdata *sctrl = NULL;
+
+ /* only two controllers */
+ ndx = ctrl->ndx;
+ ndx += 1;
+ ndx %= DSI_CTRL_MAX;
+ sctrl = ctrl_list[ndx];
+
+ return sctrl;
+
+}
+
void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
{
if (enable == 0) {
@@ -230,12 +250,12 @@
MIPI_OUTP((ctrl->ctrl_base) + 0x015c, 0x0);
}
-void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
- struct mdss_panel_data *pdata)
+void mdss_dsi_host_init(struct mdss_panel_data *pdata)
{
u32 dsi_ctrl, intr_ctrl;
u32 data;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mipi_panel_info *pinfo = NULL;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
@@ -245,6 +265,8 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+ pinfo = &pdata->panel_info.mipi;
+
pinfo->rgb_swap = DSI_RGB_SWAP_RGB;
ctrl_pdata->panel_mode = pinfo->mode;
@@ -1457,13 +1479,15 @@
u32 isr0;
isr0 = MIPI_INP(left_ctrl_pdata->ctrl_base
+ 0x0110);/* DSI_INTR_CTRL */
- MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0);
+ if (isr0 & DSI_INTR_CMD_DMA_DONE)
+ MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110,
+ DSI_INTR_CMD_DMA_DONE);
}
- pr_debug("%s: isr=%x", __func__, isr);
+ pr_debug("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr);
if (isr & DSI_INTR_ERROR) {
- pr_err("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
+ pr_err("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr);
mdss_dsi_error(ctrl);
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 76e6d1b..5415a7e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -153,15 +153,53 @@
mdss_dsi_cmdlist_put(ctrl, &cmdreq);
}
-void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
+static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ int rc = 0;
+
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+ rc = gpio_request(ctrl_pdata->disp_en_gpio,
+ "disp_enable");
+ if (rc) {
+ pr_err("request disp_en gpio failed, rc=%d\n",
+ rc);
+ goto disp_en_gpio_err;
+ }
+ }
+ rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
+ if (rc) {
+ pr_err("request reset gpio failed, rc=%d\n",
+ rc);
+ goto rst_gpio_err;
+ }
+ if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
+ rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
+ if (rc) {
+ pr_err("request panel mode gpio failed,rc=%d\n",
+ rc);
+ goto mode_gpio_err;
+ }
+ }
+ return rc;
+
+mode_gpio_err:
+ gpio_free(ctrl_pdata->rst_gpio);
+rst_gpio_err:
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_free(ctrl_pdata->disp_en_gpio);
+disp_en_gpio_err:
+ return rc;
+}
+
+int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo = NULL;
- int i;
+ int i, rc = 0;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
- return;
+ return -EINVAL;
}
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
@@ -175,21 +213,28 @@
if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
pr_debug("%s:%d, reset line not configured\n",
__func__, __LINE__);
- return;
+ return rc;
}
pr_debug("%s: enable = %d\n", __func__, enable);
pinfo = &(ctrl_pdata->panel_data.panel_info);
if (enable) {
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
- gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+ rc = mdss_dsi_request_gpios(ctrl_pdata);
+ if (rc) {
+ pr_err("gpio request failed\n");
+ return rc;
+ }
+ if (!pinfo->panel_power_on) {
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
- for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) {
- gpio_set_value((ctrl_pdata->rst_gpio),
- pdata->panel_info.rst_seq[i]);
- if (pdata->panel_info.rst_seq[++i])
- usleep(pdata->panel_info.rst_seq[i] * 1000);
+ for (i = 0; i < pdata->panel_info.rst_seq_len; ++i) {
+ gpio_set_value((ctrl_pdata->rst_gpio),
+ pdata->panel_info.rst_seq[i]);
+ if (pdata->panel_info.rst_seq[++i])
+ usleep(pinfo->rst_seq[i] * 1000);
+ }
}
if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
@@ -205,10 +250,16 @@
pr_debug("%s: Reset panel done\n", __func__);
}
} else {
- gpio_set_value((ctrl_pdata->rst_gpio), 0);
- if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+ if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
+ gpio_free(ctrl_pdata->disp_en_gpio);
+ }
+ gpio_set_value((ctrl_pdata->rst_gpio), 0);
+ gpio_free(ctrl_pdata->rst_gpio);
+ if (gpio_is_valid(ctrl_pdata->mode_gpio))
+ gpio_free(ctrl_pdata->mode_gpio);
}
+ return rc;
}
static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00}; /* DTYPE_DCS_LWRITE */
@@ -266,6 +317,17 @@
return rc;
}
+static struct mdss_dsi_ctrl_pdata *get_rctrl_data(struct mdss_panel_data *pdata)
+{
+ if (!pdata || !pdata->next) {
+ pr_err("%s: Invalid panel data\n", __func__);
+ return NULL;
+ }
+
+ return container_of(pdata->next, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+}
+
static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
u32 bl_level)
{
@@ -297,6 +359,16 @@
break;
case BL_DCS_CMD:
mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);
+ if (ctrl_pdata->shared_pdata.broadcast_enable &&
+ ctrl_pdata->ndx == DSI_CTRL_0) {
+ struct mdss_dsi_ctrl_pdata *rctrl_pdata = NULL;
+ rctrl_pdata = get_rctrl_data(pdata);
+ if (!rctrl_pdata) {
+ pr_err("%s: Right ctrl data NULL\n", __func__);
+ return;
+ }
+ mdss_dsi_panel_bklt_dcs(rctrl_pdata, bl_level);
+ }
break;
default:
pr_err("%s: Unknown bl_ctrl configuration\n",
@@ -632,6 +704,35 @@
return 0;
}
+static int mdss_dsi_parse_panel_features(struct device_node *np,
+ struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ struct mdss_panel_info *pinfo;
+
+ if (!np || !ctrl) {
+ pr_err("%s: Invalid arguments\n", __func__);
+ return -ENODEV;
+ }
+
+ pinfo = &ctrl->panel_data.panel_info;
+
+ pinfo->cont_splash_enabled = of_property_read_bool(np,
+ "qcom,cont-splash-enabled");
+
+ pinfo->partial_update_enabled = of_property_read_bool(np,
+ "qcom,partial-update-enabled");
+ pr_info("%s:%d Partial update %s\n", __func__, __LINE__,
+ (pinfo->partial_update_enabled ? "enabled" : "disabled"));
+ if (pinfo->partial_update_enabled)
+ ctrl->partial_update_fnc = mdss_dsi_panel_partial_update;
+
+ pinfo->ulps_feature_enabled = of_property_read_bool(np,
+ "qcom,ulps-enabled");
+ pr_info("%s: ulps feature %s", __func__,
+ (pinfo->ulps_feature_enabled ? "enabled" : "disabled"));
+
+ return 0;
+}
static int mdss_panel_parse_dt(struct device_node *np,
struct mdss_dsi_ctrl_pdata *ctrl_pdata)
@@ -856,6 +957,11 @@
rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp);
pinfo->mipi.t_clk_post = (!rc ? tmp : 0x03);
+ pinfo->mipi.rx_eot_ignore = of_property_read_bool(np,
+ "qcom,mdss-dsi-rx-eot-ignore");
+ pinfo->mipi.tx_eot_append = of_property_read_bool(np,
+ "qcom,mdss-dsi-tx-eot-append");
+
rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp);
pinfo->mipi.stream = (!rc ? tmp : 0);
@@ -906,6 +1012,12 @@
mdss_dsi_parse_dcs_cmds(np, &ctrl_pdata->off_cmds,
"qcom,mdss-dsi-off-command", "qcom,mdss-dsi-off-command-state");
+ rc = mdss_dsi_parse_panel_features(np, ctrl_pdata);
+ if (rc) {
+ pr_err("%s: failed to parse panel features\n", __func__);
+ goto error;
+ }
+
return 0;
error:
@@ -918,14 +1030,15 @@
{
int rc = 0;
static const char *panel_name;
- bool cont_splash_enabled;
- bool partial_update_enabled;
+ struct mdss_panel_info *pinfo;
- if (!node) {
- pr_err("%s: no panel node\n", __func__);
+ if (!node || !ctrl_pdata) {
+ pr_err("%s: Invalid arguments\n", __func__);
return -ENODEV;
}
+ pinfo = &ctrl_pdata->panel_data.panel_info;
+
pr_debug("%s:%d\n", __func__, __LINE__);
panel_name = of_get_property(node, "qcom,mdss-dsi-panel-name", NULL);
if (!panel_name)
@@ -940,33 +1053,10 @@
return rc;
}
- if (cmd_cfg_cont_splash)
- cont_splash_enabled = of_property_read_bool(node,
- "qcom,cont-splash-enabled");
- else
- cont_splash_enabled = false;
- if (!cont_splash_enabled) {
- pr_info("%s:%d Continuous splash flag not found.\n",
- __func__, __LINE__);
- ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 0;
- } else {
- pr_info("%s:%d Continuous splash flag enabled.\n",
- __func__, __LINE__);
-
- ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
- }
-
- partial_update_enabled = of_property_read_bool(node,
- "qcom,partial-update-enabled");
- if (partial_update_enabled) {
- pr_info("%s:%d Partial update enabled.\n", __func__, __LINE__);
- ctrl_pdata->panel_data.panel_info.partial_update_enabled = 1;
- ctrl_pdata->partial_update_fnc = mdss_dsi_panel_partial_update;
- } else {
- pr_info("%s:%d Partial update disabled.\n", __func__, __LINE__);
- ctrl_pdata->panel_data.panel_info.partial_update_enabled = 0;
- ctrl_pdata->partial_update_fnc = NULL;
- }
+ if (!cmd_cfg_cont_splash)
+ pinfo->cont_splash_enabled = false;
+ pr_info("%s: Continuous splash %s", __func__,
+ pinfo->cont_splash_enabled ? "enabled" : "disabled");
ctrl_pdata->on = mdss_dsi_panel_on;
ctrl_pdata->off = mdss_dsi_panel_off;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 1df2903..252a86e 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1214,9 +1214,11 @@
struct mdss_fb_proc_info *pinfo = NULL;
int result;
int pid = current->tgid;
+ struct task_struct *task = current->group_leader;
if (mfd->shutdown_pending) {
- pr_err("Shutdown pending. Aborting operation\n");
+ pr_err("Shutdown pending. Aborting operation. Request from pid:%d name=%s\n",
+ pid, task->comm);
return -EPERM;
}
@@ -2213,7 +2215,8 @@
mdss_fb_power_setting_idle(mfd);
if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
(cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT) &&
- (cmd != MSMFB_NOTIFY_UPDATE)) {
+ (cmd != MSMFB_NOTIFY_UPDATE) &&
+ (cmd != MSMFB_OVERLAY_PREPARE)) {
ret = mdss_fb_pan_idle(mfd);
if (ret) {
pr_debug("Shutdown pending. Aborting operation %x\n",
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 79afdca..cd2f8e4 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -3872,6 +3872,7 @@
static const struct of_device_id hdmi_tx_dt_match[] = {
{.compatible = COMPATIBLE_NAME,},
+ { /* Sentinel */ },
};
MODULE_DEVICE_TABLE(of, hdmi_tx_dt_match);
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 088472f..cfa594c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1044,6 +1044,14 @@
return rc;
}
+/**
+ * mdss_mdp_footswitch_ctrl_splash() - clocks handoff for cont. splash screen
+ * @on: 1 to start handoff, 0 to complete the handoff after first frame update
+ *
+ * MDSS Clocks and GDSC are already on during continous splash screen, but
+ * increasing ref count will keep clocks from being turned off until handoff
+ * has properly happend after frame update.
+ */
void mdss_mdp_footswitch_ctrl_splash(int on)
{
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -1052,9 +1060,11 @@
pr_debug("Enable MDP FS for splash.\n");
mdata->handoff_pending = true;
regulator_enable(mdata->fs);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_hw_init(mdata);
} else {
pr_debug("Disable MDP FS for splash.\n");
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
regulator_disable(mdata->fs);
mdata->handoff_pending = false;
}
@@ -1080,6 +1090,7 @@
SPRINT("dma_pipes=%d\n", mdata->ndma_pipes);
SPRINT("smp_count=%d\n", mdata->smp_mb_cnt);
SPRINT("smp_size=%d\n", mdata->smp_mb_size);
+ SPRINT("smp_mb_per_pipe=%d\n", mdata->smp_mb_per_pipe);
SPRINT("max_downscale_ratio=%d\n", MAX_DOWNSCALE_RATIO);
SPRINT("max_upscale_ratio=%d\n", MAX_UPSCALE_RATIO);
if (mdata->max_bw_low)
@@ -2394,8 +2405,10 @@
pr_debug("Enable MDP FS\n");
if (!mdata->fs_ena) {
regulator_enable(mdata->fs);
- mdss_mdp_cx_ctrl(mdata, true);
- mdss_mdp_batfet_ctrl(mdata, true);
+ if (!mdata->ulps) {
+ mdss_mdp_cx_ctrl(mdata, true);
+ mdss_mdp_batfet_ctrl(mdata, true);
+ }
}
mdata->fs_ena = true;
} else {
@@ -2403,13 +2416,41 @@
mdss_iommu_dettach(mdata);
if (mdata->fs_ena) {
regulator_disable(mdata->fs);
- mdss_mdp_cx_ctrl(mdata, false);
- mdss_mdp_batfet_ctrl(mdata, false);
+ if (!mdata->ulps) {
+ mdss_mdp_cx_ctrl(mdata, false);
+ mdss_mdp_batfet_ctrl(mdata, false);
+ }
}
mdata->fs_ena = false;
}
}
+/**
+ * mdss_mdp_footswitch_ctrl_ulps() - MDSS GDSC control with ULPS feature
+ * @on: 1 to turn on footswitch, 0 to turn off footswitch
+ * @dev: framebuffer device node
+ *
+ * MDSS GDSC can be voted off during idle-screen usecase for MIPI DSI command
+ * mode displays with Ultra-Low Power State (ULPS) feature enabled. Upon
+ * subsequent frame update, MDSS GDSC needs to turned back on and hw state
+ * needs to be restored.
+ */
+void mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+ pr_debug("called on=%d\n", on);
+ if (on) {
+ pm_runtime_get_sync(dev);
+ mdss_iommu_attach(mdata);
+ mdss_hw_init(mdata);
+ mdata->ulps = false;
+ } else {
+ mdata->ulps = true;
+ pm_runtime_put_sync(dev);
+ }
+}
+
static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
{
mdata->suspend_fs_ena = mdata->fs_ena;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 9d200b9..9a469a4 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -319,6 +319,7 @@
uint32_t bl_bright_shift;
uint32_t bl_lin[AD_BL_LIN_LEN];
uint32_t bl_lin_inv[AD_BL_LIN_LEN];
+ uint32_t bl_att_lut[AD_BL_ATT_LUT_LEN];
};
struct pp_sts_type {
@@ -528,6 +529,9 @@
int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff);
int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
+int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_pipe **left_plist, int left_cnt,
+ struct mdss_mdp_pipe **right_plist, int right_cnt);
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi);
int mdss_mdp_ctl_notify(struct mdss_mdp_ctl *ctl, int event);
@@ -677,6 +681,8 @@
int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable);
int mdss_mdp_wb_get_secure(struct msm_fb_data_type *mfd, uint8_t *enable);
+void mdss_mdp_ctl_restore(struct mdss_mdp_ctl *ctl);
+void mdss_mdp_footswitch_ctrl_ulps(int on, struct device *dev);
int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 1a4885c..fa64448 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -427,7 +427,8 @@
}
static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
- struct mdss_mdp_perf_params *perf)
+ struct mdss_mdp_perf_params *perf,
+ struct mdss_mdp_pipe **pipe_list, int num_pipes)
{
struct mdss_mdp_pipe *pipe;
struct mdss_panel_info *pinfo = NULL;
@@ -436,10 +437,12 @@
int i;
u32 max_clk_rate = 0;
u64 bw_overlap_max = 0;
- u64 bw_overlap[MDSS_MDP_MAX_STAGE];
- u32 v_region[MDSS_MDP_MAX_STAGE * 2];
+ u64 bw_overlap[MDSS_MDP_MAX_STAGE] = { 0 };
+ u32 v_region[MDSS_MDP_MAX_STAGE * 2] = { 0 };
u32 prefill_bytes = 0;
+ BUG_ON(num_pipes > MDSS_MDP_MAX_STAGE);
+
memset(perf, 0, sizeof(*perf));
if (!mixer->rotator_mode) {
@@ -466,9 +469,9 @@
memset(bw_overlap, 0, sizeof(u64) * MDSS_MDP_MAX_STAGE);
memset(v_region, 0, sizeof(u32) * MDSS_MDP_MAX_STAGE * 2);
- for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
+ for (i = 0; i < num_pipes; i++) {
struct mdss_mdp_perf_params tmp;
- pipe = mixer->stage_pipe[i];
+ pipe = pipe_list[i];
if (pipe == NULL)
continue;
@@ -488,8 +491,8 @@
* data for each region and sum them up, then the worst case
* of all regions is ib request.
*/
- sort(v_region, MDSS_MDP_MAX_STAGE * 2, sizeof(u32), cmpu32, NULL);
- for (i = 1; i < MDSS_MDP_MAX_STAGE * 2; i++) {
+ sort(v_region, num_pipes * 2, sizeof(u32), cmpu32, NULL);
+ for (i = 1; i < num_pipes * 2; i++) {
int j;
u64 bw_max_region = 0;
u32 y0, y1;
@@ -498,10 +501,10 @@
continue;
y0 = (v_region[i-1]) ? v_region[i-1] + 1 : 0;
y1 = v_region[i];
- for (j = 0; j < MDSS_MDP_MAX_STAGE; j++) {
+ for (j = 0; j < num_pipes; j++) {
if (!bw_overlap[j])
continue;
- pipe = mixer->stage_pipe[j];
+ pipe = pipe_list[j];
if (mdss_mdp_perf_is_overlap(y0, y1, pipe->dst.y,
(pipe->dst.y + pipe->dst.h)))
bw_max_region += bw_overlap[j];
@@ -566,22 +569,26 @@
return vbp_max;
}
-static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,
- struct mdss_mdp_perf_params *perf)
+static void __mdss_mdp_perf_calc_ctl_helper(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_perf_params *perf,
+ struct mdss_mdp_pipe **left_plist, int left_cnt,
+ struct mdss_mdp_pipe **right_plist, int right_cnt)
{
struct mdss_mdp_perf_params tmp;
memset(perf, 0, sizeof(*perf));
- if (ctl->mixer_left) {
- mdss_mdp_perf_calc_mixer(ctl->mixer_left, &tmp);
+ if (left_cnt && ctl->mixer_left) {
+ mdss_mdp_perf_calc_mixer(ctl->mixer_left, &tmp,
+ left_plist, left_cnt);
perf->bw_overlap += tmp.bw_overlap;
perf->prefill_bytes += tmp.prefill_bytes;
perf->mdp_clk_rate = tmp.mdp_clk_rate;
}
- if (ctl->mixer_right) {
- mdss_mdp_perf_calc_mixer(ctl->mixer_right, &tmp);
+ if (right_cnt && ctl->mixer_right) {
+ mdss_mdp_perf_calc_mixer(ctl->mixer_right, &tmp,
+ right_plist, right_cnt);
perf->bw_overlap += tmp.bw_overlap;
perf->prefill_bytes += tmp.prefill_bytes;
if (tmp.mdp_clk_rate > perf->mdp_clk_rate)
@@ -618,6 +625,47 @@
if (ctl->is_video_mode)
perf->bw_ctl = IB_FUDGE_FACTOR(perf->bw_ctl);
+}
+
+int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_pipe **left_plist, int left_cnt,
+ struct mdss_mdp_pipe **right_plist, int right_cnt)
+{
+ struct mdss_data_type *mdata = ctl->mdata;
+ struct mdss_mdp_perf_params perf;
+ u32 bw, threshold;
+
+ /* we only need bandwidth check on real-time clients (interfaces) */
+ if (ctl->intf_type == MDSS_MDP_NO_INTF)
+ return 0;
+
+ __mdss_mdp_perf_calc_ctl_helper(ctl, &perf,
+ left_plist, left_cnt, right_plist, right_cnt);
+
+ /* convert bandwidth to kb */
+ bw = DIV_ROUND_UP_ULL(perf.bw_ctl, 1000);
+ pr_debug("calculated bandwidth=%uk\n", bw);
+
+ threshold = ctl->is_video_mode ? mdata->max_bw_low : mdata->max_bw_high;
+ if (bw > threshold) {
+ pr_debug("exceeds bandwidth: %ukb > %ukb\n", bw, threshold);
+ return -E2BIG;
+ }
+
+ return 0;
+}
+
+static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_perf_params *perf)
+{
+ struct mdss_mdp_pipe **left_plist, **right_plist;
+
+ left_plist = ctl->mixer_left ? ctl->mixer_left->stage_pipe : NULL;
+ right_plist = ctl->mixer_right ? ctl->mixer_right->stage_pipe : NULL;
+
+ __mdss_mdp_perf_calc_ctl_helper(ctl, perf,
+ left_plist, (left_plist ? MDSS_MDP_MAX_STAGE : 0),
+ right_plist, (right_plist ? MDSS_MDP_MAX_STAGE : 0));
pr_debug("ctl=%d clk_rate=%u\n", ctl->num, perf->mdp_clk_rate);
pr_debug("bw_overlap=%llu bw_prefill=%llu prefill_byptes=%d\n",
@@ -1085,8 +1133,21 @@
return 0;
}
+static inline struct mdss_mdp_ctl *mdss_mdp_get_split_ctl(
+ struct mdss_mdp_ctl *ctl)
+{
+ if (ctl && ctl->mixer_right && (ctl->mixer_right->ctl != ctl))
+ return ctl->mixer_right->ctl;
+
+ return NULL;
+}
+
int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff)
{
+ struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl);
+ if (sctl)
+ sctl->panel_data->panel_info.cont_splash_enabled = 0;
+
switch (ctl->panel_data->panel_info.type) {
case MIPI_VIDEO_PANEL:
case EDP_PANEL:
@@ -1111,15 +1172,6 @@
return 0;
}
-static inline struct mdss_mdp_ctl *mdss_mdp_get_split_ctl(
- struct mdss_mdp_ctl *ctl)
-{
- if (ctl && ctl->mixer_right && (ctl->mixer_right->ctl != ctl))
- return ctl->mixer_right->ctl;
-
- return NULL;
-}
-
static int mdss_mdp_ctl_fbc_enable(int enable,
struct mdss_mdp_mixer *mixer, struct mdss_panel_info *pdata)
{
@@ -1536,6 +1588,25 @@
return rc;
}
+/*
+ * mdss_mdp_ctl_restore() - restore mdp ctl path
+ * @ctl: mdp controller.
+ *
+ * This function is called whenever MDP comes out of a power collapse as
+ * a result of a screen update when DSI ULPS mode is enabled. It restores
+ * the MDP controller's software state to the hardware registers.
+ */
+void mdss_mdp_ctl_restore(struct mdss_mdp_ctl *ctl)
+{
+ u32 temp;
+
+ temp = readl_relaxed(ctl->mdata->mdp_base +
+ MDSS_MDP_REG_DISP_INTF_SEL);
+ temp |= (ctl->intf_type << ((ctl->intf_num - MDSS_MDP_INTF0) * 8));
+ writel_relaxed(temp, ctl->mdata->mdp_base +
+ MDSS_MDP_REG_DISP_INTF_SEL);
+}
+
static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
{
struct mdss_mdp_mixer *mixer;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index ce0b757..8c7dc29 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -27,6 +27,7 @@
#define KOFF_TIMEOUT msecs_to_jiffies(84)
#define STOP_TIMEOUT msecs_to_jiffies(16 * (VSYNC_EXPIRE_TICK + 2))
+#define ULPS_ENTER_TIME msecs_to_jiffies(100)
struct mdss_mdp_cmd_ctx {
struct mdss_mdp_ctl *ctl;
@@ -43,6 +44,7 @@
struct mutex clk_mtx;
spinlock_t clk_lock;
struct work_struct clk_work;
+ struct delayed_work ulps_work;
struct work_struct pp_done_work;
atomic_t pp_done_cnt;
@@ -53,6 +55,7 @@
u16 start_threshold;
u32 vclk_line; /* vsync clock per line */
struct mdss_panel_recovery recovery;
+ bool ulps;
};
struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS];
@@ -200,8 +203,19 @@
mutex_lock(&ctx->clk_mtx);
if (!ctx->clk_enabled) {
ctx->clk_enabled = 1;
+ if (cancel_delayed_work_sync(&ctx->ulps_work))
+ pr_debug("deleted pending ulps work\n");
mdss_mdp_ctl_intf_event
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1);
+
+ if (ctx->ulps) {
+ if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl, 1))
+ pr_warn("tearcheck setup failed\n");
+ mdss_mdp_ctl_intf_event(ctx->ctl,
+ MDSS_EVENT_DSI_ULPS_CTRL, (void *)0);
+ ctx->ulps = false;
+ }
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
}
@@ -231,6 +245,8 @@
mdss_mdp_ctl_intf_event
(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ if (ctx->panel_on)
+ schedule_delayed_work(&ctx->ulps_work, ULPS_ENTER_TIME);
}
mutex_unlock(&ctx->clk_mtx);
}
@@ -365,6 +381,38 @@
mdss_mdp_cmd_clk_off(ctx);
}
+static void __mdss_mdp_cmd_ulps_work(struct work_struct *work)
+{
+ struct delayed_work *dw = to_delayed_work(work);
+ struct mdss_mdp_cmd_ctx *ctx =
+ container_of(dw, struct mdss_mdp_cmd_ctx, ulps_work);
+
+ if (!ctx) {
+ pr_err("%s: invalid ctx\n", __func__);
+ return;
+ }
+
+ mutex_lock(&ctx->clk_mtx);
+ if (ctx->clk_enabled) {
+ mutex_unlock(&ctx->clk_mtx);
+ pr_warn("Cannot enter ulps mode if DSI clocks are on\n");
+ return;
+ }
+ mutex_unlock(&ctx->clk_mtx);
+
+ if (!ctx->panel_on) {
+ pr_err("Panel is off. skipping ULPS configuration\n");
+ return;
+ }
+
+ if (!mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_DSI_ULPS_CTRL,
+ (void *)1)) {
+ ctx->ulps = true;
+ ctx->ctl->play_cnt = 0;
+ mdss_mdp_footswitch_ctrl_ulps(0, &ctx->ctl->mfd->pdev->dev);
+ }
+}
+
static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_vsync_handler *handle)
{
@@ -435,7 +483,6 @@
pdata->panel_info.cont_splash_enabled = 0;
mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
return ret;
}
@@ -584,11 +631,14 @@
if (cancel_work_sync(&ctx->clk_work))
pr_debug("no pending clk work\n");
+ if (cancel_delayed_work_sync(&ctx->ulps_work))
+ pr_debug("deleted pending ulps work\n");
+
+ ctx->panel_on = 0;
mdss_mdp_cmd_clk_off(ctx);
flush_work(&ctx->pp_done_work);
- ctx->panel_on = 0;
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num,
NULL, NULL);
@@ -654,6 +704,7 @@
spin_lock_init(&ctx->clk_lock);
mutex_init(&ctx->clk_mtx);
INIT_WORK(&ctx->clk_work, clk_ctrl_work);
+ INIT_DELAYED_WORK(&ctx->ulps_work, __mdss_mdp_cmd_ulps_work);
INIT_WORK(&ctx->pp_done_work, pingpong_done_work);
atomic_set(&ctx->pp_done_cnt, 0);
INIT_LIST_HEAD(&ctx->vsync_handlers);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 7304694..55a4a4d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -736,7 +736,6 @@
free_bootmem_late(mdp5_data->splash_mem_addr,
mdp5_data->splash_mem_size);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 9365be8..7420f95 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -156,6 +156,12 @@
pr_err("Invalid decimation factors horz=%d vert=%d\n",
req->horz_deci, req->vert_deci);
return -EINVAL;
+ } else if (req->flags & MDP_BWC_EN) {
+ pr_err("Decimation can't be enabled with BWC\n");
+ return -EINVAL;
+ } else if (fmt->tile) {
+ pr_err("Decimation can't be enabled with MacroTile format\n");
+ return -EINVAL;
}
}
@@ -272,7 +278,8 @@
* requirement by applying vertical decimation and reduce
* mdp clock requirement
*/
- if (mdata->has_decimation && (pipe->vert_deci < MAX_DECIMATION))
+ if (mdata->has_decimation && (pipe->vert_deci < MAX_DECIMATION)
+ && !pipe->bwc_mode && !pipe->src_fmt->tile)
pipe->vert_deci++;
else
return -EPERM;
@@ -682,6 +689,7 @@
if ((num_planes <= 0) || (num_planes > MAX_PLANES))
return -EINVAL;
+ mdss_bus_bandwidth_ctrl(1);
memset(data, 0, sizeof(*data));
for (i = 0; i < num_planes; i++) {
data->p[i].flags = flags;
@@ -695,6 +703,7 @@
break;
}
}
+ mdss_bus_bandwidth_ctrl(0);
data->num_planes = i;
@@ -704,8 +713,11 @@
int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data)
{
int i;
+
+ mdss_bus_bandwidth_ctrl(1);
for (i = 0; i < data->num_planes && data->p[i].len; i++)
mdss_mdp_put_img(&data->p[i]);
+ mdss_bus_bandwidth_ctrl(0);
data->num_planes = 0;
@@ -835,6 +847,11 @@
struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
if (ctl->power_on) {
+ if (mdp5_data->mdata->ulps) {
+ mdss_mdp_footswitch_ctrl_ulps(1, &mfd->pdev->dev);
+ mdss_mdp_ctl_restore(ctl);
+ }
+
if (!mdp5_data->mdata->batfet)
mdss_mdp_batfet_ctrl(mdp5_data->mdata, true);
if (!mfd->panel_info->cont_splash_enabled)
@@ -1030,11 +1047,13 @@
pipe->mixer = mdss_mdp_mixer_get(tmp,
MDSS_MDP_MIXER_MUX_DEFAULT);
}
+
+ /* ensure pipes are always reconfigured after power off/on */
+ if (ctl->play_cnt == 0)
+ pipe->params_changed++;
+
if (pipe->back_buf.num_planes) {
buf = &pipe->back_buf;
- } else if (ctl->play_cnt == 0 && pipe->front_buf.num_planes) {
- pipe->params_changed++;
- buf = &pipe->front_buf;
} else if (!pipe->params_changed) {
continue;
} else if (pipe->front_buf.num_planes) {
@@ -1095,7 +1114,7 @@
struct mdss_mdp_pipe *pipe;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
u32 pipe_ndx, unset_ndx = 0;
- int i;
+ int i, destroy_pipe;
for (i = 0; unset_ndx != ndx && i < MDSS_MDP_MAX_SSPP; i++) {
pipe_ndx = BIT(i);
@@ -1106,16 +1125,22 @@
pr_warn("unknown pipe ndx=%x\n", pipe_ndx);
continue;
}
+
mutex_lock(&mfd->lock);
pipe->pid = 0;
+ destroy_pipe = pipe->play_cnt == 0;
+
if (!list_empty(&pipe->used_list)) {
list_del_init(&pipe->used_list);
- list_add(&pipe->cleanup_list,
- &mdp5_data->pipes_cleanup);
+ if (!destroy_pipe)
+ list_add(&pipe->cleanup_list,
+ &mdp5_data->pipes_cleanup);
}
mutex_unlock(&mfd->lock);
mdss_mdp_mixer_pipe_unstage(pipe);
mdss_mdp_pipe_unmap(pipe);
+ if (destroy_pipe)
+ mdss_mdp_pipe_destroy(pipe);
}
}
return 0;
@@ -2206,6 +2231,10 @@
caps->features |= MDP_BWC_EN;
if (mdata->has_decimation)
caps->features |= MDP_DECIMATION_EN;
+
+ caps->max_smp_cnt = mdss_res->smp_mb_cnt;
+ caps->smp_per_pipe = mdata->smp_mb_per_pipe;
+
return 0;
}
@@ -2244,6 +2273,121 @@
return ret;
}
+static int __handle_overlay_prepare(struct msm_fb_data_type *mfd,
+ struct mdp_overlay_list *ovlist,
+ struct mdp_overlay *overlays)
+{
+ struct mdss_mdp_pipe *right_plist[MDSS_MDP_MAX_STAGE] = { 0 };
+ struct mdss_mdp_pipe *left_plist[MDSS_MDP_MAX_STAGE] = { 0 };
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+ struct mdss_mdp_pipe *pipe;
+ struct mdp_overlay *req;
+ int ret = 0, left_cnt = 0, right_cnt = 0;
+ int i;
+ u32 new_reqs = 0;
+
+ ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
+ if (ret)
+ return ret;
+
+ if (!mfd->panel_power_on) {
+ mutex_unlock(&mdp5_data->ov_lock);
+ return -EPERM;
+ }
+
+ pr_debug("prepare fb%d num_overlays=%d\n", mfd->index,
+ ovlist->num_overlays);
+
+ for (i = 0; i < ovlist->num_overlays; i++) {
+ req = overlays + i;
+
+ req->z_order += MDSS_MDP_STAGE_0;
+ ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe);
+ req->z_order -= MDSS_MDP_STAGE_0;
+
+ if (IS_ERR_VALUE(ret))
+ goto validate_exit;
+
+ /* keep track of the new overlays to unset in case of errors */
+ if (pipe->play_cnt == 0)
+ new_reqs |= pipe->ndx;
+
+ if (pipe->flags & MDSS_MDP_RIGHT_MIXER) {
+ if (right_cnt >= MDSS_MDP_MAX_STAGE) {
+ pr_err("too many pipes on right mixer\n");
+ ret = -EINVAL;
+ goto validate_exit;
+ }
+ right_plist[right_cnt] = pipe;
+ right_cnt++;
+ } else {
+ if (left_cnt >= MDSS_MDP_MAX_STAGE) {
+ pr_err("too many pipes on left mixer\n");
+ ret = -EINVAL;
+ goto validate_exit;
+ }
+ left_plist[left_cnt] = pipe;
+ left_cnt++;
+ }
+ }
+
+ ret = mdss_mdp_perf_bw_check(mdp5_data->ctl, left_plist, left_cnt,
+ right_plist, right_cnt);
+
+validate_exit:
+ if (IS_ERR_VALUE(ret))
+ mdss_mdp_overlay_release(mfd, new_reqs);
+ mutex_unlock(&mdp5_data->ov_lock);
+
+ ovlist->processed_overlays = i;
+
+ return ret;
+}
+
+static int __handle_ioctl_overlay_prepare(struct msm_fb_data_type *mfd,
+ void __user *argp)
+{
+ struct mdp_overlay_list ovlist;
+ struct mdp_overlay *overlays;
+ int i, ret;
+
+ if (copy_from_user(&ovlist, argp, sizeof(ovlist)))
+ return -EFAULT;
+
+ overlays = kmalloc(ovlist.num_overlays * sizeof(*overlays), GFP_KERNEL);
+ if (!overlays) {
+ pr_err("Unable to allocate memory for overlays\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < ovlist.num_overlays; i++) {
+ if (copy_from_user(overlays + i, ovlist.overlay_list[i],
+ sizeof(struct mdp_overlay))) {
+ ret = -EFAULT;
+ goto validate_exit;
+ }
+ }
+
+ ret = __handle_overlay_prepare(mfd, &ovlist, overlays);
+ if (!IS_ERR_VALUE(ret)) {
+ for (i = 0; i < ovlist.num_overlays; i++) {
+ if (copy_to_user(ovlist.overlay_list[i], overlays + i,
+ sizeof(struct mdp_overlay))) {
+ ret = -EFAULT;
+ goto validate_exit;
+ }
+ }
+ }
+
+ if (copy_to_user(argp, &ovlist, sizeof(ovlist)))
+ ret = -EFAULT;
+
+validate_exit:
+ kfree(overlays);
+
+ return ret;
+}
+
static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd,
u32 cmd, void __user *argp)
{
@@ -2367,6 +2511,9 @@
if (!ret)
ret = copy_to_user(argp, &metadata, sizeof(metadata));
break;
+ case MSMFB_OVERLAY_PREPARE:
+ ret = __handle_ioctl_overlay_prepare(mfd, argp);
+ break;
default:
if (mfd->panel.type == WRITEBACK_PANEL)
ret = mdss_mdp_wb_ioctl_handler(mfd, cmd, argp);
@@ -2455,10 +2602,10 @@
}
if (!mfd->panel_info->cont_splash_enabled &&
- (mfd->panel_info->type != DTV_PANEL) &&
- (mfd->panel_info->type != WRITEBACK_PANEL)) {
+ (mfd->panel_info->type != DTV_PANEL)) {
rc = mdss_mdp_overlay_start(mfd);
- if (!IS_ERR_VALUE(rc))
+ if (!IS_ERR_VALUE(rc) &&
+ (mfd->panel_info->type != WRITEBACK_PANEL))
rc = mdss_mdp_overlay_kickoff(mfd, NULL);
} else {
rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
@@ -2540,14 +2687,9 @@
int mdss_panel_register_done(struct mdss_panel_data *pdata)
{
- /*
- * Clocks are already on if continuous splash is enabled,
- * increasing ref_cnt to help balance clocks once done.
- */
- if (pdata->panel_info.cont_splash_enabled) {
+ if (pdata->panel_info.cont_splash_enabled)
mdss_mdp_footswitch_ctrl_splash(1);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- }
+
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 4999103..b6f9b17 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -209,7 +209,7 @@
u32 num_blks = 0, reserved = 0;
struct mdss_mdp_plane_sizes ps;
int i;
- int rc = 0, rot_mode = 0;
+ int rc = 0, rot_mode = 0, wb_mixer = 0;
u32 nlines, format;
u16 width;
@@ -295,6 +295,9 @@
else
nlines = pipe->bwc_mode ? 1 : 2;
+ if (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
+ wb_mixer = 1;
+
mutex_lock(&mdss_mdp_smp_lock);
for (i = (MAX_PLANES - 1); i >= ps.num_planes; i--) {
if (bitmap_weight(pipe->smp_map[i].allocated, SMP_MB_CNT)) {
@@ -306,7 +309,7 @@
}
for (i = 0; i < ps.num_planes; i++) {
- if (rot_mode) {
+ if (rot_mode || wb_mixer) {
num_blks = 1;
} else {
num_blks = DIV_ROUND_UP(ps.ystride[i] * nlines,
@@ -672,16 +675,20 @@
pr_debug("ndx=%x pnum=%d ref_cnt=%d\n", pipe->ndx, pipe->num,
atomic_read(&pipe->ref_cnt));
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
- mdss_mdp_pipe_sspp_term(pipe);
- mdss_mdp_smp_free(pipe);
+ if (pipe->play_cnt) {
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_pipe_sspp_term(pipe);
+ mdss_mdp_smp_free(pipe);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ } else {
+ mdss_mdp_smp_unreserve(pipe);
+ }
+
pipe->flags = 0;
pipe->bwc_mode = 0;
pipe->mfd = NULL;
memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-
return 0;
}
@@ -815,6 +822,7 @@
pipe->src_fmt->bpp);
pipe->is_handed_off = true;
+ pipe->play_cnt = 1;
atomic_inc(&pipe->ref_cnt);
error:
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 9b6d130..5c9ad9c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -396,6 +396,7 @@
struct mdss_mdp_ctl *ctl, u32 num, u32 *opmode);
static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
+static u32 pp_ad_attenuate_bl(u32 bl, struct mdss_ad_info *ad);
static int pp_num_to_side(struct mdss_mdp_ctl *ctl, u32 num);
static inline bool pp_sts_is_enabled(u32 sts, int side);
static inline void pp_sts_set_split_bits(u32 *sts, u32 bits);
@@ -1589,7 +1590,7 @@
if (mdata->nad_cfgs == 0)
valid_mixers = false;
for (i = 0; i < mixer_cnt && valid_mixers; i++) {
- if (mixer_id[i] > mdata->nad_cfgs)
+ if (mixer_id[i] >= mdata->nad_cfgs)
valid_mixers = false;
}
if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw)) {
@@ -1648,6 +1649,7 @@
if (ad->state & PP_AD_STATE_BL_LIN) {
bl = ad->bl_lin[bl >> ad->bl_bright_shift];
bl = bl << ad->bl_bright_shift;
+ bl = pp_ad_attenuate_bl(bl, ad);
}
ad->bl_data = bl;
pp_ad_input_write(&mdata->ad_off[dspp_num], ad);
@@ -3781,7 +3783,7 @@
{
struct mdss_ad_info *ad;
struct msm_fb_data_type *bl_mfd;
- int lin_ret = -1, inv_ret = -1, ret = 0;
+ int lin_ret = -1, inv_ret = -1, att_ret = -1, ret = 0;
u32 ratio_temp, shift = 0, last_ops;
ret = mdss_mdp_get_ad(mfd, &ad);
@@ -3830,6 +3832,23 @@
} else
ad->state |= PP_AD_STATE_BL_LIN;
+ if ((init_cfg->params.init.bl_att_len == AD_BL_ATT_LUT_LEN) &&
+ (init_cfg->params.init.bl_att_lut)) {
+ att_ret = copy_from_user(&ad->bl_att_lut,
+ init_cfg->params.init.bl_att_lut,
+ init_cfg->params.init.bl_att_len *
+ sizeof(uint32_t));
+ if (att_ret)
+ ret = -ENOMEM;
+ } else {
+ ret = -EINVAL;
+ }
+ if (ret) {
+ ad->state &= ~PP_AD_STATE_BL_LIN;
+ goto ad_config_exit;
+ } else
+ ad->state |= PP_AD_STATE_BL_LIN;
+
ad->sts |= PP_AD_STS_DIRTY_INIT;
} else if (init_cfg->ops & MDP_PP_AD_CFG) {
memcpy(&ad->cfg, &init_cfg->params.cfg,
@@ -4256,6 +4275,7 @@
if (ad->state & PP_AD_STATE_BL_LIN) {
bl = ad->bl_lin[bl >> ad->bl_bright_shift];
bl = bl << ad->bl_bright_shift;
+ bl = pp_ad_attenuate_bl(bl, ad);
}
ad->bl_data = bl;
}
@@ -4330,6 +4350,8 @@
AD_BL_LIN_LEN);
memset(&ad->bl_lin_inv, 0, sizeof(uint32_t) *
AD_BL_LIN_LEN);
+ memset(&ad->bl_att_lut, 0, sizeof(uint32_t) *
+ AD_BL_ATT_LUT_LEN);
memset(&ad->init, 0, sizeof(struct mdss_ad_init));
memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg));
mutex_lock(&bl_mfd->bl_lock);
@@ -4391,7 +4413,7 @@
ctl = mfd_to_ctl(ad->mfd);
mdata = mfd_to_mdata(ad->mfd);
- if (!mdata || ad->calc_hw_num > mdata->nad_cfgs) {
+ if (!mdata || ad->calc_hw_num >= mdata->nad_cfgs) {
mutex_unlock(&ad->lock);
return;
}
@@ -4474,6 +4496,30 @@
addr + ((PP_AD_LUT_LEN - 1) * 2));
}
+static u32 pp_ad_attenuate_bl(u32 bl, struct mdss_ad_info *ad)
+{
+ u32 shift = 0, ratio_temp = 0;
+ u32 n, lut_interval, bl_att, out;
+
+ ratio_temp = ad->cfg.backlight_max / (AD_BL_ATT_LUT_LEN - 1);
+ while (ratio_temp > 0) {
+ ratio_temp = ratio_temp >> 1;
+ shift++;
+ }
+ n = bl >> shift;
+ lut_interval = (ad->cfg.backlight_max + 1) / (AD_BL_ATT_LUT_LEN - 1);
+ bl_att = ad->bl_att_lut[n] + (bl - lut_interval * n) *
+ (ad->bl_att_lut[n + 1] - ad->bl_att_lut[n]) /
+ lut_interval;
+ if (ad->init.alpha_base)
+ out = (ad->init.alpha * bl_att +
+ (ad->init.alpha_base - ad->init.alpha) * bl) /
+ ad->init.alpha_base;
+ else
+ out = bl;
+ return out;
+}
+
int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets)
{
u32 i;
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 6eb4d6e..454183d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -894,3 +894,22 @@
return mdss_mdp_wb_set_secure(mfd, enable);
}
EXPORT_SYMBOL(msm_fb_writeback_set_secure);
+
+/**
+ * msm_fb_writeback_iommu_ref() - Power ON/OFF mdp clock
+ * @enable - true/false to Power ON/OFF mdp clock
+ *
+ * Call to enable mdp clock at start of mdp_mmap/mdp_munmap API and
+ * to disable mdp clock at end of these API's to ensure iommu is in
+ * proper state while driver map/un-map any buffers.
+ */
+int msm_fb_writeback_iommu_ref(struct fb_info *info, int enable)
+{
+ if (enable)
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ else
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_fb_writeback_iommu_ref);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 274c523..135a00a 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -127,6 +127,11 @@
- 1 clock enable
* @MDSS_EVENT_ENABLE_PARTIAL_UPDATE: Event to update ROI of the panel.
* @MDSS_EVENT_DSI_CMDLIST_KOFF: acquire dsi_mdp_busy lock before kickoff.
+ * @MDSS_EVENT_DSI_ULPS_CTRL: Event to configure Ultra Lower Power Saving
+ * mode for the DSI data and clock lanes. The
+ * event arguments can have one of these values:
+ * - 0: Disable ULPS mode
+ * - 1: Enable ULPS mode
*/
enum mdss_intf_events {
MDSS_EVENT_RESET = 1,
@@ -145,6 +150,7 @@
MDSS_EVENT_PANEL_CLK_CTRL,
MDSS_EVENT_DSI_CMDLIST_KOFF,
MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
+ MDSS_EVENT_DSI_ULPS_CTRL,
};
struct lcd_panel_info {
@@ -300,6 +306,7 @@
int pwm_period;
u32 mode_gpio_state;
bool dynamic_fps;
+ bool ulps_feature_enabled;
char dfps_update;
int new_fps;
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index 0f84b2d..c5d5366 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -194,6 +194,7 @@
static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
bool mhl_disc_en);
static int mhl_gpio_config(struct mhl_tx_ctrl *mhl_ctrl, int on);
+static int mhl_vreg_config(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on);
int mhl_i2c_reg_read(struct i2c_client *client,
uint8_t slave_addr_index, uint8_t reg_offset)
@@ -385,15 +386,69 @@
return 0;
}
+static int mhl_sii_config(struct mhl_tx_ctrl *mhl_ctrl, bool on)
+{
+ int rc = 0;
+ struct i2c_client *client = NULL;
+
+ if (!mhl_ctrl) {
+ pr_err("%s: ctrl is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ client = mhl_ctrl->i2c_handle;
+
+ if (on) {
+ rc = mhl_vreg_config(mhl_ctrl, 1);
+ if (rc) {
+ pr_err("%s: vreg init failed [%d]\n",
+ __func__, rc);
+ return -ENODEV;
+ }
+
+ rc = mhl_gpio_config(mhl_ctrl, 1);
+ if (rc) {
+ pr_err("%s: gpio init failed [%d]\n",
+ __func__, rc);
+ return -ENODEV;
+ }
+
+ rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
+ &mhl_tx_isr, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ client->dev.driver->name, mhl_ctrl);
+ if (rc) {
+ pr_err("%s: request_threaded_irq failed, status: %d\n",
+ __func__, rc);
+ return -ENODEV;
+ } else {
+ mhl_ctrl->irq_req_done = true;
+ }
+ } else {
+ free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
+ mhl_gpio_config(mhl_ctrl, 0);
+ mhl_vreg_config(mhl_ctrl, 0);
+ mhl_ctrl->irq_req_done = false;
+ }
+
+ return rc;
+}
+
+static void mhl_sii_disc_intr_work(struct work_struct *work)
+{
+ struct mhl_tx_ctrl *mhl_ctrl = NULL;
+
+ mhl_ctrl = container_of(work, struct mhl_tx_ctrl, mhl_intr_work);
+
+ mhl_sii_config(mhl_ctrl, false);
+}
+
/* USB_HANDSHAKING FUNCTIONS */
static int mhl_sii_device_discovery(void *data, int id,
void (*usb_notify_cb)(void *, int), void *ctx)
{
int rc;
struct mhl_tx_ctrl *mhl_ctrl = data;
- struct i2c_client *client = mhl_ctrl->i2c_handle;
unsigned long flags;
- int discovery_retry = 5;
if (id) {
/* When MHL cable is disconnected we get a sii8334
@@ -413,18 +468,14 @@
mhl_ctrl->notify_usb_online = usb_notify_cb;
mhl_ctrl->notify_ctx = ctx;
}
-again:
+
+ flush_work(&mhl_ctrl->mhl_intr_work);
+
if (!mhl_ctrl->irq_req_done) {
- rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
- &mhl_tx_isr, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- client->dev.driver->name, mhl_ctrl);
+ rc = mhl_sii_config(mhl_ctrl, true);
if (rc) {
- pr_debug("request_threaded_irq failed, status: %d\n",
- rc);
- return -EINVAL;
- } else {
- pr_debug("request_threaded_irq succeeded\n");
- mhl_ctrl->irq_req_done = true;
+ pr_err("%s: Failed to config vreg/gpio\n", __func__);
+ return rc;
}
/* wait for i2c interrupt line to be activated */
@@ -448,23 +499,9 @@
if (mhl_sii_wait_for_rgnd(mhl_ctrl)) {
pr_err("%s: discovery timeout\n", __func__);
- free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
- mhl_gpio_config(mhl_ctrl, 0);
- mhl_ctrl->irq_req_done = false;
+ mhl_sii_config(mhl_ctrl, false);
- msleep(100);
-
- mhl_gpio_config(mhl_ctrl, 1);
- if (discovery_retry--) {
- pr_debug("%s: retrying discovery\n", __func__);
- goto again;
- } else {
- pr_err("%s: discovery failed, ret to USB\n",
- __func__);
- if (mhl_ctrl->notify_usb_online)
- mhl_ctrl->notify_usb_online(
- mhl_ctrl->notify_ctx, 0);
- }
+ return -EAGAIN;
}
} else {
if (mhl_ctrl->cur_state == POWER_STATE_D3) {
@@ -1059,13 +1096,8 @@
mhl_msm_connection(mhl_ctrl);
} else if (status & BIT3) {
pr_debug("%s: uUSB-a type dev detct\n", __func__);
-
- /* Short RGND */
- MHL_SII_REG_NAME_MOD(REG_DISC_STAT2, BIT0 | BIT1, 0x00);
- mhl_msm_disconnection(mhl_ctrl);
power_supply_changed(&mhl_ctrl->mhl_psy);
- if (mhl_ctrl->notify_usb_online)
- mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
+ mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
return 0;
}
@@ -1081,6 +1113,9 @@
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
+
+ queue_work(mhl_ctrl->mhl_workq, &mhl_ctrl->mhl_intr_work);
+
return 0;
}
@@ -1495,6 +1530,27 @@
int rc = -EINVAL;
pr_debug("%s\n", __func__);
+
+ if (!enable) {
+ regulator_disable(reg_8941_vdda);
+ regulator_put(reg_8941_vdda);
+ reg_8941_vdda = NULL;
+
+ regulator_disable(reg_8941_smps3a);
+ regulator_put(reg_8941_smps3a);
+ reg_8941_smps3a = NULL;
+
+ regulator_disable(reg_8941_l02);
+ regulator_put(reg_8941_l02);
+ reg_8941_l02 = NULL;
+
+ regulator_disable(reg_8941_l24);
+ regulator_put(reg_8941_l24);
+ reg_8941_l24 = NULL;
+
+ return 0;
+ }
+
if (!reg_8941_l24) {
reg_8941_l24 = regulator_get(&client->dev,
"avcc_18");
@@ -1736,26 +1792,6 @@
}
/*
- * Regulator init
- */
- rc = mhl_vreg_config(mhl_ctrl, 1);
- if (rc) {
- pr_err("%s: vreg init failed [%d]\n",
- __func__, rc);
- goto failed_probe;
- }
-
- /*
- * GPIO init
- */
- rc = mhl_gpio_config(mhl_ctrl, 1);
- if (rc) {
- pr_err("%s: gpio init failed [%d]\n",
- __func__, rc);
- goto failed_probe;
- }
-
- /*
* Other initializations
* such tx specific
*/
@@ -1767,6 +1803,9 @@
spin_lock_init(&mhl_ctrl->lock);
mhl_ctrl->msc_send_workqueue = create_singlethread_workqueue
("mhl_msc_cmd_queue");
+ mhl_ctrl->mhl_workq = create_singlethread_workqueue("mhl_workq");
+
+ INIT_WORK(&mhl_ctrl->mhl_intr_work, mhl_sii_disc_intr_work);
mhl_ctrl->input = input_allocate_device();
if (mhl_ctrl->input) {
@@ -1894,9 +1933,7 @@
failed_probe_pwr:
power_supply_unregister(&mhl_ctrl->mhl_psy);
failed_probe:
- free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
- mhl_gpio_config(mhl_ctrl, 0);
- mhl_vreg_config(mhl_ctrl, 0);
+ mhl_sii_config(mhl_ctrl, false);
/* do not deep-free */
if (mhl_info)
devm_kfree(&client->dev, mhl_info);
@@ -1923,9 +1960,10 @@
return -EINVAL;
}
- free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
- mhl_gpio_config(mhl_ctrl, 0);
- mhl_vreg_config(mhl_ctrl, 0);
+ mhl_sii_config(mhl_ctrl, false);
+
+ destroy_workqueue(mhl_ctrl->mhl_workq);
+
if (mhl_ctrl->mhl_info)
devm_kfree(&client->dev, mhl_ctrl->mhl_info);
if (mhl_ctrl->pdata)
@@ -1949,17 +1987,19 @@
pr_debug("%s\n", __func__);
- if (!mhl_ctrl)
+ if (!mhl_ctrl) {
+ pr_err("%s: invalid ctrl data\n", __func__);
return 0;
-
- free_irq(mhl_ctrl->i2c_handle->irq, mhl_ctrl);
- mhl_ctrl->irq_req_done = false;
+ }
if (mhl_ctrl->mhl_mode) {
mhl_ctrl->mhl_mode = 0;
+
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(mhl_ctrl->notify_ctx, 0);
+
+ mhl_sii_config(mhl_ctrl, false);
}
return 0;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 5d4610c..a0663e3 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -64,6 +64,16 @@
goto mdss_dsi_clk_err;
}
+ if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) {
+ ctrl_pdata->mmss_misc_ahb_clk = clk_get(dev, "core_mmss_clk");
+ if (IS_ERR(ctrl_pdata->mmss_misc_ahb_clk)) {
+ rc = PTR_ERR(ctrl_pdata->mmss_misc_ahb_clk);
+ pr_err("%s: Unable to get mmss misc ahb clk. rc=%d\n",
+ __func__, rc);
+ goto mdss_dsi_clk_err;
+ }
+ }
+
ctrl_pdata->byte_clk = clk_get(dev, "byte_clk");
if (IS_ERR(ctrl_pdata->byte_clk)) {
rc = PTR_ERR(ctrl_pdata->byte_clk);
@@ -105,6 +115,8 @@
clk_put(ctrl_pdata->esc_clk);
if (ctrl_pdata->pixel_clk)
clk_put(ctrl_pdata->pixel_clk);
+ if (ctrl_pdata->mmss_misc_ahb_clk)
+ clk_put(ctrl_pdata->mmss_misc_ahb_clk);
if (ctrl_pdata->axi_clk)
clk_put(ctrl_pdata->axi_clk);
if (ctrl_pdata->ahb_clk)
@@ -247,10 +259,12 @@
return 0;
}
-int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
int rc = 0;
+ pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx);
+
rc = clk_prepare_enable(ctrl_pdata->mdp_core_clk);
if (rc) {
pr_err("%s: failed to enable mdp_core_clock. rc=%d\n",
@@ -273,18 +287,32 @@
goto error;
}
+ if (ctrl_pdata->mmss_misc_ahb_clk) {
+ rc = clk_prepare_enable(ctrl_pdata->mmss_misc_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mmss misc ahb clk.rc=%d\n",
+ __func__, rc);
+ clk_disable_unprepare(ctrl_pdata->axi_clk);
+ clk_disable_unprepare(ctrl_pdata->ahb_clk);
+ clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
+ goto error;
+ }
+ }
+
error:
return rc;
}
-void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
+ if (ctrl_pdata->mmss_misc_ahb_clk)
+ clk_disable_unprepare(ctrl_pdata->mmss_misc_ahb_clk);
clk_disable_unprepare(ctrl_pdata->axi_clk);
clk_disable_unprepare(ctrl_pdata->ahb_clk);
clk_disable_unprepare(ctrl_pdata->mdp_core_clk);
}
-static int mdss_dsi_clk_prepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int mdss_dsi_link_clk_prepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
int rc = 0;
@@ -316,7 +344,7 @@
return rc;
}
-static void mdss_dsi_clk_unprepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static void mdss_dsi_link_clk_unprepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
if (!ctrl_pdata) {
pr_err("%s: Invalid input data\n", __func__);
@@ -328,7 +356,7 @@
clk_unprepare(ctrl_pdata->esc_clk);
}
-static int mdss_dsi_clk_set_rate(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int mdss_dsi_link_clk_set_rate(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
u32 esc_clk_rate = 19200000;
int rc = 0;
@@ -369,7 +397,7 @@
return rc;
}
-static int mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static int mdss_dsi_link_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
int rc = 0;
@@ -378,6 +406,8 @@
return -EINVAL;
}
+ pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx);
+
if (ctrl_pdata->mdss_dsi_clk_on) {
pr_info("%s: mdss_dsi_clks already ON\n", __func__);
return 0;
@@ -413,13 +443,15 @@
return rc;
}
-static void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+static void mdss_dsi_link_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
if (!ctrl_pdata) {
pr_err("%s: Invalid input data\n", __func__);
return;
}
+ pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx);
+
if (ctrl_pdata->mdss_dsi_clk_on == 0) {
pr_info("%s: mdss_dsi_clks already OFF\n", __func__);
return;
@@ -432,62 +464,120 @@
ctrl_pdata->mdss_dsi_clk_on = 0;
}
-int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl)
{
int rc = 0;
- mutex_lock(&ctrl->mutex);
+ rc = mdss_dsi_link_clk_set_rate(ctrl);
+ if (rc) {
+ pr_err("%s: failed to set clk rates. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+
+ rc = mdss_dsi_link_clk_prepare(ctrl);
+ if (rc) {
+ pr_err("%s: failed to prepare clks. rc=%d\n",
+ __func__, rc);
+ goto error;
+ }
+
+ rc = mdss_dsi_link_clk_enable(ctrl);
+ if (rc) {
+ pr_err("%s: failed to enable clks. rc=%d\n",
+ __func__, rc);
+ mdss_dsi_link_clk_unprepare(ctrl);
+ goto error;
+ }
+
+error:
+ return rc;
+}
+
+void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ mdss_dsi_link_clk_disable(ctrl);
+ mdss_dsi_link_clk_unprepare(ctrl);
+}
+
+static void mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+{
+ int changed = 0;
+
if (enable) {
- if (ctrl->clk_cnt == 0) {
- rc = mdss_dsi_enable_bus_clocks(ctrl);
- if (rc) {
- pr_err("%s: failed to enable bus clks. rc=%d\n",
- __func__, rc);
- goto error;
- }
-
- rc = mdss_dsi_clk_set_rate(ctrl);
- if (rc) {
- pr_err("%s: failed to set clk rates. rc=%d\n",
- __func__, rc);
- mdss_dsi_disable_bus_clocks(ctrl);
- goto error;
- }
-
- rc = mdss_dsi_clk_prepare(ctrl);
- if (rc) {
- pr_err("%s: failed to prepare clks. rc=%d\n",
- __func__, rc);
- mdss_dsi_disable_bus_clocks(ctrl);
- goto error;
- }
-
- rc = mdss_dsi_clk_enable(ctrl);
- if (rc) {
- pr_err("%s: failed to enable clks. rc=%d\n",
- __func__, rc);
- mdss_dsi_clk_unprepare(ctrl);
- mdss_dsi_disable_bus_clocks(ctrl);
- goto error;
- }
+ if (ctrl->clk_cnt_sub == 0)
+ changed++;
+ ctrl->clk_cnt_sub++;
+ } else {
+ if (ctrl->clk_cnt_sub) {
+ ctrl->clk_cnt_sub--;
+ if (ctrl->clk_cnt_sub == 0)
+ changed++;
+ } else {
+ pr_debug("%s: Can not be turned off\n", __func__);
}
+ }
+
+ pr_debug("%s: ndx=%d clk_cnt_sub=%d changed=%d enable=%d\n",
+ __func__, ctrl->ndx, ctrl->clk_cnt_sub, changed, enable);
+ if (changed) {
+ if (enable) {
+ if (mdss_dsi_bus_clk_start(ctrl) == 0)
+ mdss_dsi_link_clk_start(ctrl);
+ } else {
+ mdss_dsi_link_clk_stop(ctrl);
+ mdss_dsi_bus_clk_stop(ctrl);
+ }
+ }
+}
+
+static DEFINE_MUTEX(dsi_clk_lock); /* per system */
+
+bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+ bool enabled;
+ mutex_lock(&dsi_clk_lock);
+ enabled = ctrl->clk_cnt ? true : false;
+ mutex_unlock(&dsi_clk_lock);
+
+ return enabled;
+}
+
+void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+{
+ int changed = 0;
+ struct mdss_dsi_ctrl_pdata *sctrl = NULL;
+
+ mutex_lock(&dsi_clk_lock);
+ if (enable) {
+ if (ctrl->clk_cnt == 0)
+ changed++;
ctrl->clk_cnt++;
} else {
if (ctrl->clk_cnt) {
ctrl->clk_cnt--;
- if (ctrl->clk_cnt == 0) {
- mdss_dsi_clk_disable(ctrl);
- mdss_dsi_clk_unprepare(ctrl);
- mdss_dsi_disable_bus_clocks(ctrl);
- }
+ if (ctrl->clk_cnt == 0)
+ changed++;
+ } else {
+ pr_debug("%s: Can not be turned off\n", __func__);
}
}
- pr_debug("%s: ctrl ndx=%d enabled=%d clk_cnt=%d\n",
- __func__, ctrl->ndx, enable, ctrl->clk_cnt);
-error:
- mutex_unlock(&ctrl->mutex);
- return rc;
+ pr_debug("%s: ndx=%d clk_cnt=%d changed=%d enable=%d\n",
+ __func__, ctrl->ndx, ctrl->clk_cnt, changed, enable);
+ if (ctrl->flags & DSI_FLAG_CLOCK_MASTER)
+ sctrl = mdss_dsi_ctrl_slave(ctrl);
+
+ if (changed) {
+ if (enable && sctrl)
+ mdss_dsi_clk_ctrl_sub(sctrl, enable);
+
+ mdss_dsi_clk_ctrl_sub(ctrl, enable);
+
+ if (!enable && sctrl)
+ mdss_dsi_clk_ctrl_sub(sctrl, enable);
+ }
+ mutex_unlock(&dsi_clk_lock);
}
void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base)
@@ -502,7 +592,7 @@
wmb();
}
-void mdss_dsi_phy_enable(struct mdss_dsi_ctrl_pdata *ctrl, int on)
+void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl)
{
static struct mdss_dsi_ctrl_pdata *left_ctrl;
@@ -511,59 +601,28 @@
return;
}
- if (!left_ctrl
- && ctrl->shared_pdata.broadcast_enable)
- if ((ctrl->panel_data).panel_info.pdest
- == DISPLAY_1)
- left_ctrl = ctrl;
+ if (left_ctrl &&
+ (ctrl->panel_data.panel_info.pdest == DISPLAY_1))
+ return;
- if (on) {
- MIPI_OUTP(ctrl->ctrl_base + 0x03cc, 0x03);
- wmb();
- usleep(100);
- MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x006);
- wmb();
- usleep(100);
- MIPI_OUTP(ctrl->ctrl_base + 0x0268, 0x001);
- wmb();
- usleep(100);
- MIPI_OUTP(ctrl->ctrl_base + 0x0268, 0x000);
- wmb();
- usleep(100);
- MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x007);
- wmb();
- MIPI_OUTP(ctrl->ctrl_base + 0x03cc, 0x01);
- wmb();
- usleep(100);
-
- /* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
- MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x07e);
- MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x06e);
- MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x06c);
- MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x064);
- MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x065);
- MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x075);
- MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x077);
- MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x07f);
- wmb();
- } else {
- if (left_ctrl &&
+ if (left_ctrl &&
(ctrl->panel_data.panel_info.pdest
- == DISPLAY_1))
- return;
-
- if (left_ctrl &&
- (ctrl->panel_data.panel_info.pdest
- == DISPLAY_2)) {
- MIPI_OUTP(left_ctrl->ctrl_base + 0x0220, 0x006);
- MIPI_OUTP(left_ctrl->ctrl_base + 0x0470, 0x000);
- MIPI_OUTP(left_ctrl->ctrl_base + 0x0598, 0x000);
- }
- MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x006);
- MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x000);
- MIPI_OUTP(ctrl->ctrl_base + 0x0598, 0x000);
- wmb();
+ ==
+ DISPLAY_2)) {
+ MIPI_OUTP(left_ctrl->ctrl_base + 0x0470,
+ 0x000);
+ MIPI_OUTP(left_ctrl->ctrl_base + 0x0598,
+ 0x000);
}
+
+ MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x000);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0598, 0x000);
+
+ /*
+ * Wait for the registers writes to complete in order to
+ * ensure that the phy is completely disabled
+ */
+ wmb();
}
void mdss_dsi_phy_init(struct mdss_panel_data *pdata)
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
old mode 100644
new mode 100755
index ec27b00..276a48f
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -42,7 +42,9 @@
#define ERR(x...) pr_err(x)
#define VID_DEC_NAME "msm_vidc_dec"
-
+#ifdef KW_TAINT_ANALYSIS 51
+ extern void * get_tainted_stuff();
+#endif
static char *node_name[2] = {"", "_sec"};
static struct vid_dec_dev *vid_dec_device_p;
static dev_t vid_dec_dev_num;
@@ -1736,7 +1738,11 @@
unsigned long kernel_vaddr, phy_addr, len;
unsigned long ker_vaddr;
u32 result = true;
+ #ifdef KW_TAINT_ANALYSIS
+ void __user *arg = (void __user *) get_tainted_stuff();
+ #else
void __user *arg = (void __user *)u_arg;
+ #endif
int rc = 0;
size_t ion_len;
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
old mode 100644
new mode 100755
index 823626a..ee9c48b
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -45,7 +45,9 @@
#define INFO(x...) printk(KERN_INFO x)
#define ERR(x...) printk(KERN_ERR x)
-
+#ifdef KW_TAINT_ANALYSIS
+ extern void * get_tainted_stuff();
+#endif
static struct vid_enc_dev *vid_enc_device_p;
static dev_t vid_enc_dev_num;
static struct class *vid_enc_class;
@@ -840,7 +842,11 @@
{
struct video_client_ctx *client_ctx = NULL;
struct venc_ioctl_msg venc_msg;
+ #ifdef KW_TAINT_ANALYSIS
+ void __user *arg = (void __user *)get_tainted_stuff();;
+ #else
void __user *arg = (void __user *)u_arg;
+ #endif
u32 result = true;
int result_read = -1;
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 341f753..8db494d 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -329,10 +329,14 @@
/* fat/misc.c */
extern __printf(3, 4) __cold
void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...);
-#define fat_fs_error(sb, fmt, args...) \
- __fat_fs_error(sb, 1, fmt , ## args)
#define fat_fs_error_ratelimit(sb, fmt, args...) \
__fat_fs_error(sb, __ratelimit(&MSDOS_SB(sb)->ratelimit), fmt , ## args)
+/*
+ * If removable devices with a fat fs are removed without a unmount, further
+ * accesses to the device by applications causes a large number of error prints
+ * & in some cases leads to watchdog bark.
+ */
+#define fat_fs_error(sb, fmt, args...) fat_fs_error_ratelimit(sb, fmt, ## args)
__printf(3, 4) __cold
void fat_msg(struct super_block *sb, const char *level, const char *fmt, ...);
extern int fat_clusters_flush(struct super_block *sb);
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index ac750ea..3f62354 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -95,6 +95,12 @@
#define BIO_FS_INTEGRITY 9 /* fs owns integrity data, not block layer */
#define BIO_QUIET 10 /* Make BIO Quiet */
#define BIO_MAPPED_INTEGRITY 11/* integrity metadata has been remapped */
+/*
+ * Added for Req based dm which need to perform post processing. This flag
+ * ensures blk_update_request does not free the bios or request, this is done
+ * at the dm level
+ */
+#define BIO_DONTFREE 12
#define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag)))
/*
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 98f34b8..546871b 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -510,5 +510,6 @@
void dm_requeue_unmapped_request(struct request *rq);
void dm_kill_unmapped_request(struct request *rq, int error);
int dm_underlying_device_busy(struct request_queue *q);
+void dm_end_request(struct request *clone, int error);
#endif /* _LINUX_DEVICE_MAPPER_H */
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index 71dec42..42ee81e 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -155,6 +155,8 @@
struct list_head list_cmd;
struct input_dev *input;
struct workqueue_struct *msc_send_workqueue;
+ struct workqueue_struct *mhl_workq;
+ struct work_struct mhl_intr_work;
u16 *rcp_key_code_tbl;
size_t rcp_key_code_tbl_len;
struct scrpd_struct scrpd;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 272fe77..8b604e3 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -94,6 +94,7 @@
u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */
+ u8 raw_drive_strength; /* 197 */
u8 out_of_int_time; /* 198 */
u8 raw_s_a_timeout; /* 217 */
u8 raw_hc_erase_gap_size; /* 221 */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 764beec..b626915 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -303,6 +303,7 @@
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
+#define EXT_CSD_DRIVE_STRENGTH 197 /* RO */
#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index f36ee04..e332368 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -1,7 +1,7 @@
/* include/linux/msm_mdp.h
*
* Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014 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
@@ -79,7 +79,8 @@
#define MSMFB_WRITEBACK_SET_MIRRORING_HINT _IOW(MSMFB_IOCTL_MAGIC, 167, \
unsigned int)
#define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 168, unsigned int)
-
+#define MSMFB_OVERLAY_PREPARE _IOWR(MSMFB_IOCTL_MAGIC, 169, \
+ struct mdp_overlay_list)
#define FB_TYPE_3D_PANEL 0x10101010
#define MDP_IMGTYPE2_START 0x10000
#define MSMFB_DRIVER_VERSION 0xF9E8D701
@@ -811,6 +812,7 @@
#define MDSS_MAX_BL_BRIGHTNESS 255
#define AD_BL_LIN_LEN 256
+#define AD_BL_ATT_LUT_LEN 33
#define MDSS_AD_MODE_AUTO_BL 0x0
#define MDSS_AD_MODE_AUTO_STR 0x1
@@ -839,9 +841,13 @@
uint16_t frame_h;
uint8_t logo_v;
uint8_t logo_h;
+ uint32_t alpha;
+ uint32_t alpha_base;
uint32_t bl_lin_len;
+ uint32_t bl_att_len;
uint32_t *bl_lin;
uint32_t *bl_lin_inv;
+ uint32_t *bl_att_lut;
};
#define MDSS_AD_BL_CTRL_MODE_EN 1
@@ -965,6 +971,8 @@
uint8_t rgb_pipes;
uint8_t vig_pipes;
uint8_t dma_pipes;
+ uint8_t max_smp_cnt;
+ uint8_t smp_per_pipe;
uint32_t features;
};
@@ -1010,6 +1018,24 @@
struct mdp_rect roi;
};
+/**
+* struct mdp_overlay_list - argument for ioctl MSMFB_OVERLAY_PREPARE
+* @num_overlays: Number of overlay layers as part of the frame.
+* @overlay_list: Pointer to a list of overlay structures identifying
+* the layers as part of the frame
+* @flags: Flags can be used to extend behavior.
+* @processed_overlays: Output parameter indicating how many pipes were
+* successful. If there are no errors this number should
+* match num_overlays. Otherwise it will indicate the last
+* successful index for overlay that couldn't be set.
+*/
+struct mdp_overlay_list {
+ uint32_t num_overlays;
+ struct mdp_overlay **overlay_list;
+ uint32_t flags;
+ uint32_t processed_overlays;
+};
+
struct mdp_page_protection {
uint32_t page_protection;
};
@@ -1063,6 +1089,7 @@
int msm_fb_writeback_stop(struct fb_info *info);
int msm_fb_writeback_terminate(struct fb_info *info);
int msm_fb_writeback_set_secure(struct fb_info *info, int enable);
+int msm_fb_writeback_iommu_ref(struct fb_info *info, int enable);
#endif
#endif /*_MSM_MDP_H_*/
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 7be6cd2..d797797 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -615,6 +615,28 @@
* @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
* return back to normal.
*
+ * @NL80211_CMD_GET_COALESCE: Get currently supported coalesce rules.
+ * @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules.
+ *
+ * @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the
+ * the new channel information (Channel Switch Announcement - CSA)
+ * in the beacon for some time (as defined in the
+ * %NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the
+ * new channel. Userspace provides the new channel information (using
+ * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel
+ * width). %NL80211_ATTR_CH_SWITCH_BLOCK_TX may be supplied to inform
+ * other station that transmission must be blocked until the channel
+ * switch is complete.
+ *
+ * @NL80211_CMD_VENDOR: Vendor-specified command/event. The command is specified
+ * by the %NL80211_ATTR_VENDOR_ID attribute and a sub-command in
+ * %NL80211_ATTR_VENDOR_SUBCMD. Parameter(s) can be transported in
+ * %NL80211_ATTR_VENDOR_DATA.
+ * For feature advertisement, the %NL80211_ATTR_VENDOR_DATA attribute is
+ * used in the wiphy data as a nested attribute containing descriptions
+ * (&struct nl80211_vendor_cmd_info) of the supported vendor commands.
+ * This may also be sent as an event with the same attributes.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -778,6 +800,13 @@
NL80211_CMD_CRIT_PROTOCOL_START,
NL80211_CMD_CRIT_PROTOCOL_STOP,
+ NL80211_CMD_GET_COALESCE,
+ NL80211_CMD_SET_COALESCE,
+
+ NL80211_CMD_CHANNEL_SWITCH,
+
+ NL80211_CMD_VENDOR,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1402,6 +1431,21 @@
* @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported
* supported operating classes.
*
+ * @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space
+ * controls DFS operation in IBSS mode. If the flag is included in
+ * %NL80211_CMD_JOIN_IBSS request, the driver will allow use of DFS
+ * channels and reports radar events to userspace. Userspace is required
+ * to react to radar events, e.g. initiate a channel switch or leave the
+ * IBSS network.
+ *
+ * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if
+ * %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet)
+ * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command
+ * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this
+ * attribute is also used for vendor command feature advertisement
+ * @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy
+ * info, containing a nested array of possible events
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1715,6 +1759,20 @@
NL80211_ATTR_STA_SUPPORTED_CHANNELS,
NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
+
+ NL80211_ATTR_HANDLE_DFS,
+
+ NL80211_ATTR_SUPPORT_5_MHZ,
+ NL80211_ATTR_SUPPORT_10_MHZ,
+
+ NL80211_ATTR_OPMODE_NOTIF,
+
+ NL80211_ATTR_VENDOR_ID,
+ NL80211_ATTR_VENDOR_SUBCMD,
+ NL80211_ATTR_VENDOR_DATA,
+
+ NL80211_ATTR_VENDOR_EVENTS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3178,4 +3236,24 @@
/* maximum duration for critical protocol measures */
#define NL80211_CRIT_PROTO_MAX_DURATION 5000 /* msec */
+/*
+ * If this flag is unset, the lower 24 bits are an OUI, if set
+ * a Linux nl80211 vendor ID is used (no such IDs are allocated
+ * yet, so that's not valid so far)
+ */
+#define NL80211_VENDOR_ID_IS_LINUX 0x80000000
+
+/**
+ * struct nl80211_vendor_cmd_info - vendor command data
+ * @vendor_id: If the %NL80211_VENDOR_ID_IS_LINUX flag is clear, then the
+ * value is a 24-bit OUI; if it is set then a separately allocated ID
+ * may be used, but no such IDs are allocated yet. New IDs should be
+ * added to this file when needed.
+ * @subcmd: sub-command ID for the command
+ */
+struct nl80211_vendor_cmd_info {
+ __u32 vendor_id;
+ __u32 subcmd;
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 2b47b88..13eb461 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -574,12 +574,10 @@
/**
* enum qpnp_adc_meas_timer_select - Selects the timer for which
* the appropriate polling frequency is set.
- * %ADC_MEAS_TIMER_SELECT1 - Select this timer if the client is USB_ID.
- * %ADC_MEAS_TIMER_SELECT2 - Select this timer if the client is batt_therm.
- * %ADC_MEAS_TIMER_SELECT3 - The timer is added only for completion. It is
- * not used by kernel space clients and user space clients cannot set
- * the polling frequency. The driver will set a appropriate polling
- * frequency to measure the user space clients from qpnp_adc_meas_timer_3.
+ * %ADC_MEAS_TIMER_SELECT1 - Select this timer for measurement polling interval
+ * for 1 second.
+ * %ADC_MEAS_TIMER_SELECT2 - Select this timer for 500ms measurement interval.
+ * %ADC_MEAS_TIMER_SELECT3 - Select this timer for 5 second interval.
*/
enum qpnp_adc_meas_timer_select {
ADC_MEAS_TIMER_SELECT1 = 0,
diff --git a/include/linux/regulator/cpr-regulator.h b/include/linux/regulator/cpr-regulator.h
index e6a8f58..9d06a8c 100644
--- a/include/linux/regulator/cpr-regulator.h
+++ b/include/linux/regulator/cpr-regulator.h
@@ -18,9 +18,6 @@
#define CPR_REGULATOR_DRIVER_NAME "qcom,cpr-regulator"
-#define CPR_PVS_EFUSE_BITS_MAX 5
-#define CPR_PVS_EFUSE_BINS_MAX (1 << CPR_PVS_EFUSE_BITS_MAX)
-
/**
* enum cpr_fuse_corner_enum - CPR fuse corner enum values
* %CPR_FUSE_CORNER_SVS: Lowest voltage for APC
@@ -70,21 +67,6 @@
};
/**
- * enum pvs_process_enum - PVS process enum values
- * %APC_PVS_NO: No PVS
- * %APC_PVS_SLOW: Slow PVS process
- * %APC_PVS_NOM: Nominal PVS process
- * %APC_PVS_FAST: Fast PVS process
- */
-enum apc_pvs_process_enum {
- APC_PVS_NO,
- APC_PVS_SLOW,
- APC_PVS_NOM,
- APC_PVS_FAST,
- NUM_APC_PVS,
-};
-
-/**
* enum vdd_mx_vmin_method - Method to determine vmin for vdd-mx
* %VDD_MX_VMIN_APC: Equal to APC voltage
* %VDD_MX_VMIN_APC_CORNER_CEILING: Equal to PVS corner ceiling voltage
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 67f4d8c..7a7b3eb 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 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
@@ -525,6 +525,8 @@
* @port_xfer_status: Called by framework when client calls get_xfer_status
* API. Returns how much buffer is actually processed and the port
* errors (e.g. overflow/underflow) if any.
+ * @xfer_user_msg: Send user message to specified logical address. Underlying
+ * controller has to support sending user messages. Returns error if any.
*/
struct slim_controller {
struct device dev;
@@ -567,10 +569,13 @@
int (*framer_handover)(struct slim_controller *ctrl,
struct slim_framer *new_framer);
int (*port_xfer)(struct slim_controller *ctrl,
- u8 pn, u8 *iobuf, u32 len,
+ u8 pn, phys_addr_t iobuf, u32 len,
struct completion *comp);
enum slim_port_err (*port_xfer_status)(struct slim_controller *ctr,
- u8 pn, u8 **done_buf, u32 *done_len);
+ u8 pn, phys_addr_t *done_buf, u32 *done_len);
+ int (*xfer_user_msg)(struct slim_controller *ctrl,
+ u8 la, u8 mt, u8 mc,
+ struct slim_ele_access *msg, u8 *buf, u8 len);
};
#define to_slim_controller(d) container_of(d, struct slim_controller, dev)
@@ -634,6 +639,10 @@
* @driver: Device's driver. Pointer to access routines.
* @ctrl: Slimbus controller managing the bus hosting this device.
* @laddr: 1-byte Logical address of this device.
+ * @reported: Flag to indicate whether this device reported present. The flag
+ * is set when device reports present, and is reset when it reports
+ * absent. This flag alongwith notified flag below is used to call
+ * device_up, or device_down callbacks for driver of this device.
* @mark_define: List of channels pending definition/activation.
* @mark_suspend: List of channels pending suspend.
* @mark_removal: List of channels pending removal.
@@ -657,6 +666,7 @@
struct slim_driver *driver;
struct slim_controller *ctrl;
u8 laddr;
+ bool reported;
struct list_head mark_define;
struct list_head mark_suspend;
struct list_head mark_removal;
@@ -739,6 +749,20 @@
extern int slim_xfer_msg(struct slim_controller *ctrl,
struct slim_device *sbdev, struct slim_ele_access *msg,
u16 mc, u8 *rbuf, const u8 *wbuf, u8 len);
+
+/*
+ * User message:
+ * slim_user_msg: Send user message that is interpreted by destination device
+ * @sb: Client handle sending the message
+ * @la: Destination device for this user message
+ * @mt: Message Type (Soruce-referred, or Destination-referred)
+ * @mc: Message Code
+ * @msg: Message structure (start offset, number of bytes) to be sent
+ * @buf: data buffer to be sent
+ * @len: data buffer size in bytes
+ */
+extern int slim_user_msg(struct slim_device *sb, u8 la, u8 mt, u8 mc,
+ struct slim_ele_access *msg, u8 *buf, u8 len);
/* end of message apis */
/* Port management for manager device APIs */
@@ -778,8 +802,8 @@
* Client will call slim_port_get_xfer_status to get error and/or number of
* bytes transferred if used asynchronously.
*/
-extern int slim_port_xfer(struct slim_device *sb, u32 ph, u8 *iobuf, u32 len,
- struct completion *comp);
+extern int slim_port_xfer(struct slim_device *sb, u32 ph, phys_addr_t iobuf,
+ u32 len, struct completion *comp);
/*
* slim_port_get_xfer_status: Poll for port transfers, or get transfer status
@@ -801,7 +825,7 @@
* processed from the multiple transfers.
*/
extern enum slim_port_err slim_port_get_xfer_status(struct slim_device *sb,
- u32 ph, u8 **done_buf, u32 *done_len);
+ u32 ph, phys_addr_t *done_buf, u32 *done_len);
/*
* slim_connect_src: Connect source port to channel.
diff --git a/include/linux/smsc_hub.h b/include/linux/smsc_hub.h
index 9c0afc0..c87f21b 100644
--- a/include/linux/smsc_hub.h
+++ b/include/linux/smsc_hub.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -14,6 +14,7 @@
#ifndef __LINUX_SMSC3503_H__
#define __LINUX_SMSC3503_H__
+#define SMSC3502_ID 3502
#define SMSC3503_ID 3503
#define SMSC4604_ID 4604
#define SMSC3503_I2C_ADDR 0x08
@@ -52,6 +53,7 @@
int hub_reset;
int refclk_gpio;
int int_gpio;
+ int xo_clk_gpio;
};
#endif
diff --git a/include/linux/tick.h b/include/linux/tick.h
index dc15221..78ae909 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -92,7 +92,16 @@
# ifdef CONFIG_TICK_ONESHOT
extern struct cpumask *tick_get_broadcast_oneshot_mask(void);
# endif
+#else
+static inline struct tick_device *tick_get_broadcast_device(void)
+{
+ return NULL;
+}
+static inline struct cpumask *tick_get_broadcast_mask(void)
+{
+ return NULL;
+}
# endif /* BROADCAST */
# ifdef CONFIG_TICK_ONESHOT
@@ -109,6 +118,10 @@
static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
static inline void tick_check_idle(int cpu) { }
static inline int tick_oneshot_mode_active(void) { return 0; }
+static inline struct cpumask *tick_get_broadcast_oneshot_mask(void)
+{
+ return NULL;
+}
# endif
#else /* CONFIG_GENERIC_CLOCKEVENTS */
diff --git a/include/linux/usb/msm_ext_chg.h b/include/linux/usb/msm_ext_chg.h
index dcc786d..596ab49 100644
--- a/include/linux/usb/msm_ext_chg.h
+++ b/include/linux/usb/msm_ext_chg.h
@@ -6,6 +6,8 @@
#define USB_CHG_BLOCK_ULPI 1
#define USB_CHG_BLOCK_QSCRATCH 2
+#define USB_REQUEST_5V 1
+#define USB_REQUEST_9V 2
/**
* struct msm_usb_chg_info - MSM USB charger block details.
* @chg_block_type: The type of charger block. QSCRATCH/ULPI.
@@ -28,4 +30,10 @@
/* Vote against USB hardware low power mode */
#define MSM_USB_EXT_CHG_BLOCK_LPM _IOW('M', 1, int)
+/* To tell kernel about voltage being voted */
+#define MSM_USB_EXT_CHG_VOLTAGE_INFO _IOW('M', 2, int)
+
+/* To tell kernel about voltage request result */
+#define MSM_USB_EXT_CHG_RESULT _IOW('M', 3, int)
+
#endif /* __LINUX_USB_MSM_EXT_CHG_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 862a0cc..d16448a 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -464,6 +464,7 @@
struct completion ext_chg_wait;
int ui_enabled;
bool pm_done;
+ struct qpnp_vadc_chip *vadc_dev;
};
struct ci13xxx_platform_data {
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index e301d8f..a88a71d 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -494,9 +494,18 @@
MSM_ACTUATOR_WORD_ADDR,
};
+enum msm_actuator_i2c_operation {
+ MSM_ACT_WRITE = 0,
+ MSM_ACT_POLL,
+};
+
struct reg_settings_t {
uint16_t reg_addr;
+ enum msm_actuator_addr_type addr_type;
uint16_t reg_data;
+ enum msm_actuator_data_type data_type;
+ enum msm_actuator_i2c_operation i2c_operation;
+ uint32_t delay;
};
struct region_params_t {
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 3ba0abe..3828221 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -1,3 +1,14 @@
+/* Copyright (c) 2013-2014, 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 __MSMB_ISP__
#define __MSMB_ISP__
@@ -302,15 +313,16 @@
ISP_WM_BUS_OVERFLOW = 4,
ISP_STATS_OVERFLOW = 5,
ISP_CAMIF_ERROR = 6,
- ISP_SOF = 7,
- ISP_EOF = 8,
- ISP_EVENT_MAX = 9
+ ISP_BUF_DONE = 9,
+ ISP_EVENT_MAX = 10
};
#define ISP_EVENT_OFFSET 8
#define ISP_EVENT_BASE (V4L2_EVENT_PRIVATE_START)
#define ISP_BUF_EVENT_BASE (ISP_EVENT_BASE + (1 << ISP_EVENT_OFFSET))
#define ISP_STATS_EVENT_BASE (ISP_EVENT_BASE + (2 << ISP_EVENT_OFFSET))
+#define ISP_SOF_EVENT_BASE (ISP_EVENT_BASE + (3 << ISP_EVENT_OFFSET))
+#define ISP_EOF_EVENT_BASE (ISP_EVENT_BASE + (4 << ISP_EVENT_OFFSET))
#define ISP_EVENT_REG_UPDATE (ISP_EVENT_BASE + ISP_REG_UPDATE)
#define ISP_EVENT_START_ACK (ISP_EVENT_BASE + ISP_START_ACK)
#define ISP_EVENT_STOP_ACK (ISP_EVENT_BASE + ISP_STOP_ACK)
@@ -318,8 +330,9 @@
#define ISP_EVENT_WM_BUS_OVERFLOW (ISP_EVENT_BASE + ISP_WM_BUS_OVERFLOW)
#define ISP_EVENT_STATS_OVERFLOW (ISP_EVENT_BASE + ISP_STATS_OVERFLOW)
#define ISP_EVENT_CAMIF_ERROR (ISP_EVENT_BASE + ISP_CAMIF_ERROR)
-#define ISP_EVENT_SOF (ISP_EVENT_BASE + ISP_SOF)
-#define ISP_EVENT_EOF (ISP_EVENT_BASE + ISP_EOF)
+#define ISP_EVENT_SOF (ISP_SOF_EVENT_BASE)
+#define ISP_EVENT_EOF (ISP_EOF_EVENT_BASE)
+#define ISP_EVENT_BUF_DONE (ISP_EVENT_BASE + ISP_BUF_DONE)
#define ISP_EVENT_BUF_DIVERT (ISP_BUF_EVENT_BASE)
#define ISP_EVENT_STATS_NOTIFY (ISP_STATS_EVENT_BASE)
#define ISP_EVENT_COMP_STATS_NOTIFY (ISP_EVENT_STATS_NOTIFY + MSM_ISP_STATS_MAX)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 77084ed..ecaef21 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2046,6 +2046,34 @@
};
/**
+ * enum wiphy_vendor_command_flags - validation flags for vendor commands
+ * @WIPHY_VENDOR_CMD_NEED_WDEV: vendor command requires wdev
+ * @WIPHY_VENDOR_CMD_NEED_NETDEV: vendor command requires netdev
+ * @WIPHY_VENDOR_CMD_NEED_RUNNING: interface/wdev must be up & running
+ * (must be combined with %_WDEV or %_NETDEV)
+ */
+enum wiphy_vendor_command_flags {
+ WIPHY_VENDOR_CMD_NEED_WDEV = BIT(0),
+ WIPHY_VENDOR_CMD_NEED_NETDEV = BIT(1),
+ WIPHY_VENDOR_CMD_NEED_RUNNING = BIT(2),
+};
+
+/**
+ * struct wiphy_vendor_command - vendor command definition
+ * @info: vendor command identifying information, as used in nl80211
+ * @flags: flags, see &enum wiphy_vendor_command_flags
+ * @doit: callback for the operation, note that wdev is %NULL if the
+ * flags didn't ask for a wdev and non-%NULL otherwise; the data
+ * pointer may be %NULL if userspace provided no data at all
+ */
+struct wiphy_vendor_command {
+ struct nl80211_vendor_cmd_info info;
+ u32 flags;
+ int (*doit)(struct wiphy *wiphy, struct wireless_dev *wdev,
+ void *data, int data_len);
+};
+
+/**
* struct wiphy - wireless hardware description
* @reg_notifier: the driver's regulatory notification callback,
* note that if your driver uses wiphy_apply_custom_regulatory()
@@ -2144,6 +2172,11 @@
* supports for ACL.
* @country_ie_pref: country IE processing preferences specified
* by enum nl80211_country_ie_pref
+ *
+ * @vendor_commands: array of vendor commands supported by the hardware
+ * @n_vendor_commands: number of vendor commands
+ * @vendor_events: array of vendor events supported by the hardware
+ * @n_vendor_events: number of vendor events
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -2248,6 +2281,10 @@
const struct iw_handler_def *wext;
#endif
+ const struct wiphy_vendor_command *vendor_commands;
+ const struct nl80211_vendor_cmd_info *vendor_events;
+ int n_vendor_commands, n_vendor_events;
+
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
@@ -3128,6 +3165,121 @@
*/
void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
+/**
+ * DOC: Vendor commands
+ *
+ * Occasionally, there are special protocol or firmware features that
+ * can't be implemented very openly. For this and similar cases, the
+ * vendor command functionality allows implementing the features with
+ * (typically closed-source) userspace and firmware, using nl80211 as
+ * the configuration mechanism.
+ *
+ * A driver supporting vendor commands must register them as an array
+ * in struct wiphy, with handlers for each one, each command has an
+ * OUI and sub command ID to identify it.
+ *
+ * Note that this feature should not be (ab)used to implement protocol
+ * features that could openly be shared across drivers. In particular,
+ * it must never be required to use vendor commands to implement any
+ * "normal" functionality that higher-level userspace like connection
+ * managers etc. need.
+ */
+
+struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
+ enum nl80211_commands cmd,
+ enum nl80211_attrs attr,
+ int approxlen);
+
+struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+ enum nl80211_commands cmd,
+ enum nl80211_attrs attr,
+ int vendor_event_idx,
+ int approxlen, gfp_t gfp);
+
+void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp);
+
+/**
+ * cfg80211_vendor_cmd_alloc_reply_skb - allocate vendor command reply
+ * @wiphy: the wiphy
+ * @approxlen: an upper bound of the length of the data that will
+ * be put into the skb
+ *
+ * This function allocates and pre-fills an skb for a reply to
+ * a vendor command. Since it is intended for a reply, calling
+ * it outside of a vendor command's doit() operation is invalid.
+ *
+ * The returned skb is pre-filled with some identifying data in
+ * a way that any data that is put into the skb (with skb_put(),
+ * nla_put() or similar) will end up being within the
+ * %NL80211_ATTR_VENDOR_DATA attribute, so all that needs to be done
+ * with the skb is adding data for the corresponding userspace tool
+ * which can then read that data out of the testdata attribute. You
+ * must not modify the skb in any other way.
+ *
+ * When done, call cfg80211_vendor_cmd_reply() with the skb and return
+ * its error code as the result of the doit() operation.
+ *
+ * Return: An allocated and pre-filled skb. %NULL if any errors happen.
+ */
+static inline struct sk_buff *
+cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
+{
+ return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_VENDOR,
+ NL80211_ATTR_VENDOR_DATA, approxlen);
+}
+
+/**
+ * cfg80211_vendor_cmd_reply - send the reply skb
+ * @skb: The skb, must have been allocated with
+ * cfg80211_vendor_cmd_alloc_reply_skb()
+ *
+ * Since calling this function will usually be the last thing
+ * before returning from the vendor command doit() you should
+ * return the error code. Note that this function consumes the
+ * skb regardless of the return value.
+ *
+ * Return: An error code or 0 on success.
+ */
+int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
+
+/**
+ * cfg80211_vendor_event_alloc - allocate vendor-specific event skb
+ * @wiphy: the wiphy
+ * @event_idx: index of the vendor event in the wiphy's vendor_events
+ * @approxlen: an upper bound of the length of the data that will
+ * be put into the skb
+ * @gfp: allocation flags
+ *
+ * This function allocates and pre-fills an skb for an event on the
+ * vendor-specific multicast group.
+ *
+ * When done filling the skb, call cfg80211_vendor_event() with the
+ * skb to send the event.
+ *
+ * Return: An allocated and pre-filled skb. %NULL if any errors happen.
+ */
+static inline struct sk_buff *
+cfg80211_vendor_event_alloc(struct wiphy *wiphy, int approxlen,
+ int event_idx, gfp_t gfp)
+{
+ return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_VENDOR,
+ NL80211_ATTR_VENDOR_DATA,
+ event_idx, approxlen, gfp);
+}
+
+/**
+ * cfg80211_vendor_event - send the event
+ * @skb: The skb, must have been allocated with cfg80211_vendor_event_alloc()
+ * @gfp: allocation flags
+ *
+ * This function sends the given @skb, which must have been allocated
+ * by cfg80211_vendor_event_alloc(), as an event. It always consumes it.
+ */
+static inline void cfg80211_vendor_event(struct sk_buff *skb, gfp_t gfp)
+{
+ __cfg80211_send_event_skb(skb, gfp);
+}
+
#ifdef CONFIG_NL80211_TESTMODE
/**
* DOC: Test mode
@@ -3161,8 +3313,12 @@
* When done, call cfg80211_testmode_reply() with the skb and return
* its error code as the result of the @testmode_cmd operation.
*/
-struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
- int approxlen);
+static inline struct sk_buff *
+cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
+{
+ return __cfg80211_alloc_reply_skb(wiphy, NL80211_CMD_TESTMODE,
+ NL80211_ATTR_TESTDATA, approxlen);
+}
/**
* cfg80211_testmode_reply - send the reply skb
@@ -3175,7 +3331,10 @@
* Note that this function consumes the skb regardless of the
* return value.
*/
-int cfg80211_testmode_reply(struct sk_buff *skb);
+static inline int cfg80211_testmode_reply(struct sk_buff *skb)
+{
+ return cfg80211_vendor_cmd_reply(skb);
+}
/**
* cfg80211_testmode_alloc_event_skb - allocate testmode event
@@ -3196,8 +3355,13 @@
* When done filling the skb, call cfg80211_testmode_event() with the
* skb to send the event.
*/
-struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
- int approxlen, gfp_t gfp);
+static inline struct sk_buff *
+cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
+{
+ return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_TESTMODE,
+ NL80211_ATTR_TESTDATA, -1,
+ approxlen, gfp);
+}
/**
* cfg80211_testmode_event - send the event
@@ -3209,7 +3373,10 @@
* by cfg80211_testmode_alloc_event_skb(), as an event. It always
* consumes it.
*/
-void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp);
+static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
+{
+ __cfg80211_send_event_skb(skb, gfp);
+}
#define CFG80211_TESTMODE_CMD(cmd) .testmode_cmd = (cmd),
#define CFG80211_TESTMODE_DUMP(cmd) .testmode_dump = (cmd),
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 2c969cd..69944a6 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6874,6 +6874,7 @@
#define Q6AFE_LPASS_IBIT_CLK_1_P024_MHZ 0xFA000
#define Q6AFE_LPASS_IBIT_CLK_768_KHZ 0xBB800
#define Q6AFE_LPASS_IBIT_CLK_512_KHZ 0x7D000
+#define Q6AFE_LPASS_IBIT_CLK_256_KHZ 0x3E800
#define Q6AFE_LPASS_IBIT_CLK_DISABLE 0x0
/* Supported LPASS CLK sources */
diff --git a/include/sound/q6lsm.h b/include/sound/q6lsm.h
index 34eba81..8f06f20c 100644
--- a/include/sound/q6lsm.h
+++ b/include/sound/q6lsm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, 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
@@ -47,6 +47,8 @@
uint16_t user_sensitivity;
uint16_t kw_sensitivity;
bool started;
+ dma_addr_t lsm_cal_phy_addr;
+ uint32_t lsm_cal_size;
};
struct lsm_stream_cmd_open_tx {
@@ -123,10 +125,9 @@
int q6lsm_open(struct lsm_client *client);
int q6lsm_start(struct lsm_client *client, bool wait);
int q6lsm_stop(struct lsm_client *client, bool wait);
-int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len);
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len);
int q6lsm_snd_model_buf_free(struct lsm_client *client);
int q6lsm_close(struct lsm_client *client);
-int q6lsm_unmap_cal_blocks(void);
int q6lsm_register_sound_model(struct lsm_client *client,
enum lsm_detection_mode mode, u16 minkeyword,
u16 minuser, bool detectfailure);
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 31b6f25..e10e171 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -35,6 +35,7 @@
u64 elapsed_csecs64;
unsigned int elapsed_csecs;
bool wakeup = false;
+ int sleep_usecs = USEC_PER_MSEC;
do_gettimeofday(&start);
@@ -81,9 +82,12 @@
/*
* We need to retry, but first give the freezing tasks some
- * time to enter the regrigerator.
+ * time to enter the refrigerator. Start with an initial
+ * 1 ms sleep followed by exponential backoff until 8 ms.
*/
- msleep(10);
+ usleep_range(sleep_usecs / 2, sleep_usecs);
+ if (sleep_usecs < 8 * USEC_PER_MSEC)
+ sleep_usecs *= 2;
}
do_gettimeofday(&end);
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 604ee09..fd699ca 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -177,7 +177,7 @@
struct gen_pool_chunk *chunk;
int nbits = size >> pool->min_alloc_order;
int nbytes = sizeof(struct gen_pool_chunk) +
- (nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
+ BITS_TO_LONGS(nbits) * sizeof(long);
if (nbytes <= PAGE_SIZE)
chunk = kmalloc_node(nbytes, __GFP_ZERO, nid);
@@ -247,7 +247,7 @@
end_bit = (chunk->end_addr - chunk->start_addr) >> order;
nbytes = sizeof(struct gen_pool_chunk) +
- (end_bit + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
+ BITS_TO_LONGS(end_bit) * sizeof(long);
bit = find_next_bit(chunk->bits, end_bit, 0);
BUG_ON(bit < end_bit);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 036faee..2e85324 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -69,9 +69,7 @@
struct mutex sched_scan_mtx;
-#ifdef CONFIG_NL80211_TESTMODE
- struct genl_info *testmode_info;
-#endif
+ struct genl_info *cur_cmd_info;
struct work_struct conn_work;
struct work_struct event_work;
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index 0e44fa8..f6c74c9 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -18,7 +18,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country AL:
@@ -42,7 +42,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country AS:
@@ -64,7 +64,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country AW:
@@ -139,7 +139,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country BS:
@@ -163,7 +163,7 @@
(2402 - 2472 @ 40), (N/A, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country CH: DFS-ETSI
@@ -196,14 +196,14 @@
(2402 - 2472 @ 40), (N/A, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country CR:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
(5250 - 5330 @ 20), (3, 24), DFS
- (5490 - 5710 @ 20), (3, 24), DFS
+ (5490 - 5730 @ 20), (3, 24), DFS
(5735 - 5835 @ 20), (3, 30)
country CY: DFS-ETSI
@@ -271,7 +271,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
(5250 - 5330 @ 20), (3, 24), DFS
- (5490 - 5710 @ 20), (3, 24), DFS
+ (5490 - 5730 @ 20), (3, 24), DFS
(5735 - 5835 @ 20), (3, 30)
country EE: DFS-ETSI
@@ -295,6 +295,12 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country ET: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 80), (N/A, 20)
+ (5250 - 5330 @ 80), (N/A, 20), DFS
+ (5490 - 5710 @ 80), (N/A, 27), DFS
+
country FI: DFS-ETSI
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (N/A, 20)
@@ -336,7 +342,7 @@
(2402 - 2472 @ 40), (3, 30)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country GP:
@@ -369,21 +375,21 @@
(2402 - 2472 @ 40), (3, 30)
(5170 - 5250 @ 20), (6, 17)
(5250 - 5330 @ 20), (6, 24), DFS
- (5490 - 5710 @ 20), (6, 24), DFS
+ (5490 - 5730 @ 20), (6, 24), DFS
(5735 - 5835 @ 20), (6, 30)
country HN:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country HK:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country HR: DFS-ETSI
@@ -410,7 +416,7 @@
country ID:
# ref: http://www.postel.go.id/content/ID/regulasi/standardisasi/kepdir/bwa%205,8%20ghz.pdf
- (2402 - 2482 @ 40), (N/A, 20)
+ (2402 - 2482 @ 20), (N/A, 20)
(5735 - 5815 @ 20), (N/A, 23)
country IE: DFS-ETSI
@@ -456,7 +462,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country JP:
@@ -485,6 +491,13 @@
(5250 - 5330 @ 80), (N/A, 20), DFS
(5490 - 5710 @ 80), (N/A, 27), DFS
+country KY:
+ (2402 - 2472 @ 40), (N/A, 27)
+ (5170 - 5250 @ 80), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
+
country KP:
(2402 - 2482 @ 20), (N/A, 20)
(5170 - 5330 @ 20), (6, 20)
@@ -524,7 +537,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
(5250 - 5330 @ 20), (3, 20), DFS
- (5490 - 5710 @ 20), (3, 20), DFS
+ (5490 - 5730 @ 20), (3, 20), DFS
(5735 - 5835 @ 20), (3, 30)
country LT: DFS-ETSI
@@ -621,7 +634,7 @@
(2402 - 2472 @ 40), (3, 27)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country MW:
@@ -668,7 +681,7 @@
(2402 - 2482 @ 40), (N/A, 30)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country OM:
@@ -687,7 +700,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 20)
(5250 - 5330 @ 80), (6, 20), DFS
- (5490 - 5710 @ 80), (6, 27), DFS
+ (5490 - 5730 @ 80), (6, 27), DFS
(5735 - 5835 @ 80), (6, 30)
country PF:
@@ -707,7 +720,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country PK:
@@ -734,7 +747,7 @@
(2402 - 2472 @ 40), (3, 30)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country PY:
@@ -806,7 +819,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (6, 17)
(5250 - 5330 @ 80), (6, 24), DFS
- (5490 - 5710 @ 80), (6, 24), DFS
+ (5490 - 5730 @ 80), (6, 24), DFS
(5735 - 5835 @ 80), (6, 30)
country SI: DFS-ETSI
@@ -825,6 +838,12 @@
# 60 gHz band channels 1-4, ref: Etsi En 302 567
(57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR
+country SR: DFS-ETSI
+ (2400 - 2483.5 @ 40), (N/A, 100 mW)
+ (5150 - 5250 @ 80), (N/A, 100 mW), NO-OUTDOOR
+ (5250 - 5350 @ 80), (N/A, 100 mW), NO-OUTDOOR, DFS
+ (5470 - 5725 @ 80), (N/A, 500 mW), DFS
+
country SV:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 20), (3, 17)
@@ -837,21 +856,21 @@
country TW:
(2402 - 2472 @ 40), (3, 27)
(5270 - 5330 @ 40), (6, 17), DFS
- (5490 - 5710 @ 80), (6, 30), DFS
+ (5490 - 5730 @ 80), (6, 30), DFS
(5735 - 5815 @ 80), (6, 30)
country TH:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country TT:
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (3, 17)
(5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
+ (5490 - 5730 @ 40), (3, 20), DFS
(5735 - 5835 @ 40), (3, 30)
country TN:
@@ -895,8 +914,8 @@
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
(5490 - 5600 @ 80), (3, 24), DFS
- (5650 - 5710 @ 40), (3, 24), DFS
- (5710 - 5835 @ 80), (3, 30)
+ (5650 - 5730 @ 40), (3, 24), DFS
+ (5735 - 5835 @ 80), (3, 30)
# 60g band
# reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255
# channels 1,2,3, EIRP=40dBm(43dBm peak)
@@ -916,14 +935,14 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 40), (3, 17)
(5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
+ (5490 - 5730 @ 40), (3, 20), DFS
(5735 - 5835 @ 40), (3, 30)
country UZ:
(2402 - 2472 @ 40), (3, 27)
(5170 - 5250 @ 40), (3, 17)
(5250 - 5330 @ 40), (3, 20), DFS
- (5490 - 5710 @ 40), (3, 20), DFS
+ (5490 - 5730 @ 40), (3, 20), DFS
(5735 - 5835 @ 40), (3, 30)
country VE:
@@ -937,7 +956,7 @@
(2402 - 2482 @ 40), (N/A, 20)
(5170 - 5250 @ 80), (3, 17)
(5250 - 5330 @ 80), (3, 24), DFS
- (5490 - 5710 @ 80), (3, 24), DFS
+ (5490 - 5730 @ 80), (3, 24), DFS
(5735 - 5835 @ 80), (3, 30)
country VI:
@@ -947,6 +966,12 @@
(5470 - 5725 @ 80), (6, 24), DFS
(5725 - 5850 @ 80), (6, 30)
+country WS: DFS-ETSI
+ (2402 - 2482 @ 40), (N/A, 20)
+ (5170 - 5250 @ 20), (3, 17)
+ (5250 - 5330 @ 80), (3, 24), DFS
+ (5490 - 5710 @ 80), (3, 24), DFS
+
country YE:
(2402 - 2482 @ 40), (N/A, 20)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a251231..b73cfe5 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -225,6 +225,18 @@
[NL80211_ATTR_PEER_AID] = { .type = NLA_U16 },
[NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
+ [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
+ [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
+ [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
+ [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 },
+ [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 },
+ [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY },
+ [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY },
+ [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
+ [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
+ [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
+ [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
+ [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
};
/* policy for the key attributes */
@@ -1076,6 +1088,39 @@
NLA_PUT_U32(msg, NL80211_ATTR_MAC_ACL_MAX,
dev->wiphy.max_acl_mac_addrs);
+ if (dev->wiphy.n_vendor_commands) {
+ const struct nl80211_vendor_cmd_info *info;
+ struct nlattr *nested;
+
+ nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!nested)
+ goto nla_put_failure;
+
+ for (i = 0; i < dev->wiphy.n_vendor_commands; i++) {
+ info = &dev->wiphy.vendor_commands[i].info;
+ if (nla_put(msg, i + 1, sizeof(*info), info))
+ goto nla_put_failure;
+ }
+ nla_nest_end(msg, nested);
+ }
+
+ if (dev->wiphy.n_vendor_events) {
+ const struct nl80211_vendor_cmd_info *info;
+ struct nlattr *nested;
+
+ nested = nla_nest_start(msg,
+ NL80211_ATTR_VENDOR_EVENTS);
+ if (!nested)
+ goto nla_put_failure;
+
+ for (i = 0; i < dev->wiphy.n_vendor_events; i++) {
+ info = &dev->wiphy.vendor_events[i];
+ if (nla_put(msg, i + 1, sizeof(*info), info))
+ goto nla_put_failure;
+ }
+ nla_nest_end(msg, nested);
+ }
+
return genlmsg_end(msg, hdr);
nla_put_failure:
@@ -5211,6 +5256,57 @@
return cfg80211_leave_ibss(rdev, dev, false);
}
+static struct sk_buff *
+__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
+ int approxlen, u32 portid, u32 seq,
+ enum nl80211_commands cmd,
+ enum nl80211_attrs attr,
+ const struct nl80211_vendor_cmd_info *info,
+ gfp_t gfp)
+{
+ struct sk_buff *skb;
+ void *hdr;
+ struct nlattr *data;
+
+ skb = nlmsg_new(approxlen + 100, gfp);
+ if (!skb)
+ return NULL;
+
+ hdr = nl80211hdr_put(skb, portid, seq, 0, cmd);
+ if (!hdr) {
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
+ goto nla_put_failure;
+
+ if (info) {
+ if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
+ info->vendor_id))
+ goto nla_put_failure;
+ if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
+ info->subcmd))
+ goto nla_put_failure;
+ }
+
+ data = nla_nest_start(skb, attr);
+
+ ((void **)skb->cb)[0] = rdev;
+ ((void **)skb->cb)[1] = hdr;
+ ((void **)skb->cb)[2] = data;
+
+ return skb;
+
+ nla_put_failure:
+ kfree_skb(skb);
+ return NULL;
+}
+
+static struct genl_multicast_group nl80211_vendor_mcgrp = {
+ .name = "vendor",
+};
+
#ifdef CONFIG_NL80211_TESTMODE
static struct genl_multicast_group nl80211_testmode_mcgrp = {
.name = "testmode",
@@ -5226,11 +5322,11 @@
err = -EOPNOTSUPP;
if (rdev->ops->testmode_cmd) {
- rdev->testmode_info = info;
+ rdev->cur_cmd_info = info;
err = rdev->ops->testmode_cmd(&rdev->wiphy,
nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
- rdev->testmode_info = NULL;
+ rdev->cur_cmd_info = NULL;
}
return err;
@@ -5335,90 +5431,56 @@
return err;
}
-static struct sk_buff *
-__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
- int approxlen, u32 pid, u32 seq, gfp_t gfp)
-{
- struct sk_buff *skb;
- void *hdr;
- struct nlattr *data;
+#endif
- skb = nlmsg_new(approxlen + 100, gfp);
- if (!skb)
- return NULL;
-
- hdr = nl80211hdr_put(skb, pid, seq, 0, NL80211_CMD_TESTMODE);
- if (!hdr) {
- kfree_skb(skb);
- return NULL;
- }
-
- NLA_PUT_U32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
- data = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
-
- ((void **)skb->cb)[0] = rdev;
- ((void **)skb->cb)[1] = hdr;
- ((void **)skb->cb)[2] = data;
-
- return skb;
-
- nla_put_failure:
- kfree_skb(skb);
- return NULL;
-}
-
-struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
- int approxlen)
+struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+ enum nl80211_commands cmd,
+ enum nl80211_attrs attr,
+ int vendor_event_idx,
+ int approxlen, gfp_t gfp)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ const struct nl80211_vendor_cmd_info *info;
- if (WARN_ON(!rdev->testmode_info))
+ switch (cmd) {
+ case NL80211_CMD_TESTMODE:
+ if (WARN_ON(vendor_event_idx != -1))
+ return NULL;
+ info = NULL;
+ break;
+ case NL80211_CMD_VENDOR:
+ if (WARN_ON(vendor_event_idx < 0 ||
+ vendor_event_idx >= wiphy->n_vendor_events))
+ return NULL;
+ info = &wiphy->vendor_events[vendor_event_idx];
+ break;
+ default:
+ WARN_ON(1);
return NULL;
-
- return __cfg80211_testmode_alloc_skb(rdev, approxlen,
- rdev->testmode_info->snd_pid,
- rdev->testmode_info->snd_seq,
- GFP_KERNEL);
+ }
+ return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
+ cmd, attr, info, gfp);
}
-EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb);
+EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
-int cfg80211_testmode_reply(struct sk_buff *skb)
+void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
{
struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
void *hdr = ((void **)skb->cb)[1];
struct nlattr *data = ((void **)skb->cb)[2];
- if (WARN_ON(!rdev->testmode_info)) {
- kfree_skb(skb);
- return -EINVAL;
- }
-
nla_nest_end(skb, data);
genlmsg_end(skb, hdr);
- return genlmsg_reply(skb, rdev->testmode_info);
+
+ if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
+ nl80211_vendor_mcgrp.id, gfp);
+ else
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
+ nl80211_testmode_mcgrp.id, gfp);
}
-EXPORT_SYMBOL(cfg80211_testmode_reply);
+EXPORT_SYMBOL(__cfg80211_send_event_skb);
-struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
- int approxlen, gfp_t gfp)
-{
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp);
-}
-EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
-
-void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
-{
- void *hdr = ((void **)skb->cb)[1];
- struct nlattr *data = ((void **)skb->cb)[2];
-
- nla_nest_end(skb, data);
- genlmsg_end(skb, hdr);
- genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp);
-}
-EXPORT_SYMBOL(cfg80211_testmode_event);
-#endif
static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
{
@@ -6635,6 +6697,105 @@
return rdev->ops->update_ft_ies(&rdev->wiphy, dev, &ft_params);
}
+static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int i, err;
+ u32 vid, subcmd;
+
+ if (!rdev->wiphy.vendor_commands)
+ return -EOPNOTSUPP;
+
+ if (IS_ERR(wdev)) {
+ err = PTR_ERR(wdev);
+ if (err != -EINVAL)
+ return err;
+ wdev = NULL;
+ } else if (wdev->wiphy != &rdev->wiphy) {
+ return -EINVAL;
+ }
+
+ if (!info->attrs[NL80211_ATTR_VENDOR_ID] ||
+ !info->attrs[NL80211_ATTR_VENDOR_SUBCMD])
+ return -EINVAL;
+
+ vid = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_ID]);
+ subcmd = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_SUBCMD]);
+ for (i = 0; i < rdev->wiphy.n_vendor_commands; i++) {
+ const struct wiphy_vendor_command *vcmd;
+ void *data = NULL;
+ int len = 0;
+
+ vcmd = &rdev->wiphy.vendor_commands[i];
+
+ if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
+ continue;
+
+ if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV)) {
+ if (!wdev)
+ return -EINVAL;
+ if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
+ !wdev->netdev)
+ return -EINVAL;
+
+ if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
+ if (wdev->netdev &&
+ !netif_running(wdev->netdev))
+ return -ENETDOWN;
+ }
+ } else {
+ wdev = NULL;
+ }
+
+ if (info->attrs[NL80211_ATTR_VENDOR_DATA]) {
+ data = nla_data(info->attrs[NL80211_ATTR_VENDOR_DATA]);
+ len = nla_len(info->attrs[NL80211_ATTR_VENDOR_DATA]);
+ }
+
+ return rdev->wiphy.vendor_commands[i].doit(&rdev->wiphy, wdev,
+ data, len);
+ }
+
+ return -EOPNOTSUPP;
+}
+
+struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
+ enum nl80211_commands cmd,
+ enum nl80211_attrs attr,
+ int approxlen)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ if (WARN_ON(!rdev->cur_cmd_info))
+ return NULL;
+
+ return __cfg80211_alloc_vendor_skb(rdev, approxlen,
+ 0,
+ 0,
+ cmd, attr, NULL, GFP_KERNEL);
+}
+EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
+
+int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
+{
+ struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
+ void *hdr = ((void **)skb->cb)[1];
+ struct nlattr *data = ((void **)skb->cb)[2];
+
+ if (WARN_ON(!rdev->cur_cmd_info)) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ nla_nest_end(skb, data);
+ genlmsg_end(skb, hdr);
+ return genlmsg_reply(skb, rdev->cur_cmd_info);
+}
+EXPORT_SYMBOL(cfg80211_vendor_cmd_reply);
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -7239,7 +7400,14 @@
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
-
+ {
+ .cmd = NL80211_CMD_VENDOR,
+ .doit = nl80211_vendor_cmd,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -8562,6 +8730,9 @@
if (err)
goto err_out;
#endif
+ err = genl_register_mc_group(&nl80211_fam, &nl80211_vendor_mcgrp);
+ if (err)
+ goto err_out;
err = netlink_register_notifier(&nl80211_netlink_notifier);
if (err)
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c
old mode 100644
new mode 100755
index af648e0..120e0dc
--- a/net/wireless/wext-core.c
+++ b/net/wireless/wext-core.c
@@ -19,7 +19,9 @@
#include <net/netlink.h>
#include <net/wext.h>
#include <net/net_namespace.h>
-
+#ifdef KW_TAINT_ANALYSIS
+ extern void * get_tainted_stuff();
+#endif
typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
unsigned int, struct iw_request_info *,
iw_handler);
@@ -1006,8 +1008,13 @@
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
- void __user *arg)
+ void __user *arg_actual)
{
+ #ifdef KW_TAINT_ANALYSIS
+ void __user *arg = (void __user *)get_tainted_stuff();
+ #else
+ void __user *arg = (void __user *)arg_actual;
+ #endif
struct iw_request_info info = { .cmd = cmd, .flags = 0 };
int ret;
@@ -1056,7 +1063,11 @@
int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg)
{
+ #ifdef KW_TAINT_ANALYSIS
+ void __user *argp = (void __user *)get_tainted_stuff();
+ #else
void __user *argp = (void __user *)arg;
+ #endif
struct iw_request_info info;
struct iwreq iwr;
char *colon;
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
old mode 100644
new mode 100755
index a306bc6..c143046
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -59,7 +59,9 @@
#include <net/x25.h>
#include <net/compat.h>
-
+#ifdef KW_TAINT_ANALYSIS
+ extern void * get_tainted_stuff();
+#endif
int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20;
int sysctl_x25_call_request_timeout = X25_DEFAULT_T21;
int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22;
@@ -1625,7 +1627,7 @@
#ifdef CONFIG_COMPAT
static int compat_x25_subscr_ioctl(unsigned int cmd,
- struct compat_x25_subscrip_struct __user *x25_subscr32)
+ struct compat_x25_subscrip_struct __user *x25_subscr32_actual)
{
struct compat_x25_subscrip_struct x25_subscr;
struct x25_neigh *nb;
@@ -1633,6 +1635,11 @@
int rc = -EINVAL;
rc = -EFAULT;
+ #ifdef KW_TAINT_ANALYSIS
+ struct compat_x25_subscrip_struct __user *x25_subscr32 = (struct compat_x25_subscrip_struct __user *)get_tainted_stuff();
+ #else
+ struct compat_x25_subscrip_struct __user *x25_subscr32 = x25_subscr32_actual;
+ #endif
if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32)))
goto out;
@@ -1675,7 +1682,11 @@
static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg)
{
+ #ifdef KW_TAINT_ANALYSIS
+ void __user *argp = (void __user *)get_tainted_stuff();
+ #else
void __user *argp = compat_ptr(arg);
+ #endif
struct sock *sk = sock->sk;
int rc = -ENOIOCTLCMD;
diff --git a/net/x25/x25_link.c b/net/x25/x25_link.c
old mode 100644
new mode 100755
index 4acacf3..c82fcc2
--- a/net/x25/x25_link.c
+++ b/net/x25/x25_link.c
@@ -31,6 +31,9 @@
#include <linux/init.h>
#include <net/x25.h>
+#ifdef KW_TAINT_ANALYSIS
+ extern void * get_tainted_stuff();
+#endif
LIST_HEAD(x25_neigh_list);
DEFINE_RWLOCK(x25_neigh_list_lock);
@@ -338,13 +341,17 @@
/*
* Handle the ioctls that control the subscription functions.
*/
-int x25_subscr_ioctl(unsigned int cmd, void __user *arg)
+int x25_subscr_ioctl(unsigned int cmd, void __user *arg_actual)
{
struct x25_subscrip_struct x25_subscr;
struct x25_neigh *nb;
struct net_device *dev;
int rc = -EINVAL;
-
+ #ifdef KW_TAINT_ANALYSIS
+ void __user *arg = (void __user *)get_tainted_stuff();
+ #else
+ void __user *arg = arg_actual;
+ #endif
if (cmd != SIOCX25GSUBSCRIP && cmd != SIOCX25SSUBSCRIP)
goto out;
diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c
old mode 100644
new mode 100755
index cf63662..7a1778a
--- a/net/x25/x25_route.c
+++ b/net/x25/x25_route.c
@@ -21,7 +21,9 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <net/x25.h>
-
+#ifdef KW_TAINT_ANALYSIS
+ extern void * get_tainted_stuff();
+#endif
LIST_HEAD(x25_route_list);
DEFINE_RWLOCK(x25_route_list_lock);
@@ -179,12 +181,16 @@
/*
* Handle the ioctls that control the routing functions.
*/
-int x25_route_ioctl(unsigned int cmd, void __user *arg)
+int x25_route_ioctl(unsigned int cmd, void __user *arg_actual)
{
struct x25_route_struct rt;
struct net_device *dev;
int rc = -EINVAL;
-
+ #ifdef KW_TAINT_ANALYSIS
+ void __user *arg = (void __user *)get_tainted_stuff();
+ #else
+ void __user *arg = arg_actual;
+ #endif
if (cmd != SIOCADDRT && cmd != SIOCDELRT)
goto out;
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index fe4eb34..452bbab 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -189,6 +189,7 @@
* end of impedance measurement
*/
struct list_head reg_save_restore;
+ u32 micb_en_count;
};
static unsigned short rx_digital_gain_reg[] = {
@@ -1697,6 +1698,9 @@
snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x04);
snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL,
0x80, 0x80);
+ msm8x10_wcd->micb_en_count++;
+ pr_debug("%s micb_en_count : %d", __func__,
+ msm8x10_wcd->micb_en_count);
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20100);
@@ -1704,6 +1708,10 @@
wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
+ if (msm8x10_wcd->micb_en_count > 0)
+ msm8x10_wcd->micb_en_count--;
+ pr_debug("%s micb_en_count : %d", __func__,
+ msm8x10_wcd->micb_en_count);
snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL,
0x80, 0x00);
/* Let MBHC module know so micbias switch to be off */
@@ -2802,6 +2810,7 @@
enum wcd9xxx_micbias_num micb_num)
{
int rc;
+ struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
if (micb_num != MBHC_MICBIAS1) {
rc = -EINVAL;
@@ -2811,13 +2820,18 @@
if (enable)
rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
DAPM_MICBIAS_EXTERNAL_STANDALONE);
- else
+ else {
+ if (msm8x10_wcd->micb_en_count > 0) {
+ msm8x10_wcd->micb_en_count--;
+ pr_debug("%s micb_en_count : %d", __func__,
+ msm8x10_wcd->micb_en_count);
+ return 0;
+ }
rc = snd_soc_dapm_disable_pin(&codec->dapm,
DAPM_MICBIAS_EXTERNAL_STANDALONE);
+ }
snd_soc_dapm_sync(&codec->dapm);
- snd_soc_update_bits(codec, WCD9XXX_A_MICB_1_CTL,
- 0x80, enable ? 0x80 : 0x00);
err:
if (rc)
pr_debug("%s: Failed to force %s micbias", __func__,
@@ -3291,6 +3305,8 @@
on_demand_supply_name[ON_DEMAND_MICBIAS]);
atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
+ msm8x10_wcd_priv->micb_en_count = 0;
+
ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
&msm8x10_wcd_priv->resmgr,
codec, msm8x10_wcd_enable_mbhc_micbias,
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index e3c9ad3..d84ba90 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -1110,14 +1110,14 @@
SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
tapan_pa_gain_get, tapan_pa_gain_put),
- SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 14, 1,
+ SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 20, 1,
line_gain),
- SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 14, 1,
+ SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 20, 1,
line_gain),
- SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 14, 1,
+ SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 20, 1,
line_gain),
- SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 14, 1,
+ SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 20, 1,
line_gain),
SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 8, 1,
@@ -5523,7 +5523,8 @@
mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
break;
case PA_DISABLE:
- wcd9xxx_enable_static_pa(mbhc, false);
+ if (!mbhc->hph_pa_dac_state)
+ wcd9xxx_enable_static_pa(mbhc, false);
wcd9xxx_restore_registers(codec, &tapan->reg_save_restore);
break;
}
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index cf33a9d..b72590f 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -1652,6 +1652,21 @@
"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
};
+static const char * const iir_inp2_text[] = {
+ "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+ "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const iir_inp3_text[] = {
+ "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+ "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const iir_inp4_text[] = {
+ "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+ "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
static const struct soc_enum rx_mix1_inp1_chain_enum =
SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
@@ -1800,6 +1815,24 @@
static const struct soc_enum iir2_inp1_mux_enum =
SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B1_CTL, 0, 18, iir_inp1_text);
+static const struct soc_enum iir1_inp2_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ1_B2_CTL, 0, 18, iir_inp2_text);
+
+static const struct soc_enum iir2_inp2_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B2_CTL, 0, 18, iir_inp2_text);
+
+static const struct soc_enum iir1_inp3_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ1_B3_CTL, 0, 18, iir_inp3_text);
+
+static const struct soc_enum iir2_inp3_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B3_CTL, 0, 18, iir_inp3_text);
+
+static const struct soc_enum iir1_inp4_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ1_B4_CTL, 0, 18, iir_inp4_text);
+
+static const struct soc_enum iir2_inp4_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ2_B4_CTL, 0, 18, iir_inp4_text);
+
static const struct snd_kcontrol_new rx_mix1_inp1_mux =
SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
@@ -2025,6 +2058,24 @@
static const struct snd_kcontrol_new iir2_inp1_mux =
SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
+static const struct snd_kcontrol_new iir1_inp2_mux =
+ SOC_DAPM_ENUM("IIR1 INP2 Mux", iir1_inp2_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp2_mux =
+ SOC_DAPM_ENUM("IIR2 INP2 Mux", iir2_inp2_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp3_mux =
+ SOC_DAPM_ENUM("IIR1 INP3 Mux", iir1_inp3_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp3_mux =
+ SOC_DAPM_ENUM("IIR2 INP3 Mux", iir2_inp3_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp4_mux =
+ SOC_DAPM_ENUM("IIR1 INP4 Mux", iir1_inp4_mux_enum);
+
+static const struct snd_kcontrol_new iir2_inp4_mux =
+ SOC_DAPM_ENUM("IIR2 INP4 Mux", iir2_inp4_mux_enum);
+
static const struct snd_kcontrol_new anc1_mux =
SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
@@ -4012,6 +4063,120 @@
{"IIR2 INP1 MUX", "RX6", "SLIM RX6"},
{"IIR2 INP1 MUX", "RX7", "SLIM RX7"},
+ {"IIR1", NULL, "IIR1 INP2 MUX"},
+ {"IIR1 INP2 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR1 INP2 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR1 INP2 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR1 INP2 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR1 INP2 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR1 INP2 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR1 INP2 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR1 INP2 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR1 INP2 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR1 INP2 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR1 INP2 MUX", "RX1", "SLIM RX1"},
+ {"IIR1 INP2 MUX", "RX2", "SLIM RX2"},
+ {"IIR1 INP2 MUX", "RX3", "SLIM RX3"},
+ {"IIR1 INP2 MUX", "RX4", "SLIM RX4"},
+ {"IIR1 INP2 MUX", "RX5", "SLIM RX5"},
+ {"IIR1 INP2 MUX", "RX6", "SLIM RX6"},
+ {"IIR1 INP2 MUX", "RX7", "SLIM RX7"},
+
+ {"IIR2", NULL, "IIR2 INP2 MUX"},
+ {"IIR2 INP2 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR2 INP2 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR2 INP2 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR2 INP2 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR2 INP2 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR2 INP2 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR2 INP2 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR2 INP2 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR2 INP2 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR2 INP2 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR2 INP2 MUX", "RX1", "SLIM RX1"},
+ {"IIR2 INP2 MUX", "RX2", "SLIM RX2"},
+ {"IIR2 INP2 MUX", "RX3", "SLIM RX3"},
+ {"IIR2 INP2 MUX", "RX4", "SLIM RX4"},
+ {"IIR2 INP2 MUX", "RX5", "SLIM RX5"},
+ {"IIR2 INP2 MUX", "RX6", "SLIM RX6"},
+ {"IIR2 INP2 MUX", "RX7", "SLIM RX7"},
+
+ {"IIR1", NULL, "IIR1 INP3 MUX"},
+ {"IIR1 INP3 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR1 INP3 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR1 INP3 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR1 INP3 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR1 INP3 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR1 INP3 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR1 INP3 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR1 INP3 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR1 INP3 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR1 INP3 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR1 INP3 MUX", "RX1", "SLIM RX1"},
+ {"IIR1 INP3 MUX", "RX2", "SLIM RX2"},
+ {"IIR1 INP3 MUX", "RX3", "SLIM RX3"},
+ {"IIR1 INP3 MUX", "RX4", "SLIM RX4"},
+ {"IIR1 INP3 MUX", "RX5", "SLIM RX5"},
+ {"IIR1 INP3 MUX", "RX6", "SLIM RX6"},
+ {"IIR1 INP3 MUX", "RX7", "SLIM RX7"},
+
+ {"IIR2", NULL, "IIR2 INP3 MUX"},
+ {"IIR2 INP3 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR2 INP3 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR2 INP3 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR2 INP3 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR2 INP3 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR2 INP3 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR2 INP3 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR2 INP3 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR2 INP3 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR2 INP3 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR2 INP3 MUX", "RX1", "SLIM RX1"},
+ {"IIR2 INP3 MUX", "RX2", "SLIM RX2"},
+ {"IIR2 INP3 MUX", "RX3", "SLIM RX3"},
+ {"IIR2 INP3 MUX", "RX4", "SLIM RX4"},
+ {"IIR2 INP3 MUX", "RX5", "SLIM RX5"},
+ {"IIR2 INP3 MUX", "RX6", "SLIM RX6"},
+ {"IIR2 INP3 MUX", "RX7", "SLIM RX7"},
+
+ {"IIR1", NULL, "IIR1 INP4 MUX"},
+ {"IIR1 INP4 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR1 INP4 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR1 INP4 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR1 INP4 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR1 INP4 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR1 INP4 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR1 INP4 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR1 INP4 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR1 INP4 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR1 INP4 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR1 INP4 MUX", "RX1", "SLIM RX1"},
+ {"IIR1 INP4 MUX", "RX2", "SLIM RX2"},
+ {"IIR1 INP4 MUX", "RX3", "SLIM RX3"},
+ {"IIR1 INP4 MUX", "RX4", "SLIM RX4"},
+ {"IIR1 INP4 MUX", "RX5", "SLIM RX5"},
+ {"IIR1 INP4 MUX", "RX6", "SLIM RX6"},
+ {"IIR1 INP4 MUX", "RX7", "SLIM RX7"},
+
+ {"IIR2", NULL, "IIR2 INP4 MUX"},
+ {"IIR2 INP4 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR2 INP4 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR2 INP4 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR2 INP4 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR2 INP4 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR2 INP4 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR2 INP4 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR2 INP4 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR2 INP4 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR2 INP4 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR2 INP4 MUX", "RX1", "SLIM RX1"},
+ {"IIR2 INP4 MUX", "RX2", "SLIM RX2"},
+ {"IIR2 INP4 MUX", "RX3", "SLIM RX3"},
+ {"IIR2 INP4 MUX", "RX4", "SLIM RX4"},
+ {"IIR2 INP4 MUX", "RX5", "SLIM RX5"},
+ {"IIR2 INP4 MUX", "RX6", "SLIM RX6"},
+ {"IIR2 INP4 MUX", "RX7", "SLIM RX7"},
+
{"MIC BIAS1 Internal1", NULL, "LDO_H"},
{"MIC BIAS1 Internal2", NULL, "LDO_H"},
{"MIC BIAS1 External", NULL, "LDO_H"},
@@ -5147,6 +5312,24 @@
return 0;
}
+static int taiko_codec_iir_mux_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_write(codec, w->reg, snd_soc_read(codec, w->reg));
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_write(codec, w->reg, snd_soc_read(codec, w->reg));
+ break;
+ }
+ return 0;
+}
+
static int taiko_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -5645,10 +5828,40 @@
SND_SOC_DAPM_POST_PMD),
/* Sidetone */
- SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+ SND_SOC_DAPM_MUX_E("IIR1 INP1 MUX", TAIKO_A_CDC_IIR1_GAIN_B1_CTL, 0, 0,
+ &iir1_inp1_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("IIR1 INP2 MUX", TAIKO_A_CDC_IIR1_GAIN_B2_CTL, 0, 0,
+ &iir1_inp2_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("IIR1 INP3 MUX", TAIKO_A_CDC_IIR1_GAIN_B3_CTL, 0, 0,
+ &iir1_inp3_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("IIR1 INP4 MUX", TAIKO_A_CDC_IIR1_GAIN_B4_CTL, 0, 0,
+ &iir1_inp4_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
SND_SOC_DAPM_MIXER("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
- SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
+ SND_SOC_DAPM_MUX_E("IIR2 INP1 MUX", TAIKO_A_CDC_IIR2_GAIN_B1_CTL, 0, 0,
+ &iir2_inp1_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("IIR2 INP2 MUX", TAIKO_A_CDC_IIR2_GAIN_B2_CTL, 0, 0,
+ &iir2_inp2_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("IIR2 INP3 MUX", TAIKO_A_CDC_IIR2_GAIN_B3_CTL, 0, 0,
+ &iir2_inp3_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("IIR2 INP4 MUX", TAIKO_A_CDC_IIR2_GAIN_B4_CTL, 0, 0,
+ &iir2_inp4_mux, taiko_codec_iir_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
SND_SOC_DAPM_MIXER("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
/* AUX PGA */
@@ -6513,7 +6726,8 @@
/* Clean up starts */
/* Turn off PA ramp generator */
snd_soc_write(codec, WCD9XXX_A_CDC_PA_RAMP_B1_CTL, 0x0);
- wcd9xxx_enable_static_pa(mbhc, false);
+ if (!mbhc->hph_pa_dac_state)
+ wcd9xxx_enable_static_pa(mbhc, false);
wcd9xxx_restore_registers(codec, &taiko->reg_save_restore);
break;
}
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 12348f8..2b43ab6 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -689,20 +689,6 @@
.name = "DTMF_RX_HOSTLESS",
},
{
- .capture = {
- .stream_name = "Listen Audio Service Capture",
- .aif_name = "LSM_UL_HL",
- .rates = SNDRV_PCM_RATE_16000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .channels_min = 1,
- .channels_max = 1,
- .rate_min = 16000,
- .rate_max = 16000,
- },
- .ops = &msm_fe_dai_ops,
- .name = "LSM",
- },
- {
.playback = {
.stream_name = "VoLTE Stub Playback",
.aif_name = "VOLTE_STUB_DL",
@@ -801,6 +787,118 @@
.ops = &msm_fe_dai_ops,
.name = "QCHAT",
},
+ {
+ .capture = {
+ .stream_name = "Listen 1 Audio Service Capture",
+ .aif_name = "LSM1_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM1",
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 2 Audio Service Capture",
+ .aif_name = "LSM2_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM2",
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 3 Audio Service Capture",
+ .aif_name = "LSM3_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM3",
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 4 Audio Service Capture",
+ .aif_name = "LSM4_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM4",
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 5 Audio Service Capture",
+ .aif_name = "LSM5_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM5",
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 6 Audio Service Capture",
+ .aif_name = "LSM6_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM6",
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 7 Audio Service Capture",
+ .aif_name = "LSM7_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM7",
+ },
+ {
+ .capture = {
+ .stream_name = "Listen 8 Audio Service Capture",
+ .aif_name = "LSM8_UL_HL",
+ .rates = SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_min = 16000,
+ .rate_max = 16000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "LSM8",
+ },
};
static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index be0cb7f..17e99dd 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -32,6 +32,10 @@
#include "../codecs/wcd9xxx-common.h"
#include "../codecs/wcd9306.h"
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_192KHZ 192000
+
#define DRV_NAME "msm8226-asoc-tapan"
#define MSM_SLIM_0_RX_MAX_CHANNELS 2
@@ -154,6 +158,8 @@
static int ext_spk_amp_gpio = -1;
static int vdd_spkr_gpio = -1;
static int msm_proxy_rx_ch = 2;
+
+static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static inline int param_is_mask(int p)
@@ -388,6 +394,9 @@
static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight"};
+static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192"};
static const struct soc_enum msm_enum[] = {
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
@@ -399,6 +408,58 @@
SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
};
+static int slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (slim0_rx_sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ slim0_rx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -725,8 +786,7 @@
pr_debug("%s()\n", __func__);
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
slim0_rx_bit_format);
-
- rate->min = rate->max = 48000;
+ rate->min = rate->max = slim0_rx_sample_rate;
channels->min = channels->max = msm_slim_0_rx_ch;
return 0;
@@ -780,6 +840,8 @@
SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(3, slim0_rx_sample_rate_text),
};
static const struct snd_kcontrol_new msm_snd_controls[] = {
@@ -795,7 +857,8 @@
msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[3],
slim0_rx_bit_format_get, slim0_rx_bit_format_put),
-
+ SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[4],
+ slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
};
static int msm_afe_set_config(struct snd_soc_codec *codec)
@@ -1410,9 +1473,9 @@
},
/* LSM FE */
{
- .name = "Listen Audio Service",
- .stream_name = "Listen Audio Service",
- .cpu_dai_name = "LSM",
+ .name = "Listen 1 Audio Service",
+ .stream_name = "Listen 1 Audio Service",
+ .cpu_dai_name = "LSM1",
.platform_name = "msm-lsm-client",
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
@@ -1439,6 +1502,142 @@
/* this dainlink has playback support */
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
},
+ {
+ .name = "Listen 2 Audio Service",
+ .stream_name = "Listen 2 Audio Service",
+ .cpu_dai_name = "LSM2",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM2,
+ },
+ {
+ .name = "Listen 3 Audio Service",
+ .stream_name = "Listen 3 Audio Service",
+ .cpu_dai_name = "LSM3",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM3,
+ },
+ {
+ .name = "Listen 4 Audio Service",
+ .stream_name = "Listen 4 Audio Service",
+ .cpu_dai_name = "LSM4",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM4,
+ },
+ {
+ .name = "Listen 5 Audio Service",
+ .stream_name = "Listen 5 Audio Service",
+ .cpu_dai_name = "LSM5",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM5,
+ },
+ {
+ .name = "Listen 6 Audio Service",
+ .stream_name = "Listen 6 Audio Service",
+ .cpu_dai_name = "LSM6",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM6,
+ },
+ {
+ .name = "Listen 7 Audio Service",
+ .stream_name = "Listen 7 Audio Service",
+ .cpu_dai_name = "LSM7",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM7,
+ },
+ {
+ .name = "Listen 8 Audio Service",
+ .stream_name = "Listen 8 Audio Service",
+ .cpu_dai_name = "LSM8",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM8,
+ },
+ {
+ .name = "INT_HFP_BT Hostless",
+ .stream_name = "INT_HFP_BT Hostless",
+ .cpu_dai_name = "INT_HFP_BT_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "MSM8226 HFP TX",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ /* this dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 0eea842..ca5e217 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -2117,9 +2117,9 @@
},
/* LSM FE */
{
- .name = "Listen Audio Service",
- .stream_name = "Listen Audio Service",
- .cpu_dai_name = "LSM",
+ .name = "Listen 1 Audio Service",
+ .stream_name = "Listen 1 Audio Service",
+ .cpu_dai_name = "LSM1",
.platform_name = "msm-lsm-client",
.dynamic = 1,
.trigger = { SND_SOC_DPCM_TRIGGER_POST,
@@ -2256,6 +2256,111 @@
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
},
{
+ .name = "Listen 2 Audio Service",
+ .stream_name = "Listen 2 Audio Service",
+ .cpu_dai_name = "LSM2",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM2,
+ },
+ {
+ .name = "Listen 3 Audio Service",
+ .stream_name = "Listen 3 Audio Service",
+ .cpu_dai_name = "LSM3",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM3,
+ },
+ {
+ .name = "Listen 4 Audio Service",
+ .stream_name = "Listen 4 Audio Service",
+ .cpu_dai_name = "LSM4",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM4,
+ },
+ {
+ .name = "Listen 5 Audio Service",
+ .stream_name = "Listen 5 Audio Service",
+ .cpu_dai_name = "LSM5",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM5,
+ },
+ {
+ .name = "Listen 6 Audio Service",
+ .stream_name = "Listen 6 Audio Service",
+ .cpu_dai_name = "LSM6",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM6,
+ },
+ {
+ .name = "Listen 7 Audio Service",
+ .stream_name = "Listen 7 Audio Service",
+ .cpu_dai_name = "LSM7",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM7,
+ },
+ {
+ .name = "Listen 8 Audio Service",
+ .stream_name = "Listen 8 Audio Service",
+ .cpu_dai_name = "LSM8",
+ .platform_name = "msm-lsm-client",
+ .dynamic = 1,
+ .trigger = { SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST },
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM8,
+ },
+ {
.name = LPASS_BE_SLIMBUS_4_TX,
.stream_name = "Slimbus4 Capture",
.cpu_dai_name = "msm-dai-q6-dev.16393",
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 7b3a028..89df806 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -624,8 +624,8 @@
btn_low[5] = 190;
btn_high[5] = 228;
btn_low[6] = 229;
- btn_high[6] = 269;
- btn_low[7] = 270;
+ btn_high[6] = 264;
+ btn_low[7] = 265;
btn_high[7] = 500;
n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
n_ready[0] = 80;
@@ -894,6 +894,21 @@
.codec_name = "snd-soc-dummy",
.be_id = MSM_FRONTEND_DAI_QCHAT,
},
+ {/* hw:x,15 */
+ .name = "MSM8X10 Media9",
+ .stream_name = "MultiMedia9",
+ .cpu_dai_name = "MultiMedia9",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9
+ },
/* Backend I2S DAI Links */
{
.name = LPASS_BE_SEC_MI2S_RX,
@@ -1039,6 +1054,19 @@
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_suspend = 1,
},
+ /* Incall Music 2 BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE2_PLAYBACK_TX,
+ .stream_name = "Voice2 Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32770",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
};
struct snd_soc_card snd_soc_card_msm8x10 = {
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 4e04bef..df15c59 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, 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
@@ -1151,13 +1151,6 @@
result = result2;
}
- result2 = q6lsm_unmap_cal_blocks();
- if (result2 < 0) {
- pr_err("%s: lsm_unmap_cal_blocks failed, err = %d\n",
- __func__, result2);
- result = result2;
- }
-
result2 = q6asm_unmap_cal_blocks();
if (result2 < 0) {
pr_err("%s: asm_unmap_cal_blocks failed, err = %d\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 41ef3e3..143508f 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -472,11 +472,12 @@
COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
prtd->compr_cap.max_fragments =
COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
- prtd->compr_cap.num_codecs = 4;
+ prtd->compr_cap.num_codecs = 5;
prtd->compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
prtd->compr_cap.codecs[2] = SND_AUDIOCODEC_AC3;
prtd->compr_cap.codecs[3] = SND_AUDIOCODEC_EAC3;
+ prtd->compr_cap.codecs[4] = SND_AUDIOCODEC_PCM;
}
static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
@@ -486,8 +487,22 @@
struct msm_compr_audio *prtd = runtime->private_data;
struct asm_aac_cfg aac_cfg;
int ret = 0;
+ uint16_t bit_width = 16;
switch (prtd->codec) {
+ case FORMAT_LINEAR_PCM:
+ pr_debug("SND_AUDIOCODEC_PCM\n");
+ if (prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE)
+ bit_width = 24;
+ ret = q6asm_media_format_block_pcm_format_support(
+ prtd->audio_client,
+ prtd->sample_rate,
+ prtd->num_channels,
+ bit_width);
+ if (ret < 0)
+ pr_err("%s: CMD Format block failed\n", __func__);
+
+ break;
case FORMAT_MP3:
/* no media format block needed */
break;
@@ -744,6 +759,7 @@
if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0) &&
(prtd->gapless_state.stream_opened[stream_index])) {
+ prtd->gapless_state.stream_opened[stream_index] = 0;
spin_unlock_irqrestore(&prtd->lock, flags);
pr_debug(" close stream %d", NEXT_STREAM_ID(stream_id));
q6asm_stream_cmd(ac, CMD_CLOSE, NEXT_STREAM_ID(stream_id));
@@ -753,6 +769,7 @@
stream_index = STREAM_ARRAY_INDEX(stream_id);
if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0) &&
(prtd->gapless_state.stream_opened[stream_index])) {
+ prtd->gapless_state.stream_opened[stream_index] = 0;
spin_unlock_irqrestore(&prtd->lock, flags);
pr_debug("close stream %d", stream_id);
q6asm_stream_cmd(ac, CMD_CLOSE, stream_id);
@@ -826,6 +843,12 @@
pr_debug("%s: sample_rate %d\n", __func__, prtd->sample_rate);
switch (params->codec.id) {
+ case SND_AUDIOCODEC_PCM: {
+ pr_debug("SND_AUDIOCODEC_PCM\n");
+ prtd->codec = FORMAT_LINEAR_PCM;
+ break;
+ }
+
case SND_AUDIOCODEC_MP3: {
pr_debug("SND_AUDIOCODEC_MP3\n");
prtd->codec = FORMAT_MP3;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 2c001fa..98d7dee 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -59,6 +59,7 @@
#define INVALID_SESSION -1
#define SESSION_TYPE_RX 0
#define SESSION_TYPE_TX 1
+#define MAX_LSM_SESSIONS 8
#define EC_PORT_ID_PRIMARY_MI2S_TX 1
#define EC_PORT_ID_SECONDARY_MI2S_TX 2
@@ -153,12 +154,12 @@
* If new back-end is defined, add new back-end DAI ID at the end of enum
*/
-
+#define SRS_TRUMEDIA_INDEX 2
union srs_trumedia_params_u {
struct srs_trumedia_params srs_params;
unsigned short int raw_params[1];
};
-static union srs_trumedia_params_u msm_srs_trumedia_params[2];
+static union srs_trumedia_params_u msm_srs_trumedia_params[SRS_TRUMEDIA_INDEX];
static int srs_port_id = -1;
static void srs_send_params(int port_id, unsigned int techs,
@@ -429,7 +430,7 @@
path_type,
msm_bedais[i].sample_rate,
msm_bedais[i].channel,
- topology, false,
+ topology, perf_mode,
bits_per_sample);
payload.copp_ids[payload.num_copps++] =
@@ -1186,7 +1187,7 @@
SRS_PARAM_OFFSET_MASK) >> 16);
value = (unsigned short)(ucontrol->value.integer.value[0] &
SRS_PARAM_VALUE_MASK);
- if (offset < max) {
+ if ((offset < max) && (index < SRS_TRUMEDIA_INDEX)) {
msm_srs_trumedia_params[index].raw_params[offset] = value;
pr_debug("SRS %s: index set... (max %d, requested %d, val %d, paramblockidx %d)",
__func__, max, offset, value, index);
@@ -1475,7 +1476,7 @@
msm_route_ext_ec_ref = AFE_PORT_INVALID;
break;
}
- if (voc_set_ext_ec_ref(msm_route_ext_ec_ref, state)) {
+ if (!voc_set_ext_ec_ref(msm_route_ext_ec_ref, state)) {
mutex_unlock(&routing_lock);
snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
} else {
@@ -2610,13 +2611,52 @@
0, 1, 0, msm_routing_get_fm_pcmrx_switch_mixer,
msm_routing_put_fm_pcmrx_switch_mixer);
+static const struct snd_kcontrol_new pri_mi2s_rx_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, msm_routing_get_switch_mixer,
+ msm_routing_put_switch_mixer);
+
static const struct soc_enum lsm_mux_enum =
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mad_audio_mux_text), mad_audio_mux_text);
-static const struct snd_kcontrol_new lsm_mux =
+
+static const struct snd_kcontrol_new lsm1_mux =
SOC_DAPM_ENUM_EXT("LSM1 MUX", lsm_mux_enum,
msm_routing_lsm_mux_get,
msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new lsm2_mux =
+ SOC_DAPM_ENUM_EXT("LSM2 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new lsm3_mux =
+ SOC_DAPM_ENUM_EXT("LSM3 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+static const struct snd_kcontrol_new lsm4_mux =
+ SOC_DAPM_ENUM_EXT("LSM4 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new lsm5_mux =
+ SOC_DAPM_ENUM_EXT("LSM5 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+static const struct snd_kcontrol_new lsm6_mux =
+ SOC_DAPM_ENUM_EXT("LSM6 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+static const struct snd_kcontrol_new lsm7_mux =
+ SOC_DAPM_ENUM_EXT("LSM7 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+static const struct snd_kcontrol_new lsm8_mux =
+ SOC_DAPM_ENUM_EXT("LSM8 MUX", lsm_mux_enum,
+ msm_routing_lsm_mux_get,
+ msm_routing_lsm_mux_put);
+
+
static const char * const lsm_func_text[] = {
"None", "AUDIO", "BEACON", "ULTRASOUND", "SWAUDIO",
};
@@ -3157,13 +3197,30 @@
SND_SOC_DAPM_AIF_OUT("PRI_MI2S_UL_HL",
"Primary MI2S_TX Hostless Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PRI_MI2S_DL_HL",
+ "Primary MI2S_RX Hostless Playback",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MI2S_DL_HL", "MI2S_RX_HOSTLESS Playback",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("DTMF_DL_HL", "DTMF_RX_HOSTLESS Playback",
0, 0, 0, 0),
/* LSM */
- SND_SOC_DAPM_AIF_OUT("LSM_UL_HL", "Listen Audio Service Capture",
+ SND_SOC_DAPM_AIF_OUT("LSM1_UL_HL", "Listen 1 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM2_UL_HL", "Listen 2 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM3_UL_HL", "Listen 3 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM4_UL_HL", "Listen 4 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM5_UL_HL", "Listen 5 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM6_UL_HL", "Listen 6 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM7_UL_HL", "Listen 7 Audio Service Capture",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LSM8_UL_HL", "Listen 8 Audio Service Capture",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("QCHAT_DL", "QCHAT Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("QCHAT_UL", "QCHAT Capture", 0, 0, 0, 0),
@@ -3249,9 +3306,18 @@
&fm_switch_mixer_controls),
SND_SOC_DAPM_SWITCH("PCM_RX_DL_HL", SND_SOC_NOPM, 0, 0,
&pcm_rx_switch_mixer_controls),
+ SND_SOC_DAPM_SWITCH("PRI_MI2S_RX_DL_HL", SND_SOC_NOPM, 0, 0,
+ &pri_mi2s_rx_switch_mixer_controls),
/* Mux Definitions */
- SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm_mux),
+ SND_SOC_DAPM_MUX("LSM1 MUX", SND_SOC_NOPM, 0, 0, &lsm1_mux),
+ SND_SOC_DAPM_MUX("LSM2 MUX", SND_SOC_NOPM, 0, 0, &lsm2_mux),
+ SND_SOC_DAPM_MUX("LSM3 MUX", SND_SOC_NOPM, 0, 0, &lsm3_mux),
+ SND_SOC_DAPM_MUX("LSM4 MUX", SND_SOC_NOPM, 0, 0, &lsm4_mux),
+ SND_SOC_DAPM_MUX("LSM5 MUX", SND_SOC_NOPM, 0, 0, &lsm5_mux),
+ SND_SOC_DAPM_MUX("LSM6 MUX", SND_SOC_NOPM, 0, 0, &lsm6_mux),
+ SND_SOC_DAPM_MUX("LSM7 MUX", SND_SOC_NOPM, 0, 0, &lsm7_mux),
+ SND_SOC_DAPM_MUX("LSM8 MUX", SND_SOC_NOPM, 0, 0, &lsm8_mux),
SND_SOC_DAPM_MUX("SLIM_0_RX AANC MUX", SND_SOC_NOPM, 0, 0,
aanc_slim_0_rx_mux),
@@ -3781,7 +3847,62 @@
{"LSM1 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
{"LSM1 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
{"LSM1 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
- {"LSM_UL_HL", NULL, "LSM1 MUX"},
+ {"LSM1_UL_HL", NULL, "LSM1 MUX"},
+
+ {"LSM2 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM2 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM2 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM2 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM2 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM2_UL_HL", NULL, "LSM2 MUX"},
+
+
+ {"LSM3 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM3 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM3 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM3 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM3 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM3_UL_HL", NULL, "LSM3 MUX"},
+
+
+ {"LSM4 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM4 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM4 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM4 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM4 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM4_UL_HL", NULL, "LSM4 MUX"},
+
+ {"LSM5 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM5 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM5 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM5 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM5 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM5_UL_HL", NULL, "LSM5 MUX"},
+
+ {"LSM6 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM6 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM6 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM6 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM6 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM6_UL_HL", NULL, "LSM6 MUX"},
+
+
+ {"LSM7 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM7 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM7 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM7 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM7 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM7_UL_HL", NULL, "LSM7 MUX"},
+
+
+ {"LSM8 MUX", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
+ {"LSM8 MUX", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
+ {"LSM8 MUX", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
+ {"LSM8 MUX", "SLIMBUS_4_TX", "SLIMBUS_4_TX"},
+ {"LSM8 MUX", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
+ {"LSM8_UL_HL", NULL, "LSM8 MUX"},
+
+
{"QCHAT_Tx Mixer", "PRI_TX_QCHAT", "PRI_I2S_TX"},
{"QCHAT_Tx Mixer", "SLIM_0_TX_QCHAT", "SLIMBUS_0_TX"},
@@ -3803,6 +3924,8 @@
{"MI2S_UL_HL", NULL, "MI2S_TX"},
{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
{"PCM_RX", NULL, "PCM_RX_DL_HL"},
+ {"PRI_MI2S_RX_DL_HL", "Switch", "PRI_MI2S_DL_HL"},
+ {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX_DL_HL"},
{"MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
{"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
{"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},
@@ -4060,7 +4183,7 @@
path_type,
bedai->sample_rate,
channels,
- topology, false,
+ topology, fe_dai_perf_mode[i][session_type],
bits_per_sample);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 54f5e4a..f2b0436 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 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
@@ -79,9 +79,16 @@
MSM_FRONTEND_DAI_VOICE_STUB,
MSM_FRONTEND_DAI_VOLTE,
MSM_FRONTEND_DAI_DTMF_RX,
- MSM_FRONTEND_DAI_LSM1,
MSM_FRONTEND_DAI_VOICE2,
MSM_FRONTEND_DAI_QCHAT,
+ MSM_FRONTEND_DAI_LSM1,
+ MSM_FRONTEND_DAI_LSM2,
+ MSM_FRONTEND_DAI_LSM3,
+ MSM_FRONTEND_DAI_LSM4,
+ MSM_FRONTEND_DAI_LSM5,
+ MSM_FRONTEND_DAI_LSM6,
+ MSM_FRONTEND_DAI_LSM7,
+ MSM_FRONTEND_DAI_LSM8,
MSM_FRONTEND_DAI_MAX,
};
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 3dac1f9..74b79dd 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -133,6 +133,10 @@
static ssize_t audio_output_latency_dbgfs_read(struct file *file,
char __user *buf, size_t count, loff_t *ppos)
{
+ if (out_buffer == NULL) {
+ pr_err("%s: out_buffer is null\n", __func__);
+ return 0;
+ }
snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",\
out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,\
out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec);
@@ -178,6 +182,10 @@
static ssize_t audio_input_latency_dbgfs_read(struct file *file,
char __user *buf, size_t count, loff_t *ppos)
{
+ if (in_buffer == NULL) {
+ pr_err("%s: in_buffer is null\n", __func__);
+ return 0;
+ }
snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",\
in_cont_tv.tv_sec, in_cont_tv.tv_usec);
return simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos,
@@ -293,17 +301,38 @@
static void config_debug_fs_init(void)
{
out_buffer = kmalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
+ if (out_buffer == NULL) {
+ pr_err("%s: kmalloc() for out_buffer failed\n", __func__);
+ goto outbuf_fail;
+ }
+ in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL);
+ if (in_buffer == NULL) {
+ pr_err("%s: kmalloc() for in_buffer failed\n", __func__);
+ goto inbuf_fail;
+ }
out_dentry = debugfs_create_file("audio_out_latency_measurement_node",\
S_IRUGO | S_IWUSR | S_IWGRP,\
NULL, NULL, &audio_output_latency_debug_fops);
- if (IS_ERR(out_dentry))
- pr_err("debugfs_create_file failed\n");
- in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL);
+ if (IS_ERR(out_dentry)) {
+ pr_err("%s: debugfs_create_file failed\n", __func__);
+ goto file_fail;
+ }
in_dentry = debugfs_create_file("audio_in_latency_measurement_node",\
S_IRUGO | S_IWUSR | S_IWGRP,\
NULL, NULL, &audio_input_latency_debug_fops);
- if (IS_ERR(in_dentry))
- pr_err("debugfs_create_file failed\n");
+ if (IS_ERR(in_dentry)) {
+ pr_err("%s: debugfs_create_file failed\n", __func__);
+ goto file_fail;
+ }
+ return;
+file_fail:
+ kfree(in_buffer);
+inbuf_fail:
+ kfree(out_buffer);
+outbuf_fail:
+ in_buffer = NULL;
+ out_buffer = NULL;
+ return;
}
#else
static void config_debug_fs_write(struct audio_buffer *ab)
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index e9352df..496a5ef 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -41,6 +41,11 @@
uint32_t nseg;
int i, j;
+ if (data == NULL) {
+ pr_err("%s: data argument is null\n", __func__);
+ return -EINVAL;
+ }
+
pr_debug("core msg: payload len = %u, apr resp opcode = 0x%X\n",
data->payload_size, data->opcode);
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index 9227b23..a88b733 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,7 @@
#define APR_TIMEOUT (5 * HZ)
#define LSM_CAL_SIZE 4096
+#define LSM_ALIGN_BOUNDARY 512
enum {
CMD_STATE_CLEARED = 0,
@@ -48,13 +49,11 @@
LSM_CONTROL_SESSION = 0x0F,
};
+#define CHECK_SESSION(x) (x < LSM_MIN_SESSION_ID || x > LSM_MAX_SESSION_ID)
struct lsm_common {
void *apr;
atomic_t apr_users;
- uint32_t lsm_cal_addr;
- uint32_t lsm_cal_size;
- uint32_t mmap_handle_for_cal;
- struct lsm_client common_client;
+ struct lsm_client common_client[LSM_MAX_SESSION_ID + 1];
struct mutex apr_lock;
};
@@ -93,9 +92,9 @@
}
payload = data->payload;
- pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n",
- __func__, client->session,
- data->opcode, data->token, data->payload_size);
+ pr_debug("%s: Session %d opcode 0x%x token 0x%x payload size %d\n"
+ "payload [0] = %x\n", __func__, client->session,
+ data->opcode, data->token, data->payload_size, payload[0]);
if (data->opcode == APR_BASIC_RSP_RESULT) {
token = data->token;
@@ -150,13 +149,13 @@
}
}
spin_unlock_irqrestore(&lsm_session_lock, flags);
+ pr_debug("%s: Alloc Session %d", __func__, n);
return ret;
}
static void q6lsm_session_free(struct lsm_client *client)
{
unsigned long flags;
-
pr_debug("%s: Freeing session ID %d\n", __func__, client->session);
spin_lock_irqsave(&lsm_session_lock, flags);
lsm_session[client->session] = LSM_INVALID_SESSION_ID;
@@ -207,13 +206,18 @@
kfree(client);
return NULL;
}
-
- pr_debug("%s: New client session %d\n", __func__, client->session);
client->session = n;
client->cb = cb;
client->priv = priv;
+ pr_debug("%s:Client session %d\n", __func__, client->session);
+ if (CHECK_SESSION(client->session)) {
+ kfree(client);
+ return NULL;
+ }
+ pr_debug("%s:Client Session %d\n", __func__, client->session);
client->apr = apr_register("ADSP", "LSM", q6lsm_callback,
- ((client->session) << 8 | 0x0001), client);
+ ((client->session) << 8 | client->session),
+ client);
if (client->apr == NULL) {
pr_err("%s: Registration with APR failed\n", __func__);
@@ -239,9 +243,12 @@
void q6lsm_client_free(struct lsm_client *client)
{
- if (!client || !client->session)
+ if (!client)
return;
-
+ if (CHECK_SESSION(client->session)) {
+ pr_err("%s: Invalid Session %d", __func__, client->session);
+ return;
+ }
apr_deregister(client->apr);
client->mmap_apr = NULL;
q6lsm_session_free(client);
@@ -308,8 +315,8 @@
hdr->src_domain = APR_DOMAIN_APPS;
hdr->dest_svc = APR_SVC_LSM;
hdr->dest_domain = APR_DOMAIN_ADSP;
- hdr->src_port = ((client->session << 8) & 0xFF00) | 0x01;
- hdr->dest_port = ((client->session << 8) & 0xFF00) | 0x01;
+ hdr->src_port = ((client->session << 8) & 0xFF00) | client->session;
+ hdr->dest_port = ((client->session << 8) & 0xFF00) | client->session;
hdr->pkt_size = pkt_size;
if (cmd_flg)
hdr->token = client->session;
@@ -331,7 +338,7 @@
if (rc)
pr_err("%s: Open failed opcode 0x%x, rc %d\n",
__func__, open.hdr.opcode, rc);
-
+ pr_debug("%s: leave %d\n", __func__, rc);
return rc;
}
@@ -429,15 +436,15 @@
q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd), true);
cmd.hdr.opcode = LSM_SESSION_CMD_REGISTER_SOUND_MODEL;
- cmd.model_addr_lsw = client->sound_model.phys;
- cmd.model_addr_msw = 0;
+ cmd.model_addr_lsw = lower_32_bits(client->sound_model.phys);
+ cmd.model_addr_msw = upper_32_bits(client->sound_model.phys);
cmd.model_size = client->sound_model.size;
/* read updated mem_map_handle by q6lsm_mmapcallback */
rmb();
cmd.mem_map_handle = client->sound_model.mem_map_handle;
- pr_debug("%s: lsw %x, size %d, handle %x\n", __func__,
- cmd.model_addr_lsw, cmd.model_size, cmd.mem_map_handle);
+ pr_debug("%s: addr %pa, size %d, handle %x\n", __func__,
+ &client->sound_model.phys, cmd.model_size, cmd.mem_map_handle);
rc = q6lsm_apr_send_pkt(client, client->apr, &cmd, true, NULL);
if (rc)
pr_err("%s: Failed cmd op[0x%x]rc[%d]\n", __func__,
@@ -458,6 +465,8 @@
return -EINVAL;
}
pr_debug("%s: session[%d]", __func__, client->session);
+ if (CHECK_SESSION(client->session))
+ return -EINVAL;
memset(&cmd, 0, sizeof(cmd));
q6lsm_add_hdr(client, &cmd.hdr, sizeof(cmd.hdr), false);
@@ -492,7 +501,7 @@
}
static int q6lsm_memory_map_regions(struct lsm_client *client,
- uint32_t dma_addr_p, uint32_t dma_buf_sz,
+ dma_addr_t dma_addr_p, uint32_t dma_buf_sz,
uint32_t *mmap_p)
{
struct avs_cmd_shared_mem_map_regions *mmap_regions = NULL;
@@ -502,9 +511,11 @@
int rc;
int cmd_size = 0;
- pr_debug("%s: dma_addr_p 0x%x, dma_buf_sz %d, mmap_p 0x%p, session %d\n",
- __func__, dma_addr_p, dma_buf_sz, mmap_p, client->session);
-
+ pr_debug("%s: dma_addr_p 0x%pa, dma_buf_sz %d, mmap_p 0x%p, session %d\n",
+ __func__, &dma_addr_p, dma_buf_sz, mmap_p,
+ client->session);
+ if (CHECK_SESSION(client->session))
+ return -EINVAL;
cmd_size = sizeof(struct avs_cmd_shared_mem_map_regions) +
sizeof(struct avs_shared_map_region_payload);
@@ -524,8 +535,8 @@
sizeof(struct avs_cmd_shared_mem_map_regions));
mregions = (struct avs_shared_map_region_payload *)payload;
- mregions->shm_addr_lsw = dma_addr_p;
- mregions->shm_addr_msw = 0;
+ mregions->shm_addr_lsw = lower_32_bits(dma_addr_p);
+ mregions->shm_addr_msw = upper_32_bits(dma_addr_p);
mregions->mem_size_bytes = dma_buf_sz;
rc = q6lsm_apr_send_pkt(client, client->mmap_apr, mmap_region_cmd,
@@ -545,7 +556,8 @@
struct avs_cmd_shared_mem_unmap_regions unmap;
int rc = 0;
int cmd_size = 0;
-
+ if (CHECK_SESSION(client->session))
+ return -EINVAL;
cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
q6lsm_add_mmaphdr(client, &unmap.hdr, cmd_size,
true, (client->session << 8));
@@ -569,107 +581,35 @@
struct lsm_cmd_set_params params;
struct acdb_cal_block lsm_cal;
- pr_debug("%s: enter\n", __func__);
-
+ pr_debug("%s: Session %d\n", __func__, client->session);
+ if (CHECK_SESSION(client->session))
+ return -EINVAL;
memset(&lsm_cal, 0, sizeof(lsm_cal));
get_lsm_cal(&lsm_cal);
- if (!lsm_cal.cal_size) {
- pr_err("%s: Could not get LSM calibration data\n", __func__);
- rc = -EINVAL;
- goto bail;
- }
-
/* Cache mmap address, only map once or if new addr */
- if ((lsm_common.lsm_cal_addr != lsm_cal.cal_paddr) ||
- (lsm_cal.cal_size > lsm_common.lsm_cal_size)) {
- if (lsm_common.lsm_cal_addr != 0) {
- rc = q6lsm_memory_unmap_regions(client,
- lsm_common.mmap_handle_for_cal);
- if (rc)
- pr_warn("%s: Unmapping %x failed, %d\n",
- __func__, lsm_common.lsm_cal_addr, rc);
- }
-
- rc = q6lsm_memory_map_regions(client, lsm_cal.cal_paddr,
- LSM_CAL_SIZE,
- &lsm_common.mmap_handle_for_cal);
- if (rc < 0) {
- pr_err("%s: Calibration data memory map failed, %d\n",
- __func__, rc);
- goto bail;
- }
- lsm_common.lsm_cal_addr = lsm_cal.cal_paddr;
- lsm_common.lsm_cal_size = LSM_CAL_SIZE;
- lsm_common.common_client.session = client->session;
- }
-
+ lsm_common.common_client[client->session].session = client->session;
q6lsm_add_hdr(client, ¶ms.hdr, sizeof(params), true);
params.hdr.opcode = LSM_SESSION_CMD_SET_PARAMS;
- params.data_payload_addr_lsw = lsm_cal.cal_paddr;
- params.data_payload_addr_msw = 0;
- /* read updated mem_map_handle by q6lsm_mmapcallback */
- rmb();
- params.mem_map_handle = lsm_common.mmap_handle_for_cal;
+ params.data_payload_addr_lsw = lower_32_bits(client->lsm_cal_phy_addr);
+ params.data_payload_addr_msw = upper_32_bits(client->lsm_cal_phy_addr);
+ params.mem_map_handle = client->sound_model.mem_map_handle;
params.data_payload_size = lsm_cal.cal_size;
-
+ pr_debug("%s: Cal Size = %x", __func__, client->lsm_cal_size);
rc = q6lsm_apr_send_pkt(client, client->apr, ¶ms, true, NULL);
if (rc)
pr_err("%s: Failed set_params opcode 0x%x, rc %d\n",
__func__, params.hdr.opcode, rc);
-bail:
return rc;
}
-int q6lsm_unmap_cal_blocks(void)
-{
- int result = 0;
- int result2 = 0;
-
- if (lsm_common.mmap_handle_for_cal == 0)
- goto done;
-
- if (lsm_common.common_client.mmap_apr == NULL) {
- lsm_common.common_client.mmap_apr = q6lsm_mmap_apr_reg();
- if (lsm_common.common_client.mmap_apr == NULL) {
- pr_err("%s: q6lsm_mmap_apr_reg failed\n",
- __func__);
- result = -EPERM;
- goto done;
- }
- }
-
- result2 = q6lsm_memory_unmap_regions(
- &lsm_common.common_client,
- lsm_common.mmap_handle_for_cal);
- if (result2 < 0) {
- pr_err("%s: unmap failed, err %d\n",
- __func__, result2);
- result = result2;
- } else {
- lsm_common.mmap_handle_for_cal = 0;
- }
-
- result2 = q6lsm_mmap_apr_dereg();
- if (result2 < 0) {
- pr_err("%s: q6lsm_mmap_apr_dereg failed, err %d\n",
- __func__, result2);
- result = result2;
- } else {
- lsm_common.common_client.mmap_apr = NULL;
- }
-
- lsm_common.lsm_cal_addr = 0;
- lsm_common.lsm_cal_size = 0;
-
-done:
- return result;
-}
-
int q6lsm_snd_model_buf_free(struct lsm_client *client)
{
int rc;
pr_debug("%s: Session id %d\n", __func__, client->session);
+ if (CHECK_SESSION(client->session))
+ return -EINVAL;
+
mutex_lock(&client->cmd_lock);
rc = q6lsm_memory_unmap_regions(client,
client->sound_model.mem_map_handle);
@@ -678,12 +618,16 @@
if (client->sound_model.data) {
ion_unmap_kernel(client->sound_model.client,
- client->sound_model.handle);
+ client->sound_model.handle);
ion_free(client->sound_model.client,
- client->sound_model.handle);
+ client->sound_model.handle);
ion_client_destroy(client->sound_model.client);
+ client->sound_model.client = NULL;
+ client->sound_model.handle = NULL;
client->sound_model.data = NULL;
client->sound_model.phys = 0;
+ client->lsm_cal_phy_addr = 0;
+ client->lsm_cal_size = 0;
}
mutex_unlock(&client->cmd_lock);
return rc;
@@ -695,7 +639,7 @@
struct lsm_client *client = NULL;
if (session_id == LSM_CONTROL_SESSION) {
- client = &lsm_common.common_client;
+ client = &lsm_common.common_client[session_id];
goto done;
}
@@ -724,19 +668,19 @@
struct lsm_client *client = NULL;
if (data->opcode == RESET_EVENTS) {
- pr_debug("%s: SSR event received 0x%x, event 0x%x, proc 0x%x\n",
- __func__, data->opcode, data->reset_event,
- data->reset_proc);
- lsm_common.lsm_cal_addr = 0;
+ sid = (data->token >> 8) & 0x0F;
+ pr_debug("%s: SSR event received 0x%x, event 0x%x,\n"
+ "proc 0x%x SID 0x%x\n", __func__, data->opcode,
+ data->reset_event, data->reset_proc, sid);
+ lsm_common.common_client[sid].lsm_cal_phy_addr = 0;
return 0;
}
command = payload[0];
retcode = payload[1];
- pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x\n", __func__,
- data->opcode, command, retcode);
-
sid = (data->token >> 8) & 0x0F;
+ pr_debug("%s: opcode 0x%x command 0x%x return code 0x%x SID 0x%x\n",
+ __func__, data->opcode, command, retcode, sid);
client = q6lsm_get_lsm_client(sid);
if (!client) {
pr_debug("%s: Session %d already freed\n", __func__, sid);
@@ -774,15 +718,31 @@
return 0;
}
-int q6lsm_snd_model_buf_alloc(struct lsm_client *client, uint32_t len)
+int q6lsm_snd_model_buf_alloc(struct lsm_client *client, size_t len)
{
int rc = -EINVAL;
+ struct acdb_cal_block lsm_cal;
+ size_t pad_zero = 0, total_mem = 0;
- if (!client)
+ if (!client || len <= LSM_ALIGN_BOUNDARY)
return rc;
-
+ memset(&lsm_cal, 0, sizeof(lsm_cal));
mutex_lock(&client->cmd_lock);
+ get_lsm_cal(&lsm_cal);
+ pr_debug("%s:Snd Model len = %d cal size %d", __func__,
+ len, lsm_cal.cal_size);
+ if (!lsm_cal.cal_paddr) {
+ pr_err("%s: No LSM calibration set for session", __func__);
+ mutex_unlock(&client->cmd_lock);
+ return -EINVAL;
+ }
if (!client->sound_model.data) {
+ client->sound_model.size = len;
+ pad_zero = (LSM_ALIGN_BOUNDARY -
+ (len % LSM_ALIGN_BOUNDARY));
+ total_mem = pad_zero + len + lsm_cal.cal_size;
+ pr_debug("%s: Pad zeros sound model %d Total mem %d\n",
+ __func__, pad_zero, total_mem);
client->sound_model.client =
msm_ion_client_create(UINT_MAX, "lsm_client");
if (IS_ERR_OR_NULL(client->sound_model.client)) {
@@ -791,8 +751,8 @@
goto fail;
}
client->sound_model.handle =
- ion_alloc(client->sound_model.client,
- len, SZ_4K, (0x1 << ION_AUDIO_HEAP_ID), 0);
+ ion_alloc(client->sound_model.client,
+ total_mem, SZ_4K, (0x1 << ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL(client->sound_model.handle)) {
pr_err("%s: ION memory allocation for AUDIO failed\n",
__func__);
@@ -817,7 +777,13 @@
goto fail;
}
memset(client->sound_model.data, 0, len);
- client->sound_model.size = len;
+ client->lsm_cal_phy_addr = (pad_zero +
+ client->sound_model.phys +
+ client->sound_model.size);
+ client->lsm_cal_size = lsm_cal.cal_size;
+ memcpy((client->sound_model.data + pad_zero +
+ client->sound_model.size),
+ (uint32_t *)lsm_cal.cal_kvaddr, len);
} else {
rc = -EBUSY;
goto fail;
@@ -825,7 +791,7 @@
mutex_unlock(&client->cmd_lock);
rc = q6lsm_memory_map_regions(client, client->sound_model.phys,
- client->sound_model.size,
+ len,
&client->sound_model.mem_map_handle);
if (rc < 0) {
pr_err("%s:CMD Memory_map_regions failed\n", __func__);
@@ -882,16 +848,18 @@
static int __init q6lsm_init(void)
{
+ int i = 0;
pr_debug("%s\n", __func__);
spin_lock_init(&lsm_session_lock);
spin_lock_init(&mmap_lock);
mutex_init(&lsm_common.apr_lock);
-
- lsm_common.common_client.session = LSM_CONTROL_SESSION;
- init_waitqueue_head(&lsm_common.common_client.cmd_wait);
- mutex_init(&lsm_common.common_client.cmd_lock);
- atomic_set(&lsm_common.common_client.cmd_state, CMD_STATE_CLEARED);
-
+ for (; i <= LSM_MAX_SESSION_ID; i++) {
+ lsm_common.common_client[i].session = LSM_CONTROL_SESSION;
+ init_waitqueue_head(&lsm_common.common_client[i].cmd_wait);
+ mutex_init(&lsm_common.common_client[i].cmd_lock);
+ atomic_set(&lsm_common.common_client[i].cmd_state,
+ CMD_STATE_CLEARED);
+ }
return 0;
}