Merge "mdss: support for solid fill with color specified by HAL"
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt b/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt
new file mode 100644
index 0000000..ee9a286
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/clock-krait-8974.txt
@@ -0,0 +1,98 @@
+Qualcomm MSM8974 Krait clock tree
+
+clock-krait-8974 is a device that represents the MSM8974 Krait subsystem
+clock tree. It lists the various power supplies that need to be scaled when
+the clocks are scaled and also other HW specific parameters like fmax tables,
+avs settings table, etc.
+
+Required properties:
+- compatible: Must be "qcom,clock-krait-8974"
+- reg: Pairs of physical base addresses and region sizes of
+ memory mapped registers.
+- reg-names: Names of the bases for the above registers. Expected
+ bases are:
+ "hfpll_l2_clk", "hfpll0_clk", ... "hfpllN_clk", "efuse"
+- cpuX-supply: The regulator powering the CPUX.
+- l2-dig-supply: The regulator powering the L2 digital logic.
+- hfpll-dig-supply: The regulator powering the HFPLL digital domains.
+- hfpll-analog-supply: The regulator powering the HFPLL analog domains.
+- qcom,l2-fmax: A table of L2 frequency to voltage mappings that
+ represents the max frequency (Hz) possible for each
+ supported voltage level (uV).
+- qcom,speedX-pvsY-bin-vZ:
+ A table of CPU frequency (Hz) to voltage (uV) and
+ current (uA) mapping that represents the max
+ frequency possible for each supported voltage level
+ for a CPU that's binned as speed bin X, PVS bin Y
+ based on characterization version Z. Speed and PVS
+ bin values can be between [0-7] and the version can
+ be between [0-3]
+
+Optional properties:
+- qcom,avs-tbl: A table of frequencies (Hz) and their corresponding
+ AVS DSCR register settings (32 bit value) to program
+ into the AVS HW. Frequencies with no AVS support do
+ not need to be listed in the table. If there is no
+ AVS support at all, then the whole property can be
+ omitted.
+- qcom,hfpll-config-val:
+ A 32 bit value to be programmed into the HFPLL
+ configuration control register.
+- qcom,hfpll-user-vco-mask:
+ The mask to be used when programming the VCO selection
+ bits in the user control register.
+
+Example:
+ qcom,clock-krait@f9016000 {
+ compatible = "qcom,clock-krait-8974";
+ reg = <0xf9016000 0x20>,
+ <0xf908a000 0x20>,
+ <0xf909a000 0x20>,
+ <0xf90aa000 0x20>,
+ <0xf90ba000 0x20>,
+ <0xfc4b80b0 0x08>;
+ reg-names = "hfpll_l2_clk", "hfpll0_clk",
+ "hfpll1_clk", "hfpll2_clk",
+ "hfpll3_clk", "efuse";
+ cpu0-supply = <&krait0_vreg>;
+ cpu1-supply = <&krait1_vreg>;
+ cpu2-supply = <&krait2_vreg>;
+ cpu3-supply = <&krait3_vreg>;
+ l2-dig-supply = <&pm8841_s2_corner_ao>;
+ hfpll-dig-supply = <&pm8841_s2_corner_ao>;
+ hfpll-analog-supply = <&pm8941_l12_ao>;
+
+ qcom,l2-fmax =
+ < 576000000 4 /* svs_soc */ >,
+ < 1036800000 5 /* normal */ >,
+ < 1728000000 7 /* super_turbo */>;
+
+ qcom,avs-tbl =
+ < 300000000 0xfa70054 >,
+ < 1574400000 0xfa70100 >;
+
+ qcom,speed0-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 815000 73 >,
+ .....
+ .....
+ < 1958400000 1100000 598 >;
+
+ qcom,speed0-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 73 >,
+ .....
+ .....
+ < 1958400000 1075000 598 >;
+
+ .....
+ .....
+
+ qcom,speed2-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ .....
+ .....
+ < 2265600000 950000 691 >;
+
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt b/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt
new file mode 100644
index 0000000..02514d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm-cpufreq.txt
@@ -0,0 +1,44 @@
+Qualcomm MSM CPUfreq device
+
+msm-cpufreq is a device that represents the list of useable CPU frequencies
+and the cache frequency and/or memory bandwidth required for each of them. It
+also captures the bus master/slave ports towards which the bus bandwidth
+requests need to be made to ensure the required memory bandwidth.
+
+Required properties:
+- compatible: Must be "qcom,msm-cpufreq"
+- qcom,cpufreq-table: A list of tuples where each tuple consists of a
+ usable CPU frequency (KHz), an optional cache
+ frequency (KHz) and an optional memory bandwidth
+ value (MBPS) listed in that order. The cache
+ frequencies shall not be listed if the device cannot
+ run the cache asynchronous to one or more CPUs. The
+ memory bandwidth values shall not be listed if the
+ optional cpu-mem-ports property is not supplied.
+
+Optional properties:
+- qcom,cpu-mem-ports: A list of tuples where each tuple consists of a bus
+ master (CPU) port number and a bus slave (memory)
+ port number.
+
+Example:
+ qcom,msm-cpufreq@0 {
+ regs = <0 4>
+ compatible = "qcom,msm-cpufreq";
+ qcom,cpu-mem-ports = <1 512>, <2 513>;
+ qcom,cpufreq-table =
+ < 300000 300000 600 >,
+ < 422400 422400 1200 >,
+ < 652800 499200 1600 >,
+ < 729600 576000 2456 >,
+ < 883200 576000 2456 >,
+ < 960000 960000 3680 >,
+ < 1036800 1036800 3680 >,
+ < 1190400 1036800 3680 >,
+ < 1267200 1267200 6400 >,
+ < 1497600 1497600 6400 >,
+ < 1574400 1574400 6400 >,
+ < 1728000 1651200 6400 >,
+ < 1958400 1728000 7448 >,
+ < 2265600 1728000 7448 >;
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index 82e7e2a..795af3b 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -25,6 +25,11 @@
- qcom,saw-turns-off-pll: Version of SAW2.1 or can turn off the HFPLL, when
doing power collapse and so the core need to switch to Global PLL before
PC.
+- qcom,synced-clocks: Indicates that all cpus running off a single clock source and to
+ instantiate the necessary clock source.
+- qcom,cpus-as-clocks: Indicates that the CPU clocks are implemented using clock APIs and should
+ switch to using generic clock APIs to enable/disable power collapse.
+ If set, the pm driver would ignore clock API errors and continue to call acpuclock API directly.
- qcom,pc-resets-timer: Indicates that the timer gets reset during power collapse.
Example:
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index d9a0d59..f969e2f 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -40,6 +40,8 @@
- qcom,saw2-spm-cmd-wfi: The WFI command sequence
- qcom,saw2-spm-cmd-ret: The Retention command sequence
- qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
+- qcom,saw2-spm-cmd-pc-no-rpm: The Power Collapse command sequence where APPS
+ proc won't inform the RPM.
- qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
- qcom,saw2-spm-cmd-gdhs: L2 GDHS command sequence
- qcom,L2-spm-is-apcs-master: Boolean indicates if the target uses L2 SAW to
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
index fdba7c2..f2ca95b 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -30,6 +30,7 @@
min y, max x and max y values.
- goodix,i2c-pull-up : To specify pull up is required.
- goodix,no-force-update : To specify force update is allowed.
+ - goodix,enable-power-off : Power off touchscreen during suspend.
- goodix,button-map : Button map of key codes. The number of key codes
depend on panel.
- goodix,cfg-data0 : Touch screen controller config data group 0. Ask vendor
@@ -50,6 +51,7 @@
to provide that.
- goodix,cfg-data5 : Touch screen controller config data group 5. Ask vendor
to provide that.
+ - goodix,fw-name : Touch screen controller firmware file name.
Example:
i2c@f9927000 {
goodix@5d {
@@ -84,5 +86,6 @@
20 21 22 24 26 28 29 2A FF FF
FF FF FF FF FF FF FF 22 22 22
22 22 22 FF 07 01];
+ goodix,fw_name = "gtp_fw.bin";
};
};
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index af6a0b5..749c594 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -10,13 +10,13 @@
node will further contain the type of LED supported and its
properties. At least one child node is required for each LED
module. Each must have the required properties below, in addition
-to the properties for the LED type, WLED, Flash or RGB.
+to the properties for the LED type, WLED, Flash, RGB and MPP.
Required properties for each child node, WLED, Flash and RGB:
- compatible : should be "qcom,leds-qpnp"
- qcom,id : must be one of values supported in enum qpnp_led
- label : type of led that will be used, ie "wled"
-- qcom,max-current : maximum current that the LED can sustain
+- qcom,max-current : maximum current that the LED can sustain in mA
- linux,name : name of the led that is used in led framework
WLED is primarily used as display backlight. Display subsystem uses
@@ -85,6 +85,7 @@
- qcom,vin-ctrl: select input source, supported values are 0 to 3
- qcom,use-blink: Use blink sysfs entry for switching into lpg mode. For optimal use, set default mode to pwm. All required lpg parameters must be supplied.
- qcom,min-brightness - Lowest possible brightness supported on this LED other than 0.
+- qcom,current-setting: default current value for wled used as button backlight in mA
Required properties for PWM mode only:
- qcom,pwm-channel: pwm channel the led will operate on
@@ -131,6 +132,22 @@
Example:
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "hr-trigger";
+ qcom,default-state = "off";
+ qcom,current-setting = <20>;
+ qcom,max-current = <40>;
+ qcom,id = <6>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x61>;
+ qcom,mode = "manual";
+ };
+ };
+
qcom,leds@a200 {
status = "okay";
qcom,led_mpp_3 {
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index 5425c92..584a76d 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -93,6 +93,10 @@
set, the charger ovp status is monitored in software.
- qcom,ext-ovp-present Indicates if an external OVP exists which reduces the
overall input resistance of the charge path.
+- qcom,power-stage-reduced Indicates if power stage workaround is enabled. This work
+ around reduces the power stage segments while charging
+ under high load during low battery voltages. It's for
+ improving IADC accuracy while board has a bad layout.
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 a8195df..7c661fe 100644
--- a/Documentation/devicetree/bindings/regulator/krait-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/krait-regulator.txt
@@ -55,6 +55,9 @@
to LDO mode. Acceptable values are from 1000uV to 100000uV
- qcom,cpu-num: Indicates what cpu this regulator controls
+Optional properties:
+- qcom,ldo-disable: Indicates whether to disable using LDO mode
+
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 5e686a4f..56bdc59 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -407,6 +407,17 @@
Required properties:
- compatible : "qcom,msm8974-audio-taiko"
- qcom,model : The user-visible name of this sound card.
+- reg : Offset and length of the register region(s) for MI2S/PCM MUX
+- reg-names : Register region name(s) referenced in reg above
+ Required register resource entries are:
+ "lpaif_pri_mode_muxsel": Physical address of MUX to select between
+ Primary PCM and Primary MI2S
+ "lpaif_sec_mode_muxsel": Physical address of MUX to select between
+ Secondary PCM and Secondary MI2S
+ "lpaif_tert_mode_muxsel": Physical address of MUX to select between
+ Primary PCM and Tertiary MI2S
+ "lpaif_quat_mode_muxsel": Physical address of MUX to select between
+ Secondary PCM and Quarternary MI2S
- qcom,audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source.
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index e7eae76..714311e 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -86,6 +86,11 @@
for detection of dp line transition during VDD minimization.
- qcom,hsusb-otg-dmsehv-int: If present, indicates mpm interrupt to be configured
for detection of dm line transition during VDD minimization.
+- qcom,ahb-async-bridge-bypass: If present, indicates that enable AHB2AHB By Pass
+ mode with device controller for better throughput. With this mode, USB Core
+ runs using PNOC clock and synchronous to it. Hence it is must to have proper
+ "qcom,msm_bus,vectors" to have high bus frequency. User shouldn't try to
+ enable this feature without proper bus voting.
Example HSUSB OTG controller device node :
usb@f9690000 {
@@ -176,12 +181,19 @@
- qcom,android-usb-cdrom : if this property is present then device creates
a new LUN as CD-ROM
- qcom,android-usb-internal-ums : if this property is present then device
- creates a new LUN as internal usb mass storage
+ creates a new LUN as internal usb mass storage.
+- qcom,streaming-func : add list of usb function name. If mention usb function
+ is being enable as part of USB composition, streaming mode is enable with
+ usb device controller to get better throughput. NOTE: Inverted CRC and
+ turnaround timeout is observed on enabling streaming. Hence it is required
+ to see these errors and number of erros on enabling this at USB level to make
+ final decision to enable this feature or not.
Example Android USB device node :
android_usb@fc42b0c8 {
compatible = "qcom,android-usb";
reg = <0xfc42b0c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,streaming-func = "rndis","mtp";
};
diff --git a/arch/arm/boot/dts/apq8026-v1-cdp.dts b/arch/arm/boot/dts/apq8026-v1-cdp.dts
index d7e283b..b9ec6f9 100644
--- a/arch/arm/boot/dts/apq8026-v1-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-cdp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v1.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/ {
model = "Qualcomm APQ 8026 CDP";
diff --git a/arch/arm/boot/dts/apq8026-v1-mtp.dts b/arch/arm/boot/dts/apq8026-v1-mtp.dts
index d24875c..c2fc72c 100644
--- a/arch/arm/boot/dts/apq8026-v1-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-mtp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v1.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
/ {
model = "Qualcomm APQ 8026 MTP";
diff --git a/arch/arm/boot/dts/apq8026-v1-xpm.dts b/arch/arm/boot/dts/apq8026-v1-xpm.dts
index f69511b..b435018 100644
--- a/arch/arm/boot/dts/apq8026-v1-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v1-xpm.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v1.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/ {
model = "Qualcomm APQ 8026 XPM";
diff --git a/arch/arm/boot/dts/apq8026-v2-cdp.dts b/arch/arm/boot/dts/apq8026-v2-1080p-cdp.dts
similarity index 91%
copy from arch/arm/boot/dts/apq8026-v2-cdp.dts
copy to arch/arm/boot/dts/apq8026-v2-1080p-cdp.dts
index cb68779..5294628 100644
--- a/arch/arm/boot/dts/apq8026-v2-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-1080p-cdp.dts
@@ -13,10 +13,10 @@
/dts-v1/;
/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-1080p-cdp.dtsi"
/ {
model = "Qualcomm APQ 8026v2 CDP";
compatible = "qcom,apq8026-cdp", "qcom,apq8026", "qcom,cdp";
- qcom,board-id = <1 0>;
+ qcom,board-id = <1 2>;
};
diff --git a/arch/arm/boot/dts/apq8026-v2-mtp.dts b/arch/arm/boot/dts/apq8026-v2-1080p-mtp.dts
similarity index 91%
copy from arch/arm/boot/dts/apq8026-v2-mtp.dts
copy to arch/arm/boot/dts/apq8026-v2-1080p-mtp.dts
index 40856c8..0ea98f5 100644
--- a/arch/arm/boot/dts/apq8026-v2-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-1080p-mtp.dts
@@ -13,10 +13,10 @@
/dts-v1/;
/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-1080p-mtp.dtsi"
/ {
model = "Qualcomm APQ 8026v2 MTP";
compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
- qcom,board-id = <8 0>;
+ qcom,board-id = <8 2>;
};
diff --git a/arch/arm/boot/dts/apq8026-v2-cdp.dts b/arch/arm/boot/dts/apq8026-v2-720p-cdp.dts
similarity index 95%
rename from arch/arm/boot/dts/apq8026-v2-cdp.dts
rename to arch/arm/boot/dts/apq8026-v2-720p-cdp.dts
index cb68779..cb2226a 100644
--- a/arch/arm/boot/dts/apq8026-v2-cdp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-720p-cdp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/ {
model = "Qualcomm APQ 8026v2 CDP";
diff --git a/arch/arm/boot/dts/apq8026-v2-mtp.dts b/arch/arm/boot/dts/apq8026-v2-720p-mtp.dts
similarity index 95%
rename from arch/arm/boot/dts/apq8026-v2-mtp.dts
rename to arch/arm/boot/dts/apq8026-v2-720p-mtp.dts
index 40856c8..439b3d7 100644
--- a/arch/arm/boot/dts/apq8026-v2-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v2-720p-mtp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
/ {
model = "Qualcomm APQ 8026v2 MTP";
diff --git a/arch/arm/boot/dts/apq8026-v2-xpm.dts b/arch/arm/boot/dts/apq8026-v2-xpm.dts
index 324516d..3133424 100644
--- a/arch/arm/boot/dts/apq8026-v2-xpm.dts
+++ b/arch/arm/boot/dts/apq8026-v2-xpm.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "apq8026-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/ {
model = "Qualcomm APQ 8026v2 XPM";
diff --git a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
index 23b65f3..92e6fc1 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
@@ -81,14 +81,47 @@
00 00 00 00
39 01 00 00 00 00 24
E0 79 05 0F
- 14 26 20 3F
- 2A 43 04 0C
- 11 15 17 15
- 15 10 13 05
- 0F 14 26 20
- 3F 2A 43 04
- 0C 11 15 17
- 15 15 10 13
+ 14 23 24 3F
+ 30 46 06 10
+ 13 16 17 16
+ 16 13 18 05
+ 0F 14 23 24
+ 3F 30 46 06
+ 10 13 16 17
+ 16 16 13 18
+ 39 01 00 00 00 00 80
+ C1 01 00 07
+ 10 17 1D 2A
+ 33 3A 43 4A
+ 52 5B 64 6D
+ 78 7F 88 90
+ 98 A0 A9 B2
+ B9 C1 C9 D1
+ D7 DF E6 ED
+ F4 FA FD 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 08 10 18
+ 20 28 30 38
+ 40 47 4F 58
+ 60 68 70 78
+ 80 88 90 98
+ A0 A9 B1 B9
+ C1 C9 D1 D8
+ E0 E8 F0 F9
+ FE 00 00 00
+ 00 00 00 00
+ 00 00 00 08
+ 10 18 1E 26
+ 2E 34 3A 41
+ 49 4F 58 5E
+ 67 6F 77 80
+ 88 8F 97 9F
+ A7 AF B8 BF
+ C7 D1 D8 E3
+ EA F6 FF 00
+ 00 00 00 00
+ 00 00 00 00
23 01 00 00 00 00 02
cc 02
39 01 00 00 00 00 05
diff --git a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
index 7e63014..8f94502 100755
--- a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
@@ -124,7 +124,7 @@
qcom,mdss-dsi-panel-timings = [97 23 17 00 4B 53 1C 27 27 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x04>;
qcom,mdss-dsi-t-clk-pre = <0x1b>;
- qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-min-level = <26>;
qcom,mdss-dsi-bl-max-level = <255>;
qcom,mdss-dsi-dma-trigger = <4>;
qcom,mdss-dsi-mdp-trigger = <0>;
diff --git a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
index 9477c56..393419b 100644
--- a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
@@ -256,7 +256,7 @@
qcom,mdss-dsi-panel-timings = [8B 1F 14 00 45 4A 19 23 23 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x04>;
qcom,mdss-dsi-t-clk-pre = <0x1b>;
- qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-min-level = <26>;
qcom,mdss-dsi-bl-max-level = <255>;
qcom,mdss-dsi-dma-trigger = <4>;
qcom,mdss-dsi-mdp-trigger = <0>;
diff --git a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
index bb8389f..b510e6b 100644
--- a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
@@ -30,9 +30,9 @@
qcom,mdss-dsi-h-back-porch = <24>;
qcom,mdss-dsi-h-pulse-width = <14>;
qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <15>;
- qcom,mdss-dsi-v-front-porch = <12>;
- qcom,mdss-dsi-v-pulse-width = <10>;
+ qcom,mdss-dsi-v-back-porch = <14>;
+ qcom,mdss-dsi-v-front-porch = <11>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
qcom,mdss-dsi-h-left-border = <0>;
qcom,mdss-dsi-h-right-border = <0>;
qcom,mdss-dsi-v-top-border = <0>;
diff --git a/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi b/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
new file mode 100644
index 0000000..bb66538
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-1080p-cdp.dtsi
@@ -0,0 +1,502 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "msm8226-camera-sensor-cdp.dtsi"
+
+&soc {
+ serial@f991f000 {
+ status = "ok";
+ };
+
+ i2c@f9927000 { /* BLSP1 QUP5 */
+ synaptics@20 {
+ compatible = "synaptics,rmi4";
+ reg = <0x20>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2008>;
+ vdd-supply = <&pm8226_l19>;
+ vcc_i2c-supply = <&pm8226_lvs1>;
+ synaptics,reset-gpio = <&msmgpio 16 0x00>;
+ synaptics,irq-gpio = <&msmgpio 17 0x2008>;
+ synaptics,display-coords = <0 0 1079 1919>;
+ synaptics,i2c-pull-up;
+ synaptics,power-down;
+ synaptics,disable-gpios;
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "synaptics_rmi4_i2c";
+ qcom,disp-maxx = <1079>;
+ qcom,disp-maxy = <1919>;
+ qcom,panel-maxx = <1079>;
+ qcom,panel-maxy = <2084>;
+ qcom,key-codes = <158 139 102 217>;
+ };
+
+ i2c@f9925000 { /* BLSP1 QUP3 */
+ nfc-nci@0e {
+ compatible = "qcom,nfc-nci";
+ reg = <0x0e>;
+ qcom,irq-gpio = <&msmgpio 21 0x00>;
+ qcom,dis-gpio = <&msmgpio 20 0x00>;
+ qcom,clk-src = "BBCLK2";
+ qcom,clk-en-gpio = <&msmgpio 0 0x00>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <21 0>;
+ qcom,clk-gpio = <&pm8226_gpios 3 0>;
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&msmgpio 108 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&msmgpio 107 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&msmgpio 106 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <115 0x8>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
+
+ sound {
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC5", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4";
+
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,headset-jack-type-NC;
+ };
+
+ sound-9302 {
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
+ "AMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Handset Mic";
+
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,headset-jack-type-NC;
+ };
+};
+
+&sdcc1 {
+ vdd-supply = <&pm8226_l17>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ vdd-io-supply = <&pm8226_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "disabled";
+};
+
+&sdhc_1 {
+ vdd-supply = <&pm8226_l17>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ vdd-io-supply = <&pm8226_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "ok";
+};
+
+&sdcc2 {
+ vdd-supply = <&pm8226_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ vdd-io-supply = <&pm8226_l21>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,xpc;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+ qcom,current-limit = <600>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdcc2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 220 0
+ 2 &msmgpio 38 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "disabled";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8226_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ vdd-io-supply = <&pm8226_l21>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 38 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "ok";
+};
+
+&sdcc3 {
+ qcom,sup-voltages = <1800 1800>;
+ status = "disabled";
+};
+
+&sdhc_3 {
+ qcom,sup-voltages = <1800 1800>;
+ status = "disabled";
+};
+
+&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
+ qcom,leds@a300 {
+ status = "okay";
+ qcom,led_mpp_4 {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "battery-full";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "pwm";
+ qcom,pwm-us = <1000>;
+ qcom,source-sel = <8>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,pwm-channel = <0>;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 00
+ 00 00 00 00 00
+ 50 00 00 00 00
+ 00 00 00 00 00
+ 00];
+ qcom,use-blink;
+ };
+ };
+
+ qcom,leds@a500 {
+ status = "okay";
+ qcom,led_mpp_6 {
+ label = "mpp";
+ linux,name = "red";
+ linux,default-trigger = "battery-charging";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "pwm";
+ qcom,pwm-us = <1000>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,source-sel = <10>;
+ qcom,pwm-channel = <5>;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 00
+ 00 00 00 00 00
+ 50 00 00 00 00
+ 00 00 00 00 00
+ 00];
+ qcom,use-blink;
+ };
+ };
+ };
+
+ qcom,pm8226@1 {
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck = <1>;
+ qcom,default-state = "on";
+ qcom,max-current = <20>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <11>;
+ qcom,ovp-val = <0>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
+ };
+
+ qcom,vibrator@c000 {
+ status = "okay";
+ qcom,vib-timeout-ms = <15000>;
+ qcom,vib-vtg-level-mV = <3100>;
+ };
+ };
+};
+
+&pm8226_gpios {
+ gpio@c000 { /* GPIO 1 */
+ /* XO_PMIC_CDC_MCLK enable for tapan codec */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
+ qcom,vin-sel = <3>; /* QPNP_PIN_VIN3 */
+ qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <3>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+};
+
+&pm8226_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* PA_THERM0 config */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <0>; /* AMUX 5 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ /* PA_THERM1 config */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+};
+
+&pm8226_chg {
+ qcom,charging-disabled;
+ qcom,use-default-batt-values;
+
+ qcom,bat-if@1200 {
+ status = "disabled";
+ };
+};
+
+&pm8226_vadc {
+ chan@14 {
+ label = "pa_therm0";
+ reg = <0x14>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@17 {
+ label = "pa_therm1";
+ reg = <0x17>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_jdi_1080_vid>;
+ qcom,platform-enable-gpio = <&msmgpio 109 0>;
+};
+
+&dsi_jdi_1080_vid {
+ qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
new file mode 100644
index 0000000..31624de
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-1080p-mtp.dtsi
@@ -0,0 +1,519 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/include/ "msm8226-camera-sensor-mtp.dtsi"
+
+&soc {
+ serial@f991f000 {
+ status = "ok";
+ };
+
+ i2c@f9927000 { /* BLSP1 QUP5 */
+ synaptics@20 {
+ compatible = "synaptics,rmi4";
+ reg = <0x20>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2008>;
+ vdd-supply = <&pm8226_l19>;
+ vcc_i2c-supply = <&pm8226_lvs1>;
+ synaptics,reset-gpio = <&msmgpio 16 0x00>;
+ synaptics,irq-gpio = <&msmgpio 17 0x2008>;
+ synaptics,display-coords = <0 0 1079 1919>;
+ synaptics,i2c-pull-up;
+ synaptics,power-down;
+ synaptics,disable-gpios;
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "synaptics_rmi4_i2c";
+ qcom,disp-maxx = <1079>;
+ qcom,disp-maxy = <1919>;
+ qcom,panel-maxx = <1079>;
+ qcom,panel-maxy = <2084>;
+ qcom,key-codes = <158 139 102 217>;
+ };
+
+ i2c@f9925000 { /* BLSP1 QUP3 */
+ nfc-nci@0e {
+ compatible = "qcom,nfc-nci";
+ reg = <0x0e>;
+ qcom,irq-gpio = <&msmgpio 21 0x00>;
+ qcom,dis-gpio = <&msmgpio 20 0x00>;
+ qcom,clk-src = "BBCLK2";
+ qcom,clk-en-gpio = <&msmgpio 0 0x00>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <21 0>;
+ qcom,clk-gpio = <&pm8226_gpios 3 0>;
+ };
+ };
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&msmgpio 108 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&msmgpio 107 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&msmgpio 106 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <115 0x8>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
+
+ sound {
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
+ "AMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC5", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic";
+
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ };
+
+ sound-9302 {
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Handset Mic";
+
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ };
+};
+
+&usb_otg {
+ #address-cells = <0>;
+ interrupt-parent = <&usb_otg>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 134 0
+ 1 &intc 0 140 0
+ 2 &spmi_bus 0x0 0x0 0x9 0x0>;
+ interrupt-names = "core_irq", "async_irq", "pmic_id_irq";
+
+ qcom,hsusb-otg-mode = <3>;
+ vbus_otg-supply = <&pm8226_chg_otg>;
+};
+
+&sdcc1 {
+ vdd-supply = <&pm8226_l17>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ vdd-io-supply = <&pm8226_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "disabled";
+};
+
+&sdhc_1 {
+ vdd-supply = <&pm8226_l17>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ vdd-io-supply = <&pm8226_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "ok";
+};
+
+&sdcc2 {
+ vdd-supply = <&pm8226_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ vdd-io-supply = <&pm8226_l21>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,xpc;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+ qcom,current-limit = <600>; #address-cells = <0>; interrupt-parent = <&sdcc2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 220 0
+ 2 &msmgpio 38 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "disabled";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8226_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ vdd-io-supply = <&pm8226_l21>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 38 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "ok";
+};
+
+&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
+ qcom,leds@a300 {
+ status = "okay";
+ qcom,led_mpp_4 {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "battery-full";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "pwm";
+ qcom,pwm-us = <1000>;
+ qcom,source-sel = <8>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,pwm-channel = <0>;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 00
+ 00 00 00 00 00
+ 50 00 00 00 00
+ 00 00 00 00 00
+ 00];
+ qcom,use-blink;
+ };
+ };
+
+ qcom,leds@a500 {
+ status = "okay";
+ qcom,led_mpp_6 {
+ label = "mpp";
+ linux,name = "red";
+ linux,default-trigger = "battery-charging";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "pwm";
+ qcom,pwm-us = <1000>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,source-sel = <10>;
+ qcom,pwm-channel = <5>;
+ qcom,start-idx = <1>;
+ qcom,ramp-step-ms = <120>;
+ qcom,duty-pcts = [00 00 00 00 00
+ 00 00 00 00 00
+ 50 00 00 00 00
+ 00 00 00 00 00
+ 00];
+ qcom,use-blink;
+ };
+ };
+ };
+
+ qcom,pm8226@1 {
+ qcom,leds@d300 {
+ status = "okay";
+ };
+
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck = <1>;
+ qcom,default-state = "on";
+ qcom,max-current = <20>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <11>;
+ qcom,ovp-val = <0>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
+ };
+
+ qcom,vibrator@c000 {
+ status = "okay";
+ qcom,vib-timeout-ms = <15000>;
+ qcom,vib-vtg-level-mV = <3100>;
+ };
+ };
+};
+
+&pm8226_gpios {
+ gpio@c000 { /* GPIO 1 */
+ /* XO_PMIC_CDC_MCLK enable for tapan codec */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
+ qcom,vin-sel = <3>; /* QPNP_PIN_VIN3 */
+ qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <3>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+};
+
+&pm8226_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* PA_THERM0 config */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <0>; /* AMUX 5 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ /* PA_THERM1 config */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+};
+
+&pm8226_vadc {
+ chan@14 {
+ label = "pa_therm0";
+ reg = <0x14>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@17 {
+ label = "pa_therm1";
+ reg = <0x17>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
+
+/ {
+ mtp_batterydata: qcom,battery-data {
+ qcom,rpull-up-kohm = <100>;
+ qcom,vref-batt-therm = <1800000>;
+
+ /include/ "batterydata-palladium.dtsi"
+ /include/ "batterydata-mtp-3000mah.dtsi"
+ };
+};
+
+&pm8226_bms {
+ status = "ok";
+ qcom,battery-data = <&mtp_batterydata>;
+ qcom,enable-fcc-learning;
+ qcom,min-fcc-learning-soc = <20>;
+ qcom,min-fcc-ocv-pc = <30>;
+ qcom,min-fcc-learning-samples = <5>;
+ qcom,fcc-resolution = <10>;
+};
+
+&pm8226_chg {
+ qcom,charging-disabled;
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&slim_msm {
+ tapan_codec {
+ qcom,cdc-micbias1-ext-cap;
+ };
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_jdi_1080_vid>;
+ qcom,platform-enable-gpio = <&msmgpio 109 0>;
+};
+
+&dsi_jdi_1080_vid {
+ qcom,cont-splash-enabled;
+};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-720p-cdp.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8226-cdp.dtsi
rename to arch/arm/boot/dts/msm8226-720p-cdp.dtsi
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-720p-mtp.dtsi
similarity index 100%
rename from arch/arm/boot/dts/msm8226-mtp.dtsi
rename to arch/arm/boot/dts/msm8226-720p-mtp.dtsi
diff --git a/arch/arm/boot/dts/msm8226-mdss-panels.dtsi b/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
index eeec175..0731a9a 100644
--- a/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss-panels.dtsi
@@ -16,3 +16,4 @@
/include/ "dsi-panel-nt35596-1080p-video.dtsi"
/include/ "dsi-panel-nt35590-720p-cmd.dtsi"
/include/ "dsi-panel-ssd2080m-720p-video.dtsi"
+/include/ "dsi-panel-jdi-1080p-video.dtsi"
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 3e2507ff..e2891d1 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -36,7 +36,7 @@
qcom,mdss-wb-off = <0x00011100 0x00013100>;
qcom,mdss-intf-off = <0x00000000 0x00021300>;
qcom,mdss-rot-block-size = <64>;
- qcom,mdss-smp-mb-per-pipe = <2>;
+ qcom,mdss-smp-mb-per-pipe = <4>;
vdd-cx-supply = <&pm8226_s1_corner>;
qcom,vbif-settings = <0x004 0x00000001>,
diff --git a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
index 66f5095..76bd262 100755
--- a/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd-skuf.dtsi
@@ -124,6 +124,7 @@
20 21 22 24 26 28 29 2A FF FF
FF FF FF FF FF FF FF FF FF FF
FF FF FF FF 3E 01];
+ goodix,fw_name = "gtp_fw.bin";
};
};
};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 23a2158..9764982 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -336,7 +336,7 @@
pm8226_l16: regulator-l16 {
regulator-name = "8226_l16";
regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3300000>;
+ regulator-max-microvolt = <3350000>;
qcom,init-voltage = <3300000>;
status = "okay";
};
@@ -423,7 +423,7 @@
pm8226_l24: regulator-l24 {
regulator-name = "8226_l24";
regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
qcom,init-voltage = <1300000>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/msm8226-v1-cdp.dts b/arch/arm/boot/dts/msm8226-v1-cdp.dts
index e426a97..4b8cafd 100644
--- a/arch/arm/boot/dts/msm8226-v1-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-cdp.dts
@@ -12,7 +12,7 @@
/dts-v1/;
/include/ "msm8226-v1.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/ {
model = "Qualcomm MSM 8226 CDP";
diff --git a/arch/arm/boot/dts/msm8226-v1-mtp.dts b/arch/arm/boot/dts/msm8226-v1-mtp.dts
index 08d7cec..a1e78b7 100644
--- a/arch/arm/boot/dts/msm8226-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-mtp.dts
@@ -12,7 +12,7 @@
/dts-v1/;
/include/ "msm8226-v1.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
/ {
model = "Qualcomm MSM 8226 MTP";
diff --git a/arch/arm/boot/dts/msm8226-v2-cdp.dts b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
similarity index 92%
copy from arch/arm/boot/dts/msm8226-v2-cdp.dts
copy to arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
index 3302d26..77cc08c 100644
--- a/arch/arm/boot/dts/msm8226-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-1080p-cdp.dts
@@ -12,13 +12,13 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-1080p-cdp.dtsi"
/include/ "msm8226-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm MSM 8226v2 CDP";
compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
- qcom,board-id = <1 0>;
+ qcom,board-id = <1 2>;
};
&hsic_host {
diff --git a/arch/arm/boot/dts/msm8226-v2-mtp.dts b/arch/arm/boot/dts/msm8226-v2-1080p-mtp.dts
similarity index 92%
copy from arch/arm/boot/dts/msm8226-v2-mtp.dts
copy to arch/arm/boot/dts/msm8226-v2-1080p-mtp.dts
index 6034107..b12a77d 100644
--- a/arch/arm/boot/dts/msm8226-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-1080p-mtp.dts
@@ -12,11 +12,11 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-1080p-mtp.dtsi"
/include/ "msm8226-camera-sensor-mtp.dtsi"
/ {
model = "Qualcomm MSM 8226v2 MTP";
compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
- qcom,board-id = <8 0>;
+ qcom,board-id = <8 2>;
};
diff --git a/arch/arm/boot/dts/msm8226-v2-cdp.dts b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
similarity index 95%
rename from arch/arm/boot/dts/msm8226-v2-cdp.dts
rename to arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
index 3302d26..966ae2b 100644
--- a/arch/arm/boot/dts/msm8226-v2-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-720p-cdp.dts
@@ -12,7 +12,7 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/include/ "msm8226-camera-sensor-cdp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8226-v2-mtp.dts b/arch/arm/boot/dts/msm8226-v2-720p-mtp.dts
similarity index 95%
rename from arch/arm/boot/dts/msm8226-v2-mtp.dts
rename to arch/arm/boot/dts/msm8226-v2-720p-mtp.dts
index 6034107..0768b75 100644
--- a/arch/arm/boot/dts/msm8226-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v2-720p-mtp.dts
@@ -12,7 +12,7 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
/include/ "msm8226-camera-sensor-mtp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 51a0795..3ef0d6d 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -39,7 +39,7 @@
qsecom_mem: qsecom_region {
linux,contiguous-region;
- reg = <0 0x780000>;
+ reg = <0 0xd00000>;
label = "qsecom_mem";
};
};
@@ -283,6 +283,7 @@
qcom,hsusb-otg-otg-control = <2>;
qcom,hsusb-otg-disable-reset;
qcom,dp-manual-pullup;
+ qcom,ahb-async-bridge-bypass;
qcom,msm-bus,name = "usb";
qcom,msm-bus,num-cases = <3>;
@@ -297,6 +298,7 @@
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,streaming-func = "rndis";
};
hsic_host: hsic@f9a00000 {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index 9920f77..d63c6e5 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -20,7 +20,7 @@
compatible = "atmel,mxt-ts";
reg = <0x4a>;
interrupt-parent = <&msmgpio>;
- interrupts = <1 0x2>;
+ interrupts = <1 0x2002>;
vdd_ana-supply = <&pm8110_l19>;
vcc_i2c-supply = <&pm8110_l14>;
atmel,reset-gpio = <&msmgpio 0 0x00>;
@@ -76,6 +76,21 @@
];
};
};
+
+ synaptics@20 {
+ compatible = "synaptics,rmi4";
+ reg = <0x20>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2002>;
+ vdd-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ synaptics,reset-gpio = <&msmgpio 0 0x00>;
+ synaptics,irq-gpio = <&msmgpio 1 0x2008>;
+ synaptics,button-map = <139 102 158>;
+ synaptics,i2c-pull-up;
+ synaptics,power-down;
+ synaptics,disable-gpios;
+ };
};
gen-vkeys {
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index 0244b89..6ce0109 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -20,7 +20,7 @@
compatible = "atmel,mxt-ts";
reg = <0x4a>;
interrupt-parent = <&msmgpio>;
- interrupts = <1 0x2>;
+ interrupts = <1 0x2002>;
vdd_ana-supply = <&pm8110_l19>;
vcc_i2c-supply = <&pm8110_l14>;
atmel,reset-gpio = <&msmgpio 0 0x00>;
@@ -76,6 +76,21 @@
];
};
};
+
+ synaptics@20 {
+ compatible = "synaptics,rmi4";
+ reg = <0x20>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2002>;
+ vdd-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ synaptics,reset-gpio = <&msmgpio 0 0x00>;
+ synaptics,irq-gpio = <&msmgpio 1 0x2008>;
+ synaptics,button-map = <139 102 158>;
+ synaptics,i2c-pull-up;
+ synaptics,power-down;
+ synaptics,disable-gpios;
+ };
};
i2c@f9925000 {
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
index 08e9be5..a22958a 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dtsi
@@ -67,6 +67,7 @@
goodix,display-coords = <0 0 540 960>;
goodix,button-map= <139 102 158>;
goodix,product-id = "915";
+ goodix,enable-power-off;
goodix,cfg-data0 = [
46 1C 02 C0 03 0A 05 11 01 08
14 3B 46 32 03 05 00 00 00 00
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index d578ef6..85bd746 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -210,8 +210,9 @@
status = "okay";
qcom,led_mpp_2 {
label = "mpp";
- linux,name = "wled-homerow";
- linux-default-trigger = "hr-trigger";
+ linux,name = "button-backlight";
+ linux,default-trigger = "hr-trigger";
+ qcom,current-setting = <20>;
qcom,default-state = "off";
qcom,max-current = <40>;
qcom,id = <6>;
@@ -287,7 +288,7 @@
qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,clk-rates = <400000 25000000 50000000>;
#address-cells = <0>;
interrupt-parent = <&sdhc_2>;
@@ -308,6 +309,7 @@
qcom,chgr@1000 {
status = "ok";
+ qcom,tchg-mins = <250>;
};
qcom,buck@1100 {
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index f97d991..7eb6a22 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -215,7 +215,7 @@
status = "okay";
pm8110_l5: regulator-l5 {
regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
qcom,init-voltage = <1300000>;
status = "okay";
};
@@ -325,7 +325,7 @@
status = "okay";
pm8110_l16: regulator-l16 {
regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
+ regulator-max-microvolt = <3350000>;
qcom,init-voltage = <3000000>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index 6296692..62aa0f4 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -56,10 +56,10 @@
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x8>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
+ qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f90b9000 {
@@ -99,6 +99,9 @@
qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+ qcom,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
+ 11 03 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
+ 50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
qcom,L2-spm-is-apcs-master;
};
@@ -125,28 +128,29 @@
qcom,latency-us = <500>;
qcom,ss-power = <410>;
qcom,energy-overhead = <603400>;
- qcom,time-overhead = <1200>;
+ qcom,time-overhead = <1410>;
};
qcom,lpm-level@2 {
reg = <0x2>;
qcom,mode = "pc";
- qcom,l2 = "l2_cache_retention";
- qcom,latency-us = <520>;
- qcom,ss-power = <460>;
- qcom,energy-overhead = <704900>;
- qcom,time-overhead = <1300>;
+ qcom,l2 = "l2_cache_pc_no_rpm";
+ qcom,latency-us = <1000>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
};
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
qcom,l2 = "l2_cache_pc";
- qcom,latency-us = <11700>;
+ qcom,latency-us = <12700>;
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
};
+
};
qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts b/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
index 4a08f3f..de48f1f 100644
--- a/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuab-dvt2.dts
@@ -33,3 +33,10 @@
&dsi_hx8389b_qhd_vid {
qcom,cont-splash-enabled;
};
+&soc {
+ i2c@f9925000 {
+ fsl@1c {
+ fsl,sensors-position = <7>;
+ };
+ };
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index 6c7f2f6..e401f7a 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -56,10 +56,10 @@
qcom,saw2-spm-dly= <0x3c102800>;
qcom,saw2-spm-ctl = <0x8>;
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
- qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
- 0b 94 5b 80 10 06 26 30 0f];
+ qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
+ 0b 94 5b 80 10 26 30 0f];
};
qcom,spm@f90b9000 {
@@ -101,6 +101,9 @@
qcom,saw2-spm-cmd-pc = [00 32 b0 10 e0 d0 6b c0 42 f0
11 07 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
+ qcom,saw2-spm-cmd-pc-no-rpm = [00 32 b0 10 e0 d0 6b c0 42 f0
+ 11 03 01 b0 50 4e 02 02 c0 d0 12 e0 6b 02 32
+ 50 f0 0f]; /*APCS_PMIC_OFF_L2RAM_OFF*/
qcom,L2-spm-is-apcs-master;
};
@@ -134,17 +137,27 @@
reg = <0x2>;
qcom,mode = "pc";
qcom,l2 = "l2_cache_gdhs";
- qcom,latency-us = <10700>;
- qcom,ss-power = <325>;
- qcom,energy-overhead = <441250>;
- qcom,time-overhead = <1020>;
+ qcom,latency-us = <11700>;
+ qcom,ss-power = <372>;
+ qcom,energy-overhead = <738750>;
+ qcom,time-overhead = <1410>;
};
qcom,lpm-level@3 {
reg = <0x3>;
qcom,mode = "pc";
+ qcom,l2 = "l2_cache_pc_no_rpm";
+ qcom,latency-us = <1000>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <1027150>;
+ qcom,time-overhead = <2400>;
+ };
+
+ qcom,lpm-level@4 {
+ reg = <0x4>;
+ qcom,mode = "pc";
qcom,l2 = "l2_cache_pc";
- qcom,latency-us = <11700>;
+ qcom,latency-us = <12700>;
qcom,ss-power = <315>;
qcom,energy-overhead = <1027150>;
qcom,time-overhead = <2400>;
diff --git a/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts b/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
index 4735554..95a5da5 100644
--- a/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuab-dvt2.dts
@@ -56,3 +56,10 @@
&dsi_hx8389b_qhd_vid {
qcom,cont-splash-enabled;
};
+&soc {
+ i2c@f9925000 {
+ fsl@1c {
+ fsl,sensors-position = <7>;
+ };
+ };
+};
\ No newline at end of file
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 9406b75..42b7887 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -239,6 +239,7 @@
qcom,hsusb-otg-otg-control = <2>;
qcom,hsusb-otg-disable-reset;
qcom,dp-manual-pullup;
+ qcom,ahb-async-bridge-bypass;
qcom,msm-bus,name = "usb2";
qcom,msm-bus,num-cases = <2>;
@@ -253,6 +254,7 @@
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,streaming-func = "rndis";
};
sdcc1: qcom,sdcc@f9824000 {
@@ -422,7 +424,6 @@
compatible = "qcom,rpm-smd";
rpm-channel-name = "rpm_requests";
rpm-channel-type = <15>; /* SMD_APPS_RPM */
- rpm-standalone;
};
qcom,bcl {
diff --git a/arch/arm/boot/dts/msm8926-cdp.dts b/arch/arm/boot/dts/msm8926-1080p-cdp.dts
similarity index 93%
copy from arch/arm/boot/dts/msm8926-cdp.dts
copy to arch/arm/boot/dts/msm8926-1080p-cdp.dts
index d6e70e6..33e484a 100644
--- a/arch/arm/boot/dts/msm8926-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-1080p-cdp.dts
@@ -13,13 +13,13 @@
/dts-v1/;
/include/ "msm8926.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-1080p-cdp.dtsi"
/include/ "msm8226-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm MSM 8926 CDP";
compatible = "qcom,msm8926-cdp", "qcom,msm8926", "qcom,cdp";
- qcom,board-id = <1 0>;
+ qcom,board-id = <1 2>;
};
&pm8226_chg {
diff --git a/arch/arm/boot/dts/msm8926-mtp.dts b/arch/arm/boot/dts/msm8926-1080p-mtp.dts
similarity index 92%
copy from arch/arm/boot/dts/msm8926-mtp.dts
copy to arch/arm/boot/dts/msm8926-1080p-mtp.dts
index 624781b..c1217a2 100644
--- a/arch/arm/boot/dts/msm8926-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-1080p-mtp.dts
@@ -13,11 +13,11 @@
/dts-v1/;
/include/ "msm8926.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-1080p-mtp.dtsi"
/include/ "msm8226-camera-sensor-mtp.dtsi"
/ {
model = "Qualcomm MSM 8926 MTP";
compatible = "qcom,msm8926-mtp", "qcom,msm8926", "qcom,mtp";
- qcom,board-id = <8 0>;
+ qcom,board-id = <8 2>;
};
diff --git a/arch/arm/boot/dts/msm8926-cdp.dts b/arch/arm/boot/dts/msm8926-720p-cdp.dts
similarity index 96%
rename from arch/arm/boot/dts/msm8926-cdp.dts
rename to arch/arm/boot/dts/msm8926-720p-cdp.dts
index d6e70e6..80bb5e6 100644
--- a/arch/arm/boot/dts/msm8926-cdp.dts
+++ b/arch/arm/boot/dts/msm8926-720p-cdp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "msm8926.dtsi"
-/include/ "msm8226-cdp.dtsi"
+/include/ "msm8226-720p-cdp.dtsi"
/include/ "msm8226-camera-sensor-cdp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8926-mtp.dts b/arch/arm/boot/dts/msm8926-720p-mtp.dts
similarity index 95%
rename from arch/arm/boot/dts/msm8926-mtp.dts
rename to arch/arm/boot/dts/msm8926-720p-mtp.dts
index 624781b..32301fd 100644
--- a/arch/arm/boot/dts/msm8926-mtp.dts
+++ b/arch/arm/boot/dts/msm8926-720p-mtp.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "msm8926.dtsi"
-/include/ "msm8226-mtp.dtsi"
+/include/ "msm8226-720p-mtp.dtsi"
/include/ "msm8226-camera-sensor-mtp.dtsi"
/ {
diff --git a/arch/arm/boot/dts/msm8926-qrd-skug.dts b/arch/arm/boot/dts/msm8926-qrd-skug.dts
index 6d907ef..15a2d58 100644
--- a/arch/arm/boot/dts/msm8926-qrd-skug.dts
+++ b/arch/arm/boot/dts/msm8926-qrd-skug.dts
@@ -61,8 +61,8 @@
focaltech,fw-name = "ft_8926_qrd_fw.bin";
focaltech,fw-delay-aa-ms = <30>;
focaltech,fw-delay-55-ms = <30>;
- focaltech,fw-upgrade-id1 = <0x79>;
- focaltech,fw-upgrade-id2 = <0x08>;
+ focaltech,fw-upgrade-id1 = <0x11>;
+ focaltech,fw-upgrade-id2 = <0x11>;
focaltech,fw-delay-readid-ms = <10>;
focaltech,fw-delay-era-flsh-ms = <2000>;
focaltech,fw-auto-cal;
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 344c26f..9b9202e 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -289,7 +289,7 @@
status = "okay";
pm8941_l11: regulator-l11 {
regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
qcom,init-voltage = <1300000>;
status = "okay";
};
@@ -376,7 +376,7 @@
status = "okay";
pm8941_l19: regulator-l19 {
regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <3300000>;
+ regulator-max-microvolt = <3350000>;
qcom,init-voltage = <2900000>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index 0115d89..179edac 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -208,10 +208,26 @@
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 34>, /* APCC_qgicL2ErrorIrptReq */
+ <0xff 35>, /* WDT_barkInt */
+ <0xff 40>, /* qtimer_phy_irq */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
<0xff 59>, /* mss_to_apps_irq(2) */
<0xff 60>, /* mss_to_apps_irq(3) */
+ <0xff 74>, /* osmmu_CIrpt[1] */
+ <0xff 75>, /* osmmu_CIrpt[0] */
+ <0xff 77>, /* osmmu_CIrpt[0] */
+ <0xff 78>, /* osmmu_CIrpt[0] */
+ <0xff 79>, /* osmmu_CIrpt[0] */
+ <0xff 94>, /* osmmu_CIrpt[0] */
+ <0xff 99>, /* msm_iommu_pmon_nonsecure_irq */
+ <0xff 102>, /* osmmu_CIrpt[1] */
+ <0xff 109>, /* ocmem_dm_nonsec_irq */
+ <0xff 126>, /* bam_irq[0] */
+ <0xff 155>, /* sdcc_irq[0] */
+ <0xff 163>, /* usb30_ee1_irq */
+ <0xff 170>, /* sdcc_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
@@ -230,6 +246,7 @@
<0xff 195>, /* lpass_irq_out_apcs(7) */
<0xff 196>, /* lpass_irq_out_apcs(8) */
<0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 198>, /* coresight-tmc-etr interrupt */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
@@ -238,7 +255,10 @@
<0xff 205>, /* rpm_ipc(25) */
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
- <0xff 240>; /* summary_irq_kpss */
+ <0xff 240>, /* summary_irq_kpss */
+ <0xff 268>, /* bam_irq[1] */
+ <0xff 270>, /* bam_irq[0] */
+ <0xff 271>; /* bam_irq[0] */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 102>,
@@ -290,6 +310,7 @@
reg = <0xfe805664 0x40>;
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
+ qcom,cpus-as-clocks;
};
qcom,cpu-sleep-status@f9088008 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 8836975..eba053f 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -215,6 +215,9 @@
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 34>, /* APCC_qgicL2ErrorIrptReq */
+ <0xff 35>, /* WDT_barkInt */
+ <0xff 40>, /* qtimer_phy_irq */
<0xff 56>, /* modem_watchdog */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
@@ -222,8 +225,21 @@
<0xff 60>, /* mss_to_apps_irq(3) */
<0xff 61>, /* mss_a2_bam_irq */
<0xff 70>, /* iommu_pmon_nonsecure_irq */
+ <0xff 74>, /* osmmu_CIrpt[1] */
+ <0xff 75>, /* osmmu_CIrpt[0] */
+ <0xff 77>, /* osmmu_CIrpt[0] */
+ <0xff 78>, /* osmmu_CIrpt[0] */
+ <0xff 79>, /* osmmu_CIrpt[0] */
+ <0xff 94>, /* osmmu_CIrpt[0] */
<0xff 97>, /* iommu_nonsecure_irq */
+ <0xff 99>, /* msm_iommu_pmon_nonsecure_irq */
+ <0xff 102>, /* osmmu_CIrpt[1] */
<0xff 105>, /* iommu_pmon_nonsecure_irq */
+ <0xff 109>, /* ocmem_dm_nonsec_irq */
+ <0xff 126>, /* bam_irq[0] */
+ <0xff 155>, /* sdcc_irq[0] */
+ <0xff 163>, /* usb30_ee1_irq */
+ <0xff 170>, /* sdcc_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
@@ -231,7 +247,6 @@
<0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
<0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
<0xff 179>, /* o_wcss_apss_asic_intr */
-
<0xff 181>, /* wcnss watchdog */
<0xff 188>, /* lpass_irq_out_apcs(0) */
<0xff 189>, /* lpass_irq_out_apcs(1) */
@@ -243,6 +258,7 @@
<0xff 195>, /* lpass_irq_out_apcs(7) */
<0xff 196>, /* lpass_irq_out_apcs(8) */
<0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 198>, /* coresight-tmc-etr interrupt */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
@@ -252,7 +268,10 @@
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
<0xff 211>, /* usb_dwc3_otg */
- <0xff 240>; /* summary_irq_kpss */
+ <0xff 240>, /* summary_irq_kpss */
+ <0xff 268>, /* bam_irq[1] */
+ <0xff 270>, /* bam_irq[0] */
+ <0xff 271>; /* bam_irq[0] */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 102>,
@@ -304,6 +323,7 @@
reg = <0xfe805664 0x40>;
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
+ qcom,cpus-as-clocks;
qcom,pm-snoc-client {
compatible = "qcom,pm-snoc-client";
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 39fb108..de49851 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -741,6 +741,14 @@
sound {
compatible = "qcom,msm8974-audio-taiko";
qcom,model = "msm8974-taiko-snd-card";
+ reg = <0xfe02b000 0x4>,
+ <0xfe02c000 0x4>,
+ <0xfe02d000 0x4>,
+ <0xfe02e000 0x4>;
+ reg-names = "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel";
qcom,audio-routing =
"RX_BIAS", "MCLK",
@@ -865,25 +873,648 @@
qcom,master-id = <86>;
};
- qcom,acpuclk@f9000000 {
- compatible = "qcom,acpuclk-8974";
- krait0-supply = <&krait0_vreg>;
- krait1-supply = <&krait1_vreg>;
- krait2-supply = <&krait2_vreg>;
- krait3-supply = <&krait3_vreg>;
- krait0_mem-supply = <&pm8841_s1_ao>;
- krait1_mem-supply = <&pm8841_s1_ao>;
- krait2_mem-supply = <&pm8841_s1_ao>;
- krait3_mem-supply = <&pm8841_s1_ao>;
- krait0_dig-supply = <&pm8841_s2_corner_ao>;
- krait1_dig-supply = <&pm8841_s2_corner_ao>;
- krait2_dig-supply = <&pm8841_s2_corner_ao>;
- krait3_dig-supply = <&pm8841_s2_corner_ao>;
- krait0_hfpll-supply = <&pm8941_l12_ao>;
- krait1_hfpll-supply = <&pm8941_l12_ao>;
- krait2_hfpll-supply = <&pm8941_l12_ao>;
- krait3_hfpll-supply = <&pm8941_l12_ao>;
- l2_hfpll-supply = <&pm8941_l12_ao>;
+ qcom,clock-krait@f9016000 {
+ compatible = "qcom,clock-krait-8974";
+ reg = <0xf9016000 0x20>,
+ <0xf908a000 0x20>,
+ <0xf909a000 0x20>,
+ <0xf90aa000 0x20>,
+ <0xf90ba000 0x20>,
+ <0xfc4b80b0 0x08>;
+ reg-names = "hfpll_l2_clk", "hfpll0_clk",
+ "hfpll1_clk", "hfpll2_clk",
+ "hfpll3_clk", "efuse";
+ cpu0-supply = <&krait0_vreg>;
+ cpu1-supply = <&krait1_vreg>;
+ cpu2-supply = <&krait2_vreg>;
+ cpu3-supply = <&krait3_vreg>;
+ l2-dig-supply = <&pm8841_s2_corner_ao>;
+ hfpll-dig-supply = <&pm8841_s2_corner_ao>;
+ hfpll-analog-supply = <&pm8941_l12_ao>;
+ qcom,hfpll-config-val = <0x04D0405D>;
+ qcom,hfpll-user-vco-mask = <0x00100000>;
+
+ qcom,l2-fmax =
+ < 0 0 >,
+ < 576000000 4 /* SVS_SOC */ >,
+ < 1036800000 5 /* NORMAL */ >,
+ < 1728000000 7 /* SUPER_TURBO */ >;
+
+ qcom,speed0-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 815000 73 >,
+ < 345600000 825000 85 >,
+ < 422400000 835000 104 >,
+ < 499200000 845000 124 >,
+ < 576000000 855000 144 >,
+ < 652800000 865000 165 >,
+ < 729600000 875000 186 >,
+ < 806400000 890000 208 >,
+ < 883200000 900000 229 >,
+ < 960000000 915000 252 >,
+ < 1036800000 925000 275 >,
+ < 1113600000 940000 298 >,
+ < 1190400000 950000 321 >,
+ < 1267200000 965000 346 >,
+ < 1344000000 980000 371 >,
+ < 1420800000 995000 397 >,
+ < 1497600000 1010000 423 >,
+ < 1574400000 1025000 450 >,
+ < 1651200000 1040000 477 >,
+ < 1728000000 1055000 506 >,
+ < 1804800000 1070000 536 >,
+ < 1881600000 1085000 567 >,
+ < 1958400000 1100000 598 >;
+
+ qcom,speed0-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 73 >,
+ < 345600000 810000 85 >,
+ < 422400000 820000 104 >,
+ < 499200000 830000 124 >,
+ < 576000000 840000 144 >,
+ < 652800000 850000 165 >,
+ < 729600000 860000 186 >,
+ < 806400000 875000 208 >,
+ < 883200000 885000 229 >,
+ < 960000000 895000 252 >,
+ < 1036800000 910000 275 >,
+ < 1113600000 920000 298 >,
+ < 1190400000 930000 321 >,
+ < 1267200000 945000 346 >,
+ < 1344000000 960000 371 >,
+ < 1420800000 975000 397 >,
+ < 1497600000 990000 423 >,
+ < 1574400000 1005000 450 >,
+ < 1651200000 1020000 477 >,
+ < 1728000000 1030000 506 >,
+ < 1804800000 1045000 536 >,
+ < 1881600000 1060000 567 >,
+ < 1958400000 1075000 598 >;
+
+ qcom,speed0-pvs2-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 785000 73 >,
+ < 345600000 795000 85 >,
+ < 422400000 805000 104 >,
+ < 499200000 815000 124 >,
+ < 576000000 825000 144 >,
+ < 652800000 835000 165 >,
+ < 729600000 845000 186 >,
+ < 806400000 855000 208 >,
+ < 883200000 865000 229 >,
+ < 960000000 875000 252 >,
+ < 1036800000 890000 275 >,
+ < 1113600000 900000 298 >,
+ < 1190400000 910000 321 >,
+ < 1267200000 925000 346 >,
+ < 1344000000 940000 371 >,
+ < 1420800000 955000 397 >,
+ < 1497600000 970000 423 >,
+ < 1574400000 980000 450 >,
+ < 1651200000 995000 477 >,
+ < 1728000000 1005000 506 >,
+ < 1804800000 1020000 536 >,
+ < 1881600000 1035000 567 >,
+ < 1958400000 1050000 598 >;
+
+ qcom,speed0-pvs3-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 73 >,
+ < 345600000 780000 85 >,
+ < 422400000 790000 104 >,
+ < 499200000 800000 124 >,
+ < 576000000 810000 144 >,
+ < 652800000 820000 165 >,
+ < 729600000 830000 186 >,
+ < 806400000 840000 208 >,
+ < 883200000 850000 229 >,
+ < 960000000 860000 252 >,
+ < 1036800000 875000 275 >,
+ < 1113600000 885000 298 >,
+ < 1190400000 895000 321 >,
+ < 1267200000 910000 346 >,
+ < 1344000000 925000 371 >,
+ < 1420800000 935000 397 >,
+ < 1497600000 950000 423 >,
+ < 1574400000 960000 450 >,
+ < 1651200000 970000 477 >,
+ < 1728000000 985000 506 >,
+ < 1804800000 995000 536 >,
+ < 1881600000 1010000 567 >,
+ < 1958400000 1025000 598 >;
+
+ qcom,speed0-pvs4-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 73 >,
+ < 345600000 775000 85 >,
+ < 422400000 780000 104 >,
+ < 499200000 790000 124 >,
+ < 576000000 800000 144 >,
+ < 652800000 810000 165 >,
+ < 729600000 820000 186 >,
+ < 806400000 830000 208 >,
+ < 883200000 840000 229 >,
+ < 960000000 850000 252 >,
+ < 1036800000 860000 275 >,
+ < 1113600000 870000 298 >,
+ < 1190400000 880000 321 >,
+ < 1267200000 895000 346 >,
+ < 1344000000 910000 371 >,
+ < 1420800000 920000 397 >,
+ < 1497600000 930000 423 >,
+ < 1574400000 940000 450 >,
+ < 1651200000 950000 477 >,
+ < 1728000000 960000 506 >,
+ < 1804800000 975000 536 >,
+ < 1881600000 985000 567 >,
+ < 1958400000 1000000 598 >;
+
+ qcom,speed0-pvs5-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 73 >,
+ < 345600000 760000 85 >,
+ < 422400000 770000 104 >,
+ < 499200000 780000 124 >,
+ < 576000000 790000 144 >,
+ < 652800000 800000 165 >,
+ < 729600000 810000 186 >,
+ < 806400000 820000 208 >,
+ < 883200000 830000 229 >,
+ < 960000000 840000 252 >,
+ < 1036800000 850000 275 >,
+ < 1113600000 860000 298 >,
+ < 1190400000 870000 321 >,
+ < 1267200000 880000 346 >,
+ < 1344000000 890000 371 >,
+ < 1420800000 900000 397 >,
+ < 1497600000 910000 423 >,
+ < 1574400000 920000 450 >,
+ < 1651200000 930000 477 >,
+ < 1728000000 940000 506 >,
+ < 1804800000 955000 536 >,
+ < 1881600000 965000 567 >,
+ < 1958400000 975000 598 >;
+
+ qcom,speed0-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 73 >,
+ < 345600000 750000 85 >,
+ < 422400000 760000 104 >,
+ < 499200000 770000 124 >,
+ < 576000000 780000 144 >,
+ < 652800000 790000 165 >,
+ < 729600000 800000 186 >,
+ < 806400000 810000 208 >,
+ < 883200000 820000 229 >,
+ < 960000000 830000 252 >,
+ < 1036800000 840000 275 >,
+ < 1113600000 850000 298 >,
+ < 1190400000 860000 321 >,
+ < 1267200000 870000 346 >,
+ < 1344000000 875000 371 >,
+ < 1420800000 885000 397 >,
+ < 1497600000 895000 423 >,
+ < 1574400000 905000 450 >,
+ < 1651200000 915000 477 >,
+ < 1728000000 920000 506 >,
+ < 1804800000 930000 536 >,
+ < 1881600000 940000 567 >,
+ < 1958400000 950000 598 >;
+
+ qcom,speed2-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 72 >,
+ < 345600000 800000 83 >,
+ < 422400000 805000 102 >,
+ < 499200000 815000 121 >,
+ < 576000000 825000 141 >,
+ < 652800000 835000 161 >,
+ < 729600000 845000 181 >,
+ < 806400000 855000 202 >,
+ < 883200000 865000 223 >,
+ < 960000000 875000 245 >,
+ < 1036800000 890000 267 >,
+ < 1113600000 900000 289 >,
+ < 1190400000 915000 313 >,
+ < 1267200000 925000 336 >,
+ < 1344000000 940000 360 >,
+ < 1420800000 950000 383 >,
+ < 1497600000 965000 409 >,
+ < 1574400000 980000 435 >,
+ < 1651200000 995000 461 >,
+ < 1728000000 1010000 488 >,
+ < 1804800000 1025000 516 >,
+ < 1881600000 1040000 543 >,
+ < 1958400000 1055000 573 >,
+ < 2035200000 1070000 604 >,
+ < 2112000000 1085000 636 >,
+ < 2150400000 1100000 656 >;
+
+ qcom,speed2-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 72 >,
+ < 345600000 800000 83 >,
+ < 422400000 800000 102 >,
+ < 499200000 800000 121 >,
+ < 576000000 810000 141 >,
+ < 652800000 820000 161 >,
+ < 729600000 830000 181 >,
+ < 806400000 840000 202 >,
+ < 883200000 850000 223 >,
+ < 960000000 860000 245 >,
+ < 1036800000 875000 267 >,
+ < 1113600000 885000 289 >,
+ < 1190400000 895000 313 >,
+ < 1267200000 910000 336 >,
+ < 1344000000 920000 360 >,
+ < 1420800000 930000 383 >,
+ < 1497600000 945000 409 >,
+ < 1574400000 960000 435 >,
+ < 1651200000 975000 461 >,
+ < 1728000000 990000 488 >,
+ < 1804800000 1005000 516 >,
+ < 1881600000 1020000 543 >,
+ < 1958400000 1030000 573 >,
+ < 2035200000 1045000 604 >,
+ < 2112000000 1060000 636 >,
+ < 2150400000 1075000 656 >;
+
+ qcom,speed2-pvs2-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 72 >,
+ < 345600000 775000 83 >,
+ < 422400000 775000 102 >,
+ < 499200000 785000 121 >,
+ < 576000000 795000 141 >,
+ < 652800000 805000 161 >,
+ < 729600000 815000 181 >,
+ < 806400000 825000 202 >,
+ < 883200000 835000 223 >,
+ < 960000000 845000 245 >,
+ < 1036800000 855000 267 >,
+ < 1113600000 865000 289 >,
+ < 1190400000 875000 313 >,
+ < 1267200000 890000 336 >,
+ < 1344000000 900000 360 >,
+ < 1420800000 910000 383 >,
+ < 1497600000 925000 409 >,
+ < 1574400000 940000 435 >,
+ < 1651200000 955000 461 >,
+ < 1728000000 970000 488 >,
+ < 1804800000 980000 516 >,
+ < 1881600000 995000 543 >,
+ < 1958400000 1005000 573 >,
+ < 2035200000 1020000 604 >,
+ < 2112000000 1035000 636 >,
+ < 2150400000 1050000 656 >;
+
+ qcom,speed2-pvs3-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 72 >,
+ < 345600000 775000 83 >,
+ < 422400000 775000 102 >,
+ < 499200000 775000 121 >,
+ < 576000000 780000 141 >,
+ < 652800000 790000 161 >,
+ < 729600000 800000 181 >,
+ < 806400000 810000 202 >,
+ < 883200000 820000 223 >,
+ < 960000000 830000 245 >,
+ < 1036800000 840000 267 >,
+ < 1113600000 850000 289 >,
+ < 1190400000 860000 313 >,
+ < 1267200000 875000 336 >,
+ < 1344000000 885000 360 >,
+ < 1420800000 895000 383 >,
+ < 1497600000 910000 409 >,
+ < 1574400000 925000 435 >,
+ < 1651200000 935000 461 >,
+ < 1728000000 950000 488 >,
+ < 1804800000 960000 516 >,
+ < 1881600000 970000 543 >,
+ < 1958400000 985000 573 >,
+ < 2035200000 995000 604 >,
+ < 2112000000 1010000 636 >,
+ < 2150400000 1025000 656 >;
+
+ qcom,speed2-pvs4-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 72 >,
+ < 345600000 775000 83 >,
+ < 422400000 775000 102 >,
+ < 499200000 775000 121 >,
+ < 576000000 775000 141 >,
+ < 652800000 780000 161 >,
+ < 729600000 790000 181 >,
+ < 806400000 800000 202 >,
+ < 883200000 810000 223 >,
+ < 960000000 820000 245 >,
+ < 1036800000 830000 267 >,
+ < 1113600000 840000 289 >,
+ < 1190400000 850000 313 >,
+ < 1267200000 860000 336 >,
+ < 1344000000 870000 360 >,
+ < 1420800000 880000 383 >,
+ < 1497600000 895000 409 >,
+ < 1574400000 910000 435 >,
+ < 1651200000 920000 461 >,
+ < 1728000000 930000 488 >,
+ < 1804800000 940000 516 >,
+ < 1881600000 950000 543 >,
+ < 1958400000 960000 573 >,
+ < 2035200000 975000 604 >,
+ < 2112000000 985000 636 >,
+ < 2150400000 1000000 656 >;
+
+ qcom,speed2-pvs5-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ < 345600000 750000 83 >,
+ < 422400000 750000 102 >,
+ < 499200000 750000 121 >,
+ < 576000000 760000 141 >,
+ < 652800000 770000 161 >,
+ < 729600000 780000 181 >,
+ < 806400000 790000 202 >,
+ < 883200000 800000 223 >,
+ < 960000000 810000 245 >,
+ < 1036800000 820000 267 >,
+ < 1113600000 830000 289 >,
+ < 1190400000 840000 313 >,
+ < 1267200000 850000 336 >,
+ < 1344000000 860000 360 >,
+ < 1420800000 870000 383 >,
+ < 1497600000 880000 409 >,
+ < 1574400000 890000 435 >,
+ < 1651200000 900000 461 >,
+ < 1728000000 910000 488 >,
+ < 1804800000 920000 516 >,
+ < 1881600000 930000 543 >,
+ < 1958400000 940000 573 >,
+ < 2035200000 955000 604 >,
+ < 2112000000 965000 636 >,
+ < 2150400000 975000 656 >;
+
+ qcom,speed2-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ < 345600000 750000 83 >,
+ < 422400000 750000 102 >,
+ < 499200000 750000 121 >,
+ < 576000000 750000 141 >,
+ < 652800000 760000 161 >,
+ < 729600000 770000 181 >,
+ < 806400000 780000 202 >,
+ < 883200000 790000 223 >,
+ < 960000000 800000 245 >,
+ < 1036800000 810000 267 >,
+ < 1113600000 820000 289 >,
+ < 1190400000 830000 313 >,
+ < 1267200000 840000 336 >,
+ < 1344000000 850000 360 >,
+ < 1420800000 860000 383 >,
+ < 1497600000 870000 409 >,
+ < 1574400000 875000 435 >,
+ < 1651200000 885000 461 >,
+ < 1728000000 895000 488 >,
+ < 1804800000 905000 516 >,
+ < 1881600000 915000 543 >,
+ < 1958400000 920000 573 >,
+ < 2035200000 930000 604 >,
+ < 2112000000 940000 636 >,
+ < 2150400000 950000 656 >;
+
+ qcom,speed1-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 72 >,
+ < 345600000 775000 83 >,
+ < 422400000 775000 101 >,
+ < 499200000 780000 120 >,
+ < 576000000 790000 139 >,
+ < 652800000 800000 159 >,
+ < 729600000 810000 180 >,
+ < 806400000 820000 200 >,
+ < 883200000 830000 221 >,
+ < 960000000 840000 242 >,
+ < 1036800000 850000 264 >,
+ < 1113600000 865000 287 >,
+ < 1190400000 875000 308 >,
+ < 1267200000 890000 333 >,
+ < 1344000000 900000 356 >,
+ < 1420800000 915000 380 >,
+ < 1497600000 925000 404 >,
+ < 1574400000 940000 430 >,
+ < 1651200000 955000 456 >,
+ < 1728000000 970000 482 >,
+ < 1804800000 985000 510 >,
+ < 1881600000 1000000 538 >,
+ < 1958400000 1015000 565 >,
+ < 2035200000 1030000 596 >,
+ < 2112000000 1045000 627 >,
+ < 2188800000 1060000 659 >,
+ < 2265600000 1075000 691 >;
+
+ qcom,speed1-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 72 >,
+ < 345600000 775000 83 >,
+ < 422400000 775000 101 >,
+ < 499200000 775000 120 >,
+ < 576000000 775000 139 >,
+ < 652800000 785000 159 >,
+ < 729600000 795000 180 >,
+ < 806400000 805000 200 >,
+ < 883200000 815000 221 >,
+ < 960000000 825000 242 >,
+ < 1036800000 835000 264 >,
+ < 1113600000 850000 287 >,
+ < 1190400000 860000 308 >,
+ < 1267200000 870000 333 >,
+ < 1344000000 885000 356 >,
+ < 1420800000 895000 380 >,
+ < 1497600000 905000 404 >,
+ < 1574400000 920000 430 >,
+ < 1651200000 935000 456 >,
+ < 1728000000 950000 482 >,
+ < 1804800000 965000 510 >,
+ < 1881600000 980000 538 >,
+ < 1958400000 995000 565 >,
+ < 2035200000 1005000 596 >,
+ < 2112000000 1020000 627 >,
+ < 2188800000 1035000 659 >,
+ < 2265600000 1050000 691 >;
+
+ qcom,speed1-pvs2-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ < 345600000 750000 83 >,
+ < 422400000 750000 101 >,
+ < 499200000 750000 120 >,
+ < 576000000 760000 139 >,
+ < 652800000 770000 159 >,
+ < 729600000 780000 180 >,
+ < 806400000 790000 200 >,
+ < 883200000 800000 221 >,
+ < 960000000 810000 242 >,
+ < 1036800000 820000 264 >,
+ < 1113600000 830000 287 >,
+ < 1190400000 840000 308 >,
+ < 1267200000 850000 333 >,
+ < 1344000000 865000 356 >,
+ < 1420800000 875000 380 >,
+ < 1497600000 885000 404 >,
+ < 1574400000 900000 430 >,
+ < 1651200000 915000 456 >,
+ < 1728000000 930000 482 >,
+ < 1804800000 945000 510 >,
+ < 1881600000 955000 538 >,
+ < 1958400000 970000 565 >,
+ < 2035200000 980000 596 >,
+ < 2112000000 995000 627 >,
+ < 2188800000 1010000 659 >,
+ < 2265600000 1025000 691 >;
+
+ qcom,speed1-pvs3-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ < 345600000 750000 83 >,
+ < 422400000 750000 101 >,
+ < 499200000 750000 120 >,
+ < 576000000 750000 139 >,
+ < 652800000 755000 159 >,
+ < 729600000 765000 180 >,
+ < 806400000 775000 200 >,
+ < 883200000 785000 221 >,
+ < 960000000 795000 242 >,
+ < 1036800000 805000 264 >,
+ < 1113600000 815000 287 >,
+ < 1190400000 825000 308 >,
+ < 1267200000 835000 333 >,
+ < 1344000000 850000 356 >,
+ < 1420800000 860000 380 >,
+ < 1497600000 870000 404 >,
+ < 1574400000 885000 430 >,
+ < 1651200000 900000 456 >,
+ < 1728000000 910000 482 >,
+ < 1804800000 925000 510 >,
+ < 1881600000 935000 538 >,
+ < 1958400000 945000 565 >,
+ < 2035200000 960000 596 >,
+ < 2112000000 970000 627 >,
+ < 2188800000 985000 659 >,
+ < 2265600000 1000000 691 >;
+
+ qcom,speed1-pvs4-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 72 >,
+ < 345600000 750000 83 >,
+ < 422400000 750000 101 >,
+ < 499200000 750000 120 >,
+ < 576000000 750000 139 >,
+ < 652800000 750000 159 >,
+ < 729600000 755000 180 >,
+ < 806400000 765000 200 >,
+ < 883200000 775000 221 >,
+ < 960000000 785000 242 >,
+ < 1036800000 795000 264 >,
+ < 1113600000 805000 287 >,
+ < 1190400000 815000 308 >,
+ < 1267200000 825000 333 >,
+ < 1344000000 835000 356 >,
+ < 1420800000 845000 380 >,
+ < 1497600000 855000 404 >,
+ < 1574400000 870000 430 >,
+ < 1651200000 885000 456 >,
+ < 1728000000 895000 482 >,
+ < 1804800000 905000 510 >,
+ < 1881600000 915000 538 >,
+ < 1958400000 925000 565 >,
+ < 2035200000 935000 596 >,
+ < 2112000000 950000 627 >,
+ < 2188800000 960000 659 >,
+ < 2265600000 975000 691 >;
+
+ qcom,speed1-pvs5-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 725000 72 >,
+ < 345600000 725000 83 >,
+ < 422400000 725000 101 >,
+ < 499200000 725000 120 >,
+ < 576000000 725000 139 >,
+ < 652800000 735000 159 >,
+ < 729600000 745000 180 >,
+ < 806400000 755000 200 >,
+ < 883200000 765000 221 >,
+ < 960000000 775000 242 >,
+ < 1036800000 785000 264 >,
+ < 1113600000 795000 287 >,
+ < 1190400000 805000 308 >,
+ < 1267200000 815000 333 >,
+ < 1344000000 825000 356 >,
+ < 1420800000 835000 380 >,
+ < 1497600000 845000 404 >,
+ < 1574400000 855000 430 >,
+ < 1651200000 865000 456 >,
+ < 1728000000 875000 482 >,
+ < 1804800000 885000 510 >,
+ < 1881600000 895000 538 >,
+ < 1958400000 905000 565 >,
+ < 2035200000 915000 596 >,
+ < 2112000000 930000 627 >,
+ < 2188800000 940000 659 >,
+ < 2265600000 950000 691 >;
+
+ qcom,speed1-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 725000 72 >,
+ < 345600000 725000 83 >,
+ < 422400000 725000 101 >,
+ < 499200000 725000 120 >,
+ < 576000000 725000 139 >,
+ < 652800000 725000 159 >,
+ < 729600000 735000 180 >,
+ < 806400000 745000 200 >,
+ < 883200000 755000 221 >,
+ < 960000000 765000 242 >,
+ < 1036800000 775000 264 >,
+ < 1113600000 785000 287 >,
+ < 1190400000 795000 308 >,
+ < 1267200000 805000 333 >,
+ < 1344000000 815000 356 >,
+ < 1420800000 825000 380 >,
+ < 1497600000 835000 404 >,
+ < 1574400000 845000 430 >,
+ < 1651200000 850000 456 >,
+ < 1728000000 860000 482 >,
+ < 1804800000 870000 510 >,
+ < 1881600000 880000 538 >,
+ < 1958400000 890000 565 >,
+ < 2035200000 895000 596 >,
+ < 2112000000 905000 627 >,
+ < 2188800000 915000 659 >,
+ < 2265600000 925000 691 >;
+ };
+
+ qcom,msm-cpufreq@0 {
+ reg = <0 4>;
+ compatible = "qcom,msm-cpufreq";
+ qcom,cpu-mem-ports = <1 512>, <2 512>;
+ qcom,cpufreq-table =
+ < 300000 300000 600 /* 75 MHz */ >,
+ < 422400 422400 1200 /* 150 MHz */ >,
+ < 652800 499200 1600 /* 200 MHz */ >,
+ < 729600 576000 2456 /* 307 MHz */ >,
+ < 883200 576000 2456 /* 307 MHz */ >,
+ < 960000 960000 3680 /* 460 MHz */ >,
+ < 1036800 1036800 3680 /* 460 MHz */ >,
+ < 1190400 1036800 3680 /* 460 MHz */ >,
+ < 1267200 1267200 4912 /* 614 MHz */ >,
+ < 1497600 1497600 4912 /* 614 MHz */ >,
+ < 1574400 1574400 6400 /* 800 MHz */ >,
+ < 1728000 1651200 6400 /* 800 MHz */ >,
+ < 1958400 1728000 7448 /* 931 MHz */ >,
+ < 2265600 1728000 7448 /* 931 MHz */ >;
};
usb3: qcom,ssusb@f9200000 {
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 9e1f83f..5769446 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -205,6 +205,9 @@
<50 172>, /* usb1_hs_async_wakeup_irq */
<53 104>, /* mdss_irq */
<62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 34>, /* APCC_qgicL2ErrorIrptReq */
+ <0xff 35>, /* WDT_barkInt */
+ <0xff 40>, /* qtimer_phy_irq */
<0xff 56>, /* modem_watchdog */
<0xff 57>, /* mss_to_apps_irq(0) */
<0xff 58>, /* mss_to_apps_irq(1) */
@@ -212,8 +215,21 @@
<0xff 60>, /* mss_to_apps_irq(3) */
<0xff 61>, /* mss_a2_bam_irq */
<0xff 70>, /* iommu_pmon_nonsecure_irq */
+ <0xff 74>, /* osmmu_CIrpt[1] */
+ <0xff 75>, /* osmmu_CIrpt[0] */
+ <0xff 77>, /* osmmu_CIrpt[0] */
+ <0xff 78>, /* osmmu_CIrpt[0] */
+ <0xff 79>, /* osmmu_CIrpt[0] */
+ <0xff 94>, /* osmmu_CIrpt[0] */
<0xff 97>, /* iommu_nonsecure_irq */
+ <0xff 99>, /* msm_iommu_pmon_nonsecure_irq */
+ <0xff 102>, /* osmmu_CIrpt[1] */
<0xff 105>, /* iommu_pmon_nonsecure_irq */
+ <0xff 109>, /* ocmem_dm_nonsec_irq */
+ <0xff 126>, /* bam_irq[0] */
+ <0xff 155>, /* sdcc_irq[0] */
+ <0xff 163>, /* usb30_ee1_irq */
+ <0xff 170>, /* sdcc_pwr_cmd_irq */
<0xff 173>, /* o_wcss_apss_smd_hi */
<0xff 174>, /* o_wcss_apss_smd_med */
<0xff 175>, /* o_wcss_apss_smd_low */
@@ -233,6 +249,7 @@
<0xff 195>, /* lpass_irq_out_apcs(7) */
<0xff 196>, /* lpass_irq_out_apcs(8) */
<0xff 197>, /* lpass_irq_out_apcs(9) */
+ <0xff 198>, /* coresight-tmc-etr interrupt */
<0xff 200>, /* rpm_ipc(4) */
<0xff 201>, /* rpm_ipc(5) */
<0xff 202>, /* rpm_ipc(6) */
@@ -242,7 +259,10 @@
<0xff 206>, /* rpm_ipc(26) */
<0xff 207>, /* rpm_ipc(27) */
<0xff 211>, /* usb_dwc3_otg */
- <0xff 240>; /* summary_irq_kpss */
+ <0xff 240>, /* summary_irq_kpss */
+ <0xff 268>, /* bam_irq[1] */
+ <0xff 270>, /* bam_irq[0] */
+ <0xff 271>; /* bam_irq[0] */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 102>,
diff --git a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
index cd485c5..2693642 100644
--- a/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pma8084.dtsi
@@ -100,20 +100,10 @@
};
};
- qcom,acpuclk@f9000000 {
- krait0_mem-supply = <&pma8084_s1_ao>;
- krait1_mem-supply = <&pma8084_s1_ao>;
- krait2_mem-supply = <&pma8084_s1_ao>;
- krait3_mem-supply = <&pma8084_s1_ao>;
- krait0_dig-supply = <&pma8084_s2_corner_ao>;
- krait1_dig-supply = <&pma8084_s2_corner_ao>;
- krait2_dig-supply = <&pma8084_s2_corner_ao>;
- krait3_dig-supply = <&pma8084_s2_corner_ao>;
- krait0_hfpll-supply = <&pma8084_l12_ao>;
- krait1_hfpll-supply = <&pma8084_l12_ao>;
- krait2_hfpll-supply = <&pma8084_l12_ao>;
- krait3_hfpll-supply = <&pma8084_l12_ao>;
- l2_hfpll-supply = <&pma8084_l12_ao>;
+ qcom,clock-krait@f9016000 {
+ l2-dig-supply = <&pma8084_s2_corner_ao>;
+ hfpll-dig-supply = <&pma8084_s2_corner_ao>;
+ hfpll-analog-supply = <&pma8084_l12_ao>;
};
qcom,ssusb@f9200000 {
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index 6d5c862..85c2fe3 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -39,6 +39,1533 @@
/delete-property/ qcom,pmic-sw-mode-temp-hysteresis;
/delete-property/ qcom,pmic-sw-mode-regs;
};
+
+ sound {
+ reg = <0xfe02c000 0x4>,
+ <0xfe02d000 0x4>,
+ <0xfe02e000 0x4>,
+ <0xfe02f000 0x4>;
+ reg-names = "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel";
+ };
+
+ qcom,clock-krait@f9016000 {
+ qcom,speed1-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 74 >,
+ < 345600000 775000 85 >,
+ < 422400000 775000 104 >,
+ < 499200000 780000 124 >,
+ < 576000000 790000 144 >,
+ < 652800000 800000 164 >,
+ < 729600000 810000 184 >,
+ < 806400000 820000 206 >,
+ < 883200000 830000 227 >,
+ < 960000000 840000 249 >,
+ < 1036800000 850000 271 >,
+ < 1113600000 865000 295 >,
+ < 1190400000 875000 318 >,
+ < 1267200000 890000 342 >,
+ < 1344000000 900000 365 >,
+ < 1420800000 915000 392 >,
+ < 1497600000 925000 416 >,
+ < 1574400000 940000 442 >,
+ < 1651200000 955000 469 >,
+ < 1728000000 970000 497 >,
+ < 1804800000 985000 525 >,
+ < 1881600000 1000000 554 >,
+ < 1958400000 1015000 583 >,
+ < 2035200000 1030000 613 >,
+ < 2112000000 1045000 642 >,
+ < 2150400000 1060000 663 >,
+ < 2188800000 1060000 675 >,
+ < 2265600000 1075000 708 >;
+
+ qcom,speed1-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 74 >,
+ < 345600000 775000 85 >,
+ < 422400000 775000 104 >,
+ < 499200000 775000 124 >,
+ < 576000000 775000 144 >,
+ < 652800000 785000 164 >,
+ < 729600000 795000 184 >,
+ < 806400000 805000 206 >,
+ < 883200000 815000 227 >,
+ < 960000000 825000 249 >,
+ < 1036800000 835000 271 >,
+ < 1113600000 850000 295 >,
+ < 1190400000 860000 318 >,
+ < 1267200000 870000 342 >,
+ < 1344000000 885000 365 >,
+ < 1420800000 895000 392 >,
+ < 1497600000 905000 416 >,
+ < 1574400000 920000 442 >,
+ < 1651200000 935000 469 >,
+ < 1728000000 950000 497 >,
+ < 1804800000 965000 525 >,
+ < 1881600000 980000 554 >,
+ < 1958400000 995000 583 >,
+ < 2035200000 1005000 613 >,
+ < 2112000000 1020000 642 >,
+ < 2150400000 1035000 663 >,
+ < 2188800000 1035000 675 >,
+ < 2265600000 1050000 708 >;
+
+ qcom,speed1-pvs2-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 74 >,
+ < 345600000 750000 85 >,
+ < 422400000 750000 104 >,
+ < 499200000 750000 124 >,
+ < 576000000 760000 144 >,
+ < 652800000 770000 164 >,
+ < 729600000 780000 184 >,
+ < 806400000 790000 206 >,
+ < 883200000 800000 227 >,
+ < 960000000 810000 249 >,
+ < 1036800000 820000 271 >,
+ < 1113600000 830000 295 >,
+ < 1190400000 840000 318 >,
+ < 1267200000 850000 342 >,
+ < 1344000000 865000 365 >,
+ < 1420800000 875000 392 >,
+ < 1497600000 885000 416 >,
+ < 1574400000 900000 442 >,
+ < 1651200000 915000 469 >,
+ < 1728000000 930000 497 >,
+ < 1804800000 945000 525 >,
+ < 1881600000 955000 554 >,
+ < 1958400000 970000 583 >,
+ < 2035200000 980000 613 >,
+ < 2112000000 995000 642 >,
+ < 2150400000 1010000 663 >,
+ < 2188800000 1010000 675 >,
+ < 2265600000 1025000 708 >;
+
+ qcom,speed1-pvs3-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 74 >,
+ < 345600000 750000 85 >,
+ < 422400000 750000 104 >,
+ < 499200000 750000 124 >,
+ < 576000000 750000 144 >,
+ < 652800000 755000 164 >,
+ < 729600000 765000 184 >,
+ < 806400000 775000 206 >,
+ < 883200000 785000 227 >,
+ < 960000000 795000 249 >,
+ < 1036800000 805000 271 >,
+ < 1113600000 815000 295 >,
+ < 1190400000 825000 318 >,
+ < 1267200000 835000 342 >,
+ < 1344000000 850000 365 >,
+ < 1420800000 860000 392 >,
+ < 1497600000 870000 416 >,
+ < 1574400000 885000 442 >,
+ < 1651200000 900000 469 >,
+ < 1728000000 910000 497 >,
+ < 1804800000 925000 525 >,
+ < 1881600000 935000 554 >,
+ < 1958400000 945000 583 >,
+ < 2035200000 960000 613 >,
+ < 2112000000 970000 642 >,
+ < 2150400000 985000 663 >,
+ < 2188800000 985000 675 >,
+ < 2265600000 1000000 708 >;
+
+ qcom,speed1-pvs4-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 74 >,
+ < 345600000 750000 85 >,
+ < 422400000 750000 104 >,
+ < 499200000 750000 124 >,
+ < 576000000 750000 144 >,
+ < 652800000 750000 164 >,
+ < 729600000 755000 184 >,
+ < 806400000 765000 206 >,
+ < 883200000 775000 227 >,
+ < 960000000 785000 249 >,
+ < 1036800000 795000 271 >,
+ < 1113600000 805000 295 >,
+ < 1190400000 815000 318 >,
+ < 1267200000 825000 342 >,
+ < 1344000000 835000 365 >,
+ < 1420800000 845000 392 >,
+ < 1497600000 855000 416 >,
+ < 1574400000 870000 442 >,
+ < 1651200000 885000 469 >,
+ < 1728000000 895000 497 >,
+ < 1804800000 905000 525 >,
+ < 1881600000 915000 554 >,
+ < 1958400000 925000 583 >,
+ < 2035200000 935000 613 >,
+ < 2112000000 950000 642 >,
+ < 2150400000 960000 663 >,
+ < 2188800000 960000 675 >,
+ < 2265600000 975000 708 >;
+
+ qcom,speed1-pvs5-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 725000 74 >,
+ < 345600000 725000 85 >,
+ < 422400000 725000 104 >,
+ < 499200000 725000 124 >,
+ < 576000000 725000 144 >,
+ < 652800000 735000 164 >,
+ < 729600000 745000 184 >,
+ < 806400000 755000 206 >,
+ < 883200000 765000 227 >,
+ < 960000000 775000 249 >,
+ < 1036800000 785000 271 >,
+ < 1113600000 795000 295 >,
+ < 1190400000 805000 318 >,
+ < 1267200000 815000 342 >,
+ < 1344000000 825000 365 >,
+ < 1420800000 835000 392 >,
+ < 1497600000 845000 416 >,
+ < 1574400000 855000 442 >,
+ < 1651200000 865000 469 >,
+ < 1728000000 875000 497 >,
+ < 1804800000 885000 525 >,
+ < 1881600000 895000 554 >,
+ < 1958400000 905000 583 >,
+ < 2035200000 915000 613 >,
+ < 2112000000 930000 642 >,
+ < 2150400000 940000 663 >,
+ < 2188800000 940000 675 >,
+ < 2265600000 950000 708 >;
+
+ qcom,speed1-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 725000 74 >,
+ < 345600000 725000 85 >,
+ < 422400000 725000 104 >,
+ < 499200000 725000 124 >,
+ < 576000000 725000 144 >,
+ < 652800000 725000 164 >,
+ < 729600000 735000 184 >,
+ < 806400000 745000 206 >,
+ < 883200000 755000 227 >,
+ < 960000000 765000 249 >,
+ < 1036800000 775000 271 >,
+ < 1113600000 785000 295 >,
+ < 1190400000 795000 318 >,
+ < 1267200000 805000 342 >,
+ < 1344000000 815000 365 >,
+ < 1420800000 825000 392 >,
+ < 1497600000 835000 416 >,
+ < 1574400000 845000 442 >,
+ < 1651200000 850000 469 >,
+ < 1728000000 860000 497 >,
+ < 1804800000 870000 525 >,
+ < 1881600000 880000 554 >,
+ < 1958400000 890000 583 >,
+ < 2035200000 895000 613 >,
+ < 2112000000 905000 642 >,
+ < 2150400000 915000 663 >,
+ < 2188800000 915000 675 >,
+ < 2265600000 925000 708 >;
+
+ qcom,speed3-pvs0-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 125 >,
+ < 576000000 800000 145 >,
+ < 652800000 810000 165 >,
+ < 729600000 820000 186 >,
+ < 806400000 830000 208 >,
+ < 883200000 840000 229 >,
+ < 960000000 850000 251 >,
+ < 1036800000 860000 273 >,
+ < 1113600000 870000 296 >,
+ < 1190400000 880000 319 >,
+ < 1267200000 890000 342 >,
+ < 1344000000 900000 365 >,
+ < 1420800000 910000 390 >,
+ < 1497600000 920000 415 >,
+ < 1574400000 930000 439 >,
+ < 1651200000 945000 465 >,
+ < 1728000000 960000 493 >,
+ < 1804800000 975000 521 >,
+ < 1881600000 990000 549 >,
+ < 1958400000 1005000 579 >,
+ < 2035200000 1020000 608 >,
+ < 2112000000 1035000 638 >,
+ < 2150400000 1050000 667 >,
+ < 2188800000 1050000 667 >,
+ < 2265600000 1065000 700 >,
+ < 2342400000 1080000 734 >,
+ < 2419200000 1095000 769 >,
+ < 2457600000 1100000 785 >;
+
+ qcom,speed3-pvs1-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 125 >,
+ < 576000000 800000 145 >,
+ < 652800000 800000 165 >,
+ < 729600000 800000 186 >,
+ < 806400000 805000 208 >,
+ < 883200000 815000 229 >,
+ < 960000000 825000 251 >,
+ < 1036800000 835000 273 >,
+ < 1113600000 845000 296 >,
+ < 1190400000 855000 319 >,
+ < 1267200000 865000 342 >,
+ < 1344000000 875000 365 >,
+ < 1420800000 885000 390 >,
+ < 1497600000 895000 415 >,
+ < 1574400000 905000 439 >,
+ < 1651200000 920000 465 >,
+ < 1728000000 935000 493 >,
+ < 1804800000 950000 521 >,
+ < 1881600000 965000 549 >,
+ < 1958400000 980000 579 >,
+ < 2035200000 995000 608 >,
+ < 2112000000 1010000 638 >,
+ < 2150400000 1025000 667 >,
+ < 2188800000 1025000 667 >,
+ < 2265600000 1040000 700 >,
+ < 2342400000 1055000 734 >,
+ < 2419200000 1070000 769 >,
+ < 2457600000 1075000 785 >;
+
+ qcom,speed3-pvs2-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 125 >,
+ < 576000000 775000 145 >,
+ < 652800000 775000 165 >,
+ < 729600000 775000 186 >,
+ < 806400000 780000 208 >,
+ < 883200000 790000 229 >,
+ < 960000000 800000 251 >,
+ < 1036800000 810000 273 >,
+ < 1113600000 820000 296 >,
+ < 1190400000 830000 319 >,
+ < 1267200000 840000 342 >,
+ < 1344000000 850000 365 >,
+ < 1420800000 860000 390 >,
+ < 1497600000 870000 415 >,
+ < 1574400000 880000 439 >,
+ < 1651200000 895000 465 >,
+ < 1728000000 910000 493 >,
+ < 1804800000 925000 521 >,
+ < 1881600000 940000 549 >,
+ < 1958400000 955000 579 >,
+ < 2035200000 970000 608 >,
+ < 2112000000 985000 638 >,
+ < 2150400000 1000000 667 >,
+ < 2188800000 1000000 667 >,
+ < 2265600000 1015000 700 >,
+ < 2342400000 1030000 734 >,
+ < 2419200000 1045000 769 >,
+ < 2457600000 1050000 785 >;
+
+ qcom,speed3-pvs3-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 125 >,
+ < 576000000 775000 145 >,
+ < 652800000 775000 165 >,
+ < 729600000 775000 186 >,
+ < 806400000 775000 208 >,
+ < 883200000 775000 229 >,
+ < 960000000 780000 251 >,
+ < 1036800000 785000 273 >,
+ < 1113600000 795000 296 >,
+ < 1190400000 805000 319 >,
+ < 1267200000 815000 342 >,
+ < 1344000000 825000 365 >,
+ < 1420800000 835000 390 >,
+ < 1497600000 845000 415 >,
+ < 1574400000 855000 439 >,
+ < 1651200000 870000 465 >,
+ < 1728000000 885000 493 >,
+ < 1804800000 900000 521 >,
+ < 1881600000 915000 549 >,
+ < 1958400000 930000 579 >,
+ < 2035200000 945000 608 >,
+ < 2112000000 960000 638 >,
+ < 2150400000 975000 667 >,
+ < 2188800000 975000 667 >,
+ < 2265600000 990000 700 >,
+ < 2342400000 1005000 734 >,
+ < 2419200000 1020000 769 >,
+ < 2457600000 1025000 785 >;
+
+ qcom,speed3-pvs4-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 125 >,
+ < 576000000 775000 145 >,
+ < 652800000 775000 165 >,
+ < 729600000 775000 186 >,
+ < 806400000 775000 208 >,
+ < 883200000 775000 229 >,
+ < 960000000 775000 251 >,
+ < 1036800000 775000 273 >,
+ < 1113600000 775000 296 >,
+ < 1190400000 780000 319 >,
+ < 1267200000 790000 342 >,
+ < 1344000000 800000 365 >,
+ < 1420800000 810000 390 >,
+ < 1497600000 820000 415 >,
+ < 1574400000 830000 439 >,
+ < 1651200000 845000 465 >,
+ < 1728000000 860000 493 >,
+ < 1804800000 875000 521 >,
+ < 1881600000 890000 549 >,
+ < 1958400000 905000 579 >,
+ < 2035200000 920000 608 >,
+ < 2112000000 935000 638 >,
+ < 2150400000 950000 667 >,
+ < 2188800000 950000 667 >,
+ < 2265600000 965000 700 >,
+ < 2342400000 980000 734 >,
+ < 2419200000 995000 769 >,
+ < 2457600000 1000000 785 >;
+
+ qcom,speed3-pvs5-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 106 >,
+ < 499200000 750000 125 >,
+ < 576000000 750000 145 >,
+ < 652800000 750000 165 >,
+ < 729600000 750000 186 >,
+ < 806400000 750000 208 >,
+ < 883200000 750000 229 >,
+ < 960000000 750000 251 >,
+ < 1036800000 750000 273 >,
+ < 1113600000 750000 296 >,
+ < 1190400000 760000 319 >,
+ < 1267200000 770000 342 >,
+ < 1344000000 780000 365 >,
+ < 1420800000 790000 390 >,
+ < 1497600000 800000 415 >,
+ < 1574400000 810000 439 >,
+ < 1651200000 820000 465 >,
+ < 1728000000 835000 493 >,
+ < 1804800000 850000 521 >,
+ < 1881600000 865000 549 >,
+ < 1958400000 880000 579 >,
+ < 2035200000 895000 608 >,
+ < 2112000000 910000 638 >,
+ < 2150400000 925000 667 >,
+ < 2188800000 925000 667 >,
+ < 2265600000 940000 700 >,
+ < 2342400000 955000 734 >,
+ < 2419200000 970000 769 >,
+ < 2457600000 975000 785 >;
+
+ qcom,speed3-pvs6-bin-v0 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 106 >,
+ < 499200000 750000 125 >,
+ < 576000000 750000 145 >,
+ < 652800000 750000 165 >,
+ < 729600000 750000 186 >,
+ < 806400000 750000 208 >,
+ < 883200000 750000 229 >,
+ < 960000000 750000 251 >,
+ < 1036800000 750000 273 >,
+ < 1113600000 750000 296 >,
+ < 1190400000 750000 319 >,
+ < 1267200000 755000 342 >,
+ < 1344000000 765000 365 >,
+ < 1420800000 775000 390 >,
+ < 1497600000 785000 415 >,
+ < 1574400000 795000 439 >,
+ < 1651200000 805000 465 >,
+ < 1728000000 815000 493 >,
+ < 1804800000 825000 521 >,
+ < 1881600000 840000 549 >,
+ < 1958400000 855000 579 >,
+ < 2035200000 870000 608 >,
+ < 2112000000 885000 638 >,
+ < 2150400000 900000 667 >,
+ < 2188800000 900000 667 >,
+ < 2265600000 915000 700 >,
+ < 2342400000 930000 734 >,
+ < 2419200000 945000 769 >,
+ < 2457600000 950000 785 >;
+
+ qcom,speed1-pvs0-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 810000 87 >,
+ < 422400000 820000 108 >,
+ < 499200000 830000 129 >,
+ < 576000000 840000 150 >,
+ < 652800000 850000 171 >,
+ < 729600000 860000 193 >,
+ < 806400000 870000 215 >,
+ < 883200000 880000 237 >,
+ < 960000000 890000 260 >,
+ < 1036800000 900000 282 >,
+ < 1113600000 910000 306 >,
+ < 1190400000 920000 330 >,
+ < 1267200000 930000 354 >,
+ < 1344000000 940000 378 >,
+ < 1420800000 955000 404 >,
+ < 1497600000 970000 431 >,
+ < 1574400000 985000 458 >,
+ < 1651200000 1000000 486 >,
+ < 1728000000 1015000 515 >,
+ < 1804800000 1030000 543 >,
+ < 1881600000 1045000 572 >,
+ < 1958400000 1060000 604 >,
+ < 2035200000 1075000 636 >,
+ < 2112000000 1090000 669 >,
+ < 2150400000 1105000 703 >,
+ < 2188800000 1105000 703 >,
+ < 2265600000 1120000 738 >;
+
+ qcom,speed1-pvs1-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 810000 108 >,
+ < 499200000 820000 129 >,
+ < 576000000 830000 150 >,
+ < 652800000 840000 171 >,
+ < 729600000 850000 193 >,
+ < 806400000 860000 215 >,
+ < 883200000 870000 237 >,
+ < 960000000 880000 260 >,
+ < 1036800000 890000 282 >,
+ < 1113600000 900000 306 >,
+ < 1190400000 910000 330 >,
+ < 1267200000 920000 354 >,
+ < 1344000000 930000 378 >,
+ < 1420800000 945000 404 >,
+ < 1497600000 960000 431 >,
+ < 1574400000 975000 458 >,
+ < 1651200000 990000 486 >,
+ < 1728000000 1005000 515 >,
+ < 1804800000 1020000 543 >,
+ < 1881600000 1035000 572 >,
+ < 1958400000 1050000 604 >,
+ < 2035200000 1065000 636 >,
+ < 2112000000 1080000 669 >,
+ < 2150400000 1095000 703 >,
+ < 2188800000 1095000 703 >,
+ < 2265600000 1110000 738 >;
+
+ qcom,speed1-pvs2-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 108 >,
+ < 499200000 810000 129 >,
+ < 576000000 820000 150 >,
+ < 652800000 830000 171 >,
+ < 729600000 840000 193 >,
+ < 806400000 850000 215 >,
+ < 883200000 860000 237 >,
+ < 960000000 870000 260 >,
+ < 1036800000 880000 282 >,
+ < 1113600000 890000 306 >,
+ < 1190400000 900000 330 >,
+ < 1267200000 910000 354 >,
+ < 1344000000 920000 378 >,
+ < 1420800000 935000 404 >,
+ < 1497600000 950000 431 >,
+ < 1574400000 965000 458 >,
+ < 1651200000 980000 486 >,
+ < 1728000000 995000 515 >,
+ < 1804800000 1010000 543 >,
+ < 1881600000 1025000 572 >,
+ < 1958400000 1040000 604 >,
+ < 2035200000 1055000 636 >,
+ < 2112000000 1070000 669 >,
+ < 2150400000 1085000 703 >,
+ < 2188800000 1085000 703 >,
+ < 2265600000 1100000 738 >;
+
+ qcom,speed1-pvs3-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 108 >,
+ < 499200000 800000 129 >,
+ < 576000000 810000 150 >,
+ < 652800000 820000 171 >,
+ < 729600000 830000 193 >,
+ < 806400000 840000 215 >,
+ < 883200000 850000 237 >,
+ < 960000000 860000 260 >,
+ < 1036800000 870000 282 >,
+ < 1113600000 880000 306 >,
+ < 1190400000 890000 330 >,
+ < 1267200000 900000 354 >,
+ < 1344000000 910000 378 >,
+ < 1420800000 925000 404 >,
+ < 1497600000 940000 431 >,
+ < 1574400000 955000 458 >,
+ < 1651200000 970000 486 >,
+ < 1728000000 985000 515 >,
+ < 1804800000 1000000 543 >,
+ < 1881600000 1015000 572 >,
+ < 1958400000 1030000 604 >,
+ < 2035200000 1045000 636 >,
+ < 2112000000 1060000 669 >,
+ < 2150400000 1075000 703 >,
+ < 2188800000 1075000 703 >,
+ < 2265600000 1090000 738 >;
+
+ qcom,speed1-pvs4-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 108 >,
+ < 499200000 800000 129 >,
+ < 576000000 800000 150 >,
+ < 652800000 810000 171 >,
+ < 729600000 820000 193 >,
+ < 806400000 830000 215 >,
+ < 883200000 840000 237 >,
+ < 960000000 850000 260 >,
+ < 1036800000 860000 282 >,
+ < 1113600000 870000 306 >,
+ < 1190400000 880000 330 >,
+ < 1267200000 890000 354 >,
+ < 1344000000 900000 378 >,
+ < 1420800000 915000 404 >,
+ < 1497600000 930000 431 >,
+ < 1574400000 945000 458 >,
+ < 1651200000 960000 486 >,
+ < 1728000000 975000 515 >,
+ < 1804800000 990000 543 >,
+ < 1881600000 1005000 572 >,
+ < 1958400000 1020000 604 >,
+ < 2035200000 1035000 636 >,
+ < 2112000000 1050000 669 >,
+ < 2150400000 1065000 703 >,
+ < 2188800000 1065000 703 >,
+ < 2265600000 1080000 738 >;
+
+ qcom,speed1-pvs5-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 108 >,
+ < 499200000 800000 129 >,
+ < 576000000 800000 150 >,
+ < 652800000 800000 171 >,
+ < 729600000 810000 193 >,
+ < 806400000 820000 215 >,
+ < 883200000 830000 237 >,
+ < 960000000 840000 260 >,
+ < 1036800000 850000 282 >,
+ < 1113600000 860000 306 >,
+ < 1190400000 870000 330 >,
+ < 1267200000 880000 354 >,
+ < 1344000000 890000 378 >,
+ < 1420800000 905000 404 >,
+ < 1497600000 920000 431 >,
+ < 1574400000 935000 458 >,
+ < 1651200000 950000 486 >,
+ < 1728000000 965000 515 >,
+ < 1804800000 980000 543 >,
+ < 1881600000 995000 572 >,
+ < 1958400000 1010000 604 >,
+ < 2035200000 1025000 636 >,
+ < 2112000000 1040000 669 >,
+ < 2150400000 1055000 703 >,
+ < 2188800000 1055000 703 >,
+ < 2265600000 1070000 738 >;
+
+ qcom,speed1-pvs6-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 780000 150 >,
+ < 652800000 790000 171 >,
+ < 729600000 800000 193 >,
+ < 806400000 810000 215 >,
+ < 883200000 820000 237 >,
+ < 960000000 830000 260 >,
+ < 1036800000 840000 282 >,
+ < 1113600000 850000 306 >,
+ < 1190400000 860000 330 >,
+ < 1267200000 870000 354 >,
+ < 1344000000 880000 378 >,
+ < 1420800000 895000 404 >,
+ < 1497600000 910000 431 >,
+ < 1574400000 925000 458 >,
+ < 1651200000 940000 486 >,
+ < 1728000000 955000 515 >,
+ < 1804800000 970000 543 >,
+ < 1881600000 985000 572 >,
+ < 1958400000 1000000 604 >,
+ < 2035200000 1015000 636 >,
+ < 2112000000 1030000 669 >,
+ < 2150400000 1045000 703 >,
+ < 2188800000 1045000 703 >,
+ < 2265600000 1060000 738 >;
+
+ qcom,speed1-pvs7-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 780000 171 >,
+ < 729600000 790000 193 >,
+ < 806400000 800000 215 >,
+ < 883200000 810000 237 >,
+ < 960000000 820000 260 >,
+ < 1036800000 830000 282 >,
+ < 1113600000 840000 306 >,
+ < 1190400000 850000 330 >,
+ < 1267200000 860000 354 >,
+ < 1344000000 870000 378 >,
+ < 1420800000 885000 404 >,
+ < 1497600000 900000 431 >,
+ < 1574400000 915000 458 >,
+ < 1651200000 930000 486 >,
+ < 1728000000 945000 515 >,
+ < 1804800000 960000 543 >,
+ < 1881600000 975000 572 >,
+ < 1958400000 990000 604 >,
+ < 2035200000 1005000 636 >,
+ < 2112000000 1020000 669 >,
+ < 2150400000 1035000 703 >,
+ < 2188800000 1035000 703 >,
+ < 2265600000 1050000 738 >;
+
+ qcom,speed1-pvs8-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 780000 193 >,
+ < 806400000 790000 215 >,
+ < 883200000 800000 237 >,
+ < 960000000 810000 260 >,
+ < 1036800000 820000 282 >,
+ < 1113600000 830000 306 >,
+ < 1190400000 840000 330 >,
+ < 1267200000 850000 354 >,
+ < 1344000000 860000 378 >,
+ < 1420800000 875000 404 >,
+ < 1497600000 890000 431 >,
+ < 1574400000 905000 458 >,
+ < 1651200000 920000 486 >,
+ < 1728000000 935000 515 >,
+ < 1804800000 950000 543 >,
+ < 1881600000 965000 572 >,
+ < 1958400000 980000 604 >,
+ < 2035200000 995000 636 >,
+ < 2112000000 1010000 669 >,
+ < 2150400000 1025000 703 >,
+ < 2188800000 1025000 703 >,
+ < 2265600000 1040000 738 >;
+
+ qcom,speed1-pvs9-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 775000 193 >,
+ < 806400000 780000 215 >,
+ < 883200000 790000 237 >,
+ < 960000000 800000 260 >,
+ < 1036800000 810000 282 >,
+ < 1113600000 820000 306 >,
+ < 1190400000 830000 330 >,
+ < 1267200000 840000 354 >,
+ < 1344000000 850000 378 >,
+ < 1420800000 865000 404 >,
+ < 1497600000 880000 431 >,
+ < 1574400000 895000 458 >,
+ < 1651200000 910000 486 >,
+ < 1728000000 925000 515 >,
+ < 1804800000 940000 543 >,
+ < 1881600000 955000 572 >,
+ < 1958400000 970000 604 >,
+ < 2035200000 985000 636 >,
+ < 2112000000 1000000 669 >,
+ < 2150400000 1015000 703 >,
+ < 2188800000 1015000 703 >,
+ < 2265600000 1030000 738 >;
+
+ qcom,speed1-pvs10-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 775000 193 >,
+ < 806400000 775000 215 >,
+ < 883200000 780000 237 >,
+ < 960000000 790000 260 >,
+ < 1036800000 800000 282 >,
+ < 1113600000 810000 306 >,
+ < 1190400000 820000 330 >,
+ < 1267200000 830000 354 >,
+ < 1344000000 840000 378 >,
+ < 1420800000 855000 404 >,
+ < 1497600000 870000 431 >,
+ < 1574400000 885000 458 >,
+ < 1651200000 900000 486 >,
+ < 1728000000 915000 515 >,
+ < 1804800000 930000 543 >,
+ < 1881600000 945000 572 >,
+ < 1958400000 960000 604 >,
+ < 2035200000 975000 636 >,
+ < 2112000000 990000 669 >,
+ < 2150400000 1005000 703 >,
+ < 2188800000 1005000 703 >,
+ < 2265600000 1020000 738 >;
+
+ qcom,speed1-pvs11-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 775000 193 >,
+ < 806400000 775000 215 >,
+ < 883200000 775000 237 >,
+ < 960000000 780000 260 >,
+ < 1036800000 790000 282 >,
+ < 1113600000 800000 306 >,
+ < 1190400000 810000 330 >,
+ < 1267200000 820000 354 >,
+ < 1344000000 830000 378 >,
+ < 1420800000 845000 404 >,
+ < 1497600000 860000 431 >,
+ < 1574400000 875000 458 >,
+ < 1651200000 890000 486 >,
+ < 1728000000 905000 515 >,
+ < 1804800000 920000 543 >,
+ < 1881600000 935000 572 >,
+ < 1958400000 950000 604 >,
+ < 2035200000 965000 636 >,
+ < 2112000000 980000 669 >,
+ < 2150400000 995000 703 >,
+ < 2188800000 995000 703 >,
+ < 2265600000 1010000 738 >;
+
+ qcom,speed1-pvs12-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 775000 193 >,
+ < 806400000 775000 215 >,
+ < 883200000 775000 237 >,
+ < 960000000 775000 260 >,
+ < 1036800000 780000 282 >,
+ < 1113600000 790000 306 >,
+ < 1190400000 800000 330 >,
+ < 1267200000 810000 354 >,
+ < 1344000000 820000 378 >,
+ < 1420800000 835000 404 >,
+ < 1497600000 850000 431 >,
+ < 1574400000 865000 458 >,
+ < 1651200000 880000 486 >,
+ < 1728000000 895000 515 >,
+ < 1804800000 910000 543 >,
+ < 1881600000 925000 572 >,
+ < 1958400000 940000 604 >,
+ < 2035200000 955000 636 >,
+ < 2112000000 970000 669 >,
+ < 2150400000 985000 703 >,
+ < 2188800000 985000 703 >,
+ < 2265600000 1000000 738 >;
+
+ qcom,speed1-pvs13-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 108 >,
+ < 499200000 775000 129 >,
+ < 576000000 775000 150 >,
+ < 652800000 775000 171 >,
+ < 729600000 775000 193 >,
+ < 806400000 775000 215 >,
+ < 883200000 775000 237 >,
+ < 960000000 775000 260 >,
+ < 1036800000 775000 282 >,
+ < 1113600000 780000 306 >,
+ < 1190400000 790000 330 >,
+ < 1267200000 800000 354 >,
+ < 1344000000 810000 378 >,
+ < 1420800000 825000 404 >,
+ < 1497600000 840000 431 >,
+ < 1574400000 855000 458 >,
+ < 1651200000 870000 486 >,
+ < 1728000000 885000 515 >,
+ < 1804800000 900000 543 >,
+ < 1881600000 915000 572 >,
+ < 1958400000 930000 604 >,
+ < 2035200000 945000 636 >,
+ < 2112000000 960000 669 >,
+ < 2150400000 975000 703 >,
+ < 2188800000 975000 703 >,
+ < 2265600000 990000 738 >;
+
+ qcom,speed1-pvs14-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 108 >,
+ < 499200000 750000 129 >,
+ < 576000000 750000 150 >,
+ < 652800000 750000 171 >,
+ < 729600000 750000 193 >,
+ < 806400000 750000 215 >,
+ < 883200000 750000 237 >,
+ < 960000000 750000 260 >,
+ < 1036800000 760000 282 >,
+ < 1113600000 770000 306 >,
+ < 1190400000 780000 330 >,
+ < 1267200000 790000 354 >,
+ < 1344000000 800000 378 >,
+ < 1420800000 815000 404 >,
+ < 1497600000 830000 431 >,
+ < 1574400000 845000 458 >,
+ < 1651200000 860000 486 >,
+ < 1728000000 875000 515 >,
+ < 1804800000 890000 543 >,
+ < 1881600000 905000 572 >,
+ < 1958400000 920000 604 >,
+ < 2035200000 935000 636 >,
+ < 2112000000 950000 669 >,
+ < 2150400000 965000 703 >,
+ < 2188800000 965000 703 >,
+ < 2265600000 980000 738 >;
+
+ qcom,speed1-pvs15-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 108 >,
+ < 499200000 750000 129 >,
+ < 576000000 750000 150 >,
+ < 652800000 750000 171 >,
+ < 729600000 750000 193 >,
+ < 806400000 750000 215 >,
+ < 883200000 750000 237 >,
+ < 960000000 750000 260 >,
+ < 1036800000 750000 282 >,
+ < 1113600000 760000 306 >,
+ < 1190400000 770000 330 >,
+ < 1267200000 780000 354 >,
+ < 1344000000 790000 378 >,
+ < 1420800000 805000 404 >,
+ < 1497600000 820000 431 >,
+ < 1574400000 835000 458 >,
+ < 1651200000 850000 486 >,
+ < 1728000000 865000 515 >,
+ < 1804800000 880000 543 >,
+ < 1881600000 895000 572 >,
+ < 1958400000 910000 604 >,
+ < 2035200000 925000 636 >,
+ < 2112000000 940000 669 >,
+ < 2150400000 955000 703 >,
+ < 2188800000 955000 703 >,
+ < 2265600000 970000 738 >;
+
+ qcom,speed3-pvs0-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 810000 126 >,
+ < 576000000 820000 147 >,
+ < 652800000 830000 168 >,
+ < 729600000 840000 189 >,
+ < 806400000 850000 211 >,
+ < 883200000 860000 233 >,
+ < 960000000 870000 256 >,
+ < 1036800000 880000 278 >,
+ < 1113600000 890000 301 >,
+ < 1190400000 900000 324 >,
+ < 1267200000 910000 348 >,
+ < 1344000000 920000 372 >,
+ < 1420800000 930000 396 >,
+ < 1497600000 940000 421 >,
+ < 1574400000 950000 446 >,
+ < 1651200000 965000 473 >,
+ < 1728000000 980000 501 >,
+ < 1804800000 995000 529 >,
+ < 1881600000 1010000 558 >,
+ < 1958400000 1025000 588 >,
+ < 2035200000 1040000 617 >,
+ < 2112000000 1055000 649 >,
+ < 2150400000 1070000 682 >,
+ < 2188800000 1070000 682 >,
+ < 2265600000 1085000 716 >,
+ < 2342400000 1100000 751 >,
+ < 2419200000 1115000 786 >,
+ < 2457600000 1120000 802 >;
+
+ qcom,speed3-pvs1-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 126 >,
+ < 576000000 810000 147 >,
+ < 652800000 820000 168 >,
+ < 729600000 830000 189 >,
+ < 806400000 840000 211 >,
+ < 883200000 850000 233 >,
+ < 960000000 860000 256 >,
+ < 1036800000 870000 278 >,
+ < 1113600000 880000 301 >,
+ < 1190400000 890000 324 >,
+ < 1267200000 900000 348 >,
+ < 1344000000 910000 372 >,
+ < 1420800000 920000 396 >,
+ < 1497600000 930000 421 >,
+ < 1574400000 940000 446 >,
+ < 1651200000 955000 473 >,
+ < 1728000000 970000 501 >,
+ < 1804800000 985000 529 >,
+ < 1881600000 1000000 558 >,
+ < 1958400000 1015000 588 >,
+ < 2035200000 1030000 617 >,
+ < 2112000000 1045000 649 >,
+ < 2150400000 1060000 682 >,
+ < 2188800000 1060000 682 >,
+ < 2265600000 1075000 716 >,
+ < 2342400000 1090000 751 >,
+ < 2419200000 1105000 786 >,
+ < 2457600000 1110000 802 >;
+
+ qcom,speed3-pvs2-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 126 >,
+ < 576000000 800000 147 >,
+ < 652800000 810000 168 >,
+ < 729600000 820000 189 >,
+ < 806400000 830000 211 >,
+ < 883200000 840000 233 >,
+ < 960000000 850000 256 >,
+ < 1036800000 860000 278 >,
+ < 1113600000 870000 301 >,
+ < 1190400000 880000 324 >,
+ < 1267200000 890000 348 >,
+ < 1344000000 900000 372 >,
+ < 1420800000 910000 396 >,
+ < 1497600000 920000 421 >,
+ < 1574400000 930000 446 >,
+ < 1651200000 945000 473 >,
+ < 1728000000 960000 501 >,
+ < 1804800000 975000 529 >,
+ < 1881600000 990000 558 >,
+ < 1958400000 1005000 588 >,
+ < 2035200000 1020000 617 >,
+ < 2112000000 1035000 649 >,
+ < 2150400000 1050000 682 >,
+ < 2188800000 1050000 682 >,
+ < 2265600000 1065000 716 >,
+ < 2342400000 1080000 751 >,
+ < 2419200000 1095000 786 >,
+ < 2457600000 1100000 802 >;
+
+ qcom,speed3-pvs3-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 126 >,
+ < 576000000 800000 147 >,
+ < 652800000 800000 168 >,
+ < 729600000 810000 189 >,
+ < 806400000 820000 211 >,
+ < 883200000 830000 233 >,
+ < 960000000 840000 256 >,
+ < 1036800000 850000 278 >,
+ < 1113600000 860000 301 >,
+ < 1190400000 870000 324 >,
+ < 1267200000 880000 348 >,
+ < 1344000000 890000 372 >,
+ < 1420800000 900000 396 >,
+ < 1497600000 910000 421 >,
+ < 1574400000 920000 446 >,
+ < 1651200000 935000 473 >,
+ < 1728000000 950000 501 >,
+ < 1804800000 965000 529 >,
+ < 1881600000 980000 558 >,
+ < 1958400000 995000 588 >,
+ < 2035200000 1010000 617 >,
+ < 2112000000 1025000 649 >,
+ < 2150400000 1040000 682 >,
+ < 2188800000 1040000 682 >,
+ < 2265600000 1055000 716 >,
+ < 2342400000 1070000 751 >,
+ < 2419200000 1085000 786 >,
+ < 2457600000 1090000 802 >;
+
+ qcom,speed3-pvs4-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 126 >,
+ < 576000000 800000 147 >,
+ < 652800000 800000 168 >,
+ < 729600000 800000 189 >,
+ < 806400000 810000 211 >,
+ < 883200000 820000 233 >,
+ < 960000000 830000 256 >,
+ < 1036800000 840000 278 >,
+ < 1113600000 850000 301 >,
+ < 1190400000 860000 324 >,
+ < 1267200000 870000 348 >,
+ < 1344000000 880000 372 >,
+ < 1420800000 890000 396 >,
+ < 1497600000 900000 421 >,
+ < 1574400000 910000 446 >,
+ < 1651200000 925000 473 >,
+ < 1728000000 940000 501 >,
+ < 1804800000 955000 529 >,
+ < 1881600000 970000 558 >,
+ < 1958400000 985000 588 >,
+ < 2035200000 1000000 617 >,
+ < 2112000000 1015000 649 >,
+ < 2150400000 1030000 682 >,
+ < 2188800000 1030000 682 >,
+ < 2265600000 1045000 716 >,
+ < 2342400000 1060000 751 >,
+ < 2419200000 1075000 786 >,
+ < 2457600000 1080000 802 >;
+
+ qcom,speed3-pvs5-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 800000 76 >,
+ < 345600000 800000 87 >,
+ < 422400000 800000 106 >,
+ < 499200000 800000 126 >,
+ < 576000000 800000 147 >,
+ < 652800000 800000 168 >,
+ < 729600000 800000 189 >,
+ < 806400000 800000 211 >,
+ < 883200000 810000 233 >,
+ < 960000000 820000 256 >,
+ < 1036800000 830000 278 >,
+ < 1113600000 840000 301 >,
+ < 1190400000 850000 324 >,
+ < 1267200000 860000 348 >,
+ < 1344000000 870000 372 >,
+ < 1420800000 880000 396 >,
+ < 1497600000 890000 421 >,
+ < 1574400000 900000 446 >,
+ < 1651200000 915000 473 >,
+ < 1728000000 930000 501 >,
+ < 1804800000 945000 529 >,
+ < 1881600000 960000 558 >,
+ < 1958400000 975000 588 >,
+ < 2035200000 990000 617 >,
+ < 2112000000 1005000 649 >,
+ < 2150400000 1020000 682 >,
+ < 2188800000 1020000 682 >,
+ < 2265600000 1035000 716 >,
+ < 2342400000 1050000 751 >,
+ < 2419200000 1065000 786 >,
+ < 2457600000 1070000 802 >;
+
+ qcom,speed3-pvs6-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 780000 189 >,
+ < 806400000 790000 211 >,
+ < 883200000 800000 233 >,
+ < 960000000 810000 256 >,
+ < 1036800000 820000 278 >,
+ < 1113600000 830000 301 >,
+ < 1190400000 840000 324 >,
+ < 1267200000 850000 348 >,
+ < 1344000000 860000 372 >,
+ < 1420800000 870000 396 >,
+ < 1497600000 880000 421 >,
+ < 1574400000 890000 446 >,
+ < 1651200000 905000 473 >,
+ < 1728000000 920000 501 >,
+ < 1804800000 935000 529 >,
+ < 1881600000 950000 558 >,
+ < 1958400000 965000 588 >,
+ < 2035200000 980000 617 >,
+ < 2112000000 995000 649 >,
+ < 2150400000 1010000 682 >,
+ < 2188800000 1010000 682 >,
+ < 2265600000 1025000 716 >,
+ < 2342400000 1040000 751 >,
+ < 2419200000 1055000 786 >,
+ < 2457600000 1060000 802 >;
+
+ qcom,speed3-pvs7-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 780000 211 >,
+ < 883200000 790000 233 >,
+ < 960000000 800000 256 >,
+ < 1036800000 810000 278 >,
+ < 1113600000 820000 301 >,
+ < 1190400000 830000 324 >,
+ < 1267200000 840000 348 >,
+ < 1344000000 850000 372 >,
+ < 1420800000 860000 396 >,
+ < 1497600000 870000 421 >,
+ < 1574400000 880000 446 >,
+ < 1651200000 895000 473 >,
+ < 1728000000 910000 501 >,
+ < 1804800000 925000 529 >,
+ < 1881600000 940000 558 >,
+ < 1958400000 955000 588 >,
+ < 2035200000 970000 617 >,
+ < 2112000000 985000 649 >,
+ < 2150400000 1000000 682 >,
+ < 2188800000 1000000 682 >,
+ < 2265600000 1015000 716 >,
+ < 2342400000 1030000 751 >,
+ < 2419200000 1045000 786 >,
+ < 2457600000 1050000 802 >;
+
+ qcom,speed3-pvs8-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 780000 233 >,
+ < 960000000 790000 256 >,
+ < 1036800000 800000 278 >,
+ < 1113600000 810000 301 >,
+ < 1190400000 820000 324 >,
+ < 1267200000 830000 348 >,
+ < 1344000000 840000 372 >,
+ < 1420800000 850000 396 >,
+ < 1497600000 860000 421 >,
+ < 1574400000 870000 446 >,
+ < 1651200000 885000 473 >,
+ < 1728000000 900000 501 >,
+ < 1804800000 915000 529 >,
+ < 1881600000 930000 558 >,
+ < 1958400000 945000 588 >,
+ < 2035200000 960000 617 >,
+ < 2112000000 975000 649 >,
+ < 2150400000 990000 682 >,
+ < 2188800000 990000 682 >,
+ < 2265600000 1005000 716 >,
+ < 2342400000 1020000 751 >,
+ < 2419200000 1035000 786 >,
+ < 2457600000 1040000 802 >;
+
+ qcom,speed3-pvs9-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 775000 233 >,
+ < 960000000 780000 256 >,
+ < 1036800000 790000 278 >,
+ < 1113600000 800000 301 >,
+ < 1190400000 810000 324 >,
+ < 1267200000 820000 348 >,
+ < 1344000000 830000 372 >,
+ < 1420800000 840000 396 >,
+ < 1497600000 850000 421 >,
+ < 1574400000 860000 446 >,
+ < 1651200000 875000 473 >,
+ < 1728000000 890000 501 >,
+ < 1804800000 905000 529 >,
+ < 1881600000 920000 558 >,
+ < 1958400000 935000 588 >,
+ < 2035200000 950000 617 >,
+ < 2112000000 965000 649 >,
+ < 2150400000 980000 682 >,
+ < 2188800000 980000 682 >,
+ < 2265600000 995000 716 >,
+ < 2342400000 1010000 751 >,
+ < 2419200000 1025000 786 >,
+ < 2457600000 1030000 802 >;
+
+ qcom,speed3-pvs10-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 775000 233 >,
+ < 960000000 775000 256 >,
+ < 1036800000 780000 278 >,
+ < 1113600000 790000 301 >,
+ < 1190400000 800000 324 >,
+ < 1267200000 810000 348 >,
+ < 1344000000 820000 372 >,
+ < 1420800000 830000 396 >,
+ < 1497600000 840000 421 >,
+ < 1574400000 850000 446 >,
+ < 1651200000 865000 473 >,
+ < 1728000000 880000 501 >,
+ < 1804800000 895000 529 >,
+ < 1881600000 910000 558 >,
+ < 1958400000 925000 588 >,
+ < 2035200000 940000 617 >,
+ < 2112000000 955000 649 >,
+ < 2150400000 970000 682 >,
+ < 2188800000 970000 682 >,
+ < 2265600000 985000 716 >,
+ < 2342400000 1000000 751 >,
+ < 2419200000 1015000 786 >,
+ < 2457600000 1020000 802 >;
+
+ qcom,speed3-pvs11-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 775000 233 >,
+ < 960000000 775000 256 >,
+ < 1036800000 775000 278 >,
+ < 1113600000 780000 301 >,
+ < 1190400000 790000 324 >,
+ < 1267200000 800000 348 >,
+ < 1344000000 810000 372 >,
+ < 1420800000 820000 396 >,
+ < 1497600000 830000 421 >,
+ < 1574400000 840000 446 >,
+ < 1651200000 855000 473 >,
+ < 1728000000 870000 501 >,
+ < 1804800000 885000 529 >,
+ < 1881600000 900000 558 >,
+ < 1958400000 915000 588 >,
+ < 2035200000 930000 617 >,
+ < 2112000000 945000 649 >,
+ < 2150400000 960000 682 >,
+ < 2188800000 960000 682 >,
+ < 2265600000 975000 716 >,
+ < 2342400000 990000 751 >,
+ < 2419200000 1005000 786 >,
+ < 2457600000 1010000 802 >;
+
+ qcom,speed3-pvs12-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 775000 233 >,
+ < 960000000 775000 256 >,
+ < 1036800000 775000 278 >,
+ < 1113600000 775000 301 >,
+ < 1190400000 780000 324 >,
+ < 1267200000 790000 348 >,
+ < 1344000000 800000 372 >,
+ < 1420800000 810000 396 >,
+ < 1497600000 820000 421 >,
+ < 1574400000 830000 446 >,
+ < 1651200000 845000 473 >,
+ < 1728000000 860000 501 >,
+ < 1804800000 875000 529 >,
+ < 1881600000 890000 558 >,
+ < 1958400000 905000 588 >,
+ < 2035200000 920000 617 >,
+ < 2112000000 935000 649 >,
+ < 2150400000 950000 682 >,
+ < 2188800000 950000 682 >,
+ < 2265600000 965000 716 >,
+ < 2342400000 980000 751 >,
+ < 2419200000 995000 786 >,
+ < 2457600000 1000000 802 >;
+
+ qcom,speed3-pvs13-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 775000 76 >,
+ < 345600000 775000 87 >,
+ < 422400000 775000 106 >,
+ < 499200000 775000 126 >,
+ < 576000000 775000 147 >,
+ < 652800000 775000 168 >,
+ < 729600000 775000 189 >,
+ < 806400000 775000 211 >,
+ < 883200000 775000 233 >,
+ < 960000000 775000 256 >,
+ < 1036800000 775000 278 >,
+ < 1113600000 775000 301 >,
+ < 1190400000 775000 324 >,
+ < 1267200000 780000 348 >,
+ < 1344000000 790000 372 >,
+ < 1420800000 800000 396 >,
+ < 1497600000 810000 421 >,
+ < 1574400000 820000 446 >,
+ < 1651200000 835000 473 >,
+ < 1728000000 850000 501 >,
+ < 1804800000 865000 529 >,
+ < 1881600000 880000 558 >,
+ < 1958400000 895000 588 >,
+ < 2035200000 910000 617 >,
+ < 2112000000 925000 649 >,
+ < 2150400000 940000 682 >,
+ < 2188800000 940000 682 >,
+ < 2265600000 955000 716 >,
+ < 2342400000 970000 751 >,
+ < 2419200000 985000 786 >,
+ < 2457600000 990000 802 >;
+
+ qcom,speed3-pvs14-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 106 >,
+ < 499200000 750000 126 >,
+ < 576000000 750000 147 >,
+ < 652800000 750000 168 >,
+ < 729600000 750000 189 >,
+ < 806400000 750000 211 >,
+ < 883200000 750000 233 >,
+ < 960000000 750000 256 >,
+ < 1036800000 750000 278 >,
+ < 1113600000 750000 301 >,
+ < 1190400000 760000 324 >,
+ < 1267200000 770000 348 >,
+ < 1344000000 780000 372 >,
+ < 1420800000 790000 396 >,
+ < 1497600000 800000 421 >,
+ < 1574400000 810000 446 >,
+ < 1651200000 825000 473 >,
+ < 1728000000 840000 501 >,
+ < 1804800000 855000 529 >,
+ < 1881600000 870000 558 >,
+ < 1958400000 885000 588 >,
+ < 2035200000 900000 617 >,
+ < 2112000000 915000 649 >,
+ < 2150400000 930000 682 >,
+ < 2188800000 930000 682 >,
+ < 2265600000 945000 716 >,
+ < 2342400000 960000 751 >,
+ < 2419200000 975000 786 >,
+ < 2457600000 980000 802 >;
+
+ qcom,speed3-pvs15-bin-v1 =
+ < 0 0 0 >,
+ < 300000000 750000 76 >,
+ < 345600000 750000 87 >,
+ < 422400000 750000 106 >,
+ < 499200000 750000 126 >,
+ < 576000000 750000 147 >,
+ < 652800000 750000 168 >,
+ < 729600000 750000 189 >,
+ < 806400000 750000 211 >,
+ < 883200000 750000 233 >,
+ < 960000000 750000 256 >,
+ < 1036800000 750000 278 >,
+ < 1113600000 750000 301 >,
+ < 1190400000 750000 324 >,
+ < 1267200000 760000 348 >,
+ < 1344000000 770000 372 >,
+ < 1420800000 780000 396 >,
+ < 1497600000 790000 421 >,
+ < 1574400000 800000 446 >,
+ < 1651200000 815000 473 >,
+ < 1728000000 830000 501 >,
+ < 1804800000 845000 529 >,
+ < 1881600000 860000 558 >,
+ < 1958400000 875000 588 >,
+ < 2035200000 890000 617 >,
+ < 2112000000 905000 649 >,
+ < 2150400000 920000 682 >,
+ < 2188800000 920000 682 >,
+ < 2265600000 935000 716 >,
+ < 2342400000 950000 751 >,
+ < 2419200000 965000 786 >,
+ < 2457600000 970000 802 >;
+ };
+
+ qcom,msm-cpufreq@0 {
+ qcom,cpufreq-table =
+ < 300000 300000 600 /* 75 MHz */ >,
+ < 422400 422400 1200 /* 150 MHz */ >,
+ < 652800 499200 1600 /* 200 MHz */ >,
+ < 729600 576000 2456 /* 307 MHz */ >,
+ < 883200 576000 2456 /* 307 MHz */ >,
+ < 960000 960000 3680 /* 460 MHz */ >,
+ < 1036800 1036800 3680 /* 460 MHz */ >,
+ < 1190400 1036800 3680 /* 460 MHz */ >,
+ < 1267200 1267200 4912 /* 614 MHz */ >,
+ < 1497600 1497600 4912 /* 614 MHz */ >,
+ < 1574400 1574400 6400 /* 800 MHz */ >,
+ < 1728000 1651200 6400 /* 800 MHz */ >,
+ < 1958400 1728000 7448 /* 931 MHz */ >,
+ < 2265600 1728000 7448 /* 931 MHz */ >,
+ < 2457600 1728000 7448 /* 931 MHz */ >;
+ };
};
/* GPU overrides */
@@ -48,20 +1575,29 @@
qcom,initial-pwrlevel = <6>;
+ qcom,msm-bus,num-cases = <10>;
/* Updated bus bandwidth requirements */
qcom,msm-bus,vectors-KBps =
/* Off */
<26 512 0 0>, <89 604 0 0>,
/* SVS */
- <26 512 0 2400000>, <89 604 0 3000000>,
+ <26 512 0 2400000>, <89 604 0 3200000>,
/* Nominal / SVS */
- <26 512 0 4656000>, <89 604 0 3000000>,
- /* Nominal */
- <26 512 0 4656000>, <89 604 0 5120000>,
- /* Turbo / Nominal */
- <26 512 0 7464000>, <89 604 0 5120000>,
+ <26 512 0 3680000>, <89 604 0 3200000>,
+ /* Nominal / Nominal */
+ <26 512 0 3680000>, <89 604 0 5280000>,
+ /* Nominal / Nominal */
+ <26 512 0 4912000>, <89 604 0 5280000>,
+ /* Nominal / Turbo */
+ <26 512 0 4912000>, <89 604 0 6224000>,
+ /* Turbo / Turbo */
+ <26 512 0 7464000>, <89 604 0 6224000>,
+ /* Nominal / Turbo */
+ <26 512 0 4912000>, <89 604 0 7400000>,
/* Turbo */
- <26 512 0 7464000>, <89 604 0 6400000>;
+ <26 512 0 7464000>, <89 604 0 7400000>,
+ /* Turbo */
+ <26 512 0 7464000>, <89 604 0 9248000>;
qcom,gpu-pwrlevels {
#address-cells = <1>;
@@ -72,35 +1608,35 @@
qcom,gpu-pwrlevel@0 {
reg = <0>;
qcom,gpu-freq = <578000000>;
- qcom,bus-freq = <5>;
+ qcom,bus-freq = <9>;
qcom,io-fraction = <33>;
};
qcom,gpu-pwrlevel@1 {
reg = <1>;
qcom,gpu-freq = <462400000>;
- qcom,bus-freq = <4>;
+ qcom,bus-freq = <8>;
qcom,io-fraction = <33>;
};
qcom,gpu-pwrlevel@2 {
reg = <2>;
qcom,gpu-freq = <462400000>;
- qcom,bus-freq = <3>;
+ qcom,bus-freq = <7>;
qcom,io-fraction = <66>;
};
qcom,gpu-pwrlevel@3 {
reg = <3>;
qcom,gpu-freq = <389000000>;
- qcom,bus-freq = <4>;
+ qcom,bus-freq = <6>;
qcom,io-fraction = <66>;
};
qcom,gpu-pwrlevel@4 {
reg = <4>;
qcom,gpu-freq = <389000000>;
- qcom,bus-freq = <3>;
+ qcom,bus-freq = <5>;
qcom,io-fraction = <66>;
};
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 7c1af1a..cda1e59 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -90,6 +90,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 265234b..818e052 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -25,6 +25,7 @@
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_KPROBES=y
@@ -81,6 +82,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 55627a3..c1f2ca2 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -82,6 +82,7 @@
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 7ea1bd5..efdd8de 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -82,6 +82,7 @@
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
CONFIG_CC_STACKPROTECTOR=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -313,7 +314,6 @@
CONFIG_MSM_KGSL=y
CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
CONFIG_FB_MSM=y
# CONFIG_FB_MSM_BACKLIGHT is not set
CONFIG_FB_MSM_MDSS=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 8e6f5f9..c140a46 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -83,6 +83,7 @@
CONFIG_HIGHMEM=y
CONFIG_COMPACTION=y
CONFIG_CC_STACKPROTECTOR=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index e000e5e..edb73b4 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -440,12 +440,18 @@
*/
thumb = handler & 1;
+#if __LINUX_ARM_ARCH__ >= 7
+ /*
+ * Clear the If-Then Thumb-2 execution state
+ * ARM spec requires this to be all 000s in ARM mode
+ * Snapdragon S4/Krait misbehaves on a Thumb=>ARM
+ * signal transition without this.
+ */
+ cpsr &= ~PSR_IT_MASK;
+#endif
+
if (thumb) {
cpsr |= PSR_T_BIT;
-#if __LINUX_ARM_ARCH__ >= 7
- /* clear the If-Then Thumb-2 execution state */
- cpsr &= ~PSR_IT_MASK;
-#endif
} else
cpsr &= ~PSR_T_BIT;
}
diff --git a/arch/arm/lib/memset.S b/arch/arm/lib/memset.S
index 650d592..94b0650 100644
--- a/arch/arm/lib/memset.S
+++ b/arch/arm/lib/memset.S
@@ -14,27 +14,15 @@
.text
.align 5
- .word 0
-
-1: subs r2, r2, #4 @ 1 do we have enough
- blt 5f @ 1 bytes to align with?
- cmp r3, #2 @ 1
- strltb r1, [r0], #1 @ 1
- strleb r1, [r0], #1 @ 1
- strb r1, [r0], #1 @ 1
- add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
-/*
- * The pointer is now aligned and the length is adjusted. Try doing the
- * memset again.
- */
ENTRY(memset)
ands r3, r0, #3 @ 1 unaligned?
- bne 1b @ 1
+ mov ip, r0 @ preserve r0 as return value
+ bne 6f @ 1
/*
- * we know that the pointer in r0 is aligned to a word boundary.
+ * we know that the pointer in ip is aligned to a word boundary.
*/
- orr r1, r1, r1, lsl #8
+1: orr r1, r1, r1, lsl #8
orr r1, r1, r1, lsl #16
mov r3, r1
cmp r2, #16
@@ -43,29 +31,28 @@
#if ! CALGN(1)+0
/*
- * We need an extra register for this loop - save the return address and
- * use the LR
+ * We need 2 extra registers for this loop - use r8 and the LR
*/
- str lr, [sp, #-4]!
- mov ip, r1
+ stmfd sp!, {r8, lr}
+ mov r8, r1
mov lr, r1
2: subs r2, r2, #64
- stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
- stmgeia r0!, {r1, r3, ip, lr}
- stmgeia r0!, {r1, r3, ip, lr}
- stmgeia r0!, {r1, r3, ip, lr}
+ stmgeia ip!, {r1, r3, r8, lr} @ 64 bytes at a time.
+ stmgeia ip!, {r1, r3, r8, lr}
+ stmgeia ip!, {r1, r3, r8, lr}
+ stmgeia ip!, {r1, r3, r8, lr}
bgt 2b
- ldmeqfd sp!, {pc} @ Now <64 bytes to go.
+ ldmeqfd sp!, {r8, pc} @ Now <64 bytes to go.
/*
* No need to correct the count; we're only testing bits from now on
*/
tst r2, #32
- stmneia r0!, {r1, r3, ip, lr}
- stmneia r0!, {r1, r3, ip, lr}
+ stmneia ip!, {r1, r3, r8, lr}
+ stmneia ip!, {r1, r3, r8, lr}
tst r2, #16
- stmneia r0!, {r1, r3, ip, lr}
- ldr lr, [sp], #4
+ stmneia ip!, {r1, r3, r8, lr}
+ ldmfd sp!, {r8, lr}
#else
@@ -74,54 +61,63 @@
* whole cache lines at once.
*/
- stmfd sp!, {r4-r7, lr}
+ stmfd sp!, {r4-r8, lr}
mov r4, r1
mov r5, r1
mov r6, r1
mov r7, r1
- mov ip, r1
+ mov r8, r1
mov lr, r1
cmp r2, #96
- tstgt r0, #31
+ tstgt ip, #31
ble 3f
- and ip, r0, #31
- rsb ip, ip, #32
- sub r2, r2, ip
- movs ip, ip, lsl #(32 - 4)
- stmcsia r0!, {r4, r5, r6, r7}
- stmmiia r0!, {r4, r5}
- tst ip, #(1 << 30)
- mov ip, r1
- strne r1, [r0], #4
+ and r8, ip, #31
+ rsb r8, r8, #32
+ sub r2, r2, r8
+ movs r8, r8, lsl #(32 - 4)
+ stmcsia ip!, {r4, r5, r6, r7}
+ stmmiia ip!, {r4, r5}
+ tst r8, #(1 << 30)
+ mov r8, r1
+ strne r1, [ip], #4
3: subs r2, r2, #64
- stmgeia r0!, {r1, r3-r7, ip, lr}
- stmgeia r0!, {r1, r3-r7, ip, lr}
+ stmgeia ip!, {r1, r3-r8, lr}
+ stmgeia ip!, {r1, r3-r8, lr}
bgt 3b
- ldmeqfd sp!, {r4-r7, pc}
+ ldmeqfd sp!, {r4-r8, pc}
tst r2, #32
- stmneia r0!, {r1, r3-r7, ip, lr}
+ stmneia ip!, {r1, r3-r8, lr}
tst r2, #16
- stmneia r0!, {r4-r7}
- ldmfd sp!, {r4-r7, lr}
+ stmneia ip!, {r4-r7}
+ ldmfd sp!, {r4-r8, lr}
#endif
4: tst r2, #8
- stmneia r0!, {r1, r3}
+ stmneia ip!, {r1, r3}
tst r2, #4
- strne r1, [r0], #4
+ strne r1, [ip], #4
/*
* When we get here, we've got less than 4 bytes to zero. We
* may have an unaligned pointer as well.
*/
5: tst r2, #2
- strneb r1, [r0], #1
- strneb r1, [r0], #1
+ strneb r1, [ip], #1
+ strneb r1, [ip], #1
tst r2, #1
- strneb r1, [r0], #1
+ strneb r1, [ip], #1
mov pc, lr
+
+6: subs r2, r2, #4 @ 1 do we have enough
+ blt 5b @ 1 bytes to align with?
+ cmp r3, #2 @ 1
+ strltb r1, [ip], #1 @ 1
+ strleb r1, [ip], #1 @ 1
+ strb r1, [ip], #1 @ 1
+ add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3))
+ b 1b
ENDPROC(memset)
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 87c2f8c..a341c23 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -280,11 +280,11 @@
select MEMORY_HOLE_CARVEOUT
select MSM_RPM_STATS_LOG
select QMI_ENCDEC
- select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_ULTRASOUND_B
select MSM_RPM_LOG
select ARCH_WANT_KMAP_ATOMIC_FLUSH
select KRAIT_REGULATOR
+ select ENABLE_VMALLOC_SAVINGS
config ARCH_APQ8084
bool "APQ8084"
@@ -305,12 +305,12 @@
select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
select ARCH_WANT_KMAP_ATOMIC_FLUSH
select MEMORY_HOLE_CARVEOUT
- select DONT_MAP_HOLE_AFTER_MEMBANK0
select QMI_ENCDEC
select MSM_SPM_V2
select MSM_L2_SPM
select MSM_PM8X60 if PM
select MSM_RPM_SMD
+ select ENABLE_VMALLOC_SAVINGS
config ARCH_MPQ8092
bool "MPQ8092"
@@ -460,7 +460,6 @@
select MSM_L2_SPM
select MSM_PM8X60 if PM
select MEMORY_HOLE_CARVEOUT
- select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_BUS_SCALING
select CPU_FREQ_MSM
select CPU_FREQ
@@ -475,6 +474,7 @@
select MSM_RPM_LOG
select MSM_IOMMU_SYNC
select MSM_RPM_STATS_LOG
+ select ENABLE_VMALLOC_SAVINGS
config ARCH_MSM8226
bool "MSM8226"
@@ -500,7 +500,6 @@
select MSM_L2_SPM
select MSM_PM8X60 if PM
select MEMORY_HOLE_CARVEOUT
- select DONT_MAP_HOLE_AFTER_MEMBANK0
select MSM_BUS_SCALING
select CPU_FREQ_MSM
select CPU_FREQ
@@ -515,6 +514,7 @@
select MSM_RPM_LOG
select MSM_RPM_STATS_LOG
select ARCH_WANT_KMAP_ATOMIC_FLUSH
+ select ENABLE_VMALLOC_SAVINGS
config ARCH_MSMSAMARIUM
bool "MSMSAMARIUM"
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index c44dbc7..eacdcdf 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -161,7 +161,6 @@
obj-$(CONFIG_MSM_AUDIO_QDSP6V2) += qdsp6v2/
obj-$(CONFIG_MSM_HW3D) += hw3d.o
obj-$(CONFIG_PM) += pm-boot.o
-obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
obj-$(CONFIG_MSM_IDLE_STATS) += pm-stats.o
obj-$(CONFIG_MSM_PM2) += pm2.o
obj-$(CONFIG_MSM_NOPM) += no-pm.o
@@ -286,7 +285,7 @@
obj-$(CONFIG_ARCH_APQ8084) += board-8084.o board-8084-gpiomux.o
obj-$(CONFIG_ARCH_APQ8084) += clock-8084.o
obj-$(CONFIG_ARCH_MSM8974) += board-8974.o board-8974-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o
+obj-$(CONFIG_ARCH_MSM8974) += acpuclock-8974.o clock-krait-8974.o
obj-$(CONFIG_ARCH_MSM8974) += clock-local2.o clock-pll.o clock-8974.o clock-rpm.o clock-voter.o clock-mdss-8974.o
obj-$(CONFIG_ARCH_MSM8974) += gdsc.o
obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
@@ -311,6 +310,8 @@
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_PM8X60) += pm-8x60.o pm-data.o
+
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-mmc.o board-sapphire-wifi.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 552ed16..83c1d4c 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -99,28 +99,34 @@
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-sim.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-fluid.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-evt.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-dvt.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-evt.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-dvt.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8926-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8926-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd-skug.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-skuf.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-skuf.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-xpm.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-mtp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-xpm.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-sim.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-fluid.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-evt.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-dvt.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-720p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-1080p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-720p-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-1080p-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-evt.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-dvt.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-720p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-1080p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-720p-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-1080p-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8926-qrd-skug.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v1-qrd-skuf.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += msm8226-v2-qrd-skuf.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-xpm.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-xpm.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-720p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-1080p-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-720p-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8226) += apq8026-v2-1080p-mtp.dtb
# FSM9XXX
zreladdr-$(CONFIG_ARCH_FSM9XXX) := 0x10008000
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 60be20a..5117949 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -95,159 +95,7 @@
},
};
-static struct msm_bus_paths bw_level_tbl_v1[] __initdata = {
- [0] = BW_MBPS(600), /* At least 75 MHz on bus. */
- [1] = BW_MBPS(800), /* At least 100 MHz on bus. */
- [2] = BW_MBPS(1200), /* At least 150 MHz on bus. */
- [3] = BW_MBPS(1600), /* At least 200 MHz on bus. */
- [4] = BW_MBPS(2224), /* At least 278 MHz on bus. */
- [5] = BW_MBPS(3200), /* At least 400 MHz on bus. */
- [6] = BW_MBPS(4448), /* At least 556 MHz on bus. */
- [7] = BW_MBPS(6400), /* At least 800 MHz on bus. */
-};
-
-static struct l2_level l2_freq_tbl_v1[] __initdata = {
- [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 950000, 0 },
- [1] = { { 345600, HFPLL, 2, 36 }, LVL_NOM, 950000, 1 },
- [2] = { { 422400, HFPLL, 2, 44 }, LVL_NOM, 950000, 1 },
- [3] = { { 499200, HFPLL, 2, 52 }, LVL_NOM, 950000, 2 },
- [4] = { { 576000, HFPLL, 1, 30 }, LVL_NOM, 950000, 3 },
- [5] = { { 652800, HFPLL, 1, 34 }, LVL_NOM, 950000, 3 },
- [6] = { { 729600, HFPLL, 1, 38 }, LVL_NOM, 950000, 3 },
- [7] = { { 806400, HFPLL, 1, 42 }, LVL_HIGH, 1050000, 4 },
- [8] = { { 883200, HFPLL, 1, 46 }, LVL_HIGH, 1050000, 4 },
- [9] = { { 960000, HFPLL, 1, 50 }, LVL_HIGH, 1050000, 4 },
- [10] = { { 1036800, HFPLL, 1, 54 }, LVL_HIGH, 1050000, 5 },
- [11] = { { 1113600, HFPLL, 1, 58 }, LVL_HIGH, 1050000, 5 },
- [12] = { { 1190400, HFPLL, 1, 62 }, LVL_HIGH, 1050000, 6 },
- [13] = { { 1267200, HFPLL, 1, 66 }, LVL_HIGH, 1050000, 6 },
- [14] = { { 1344000, HFPLL, 1, 70 }, LVL_HIGH, 1050000, 7 },
- [15] = { { 1420800, HFPLL, 1, 74 }, LVL_HIGH, 1050000, 7 },
- [16] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 7 },
- { }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs0[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 835000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 845000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 860000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 880000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 905000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 920000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 940000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 960000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 980000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 995000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 1015000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 1030000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1050000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs1[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 835000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 845000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 860000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 880000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 905000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 920000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 940000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 960000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 980000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 995000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 1015000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 1030000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1050000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs2[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 825000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 825000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 835000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 855000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 875000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 895000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 915000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 930000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 945000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 960000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 975000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 990000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1000000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs3[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 825000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 825000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 835000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 855000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 875000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 895000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 915000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 930000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 945000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 960000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 975000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 990000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 1000000, 506 },
- { 0, { 0 } }
-};
-
-static struct acpu_level acpu_freq_tbl_v1_pvs4[] __initdata = {
- { 1, { 300000, PLL_0, 0, 0 }, L2(0), 825000, 73 },
- { 0, { 345600, HFPLL, 2, 36 }, L2(3), 825000, 85 },
- { 1, { 422400, HFPLL, 2, 44 }, L2(3), 825000, 104 },
- { 0, { 499200, HFPLL, 2, 52 }, L2(6), 825000, 124 },
- { 1, { 576000, HFPLL, 1, 30 }, L2(6), 825000, 144 },
- { 1, { 652800, HFPLL, 1, 34 }, L2(7), 825000, 165 },
- { 1, { 729600, HFPLL, 1, 38 }, L2(7), 825000, 186 },
- { 0, { 806400, HFPLL, 1, 42 }, L2(10), 825000, 208 },
- { 1, { 883200, HFPLL, 1, 46 }, L2(10), 825000, 229 },
- { 0, { 960000, HFPLL, 1, 50 }, L2(10), 825000, 252 },
- { 1, { 1036800, HFPLL, 1, 54 }, L2(10), 825000, 275 },
- { 0, { 1113600, HFPLL, 1, 58 }, L2(12), 835000, 298 },
- { 0, { 1190400, HFPLL, 1, 62 }, L2(12), 855000, 321 },
- { 0, { 1267200, HFPLL, 1, 66 }, L2(12), 870000, 346 },
- { 1, { 1344000, HFPLL, 1, 70 }, L2(12), 885000, 371 },
- { 0, { 1420800, HFPLL, 1, 74 }, L2(16), 900000, 397 },
- { 0, { 1497600, HFPLL, 1, 78 }, L2(16), 910000, 423 },
- { 0, { 1574400, HFPLL, 1, 82 }, L2(16), 925000, 450 },
- { 0, { 1651200, HFPLL, 1, 86 }, L2(16), 940000, 477 },
- { 1, { 1728000, HFPLL, 1, 90 }, L2(16), 950000, 506 },
- { 0, { 0 } }
-};
-
-static struct msm_bus_paths bw_level_tbl_v2[] __initdata = {
+static struct msm_bus_paths bw_level_tbl[] __initdata = {
[0] = BW_MBPS(600), /* At least 75 MHz on bus. */
[1] = BW_MBPS(800), /* At least 100 MHz on bus. */
[2] = BW_MBPS(1200), /* At least 150 MHz on bus. */
@@ -259,7 +107,7 @@
[8] = BW_MBPS(7448), /* At least 931 MHz on bus. */
};
-static struct l2_level l2_freq_tbl_v2[] __initdata = {
+static struct l2_level l2_freq_tbl[] __initdata = {
[0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 950000, 0 },
[1] = { { 345600, HFPLL, 2, 36 }, LVL_LOW, 950000, 1 },
[2] = { { 422400, HFPLL, 2, 44 }, LVL_LOW, 950000, 2 },
@@ -2440,15 +2288,6 @@
{ 0, { 0 } }
};
-static struct pvs_table pvs_v1[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
- /* 8974v1 1.7GHz Parts */
- [0][0][0] = { acpu_freq_tbl_v1_pvs0, sizeof(acpu_freq_tbl_v1_pvs0) },
- [0][0][1] = { acpu_freq_tbl_v1_pvs1, sizeof(acpu_freq_tbl_v1_pvs1) },
- [0][0][2] = { acpu_freq_tbl_v1_pvs2, sizeof(acpu_freq_tbl_v1_pvs2) },
- [0][0][3] = { acpu_freq_tbl_v1_pvs3, sizeof(acpu_freq_tbl_v1_pvs3) },
- [0][0][4] = { acpu_freq_tbl_v1_pvs4, sizeof(acpu_freq_tbl_v1_pvs4) },
-};
-
static struct pvs_table pvs_v2[NUM_PVS_REVS][NUM_SPEED_BINS][NUM_PVS] __initdata = {
/* 8974v2 2.0GHz Parts */
[0][0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
@@ -2560,8 +2399,8 @@
};
static struct msm_bus_scale_pdata bus_scale_data __initdata = {
- .usecase = bw_level_tbl_v2,
- .num_usecases = ARRAY_SIZE(bw_level_tbl_v2),
+ .usecase = bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(bw_level_tbl),
.active_only = 1,
.name = "acpuclk-8974",
};
@@ -2570,68 +2409,23 @@
.scalable = scalable,
.scalable_size = sizeof(scalable),
.hfpll_data = &hfpll_data,
- .pvs_tables = pvs_v2,
- .l2_freq_tbl = l2_freq_tbl_v2,
- .l2_freq_tbl_size = sizeof(l2_freq_tbl_v2),
+ .l2_freq_tbl = l2_freq_tbl,
+ .l2_freq_tbl_size = sizeof(l2_freq_tbl),
.bus_scale = &bus_scale_data,
.pte_efuse_phys = 0xFC4B80B0,
.get_bin_info = get_krait_bin_format_b,
.stby_khz = 300000,
};
-static void __init apply_pro_bringup_workaround(void)
-{
- acpuclk_8974_params.pvs_tables = pvs_pro;
-}
-
-static void __init apply_v1_l2_workaround(void)
-{
- static struct l2_level resticted_l2_tbl[] __initdata = {
- [0] = { { 300000, PLL_0, 0, 0 }, LVL_LOW, 1050000, 0 },
- [1] = { { 1497600, HFPLL, 1, 78 }, LVL_HIGH, 1050000, 7 },
- { }
- };
- struct acpu_level *l;
- int s, p, r;
-
- for (r = 0; r < NUM_PVS_REVS; r++)
- for (s = 0; s < NUM_SPEED_BINS; s++)
- for (p = 0; p < NUM_PVS; p++) {
- l = pvs_v1[r][s][p].table;
- for (; l && l->speed.khz; l++)
- l->l2_level = l->l2_level > 5 ? 1 : 0;
- }
-
- acpuclk_8974_params.l2_freq_tbl = resticted_l2_tbl;
- acpuclk_8974_params.l2_freq_tbl_size = sizeof(resticted_l2_tbl);
-}
-
#define cpu_is_msm8974pro() (cpu_is_msm8974pro_aa() || cpu_is_msm8974pro_ab() \
|| cpu_is_msm8974pro_ac())
static int __init acpuclk_8974_probe(struct platform_device *pdev)
{
- if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1
- && cpu_is_msm8974()) {
- acpuclk_8974_params.pvs_tables = pvs_v1;
- acpuclk_8974_params.l2_freq_tbl = l2_freq_tbl_v1;
- bus_scale_data.usecase = bw_level_tbl_v1;
- bus_scale_data.num_usecases = ARRAY_SIZE(bw_level_tbl_v1);
- acpuclk_8974_params.l2_freq_tbl_size = sizeof(l2_freq_tbl_v1);
-
- /*
- * 8974 hardware revisions older than v1.2 may experience L2
- * parity errors when running at some performance points between
- * 300MHz and 1497.6MHz (non-inclusive), or when vdd_mx is less
- * than 1.05V. Restrict L2 operation to safe performance points
- * on these devices.
- */
- if (SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2)
- apply_v1_l2_workaround();
- }
-
if (cpu_is_msm8974pro())
- apply_pro_bringup_workaround();
+ acpuclk_8974_params.pvs_tables = pvs_pro;
+ else
+ acpuclk_8974_params.pvs_tables = pvs_v2;
return acpuclk_krait_init(&pdev->dev, &acpuclk_8974_params);
}
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 4dcbc3a..9767746 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -185,7 +185,14 @@
static struct msm_gpiomux_config msm_lcd_configs[] __initdata = {
{
- .gpio = 25,
+ .gpio = 25, /* LCD Reset */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &lcd_rst_act_cfg,
+ [GPIOMUX_SUSPENDED] = &lcd_rst_sus_cfg,
+ },
+ },
+ {
+ .gpio = 109, /* LCD Enable */
.settings = {
[GPIOMUX_ACTIVE] = &lcd_rst_act_cfg,
[GPIOMUX_SUSPENDED] = &lcd_rst_sus_cfg,
@@ -303,13 +310,13 @@
static struct gpiomux_setting goodix_ldo_en_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_UP,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting goodix_int_act_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_6MA,
.pull = GPIOMUX_PULL_UP,
};
@@ -321,14 +328,14 @@
static struct gpiomux_setting goodix_reset_act_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
+ .drv = GPIOMUX_DRV_6MA,
.pull = GPIOMUX_PULL_UP,
};
static struct gpiomux_setting goodix_reset_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_8MA,
- .pull = GPIOMUX_PULL_UP,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
};
static struct msm_gpiomux_config msm_skuf_blsp_configs[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index aff2d75..5244918 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -82,6 +82,8 @@
"msm_sdcc.2", NULL),
OF_DEV_AUXDATA("qcom,sdhci-msm", 0xF9864900, \
"msm_sdcc.3", NULL),
+ OF_DEV_AUXDATA("qcom,hsic-host", 0xF9A00000, "msm_hsic_host", NULL),
+
{}
};
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 45a6b89..665c040 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -24,6 +24,7 @@
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
#include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
#include "clock-local2.h"
#include "clock-pll.h"
@@ -2018,111 +2019,111 @@
},
};
-static struct cam_mux_clk csi0phy_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(11),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(9),
- .sources = (struct mux_source[]) {
- { &csi0phy_clk.c, 0 },
- { &csi1phy_clk.c, BIT(9) },
- { 0 },
- },
+static struct mux_clk csi0phy_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(11),
+ .mask = 0x1,
+ .shift = 9,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0phy_clk.c, 0 },
+ { &csi1phy_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "csi0phy_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(csi0phy_cam_mux_clk.c),
},
};
-static struct cam_mux_clk csi1phy_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(10),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(8),
- .sources = (struct mux_source[]) {
- { &csi0phy_clk.c, 0 },
- { &csi1phy_clk.c, BIT(8) },
- { 0 },
- },
+static struct mux_clk csi1phy_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(10),
+ .mask = 0x1,
+ .shift = 8,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0phy_clk.c, 0 },
+ { &csi1phy_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "csi1phy_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(csi1phy_cam_mux_clk.c),
},
};
-static struct cam_mux_clk csi0pix_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(7),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(3),
- .sources = (struct mux_source[]) {
- { &csi0pix_clk.c, 0 },
- { &csi1pix_clk.c, BIT(3) },
- { 0 },
- },
+static struct mux_clk csi0pix_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(7),
+ .mask = 0x1,
+ .shift = 3,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0pix_clk.c, 0 },
+ { &csi1pix_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "csi0pix_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(csi0pix_cam_mux_clk.c),
},
};
-static struct cam_mux_clk rdi2_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(6),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(2),
- .sources = (struct mux_source[]) {
- { &csi0rdi_clk.c, 0 },
- { &csi1rdi_clk.c, BIT(2) },
- { 0 },
- },
+static struct mux_clk rdi2_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(6),
+ .mask = 0x1,
+ .shift = 2,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0rdi_clk.c, 0 },
+ { &csi1rdi_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "rdi2_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(rdi2_cam_mux_clk.c),
},
};
-static struct cam_mux_clk rdi1_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(5),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(1),
- .sources = (struct mux_source[]) {
- { &csi0rdi_clk.c, 0 },
- { &csi1rdi_clk.c, BIT(1) },
- { 0 },
- },
+static struct mux_clk rdi1_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(5),
+ .mask = 0x1,
+ .shift = 1,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0rdi_clk.c, 0 },
+ { &csi1rdi_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "rdi1_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(rdi1_cam_mux_clk.c),
},
};
-static struct cam_mux_clk rdi0_cam_mux_clk = {
- .enable_reg = MMSS_CAMSS_MISC,
- .enable_mask = BIT(4),
- .select_reg = MMSS_CAMSS_MISC,
- .select_mask = BIT(0),
- .sources = (struct mux_source[]) {
- { &csi0rdi_clk.c, 0 },
- { &csi1rdi_clk.c, BIT(0) },
- { 0 },
- },
+static struct mux_clk rdi0_cam_mux_clk = {
+ .ops = &mux_reg_ops,
+ .en_mask = BIT(4),
+ .mask = 0x1,
+ .shift = 0,
+ .offset = MMSS_CAMSS_MISC,
+ MUX_SRC_LIST(
+ { &csi0rdi_clk.c, 0 },
+ { &csi1rdi_clk.c, 1 },
+ ),
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "rdi0_cam_mux_clk",
- .ops = &clk_ops_cam_mux,
+ .ops = &clk_ops_gen_mux,
CLK_INIT(rdi0_cam_mux_clk.c),
},
};
@@ -3040,10 +3041,12 @@
"fda00c00.qcom,csiphy"),
CLK_LOOKUP("csiphy_timer_clk", csi0phytimer_clk.c,
"fda00c00.qcom,csiphy"),
+ CLK_LOOKUP("csi_ahb_clk", csi_ahb_clk.c, "fda00c00.qcom,csiphy"),
CLK_LOOKUP("csiphy_timer_src_clk", csi1phytimer_clk_src.c,
"fda01000.qcom,csiphy"),
CLK_LOOKUP("csiphy_timer_clk", csi1phytimer_clk.c,
"fda01000.qcom,csiphy"),
+ CLK_LOOKUP("csi_ahb_clk", csi_ahb_clk.c, "fda01000.qcom,csiphy"),
/* CSID clocks */
CLK_LOOKUP("csi_clk", csi0_clk.c, "fda00000.qcom,csid"),
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 03fcb25..9feb2f0 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -4953,8 +4953,10 @@
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("hfpll_src", cxo_a_clk_src.c, "f9016000.qcom,clock-krait"),
+ CLK_LOOKUP("aux_clk", gpll0_ao_clk_src.c,
+ "f9016000.qcom,clock-krait"),
CLK_LOOKUP("gpll0", gpll0_clk_src.c, ""),
- CLK_LOOKUP("gpll0_ao", gpll0_ao_clk_src.c, ""),
CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
index b0d32a0..c7d24a8 100644
--- a/arch/arm/mach-msm/clock-generic.c
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -14,20 +14,21 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/err.h>
-
#include <linux/clk.h>
+#include <linux/io.h>
+
#include <mach/clk-provider.h>
#include <mach/clock-generic.h>
/* ==================== Mux clock ==================== */
-static int parent_to_src_sel(struct mux_clk *mux, struct clk *p)
+int parent_to_src_sel(struct clk_src *parents, int num_parents, struct clk *p)
{
int i;
- for (i = 0; i < mux->num_parents; i++) {
- if (mux->parents[i].src == p)
- return mux->parents[i].sel;
+ for (i = 0; i < num_parents; i++) {
+ if (parents[i].src == p)
+ return parents[i].sel;
}
return -EINVAL;
@@ -36,11 +37,26 @@
static int mux_set_parent(struct clk *c, struct clk *p)
{
struct mux_clk *mux = to_mux_clk(c);
- int sel = parent_to_src_sel(mux, p);
+ int sel = parent_to_src_sel(mux->parents, mux->num_parents, p);
struct clk *old_parent;
- int rc = 0;
+ int rc = 0, i;
unsigned long flags;
+ if (sel < 0 && mux->rec_set_par) {
+ for (i = 0; i < mux->num_parents; i++) {
+ rc = clk_set_parent(mux->parents[i].src, p);
+ if (!rc) {
+ sel = mux->parents[i].sel;
+ /*
+ * This is necessary to ensure prepare/enable
+ * counts get propagated correctly.
+ */
+ p = mux->parents[i].src;
+ break;
+ }
+ }
+ }
+
if (sel < 0)
return sel;
@@ -54,6 +70,7 @@
old_parent = c->parent;
c->parent = p;
+ c->rate = clk_get_rate(p);
__clk_post_reparent(c, old_parent, &flags);
return 0;
@@ -68,23 +85,17 @@
{
struct mux_clk *mux = to_mux_clk(c);
int i;
- unsigned long prate, max_prate = 0, rrate = ULONG_MAX;
+ unsigned long prate, rrate = 0;
for (i = 0; i < mux->num_parents; i++) {
prate = clk_round_rate(mux->parents[i].src, rate);
- if (IS_ERR_VALUE(prate))
- continue;
- if (prate < rate) {
- max_prate = max(prate, max_prate);
- continue;
- }
-
- rrate = min(rrate, prate);
+ if (is_better_rate(rate, rrate, prate))
+ rrate = prate;
}
- if (rrate == ULONG_MAX)
- rrate = max_prate;
+ if (!rrate)
+ return -EINVAL;
- return rrate ? rrate : -EINVAL;
+ return rrate;
}
static int mux_set_rate(struct clk *c, unsigned long rate)
@@ -136,7 +147,8 @@
set_par_fail:
clk_set_rate(new_parent, new_par_curr_rate);
set_rate_fail:
- WARN(mux->ops->set_mux_sel(mux, parent_to_src_sel(mux, c->parent)),
+ WARN(mux->ops->set_mux_sel(mux,
+ parent_to_src_sel(mux->parents, mux->num_parents, c->parent)),
"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
return rc;
}
@@ -176,7 +188,8 @@
struct mux_clk *mux = to_mux_clk(c);
c->rate = clk_get_rate(c->parent);
- mux->safe_sel = parent_to_src_sel(mux, mux->safe_parent);
+ mux->safe_sel = parent_to_src_sel(mux->parents, mux->num_parents,
+ mux->safe_parent);
if (mux->en_mask && mux->ops && mux->ops->is_enabled)
return mux->ops->is_enabled(mux)
@@ -205,30 +218,30 @@
.get_parent = mux_get_parent,
};
-
/* ==================== Divider clock ==================== */
-static long __div_round_rate(struct clk *c, unsigned long rate, int *best_div)
+static long __div_round_rate(struct div_data *data, unsigned long rate,
+ struct clk *parent, unsigned int *best_div, unsigned long *best_prate)
{
- struct div_clk *d = to_div_clk(c);
- unsigned int div, min_div, max_div;
- unsigned long p_rrate, rrate = ULONG_MAX;
+ unsigned int div, min_div, max_div, _best_div = 1;
+ unsigned long prate, _best_prate = 0, rrate = 0;
rate = max(rate, 1UL);
- if (!d->ops || !d->ops->set_div)
- min_div = max_div = d->div;
- else {
- min_div = max(d->min_div, 1U);
- max_div = min(d->max_div, (unsigned int) (ULONG_MAX / rate));
- }
+ min_div = max(data->min_div, 1U);
+ max_div = min(data->max_div, (unsigned int) (ULONG_MAX / rate));
for (div = min_div; div <= max_div; div++) {
- p_rrate = clk_round_rate(c->parent, rate * div);
- if (IS_ERR_VALUE(p_rrate))
+ prate = clk_round_rate(parent, rate * div);
+ if (IS_ERR_VALUE(prate))
break;
- p_rrate /= div;
+ if (is_better_rate(rate, rrate, prate / div)) {
+ rrate = prate / div;
+ _best_div = div;
+ _best_prate = prate;
+ }
+
/*
* Trying higher dividers is only going to ask the parent for
* a higher rate. If it can't even output a rate higher than
@@ -236,42 +249,38 @@
* going to be able to output an even higher rate required
* for a higher divider. So, stop trying higher dividers.
*/
- if (p_rrate < rate) {
- if (rrate == ULONG_MAX) {
- rrate = p_rrate;
- if (best_div)
- *best_div = div;
- }
+ if (prate / div < rate)
break;
- }
- if (p_rrate < rrate) {
- rrate = p_rrate;
- if (best_div)
- *best_div = div;
- }
- if (rrate <= rate + d->rate_margin)
+ if (rrate <= rate + data->rate_margin)
break;
}
- if (rrate == ULONG_MAX)
+ if (!rrate)
return -EINVAL;
+ if (best_div)
+ *best_div = _best_div;
+ if (best_prate)
+ *best_prate = _best_prate;
return rrate;
}
static long div_round_rate(struct clk *c, unsigned long rate)
{
- return __div_round_rate(c, rate, NULL);
+ struct div_clk *d = to_div_clk(c);
+
+ return __div_round_rate(&d->data, rate, c->parent, NULL, NULL);
}
static int div_set_rate(struct clk *c, unsigned long rate)
{
struct div_clk *d = to_div_clk(c);
int div, rc = 0;
- long rrate, old_prate;
+ long rrate, old_prate, new_prate;
+ struct div_data *data = &d->data;
- rrate = __div_round_rate(c, rate, &div);
+ rrate = __div_round_rate(data, rate, c->parent, &div, &new_prate);
if (rrate != rate)
return -EINVAL;
@@ -281,22 +290,22 @@
* !d->ops and return an error. __div_round_rate() ensures div ==
* d->div if !d->ops.
*/
- if (div > d->div)
+ if (div > data->div)
rc = d->ops->set_div(d, div);
if (rc)
return rc;
old_prate = clk_get_rate(c->parent);
- rc = clk_set_rate(c->parent, rate * div);
+ rc = clk_set_rate(c->parent, new_prate);
if (rc)
goto set_rate_fail;
- if (div < d->div)
+ if (div < data->div)
rc = d->ops->set_div(d, div);
if (rc)
goto div_dec_fail;
- d->div = div;
+ data->div = div;
return 0;
@@ -304,8 +313,8 @@
WARN(clk_set_rate(c->parent, old_prate),
"Set rate failed for %s. Also in bad state!\n", c->dbg_name);
set_rate_fail:
- if (div > d->div)
- WARN(d->ops->set_div(d, d->div),
+ if (div > data->div)
+ WARN(d->ops->set_div(d, data->div),
"Set rate failed for %s. Also in bad state!\n",
c->dbg_name);
return rc;
@@ -329,11 +338,16 @@
static enum handoff div_handoff(struct clk *c)
{
struct div_clk *d = to_div_clk(c);
+ unsigned int div = d->data.div;
if (d->ops && d->ops->get_div)
- d->div = max(d->ops->get_div(d), 1);
- d->div = max(d->div, 1U);
- c->rate = clk_get_rate(c->parent) / d->div;
+ div = max(d->ops->get_div(d), 1);
+ div = max(div, 1U);
+ c->rate = clk_get_rate(c->parent) / div;
+
+ if (!d->ops || !d->ops->set_div)
+ d->data.min_div = d->data.max_div = div;
+ d->data.div = div;
if (d->en_mask && d->ops && d->ops->is_enabled)
return d->ops->is_enabled(d)
@@ -369,12 +383,8 @@
rate = max(rate, 1UL);
- if (!d->ops || !d->ops->set_div)
- min_div = max_div = d->div;
- else {
- min_div = d->min_div;
- max_div = d->max_div;
- }
+ min_div = d->data.min_div;
+ max_div = d->data.max_div;
p_rate = clk_get_rate(c->parent);
div = p_rate / rate;
@@ -401,28 +411,320 @@
if (rrate != rate)
return -EINVAL;
- if (div == d->div)
+ if (div == d->data.div)
return 0;
/*
* For fixed divider clock we don't want to return an error if the
* requested rate matches the achievable rate. So, don't check for
* !d->ops and return an error. __slave_div_round_rate() ensures
- * div == d->div if !d->ops.
+ * div == d->data.div if !d->ops.
*/
rc = d->ops->set_div(d, div);
if (rc)
return rc;
- d->div = div;
+ d->data.div = div;
return 0;
}
+static unsigned long slave_div_get_rate(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+ if (!d->data.div)
+ return 0;
+ return clk_get_rate(c->parent) / d->data.div;
+}
+
struct clk_ops clk_ops_slave_div = {
.enable = div_enable,
.disable = div_disable,
.round_rate = slave_div_round_rate,
.set_rate = slave_div_set_rate,
+ .get_rate = slave_div_get_rate,
.handoff = div_handoff,
};
+
+
+/**
+ * External clock
+ * Some clock controllers have input clock signal that come from outside the
+ * clock controller. That input clock signal might then be used as a source for
+ * several clocks inside the clock controller. This external clock
+ * implementation models this input clock signal by just passing on the requests
+ * to the clock's parent, the original external clock source. The driver for the
+ * clock controller should clk_get() the original external clock in the probe
+ * function and set is as a parent to this external clock..
+ */
+
+static long ext_round_rate(struct clk *c, unsigned long rate)
+{
+ return clk_round_rate(c->parent, rate);
+}
+
+static int ext_set_rate(struct clk *c, unsigned long rate)
+{
+ return clk_set_rate(c->parent, rate);
+}
+
+static unsigned long ext_get_rate(struct clk *c)
+{
+ return clk_get_rate(c->parent);
+}
+
+static int ext_set_parent(struct clk *c, struct clk *p)
+{
+ return clk_set_parent(c->parent, p);
+}
+
+static enum handoff ext_handoff(struct clk *c)
+{
+ c->rate = clk_get_rate(c->parent);
+ /* Similar reasoning applied in div_handoff, see comment there. */
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_ext = {
+ .handoff = ext_handoff,
+ .round_rate = ext_round_rate,
+ .set_rate = ext_set_rate,
+ .get_rate = ext_get_rate,
+ .set_parent = ext_set_parent,
+};
+
+
+/* ==================== Mux_div clock ==================== */
+
+static int mux_div_clk_enable(struct clk *c)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+
+ if (md->ops->enable)
+ return md->ops->enable(md);
+ return 0;
+}
+
+static void mux_div_clk_disable(struct clk *c)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+
+ if (md->ops->disable)
+ return md->ops->disable(md);
+}
+
+static long __mux_div_round_rate(struct clk *c, unsigned long rate,
+ struct clk **best_parent, int *best_div, unsigned long *best_prate)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+ unsigned int i;
+ unsigned long rrate, best = 0, _best_div = 0, _best_prate = 0;
+ struct clk *_best_parent = 0;
+
+ for (i = 0; i < md->num_parents; i++) {
+ int div;
+ unsigned long prate;
+
+ rrate = __div_round_rate(&md->data, rate, md->parents[i].src,
+ &div, &prate);
+
+ if (is_better_rate(rate, best, rrate)) {
+ best = rrate;
+ _best_div = div;
+ _best_prate = prate;
+ _best_parent = md->parents[i].src;
+ }
+
+ if (rate <= rrate && rrate <= rate + md->data.rate_margin)
+ break;
+ }
+
+ if (best_div)
+ *best_div = _best_div;
+ if (best_prate)
+ *best_prate = _best_prate;
+ if (best_parent)
+ *best_parent = _best_parent;
+
+ if (best)
+ return best;
+ return -EINVAL;
+}
+
+static long mux_div_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ return __mux_div_round_rate(c, rate, NULL, NULL, NULL);
+}
+
+/* requires enable lock to be held */
+static int __set_src_div(struct mux_div_clk *md, struct clk *parent, u32 div)
+{
+ u32 rc = 0, src_sel;
+
+ src_sel = parent_to_src_sel(md->parents, md->num_parents, parent);
+ /*
+ * If the clock is disabled, don't change to the new settings until
+ * the clock is reenabled
+ */
+ if (md->c.count)
+ rc = md->ops->set_src_div(md, src_sel, div);
+ if (!rc) {
+ md->data.div = div;
+ md->src_sel = src_sel;
+ }
+
+ return rc;
+}
+
+static int set_src_div(struct mux_div_clk *md, struct clk *parent, u32 div)
+{
+ unsigned long flags;
+ u32 rc;
+
+ spin_lock_irqsave(&md->c.lock, flags);
+ rc = __set_src_div(md, parent, div);
+ spin_unlock_irqrestore(&md->c.lock, flags);
+
+ return rc;
+}
+
+/* Must be called after handoff to ensure parent clock rates are initialized */
+static int safe_parent_init_once(struct clk *c)
+{
+ unsigned long rrate;
+ u32 best_div;
+ struct clk *best_parent;
+ struct mux_div_clk *md = to_mux_div_clk(c);
+
+ if (IS_ERR(md->safe_parent))
+ return -EINVAL;
+ if (!md->safe_freq || md->safe_parent)
+ return 0;
+
+ rrate = __mux_div_round_rate(c, md->safe_freq, &best_parent,
+ &best_div, NULL);
+
+ if (rrate == md->safe_freq) {
+ md->safe_div = best_div;
+ md->safe_parent = best_parent;
+ } else {
+ md->safe_parent = ERR_PTR(-EINVAL);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int mux_div_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+ unsigned long flags, rrate;
+ unsigned long new_prate, old_prate;
+ struct clk *old_parent, *new_parent;
+ u32 new_div, old_div;
+ int rc;
+
+ rc = safe_parent_init_once(c);
+ if (rc)
+ return rc;
+
+ rrate = __mux_div_round_rate(c, rate, &new_parent, &new_div,
+ &new_prate);
+ if (rrate != rate)
+ return -EINVAL;
+
+ old_parent = c->parent;
+ old_div = md->data.div;
+ old_prate = clk_get_rate(c->parent);
+
+ /* Refer to the description of safe_freq in clock-generic.h */
+ if (md->safe_freq)
+ rc = set_src_div(md, md->safe_parent, md->safe_div);
+
+ else if (new_parent == old_parent && new_div >= old_div) {
+ /*
+ * If both the parent_rate and divider changes, there may be an
+ * intermediate frequency generated. Ensure this intermediate
+ * frequency is less than both the new rate and previous rate.
+ */
+ rc = set_src_div(md, old_parent, new_div);
+ }
+ if (rc)
+ return rc;
+
+ rc = clk_set_rate(new_parent, new_prate);
+ if (rc) {
+ pr_err("failed to set %s to %ld\n",
+ new_parent->dbg_name, new_prate);
+ goto err_set_rate;
+ }
+
+ rc = __clk_pre_reparent(c, new_parent, &flags);
+ if (rc)
+ goto err_pre_reparent;
+
+ /* Set divider and mux src atomically */
+ rc = __set_src_div(md, new_parent, new_div);
+ if (rc)
+ goto err_set_src_div;
+
+ c->parent = new_parent;
+
+ __clk_post_reparent(c, old_parent, &flags);
+ return 0;
+
+err_set_src_div:
+ /* Not switching to new_parent, so disable it */
+ __clk_post_reparent(c, new_parent, &flags);
+err_pre_reparent:
+ rc = clk_set_rate(old_parent, old_prate);
+ WARN(rc, "%s: error changing parent (%s) rate to %ld\n",
+ c->dbg_name, old_parent->dbg_name, old_prate);
+err_set_rate:
+ rc = set_src_div(md, old_parent, old_div);
+ WARN(rc, "%s: error changing back to original div (%d) and parent (%s)\n",
+ c->dbg_name, old_div, old_parent->dbg_name);
+
+ return rc;
+}
+
+static struct clk *mux_div_clk_get_parent(struct clk *c)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+ u32 i, div, src_sel;
+
+ md->ops->get_src_div(md, &src_sel, &div);
+
+ md->data.div = div;
+ md->src_sel = src_sel;
+
+ for (i = 0; i < md->num_parents; i++) {
+ if (md->parents[i].sel == src_sel)
+ return md->parents[i].src;
+ }
+
+ return NULL;
+}
+
+static enum handoff mux_div_clk_handoff(struct clk *c)
+{
+ struct mux_div_clk *md = to_mux_div_clk(c);
+ unsigned long parent_rate;
+
+ parent_rate = clk_get_rate(c->parent);
+ c->rate = parent_rate / md->data.div;
+
+ if (!md->ops->is_enabled)
+ return HANDOFF_DISABLED_CLK;
+ if (md->ops->is_enabled(md))
+ return HANDOFF_ENABLED_CLK;
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_mux_div_clk = {
+ .enable = mux_div_clk_enable,
+ .disable = mux_div_clk_disable,
+ .set_rate = mux_div_clk_set_rate,
+ .round_rate = mux_div_clk_round_rate,
+ .get_parent = mux_div_clk_get_parent,
+ .handoff = mux_div_clk_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-krait-8974.c b/arch/arm/mach-msm/clock-krait-8974.c
new file mode 100644
index 0000000..6ada01f
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krait-8974.c
@@ -0,0 +1,806 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/cpumask.h>
+
+#include <asm/cputype.h>
+
+#include <mach/rpm-regulator-smd.h>
+#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
+#include <mach/clk.h>
+#include "clock-krait.h"
+#include "clock.h"
+
+/* Clock inputs coming into Krait subsystem */
+DEFINE_FIXED_DIV_CLK(hfpll_src_clk, 1, NULL);
+DEFINE_FIXED_DIV_CLK(acpu_aux_clk, 2, NULL);
+
+static int hfpll_uv[] = {
+ RPM_REGULATOR_CORNER_NONE, 0,
+ RPM_REGULATOR_CORNER_SVS_SOC, 1800000,
+ RPM_REGULATOR_CORNER_NORMAL, 1800000,
+ RPM_REGULATOR_CORNER_SUPER_TURBO, 1800000,
+};
+static DEFINE_VDD_REGULATORS(vdd_hfpll, ARRAY_SIZE(hfpll_uv)/2, 2,
+ hfpll_uv, NULL);
+
+static unsigned long hfpll_fmax[] = { 0, 998400000, 1996800000, 2900000000UL };
+
+static struct hfpll_data hdata = {
+ .mode_offset = 0x0,
+ .l_offset = 0x4,
+ .m_offset = 0x8,
+ .n_offset = 0xC,
+ .user_offset = 0x10,
+ .config_offset = 0x14,
+ .status_offset = 0x1C,
+
+ .user_val = 0x8,
+ .low_vco_max_rate = 1248000000,
+ .min_rate = 537600000UL,
+ .max_rate = 2900000000UL,
+};
+
+static struct hfpll_clk hfpll0_clk = {
+ .d = &hdata,
+ .src_rate = 19200000,
+ .c = {
+ .parent = &hfpll_src_clk.c,
+ .dbg_name = "hfpll0_clk",
+ .ops = &clk_ops_hfpll,
+ .vdd_class = &vdd_hfpll,
+ .fmax = hfpll_fmax,
+ .num_fmax = ARRAY_SIZE(hfpll_fmax),
+ CLK_INIT(hfpll0_clk.c),
+ },
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll0_div_clk, &hfpll0_clk.c, 0x4501, true);
+
+static struct hfpll_clk hfpll1_clk = {
+ .d = &hdata,
+ .src_rate = 19200000,
+ .c = {
+ .parent = &hfpll_src_clk.c,
+ .dbg_name = "hfpll1_clk",
+ .ops = &clk_ops_hfpll,
+ .vdd_class = &vdd_hfpll,
+ .fmax = hfpll_fmax,
+ .num_fmax = ARRAY_SIZE(hfpll_fmax),
+ CLK_INIT(hfpll1_clk.c),
+ },
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll1_div_clk, &hfpll1_clk.c, 0x5501, true);
+
+static struct hfpll_clk hfpll2_clk = {
+ .d = &hdata,
+ .src_rate = 19200000,
+ .c = {
+ .parent = &hfpll_src_clk.c,
+ .dbg_name = "hfpll2_clk",
+ .ops = &clk_ops_hfpll,
+ .vdd_class = &vdd_hfpll,
+ .fmax = hfpll_fmax,
+ .num_fmax = ARRAY_SIZE(hfpll_fmax),
+ CLK_INIT(hfpll2_clk.c),
+ },
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll2_div_clk, &hfpll2_clk.c, 0x6501, true);
+
+static struct hfpll_clk hfpll3_clk = {
+ .d = &hdata,
+ .src_rate = 19200000,
+ .c = {
+ .parent = &hfpll_src_clk.c,
+ .dbg_name = "hfpll3_clk",
+ .ops = &clk_ops_hfpll,
+ .vdd_class = &vdd_hfpll,
+ .fmax = hfpll_fmax,
+ .num_fmax = ARRAY_SIZE(hfpll_fmax),
+ CLK_INIT(hfpll3_clk.c),
+ },
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll3_div_clk, &hfpll3_clk.c, 0x7501, true);
+
+static struct hfpll_clk hfpll_l2_clk = {
+ .d = &hdata,
+ .src_rate = 19200000,
+ .c = {
+ .parent = &hfpll_src_clk.c,
+ .dbg_name = "hfpll_l2_clk",
+ .ops = &clk_ops_hfpll,
+ .vdd_class = &vdd_hfpll,
+ .fmax = hfpll_fmax,
+ .num_fmax = ARRAY_SIZE(hfpll_fmax),
+ CLK_INIT(hfpll_l2_clk.c),
+ },
+};
+
+DEFINE_KPSS_DIV2_CLK(hfpll_l2_div_clk, &hfpll_l2_clk.c, 0x500, false);
+
+#define SEC_MUX_COMMON_DATA \
+ .safe_parent = &acpu_aux_clk.c, \
+ .ops = &clk_mux_ops_kpss, \
+ .mask = 0x3, \
+ .shift = 2, \
+ MUX_SRC_LIST( \
+ {&acpu_aux_clk.c, 2}, \
+ {NULL /* QSB */, 0}, \
+ )
+
+static struct mux_clk krait0_sec_mux_clk = {
+ .offset = 0x4501,
+ .priv = (void *) true,
+ SEC_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait0_sec_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait0_sec_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait1_sec_mux_clk = {
+ .offset = 0x5501,
+ .priv = (void *) true,
+ SEC_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait1_sec_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait1_sec_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait2_sec_mux_clk = {
+ .offset = 0x6501,
+ .priv = (void *) true,
+ SEC_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait2_sec_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait2_sec_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait3_sec_mux_clk = {
+ .offset = 0x7501,
+ .priv = (void *) true,
+ SEC_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait3_sec_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait3_sec_mux_clk.c),
+ },
+};
+
+static struct mux_clk l2_sec_mux_clk = {
+ .offset = 0x500,
+ SEC_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "l2_sec_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(l2_sec_mux_clk.c),
+ },
+};
+
+#define PRI_MUX_COMMON_DATA \
+ .ops = &clk_mux_ops_kpss, \
+ .mask = 0x3, \
+ .shift = 0
+
+static struct mux_clk krait0_pri_mux_clk = {
+ .offset = 0x4501,
+ .priv = (void *) true,
+ MUX_SRC_LIST(
+ { &hfpll0_clk.c, 1 },
+ { &hfpll0_div_clk.c, 2 },
+ { &krait0_sec_mux_clk.c, 0 },
+ ),
+ .safe_parent = &krait0_sec_mux_clk.c,
+ PRI_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait0_pri_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait0_pri_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait1_pri_mux_clk = {
+ .offset = 0x5501,
+ .priv = (void *) true,
+ MUX_SRC_LIST(
+ { &hfpll1_clk.c, 1 },
+ { &hfpll1_div_clk.c, 2 },
+ { &krait1_sec_mux_clk.c, 0 },
+ ),
+ .safe_parent = &krait1_sec_mux_clk.c,
+ PRI_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait1_pri_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait1_pri_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait2_pri_mux_clk = {
+ .offset = 0x6501,
+ .priv = (void *) true,
+ MUX_SRC_LIST(
+ { &hfpll2_clk.c, 1 },
+ { &hfpll2_div_clk.c, 2 },
+ { &krait2_sec_mux_clk.c, 0 },
+ ),
+ .safe_parent = &krait2_sec_mux_clk.c,
+ PRI_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait2_pri_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait2_pri_mux_clk.c),
+ },
+};
+
+static struct mux_clk krait3_pri_mux_clk = {
+ .offset = 0x7501,
+ .priv = (void *) true,
+ MUX_SRC_LIST(
+ { &hfpll3_clk.c, 1 },
+ { &hfpll3_div_clk.c, 2 },
+ { &krait3_sec_mux_clk.c, 0 },
+ ),
+ .safe_parent = &krait3_sec_mux_clk.c,
+ PRI_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "krait3_pri_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(krait3_pri_mux_clk.c),
+ },
+};
+
+static struct mux_clk l2_pri_mux_clk = {
+ .offset = 0x500,
+ MUX_SRC_LIST(
+ {&hfpll_l2_clk.c, 1 },
+ {&hfpll_l2_div_clk.c, 2},
+ {&l2_sec_mux_clk.c, 0}
+ ),
+ .safe_parent = &l2_sec_mux_clk.c,
+ PRI_MUX_COMMON_DATA,
+ .c = {
+ .dbg_name = "l2_pri_mux_clk",
+ .ops = &clk_ops_gen_mux,
+ CLK_INIT(l2_pri_mux_clk.c),
+ },
+};
+
+static struct avs_data avs_table;
+
+static DEFINE_VDD_REGS_INIT(vdd_krait0, 1);
+static DEFINE_VDD_REGS_INIT(vdd_krait1, 1);
+static DEFINE_VDD_REGS_INIT(vdd_krait2, 1);
+static DEFINE_VDD_REGS_INIT(vdd_krait3, 1);
+static DEFINE_VDD_REGS_INIT(vdd_l2, 1);
+
+/*
+ * This clock is mostly a dummy clock in the sense it can't really gate the
+ * CPU/L2 clocks or affect their frequency. It exists solely to:
+ *
+ * - Capture the PVS requirements for each CPU.
+ * - Implement HW clock gating disable ops needed for measuring the freq of
+ * Krait/L2 properly.
+ * - Implement AVS requirement.
+ */
+static struct kpss_core_clk krait0_clk = {
+ .id = 0,
+ .avs_tbl = &avs_table,
+ .c = {
+ .parent = &krait0_pri_mux_clk.c,
+ .dbg_name = "krait0_clk",
+ .ops = &clk_ops_kpss_cpu,
+ .vdd_class = &vdd_krait0,
+ CLK_INIT(krait0_clk.c),
+ },
+};
+
+static struct kpss_core_clk krait1_clk = {
+ .id = 1,
+ .avs_tbl = &avs_table,
+ .c = {
+ .parent = &krait1_pri_mux_clk.c,
+ .dbg_name = "krait1_clk",
+ .ops = &clk_ops_kpss_cpu,
+ .vdd_class = &vdd_krait1,
+ CLK_INIT(krait1_clk.c),
+ },
+};
+
+static struct kpss_core_clk krait2_clk = {
+ .id = 2,
+ .avs_tbl = &avs_table,
+ .c = {
+ .parent = &krait2_pri_mux_clk.c,
+ .dbg_name = "krait2_clk",
+ .ops = &clk_ops_kpss_cpu,
+ .vdd_class = &vdd_krait2,
+ CLK_INIT(krait2_clk.c),
+ },
+};
+
+static struct kpss_core_clk krait3_clk = {
+ .id = 3,
+ .avs_tbl = &avs_table,
+ .c = {
+ .parent = &krait3_pri_mux_clk.c,
+ .dbg_name = "krait3_clk",
+ .ops = &clk_ops_kpss_cpu,
+ .vdd_class = &vdd_krait3,
+ CLK_INIT(krait3_clk.c),
+ },
+};
+
+static struct kpss_core_clk l2_clk = {
+ .cp15_iaddr = 0x0500,
+ .c = {
+ .parent = &l2_pri_mux_clk.c,
+ .dbg_name = "l2_clk",
+ .ops = &clk_ops_kpss_l2,
+ .vdd_class = &vdd_l2,
+ CLK_INIT(l2_clk.c),
+ },
+};
+
+static struct clk_lookup kpss_clocks_8974[] = {
+ CLK_LOOKUP("", hfpll_src_clk.c, ""),
+ CLK_LOOKUP("", acpu_aux_clk.c, ""),
+ CLK_LOOKUP("", hfpll0_clk.c, ""),
+ CLK_LOOKUP("", hfpll0_div_clk.c, ""),
+ CLK_LOOKUP("", hfpll0_clk.c, ""),
+ CLK_LOOKUP("", hfpll1_div_clk.c, ""),
+ CLK_LOOKUP("", hfpll1_clk.c, ""),
+ CLK_LOOKUP("", hfpll2_div_clk.c, ""),
+ CLK_LOOKUP("", hfpll2_clk.c, ""),
+ CLK_LOOKUP("", hfpll3_div_clk.c, ""),
+ CLK_LOOKUP("", hfpll3_clk.c, ""),
+ CLK_LOOKUP("", hfpll_l2_div_clk.c, ""),
+ CLK_LOOKUP("", hfpll_l2_clk.c, ""),
+ CLK_LOOKUP("", krait0_sec_mux_clk.c, ""),
+ CLK_LOOKUP("", krait1_sec_mux_clk.c, ""),
+ CLK_LOOKUP("", krait2_sec_mux_clk.c, ""),
+ CLK_LOOKUP("", krait3_sec_mux_clk.c, ""),
+ CLK_LOOKUP("", l2_sec_mux_clk.c, ""),
+ CLK_LOOKUP("", krait0_pri_mux_clk.c, ""),
+ CLK_LOOKUP("", krait1_pri_mux_clk.c, ""),
+ CLK_LOOKUP("", krait2_pri_mux_clk.c, ""),
+ CLK_LOOKUP("", krait3_pri_mux_clk.c, ""),
+ CLK_LOOKUP("", l2_pri_mux_clk.c, ""),
+ CLK_LOOKUP("l2_clk", l2_clk.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("cpu0_clk", krait0_clk.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("cpu1_clk", krait1_clk.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("cpu2_clk", krait2_clk.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("cpu3_clk", krait3_clk.c, "0.qcom,msm-cpufreq"),
+ CLK_LOOKUP("l2_clk", l2_clk.c, "fe805664.qcom,pm-8x60"),
+ CLK_LOOKUP("cpu0_clk", krait0_clk.c, "fe805664.qcom,pm-8x60"),
+ CLK_LOOKUP("cpu1_clk", krait1_clk.c, "fe805664.qcom,pm-8x60"),
+ CLK_LOOKUP("cpu2_clk", krait2_clk.c, "fe805664.qcom,pm-8x60"),
+ CLK_LOOKUP("cpu3_clk", krait3_clk.c, "fe805664.qcom,pm-8x60"),
+};
+
+static struct clk *cpu_clk[] = {
+ &krait0_clk.c,
+ &krait1_clk.c,
+ &krait2_clk.c,
+ &krait3_clk.c,
+};
+
+static void get_krait_bin_format_b(struct platform_device *pdev,
+ int *speed, int *pvs, int *ver)
+{
+ u32 pte_efuse, redundant_sel;
+ struct resource *res;
+ void __iomem *base;
+
+ *speed = 0;
+ *pvs = 0;
+ *ver = 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse");
+ if (!res) {
+ dev_info(&pdev->dev,
+ "No speed/PVS binning available. Defaulting to 0!\n");
+ return;
+ }
+
+ base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!base) {
+ dev_warn(&pdev->dev,
+ "Unable to read efuse data. Defaulting to 0!\n");
+ return;
+ }
+
+ pte_efuse = readl_relaxed(base);
+ redundant_sel = (pte_efuse >> 24) & 0x7;
+ *speed = pte_efuse & 0x7;
+ /* 4 bits of PVS are in efuse register bits 31, 8-6. */
+ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
+ *ver = (pte_efuse >> 4) & 0x3;
+
+ switch (redundant_sel) {
+ case 1:
+ *speed = (pte_efuse >> 27) & 0xF;
+ break;
+ case 2:
+ *pvs = (pte_efuse >> 27) & 0xF;
+ break;
+ }
+
+ /* Check SPEED_BIN_BLOW_STATUS */
+ if (pte_efuse & BIT(3)) {
+ dev_info(&pdev->dev, "Speed bin: %d\n", *speed);
+ } else {
+ dev_warn(&pdev->dev, "Speed bin not set. Defaulting to 0!\n");
+ *speed = 0;
+ }
+
+ /* Check PVS_BLOW_STATUS */
+ pte_efuse = readl_relaxed(base + 0x4) & BIT(21);
+ if (pte_efuse) {
+ dev_info(&pdev->dev, "PVS bin: %d\n", *pvs);
+ } else {
+ dev_warn(&pdev->dev, "PVS bin not set. Defaulting to 0!\n");
+ *pvs = 0;
+ }
+
+ dev_info(&pdev->dev, "PVS version: %d\n", *ver);
+
+ devm_iounmap(&pdev->dev, base);
+}
+
+static int parse_tbl(struct device *dev, char *prop, int num_cols,
+ u32 **col1, u32 **col2, u32 **col3)
+{
+ int ret, prop_len, num_rows, i, j, k;
+ u32 *prop_data;
+ u32 *col[num_cols];
+
+ if (!of_find_property(dev->of_node, prop, &prop_len))
+ return -EINVAL;
+
+ prop_len /= sizeof(*prop_data);
+
+ if (prop_len % num_cols || prop_len == 0)
+ return -EINVAL;
+
+ num_rows = prop_len / num_cols;
+
+ prop_data = devm_kzalloc(dev, prop_len * sizeof(*prop_data),
+ GFP_KERNEL);
+ if (!prop_data)
+ return -ENOMEM;
+
+ for (i = 0; i < num_cols; i++) {
+ col[i] = devm_kzalloc(dev, num_rows * sizeof(u32), GFP_KERNEL);
+ if (!col[i])
+ return -ENOMEM;
+ }
+
+ ret = of_property_read_u32_array(dev->of_node, prop, prop_data,
+ prop_len);
+ if (ret)
+ return ret;
+
+ k = 0;
+ for (i = 0; i < num_rows; i++) {
+ for (j = 0; j < num_cols; j++)
+ col[j][i] = prop_data[k++];
+ }
+ if (col1)
+ *col1 = col[0];
+ if (col2)
+ *col2 = col[1];
+ if (col3)
+ *col3 = col[2];
+
+ devm_kfree(dev, prop_data);
+
+ return num_rows;
+}
+
+static int clk_init_vdd_class(struct device *dev, struct clk *clk, int num,
+ unsigned long *fmax, int *uv, int *ua)
+{
+ struct clk_vdd_class *vdd = clk->vdd_class;
+
+ vdd->level_votes = devm_kzalloc(dev, num * sizeof(int), GFP_KERNEL);
+ if (!vdd->level_votes) {
+ dev_err(dev, "Out of memory!\n");
+ return -ENOMEM;
+ }
+ vdd->num_levels = num;
+ vdd->cur_level = num;
+ vdd->vdd_uv = uv;
+ vdd->vdd_ua = ua;
+ clk->fmax = fmax;
+ clk->num_fmax = num;
+
+ return 0;
+}
+
+static int hfpll_base_init(struct platform_device *pdev, struct hfpll_clk *h)
+{
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, h->c.dbg_name);
+ if (!res) {
+ dev_err(dev, "%s base addr not found!\n", h->c.dbg_name);
+ return -EINVAL;
+ }
+ h->base = devm_ioremap(dev, res->start, resource_size(res));
+ if (!h->base) {
+ dev_err(dev, "%s ioremap failed!\n", h->c.dbg_name);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static bool enable_boost;
+module_param_named(boost, enable_boost, bool, S_IRUGO | S_IWUSR);
+
+static void krait_update_uv(int *uv, int num, int boost_uv)
+{
+ int i;
+
+ switch (read_cpuid_id()) {
+ case 0x511F04D0: /* KR28M2A20 */
+ case 0x511F04D1: /* KR28M2A21 */
+ case 0x510F06F0: /* KR28M4A10 */
+ for (i = 0; i < num; i++)
+ uv[i] = max(1150000, uv[i]);
+ };
+
+ if (enable_boost) {
+ for (i = 0; i < num; i++)
+ uv[i] += boost_uv;
+ }
+}
+
+static int clock_krait_8974_driver_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct clk *c;
+ int speed, pvs, ver, rows, cpu;
+ char prop_name[] = "qcom,speedXX-pvsXX-bin-vXX";
+ unsigned long *freq, cur_rate, aux_rate;
+ int *uv, *ua;
+ u32 *dscr, vco_mask, config_val;
+ int ret;
+
+ vdd_l2.regulator[0] = devm_regulator_get(dev, "l2-dig");
+ if (IS_ERR(vdd_l2.regulator[0])) {
+ dev_err(dev, "Unable to get l2-dig regulator!\n");
+ return PTR_ERR(vdd_l2.regulator[0]);
+ }
+
+ vdd_hfpll.regulator[0] = devm_regulator_get(dev, "hfpll-dig");
+ if (IS_ERR(vdd_hfpll.regulator[0])) {
+ dev_err(dev, "Unable to get hfpll-dig regulator!\n");
+ return PTR_ERR(vdd_hfpll.regulator[0]);
+ }
+
+ vdd_hfpll.regulator[1] = devm_regulator_get(dev, "hfpll-analog");
+ if (IS_ERR(vdd_hfpll.regulator[1])) {
+ dev_err(dev, "Unable to get hfpll-analog regulator!\n");
+ return PTR_ERR(vdd_hfpll.regulator[1]);
+ }
+
+ vdd_krait0.regulator[0] = devm_regulator_get(dev, "cpu0");
+ if (IS_ERR(vdd_krait0.regulator[0])) {
+ dev_err(dev, "Unable to get cpu0 regulator!\n");
+ return PTR_ERR(vdd_krait0.regulator[0]);
+ }
+
+ vdd_krait1.regulator[0] = devm_regulator_get(dev, "cpu1");
+ if (IS_ERR(vdd_krait1.regulator[0])) {
+ dev_err(dev, "Unable to get cpu1 regulator!\n");
+ return PTR_ERR(vdd_krait1.regulator[0]);
+ }
+
+ vdd_krait2.regulator[0] = devm_regulator_get(dev, "cpu2");
+ if (IS_ERR(vdd_krait2.regulator[0])) {
+ dev_err(dev, "Unable to get cpu2 regulator!\n");
+ return PTR_ERR(vdd_krait2.regulator[0]);
+ }
+
+ vdd_krait3.regulator[0] = devm_regulator_get(dev, "cpu3");
+ if (IS_ERR(vdd_krait3.regulator[0])) {
+ dev_err(dev, "Unable to get cpu3 regulator!\n");
+ return PTR_ERR(vdd_krait3.regulator[0]);
+ }
+
+ c = devm_clk_get(dev, "hfpll_src");
+ if (IS_ERR(c)) {
+ dev_err(dev, "Unable to get HFPLL source\n");
+ return PTR_ERR(c);
+ }
+ hfpll_src_clk.c.parent = c;
+
+ c = devm_clk_get(dev, "aux_clk");
+ if (IS_ERR(c)) {
+ dev_err(dev, "Unable to get AUX source\n");
+ return PTR_ERR(c);
+ }
+ acpu_aux_clk.c.parent = c;
+
+ if (hfpll_base_init(pdev, &hfpll0_clk))
+ return -EINVAL;
+ if (hfpll_base_init(pdev, &hfpll1_clk))
+ return -EINVAL;
+ if (hfpll_base_init(pdev, &hfpll2_clk))
+ return -EINVAL;
+ if (hfpll_base_init(pdev, &hfpll3_clk))
+ return -EINVAL;
+ if (hfpll_base_init(pdev, &hfpll_l2_clk))
+ return -EINVAL;
+
+ ret = of_property_read_u32(dev->of_node, "qcom,hfpll-config-val",
+ &config_val);
+ if (!ret)
+ hdata.config_val = config_val;
+
+ ret = of_property_read_u32(dev->of_node, "qcom,hfpll-user-vco-mask",
+ &vco_mask);
+ if (!ret)
+ hdata.user_vco_mask = vco_mask;
+
+ get_krait_bin_format_b(pdev, &speed, &pvs, &ver);
+ snprintf(prop_name, ARRAY_SIZE(prop_name),
+ "qcom,speed%d-pvs%d-bin-v%d", speed, pvs, ver);
+
+ rows = parse_tbl(dev, prop_name, 3,
+ (u32 **) &freq, (u32 **) &uv, (u32 **) &ua);
+ if (rows < 0) {
+ /* Fall back to most conservative PVS table */
+ dev_err(dev, "Unable to load voltage plan %s!\n", prop_name);
+ ret = parse_tbl(dev, "qcom,speed0-pvs0-bin-v0", 3,
+ (u32 **) &freq, (u32 **) &uv, (u32 **) &ua);
+ if (ret < 0) {
+ dev_err(dev, "Unable to load safe voltage plan\n");
+ return rows;
+ } else {
+ dev_info(dev, "Safe voltage plan loaded.\n");
+ pvs = 0;
+ rows = ret;
+ }
+ }
+
+ krait_update_uv(uv, rows, pvs ? 25000 : 0);
+
+ if (clk_init_vdd_class(dev, &krait0_clk.c, rows, freq, uv, ua))
+ return -ENOMEM;
+ if (clk_init_vdd_class(dev, &krait1_clk.c, rows, freq, uv, ua))
+ return -ENOMEM;
+ if (clk_init_vdd_class(dev, &krait2_clk.c, rows, freq, uv, ua))
+ return -ENOMEM;
+ if (clk_init_vdd_class(dev, &krait3_clk.c, rows, freq, uv, ua))
+ return -ENOMEM;
+
+ /* AVS is optional */
+ rows = parse_tbl(dev, "qcom,avs-tbl", 2, (u32 **) &freq, &dscr, NULL);
+ if (rows > 0) {
+ avs_table.rate = freq;
+ avs_table.dscr = dscr;
+ avs_table.num = rows;
+ }
+
+ rows = parse_tbl(dev, "qcom,l2-fmax", 2, (u32 **) &freq, (u32 **) &uv,
+ NULL);
+ if (rows < 0) {
+ dev_err(dev, "Unable to find L2 Fmax table!\n");
+ return rows;
+ }
+
+ if (clk_init_vdd_class(dev, &l2_clk.c, rows, freq, uv, NULL))
+ return -ENOMEM;
+
+ msm_clock_register(kpss_clocks_8974, ARRAY_SIZE(kpss_clocks_8974));
+
+ /*
+ * We don't want the CPU or L2 clocks to be turned off at late init
+ * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
+ * refcount of these clocks. Any cpufreq/hotplug manager can assume
+ * that the clocks have already been prepared and enabled by the time
+ * they take over.
+ */
+ clk_prepare_enable(&l2_clk.c);
+ for_each_online_cpu(cpu) {
+ WARN(clk_prepare_enable(cpu_clk[cpu]),
+ "Unable to turn on CPU%d clock", cpu);
+ }
+
+ /*
+ * Force reinit of HFPLLs and muxes to overwrite any potential
+ * incorrect configuration of HFPLLs and muxes by the bootloader.
+ * While at it, also make sure the cores are running at known rates
+ * and print the current rate.
+ *
+ * The clocks are set to aux clock rate first to make sure the
+ * secondary mux is not sourcing off of QSB. The rate is then set to
+ * two different rates to force a HFPLL reinit under all
+ * circumstances.
+ */
+ cur_rate = clk_get_rate(&l2_clk.c);
+ aux_rate = clk_get_rate(&acpu_aux_clk.c);
+ if (!cur_rate) {
+ pr_info("L2 @ unknown rate. Forcing new rate.\n");
+ cur_rate = aux_rate;
+ }
+ clk_set_rate(&l2_clk.c, aux_rate);
+ clk_set_rate(&l2_clk.c, clk_round_rate(&l2_clk.c, 1));
+ clk_set_rate(&l2_clk.c, cur_rate);
+ pr_info("L2 @ %lu KHz\n", clk_get_rate(&l2_clk.c) / 1000);
+ for_each_possible_cpu(cpu) {
+ struct clk *c = cpu_clk[cpu];
+ cur_rate = clk_get_rate(c);
+ if (!cur_rate) {
+ pr_info("CPU%d @ unknown rate. Forcing new rate.\n",
+ cpu);
+ cur_rate = aux_rate;
+ }
+ clk_set_rate(c, aux_rate);
+ clk_set_rate(c, clk_round_rate(c, 1));
+ clk_set_rate(c, clk_round_rate(c, cur_rate));
+ pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(c) / 1000);
+ }
+
+ return 0;
+}
+
+static struct of_device_id match_table[] = {
+ { .compatible = "qcom,clock-krait-8974" },
+ {}
+};
+
+static struct platform_driver clock_krait_8974_driver = {
+ .probe = clock_krait_8974_driver_probe,
+ .driver = {
+ .name = "clock-krait-8974",
+ .of_match_table = match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init clock_krait_8974_init(void)
+{
+ return platform_driver_register(&clock_krait_8974_driver);
+}
+module_init(clock_krait_8974_init);
+
+static void __exit clock_krait_8974_exit(void)
+{
+ platform_driver_unregister(&clock_krait_8974_driver);
+}
+module_exit(clock_krait_8974_exit);
+
+MODULE_DESCRIPTION("Krait CPU clock driver for 8974");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/clock-krait.c b/arch/arm/mach-msm/clock-krait.c
index b96ba62..cdd53e5 100644
--- a/arch/arm/mach-msm/clock-krait.c
+++ b/arch/arm/mach-msm/clock-krait.c
@@ -29,6 +29,7 @@
static DEFINE_SPINLOCK(kpss_clock_reg_lock);
+#define LPL_SHIFT 8
static void __kpss_mux_set_sel(struct mux_clk *mux, int sel)
{
unsigned long flags;
@@ -38,6 +39,10 @@
regval = get_l2_indirect_reg(mux->offset);
regval &= ~(mux->mask << mux->shift);
regval |= (sel & mux->mask) << mux->shift;
+ if (mux->priv) {
+ regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
+ regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
+ }
set_l2_indirect_reg(mux->offset, regval);
spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
@@ -95,8 +100,10 @@
spin_lock_irqsave(&kpss_clock_reg_lock, flags);
regval = get_l2_indirect_reg(div->offset);
- val = (regval >> div->shift) && div->mask;
+ val = (regval >> div->shift) & div->mask;
regval &= ~(div->mask << div->shift);
+ if (div->priv)
+ regval &= ~(div->mask << (div->shift + LPL_SHIFT));
set_l2_indirect_reg(div->offset, regval);
spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
@@ -123,7 +130,8 @@
return;
/* Configure PLL parameters for integer mode. */
- writel_relaxed(hd->config_val, h->base + hd->config_offset);
+ if (hd->config_val)
+ writel_relaxed(hd->config_val, h->base + hd->config_offset);
writel_relaxed(0, h->base + hd->m_offset);
writel_relaxed(1, h->base + hd->n_offset);
@@ -134,7 +142,7 @@
rate = readl_relaxed(h->base + hd->l_offset) * h->src_rate;
/* Pick the right VCO. */
- if (rate > hd->low_vco_max_rate)
+ if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
regval |= hd->user_vco_mask;
writel_relaxed(regval, h->base + hd->user_offset);
}
@@ -243,7 +251,7 @@
hfpll_clk_disable(c);
/* Pick the right VCO. */
- if (hd->user_offset) {
+ if (hd->user_offset && hd->user_vco_mask) {
u32 regval;
regval = readl_relaxed(h->base + hd->user_offset);
if (rate <= hd->low_vco_max_rate)
@@ -394,9 +402,6 @@
struct kpss_core_clk *cpu = to_kpss_core_clk(c);
u32 dscr = find_dscr(cpu->avs_tbl, c->rate);
- if (!c->prepare_count)
- return -ENODEV;
-
if (dscr)
AVS_DISABLE(cpu->id);
return 0;
@@ -412,9 +417,6 @@
static int kpss_core_set_rate(struct clk *c, unsigned long rate)
{
- if (!c->prepare_count)
- return -ENODEV;
-
return clk_set_rate(c->parent, rate);
}
diff --git a/arch/arm/mach-msm/clock-krait.h b/arch/arm/mach-msm/clock-krait.h
index 2691a8c..07b72d5 100644
--- a/arch/arm/mach-msm/clock-krait.h
+++ b/arch/arm/mach-msm/clock-krait.h
@@ -20,15 +20,18 @@
extern struct clk_mux_ops clk_mux_ops_kpss;
extern struct clk_div_ops clk_div_ops_kpss_div2;
-#define DEFINE_KPSS_DIV2_CLK(clk_name, _parent, _offset) \
+#define DEFINE_KPSS_DIV2_CLK(clk_name, _parent, _offset, _lf_tree) \
static struct div_clk clk_name = { \
- .div = 2, \
- .min_div = 2, \
- .max_div = 2, \
+ .data = { \
+ .div = 2, \
+ .min_div = 2, \
+ .max_div = 2, \
+ }, \
.ops = &clk_div_ops_kpss_div2, \
.offset = _offset, \
.mask = 0x3, \
.shift = 6, \
+ .priv = (void *) _lf_tree, \
.c = { \
.parent = _parent, \
.dbg_name = #clk_name, \
@@ -49,9 +52,9 @@
const u32 status_offset;
const u32 droop_val;
- const u32 config_val;
+ u32 config_val;
const u32 user_val;
- const u32 user_vco_mask;
+ u32 user_vco_mask;
unsigned long low_vco_max_rate;
unsigned long min_rate;
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 4488869..01ecba2 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -25,6 +25,7 @@
#include <mach/clk.h>
#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
#include "clock-local2.h"
@@ -796,153 +797,65 @@
}
-#define ENABLE_REG(x) (*(x)->base + (x)->enable_reg)
-#define SELECT_REG(x) (*(x)->base + (x)->select_reg)
+static DEFINE_SPINLOCK(mux_reg_lock);
-/*
- * mux clock functions
- */
-static void cam_mux_clk_halt_check(void)
+static int mux_reg_enable(struct mux_clk *clk)
{
- /* Ensure that the delay starts after the mux disable/enable. */
- mb();
- udelay(HALT_CHECK_DELAY_US);
-}
-
-static int cam_mux_clk_enable(struct clk *c)
-{
- unsigned long flags;
u32 regval;
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
+ unsigned long flags;
+ u32 offset = clk->en_reg ? clk->en_offset : clk->offset;
- spin_lock_irqsave(&local_clock_reg_lock, flags);
- regval = readl_relaxed(ENABLE_REG(mux));
- regval |= mux->enable_mask;
- writel_relaxed(regval, ENABLE_REG(mux));
- spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
- /* Wait for clock to enable before continuing. */
- cam_mux_clk_halt_check();
+ spin_lock_irqsave(&mux_reg_lock, flags);
+ regval = readl_relaxed(*clk->base + offset);
+ regval |= clk->en_mask;
+ writel_relaxed(regval, *clk->base + offset);
+ /* Ensure enable request goes through before returning */
+ mb();
+ spin_unlock_irqrestore(&mux_reg_lock, flags);
return 0;
}
-static void cam_mux_clk_disable(struct clk *c)
+static void mux_reg_disable(struct mux_clk *clk)
{
- unsigned long flags;
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
u32 regval;
+ unsigned long flags;
+ u32 offset = clk->en_reg ? clk->en_offset : clk->offset;
- spin_lock_irqsave(&local_clock_reg_lock, flags);
- regval = readl_relaxed(ENABLE_REG(mux));
- regval &= ~mux->enable_mask;
- writel_relaxed(regval, ENABLE_REG(mux));
- spin_unlock_irqrestore(&local_clock_reg_lock, flags);
-
- /* Wait for clock to disable before continuing. */
- cam_mux_clk_halt_check();
+ spin_lock_irqsave(&mux_reg_lock, flags);
+ regval = readl_relaxed(*clk->base + offset);
+ regval &= ~clk->en_mask;
+ writel_relaxed(regval, *clk->base + offset);
+ spin_unlock_irqrestore(&mux_reg_lock, flags);
}
-static int mux_source_switch(struct cam_mux_clk *mux, struct mux_source *dest)
+static int mux_reg_set_mux_sel(struct mux_clk *clk, int sel)
{
- unsigned long flags;
u32 regval;
- int ret = 0;
+ unsigned long flags;
- ret = __clk_pre_reparent(&mux->c, dest->clk, &flags);
- if (ret)
- goto out;
-
- regval = readl_relaxed(SELECT_REG(mux));
- regval &= ~mux->select_mask;
- regval |= dest->select_val;
- writel_relaxed(regval, SELECT_REG(mux));
-
- /* Make sure switch request goes through before proceeding. */
+ spin_lock_irqsave(&mux_reg_lock, flags);
+ regval = readl_relaxed(*clk->base + clk->offset);
+ regval &= ~(clk->mask << clk->shift);
+ regval |= (sel & clk->mask) << clk->shift;
+ writel_relaxed(regval, *clk->base + clk->offset);
+ /* Ensure switch request goes through before returning */
mb();
-
- __clk_post_reparent(&mux->c, mux->c.parent, &flags);
-out:
- return ret;
-}
-
-static int cam_mux_clk_set_parent(struct clk *c, struct clk *parent)
-{
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
- struct mux_source *dest = NULL;
- int ret;
-
- if (!mux->sources || !parent)
- return -EPERM;
-
- dest = mux->sources;
-
- while (dest->clk) {
- if (dest->clk == parent)
- break;
- dest++;
- }
-
- if (!dest->clk)
- return -EPERM;
-
- ret = mux_source_switch(mux, dest);
- if (ret)
- return ret;
-
- mux->c.rate = clk_get_rate(dest->clk);
+ spin_unlock_irqrestore(&mux_reg_lock, flags);
return 0;
}
-static enum handoff cam_mux_clk_handoff(struct clk *c)
+static int mux_reg_get_mux_sel(struct mux_clk *clk)
{
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
- u32 mask = mux->enable_mask;
- u32 regval = readl_relaxed(ENABLE_REG(mux));
-
- c->rate = clk_get_rate(c->parent);
-
- if (mask == (regval & mask))
- return HANDOFF_ENABLED_CLK;
-
- return HANDOFF_DISABLED_CLK;
+ u32 regval = readl_relaxed(*clk->base + clk->offset);
+ return !!((regval >> clk->shift) & clk->mask);
}
-static struct clk *cam_mux_clk_get_parent(struct clk *c)
+static bool mux_reg_is_enabled(struct mux_clk *clk)
{
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
- struct mux_source *parent = NULL;
- u32 regval = readl_relaxed(SELECT_REG(mux));
-
- if (!mux->sources)
- return ERR_PTR(-EPERM);
-
- parent = mux->sources;
-
- while (parent->clk) {
- if ((regval & mux->select_mask) == parent->select_val)
- return parent->clk;
-
- parent++;
- }
-
- return ERR_PTR(-EPERM);
-}
-
-static long cam_mux_clk_list_rate(struct clk *c, unsigned n)
-{
- struct cam_mux_clk *mux = to_cam_mux_clk(c);
- int i;
-
- for (i = 0; i < n; i++)
- if (!mux->sources[i].clk)
- break;
-
- if (!mux->sources[i].clk)
- return -ENXIO;
-
- return clk_get_rate(mux->sources[i].clk);
+ u32 regval = readl_relaxed(*clk->base + clk->offset);
+ return !!(regval & clk->en_mask);
}
struct clk_ops clk_ops_empty;
@@ -1009,13 +922,10 @@
.handoff = local_vote_clk_handoff,
};
-struct clk_ops clk_ops_cam_mux = {
- .enable = cam_mux_clk_enable,
- .disable = cam_mux_clk_disable,
- .set_parent = cam_mux_clk_set_parent,
- .get_parent = cam_mux_clk_get_parent,
- .handoff = cam_mux_clk_handoff,
- .list_rate = cam_mux_clk_list_rate,
+struct clk_mux_ops mux_reg_ops = {
+ .enable = mux_reg_enable,
+ .disable = mux_reg_disable,
+ .set_mux_sel = mux_reg_set_mux_sel,
+ .get_mux_sel = mux_reg_get_mux_sel,
+ .is_enabled = mux_reg_is_enabled,
};
-
-
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index cee5b8c..8724f63 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -157,38 +157,6 @@
return container_of(clk, struct measure_clk, c);
}
-struct mux_source {
- struct clk *const clk;
- const u32 select_val;
-};
-
-/**
- * struct cam_mux_clk - branch clock
- * @c: clk
- * @enable_reg: register that contains the enable bit(s) for the mux
- * @select_reg: register that contains the source selection bits for the mux
- * @enable_mask: mask that enables the mux
- * @select_mask: mask for the source selection bits
- * @sources: list of mux sources
- * @base: pointer to base address of ioremapped registers.
- */
-struct cam_mux_clk {
- struct clk c;
- const u32 enable_reg;
- const u32 select_reg;
- const u32 enable_mask;
- const u32 select_mask;
-
- struct mux_source *sources;
-
- void *const __iomem *base;
-};
-
-static inline struct cam_mux_clk *to_cam_mux_clk(struct clk *clk)
-{
- return container_of(clk, struct cam_mux_clk, c);
-}
-
/*
* Generic set-rate implementations
*/
@@ -200,7 +168,6 @@
*/
extern spinlock_t local_clock_reg_lock;
-extern struct clk_ops clk_ops_cam_mux;
extern struct clk_ops clk_ops_empty;
extern struct clk_ops clk_ops_rcg;
extern struct clk_ops clk_ops_rcg_mnd;
@@ -209,6 +176,7 @@
extern struct clk_ops clk_ops_rcg_hdmi;
extern struct clk_ops clk_ops_byte;
extern struct clk_ops clk_ops_pixel;
+extern struct clk_mux_ops mux_reg_ops;
enum handoff pixel_rcg_handoff(struct clk *clk);
enum handoff byte_rcg_handoff(struct clk *clk);
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index cf2df18..2fa921a 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -727,7 +727,7 @@
{
struct div_clk *div = to_div_clk(c);
/* Restore the divider's value */
- return div->ops->set_div(div, div->div);
+ return div->ops->set_div(div, div->data.div);
}
int mux_prepare(struct clk *c)
@@ -1492,8 +1492,10 @@
};
struct div_clk analog_postdiv_clk_8226 = {
- .max_div = 255,
- .min_div = 1,
+ .data = {
+ .max_div = 255,
+ .min_div = 1,
+ },
.ops = &analog_postdiv_ops,
.c = {
.parent = &dsi_vco_clk_8226.c,
@@ -1506,7 +1508,11 @@
struct div_clk indirect_path_div2_clk_8226 = {
.ops = &fixed_2div_ops,
- .div = 2,
+ .data = {
+ .div = 2,
+ .min_div = 2,
+ .max_div = 2,
+ },
.c = {
.parent = &analog_postdiv_clk_8226.c,
.dbg_name = "indirect_path_div2_clk",
@@ -1517,8 +1523,10 @@
};
struct div_clk pixel_clk_src_8226 = {
- .max_div = 255,
- .min_div = 1,
+ .data = {
+ .max_div = 255,
+ .min_div = 1,
+ },
.ops = &digital_postdiv_ops,
.c = {
.parent = &dsi_vco_clk_8226.c,
@@ -1546,8 +1554,10 @@
struct div_clk byte_clk_src_8226 = {
.ops = &fixed_4div_ops,
- .min_div = 4,
- .max_div = 4,
+ .data = {
+ .min_div = 4,
+ .max_div = 4,
+ },
.c = {
.parent = &byte_mux_8226.c,
.dbg_name = "byte_clk_src",
@@ -1585,8 +1595,10 @@
};
struct div_clk analog_postdiv_clk_8974 = {
- .max_div = 255,
- .min_div = 1,
+ .data = {
+ .max_div = 255,
+ .min_div = 1,
+ },
.ops = &analog_postdiv_ops,
.c = {
.parent = &dsi_vco_clk_8974.c,
@@ -1599,7 +1611,11 @@
struct div_clk indirect_path_div2_clk_8974 = {
.ops = &fixed_2div_ops,
- .div = 2,
+ .data = {
+ .div = 2,
+ .min_div = 2,
+ .max_div = 2,
+ },
.c = {
.parent = &analog_postdiv_clk_8974.c,
.dbg_name = "indirect_path_div2_clk",
@@ -1610,8 +1626,10 @@
};
struct div_clk pixel_clk_src_8974 = {
- .max_div = 255,
- .min_div = 1,
+ .data = {
+ .max_div = 255,
+ .min_div = 1,
+ },
.ops = &digital_postdiv_ops,
.c = {
.parent = &dsi_vco_clk_8974.c,
@@ -1639,8 +1657,10 @@
struct div_clk byte_clk_src_8974 = {
.ops = &fixed_4div_ops,
- .min_div = 4,
- .max_div = 4,
+ .data = {
+ .min_div = 4,
+ .max_div = 4,
+ },
.c = {
.parent = &byte_mux_8974.c,
.dbg_name = "byte_clk_src",
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index e3c11c5..f7ee79c 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -63,36 +63,44 @@
/* Update voltage level given the current votes. */
static int update_vdd(struct clk_vdd_class *vdd_class)
{
- int level, rc = 0, i;
+ int level, rc = 0, i, ignore;
struct regulator **r = vdd_class->regulator;
int *uv = vdd_class->vdd_uv;
int *ua = vdd_class->vdd_ua;
int n_reg = vdd_class->num_regulators;
+ int cur_lvl = vdd_class->cur_level;
int max_lvl = vdd_class->num_levels - 1;
- int lvl_base;
+ int cur_base = cur_lvl * n_reg;
+ int new_base;
+ /* aggregate votes */
for (level = max_lvl; level > 0; level--)
if (vdd_class->level_votes[level])
break;
- if (level == vdd_class->cur_level)
+ if (level == cur_lvl)
return 0;
max_lvl = max_lvl * n_reg;
- lvl_base = level * n_reg;
+ new_base = level * n_reg;
for (i = 0; i < vdd_class->num_regulators; i++) {
- rc = regulator_set_voltage(r[i], uv[lvl_base + i],
+ rc = regulator_set_voltage(r[i], uv[new_base + i],
uv[max_lvl + i]);
if (rc)
goto set_voltage_fail;
- if (!ua)
- continue;
-
- rc = regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
- rc = rc > 0 ? 0 : rc;
+ if (ua) {
+ rc = regulator_set_optimum_mode(r[i], ua[new_base + i]);
+ rc = rc > 0 ? 0 : rc;
+ if (rc)
+ goto set_mode_fail;
+ }
+ if (cur_lvl == 0 || cur_lvl == vdd_class->num_levels)
+ rc = regulator_enable(r[i]);
+ else if (level == 0)
+ rc = regulator_disable(r[i]);
if (rc)
- goto set_mode_fail;
+ goto enable_disable_fail;
}
if (vdd_class->set_vdd && !vdd_class->num_regulators)
rc = vdd_class->set_vdd(vdd_class, level);
@@ -102,20 +110,29 @@
return rc;
-set_mode_fail:
- regulator_set_voltage(r[i], uv[vdd_class->cur_level * n_reg + i],
- uv[max_lvl + i]);
-
-set_voltage_fail:
- lvl_base = vdd_class->cur_level * n_reg;
- for (i--; i >= 0; i--) {
- regulator_set_voltage(r[i], uv[lvl_base + i], uv[max_lvl + i]);
-
- if (!ua)
- continue;
- regulator_set_optimum_mode(r[i], ua[lvl_base + i]);
+enable_disable_fail:
+ /*
+ * set_optimum_mode could use voltage to derive mode. Restore
+ * previous voltage setting for r[i] first.
+ */
+ if (ua) {
+ regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]);
+ regulator_set_optimum_mode(r[i], ua[cur_base + i]);
}
+set_mode_fail:
+ regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]);
+
+set_voltage_fail:
+ for (i--; i >= 0; i--) {
+ regulator_set_voltage(r[i], uv[cur_base + i], uv[max_lvl + i]);
+ if (ua)
+ regulator_set_optimum_mode(r[i], ua[cur_base + i]);
+ if (cur_lvl == 0 || cur_lvl == vdd_class->num_levels)
+ regulator_disable(r[i]);
+ else if (level == 0)
+ ignore = regulator_enable(r[i]);
+ }
return rc;
}
@@ -527,13 +544,26 @@
long clk_round_rate(struct clk *clk, unsigned long rate)
{
+ long rrate;
+ unsigned long fmax = 0, i;
+
if (IS_ERR_OR_NULL(clk))
return -EINVAL;
if (!clk->ops->round_rate)
return -ENOSYS;
- return clk->ops->round_rate(clk, rate);
+ for (i = 0; i < clk->num_fmax; i++)
+ fmax = max(fmax, clk->fmax[i]);
+
+ if (!fmax)
+ fmax = ULONG_MAX;
+
+ rate = min(rate, fmax);
+ rrate = clk->ops->round_rate(clk, rate);
+ if (rrate > fmax)
+ return -EINVAL;
+ return rrate;
}
EXPORT_SYMBOL(clk_round_rate);
@@ -553,15 +583,16 @@
{
int rc = 0;
+ if (!clk->ops->set_parent && clk->parent == parent)
+ return 0;
+
if (!clk->ops->set_parent)
return -ENOSYS;
mutex_lock(&clk->prepare_lock);
- if (clk->parent == parent)
+ if (clk->parent == parent && !(clk->flags & CLKFLAG_NO_RATE_CACHE))
goto out;
rc = clk->ops->set_parent(clk, parent);
- if (!rc)
- clk->parent = parent;
out:
mutex_unlock(&clk->prepare_lock);
@@ -607,7 +638,6 @@
static void vdd_class_init(struct clk_vdd_class *vdd)
{
struct handoff_vdd *v;
- int i;
if (!vdd)
return;
@@ -621,9 +651,6 @@
if (vote_vdd_level(vdd, vdd->num_levels - 1))
pr_err("failed to vote for %s\n", vdd->class_name);
- for (i = 0; i < vdd->num_regulators; i++)
- regulator_enable(vdd->regulator[i]);
-
v = kmalloc(sizeof(*v), GFP_KERNEL);
if (!v) {
pr_err("Unable to kmalloc. %s will be stuck at max.\n",
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index a6c86af..85a1468 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -27,17 +27,43 @@
#include <linux/cpumask.h>
#include <linux/sched.h>
#include <linux/suspend.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
#include <trace/events/power.h>
#include <mach/socinfo.h>
-#include <mach/cpufreq.h>
+#include <mach/msm_bus.h>
#include "acpuclock.h"
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <asm/div64.h>
+#endif
+
+static DEFINE_MUTEX(l2bw_lock);
+
+static struct clk *cpu_clk[NR_CPUS];
+static struct clk *l2_clk;
+static unsigned int freq_index[NR_CPUS];
+static struct cpufreq_frequency_table *freq_table;
+static unsigned int *l2_khz;
+static bool is_clk;
+static bool is_sync;
+static struct msm_bus_vectors *bus_vec_lst;
+static struct msm_bus_scale_pdata bus_bw = {
+ .name = "msm-cpufreq",
+ .active_only = 1,
+};
+static u32 bus_client;
+
struct cpufreq_work_struct {
struct work_struct work;
struct cpufreq_policy *policy;
struct completion complete;
int frequency;
+ unsigned int index;
int status;
};
@@ -51,37 +77,45 @@
static DEFINE_PER_CPU(struct cpufreq_suspend_t, cpufreq_suspend);
-struct cpu_freq {
- uint32_t max;
- uint32_t min;
- uint32_t allowed_max;
- uint32_t allowed_min;
- uint32_t limits_init;
-};
+static void update_l2_bw(int *also_cpu)
+{
+ int rc = 0, cpu;
+ unsigned int index = 0;
-static DEFINE_PER_CPU(struct cpu_freq, cpu_freq_info);
+ mutex_lock(&l2bw_lock);
-static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq)
+ if (also_cpu)
+ index = freq_index[*also_cpu];
+
+ for_each_online_cpu(cpu) {
+ index = max(index, freq_index[cpu]);
+ }
+
+ if (l2_clk)
+ rc = clk_set_rate(l2_clk, l2_khz[index] * 1000);
+ if (rc) {
+ pr_err("Error setting L2 clock rate!\n");
+ goto out;
+ }
+
+ if (bus_client)
+ rc = msm_bus_scale_client_update_request(bus_client, index);
+ if (rc)
+ pr_err("Bandwidth req failed (%d)\n", rc);
+
+out:
+ mutex_unlock(&l2bw_lock);
+}
+
+static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq,
+ unsigned int index)
{
int ret = 0;
int saved_sched_policy = -EINVAL;
int saved_sched_rt_prio = -EINVAL;
struct cpufreq_freqs freqs;
- struct cpu_freq *limit = &per_cpu(cpu_freq_info, policy->cpu);
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
- if (limit->limits_init) {
- if (new_freq > limit->allowed_max) {
- new_freq = limit->allowed_max;
- pr_debug("max: limiting freq to %d\n", new_freq);
- }
-
- if (new_freq < limit->allowed_min) {
- new_freq = limit->allowed_min;
- pr_debug("min: limiting freq to %d\n", new_freq);
- }
- }
-
freqs.old = policy->cur;
freqs.new = new_freq;
freqs.cpu = policy->cpu;
@@ -100,7 +134,18 @@
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
trace_cpu_frequency_switch_start(freqs.old, freqs.new, policy->cpu);
- ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ);
+ if (is_clk) {
+ unsigned long rate = new_freq * 1000;
+ rate = clk_round_rate(cpu_clk[policy->cpu], rate);
+ ret = clk_set_rate(cpu_clk[policy->cpu], rate);
+ if (!ret) {
+ freq_index[policy->cpu] = index;
+ update_l2_bw(NULL);
+ }
+ } else {
+ ret = acpuclk_set_rate(policy->cpu, new_freq, SETRATE_CPUFREQ);
+ }
+
if (!ret) {
trace_cpu_frequency_switch_end(policy->cpu);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -119,7 +164,8 @@
struct cpufreq_work_struct *cpu_work =
container_of(work, struct cpufreq_work_struct, work);
- cpu_work->status = set_cpu_freq(cpu_work->policy, cpu_work->frequency);
+ cpu_work->status = set_cpu_freq(cpu_work->policy, cpu_work->frequency,
+ cpu_work->index);
complete(&cpu_work->complete);
}
@@ -157,6 +203,7 @@
cpu_work = &per_cpu(cpufreq_work, policy->cpu);
cpu_work->policy = policy;
cpu_work->frequency = table[index].frequency;
+ cpu_work->index = table[index].index;
cpu_work->status = -ENODEV;
cancel_work_sync(&cpu_work->work);
@@ -180,70 +227,12 @@
static unsigned int msm_cpufreq_get_freq(unsigned int cpu)
{
+ if (is_clk)
+ return clk_get_rate(cpu_clk[cpu]) / 1000;
+
return acpuclk_get_rate(cpu);
}
-static inline int msm_cpufreq_limits_init(void)
-{
- int cpu = 0;
- int i = 0;
- struct cpufreq_frequency_table *table = NULL;
- uint32_t min = (uint32_t) -1;
- uint32_t max = 0;
- struct cpu_freq *limit = NULL;
-
- for_each_possible_cpu(cpu) {
- limit = &per_cpu(cpu_freq_info, cpu);
- table = cpufreq_frequency_get_table(cpu);
- if (table == NULL) {
- pr_err("%s: error reading cpufreq table for cpu %d\n",
- __func__, cpu);
- continue;
- }
- for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
- if (table[i].frequency > max)
- max = table[i].frequency;
- if (table[i].frequency < min)
- min = table[i].frequency;
- }
- limit->allowed_min = min;
- limit->allowed_max = max;
- limit->min = min;
- limit->max = max;
- limit->limits_init = 1;
- }
-
- return 0;
-}
-
-int msm_cpufreq_set_freq_limits(uint32_t cpu, uint32_t min, uint32_t max)
-{
- struct cpu_freq *limit = &per_cpu(cpu_freq_info, cpu);
-
- if (!limit->limits_init)
- msm_cpufreq_limits_init();
-
- if ((min != MSM_CPUFREQ_NO_LIMIT) &&
- min >= limit->min && min <= limit->max)
- limit->allowed_min = min;
- else
- limit->allowed_min = limit->min;
-
-
- if ((max != MSM_CPUFREQ_NO_LIMIT) &&
- max <= limit->max && max >= limit->min)
- limit->allowed_max = max;
- else
- limit->allowed_max = limit->max;
-
- pr_debug("%s: Limiting cpu %d min = %d, max = %d\n",
- __func__, cpu,
- limit->allowed_min, limit->allowed_max);
-
- return 0;
-}
-EXPORT_SYMBOL(msm_cpufreq_set_freq_limits);
-
static int __cpuinit msm_cpufreq_init(struct cpufreq_policy *policy)
{
int cur_freq;
@@ -261,7 +250,7 @@
* same frequency. Hence set the cpumask to all cpu.
*/
if (cpu_is_msm8625() || cpu_is_msm8625q() || cpu_is_msm8226()
- || cpu_is_msm8610())
+ || cpu_is_msm8610() || (is_clk && is_sync))
cpumask_setall(policy->cpus);
if (cpufreq_frequency_table_cpuinfo(policy, table)) {
@@ -275,7 +264,11 @@
policy->max = CONFIG_MSM_CPU_FREQ_MAX;
#endif
- cur_freq = acpuclk_get_rate(policy->cpu);
+ if (is_clk)
+ cur_freq = clk_get_rate(cpu_clk[policy->cpu])/1000;
+ else
+ cur_freq = acpuclk_get_rate(policy->cpu);
+
if (cpufreq_frequency_table_target(policy, table, cur_freq,
CPUFREQ_RELATION_H, &index) &&
cpufreq_frequency_table_target(policy, table, cur_freq,
@@ -288,7 +281,7 @@
* Call set_cpu_freq unconditionally so that when cpu is set to
* online, frequency limit will always be updated.
*/
- ret = set_cpu_freq(policy, table[index].frequency);
+ ret = set_cpu_freq(policy, table[index].frequency, table[index].index);
if (ret)
return ret;
pr_debug("cpufreq: cpu%d init at %d switching to %d\n",
@@ -309,22 +302,41 @@
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
+ int rc;
- switch (action) {
+ switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
break;
case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
mutex_lock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex);
per_cpu(cpufreq_suspend, cpu).device_suspended = 1;
mutex_unlock(&per_cpu(cpufreq_suspend, cpu).suspend_mutex);
break;
case CPU_DOWN_FAILED:
- case CPU_DOWN_FAILED_FROZEN:
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
break;
+ /*
+ * Scale down clock/power of CPU that is dead and scale it back up
+ * before the CPU is brought up.
+ */
+ case CPU_DEAD:
+ case CPU_UP_CANCELED:
+ if (is_clk) {
+ clk_disable_unprepare(cpu_clk[cpu]);
+ update_l2_bw(NULL);
+ }
+ break;
+ case CPU_UP_PREPARE:
+ if (is_clk) {
+ rc = clk_prepare_enable(cpu_clk[cpu]);
+ if (rc < 0)
+ return NOTIFY_BAD;
+ update_l2_bw(&cpu);
+ }
+ break;
+ default:
+ break;
}
return NOTIFY_OK;
@@ -380,6 +392,242 @@
.attr = msm_freq_attr,
};
+#define PROP_TBL "qcom,cpufreq-table"
+#define PROP_PORTS "qcom,cpu-mem-ports"
+static int cpufreq_parse_dt(struct device *dev)
+{
+ int ret, len, nf, num_cols = 1, num_paths = 0, i, j, k;
+ u32 *data, *ports = NULL;
+ struct msm_bus_vectors *v = NULL;
+
+ if (l2_clk)
+ num_cols++;
+
+ /* Parse optional bus ports parameter */
+ if (of_find_property(dev->of_node, PROP_PORTS, &len)) {
+ len /= sizeof(*ports);
+ if (len % 2)
+ return -EINVAL;
+
+ ports = devm_kzalloc(dev, len * sizeof(*ports), GFP_KERNEL);
+ if (!ports)
+ return -ENOMEM;
+ ret = of_property_read_u32_array(dev->of_node, PROP_PORTS,
+ ports, len);
+ if (ret)
+ return ret;
+ num_paths = len / 2;
+ num_cols++;
+ }
+
+ /* Parse CPU freq -> L2/Mem BW map table. */
+ if (!of_find_property(dev->of_node, PROP_TBL, &len))
+ return -EINVAL;
+ len /= sizeof(*data);
+
+ if (len % num_cols || len == 0)
+ return -EINVAL;
+ nf = len / num_cols;
+
+ data = devm_kzalloc(dev, len * sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(dev->of_node, PROP_TBL, data, len);
+ if (ret)
+ return ret;
+
+ /* Allocate all data structures. */
+ freq_table = devm_kzalloc(dev, (nf + 1) * sizeof(*freq_table),
+ GFP_KERNEL);
+ if (!freq_table)
+ return -ENOMEM;
+
+ if (l2_clk) {
+ l2_khz = devm_kzalloc(dev, nf * sizeof(*l2_khz), GFP_KERNEL);
+ if (!l2_khz)
+ return -ENOMEM;
+ }
+
+ if (num_paths) {
+ int sz_u = nf * sizeof(*bus_bw.usecase);
+ int sz_v = nf * num_paths * sizeof(*bus_vec_lst);
+ bus_bw.usecase = devm_kzalloc(dev, sz_u, GFP_KERNEL);
+ v = bus_vec_lst = devm_kzalloc(dev, sz_v, GFP_KERNEL);
+ if (!bus_bw.usecase || !bus_vec_lst)
+ return -ENOMEM;
+ }
+
+ j = 0;
+ for (i = 0; i < nf; i++) {
+ unsigned long f;
+
+ f = clk_round_rate(cpu_clk[0], data[j++] * 1000);
+ if (IS_ERR_VALUE(f))
+ break;
+ f /= 1000;
+
+ /*
+ * Check if this is the last feasible frequency in the table.
+ *
+ * The table listing frequencies higher than what the HW can
+ * support is not an error since the table might be shared
+ * across CPUs in different speed bins. It's also not
+ * sufficient to check if the rounded rate is lower than the
+ * requested rate as it doesn't cover the following example:
+ *
+ * Table lists: 2.2 GHz and 2.5 GHz.
+ * Rounded rate returns: 2.2 GHz and 2.3 GHz.
+ *
+ * In this case, we can CPUfreq to use 2.2 GHz and 2.3 GHz
+ * instead of rejecting the 2.5 GHz table entry.
+ */
+ if (i > 0 && f <= freq_table[i-1].frequency)
+ break;
+
+ freq_table[i].index = i;
+ freq_table[i].frequency = f;
+
+ if (l2_clk) {
+ f = clk_round_rate(l2_clk, data[j++] * 1000);
+ if (IS_ERR_VALUE(f)) {
+ pr_err("Error finding L2 rate for CPU %d KHz\n",
+ freq_table[i].frequency);
+ freq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+ } else {
+ f /= 1000;
+ l2_khz[i] = f;
+ }
+ }
+
+ if (num_paths) {
+ unsigned int bw_mbps = data[j++];
+ bus_bw.usecase[i].num_paths = num_paths;
+ bus_bw.usecase[i].vectors = v;
+ for (k = 0; k < num_paths; k++) {
+ v->src = ports[k * 2];
+ v->dst = ports[k * 2 + 1];
+ v->ib = bw_mbps * 1000000ULL;
+ v++;
+ }
+ }
+ }
+
+ bus_bw.num_usecases = i;
+ freq_table[i].index = i;
+ freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+ if (ports)
+ devm_kfree(dev, ports);
+ devm_kfree(dev, data);
+
+ return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int msm_cpufreq_show(struct seq_file *m, void *unused)
+{
+ unsigned int i, cpu_freq;
+ uint64_t ib;
+
+ if (!freq_table)
+ return 0;
+
+ seq_printf(m, "%10s%10s", "CPU (KHz)", "L2 (KHz)");
+ if (bus_bw.usecase)
+ seq_printf(m, "%12s", "Mem (MBps)");
+ seq_printf(m, "\n");
+
+ for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ cpu_freq = freq_table[i].frequency;
+ if (cpu_freq == CPUFREQ_ENTRY_INVALID)
+ continue;
+ seq_printf(m, "%10d", cpu_freq);
+ seq_printf(m, "%10d", l2_khz ? l2_khz[i] : cpu_freq);
+ if (bus_bw.usecase) {
+ ib = bus_bw.usecase[i].vectors[0].ib;
+ do_div(ib, 1000000);
+ seq_printf(m, "%12llu", ib);
+ }
+ seq_printf(m, "\n");
+ }
+ return 0;
+}
+
+static int msm_cpufreq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, msm_cpufreq_show, inode->i_private);
+}
+
+const struct file_operations msm_cpufreq_fops = {
+ .open = msm_cpufreq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+#endif
+
+static int __init msm_cpufreq_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ char clk_name[] = "cpu??_clk";
+ struct clk *c;
+ int cpu, ret;
+
+ l2_clk = devm_clk_get(dev, "l2_clk");
+ if (IS_ERR(l2_clk))
+ l2_clk = NULL;
+
+ for_each_possible_cpu(cpu) {
+ snprintf(clk_name, sizeof(clk_name), "cpu%d_clk", cpu);
+ c = devm_clk_get(dev, clk_name);
+ if (!IS_ERR(c))
+ cpu_clk[cpu] = c;
+ else
+ is_sync = true;
+ }
+
+ if (!cpu_clk[0])
+ return -ENODEV;
+
+ ret = cpufreq_parse_dt(dev);
+ if (ret)
+ return ret;
+
+ for_each_possible_cpu(cpu) {
+ cpufreq_frequency_table_get_attr(freq_table, cpu);
+ }
+
+ if (bus_bw.usecase) {
+ bus_client = msm_bus_scale_register_client(&bus_bw);
+ if (!bus_client)
+ dev_warn(dev, "Unable to register bus client\n");
+ }
+
+ is_clk = true;
+
+#ifdef CONFIG_DEBUG_FS
+ if (!debugfs_create_file("msm_cpufreq", S_IRUGO, NULL, NULL,
+ &msm_cpufreq_fops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static struct of_device_id match_table[] = {
+ { .compatible = "qcom,msm-cpufreq" },
+ {}
+};
+
+static struct platform_driver msm_cpufreq_plat_driver = {
+ .driver = {
+ .name = "msm-cpufreq",
+ .of_match_table = match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
static int __init msm_cpufreq_register(void)
{
int cpu;
@@ -389,9 +637,9 @@
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
}
+ platform_driver_probe(&msm_cpufreq_plat_driver, msm_cpufreq_probe);
msm_cpufreq_wq = alloc_workqueue("msm-cpufreq", WQ_HIGHPRI, 0);
register_hotcpu_notifier(&msm_cpufreq_cpu_notifier);
-
return cpufreq_register_driver(&msm_cpufreq_driver);
}
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 7c06268..c480e56 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -112,8 +112,8 @@
continue;
state = &msm_cpuidle_driver.states[state_count];
- snprintf(state->name, CPUIDLE_NAME_LEN, cstate->name);
- snprintf(state->desc, CPUIDLE_DESC_LEN, cstate->desc);
+ snprintf(state->name, CPUIDLE_NAME_LEN, "%s", cstate->name);
+ snprintf(state->desc, CPUIDLE_DESC_LEN, "%s", cstate->desc);
state->flags = 0;
state->exit_latency = 0;
state->power_usage = 0;
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index f8a32b4..2956bd6 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -180,6 +180,7 @@
mov r2, #1
and r1, r2, r1, ASR #30 /* Check if the cache is write back */
orr r1, r0, r1
+ and r1, r1, #1
cmp r1, #1
bne skip
bl v7_flush_dcache_all
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 75dc240..027606e 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -17,6 +17,7 @@
#define __MACH_CLK_PROVIDER_H
#include <linux/types.h>
+#include <linux/err.h>
#include <linux/list.h>
#include <linux/clkdev.h>
#include <linux/spinlock.h>
@@ -93,6 +94,14 @@
.lock = __MUTEX_INITIALIZER(_name.lock) \
}
+#define DEFINE_VDD_REGS_INIT(_name, _num_regulators) \
+ struct clk_vdd_class _name = { \
+ .class_name = #_name, \
+ .regulator = (struct regulator * [_num_regulators]) {}, \
+ .num_regulators = _num_regulators, \
+ .lock = __MUTEX_INITIALIZER(_name.lock) \
+ }
+
enum handoff {
HANDOFF_ENABLED_CLK,
HANDOFF_DISABLED_CLK,
@@ -188,4 +197,13 @@
#define CLK_LOOKUP(con, c, dev) { .con_id = con, .clk = &c, .dev_id = dev }
+static inline bool is_better_rate(unsigned long req, unsigned long best,
+ unsigned long new)
+{
+ if (IS_ERR_VALUE(new))
+ return false;
+
+ return (req <= new && new < best) || (best < req && best < new);
+}
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/clock-generic.h b/arch/arm/mach-msm/include/mach/clock-generic.h
index f6feda0..30a2b93 100644
--- a/arch/arm/mach-msm/include/mach/clock-generic.h
+++ b/arch/arm/mach-msm/include/mach/clock-generic.h
@@ -46,10 +46,14 @@
struct clk *safe_parent;
int safe_sel;
struct clk_mux_ops *ops;
+ /* Recursively search for the requested parent. */
+ bool rec_set_par;
/* Fields not used by helper function. */
void *const __iomem *base;
u32 offset;
+ u32 en_offset;
+ int en_reg;
u32 mask;
u32 shift;
u32 en_mask;
@@ -63,6 +67,8 @@
return container_of(c, struct mux_clk, c);
}
+int parent_to_src_sel(struct clk_src *parents, int num_parents, struct clk *p);
+
extern struct clk_ops clk_ops_gen_mux;
/* ==================== Divider clock ==================== */
@@ -77,11 +83,16 @@
void (*disable)(struct div_clk *clk);
};
+struct div_data {
+ unsigned int div;
+ unsigned int min_div;
+ unsigned int max_div;
+ unsigned long rate_margin;
+};
+
struct div_clk {
- unsigned int div;
- unsigned int min_div;
- unsigned int max_div;
- unsigned long rate_margin;
+ struct div_data data;
+
/* Optional */
struct clk_div_ops *ops;
@@ -103,9 +114,17 @@
extern struct clk_ops clk_ops_div;
extern struct clk_ops clk_ops_slave_div;
+struct ext_clk {
+ struct clk c;
+};
+
+extern struct clk_ops clk_ops_ext;
+
#define DEFINE_FIXED_DIV_CLK(clk_name, _div, _parent) \
static struct div_clk clk_name = { \
- .div = _div, \
+ .data = { \
+ .div = _div, \
+ }, \
.c = { \
.parent = _parent, \
.dbg_name = #clk_name, \
@@ -116,7 +135,9 @@
#define DEFINE_FIXED_SLAVE_DIV_CLK(clk_name, _div, _parent) \
static struct div_clk clk_name = { \
- .div = _div, \
+ .data = { \
+ .div = _div, \
+ }, \
.c = { \
.parent = _parent, \
.dbg_name = #clk_name, \
@@ -125,4 +146,90 @@
} \
}
+#define DEFINE_EXT_CLK(clk_name, _parent) \
+static struct ext_clk clk_name = { \
+ .c = { \
+ .parent = _parent, \
+ .dbg_name = #clk_name, \
+ .ops = &clk_ops_ext, \
+ CLK_INIT(clk_name.c), \
+ } \
+}
+
+/* ==================== Mux Div clock ==================== */
+
+struct mux_div_clk;
+
+/*
+ * struct mux_div_ops
+ * the enable and disable ops are optional.
+ */
+
+struct mux_div_ops {
+ int (*set_src_div)(struct mux_div_clk *, u32 src_sel, u32 div);
+ void (*get_src_div)(struct mux_div_clk *, u32 *src_sel, u32 *div);
+ int (*enable)(struct mux_div_clk *);
+ void (*disable)(struct mux_div_clk *);
+ bool (*is_enabled)(struct mux_div_clk *);
+};
+
+/*
+ * struct mux_div_clk - combined mux/divider clock
+ * @priv
+ parameters needed by ops
+ * @safe_freq
+ when switching rates from A to B, the mux div clock will
+ instead switch from A -> safe_freq -> B. This allows the
+ mux_div clock to change rates while enabled, even if this
+ behavior is not supported by the parent clocks.
+
+ If changing the rate of parent A also causes the rate of
+ parent B to change, then safe_freq must be defined.
+
+ safe_freq is expected to have a source clock which is always
+ on and runs at only one rate.
+ * @parents
+ list of parents and mux indicies
+ * @ops
+ function pointers for hw specific operations
+ * @src_sel
+ the mux index which will be used if the clock is enabled.
+ */
+
+struct mux_div_clk {
+ /* Required parameters */
+ struct mux_div_ops *ops;
+ struct div_data data;
+ struct clk_src *parents;
+ u32 num_parents;
+
+ struct clk c;
+
+ /* Internal */
+ u32 src_sel;
+
+ /* Optional parameters */
+ void *priv;
+ void __iomem *base;
+ u32 div_mask;
+ u32 div_offset;
+ u32 div_shift;
+ u32 src_mask;
+ u32 src_offset;
+ u32 src_shift;
+ u32 en_mask;
+ u32 en_offset;
+
+ u32 safe_div;
+ struct clk *safe_parent;
+ unsigned long safe_freq;
+};
+
+static inline struct mux_div_clk *to_mux_div_clk(struct clk *clk)
+{
+ return container_of(clk, struct mux_div_clk, c);
+}
+
+extern struct clk_ops clk_ops_mux_div_clk;
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/cpufreq.h b/arch/arm/mach-msm/include/mach/cpufreq.h
deleted file mode 100644
index 1a6f2d9..0000000
--- a/arch/arm/mach-msm/include/mach/cpufreq.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H
-#define __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H
-
-#define MSM_CPUFREQ_NO_LIMIT 0xFFFFFFFF
-
-#ifdef CONFIG_CPU_FREQ_MSM
-
-/**
- * msm_cpufreq_set_freq_limit() - Set max/min freq limits on cpu
- *
- * @cpu: The cpu core for which the limits apply
- * @max: The max frequency allowed
- * @min: The min frequency allowed
- *
- * If the @max or @min is set to MSM_CPUFREQ_NO_LIMIT, the limit
- * will default to the CPUFreq limit.
- *
- * returns 0 on success, errno on failure
- */
-extern int msm_cpufreq_set_freq_limits(
- uint32_t cpu, uint32_t min, uint32_t max);
-#else
-static inline int msm_cpufreq_set_freq_limits(
- uint32_t cpu, uint32_t min, uint32_t max)
-{
- return -ENOSYS;
-}
-#endif
-
-#endif /* __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H */
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 20a5249..1d5e0d9 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -553,7 +553,8 @@
ida_simple_remove(&domain_nums, data->domain_num);
for (i = 0; i < data->npools; ++i)
- gen_pool_destroy(data->pools[i].gpool);
+ if (data->pools[i].gpool)
+ gen_pool_destroy(data->pools[i].gpool);
kfree(data->pools);
kfree(data);
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 4fee0ae..f4456c0 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -222,6 +222,7 @@
int ldo_threshold_uV;
int ldo_delta_uV;
int cpu_num;
+ bool ldo_disable;
int coeff1;
int coeff2;
bool reg_en;
@@ -656,6 +657,9 @@
{
struct krait_power_vreg *kvreg = info;
+ if (kvreg->ldo_disable)
+ return;
+
/*
* if the krait is in ldo mode and a voltage change is requested on the
* ldo switch to using hs before changing ldo voltage
@@ -1052,6 +1056,7 @@
(int)action, cpu, cpu_online(cpu));
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
+ case CPU_UP_CANCELED:
mutex_lock(&pvreg->krait_power_vregs_lock);
kvreg->force_bhs = true;
/*
@@ -1062,7 +1067,6 @@
__switch_to_using_bhs(kvreg);
mutex_unlock(&pvreg->krait_power_vregs_lock);
break;
- case CPU_UP_CANCELED:
case CPU_ONLINE:
mutex_lock(&pvreg->krait_power_vregs_lock);
kvreg->force_bhs = false;
@@ -1173,6 +1177,9 @@
& readl_relaxed(kvreg->reg_base + CPU_PWR_CTL);
kvreg->online_at_probe
= online ? (WAIT_FOR_LOAD | WAIT_FOR_VOLTAGE) : 0x0;
+
+ if (online)
+ kvreg->force_bhs = false;
}
static void glb_init(void __iomem *apcs_gcc_base)
@@ -1197,6 +1204,7 @@
int headroom_uV, retention_uV, ldo_default_uV, ldo_threshold_uV;
int ldo_delta_uV;
int cpu_num;
+ bool ldo_disable = false;
if (pdev->dev.of_node) {
/* Get init_data from device tree. */
@@ -1280,6 +1288,9 @@
pr_err("bad cpu-num= %d specified\n", cpu_num);
return -EINVAL;
}
+
+ ldo_disable = of_property_read_bool(pdev->dev.of_node,
+ "qcom,ldo-disable");
}
if (!init_data) {
@@ -1333,6 +1344,8 @@
kvreg->ldo_threshold_uV = ldo_threshold_uV;
kvreg->ldo_delta_uV = ldo_delta_uV;
kvreg->cpu_num = cpu_num;
+ kvreg->ldo_disable = ldo_disable;
+ kvreg->force_bhs = true;
platform_set_drvdata(pdev, kvreg);
@@ -1623,6 +1636,12 @@
void *mdd_base;
struct krait_power_vreg *kvreg;
+ if (version == 0) {
+ gcc_base_ptr = ioremap_nocache(GCC_BASE, SZ_4K);
+ version = readl_relaxed(gcc_base_ptr + VERSION);
+ iounmap(gcc_base_ptr);
+ }
+
/* Turn on the BHS, turn off LDO Bypass and power down LDO */
reg_val = BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
| LDO_PWR_DWN_MASK
@@ -1630,23 +1649,14 @@
| BHS_EN_MASK;
writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
- if (version == 0) {
- gcc_base_ptr = ioremap_nocache(GCC_BASE, SZ_4K);
- version = readl_relaxed(gcc_base_ptr + VERSION);
- iounmap(gcc_base_ptr);
- }
+ /* complete the above write before the delay */
+ mb();
+ /* wait for the bhs to settle */
+ udelay(BHS_SETTLING_DELAY_US);
- /* Turn on the BHS segments only for version < 2 */
- if (version <= KPSS_VERSION_2P0) {
- /* complete the above write before the delay */
- mb();
- /* wait for the bhs to settle */
- udelay(BHS_SETTLING_DELAY_US);
-
- /* Turn on BHS segments */
- reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
- writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
- }
+ /* Turn on BHS segments */
+ reg_val |= BHS_SEG_EN_DEFAULT << BHS_SEG_EN_BIT_POS;
+ writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
/* complete the above write before the delay */
mb();
diff --git a/arch/arm/mach-msm/msm_watchdog_v2.c b/arch/arm/mach-msm/msm_watchdog_v2.c
index 52e94e6..ead2e95 100644
--- a/arch/arm/mach-msm/msm_watchdog_v2.c
+++ b/arch/arm/mach-msm/msm_watchdog_v2.c
@@ -68,7 +68,7 @@
/*
* On the kernel command line specify
- * msm_watchdog.enable=1 to enable the watchdog
+ * msm_watchdog_v2.enable=1 to enable the watchdog
* By default watchdog is turned on
*/
static int enable = 1;
@@ -76,7 +76,7 @@
/*
* On the kernel command line specify
- * msm_watchdog.WDT_HZ=<clock val in HZ> to set Watchdog
+ * msm_watchdog_v2.WDT_HZ=<clock val in HZ> to set Watchdog
* ticks. By default it is set to 32765.
*/
static long WDT_HZ = 32765;
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index af21584..c8a6496 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -16,6 +16,8 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
#include <linux/completion.h>
#include <linux/cpuidle.h>
#include <linux/interrupt.h>
@@ -82,6 +84,8 @@
module_param_named(sleep_time_override,
msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
+static bool use_acpuclk_apis;
+
enum {
MSM_PM_DEBUG_SUSPEND = BIT(0),
MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
@@ -135,6 +139,9 @@
static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
static bool msm_pm_pc_reset_timer;
+DEFINE_PER_CPU(struct clk *, cpu_clks);
+static struct clk *l2_clk;
+
static int msm_pm_get_pc_mode(struct device_node *node,
const char *key, uint32_t *pc_mode_val)
{
@@ -560,6 +567,58 @@
return collapsed;
}
+static int ramp_down_last_cpu(int cpu)
+{
+ struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
+ int ret = 0;
+
+ if (use_acpuclk_apis) {
+ ret = acpuclk_power_collapse();
+ if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: change clk rate(old rate = %d)\n",
+ cpu, __func__, ret);
+ } else {
+ clk_disable(cpu_clk);
+ clk_disable(l2_clk);
+ }
+ return ret;
+}
+
+static int ramp_up_first_cpu(int cpu, int saved_rate)
+{
+ struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
+ int rc = 0;
+
+ if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: restore clock rate\n",
+ cpu, __func__);
+
+ if (use_acpuclk_apis) {
+ rc = acpuclk_set_rate(cpu, saved_rate, SETRATE_PC);
+ if (rc)
+ pr_err("CPU:%u: Error restoring cpu clk\n", cpu);
+ } else {
+ if (l2_clk) {
+ rc = clk_enable(l2_clk);
+ if (rc)
+ pr_err("%s(): Error restoring l2 clk\n",
+ __func__);
+ }
+
+ if (cpu_clk) {
+ int ret = clk_enable(cpu_clk);
+
+ if (ret) {
+ pr_err("%s(): Error restoring cpu clk\n",
+ __func__);
+ return ret;
+ }
+ }
+ }
+
+ return rc;
+}
+
static bool msm_pm_power_collapse(bool from_idle)
{
unsigned int cpu = smp_processor_id();
@@ -581,11 +640,7 @@
avs_set_avscsr(0); /* Disable AVS */
if (cpu_online(cpu) && !msm_no_ramp_down_pc)
- saved_acpuclk_rate = acpuclk_power_collapse();
-
- if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
- pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
- cpu, __func__, saved_acpuclk_rate);
+ saved_acpuclk_rate = ramp_down_last_cpu(cpu);
if (cp15_data.save_cp15)
msm_pm_save_cpu_reg();
@@ -595,15 +650,8 @@
if (cp15_data.save_cp15)
msm_pm_restore_cpu_reg();
- if (cpu_online(cpu)) {
- if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
- pr_info("CPU%u: %s: restore clock rate to %lu\n",
- cpu, __func__, saved_acpuclk_rate);
- if (!msm_no_ramp_down_pc &&
- acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC)
- < 0)
- pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
- cpu, __func__, saved_acpuclk_rate);
+ if (cpu_online(cpu) && !msm_no_ramp_down_pc) {
+ ramp_up_first_cpu(cpu, saved_acpuclk_rate);
} else {
unsigned int gic_dist_enabled;
unsigned int gic_dist_pending;
@@ -1617,6 +1665,46 @@
.llseek = no_llseek,
};
+static int msm_pm_clk_init(struct platform_device *pdev)
+{
+ bool synced_clocks;
+ u32 cpu;
+ char clk_name[] = "cpu??_clk";
+ bool cpu_as_clocks;
+ char *key;
+
+ key = "qcom,cpus-as-clocks";
+ cpu_as_clocks = of_property_read_bool(pdev->dev.of_node, key);
+
+ if (!cpu_as_clocks) {
+ use_acpuclk_apis = true;
+ return 0;
+ }
+
+ key = "qcom,synced-clocks";
+ synced_clocks = of_property_read_bool(pdev->dev.of_node, key);
+
+ for_each_possible_cpu(cpu) {
+ struct clk *clk;
+ snprintf(clk_name, sizeof(clk_name), "cpu%d_clk", cpu);
+ clk = devm_clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(clk)) {
+ if (cpu && synced_clocks)
+ return 0;
+ else
+ return PTR_ERR(clk);
+ }
+ per_cpu(cpu_clks, cpu) = clk;
+ }
+
+ if (synced_clocks)
+ return 0;
+
+ l2_clk = devm_clk_get(&pdev->dev, "l2_clk");
+
+ return PTR_RET(l2_clk);
+}
+
static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
{
char *key = NULL;
@@ -1661,6 +1749,12 @@
memcpy(&pdata_local, d, sizeof(struct msm_pm_init_data_type));
} else {
+ ret = msm_pm_clk_init(pdev);
+ if (ret) {
+ pr_info("msm_pm_clk_init returned error\n");
+ return ret;
+ }
+
key = "qcom,pc-mode";
ret = msm_pm_get_pc_mode(pdev->dev.of_node,
key,
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
index 85af4a7..ccacd3e 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -99,7 +99,7 @@
int audio_in_disable(struct q6audio_in *audio)
{
int rc = 0;
- if (audio->opened) {
+ if (!audio->stopped) {
audio->enabled = 0;
audio->opened = 0;
pr_debug("%s:session id %d: inbytes[%d] insamples[%d]\n",
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index a1463bc..5fa7b1b 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -179,6 +179,16 @@
pr_err("%s[%p]: pause cmd failed rc=%d\n",
__func__, audio, rc);
+ if (rc == 0) {
+ /* Send suspend only if pause was successful */
+ rc = q6asm_cmd(audio->ac, CMD_SUSPEND);
+ if (rc < 0)
+ pr_err("%s[%p]: suspend cmd failed rc=%d\n",
+ __func__, audio, rc);
+ } else
+ pr_err("%s[%p]: not sending suspend since pause failed\n",
+ __func__, audio);
+
} else
pr_err("%s[%p]: Driver not enabled\n", __func__, audio);
return rc;
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index 923e647..faf774f 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -1266,14 +1266,16 @@
{
struct device *dev = &pdev->dev;
struct rpm_regulator *reg;
+ struct rpm_vreg *rpm_vreg;
reg = platform_get_drvdata(pdev);
if (reg) {
- rpm_vreg_lock(reg->rpm_vreg);
+ rpm_vreg = reg->rpm_vreg;
+ rpm_vreg_lock(rpm_vreg);
regulator_unregister(reg->rdev);
list_del(®->list);
kfree(reg);
- rpm_vreg_unlock(reg->rpm_vreg);
+ rpm_vreg_unlock(rpm_vreg);
} else {
dev_err(dev, "%s: drvdata missing\n", __func__);
return -EINVAL;
diff --git a/arch/arm/mach-msm/sensors_adsp.c b/arch/arm/mach-msm/sensors_adsp.c
index 1534358..fab10b8 100644
--- a/arch/arm/mach-msm/sensors_adsp.c
+++ b/arch/arm/mach-msm/sensors_adsp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -355,6 +355,7 @@
if (temp == NULL) {
pr_err("%s: allocation failure\n", __func__);
rv = -ENOMEM;
+ goto out;
}
hdr->dst_module = SNS_OCMEM_MODULE_ADSP;
@@ -387,6 +388,7 @@
kfree(temp);
+out:
return rv;
}
@@ -874,7 +876,7 @@
vectors = ocmem_get_vectors(SNS_OCMEM_CLIENT_ID, sns_ctl.buf);
if ((vectors != NULL)) {
- memcpy(&msg.vectors, vectors, sizeof(vectors));
+ memcpy(&msg.vectors, vectors, sizeof(*vectors));
/* TODO: set vectors_len */
msg.vectors_valid = true;
msg.vectors_len = 0;
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 110ab87..cb9697d 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -3243,7 +3243,7 @@
*/
void smd_set_edge_subsys_name(uint32_t edge, const char *subsys_name)
{
- if (edge <= ARRAY_SIZE(edge_to_pids))
+ if (edge < ARRAY_SIZE(edge_to_pids))
strlcpy(edge_to_pids[edge].subsys_name,
subsys_name, SMD_MAX_CH_NAME_LEN);
else
@@ -3258,7 +3258,7 @@
*/
void smd_set_edge_initialized(uint32_t edge)
{
- if (edge <= ARRAY_SIZE(edge_to_pids))
+ if (edge < ARRAY_SIZE(edge_to_pids))
edge_to_pids[edge].initialized = true;
else
pr_err("%s: Invalid edge type[%d]\n", __func__, edge);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 8af3890..4b68e66 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -1080,7 +1080,7 @@
msm_get_image_crm_version, msm_set_image_crm_version);
static struct device_attribute select_image =
- __ATTR(select_image, S_IRUGO | S_IWUGO,
+ __ATTR(select_image, S_IRUGO | S_IWUSR,
msm_get_image_number, msm_select_image);
static struct sysdev_class soc_sysdev_class = {
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 1d12b07..9a1a2eb 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -85,6 +85,7 @@
}
#ifdef CONFIG_SMP
thread->vfpstate.hard.cpu = NR_CPUS;
+ vfp_current_hw_state[cpu] = NULL;
#endif
}
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index c5f9021..fbf4eeb 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -77,7 +77,7 @@
printk("Mem-info:\n");
show_free_areas(filter);
printk("Free swap: %6ldkB\n",
- nr_swap_pages << (PAGE_SHIFT-10));
+ get_nr_swap_pages() << (PAGE_SHIFT-10));
printk("%ld pages of RAM\n", totalram_pages);
printk("%ld free pages\n", nr_free_pages());
#if 0 /* undefined pgtable_cache_size, pgd_cache_size */
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
index 2410aa8..ea7dd38 100644
--- a/arch/tile/mm/pgtable.c
+++ b/arch/tile/mm/pgtable.c
@@ -61,7 +61,7 @@
global_page_state(NR_PAGETABLE),
global_page_state(NR_BOUNCE),
global_page_state(NR_FILE_PAGES),
- nr_swap_pages);
+ get_nr_swap_pages());
for_each_zone(zone) {
unsigned long flags, order, total = 0, largest_order = -1;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 97dc26d..91b90a8 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -419,6 +419,8 @@
/* Notify the DCI process that the peripheral DCI Channel is up */
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
+ if (!driver->dci_client_tbl[i].client)
+ continue;
if (driver->dci_client_tbl[i].list & peripheral_mask) {
info.si_signo = driver->dci_client_tbl[i].signal_type;
stat = send_sig_info(
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 69e6250..c28b3bd 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -229,83 +229,90 @@
static void diag_disable_log_mask(void)
{
int i = 0;
- struct mask_info *parse_ptr = (struct mask_info *)(driver->log_masks);
+ struct diag_log_mask_t *log_item = NULL;
- pr_debug("diag: disable log masks\n");
- mutex_lock(&driver->diagchar_mutex);
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- pr_debug("diag: equip id %d\n", parse_ptr->equip_id);
- if (!(parse_ptr->equip_id)) /* Reached a null entry */
- break;
- memset(driver->log_masks + parse_ptr->index, 0,
- (parse_ptr->num_items + 7)/8);
- parse_ptr++;
- }
+ mutex_lock(&driver->log_mask_mutex);
+ log_item = (struct diag_log_mask_t *)driver->log_masks;
+ for (i = 0; i < MAX_EQUIP_ID; i++, log_item++)
+ memset(log_item->ptr, 0, MAX_ITEMS_PER_EQUIP_ID);
+
driver->log_status = DIAG_CTRL_MASK_ALL_DISABLED;
- mutex_unlock(&driver->diagchar_mutex);
+ mutex_unlock(&driver->log_mask_mutex);
}
-int chk_equip_id_and_mask(int equip_id, uint8_t *buf)
+static int copy_log_mask_equip(int equip_id, uint8_t *buf)
{
- int i = 0, flag = 0, num_items, offset;
- unsigned char *ptr_data;
- struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+ int i, ret = 0;
+ uint8_t *temp = buf;
+ struct diag_log_mask_t *log_item = NULL;
+ uint32_t mask_size = 0;
- pr_debug("diag: received equip id = %d\n", equip_id);
- /* Check if this is valid equipment ID */
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
- offset = ptr->index;
- num_items = ptr->num_items;
- flag = 1;
+ if (!buf)
+ return ret;
+
+ log_item = (struct diag_log_mask_t *)driver->log_masks;
+ for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+ if (log_item->equip_id != equip_id)
+ continue;
+ *(int *)temp = log_item->equip_id;
+ temp += sizeof(int);
+ *(int *)(temp) = log_item->num_items;
+ temp += sizeof(int);
+ mask_size = LOG_ITEMS_TO_SIZE(log_item->num_items);
+ if (mask_size > MAX_ITEMS_PER_EQUIP_ID) {
+ pr_err("diag: Invalid length: %d in %s, perimissible: %d",
+ mask_size, __func__, MAX_ITEMS_PER_EQUIP_ID);
break;
}
- ptr++;
+ if (mask_size > 0) {
+ memcpy(temp, log_item->ptr, mask_size);
+ /*
+ * Return the total number of bytes copied = size of
+ * equip_id (int) + size of num_items (int) + mask_size
+ */
+ ret = (2 * sizeof(int)) + mask_size;
+ }
+ break;
}
- if (!flag)
- return -EPERM;
- ptr_data = driver->log_masks + offset;
- memcpy(buf, ptr_data, (num_items+7)/8);
- return 0;
+
+ return ret;
}
static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
{
- uint8_t *temp = buf;
int i = 0;
- unsigned char *ptr_data;
- int offset = (sizeof(struct mask_info))*MAX_EQUIP_ID;
- struct mask_info *ptr = (struct mask_info *)(driver->log_masks);
+ struct diag_log_mask_t *log_item = NULL;
+ uint32_t mask_size = 0;
- pr_debug("diag: received equip id = %d\n", equip_id);
- mutex_lock(&driver->diagchar_mutex);
- /* Check if we already know index of this equipment ID */
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- if ((ptr->equip_id == equip_id) && (ptr->index != 0)) {
- offset = ptr->index;
- break;
- }
- if ((ptr->equip_id == 0) && (ptr->index == 0)) {
- /* Reached a null entry */
- ptr->equip_id = equip_id;
- ptr->num_items = num_items;
- ptr->index = driver->log_masks_length;
- offset = driver->log_masks_length;
- driver->log_masks_length += ((num_items+7)/8);
- break;
- }
- ptr++;
+ mutex_lock(&driver->log_mask_mutex);
+ driver->log_status = DIAG_CTRL_MASK_INVALID;
+ if (!buf || (equip_id < 0 || equip_id >= MAX_EQUIP_ID) ||
+ num_items < 1) {
+ pr_err("diag: Invalid params in %s, buf: %x equip_id: %d, num_items: %d\n",
+ __func__, (unsigned int)buf, equip_id, num_items);
+ mutex_unlock(&driver->log_mask_mutex);
+ return;
}
- ptr_data = driver->log_masks + offset;
- if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
- + LOG_MASK_SIZE, (num_items+7)/8)) {
- memcpy(ptr_data, temp, (num_items+7)/8);
+ mask_size = LOG_ITEMS_TO_SIZE(num_items);
+ if (mask_size > MAX_ITEMS_PER_EQUIP_ID) {
+ pr_err("diag: In %s, Invalid mask_size %d\n", __func__,
+ mask_size);
+ mutex_unlock(&driver->log_mask_mutex);
+ return;
+ }
+
+ log_item = (struct diag_log_mask_t *)driver->log_masks;
+ for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+ if (log_item->equip_id != equip_id)
+ continue;
+ /* Found the equip id */
+ log_item->num_items = num_items;
+ if (mask_size > 0)
+ memcpy(log_item->ptr, buf, mask_size);
driver->log_status = DIAG_CTRL_MASK_VALID;
- } else {
- pr_err("diag: Not enough buffer space for LOG_MASK\n");
- driver->log_status = DIAG_CTRL_MASK_INVALID;
+ break;
}
- mutex_unlock(&driver->diagchar_mutex);
+ mutex_unlock(&driver->log_mask_mutex);
}
void diag_mask_update_fn(struct work_struct *work)
@@ -335,72 +342,76 @@
void diag_send_log_mask_update(smd_channel_t *ch, int equip_id)
{
void *buf = driver->buf_log_mask_update;
- int header_size = sizeof(struct diag_ctrl_log_mask);
- struct mask_info *ptr = (struct mask_info *)driver->log_masks;
- int i, size, wr_size = -ENOMEM, retry_count = 0;
+ struct diag_log_mask_t *log_item = NULL;
+ struct diag_ctrl_log_mask ctrl_pkt;
+ uint32_t log_mask_size = 0;
+ int wr_size = -ENOMEM, retry_count = 0;
+ int i, header_size, send_once = 0;
+ header_size = sizeof(struct diag_ctrl_log_mask);
+ log_item = (struct diag_log_mask_t *)driver->log_masks;
mutex_lock(&driver->diag_cntl_mutex);
- for (i = 0; i < MAX_EQUIP_ID; i++) {
- size = (ptr->num_items+7)/8;
- /* reached null entry */
- if ((ptr->equip_id == 0) && (ptr->index == 0))
- break;
- driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
- driver->log_mask->num_items = ptr->num_items;
- driver->log_mask->data_len = 11 + size;
- driver->log_mask->stream_id = 1; /* 2, if dual stream */
- driver->log_mask->equip_id = ptr->equip_id;
- driver->log_mask->status = driver->log_status;
+ for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+ if (equip_id != i && equip_id != ALL_EQUIP_ID)
+ continue;
+ log_mask_size = LOG_ITEMS_TO_SIZE(log_item->num_items);
+ ctrl_pkt.cmd_type = DIAG_CTRL_MSG_LOG_MASK;
+ ctrl_pkt.data_len = 11 + log_mask_size;
+ ctrl_pkt.stream_id = 1;
+ ctrl_pkt.status = driver->log_status;
switch (driver->log_status) {
case DIAG_CTRL_MASK_ALL_DISABLED:
- driver->log_mask->log_mask_size = 0;
+ ctrl_pkt.equip_id = 0;
+ ctrl_pkt.num_items = 0;
+ ctrl_pkt.log_mask_size = 0;
+ send_once = 1;
break;
case DIAG_CTRL_MASK_ALL_ENABLED:
- driver->log_mask->log_mask_size = 0;
+ ctrl_pkt.equip_id = 0;
+ ctrl_pkt.num_items = 0;
+ ctrl_pkt.log_mask_size = 0;
+ send_once = 1;
break;
case DIAG_CTRL_MASK_VALID:
- driver->log_mask->log_mask_size = size;
+ ctrl_pkt.equip_id = i;
+ ctrl_pkt.num_items = log_item->num_items;
+ ctrl_pkt.log_mask_size = log_mask_size;
+ send_once = 0;
break;
default:
- /* Log status is not set or the buffer is corrupted */
pr_err("diag: In %s, invalid status %d", __func__,
- driver->log_status);
- driver->log_mask->status = DIAG_CTRL_MASK_INVALID;
- }
-
- if (driver->log_mask->status == DIAG_CTRL_MASK_INVALID) {
+ driver->log_status);
mutex_unlock(&driver->diag_cntl_mutex);
return;
}
- /* send only desired update, NOT ALL */
- if (equip_id == ALL_EQUIP_ID || equip_id ==
- driver->log_mask->equip_id) {
- memcpy(buf, driver->log_mask, header_size);
- if (driver->log_status == DIAG_CTRL_MASK_VALID)
- memcpy(buf + header_size,
- driver->log_masks+ptr->index, size);
- if (ch) {
- while (retry_count < 3) {
- wr_size = smd_write(ch, buf,
- header_size + size);
- if (wr_size == -ENOMEM) {
- retry_count++;
- usleep_range(10000, 10100);
- } else
- break;
- }
- if (wr_size != header_size + size)
- pr_err("diag: log mask update failed %d, tried %d",
- wr_size, header_size + size);
- else
- pr_debug("diag: updated log equip ID %d,len %d\n",
- driver->log_mask->equip_id,
- driver->log_mask->log_mask_size);
- } else
- pr_err("diag: ch not valid for log update\n");
+ memcpy(buf, &ctrl_pkt, header_size);
+ if (log_mask_size > 0) {
+ memcpy(buf + header_size, log_item->ptr,
+ log_mask_size);
}
- ptr++;
+
+ if (ch) {
+ while (retry_count < 3) {
+ wr_size = smd_write(ch, buf,
+ header_size + log_mask_size);
+ if (wr_size == -ENOMEM) {
+ retry_count++;
+ usleep_range(10000, 10100);
+ } else
+ break;
+ }
+ if (wr_size != header_size + log_mask_size)
+ pr_err("diag: log mask update failed %d, tried %d",
+ wr_size, header_size + log_mask_size);
+ else
+ pr_debug("diag: updated log equip ID %d,len %d\n",
+ i, log_mask_size);
+ } else
+ pr_err("diag: ch not valid for log update\n");
+ if (send_once)
+ break;
}
+
mutex_unlock(&driver->diag_cntl_mutex);
}
@@ -623,7 +634,7 @@
int ssid_first, ssid_last, ssid_range;
int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
uint8_t *rt_mask_ptr;
- int equip_id, num_items;
+ int equip_id, copy_len;
#if defined(CONFIG_DIAG_OVER_USB)
int payload_length;
#endif
@@ -631,7 +642,6 @@
/* Set log masks */
if (*buf == 0x73 && *(int *)(buf+4) == 3) {
buf += 8;
- /* Read Equip ID and pass as first param below*/
diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
diag_update_userspace_clients(LOG_MASKS_TYPE);
#if defined(CONFIG_DIAG_OVER_USB)
@@ -639,7 +649,8 @@
driver->apps_rsp_buf[0] = 0x73;
*(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
- payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
+ payload_length = 8 +
+ LOG_ITEMS_TO_SIZE(*(int *)(buf + 4));
if (payload_length > APPS_BUF_SIZE - 12) {
pr_err("diag: log masks: buffer overflow\n");
return -EIO;
@@ -663,20 +674,16 @@
if (!(driver->smd_data[MODEM_DATA].ch) &&
chk_apps_only()) {
equip_id = *(int *)(buf + 8);
- num_items = *(int *)(buf + 12);
driver->apps_rsp_buf[0] = 0x73;
driver->apps_rsp_buf[1] = 0x0;
driver->apps_rsp_buf[2] = 0x0;
driver->apps_rsp_buf[3] = 0x0;
*(int *)(driver->apps_rsp_buf + 4) = 0x4;
- if (!chk_equip_id_and_mask(equip_id,
- driver->apps_rsp_buf+20))
- *(int *)(driver->apps_rsp_buf + 8) = 0x0;
- else
- *(int *)(driver->apps_rsp_buf + 8) = 0x1;
- *(int *)(driver->apps_rsp_buf + 12) = equip_id;
- *(int *)(driver->apps_rsp_buf + 16) = num_items;
- encode_rsp_and_send(20+(num_items+7)/8-1);
+ copy_len = copy_log_mask_equip(equip_id,
+ driver->apps_rsp_buf + 12);
+ *(int *)(driver->apps_rsp_buf + 8) =
+ (copy_len == 0) ? 1 : 0;
+ encode_rsp_and_send(12 + copy_len);
return 0;
}
#endif
@@ -858,6 +865,19 @@
return packet_type;
}
+static void diag_log_mask_init(void)
+{
+ struct diag_log_mask_t *log_item = NULL;
+ uint8_t i;
+
+ mutex_init(&driver->log_mask_mutex);
+ log_item = (struct diag_log_mask_t *)driver->log_masks;
+ for (i = 0; i < MAX_EQUIP_ID; i++, log_item++) {
+ log_item->equip_id = i;
+ log_item->num_items = LOG_GET_ITEM_NUM(log_code_last_tbl[i]);
+ }
+}
+
void diag_masks_init(void)
{
driver->event_status = DIAG_CTRL_MASK_INVALID;
@@ -936,7 +956,7 @@
goto err;
kmemleak_not_leak(driver->log_masks);
}
- driver->log_masks_length = (sizeof(struct mask_info))*MAX_EQUIP_ID;
+ diag_log_mask_init();
if (driver->event_masks == NULL) {
driver->event_masks = kzalloc(EVENT_MASK_SIZE, GFP_KERNEL);
if (driver->event_masks == NULL)
diff --git a/drivers/char/diag/diag_masks.h b/drivers/char/diag/diag_masks.h
index c66a4b6..856d4fc 100644
--- a/drivers/char/diag/diag_masks.h
+++ b/drivers/char/diag/diag_masks.h
@@ -15,7 +15,12 @@
#include "diagfwd.h"
-int chk_equip_id_and_mask(int equip_id, uint8_t *buf);
+struct diag_log_mask_t {
+ uint8_t equip_id;
+ uint32_t num_items;
+ uint8_t ptr[MAX_ITEMS_PER_EQUIP_ID];
+} __packed;
+
void diag_send_event_mask_update(smd_channel_t *, int num_bytes);
void diag_send_msg_mask_update(smd_channel_t *, int ssid_first,
int ssid_last, int proc);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 9d9d89b..5be77c4 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -82,11 +82,14 @@
* And there are MSG_MASK_TBL_CNT rows.
*/
#define MSG_MASK_SIZE ((MAX_SSID_PER_RANGE+3) * 4 * MSG_MASK_TBL_CNT)
-#define LOG_MASK_SIZE 8000
+#define MAX_EQUIP_ID 16
+#define MAX_ITEMS_PER_EQUIP_ID 512
+#define LOG_MASK_ITEM_SIZE (5 + MAX_ITEMS_PER_EQUIP_ID)
+#define LOG_MASK_SIZE (MAX_EQUIP_ID * LOG_MASK_ITEM_SIZE)
#define EVENT_MASK_SIZE 1000
#define USER_SPACE_DATA 8192
#define PKT_SIZE 4096
-#define MAX_EQUIP_ID 15
+
#define DIAG_CTRL_MSG_LOG_MASK 9
#define DIAG_CTRL_MSG_EVENT_MASK 10
#define DIAG_CTRL_MSG_F3_MASK 11
@@ -334,6 +337,7 @@
struct diag_ctrl_log_mask *log_mask;
struct diag_ctrl_msg_mask *msg_mask;
struct diag_ctrl_feature_mask *feature_mask;
+ struct mutex log_mask_mutex;
/* State for diag forwarding */
struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
@@ -380,7 +384,6 @@
uint8_t msg_status;
uint8_t *log_masks;
uint8_t log_status;
- int log_masks_length;
uint8_t *event_masks;
uint8_t event_status;
uint8_t log_on_demand_support;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 19ff6f4..f7c0d24 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1485,26 +1485,25 @@
return err;
}
if (pkt_type == CALLBACK_DATA_TYPE) {
- if (payload_size > itemsize) {
+ if (payload_size > driver->itemsize) {
pr_err("diag: Dropping packet, packet payload size crosses 4KB limit. Current payload size %d\n",
payload_size);
driver->dropped_count++;
return -EBADMSG;
}
- mutex_lock(&driver->diagchar_mutex);
buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY);
if (!buf_copy) {
driver->dropped_count++;
- mutex_unlock(&driver->diagchar_mutex);
return -ENOMEM;
}
err = copy_from_user(buf_copy, buf + 4, payload_size);
if (err) {
pr_err("diag: copy failed for user space data\n");
- ret = -EIO;
- goto fail_free_copy;
+ diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ buf_copy = NULL;
+ return -EIO;
}
/* Check for proc_type */
remote_proc = diag_get_remote(*(int *)buf_copy);
@@ -1513,7 +1512,9 @@
wait_event_interruptible(driver->wait_q,
(driver->in_busy_pktdata == 0));
ret = diag_process_apps_pkt(buf_copy, payload_size);
- goto fail_free_copy;
+ diagmem_free(driver, buf_copy, POOL_TYPE_COPY);
+ buf_copy = NULL;
+ return ret;
}
/* The packet is for the remote processor */
token_offset = 4;
@@ -1526,7 +1527,7 @@
1 + payload_size);
send.terminate = 1;
-
+ mutex_lock(&driver->diagchar_mutex);
if (!buf_hdlc)
buf_hdlc = diagmem_alloc(driver, HDLC_OUT_BUF_SIZE,
POOL_TYPE_HDLC);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index cdd315e..ba3ecc2 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1051,9 +1051,10 @@
return is_mode_reset;
}
-void diag_send_data(struct diag_master_table entry, unsigned char *buf,
+int diag_send_data(struct diag_master_table entry, unsigned char *buf,
int len, int type)
{
+ int success = 1;
driver->pkt_length = len;
/* If the process_id corresponds to an apps process */
@@ -1069,13 +1070,19 @@
if (entry.client_id < NUM_SMD_DATA_CHANNELS) {
struct diag_smd_info *smd_info;
int index = entry.client_id;
+ if (!driver->rcvd_feature_mask[
+ entry.client_id]) {
+ pr_debug("diag: In %s, feature mask for peripheral: %d not received yet\n",
+ __func__, entry.client_id);
+ return 0;
+ }
/*
* Mode reset should work even if
* modem is down
*/
if ((index == MODEM_DATA) &&
diag_check_mode_reset(buf)) {
- return;
+ return 1;
}
smd_info = (driver->separate_cmdrsp[index] &&
index < NUM_SMD_CMD_CHANNELS) ?
@@ -1095,9 +1102,12 @@
} else {
pr_alert("diag: In %s, incorrect channel: %d",
__func__, entry.client_id);
+ success = 0;
}
}
}
+
+ return success;
}
void diag_process_stm_mask(uint8_t cmd, uint8_t data_mask, int data_type,
@@ -1191,6 +1201,7 @@
unsigned char *temp = buf;
int data_type;
int mask_ret;
+ int status = 0;
#if defined(CONFIG_DIAG_OVER_USB)
unsigned char *ptr;
#endif
@@ -1217,14 +1228,15 @@
pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
for (i = 0; i < diag_max_reg; i++) {
entry = driver->table[i];
- if (entry.process_id != NO_PROCESS &&
- driver->rcvd_feature_mask[entry.client_id]) {
+ if (entry.process_id != NO_PROCESS) {
if (entry.cmd_code == cmd_code && entry.subsys_id ==
subsys_id && entry.cmd_code_lo <=
subsys_cmd_code &&
entry.cmd_code_hi >= subsys_cmd_code) {
- diag_send_data(entry, buf, len, data_type);
- packet_type = 0;
+ status = diag_send_data(entry, buf, len,
+ data_type);
+ if (status)
+ packet_type = 0;
} else if (entry.cmd_code == 255
&& cmd_code == 75) {
if (entry.subsys_id ==
@@ -1233,9 +1245,10 @@
subsys_cmd_code &&
entry.cmd_code_hi >=
subsys_cmd_code) {
- diag_send_data(entry, buf, len,
- data_type);
- packet_type = 0;
+ status = diag_send_data(entry, buf,
+ len, data_type);
+ if (status)
+ packet_type = 0;
}
} else if (entry.cmd_code == 255 &&
entry.subsys_id == 255) {
@@ -1243,9 +1256,10 @@
cmd_code &&
entry.
cmd_code_hi >= cmd_code) {
- diag_send_data(entry, buf, len,
+ status = diag_send_data(entry, buf, len,
data_type);
- packet_type = 0;
+ if (status)
+ packet_type = 0;
}
}
}
@@ -1280,22 +1294,38 @@
driver->apps_rsp_buf[0] = 0x73;
*(int *)(driver->apps_rsp_buf + 4) = 0x1; /* operation ID */
*(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success code */
- *(int *)(driver->apps_rsp_buf + 12) = LOG_GET_ITEM_NUM(LOG_0);
- *(int *)(driver->apps_rsp_buf + 16) = LOG_GET_ITEM_NUM(LOG_1);
- *(int *)(driver->apps_rsp_buf + 20) = LOG_GET_ITEM_NUM(LOG_2);
- *(int *)(driver->apps_rsp_buf + 24) = LOG_GET_ITEM_NUM(LOG_3);
- *(int *)(driver->apps_rsp_buf + 28) = LOG_GET_ITEM_NUM(LOG_4);
- *(int *)(driver->apps_rsp_buf + 32) = LOG_GET_ITEM_NUM(LOG_5);
- *(int *)(driver->apps_rsp_buf + 36) = LOG_GET_ITEM_NUM(LOG_6);
- *(int *)(driver->apps_rsp_buf + 40) = LOG_GET_ITEM_NUM(LOG_7);
- *(int *)(driver->apps_rsp_buf + 44) = LOG_GET_ITEM_NUM(LOG_8);
- *(int *)(driver->apps_rsp_buf + 48) = LOG_GET_ITEM_NUM(LOG_9);
- *(int *)(driver->apps_rsp_buf + 52) = LOG_GET_ITEM_NUM(LOG_10);
- *(int *)(driver->apps_rsp_buf + 56) = LOG_GET_ITEM_NUM(LOG_11);
- *(int *)(driver->apps_rsp_buf + 60) = LOG_GET_ITEM_NUM(LOG_12);
- *(int *)(driver->apps_rsp_buf + 64) = LOG_GET_ITEM_NUM(LOG_13);
- *(int *)(driver->apps_rsp_buf + 68) = LOG_GET_ITEM_NUM(LOG_14);
- *(int *)(driver->apps_rsp_buf + 72) = LOG_GET_ITEM_NUM(LOG_15);
+ *(int *)(driver->apps_rsp_buf + 12) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[0]);
+ *(int *)(driver->apps_rsp_buf + 16) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[1]);
+ *(int *)(driver->apps_rsp_buf + 20) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[2]);
+ *(int *)(driver->apps_rsp_buf + 24) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[3]);
+ *(int *)(driver->apps_rsp_buf + 28) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[4]);
+ *(int *)(driver->apps_rsp_buf + 32) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[5]);
+ *(int *)(driver->apps_rsp_buf + 36) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[6]);
+ *(int *)(driver->apps_rsp_buf + 40) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[7]);
+ *(int *)(driver->apps_rsp_buf + 44) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[8]);
+ *(int *)(driver->apps_rsp_buf + 48) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[9]);
+ *(int *)(driver->apps_rsp_buf + 52) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[10]);
+ *(int *)(driver->apps_rsp_buf + 56) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[11]);
+ *(int *)(driver->apps_rsp_buf + 60) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[12]);
+ *(int *)(driver->apps_rsp_buf + 64) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[13]);
+ *(int *)(driver->apps_rsp_buf + 68) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[14]);
+ *(int *)(driver->apps_rsp_buf + 72) =
+ LOG_GET_ITEM_NUM(log_code_last_tbl[15]);
encode_rsp_and_send(75);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 74a252f..57aa835 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -192,6 +192,10 @@
struct qup_i2c_clk_path_vote clk_path_vote;
};
+#ifdef CONFIG_PM
+static int i2c_qup_pm_resume_runtime(struct device *device);
+#endif
+
#ifdef DEBUG
static void
qup_print_status(struct qup_i2c_dev *dev)
@@ -944,7 +948,13 @@
long timeout;
int err;
- pm_runtime_get_sync(dev->dev);
+ /* Alternate if runtime power management is disabled */
+ if (!pm_runtime_enabled(dev->dev)) {
+ dev_dbg(dev->dev, "Runtime PM is disabled\n");
+ i2c_qup_pm_resume_runtime(dev->dev);
+ } else {
+ pm_runtime_get_sync(dev->dev);
+ }
mutex_lock(&dev->mlock);
if (dev->suspended) {
@@ -1754,22 +1764,24 @@
if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
dev_dbg(device, "system suspend");
i2c_qup_pm_suspend_runtime(device);
+ /*
+ * set the device's runtime PM status to 'suspended'
+ */
+ pm_runtime_disable(device);
+ pm_runtime_set_suspended(device);
+ pm_runtime_enable(device);
}
return 0;
}
static int qup_i2c_resume(struct device *device)
{
- int ret = 0;
- if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
- dev_dbg(device, "system resume");
- ret = i2c_qup_pm_resume_runtime(device);
- if (!ret) {
- pm_runtime_mark_last_busy(device);
- pm_request_autosuspend(device);
- }
- return ret;
- }
+ /*
+ * Rely on runtime-PM to call resume in case it is enabled
+ * Even if it's not enabled, rely on 1st client transaction to do
+ * clock ON and gpio configuration
+ */
+ dev_dbg(device, "system resume");
return 0;
}
#endif /* CONFIG_PM */
diff --git a/drivers/input/misc/mma8x5x.c b/drivers/input/misc/mma8x5x.c
index a325d54..91aa928 100644
--- a/drivers/input/misc/mma8x5x.c
+++ b/drivers/input/misc/mma8x5x.c
@@ -53,6 +53,7 @@
#define MMA8X5X_BUF_SIZE 7
#define MMA_SHUTTEDDOWN (1 << 31)
+#define MMA_STATE_MASK (~MMA_SHUTTEDDOWN)
struct sensor_regulator {
struct regulator *vreg;
@@ -349,7 +350,7 @@
struct input_polled_dev *poll_dev = pdata->poll_dev;
struct mma8x5x_data_axis data;
mutex_lock(&pdata->data_lock);
- if (pdata->active == MMA_STANDBY) {
+ 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;
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index ef76e69..9a4301e 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -131,8 +131,9 @@
#define FT_FW_PKT_DLY_MS 20
#define FT_FW_LAST_PKT 0x6ffa
#define FT_EARSE_DLY_MS 100
+#define FT_55_AA_DLY_NS 5000
-#define FT_UPGRADE_LOOP 10
+#define FT_UPGRADE_LOOP 30
#define FT_CAL_START 0x04
#define FT_CAL_FIN 0x00
#define FT_CAL_STORE 0x05
@@ -142,6 +143,30 @@
#define FT_INFO_MAX_LEN 512
+#define FT_BLOADER_SIZE_OFF 12
+#define FT_BLOADER_NEW_SIZE 30
+#define FT_DATA_LEN_OFF_OLD_FW 8
+#define FT_DATA_LEN_OFF_NEW_FW 14
+#define FT_FINISHING_PKT_LEN_OLD_FW 6
+#define FT_FINISHING_PKT_LEN_NEW_FW 12
+#define FT_MAGIC_BLOADER_Z7 0x7bfa
+#define FT_MAGIC_BLOADER_LZ4 0x6ffa
+#define FT_MAGIC_BLOADER_GZF_30 0x7ff4
+#define FT_MAGIC_BLOADER_GZF 0x7bf4
+
+enum {
+ FT_BLOADER_VERSION_LZ4 = 0,
+ FT_BLOADER_VERSION_Z7 = 1,
+ FT_BLOADER_VERSION_GZF = 2,
+};
+
+enum {
+ FT_FT5336_FAMILY_ID_0x11 = 0x11,
+ FT_FT5336_FAMILY_ID_0x12 = 0x12,
+ FT_FT5336_FAMILY_ID_0x13 = 0x13,
+ FT_FT5336_FAMILY_ID_0x14 = 0x14,
+};
+
#define FT_STORE_TS_INFO(buf, id, name, max_tch, group_id, fw_vkey_support, \
fw_name, fw_maj, fw_min, fw_sub_min) \
snprintf(buf, FT_INFO_MAX_LEN, \
@@ -645,11 +670,20 @@
u8 reset_reg;
u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0};
u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN];
- int rc, i, j, temp;
+ int i, j, temp;
u32 pkt_num, pkt_len;
+ u8 is_5336_new_bootloader = false;
+ u8 is_5336_fwsize_30 = false;
u8 fw_ecc;
+ /* determine firmware size */
+ if (*(data + data_len - FT_BLOADER_SIZE_OFF) == FT_BLOADER_NEW_SIZE)
+ is_5336_fwsize_30 = true;
+ else
+ is_5336_fwsize_30 = false;
+
for (i = 0, j = 0; i < FT_UPGRADE_LOOP; i++) {
+ msleep(FT_EARSE_DLY_MS);
/* reset - write 0xaa and 0x55 to reset register */
if (ts_data->family_id == FT6X06_ID)
reset_reg = FT_RST_CMD_REG2;
@@ -660,16 +694,17 @@
msleep(info.delay_aa);
ft5x0x_write_reg(client, reset_reg, FT_UPGRADE_55);
- msleep(info.delay_55);
+ if (i <= (FT_UPGRADE_LOOP / 2))
+ msleep(info.delay_55 + i * 3);
+ else
+ msleep(info.delay_55 - (i - (FT_UPGRADE_LOOP / 2)) * 2);
/* Enter upgrade mode */
w_buf[0] = FT_UPGRADE_55;
- w_buf[1] = FT_UPGRADE_AA;
- do {
- j++;
- rc = ft5x06_i2c_write(client, w_buf, 2);
- msleep(FT_RETRY_DLY);
- } while (rc <= 0 && j < FT_MAX_TRIES);
+ ft5x06_i2c_write(client, w_buf, 1);
+ usleep(FT_55_AA_DLY_NS);
+ w_buf[0] = FT_UPGRADE_AA;
+ ft5x06_i2c_write(client, w_buf, 1);
/* check READ_ID */
msleep(info.delay_readid);
@@ -682,7 +717,9 @@
if (r_buf[0] != info.upgrade_id_1
|| r_buf[1] != info.upgrade_id_2) {
- dev_err(&client->dev, "Upgrade ID mismatch(%d)\n", i);
+ dev_err(&client->dev, "Upgrade ID mismatch(%d), IC=0x%x 0x%x, info=0x%x 0x%x\n",
+ i, r_buf[0], r_buf[1],
+ info.upgrade_id_1, info.upgrade_id_2);
} else
break;
}
@@ -692,17 +729,44 @@
return -EIO;
}
+ w_buf[0] = 0xcd;
+ ft5x06_i2c_read(client, w_buf, 1, r_buf, 1);
+
+ if (r_buf[0] <= 4)
+ is_5336_new_bootloader = FT_BLOADER_VERSION_LZ4;
+ else if (r_buf[0] == 7)
+ is_5336_new_bootloader = FT_BLOADER_VERSION_Z7;
+ else if (r_buf[0] >= 0x0f &&
+ ((ts_data->family_id == FT_FT5336_FAMILY_ID_0x11) ||
+ (ts_data->family_id == FT_FT5336_FAMILY_ID_0x12) ||
+ (ts_data->family_id == FT_FT5336_FAMILY_ID_0x13) ||
+ (ts_data->family_id == FT_FT5336_FAMILY_ID_0x14)))
+ is_5336_new_bootloader = FT_BLOADER_VERSION_GZF;
+ else
+ is_5336_new_bootloader = FT_BLOADER_VERSION_LZ4;
+
+ dev_dbg(&client->dev, "bootloader type=%d, r_buf=0x%x, family_id=0x%x\n",
+ is_5336_new_bootloader, r_buf[0], ts_data->family_id);
+ /* is_5336_new_bootloader = FT_BLOADER_VERSION_GZF; */
+
/* erase app and panel paramenter area */
w_buf[0] = FT_ERASE_APP_REG;
ft5x06_i2c_write(client, w_buf, 1);
msleep(info.delay_erase_flash);
- w_buf[0] = FT_ERASE_PANEL_REG;
- ft5x06_i2c_write(client, w_buf, 1);
+ if (is_5336_fwsize_30) {
+ w_buf[0] = FT_ERASE_PANEL_REG;
+ ft5x06_i2c_write(client, w_buf, 1);
+ }
msleep(FT_EARSE_DLY_MS);
/* program firmware */
- data_len = data_len - 8;
+ if (is_5336_new_bootloader == FT_BLOADER_VERSION_LZ4
+ || is_5336_new_bootloader == FT_BLOADER_VERSION_Z7)
+ data_len = data_len - FT_DATA_LEN_OFF_OLD_FW;
+ else
+ data_len = data_len - FT_DATA_LEN_OFF_NEW_FW;
+
pkt_num = (data_len) / FT_FW_PKT_LEN;
pkt_len = FT_FW_PKT_LEN;
pkt_buf[0] = FT_FW_START_REG;
@@ -745,17 +809,45 @@
}
/* send the finishing packet */
- for (i = 0; i < 6; i++) {
- temp = FT_FW_LAST_PKT + i;
- pkt_buf[2] = (u8) (temp >> 8);
- pkt_buf[3] = (u8) temp;
- temp = 1;
- pkt_buf[4] = (u8) (temp >> 8);
- pkt_buf[5] = (u8) temp;
- pkt_buf[6] = data[data_len + i];
- fw_ecc ^= pkt_buf[6];
- ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN);
- msleep(FT_FW_PKT_DLY_MS);
+ if (is_5336_new_bootloader == FT_BLOADER_VERSION_LZ4 ||
+ is_5336_new_bootloader == FT_BLOADER_VERSION_Z7) {
+ for (i = 0; i < FT_FINISHING_PKT_LEN_OLD_FW; i++) {
+ if (is_5336_new_bootloader == FT_BLOADER_VERSION_Z7)
+ temp = FT_MAGIC_BLOADER_Z7 + i;
+ else if (is_5336_new_bootloader ==
+ FT_BLOADER_VERSION_LZ4)
+ temp = FT_MAGIC_BLOADER_LZ4 + i;
+ pkt_buf[2] = (u8)(temp >> 8);
+ pkt_buf[3] = (u8)temp;
+ temp = 1;
+ pkt_buf[4] = (u8)(temp >> 8);
+ pkt_buf[5] = (u8)temp;
+ pkt_buf[6] = data[data_len + i];
+ fw_ecc ^= pkt_buf[6];
+
+ ft5x06_i2c_write(client,
+ pkt_buf, temp + FT_FW_PKT_META_LEN);
+ msleep(FT_FW_PKT_DLY_MS);
+ }
+ } else if (is_5336_new_bootloader == FT_BLOADER_VERSION_GZF) {
+ for (i = 0; i < FT_FINISHING_PKT_LEN_NEW_FW; i++) {
+ if (is_5336_fwsize_30)
+ temp = FT_MAGIC_BLOADER_GZF_30 + i;
+ else
+ temp = FT_MAGIC_BLOADER_GZF + i;
+ pkt_buf[2] = (u8)(temp >> 8);
+ pkt_buf[3] = (u8)temp;
+ temp = 1;
+ pkt_buf[4] = (u8)(temp >> 8);
+ pkt_buf[5] = (u8)temp;
+ pkt_buf[6] = data[data_len + i];
+ fw_ecc ^= pkt_buf[6];
+
+ ft5x06_i2c_write(client,
+ pkt_buf, temp + FT_FW_PKT_META_LEN);
+ msleep(FT_FW_PKT_DLY_MS);
+
+ }
}
/* verify checksum */
@@ -1451,7 +1543,7 @@
goto free_reset_gpio;
}
- data->family_id = reg_value;
+ data->family_id = pdata->family_id;
err = request_threaded_irq(client->irq, NULL,
ft5x06_ts_interrupt, pdata->irqflags,
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index 8b08ac9..ba38061 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -95,6 +95,8 @@
static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms);
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);
+static int goodix_power_on(struct goodix_ts_data *ts);
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
@@ -758,7 +760,7 @@
ts: private data.
Output:
Executive outcomes.
- 1: succeed, otherwise failed.
+ >0: succeed, otherwise failed.
*******************************************************/
static s8 gtp_enter_sleep(struct goodix_ts_data *ts)
{
@@ -769,20 +771,37 @@
(u8)GTP_REG_SLEEP, 5};
ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
- usleep(5000);
- while (retry++ < 5) {
- ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
- if (ret > 0) {
- dev_dbg(&ts->client->dev,
- "GTP enter sleep!");
- return ret;
+ if (ret)
+ dev_err(&ts->client->dev,
+ "GTP sleep: Cannot reconfig gpio %d.\n",
+ ts->pdata->irq_gpio);
+ if (ts->pdata->enable_power_off) {
+ ret = gpio_direction_output(ts->pdata->reset_gpio, 0);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "GTP sleep: Cannot reconfig gpio %d.\n",
+ ts->pdata->reset_gpio);
+ ret = goodix_power_off(ts);
+ if (ret) {
+ dev_err(&ts->client->dev, "GTP power off failed.\n");
+ return 0;
}
- msleep(20);
+ return 1;
+ } else {
+ usleep(5000);
+ while (retry++ < 5) {
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret == 1) {
+ dev_dbg(&ts->client->dev, "GTP enter sleep!");
+ return ret;
+ }
+ msleep(20);
+ }
+ dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
+ return ret;
}
- dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
- return ret;
}
-#endif
+#endif /* !GTP_SLIDE_WAKEUP */
/*******************************************************
Function:
@@ -798,17 +817,36 @@
u8 retry = 0;
s8 ret = -1;
-#if GTP_POWER_CTRL_SLEEP
- gtp_reset_guitar(ts, 20);
+ if (ts->pdata->enable_power_off) {
+ ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "GTP wakeup: Cannot reconfig gpio %d.\n",
+ ts->pdata->irq_gpio);
+ ret = gpio_direction_output(ts->pdata->reset_gpio, 0);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "GTP wakeup: Cannot reconfig gpio %d.\n",
+ ts->pdata->reset_gpio);
+ ret = goodix_power_on(ts);
+ if (ret) {
+ dev_err(&ts->client->dev, "GTP power on failed.\n");
+ return 0;
+ }
- ret = gtp_send_cfg(ts);
- if (ret > 0) {
+ gtp_reset_guitar(ts, 20);
+
+ ret = gtp_send_cfg(ts);
+ if (ret <= 0) {
+ dev_err(&ts->client->dev,
+ "GTP wakeup sleep failed.\n");
+ return ret;
+ }
+
dev_dbg(&ts->client->dev,
- "Wakeup sleep send config success.");
- return 1;
- }
-#else
- while (retry++ < 10) {
+ "Wakeup sleep send config success.");
+ } else {
+err_retry:
#if GTP_SLIDE_WAKEUP
/* wakeup not by slide */
if (DOZE_WAKEUP != doze_status)
@@ -825,7 +863,7 @@
}
#endif
ret = gtp_i2c_test(ts->client);
- if (ret > 0) {
+ if (ret == 2) {
dev_dbg(&ts->client->dev, "GTP wakeup sleep.");
#if (!GTP_SLIDE_WAKEUP)
if (chip_gt9xxs == 0) {
@@ -839,10 +877,10 @@
return ret;
}
gtp_reset_guitar(ts, 20);
+ if (retry++ < 10)
+ goto err_retry;
+ dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
}
-#endif
-
- dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
return ret;
}
#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/
@@ -1055,9 +1093,7 @@
dev_info(&client->dev, "Goodix Product ID = %s\n", product_id);
- if (!IS_ERR(ts->pdata->product_id))
- ret = strcmp(product_id, ts->pdata->product_id);
-
+ ret = strcmp(product_id, ts->pdata->product_id);
if (ret != 0)
return -EINVAL;
@@ -1292,6 +1328,12 @@
{
int ret;
+ if (ts->power_on) {
+ dev_info(&ts->client->dev,
+ "Device already power on\n");
+ return 0;
+ }
+
if (!IS_ERR(ts->avdd)) {
ret = reg_set_optimum_mode_check(ts->avdd,
GOODIX_VDD_LOAD_MAX_UA);
@@ -1358,6 +1400,7 @@
}
}
+ ts->power_on = true;
return 0;
err_enable_vcc_i2c:
@@ -1376,6 +1419,7 @@
regulator_disable(ts->avdd);
err_enable_avdd:
err_set_opt_avdd:
+ ts->power_on = false;
return ret;
}
@@ -1389,6 +1433,12 @@
{
int ret;
+ if (!ts->power_on) {
+ dev_info(&ts->client->dev,
+ "Device already power off\n");
+ return 0;
+ }
+
if (!IS_ERR(ts->vcc_i2c)) {
ret = regulator_set_voltage(ts->vcc_i2c, 0,
GOODIX_I2C_VTG_MAX_UV);
@@ -1421,6 +1471,7 @@
"Regulator avdd disable failed ret=%d\n", ret);
}
+ ts->power_on = false;
return 0;
}
@@ -1473,6 +1524,50 @@
return 0;
}
+static ssize_t gtp_fw_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct goodix_ts_data *ts = dev_get_drvdata(dev);
+
+ if (!strlen(ts->fw_name))
+ return snprintf(buf, GTP_FW_NAME_MAXSIZE - 1,
+ "No fw name has been given.");
+ else
+ return snprintf(buf, GTP_FW_NAME_MAXSIZE - 1,
+ "%s\n", ts->fw_name);
+}
+
+static ssize_t gtp_fw_name_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct goodix_ts_data *ts = dev_get_drvdata(dev);
+
+ if (size > GTP_FW_NAME_MAXSIZE - 1) {
+ dev_err(dev, "FW name size exceeds the limit.");
+ return -EINVAL;
+ }
+
+ strlcpy(ts->fw_name, buf, size);
+ if (ts->fw_name[size-1] == '\n')
+ ts->fw_name[size-1] = '\0';
+
+ return size;
+}
+
+static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR | S_IWGRP),
+ gtp_fw_name_show,
+ gtp_fw_name_store);
+
+static struct attribute *gtp_attrs[] = {
+ &dev_attr_fw_name.attr,
+ NULL
+};
+
+static const struct attribute_group gtp_attr_grp = {
+ .attrs = gtp_attrs,
+};
+
static int goodix_ts_get_dt_coords(struct device *dev, char *name,
struct goodix_ts_platform_data *pdata)
{
@@ -1536,6 +1631,9 @@
pdata->no_force_update = of_property_read_bool(np,
"goodix,no-force-update");
+
+ pdata->enable_power_off = of_property_read_bool(np,
+ "goodix,enable-power-off");
/* reset, irq gpio info */
pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
0, &pdata->reset_gpio_flags);
@@ -1549,8 +1647,17 @@
rc = of_property_read_string(np, "goodix,product-id",
&pdata->product_id);
- if (rc < 0 || strlen(pdata->product_id) > GTP_PRODUCT_ID_MAXSIZE)
- return rc;
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Failed to parse product_id.");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_string(np, "goodix,fw_name",
+ &pdata->fw_name);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Failed to parse firmware name.\n");
+ return -EINVAL;
+ }
prop = of_find_property(np, "goodix,button-map", NULL);
if (prop) {
@@ -1662,6 +1769,7 @@
spin_lock_init(&ts->irq_lock);
i2c_set_clientdata(client, ts);
ts->gtp_rawdiff_mode = 0;
+ ts->power_on = false;
ret = goodix_power_init(ts);
if (ret) {
@@ -1689,12 +1797,16 @@
goto exit_free_io_port;
}
+ if (pdata->fw_name)
+ strlcpy(ts->fw_name, pdata->fw_name,
+ strlen(pdata->fw_name) + 1);
+
#if GTP_AUTO_UPDATE
ret = gup_init_update_proc(ts);
if (ret < 0) {
dev_err(&client->dev,
"GTP Create firmware update thread error.\n");
- goto exit_free_io_port;
+ goto exit_power_off;
}
#endif
@@ -1711,7 +1823,9 @@
dev_err(&client->dev, "GTP request input dev failed.\n");
goto exit_free_inputdev;
}
+ input_set_drvdata(ts->input_dev, ts);
+ mutex_init(&ts->lock);
#if defined(CONFIG_FB)
ts->fb_notif.notifier_call = fb_notifier_callback;
ret = fb_register_client(&ts->fb_notif);
@@ -1754,9 +1868,16 @@
#if GTP_ESD_PROTECT
gtp_esd_switch(client, SWITCH_ON);
#endif
+ ret = sysfs_create_group(&client->dev.kobj, >p_attr_grp);
+ if (ret < 0) {
+ dev_err(&client->dev, "sys file creation failed.\n");
+ goto exit_free_irq;
+ }
+
init_done = true;
return 0;
exit_free_irq:
+ mutex_destroy(&ts->lock);
#if defined(CONFIG_FB)
if (fb_unregister_client(&ts->fb_notif))
dev_err(&client->dev,
@@ -1806,6 +1927,8 @@
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
+ sysfs_remove_group(&ts->input_dev->dev.kobj, >p_attr_grp);
+
#if defined(CONFIG_FB)
if (fb_unregister_client(&ts->fb_notif))
dev_err(&client->dev,
@@ -1813,6 +1936,7 @@
#elif defined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&ts->early_suspend);
#endif
+ mutex_destroy(&ts->lock);
#if GTP_CREATE_WR_NODE
uninit_wr_node();
@@ -1868,6 +1992,7 @@
{
int ret = -1, i;
+ mutex_lock(&ts->lock);
#if GTP_ESD_PROTECT
ts->gtp_is_suspend = 1;
gtp_esd_switch(ts->client, SWITCH_OFF);
@@ -1888,12 +2013,13 @@
ret = gtp_enter_sleep(ts);
#endif
- if (ret < 0)
+ 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
*/
msleep(58);
+ mutex_unlock(&ts->lock);
}
/*******************************************************
@@ -1908,13 +2034,14 @@
{
int ret = -1;
+ mutex_lock(&ts->lock);
ret = gtp_wakeup_sleep(ts);
#if GTP_SLIDE_WAKEUP
doze_status = DOZE_DISABLED;
#endif
- if (ret < 0)
+ if (ret <= 0)
dev_err(&ts->client->dev, "GTP resume failed.\n");
if (ts->use_irq)
@@ -1927,6 +2054,7 @@
ts->gtp_is_suspend = 0;
gtp_esd_switch(ts->client, SWITCH_ON);
#endif
+ mutex_unlock(&ts->lock);
}
#if defined(CONFIG_FB)
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index 1fdbfa3..1d31f2a 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -36,6 +36,7 @@
#include <linux/regulator/consumer.h>
#include <linux/firmware.h>
#include <linux/debugfs.h>
+#include <linux/mutex.h>
#if defined(CONFIG_FB)
#include <linux/notifier.h>
@@ -46,12 +47,15 @@
#endif
#define GOODIX_MAX_CFG_GROUP 6
+#define GTP_FW_NAME_MAXSIZE 50
+
struct goodix_ts_platform_data {
int irq_gpio;
u32 irq_gpio_flags;
int reset_gpio;
u32 reset_gpio_flags;
const char *product_id;
+ const char *fw_name;
u32 x_max;
u32 y_max;
u32 x_min;
@@ -62,6 +66,7 @@
u32 panel_maxy;
bool no_force_update;
bool i2c_pull_up;
+ bool enable_power_off;
size_t config_data_len[GOODIX_MAX_CFG_GROUP];
u8 *config_data[GOODIX_MAX_CFG_GROUP];
};
@@ -73,6 +78,7 @@
struct hrtimer timer;
struct workqueue_struct *goodix_wq;
struct work_struct work;
+ char fw_name[GTP_FW_NAME_MAXSIZE];
s32 irq_is_disabled;
s32 use_irq;
u16 abs_x_max;
@@ -89,6 +95,8 @@
u8 fixed_cfg;
u8 esd_running;
u8 fw_error;
+ bool power_on;
+ struct mutex lock;
struct regulator *avdd;
struct regulator *vdd;
struct regulator *vcc_i2c;
@@ -107,7 +115,6 @@
#define GTP_CHANGE_X2Y 0
#define GTP_DRIVER_SEND_CFG 1
#define GTP_HAVE_TOUCH_KEY 1
-#define GTP_POWER_CTRL_SLEEP 0
/* auto updated by .bin file as default */
#define GTP_AUTO_UPDATE 0
@@ -119,6 +126,7 @@
#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
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 70c1307..7282c2e 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -353,7 +353,7 @@
if (img->is_contain_build_info) {
img->firmware_id = extract_uint(data->firmware_id);
- img->package_id = (data->pkg_id_rev_msb << 8) |
+ img->package_id = (data->pkg_id_msb << 8) |
data->pkg_id_lsb;
img->package_revision_id = (data->pkg_id_rev_msb << 8) |
data->pkg_id_rev_lsb;
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 5f36a4a..ea0195d 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
@@ -513,7 +513,9 @@
}
lo_tbl_ptr = cfg_data +
reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4;
-
+ if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT)
+ reg_cfg_cmd->u.dmi_info.len =
+ reg_cfg_cmd->u.dmi_info.len / 2;
for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) {
lo_val = *lo_tbl_ptr++;
if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_16BIT) {
@@ -621,6 +623,12 @@
goto reg_cfg_failed;
}
+ if (!proc_cmd->cmd_len) {
+ pr_err("%s: Passed cmd_len as 0\n", __func__);
+ rc = -EINVAL;
+ goto cfg_data_failed;
+ }
+
cfg_data = kzalloc(proc_cmd->cmd_len, GFP_KERNEL);
if (!cfg_data) {
pr_err("%s: cfg_data alloc failed\n", __func__);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
old mode 100644
new mode 100755
index 89016ec..de098c9
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -200,17 +200,17 @@
ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
-
+ pr_debug("%s: base %x", __func__, (unsigned int)ispif->base);
msm_camera_io_w(0, ispif->base +
ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
msm_camera_io_w(0, ispif->base +
ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1));
msm_camera_io_w(0, ispif->base +
- ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
+ ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 0));
msm_camera_io_w(0, ispif->base +
- ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 1));
+ ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 1));
msm_camera_io_w(0, ispif->base +
- ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 2));
+ ISPIF_VFE_m_RDI_INTF_n_CID_MASK(i, 2));
msm_camera_io_w(0, ispif->base +
ISPIF_VFE_m_PIX_INTF_n_CROP(i, 0));
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 8b8d23b..2124b13 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -926,35 +926,35 @@
cpp_dev->cpp_open_cnt--;
if (cpp_dev->cpp_open_cnt == 0) {
- pr_err("%s: irq_status: 0x%x\n", __func__,
+ pr_debug("irq_status: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4));
- pr_err("%s: DEBUG_SP: 0x%x\n", __func__,
+ pr_debug("DEBUG_SP: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x40));
- pr_err("%s: DEBUG_T: 0x%x\n", __func__,
+ pr_debug("DEBUG_T: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x44));
- pr_err("%s: DEBUG_N: 0x%x\n", __func__,
+ pr_debug("DEBUG_N: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x48));
- pr_err("%s: DEBUG_R: 0x%x\n", __func__,
+ pr_debug("DEBUG_R: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x4C));
- pr_err("%s: DEBUG_OPPC: 0x%x\n", __func__,
+ pr_debug("DEBUG_OPPC: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x50));
- pr_err("%s: DEBUG_MO: 0x%x\n", __func__,
+ pr_debug("DEBUG_MO: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x54));
- pr_err("%s: DEBUG_TIMER0: 0x%x\n", __func__,
+ pr_debug("DEBUG_TIMER0: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x60));
- pr_err("%s: DEBUG_TIMER1: 0x%x\n", __func__,
+ pr_debug("DEBUG_TIMER1: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x64));
- pr_err("%s: DEBUG_GPI: 0x%x\n", __func__,
+ pr_debug("DEBUG_GPI: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x70));
- pr_err("%s: DEBUG_GPO: 0x%x\n", __func__,
+ pr_debug("DEBUG_GPO: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x74));
- pr_err("%s: DEBUG_T0: 0x%x\n", __func__,
+ pr_debug("DEBUG_T0: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x80));
- pr_err("%s: DEBUG_R0: 0x%x\n", __func__,
+ pr_debug("DEBUG_R0: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x84));
- pr_err("%s: DEBUG_T1: 0x%x\n", __func__,
+ pr_debug("DEBUG_T1: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x88));
- pr_err("%s: DEBUG_R1: 0x%x\n", __func__,
+ pr_debug("DEBUG_R1: 0x%x\n",
msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C));
msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
cpp_deinit_mem(cpp_dev);
@@ -1712,6 +1712,7 @@
struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
struct msm_cpp_frame_info_t inst_info;
+ memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t));
for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) {
inst_info.inst_id = i;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
old mode 100644
new mode 100755
index 9384a5b..d8608ae
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -177,6 +177,7 @@
static struct msm_cam_clk_info csiphy_8610_clk_info[] = {
{"csiphy_timer_src_clk", 200000000},
{"csiphy_timer_clk", -1},
+ {"csi_ahb_clk", -1},
};
static struct msm_cam_clk_info csiphy_8974_clk_info[] = {
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index e3a539c..d3b9c0a 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -4036,6 +4036,13 @@
__func__);
return ret;
}
+
+ if (mpq_feed->sdmx_filter_handle ==
+ SDMX_INVALID_FILTER_HANDLE) {
+ MPQ_DVB_DBG_PRINT("%s: filter was stopped\n",
+ __func__);
+ return -ENODEV;
+ }
}
if (mpq_feed->sdmx_buf.pread + header->payload_length <
@@ -4089,6 +4096,13 @@
mutex_lock(&mpq_demux->mutex);
+ if (mpq_feed->sdmx_filter_handle ==
+ SDMX_INVALID_FILTER_HANDLE) {
+ MPQ_DVB_DBG_PRINT("%s: filter was stopped\n",
+ __func__);
+ return -ENODEV;
+ }
+
return ret;
}
@@ -4456,6 +4470,14 @@
return;
}
+ if (!header.payload_length) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: warnning - video frame with 0 length, dropping\n",
+ __func__);
+ spin_unlock(&mpq_feed->video_info.video_buffer_lock);
+ continue;
+ }
+
packet.raw_data_len = header.payload_length;
packet.user_data_len = sizeof(meta_data);
mpq_streambuffer_get_buffer_handle(sbuf, 0,
diff --git a/drivers/media/platform/msm/vcap/Kconfig b/drivers/media/platform/msm/vcap/Kconfig
index 2bdcfbd..db3bc47 100644
--- a/drivers/media/platform/msm/vcap/Kconfig
+++ b/drivers/media/platform/msm/vcap/Kconfig
@@ -1,7 +1,6 @@
config MSM_VCAP
tristate "Qualcomm MSM VCAP"
depends on VIDEO_DEV && VIDEO_V4L2
- default y
---help---
Enables VCAP driver. This device allows for video capture and
video processing using the v4l2 api
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 30ada3e..ae94287 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -803,7 +803,8 @@
pkt->rg_property_data[0] =
HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE;
hfi = (struct hfi_enable_picture *) &pkt->rg_property_data[1];
- hfi->picture_type = (u32) pdata;
+ hfi->picture_type =
+ ((struct hfi_enable_picture *)pdata)->picture_type;
pkt->size += sizeof(u32) * 2;
break;
}
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index abdb039..3fd5d3a 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1183,42 +1183,78 @@
callback(SESSION_GET_SEQ_HDR_DONE, &data_done);
}
-void hfi_process_sys_property_info(
- struct hfi_property_sys_image_version_info_type *pkt)
+static void hfi_process_sys_get_prop_image_version(
+ struct hfi_msg_sys_property_info_packet *pkt)
{
int i = 0;
u32 smem_block_size = 0;
u8 *smem_table_ptr;
char version[256];
+ const u32 version_string_size = 128;
const u32 smem_image_index_venus = 14 * 128;
+ u8 *str_image_version;
+ int req_bytes;
- if (!pkt || !pkt->string_size) {
+ req_bytes = pkt->size - sizeof(*pkt);
+ if (req_bytes < version_string_size ||
+ !pkt->rg_property_data[1] ||
+ pkt->num_properties > 1) {
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_get_prop_image_version:bad_pkt: %d",
+ req_bytes);
+ return;
+ }
+ str_image_version = (u8 *)&pkt->rg_property_data[1];
+ /*
+ * The version string returned by firmware includes null
+ * characters at the start and in between. Replace the null
+ * characters with space, to print the version info.
+ */
+ for (i = 0; i < version_string_size; i++) {
+ if (str_image_version[i] != '\0')
+ version[i] = str_image_version[i];
+ else
+ version[i] = ' ';
+ }
+ version[i] = '\0';
+ dprintk(VIDC_DBG, "F/W version: %s\n", version);
+
+ smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
+ &smem_block_size);
+ if (smem_table_ptr &&
+ ((smem_image_index_venus +
+ version_string_size) <= smem_block_size))
+ memcpy(smem_table_ptr + smem_image_index_venus,
+ str_image_version, version_string_size);
+}
+
+static void hfi_process_sys_property_info(
+ struct hfi_msg_sys_property_info_packet *pkt)
+{
+ if (!pkt) {
dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
return;
}
-
- if (pkt->string_size < sizeof(version)) {
- /*
- * The version string returned by firmware includes null
- * characters at the start and in between. Replace the null
- * characters with space, to print the version info.
- */
- for (i = 0; i < pkt->string_size; i++) {
- if (pkt->str_image_version[i] != '\0')
- version[i] = pkt->str_image_version[i];
- else
- version[i] = ' ';
- }
- version[i] = '\0';
- dprintk(VIDC_DBG, "F/W version: %s\n", version);
+ if (pkt->size < sizeof(*pkt)) {
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_property_info: bad_pkt_size\n");
+ return;
+ }
+ if (pkt->num_properties == 0) {
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_property_info: no_properties\n");
+ return;
}
- smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
- &smem_block_size);
- if (smem_table_ptr &&
- ((smem_image_index_venus + 128) <= smem_block_size))
- memcpy(smem_table_ptr + smem_image_index_venus,
- (u8 *)pkt->str_image_version, 128);
+ switch (pkt->rg_property_data[0]) {
+ case HFI_PROPERTY_SYS_IMAGE_VERSION:
+ hfi_process_sys_get_prop_image_version(pkt);
+ break;
+ default:
+ dprintk(VIDC_ERR,
+ "hfi_process_sys_property_info:unknown_prop_id: %d\n",
+ pkt->rg_property_data[0]);
+ }
}
u32 hfi_process_msg_packet(
@@ -1263,7 +1299,7 @@
break;
case HFI_MSG_SYS_PROPERTY_INFO:
hfi_process_sys_property_info(
- (struct hfi_property_sys_image_version_info_type *)
+ (struct hfi_msg_sys_property_info_packet *)
msg_hdr);
break;
case HFI_MSG_SYS_SESSION_END_DONE:
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index f4fdfe7..efa195e 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -686,6 +686,7 @@
int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
+ unsigned int *plane_sizes = NULL;
struct hfi_device *hdev;
int stride, scanlines;
int extra_idx = 0;
@@ -741,9 +742,19 @@
goto exit;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ plane_sizes =
+ &inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[0];
for (i = 0; i < fmt->num_planes; ++i) {
- f->fmt.pix_mp.plane_fmt[i].sizeimage =
- inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i];
+ if (plane_sizes[i] == 0) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i,
+ inst->capability.height.max,
+ inst->capability.width.max);
+ plane_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ } else
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ plane_sizes[i];
}
} else {
switch (fmt->fourcc) {
@@ -979,8 +990,10 @@
inst->capability.height.max,
inst->capability.width.max);
- if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size)
+ if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size ||
+ f->fmt.pix_mp.plane_fmt[0].sizeimage == 0) {
f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size;
+ }
f->fmt.pix_mp.num_planes = fmt->num_planes;
for (i = 0; i < fmt->num_planes; ++i) {
@@ -1807,7 +1820,7 @@
int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
{
int idx = 0;
- struct v4l2_ctrl_config ctrl_cfg;
+ struct v4l2_ctrl_config ctrl_cfg = {0};
int ret_val = 0;
ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index f9b5519..c0bf32c 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2662,7 +2662,7 @@
{
int idx = 0;
- struct v4l2_ctrl_config ctrl_cfg;
+ struct v4l2_ctrl_config ctrl_cfg = {0};
int ret_val = 0;
ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
if (ret_val) {
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 7c99ec3..8e91f34 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -560,17 +560,28 @@
dprintk(VIDC_ERR, "session_init: failed to create packet");
goto err_session_init;
}
+ /*
+ * Add session id to the list entry and then send the apr pkt.
+ * This will avoid scenarios where apr_send_pkt is taking more
+ * time and Q6 is returning an ack even before the session id
+ * gets added to the session list.
+ */
+ mutex_lock(&dev->session_lock);
+ list_add_tail(&new_session->list, &dev->sess_head);
+ mutex_unlock(&dev->session_lock);
rc = apr_send_pkt(dev->apr, (uint32_t *)&apr);
if (rc != apr.hdr.pkt_size) {
dprintk(VIDC_ERR, "%s: apr_send_pkt failed rc: %d",
__func__, rc);
+ /* Delete the session id as the send pkt is not successful */
+ mutex_lock(&dev->session_lock);
+ list_del(&new_session->list);
+ mutex_unlock(&dev->session_lock);
rc = -EBADE;
goto err_session_init;
}
- mutex_lock(&dev->session_lock);
- list_add_tail(&new_session->list, &dev->sess_head);
- mutex_unlock(&dev->session_lock);
+
return new_session;
err_session_init:
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 916df1d..8cd3889 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1057,30 +1057,32 @@
dprintk(VIDC_ERR, "cannot write to shared Q's");
goto err_q_null;
}
- mutex_lock(&device->clk_pwr_lock);
- result = venus_hfi_clk_gating_off(device);
- if (result) {
- dprintk(VIDC_ERR, "%s : Clock enable failed\n",
- __func__);
- goto err_q_write;
- }
- result = venus_hfi_scale_clocks(device, device->clk_load);
- if (result) {
- dprintk(VIDC_ERR, "Clock scaling failed\n");
- goto err_q_write;
- }
if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
+ mutex_lock(&device->clk_pwr_lock);
+ result = venus_hfi_clk_gating_off(device);
+ if (result) {
+ dprintk(VIDC_ERR, "%s : Clock enable failed\n",
+ __func__);
+ mutex_unlock(&device->clk_pwr_lock);
+ goto err_q_write;
+ }
+ result = venus_hfi_scale_clocks(device, device->clk_load);
+ if (result) {
+ dprintk(VIDC_ERR, "Clock scaling failed\n");
+ mutex_unlock(&device->clk_pwr_lock);
+ goto err_q_write;
+ }
if (rx_req_is_set)
venus_hfi_write_register(
device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
result = 0;
+ mutex_unlock(&device->clk_pwr_lock);
} else {
dprintk(VIDC_ERR, "venus_hfi_iface_cmdq_write:queue_full");
}
err_q_write:
- mutex_unlock(&device->clk_pwr_lock);
err_q_null:
mutex_unlock(&device->write_lock);
return result;
@@ -1104,26 +1106,27 @@
goto read_error_null;
}
q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
- mutex_lock(&device->clk_pwr_lock);
- rc = venus_hfi_clk_gating_off(device);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s : Clock enable failed\n", __func__);
- goto read_error;
- }
if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+ mutex_lock(&device->clk_pwr_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
+ mutex_unlock(&device->clk_pwr_lock);
+ goto read_error;
+ }
if (tx_req_is_set)
venus_hfi_write_register(
device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
rc = 0;
+ mutex_unlock(&device->clk_pwr_lock);
} else {
dprintk(VIDC_INFO, "venus_hfi_iface_msgq_read:queue_empty");
rc = -ENODATA;
}
read_error:
- mutex_unlock(&device->clk_pwr_lock);
read_error_null:
mutex_unlock(&device->read_lock);
return rc;
@@ -1146,27 +1149,28 @@
rc = -ENODATA;
goto dbg_error_null;
}
- mutex_lock(&device->clk_pwr_lock);
- rc = venus_hfi_clk_gating_off(device);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s : Clock enable failed\n", __func__);
- goto dbg_error;
- }
q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
+ mutex_lock(&device->clk_pwr_lock);
+ rc = venus_hfi_clk_gating_off(device);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s : Clock enable failed\n", __func__);
+ mutex_unlock(&device->clk_pwr_lock);
+ goto dbg_error;
+ }
if (tx_req_is_set)
venus_hfi_write_register(
device,
VIDC_CPU_IC_SOFTINT,
1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT, 0);
rc = 0;
+ mutex_unlock(&device->clk_pwr_lock);
} else {
dprintk(VIDC_INFO, "venus_hfi_iface_dbgq_read:queue_empty");
rc = -ENODATA;
}
dbg_error:
- mutex_unlock(&device->clk_pwr_lock);
dbg_error_null:
mutex_unlock(&device->read_lock);
return rc;
@@ -1251,7 +1255,7 @@
for (i = 0; i < num_entries; i++) {
rc = msm_iommu_map_contig_buffer(venus_qdss_entries[i][0],
- domain, 1 , venus_qdss_entries[i][1],
+ domain, partition, venus_qdss_entries[i][1],
SZ_4K, 0, &iova);
if (rc) {
dprintk(VIDC_ERR,
@@ -1567,20 +1571,59 @@
return 0;
}
+static int venus_hfi_is_cmd_pending(struct venus_hfi_device *dev)
+{
+ struct hfi_queue_header *queue;
+ struct vidc_iface_q_info *q_info;
+ u32 write_ptr, read_ptr;
+ u32 rc = 0;
+ q_info = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
+ if (!q_info)
+ dprintk(VIDC_ERR, "cannot read shared Q's");
+ queue = (struct hfi_queue_header *) q_info->q_hdr;
+ if (!queue) {
+ dprintk(VIDC_ERR, "queue not present");
+ return -ENOENT;
+ }
+ write_ptr = (u32)queue->qhdr_write_idx;
+ read_ptr = (u32)queue->qhdr_read_idx;
+ rc = read_ptr - write_ptr;
+ return rc;
+}
+
+static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
+{
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n", device);
+ return;
+ }
+ if (!device->clocks_enabled) {
+ dprintk(VIDC_DBG, "Clocks are already disabled");
+ goto already_disabled;
+ }
+ venus_hfi_clk_disable(device);
+ if (!queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work,
+ msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
+ dprintk(VIDC_DBG, "PM work already scheduled\n");
+already_disabled:
+ device->clocks_enabled = 0;
+}
+
static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
{
u32 intr_status = 0;
- int rc = 0;
+ int rc = 0, ctrl_status;
if (!device->callback)
return;
+
+ mutex_lock(&device->write_lock);
mutex_lock(&device->clk_pwr_lock);
rc = venus_hfi_clk_gating_off(device);
if (rc) {
dprintk(VIDC_ERR,
"%s : Clock enable failed\n", __func__);
- mutex_unlock(&device->clk_pwr_lock);
- return;
+ goto err_clk_gating_off;
}
intr_status = venus_hfi_read_register(
device,
@@ -1603,8 +1646,23 @@
VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
venus_hfi_write_register(device,
VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
- mutex_unlock(&device->clk_pwr_lock);
+ rc = venus_hfi_is_cmd_pending(device);
+ ctrl_status = venus_hfi_read_register(
+ device,
+ VIDC_CPU_CS_SCIACMDARG0);
+ dprintk(VIDC_INFO,
+ "CLEAR INTERRUPT - cmd_pending %d, ctrl_status 0x%x\n",
+ rc, ctrl_status);
+ if ((ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)
+ && !rc) {
+ dprintk(VIDC_DBG, "SYS_IDLE interrupt, disable clocks\n");
+ venus_hfi_clk_gating_on(device);
+ }
+
dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
+err_clk_gating_off:
+ mutex_unlock(&device->clk_pwr_lock);
+ mutex_unlock(&device->write_lock);
}
static int venus_hfi_core_set_resource(void *device,
@@ -2321,26 +2379,6 @@
device->callback(SYS_WATCHDOG_TIMEOUT, &cmd_done);
}
-static int venus_hfi_is_cmd_pending(struct venus_hfi_device *dev)
-{
- struct hfi_queue_header *queue;
- struct vidc_iface_q_info *q_info;
- u32 write_ptr, read_ptr;
- u32 rc = 0;
- q_info = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
- if (!q_info)
- dprintk(VIDC_ERR, "cannot read shared Q's");
- queue = (struct hfi_queue_header *) q_info->q_hdr;
- if (!queue) {
- dprintk(VIDC_ERR, "queue not present");
- return -ENOENT;
- }
- write_ptr = (u32)queue->qhdr_write_idx;
- read_ptr = (u32)queue->qhdr_read_idx;
- rc = read_ptr - write_ptr;
- return rc;
-}
-
static int venus_hfi_core_pc_prep(void *device)
{
struct hfi_cmd_sys_pc_prep_packet pkt;
@@ -2408,24 +2446,6 @@
mutex_unlock(&device->clk_pwr_lock);
}
-static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
-{
- if (!device) {
- dprintk(VIDC_ERR, "Invalid params: %p\n", device);
- return;
- }
- if (!device->clocks_enabled) {
- dprintk(VIDC_DBG, "Clocks are already disabled");
- goto already_disabled;
- }
- venus_hfi_clk_disable(device);
- if (!queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work,
- msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
- dprintk(VIDC_DBG, "PM work already scheduled\n");
-already_disabled:
- device->clocks_enabled = 0;
-}
-
static int venus_hfi_try_clk_gating(struct venus_hfi_device *device)
{
int rc = 0;
@@ -2506,10 +2526,12 @@
(struct hfi_msg_sys_debug_packet *) packet;
dprintk(VIDC_FW, "FW-SAYS: %s", pkt->rg_msg_data);
}
- if (rc == HFI_MSG_SYS_IDLE)
+ if (rc == HFI_MSG_SYS_IDLE) {
+ dprintk(VIDC_DBG, "Received HFI_MSG_SYS_IDLE\n");
rc = venus_hfi_try_clk_gating(device);
- else if (rc == HFI_MSG_SYS_PC_PREP_DONE) {
- dprintk(VIDC_DBG, "Received HFI_MSG_SYS_PC_PREP_DONE");
+ } else if (rc == HFI_MSG_SYS_PC_PREP_DONE) {
+ dprintk(VIDC_DBG,
+ "Received HFI_MSG_SYS_PC_PREP_DONE\n");
rc = venus_hfi_try_clk_gating(device);
if (rc)
dprintk(VIDC_ERR,
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index e0a99e2..6b9f2b3 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -3051,7 +3051,7 @@
int retval = 0;
int bytes_to_copy;
int bytes_copied = 0;
- int bytes_left = 0;
+ __u32 bytes_left = 0;
int chunk_index = 0;
char tx_data[XFR_REG_NUM];
struct tavarua_device *radio = video_get_drvdata(video_devdata(file));
@@ -3066,15 +3066,15 @@
chunk_index = 0;
bytes_copied = 0;
- bytes_left = min((int)(ctrl->controls[0]).size,
- MAX_PS_LENGTH);
+ bytes_left = min((ctrl->controls[0]).size,
+ (__u32)MAX_PS_LENGTH);
data = (ctrl->controls[0]).string;
/* send payload to FM hardware */
while (bytes_left) {
chunk_index++;
FMDBG("chunk is %d", chunk_index);
- bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+ bytes_to_copy = min(bytes_left, (__u32)XFR_REG_NUM);
/*Clear the tx_data */
memset(tx_data, 0, XFR_REG_NUM);
if (copy_from_user(tx_data,
@@ -3116,12 +3116,12 @@
FMDBG("Passed RT String : %s\n",
(ctrl->controls[0]).string);
bytes_left =
- min((int)(ctrl->controls[0]).size, MAX_RT_LENGTH);
+ min((ctrl->controls[0]).size, (__u32)MAX_RT_LENGTH);
data = (ctrl->controls[0]).string;
/* send payload to FM hardware */
while (bytes_left) {
chunk_index++;
- bytes_to_copy = min(bytes_left, XFR_REG_NUM);
+ bytes_to_copy = min(bytes_left, (__u32)XFR_REG_NUM);
memset(tx_data, 0, XFR_REG_NUM);
if (copy_from_user(tx_data,
data + bytes_copied, bytes_to_copy))
@@ -4466,8 +4466,8 @@
struct marimba_fm_platform_data *tavarua_pdata;
struct tavarua_device *radio;
- int retval;
- int i;
+ int retval = 0;
+ int i = 0, j = 0;
FMDBG("%s: probe called\n", __func__);
/* private data allocation */
radio = kzalloc(sizeof(struct tavarua_device), GFP_KERNEL);
@@ -4480,6 +4480,7 @@
tavarua_pdata = pdev->dev.platform_data;
radio->pdata = tavarua_pdata;
radio->dev = &pdev->dev;
+ radio->wqueue = NULL;
platform_set_drvdata(pdev, radio);
/* video device allocation */
@@ -4509,15 +4510,16 @@
if (kfifo_alloc_rc!=0) {
printk(KERN_ERR "%s: failed allocating buffers %d\n",
__func__, kfifo_alloc_rc);
- goto err_bufs;
+ retval = -ENOMEM;
+ goto err_all;
}
}
/* initializing the device count */
atomic_set(&radio->users, 1);
radio->xfr_in_progress = 0;
radio->xfr_bytes_left = 0;
- for (i = 0; i < TAVARUA_XFR_MAX; i++)
- radio->pending_xfrs[i] = 0;
+ for (j = 0; j < TAVARUA_XFR_MAX; j++)
+ radio->pending_xfrs[j] = 0;
/* init transmit data */
radio->tx_mode = TAVARUA_TX_RT;
@@ -4548,11 +4550,14 @@
/*Start the worker thread for event handling and register read_int_stat
as worker function*/
radio->wqueue = create_singlethread_workqueue("kfmradio");
- if (!radio->wqueue)
- return -ENOMEM;
+ if (!radio->wqueue) {
+ retval = -ENOMEM;
+ goto err_all;
+ }
/* register video device */
- if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+ retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (retval != 0) {
printk(KERN_WARNING DRIVER_NAME
": Could not register video device\n");
goto err_all;
@@ -4562,9 +4567,11 @@
err_all:
video_device_release(radio->videodev);
-err_bufs:
- for (; i > -1; i--)
+ if (radio->wqueue)
+ destroy_workqueue(radio->wqueue);
+ for (i--; i >= 0; i--) {
kfifo_free(&radio->data_buf[i]);
+ }
err_radio:
kfree(radio);
err_initial:
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 293033b..a296e48 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -61,6 +61,7 @@
/* Flushing a large amount of cached data may take a long time. */
#define MMC_FLUSH_REQ_TIMEOUT_MS 90000 /* msec */
+#define MMC_CACHE_DISBALE_TIMEOUT_MS 180000 /* msec */
static struct workqueue_struct *workqueue;
@@ -744,7 +745,11 @@
*/
mmc_update_clk_scaling(host);
err = mmc_stop_request(host);
- if (err && !context_info->is_done_rcv) {
+ if (err == MMC_BLK_NO_REQ_TO_STOP) {
+ pending_is_urgent = true;
+ /* wait for done/new/urgent event */
+ continue;
+ } else if (err && !context_info->is_done_rcv) {
err = MMC_BLK_ABORT;
break;
}
@@ -3389,14 +3394,14 @@
if (card->ext_csd.cache_ctrl ^ enable) {
if (!enable)
- timeout = MMC_FLUSH_REQ_TIMEOUT_MS;
+ timeout = MMC_CACHE_DISBALE_TIMEOUT_MS;
err = mmc_switch_ignore_timeout(card,
EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_CACHE_CTRL, enable, timeout);
if (err == -ETIMEDOUT && !enable) {
- pr_debug("%s:cache disable operation timeout\n",
+ pr_err("%s:cache disable operation timeout\n",
mmc_hostname(card->host));
rc = mmc_interrupt_hpi(card);
if (rc)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 758a79e..513ddfb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -27,6 +27,7 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
#include "sdhci.h"
@@ -745,6 +746,12 @@
if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
return 0xE;
+ /* During initialization, don't use max timeout as the clock is slow */
+ if ((host->quirks2 & SDHCI_QUIRK2_USE_RESERVED_MAX_TIMEOUT) &&
+ (host->clock > 400000)) {
+ return 0xF;
+ }
+
/* Unspecified timeout, assume max */
if (!data && !cmd->cmd_timeout_ms)
return 0xE;
@@ -2223,10 +2230,13 @@
struct sdhci_host *host = mmc_priv(mmc);
unsigned long flags;
struct mmc_data *data;
+ int ret = 0;
spin_lock_irqsave(&host->lock, flags);
- if (!host->mrq || !host->data)
+ if (!host->mrq || !host->data) {
+ ret = MMC_BLK_NO_REQ_TO_STOP;
goto out;
+ }
data = host->data;
@@ -2252,7 +2262,7 @@
host->data = NULL;
out:
spin_unlock_irqrestore(&host->lock, flags);
- return 0;
+ return ret;
}
static unsigned int sdhci_get_xfer_remain(struct mmc_host *mmc)
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 6a16cf3..1ef1f1b 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -963,7 +963,7 @@
enum ipa_pipe_mem_type mem_type;
if (!pipe_connection || !node)
- goto err;
+ return -EINVAL;
key = "qcom,src-bam-physical-address";
rc = of_property_read_u32(node, key, &val);
diff --git a/drivers/platform/msm/ipa/ipa_flt.c b/drivers/platform/msm/ipa/ipa_flt.c
index 2d75141..c3db716 100644
--- a/drivers/platform/msm/ipa/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_flt.c
@@ -802,8 +802,11 @@
IPADBG("reset flt ip=%d\n", ip);
list_for_each_entry_safe(entry, next, &tbl->head_flt_rule_list, link) {
node = ipa_search(&ipa_ctx->flt_rule_hdl_tree, (u32)entry);
- if (node == NULL)
+ if (node == NULL) {
WARN_ON(1);
+ mutex_unlock(&ipa_ctx->lock);
+ return -EFAULT;
+ }
if ((ip == IPA_IP_v4 &&
entry->rule.attrib.attrib_mask == IPA_FLT_PROTOCOL &&
@@ -833,8 +836,11 @@
link) {
node = ipa_search(&ipa_ctx->flt_rule_hdl_tree,
(u32)entry);
- if (node == NULL)
+ if (node == NULL) {
WARN_ON(1);
+ mutex_unlock(&ipa_ctx->lock);
+ return -EFAULT;
+ }
list_del(&entry->link);
entry->tbl->rule_cnt--;
if (entry->rt_tbl)
diff --git a/drivers/platform/msm/ipa/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_hdr.c
index 9618da2..54cbf5f 100644
--- a/drivers/platform/msm/ipa/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_hdr.c
@@ -450,8 +450,11 @@
continue;
node = ipa_search(&ipa_ctx->hdr_hdl_tree, (u32) entry);
- if (node == NULL)
+ if (node == NULL) {
WARN_ON(1);
+ mutex_unlock(&ipa_ctx->lock);
+ return -EFAULT;
+ }
list_del(&entry->link);
entry->cookie = 0;
kmem_cache_free(ipa_ctx->hdr_cache, entry);
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 8d6d5e6..f453010 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -843,8 +843,11 @@
&tbl->head_rt_rule_list, link) {
node = ipa_search(&ipa_ctx->rt_rule_hdl_tree,
(u32)rule);
- if (node == NULL)
+ if (node == NULL) {
WARN_ON(1);
+ mutex_unlock(&ipa_ctx->lock);
+ return -EFAULT;
+ }
/*
* for the "default" routing tbl, remove all but the
@@ -866,8 +869,11 @@
}
node = ipa_search(&ipa_ctx->rt_tbl_hdl_tree, (u32)tbl);
- if (node == NULL)
+ if (node == NULL) {
WARN_ON(1);
+ mutex_unlock(&ipa_ctx->lock);
+ return -EFAULT;
+ }
/* do not remove the "default" routing tbl which has index 0 */
if (tbl->idx != 0) {
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index a65ac5b..a627ec2 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -369,6 +369,7 @@
struct alarm reduce_power_stage_alarm;
struct work_struct reduce_power_stage_work;
bool power_stage_workaround_running;
+ bool power_stage_workaround_enable;
};
@@ -2151,7 +2152,8 @@
if ((chip->flags & POWER_STAGE_WA)
&& ((ret.intval / 1000) > USB_WALL_THRESHOLD_MA)
- && !chip->power_stage_workaround_running) {
+ && !chip->power_stage_workaround_running
+ && chip->power_stage_workaround_enable) {
chip->power_stage_workaround_running = true;
pr_debug("usb wall chg inserted starting power stage workaround charger_monitor = %d\n",
charger_monitor);
@@ -4124,6 +4126,10 @@
if (chip->use_default_batt_values)
chip->charging_disabled = true;
+ chip->power_stage_workaround_enable =
+ of_property_read_bool(chip->spmi->dev.of_node,
+ "qcom,power-stage-reduced");
+
of_get_property(chip->spmi->dev.of_node, "qcom,thermal-mitigation",
&(chip->thermal_levels));
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 0c9959c..67cf049 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -1065,7 +1065,7 @@
}
dev = kzalloc(sizeof(struct msm_slim_ctrl), GFP_KERNEL);
- if (IS_ERR(dev)) {
+ if (IS_ERR_OR_NULL(dev)) {
dev_err(&pdev->dev, "no memory for MSM slimbus controller\n");
return PTR_ERR(dev);
}
diff --git a/drivers/staging/zram/Kconfig b/drivers/staging/zram/Kconfig
index 9d11a4c..983314c 100644
--- a/drivers/staging/zram/Kconfig
+++ b/drivers/staging/zram/Kconfig
@@ -1,9 +1,6 @@
config ZRAM
tristate "Compressed RAM block device support"
- # X86 dependency is because zsmalloc uses non-portable pte/tlb
- # functions
- depends on BLOCK && SYSFS && X86
- select ZSMALLOC
+ depends on BLOCK && SYSFS && ZSMALLOC
select LZO_COMPRESS
select LZO_DECOMPRESS
default n
@@ -17,7 +14,7 @@
disks and maybe many more.
See zram.txt for more information.
- Project home: http://compcache.googlecode.com/
+ Project home: <https://compcache.googlecode.com/>
config ZRAM_DEBUG
bool "Compressed RAM block device debug support"
diff --git a/drivers/staging/zram/Makefile b/drivers/staging/zram/Makefile
index 7f4a301..cb0f9ce 100644
--- a/drivers/staging/zram/Makefile
+++ b/drivers/staging/zram/Makefile
@@ -1,3 +1,3 @@
-zram-y := zram_drv.o zram_sysfs.o
+zram-y := zram_drv.o
obj-$(CONFIG_ZRAM) += zram.o
diff --git a/drivers/staging/zram/zram.txt b/drivers/staging/zram/zram.txt
index 5f75d29..765d790 100644
--- a/drivers/staging/zram/zram.txt
+++ b/drivers/staging/zram/zram.txt
@@ -23,17 +23,17 @@
This creates 4 devices: /dev/zram{0,1,2,3}
(num_devices parameter is optional. Default: 1)
-2) Set Disksize (Optional):
- Set disk size by writing the value to sysfs node 'disksize'
- (in bytes). If disksize is not given, default value of 25%
- of RAM is used.
+2) Set Disksize
+ Set disk size by writing the value to sysfs node 'disksize'.
+ The value can be either in bytes or you can use mem suffixes.
+ Examples:
+ # Initialize /dev/zram0 with 50MB disksize
+ echo $((50*1024*1024)) > /sys/block/zram0/disksize
- # Initialize /dev/zram0 with 50MB disksize
- echo $((50*1024*1024)) > /sys/block/zram0/disksize
-
- NOTE: disksize cannot be changed if the disk contains any
- data. So, for such a disk, you need to issue 'reset' (see below)
- before you can change its disksize.
+ # Using mem suffixes
+ echo 256K > /sys/block/zram0/disksize
+ echo 512M > /sys/block/zram0/disksize
+ echo 1G > /sys/block/zram0/disksize
3) Activate:
mkswap /dev/zram0
@@ -65,8 +65,9 @@
echo 1 > /sys/block/zram0/reset
echo 1 > /sys/block/zram1/reset
- (This frees all the memory allocated for the given device).
-
+ This frees all the memory allocated for the given device and
+ resets the disksize to zero. You must set the disksize again
+ before reusing the device.
Please report any problems at:
- Mailing list: linux-mm-cc at laptop dot org
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 685d612..91d94b5 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -37,56 +37,216 @@
/* Globals */
static int zram_major;
-struct zram *zram_devices;
+static struct zram *zram_devices;
/* Module params (documentation at end) */
-static unsigned int num_devices;
+static unsigned int num_devices = 1;
-static void zram_stat_inc(u32 *v)
+static inline struct zram *dev_to_zram(struct device *dev)
{
- *v = *v + 1;
+ return (struct zram *)dev_to_disk(dev)->private_data;
}
-static void zram_stat_dec(u32 *v)
+static ssize_t disksize_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- *v = *v - 1;
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n", zram->disksize);
}
-static void zram_stat64_add(struct zram *zram, u64 *v, u64 inc)
+static ssize_t initstate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- spin_lock(&zram->stat64_lock);
- *v = *v + inc;
- spin_unlock(&zram->stat64_lock);
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%u\n", zram->init_done);
}
-static void zram_stat64_sub(struct zram *zram, u64 *v, u64 dec)
+static ssize_t num_reads_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- spin_lock(&zram->stat64_lock);
- *v = *v - dec;
- spin_unlock(&zram->stat64_lock);
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)atomic64_read(&zram->stats.num_reads));
}
-static void zram_stat64_inc(struct zram *zram, u64 *v)
+static ssize_t num_writes_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- zram_stat64_add(zram, v, 1);
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)atomic64_read(&zram->stats.num_writes));
}
-static int zram_test_flag(struct zram *zram, u32 index,
+static ssize_t invalid_io_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)atomic64_read(&zram->stats.invalid_io));
+}
+
+static ssize_t notify_free_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)atomic64_read(&zram->stats.notify_free));
+}
+
+static ssize_t zero_pages_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%u\n", zram->stats.pages_zero);
+}
+
+static ssize_t orig_data_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)(zram->stats.pages_stored) << PAGE_SHIFT);
+}
+
+static ssize_t compr_data_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return sprintf(buf, "%llu\n",
+ (u64)atomic64_read(&zram->stats.compr_size));
+}
+
+static ssize_t mem_used_total_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u64 val = 0;
+ struct zram *zram = dev_to_zram(dev);
+ struct zram_meta *meta = zram->meta;
+
+ down_read(&zram->init_lock);
+ if (zram->init_done)
+ val = zs_get_total_size_bytes(meta->mem_pool);
+ up_read(&zram->init_lock);
+
+ return sprintf(buf, "%llu\n", val);
+}
+
+static int zram_test_flag(struct zram_meta *meta, u32 index,
enum zram_pageflags flag)
{
- return zram->table[index].flags & BIT(flag);
+ return meta->table[index].flags & BIT(flag);
}
-static void zram_set_flag(struct zram *zram, u32 index,
+static void zram_set_flag(struct zram_meta *meta, u32 index,
enum zram_pageflags flag)
{
- zram->table[index].flags |= BIT(flag);
+ meta->table[index].flags |= BIT(flag);
}
-static void zram_clear_flag(struct zram *zram, u32 index,
+static void zram_clear_flag(struct zram_meta *meta, u32 index,
enum zram_pageflags flag)
{
- zram->table[index].flags &= ~BIT(flag);
+ meta->table[index].flags &= ~BIT(flag);
+}
+
+static inline int is_partial_io(struct bio_vec *bvec)
+{
+ return bvec->bv_len != PAGE_SIZE;
+}
+
+/*
+ * Check if request is within bounds and aligned on zram logical blocks.
+ */
+static inline int valid_io_request(struct zram *zram, struct bio *bio)
+{
+ u64 start, end, bound;
+
+ /* unaligned request */
+ if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
+ return 0;
+ if (unlikely(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))
+ return 0;
+
+ start = bio->bi_sector;
+ end = start + (bio->bi_size >> SECTOR_SHIFT);
+ bound = zram->disksize >> SECTOR_SHIFT;
+ /* out of range range */
+ if (unlikely(start >= bound || end > bound || start > end))
+ return 0;
+
+ /* I/O request is valid */
+ return 1;
+}
+
+static void zram_meta_free(struct zram_meta *meta)
+{
+ zs_destroy_pool(meta->mem_pool);
+ kfree(meta->compress_workmem);
+ free_pages((unsigned long)meta->compress_buffer, 1);
+ vfree(meta->table);
+ kfree(meta);
+}
+
+static struct zram_meta *zram_meta_alloc(u64 disksize)
+{
+ size_t num_pages;
+ struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+ if (!meta)
+ goto out;
+
+ meta->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+ if (!meta->compress_workmem)
+ goto free_meta;
+
+ meta->compress_buffer =
+ (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
+ if (!meta->compress_buffer) {
+ pr_err("Error allocating compressor buffer space\n");
+ goto free_workmem;
+ }
+
+ num_pages = disksize >> PAGE_SHIFT;
+ meta->table = vzalloc(num_pages * sizeof(*meta->table));
+ if (!meta->table) {
+ pr_err("Error allocating zram address table\n");
+ goto free_buffer;
+ }
+
+ meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM);
+ if (!meta->mem_pool) {
+ pr_err("Error creating memory pool\n");
+ goto free_table;
+ }
+
+ return meta;
+
+free_table:
+ vfree(meta->table);
+free_buffer:
+ free_pages((unsigned long)meta->compress_buffer, 1);
+free_workmem:
+ kfree(meta->compress_workmem);
+free_meta:
+ kfree(meta);
+ meta = NULL;
+out:
+ return meta;
+}
+
+static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
+{
+ if (*offset + bvec->bv_len >= PAGE_SIZE)
+ (*index)++;
+ *offset = (*offset + bvec->bv_len) % PAGE_SIZE;
}
static int page_zero_filled(void *ptr)
@@ -104,352 +264,269 @@
return 1;
}
-static void zram_set_disksize(struct zram *zram, size_t totalram_bytes)
-{
- if (!zram->disksize) {
- pr_info(
- "disk size not provided. You can use disksize_kb module "
- "param to specify size.\nUsing default: (%u%% of RAM).\n",
- default_disksize_perc_ram
- );
- zram->disksize = default_disksize_perc_ram *
- (totalram_bytes / 100);
- }
-
- if (zram->disksize > 2 * (totalram_bytes)) {
- pr_info(
- "There is little point creating a zram of greater than "
- "twice the size of memory since we expect a 2:1 compression "
- "ratio. Note that zram uses about 0.1%% of the size of "
- "the disk when not in use so a huge zram is "
- "wasteful.\n"
- "\tMemory Size: %zu kB\n"
- "\tSize you selected: %llu kB\n"
- "Continuing anyway ...\n",
- totalram_bytes >> 10, zram->disksize
- );
- }
-
- zram->disksize &= PAGE_MASK;
-}
-
-static void zram_free_page(struct zram *zram, size_t index)
-{
- void *handle = zram->table[index].handle;
-
- if (unlikely(!handle)) {
- /*
- * No memory is allocated for zero filled pages.
- * Simply clear zero page flag.
- */
- if (zram_test_flag(zram, index, ZRAM_ZERO)) {
- zram_clear_flag(zram, index, ZRAM_ZERO);
- zram_stat_dec(&zram->stats.pages_zero);
- }
- return;
- }
-
- if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
- __free_page(handle);
- zram_clear_flag(zram, index, ZRAM_UNCOMPRESSED);
- zram_stat_dec(&zram->stats.pages_expand);
- goto out;
- }
-
- zs_free(zram->mem_pool, handle);
-
- if (zram->table[index].size <= PAGE_SIZE / 2)
- zram_stat_dec(&zram->stats.good_compress);
-
-out:
- zram_stat64_sub(zram, &zram->stats.compr_size,
- zram->table[index].size);
- zram_stat_dec(&zram->stats.pages_stored);
-
- zram->table[index].handle = NULL;
- zram->table[index].size = 0;
-}
-
static void handle_zero_page(struct bio_vec *bvec)
{
struct page *page = bvec->bv_page;
void *user_mem;
user_mem = kmap_atomic(page);
- memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
+ if (is_partial_io(bvec))
+ memset(user_mem + bvec->bv_offset, 0, bvec->bv_len);
+ else
+ clear_page(user_mem);
kunmap_atomic(user_mem);
flush_dcache_page(page);
}
-static void handle_uncompressed_page(struct zram *zram, struct bio_vec *bvec,
- u32 index, int offset)
+static void zram_free_page(struct zram *zram, size_t index)
{
- struct page *page = bvec->bv_page;
- unsigned char *user_mem, *cmem;
+ struct zram_meta *meta = zram->meta;
+ unsigned long handle = meta->table[index].handle;
+ u16 size = meta->table[index].size;
- user_mem = kmap_atomic(page);
- cmem = kmap_atomic(zram->table[index].handle);
+ if (unlikely(!handle)) {
+ /*
+ * No memory is allocated for zero filled pages.
+ * Simply clear zero page flag.
+ */
+ if (zram_test_flag(meta, index, ZRAM_ZERO)) {
+ zram_clear_flag(meta, index, ZRAM_ZERO);
+ zram->stats.pages_zero--;
+ }
+ return;
+ }
- memcpy(user_mem + bvec->bv_offset, cmem + offset, bvec->bv_len);
- kunmap_atomic(cmem);
- kunmap_atomic(user_mem);
+ if (unlikely(size > max_zpage_size))
+ zram->stats.bad_compress--;
- flush_dcache_page(page);
+ zs_free(meta->mem_pool, handle);
+
+ if (size <= PAGE_SIZE / 2)
+ zram->stats.good_compress--;
+
+ atomic64_sub(meta->table[index].size, &zram->stats.compr_size);
+ zram->stats.pages_stored--;
+
+ meta->table[index].handle = 0;
+ meta->table[index].size = 0;
}
-static inline int is_partial_io(struct bio_vec *bvec)
+static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
{
- return bvec->bv_len != PAGE_SIZE;
+ int ret = LZO_E_OK;
+ size_t clen = PAGE_SIZE;
+ unsigned char *cmem;
+ struct zram_meta *meta = zram->meta;
+ unsigned long handle = meta->table[index].handle;
+
+ if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
+ clear_page(mem);
+ return 0;
+ }
+
+ cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
+ if (meta->table[index].size == PAGE_SIZE)
+ copy_page(mem, cmem);
+ else
+ ret = lzo1x_decompress_safe(cmem, meta->table[index].size,
+ mem, &clen);
+ zs_unmap_object(meta->mem_pool, handle);
+
+ /* Should NEVER happen. Return bio error if it does. */
+ if (unlikely(ret != LZO_E_OK)) {
+ pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
+ atomic64_inc(&zram->stats.failed_reads);
+ return ret;
+ }
+
+ return 0;
}
static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
u32 index, int offset, struct bio *bio)
{
int ret;
- size_t clen;
struct page *page;
- struct zobj_header *zheader;
- unsigned char *user_mem, *cmem, *uncmem = NULL;
-
+ unsigned char *user_mem, *uncmem = NULL;
+ struct zram_meta *meta = zram->meta;
page = bvec->bv_page;
- if (zram_test_flag(zram, index, ZRAM_ZERO)) {
+ if (unlikely(!meta->table[index].handle) ||
+ zram_test_flag(meta, index, ZRAM_ZERO)) {
handle_zero_page(bvec);
return 0;
}
- /* Requested page is not present in compressed area */
- if (unlikely(!zram->table[index].handle)) {
- pr_debug("Read before write: sector=%lu, size=%u",
- (ulong)(bio->bi_sector), bio->bi_size);
- handle_zero_page(bvec);
- return 0;
- }
-
- /* Page is stored uncompressed since it's incompressible */
- if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
- handle_uncompressed_page(zram, bvec, index, offset);
- return 0;
- }
-
- if (is_partial_io(bvec)) {
+ if (is_partial_io(bvec))
/* Use a temporary buffer to decompress the page */
- uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!uncmem) {
- pr_info("Error allocating temp memory!\n");
- return -ENOMEM;
- }
- }
+ uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);
user_mem = kmap_atomic(page);
if (!is_partial_io(bvec))
uncmem = user_mem;
- clen = PAGE_SIZE;
- cmem = zs_map_object(zram->mem_pool, zram->table[index].handle);
-
- ret = lzo1x_decompress_safe(cmem + sizeof(*zheader),
- zram->table[index].size,
- uncmem, &clen);
-
- if (is_partial_io(bvec)) {
- memcpy(user_mem + bvec->bv_offset, uncmem + offset,
- bvec->bv_len);
- kfree(uncmem);
+ if (!uncmem) {
+ pr_info("Unable to allocate temp memory\n");
+ ret = -ENOMEM;
+ goto out_cleanup;
}
- zs_unmap_object(zram->mem_pool, zram->table[index].handle);
- kunmap_atomic(user_mem);
-
+ ret = zram_decompress_page(zram, uncmem, index);
/* Should NEVER happen. Return bio error if it does. */
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
- zram_stat64_inc(zram, &zram->stats.failed_reads);
- return ret;
- }
+ if (unlikely(ret != LZO_E_OK))
+ goto out_cleanup;
+
+ if (is_partial_io(bvec))
+ memcpy(user_mem + bvec->bv_offset, uncmem + offset,
+ bvec->bv_len);
flush_dcache_page(page);
-
- return 0;
-}
-
-static int zram_read_before_write(struct zram *zram, char *mem, u32 index)
-{
- int ret;
- size_t clen = PAGE_SIZE;
- struct zobj_header *zheader;
- unsigned char *cmem;
-
- if (zram_test_flag(zram, index, ZRAM_ZERO) ||
- !zram->table[index].handle) {
- memset(mem, 0, PAGE_SIZE);
- return 0;
- }
-
- cmem = zs_map_object(zram->mem_pool, zram->table[index].handle);
-
- /* Page is stored uncompressed since it's incompressible */
- if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
- memcpy(mem, cmem, PAGE_SIZE);
- kunmap_atomic(cmem);
- return 0;
- }
-
- ret = lzo1x_decompress_safe(cmem + sizeof(*zheader),
- zram->table[index].size,
- mem, &clen);
- zs_unmap_object(zram->mem_pool, zram->table[index].handle);
-
- /* Should NEVER happen. Return bio error if it does. */
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
- zram_stat64_inc(zram, &zram->stats.failed_reads);
- return ret;
- }
-
- return 0;
+ ret = 0;
+out_cleanup:
+ kunmap_atomic(user_mem);
+ if (is_partial_io(bvec))
+ kfree(uncmem);
+ return ret;
}
static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
int offset)
{
- int ret;
- u32 store_offset;
+ int ret = 0;
size_t clen;
- void *handle;
- struct zobj_header *zheader;
- struct page *page, *page_store;
+ unsigned long handle;
+ struct page *page;
unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
+ struct zram_meta *meta = zram->meta;
page = bvec->bv_page;
- src = zram->compress_buffer;
+ src = meta->compress_buffer;
if (is_partial_io(bvec)) {
/*
* This is a partial IO. We need to read the full page
* before to write the changes.
*/
- uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ uncmem = kmalloc(PAGE_SIZE, GFP_NOIO);
if (!uncmem) {
- pr_info("Error allocating temp memory!\n");
ret = -ENOMEM;
goto out;
}
- ret = zram_read_before_write(zram, uncmem, index);
- if (ret) {
- kfree(uncmem);
+ ret = zram_decompress_page(zram, uncmem, index);
+ if (ret)
goto out;
- }
}
- /*
- * System overwrites unused sectors. Free memory associated
- * with this sector now.
- */
- if (zram->table[index].handle ||
- zram_test_flag(zram, index, ZRAM_ZERO))
- zram_free_page(zram, index);
-
user_mem = kmap_atomic(page);
- if (is_partial_io(bvec))
+ if (is_partial_io(bvec)) {
memcpy(uncmem + offset, user_mem + bvec->bv_offset,
bvec->bv_len);
- else
+ kunmap_atomic(user_mem);
+ user_mem = NULL;
+ } else {
uncmem = user_mem;
+ }
if (page_zero_filled(uncmem)) {
kunmap_atomic(user_mem);
- if (is_partial_io(bvec))
- kfree(uncmem);
- zram_stat_inc(&zram->stats.pages_zero);
- zram_set_flag(zram, index, ZRAM_ZERO);
+ /* Free memory associated with this sector now. */
+ zram_free_page(zram, index);
+
+ zram->stats.pages_zero++;
+ zram_set_flag(meta, index, ZRAM_ZERO);
ret = 0;
goto out;
}
- ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
- zram->compress_workmem);
+ /*
+ * zram_slot_free_notify could miss free so that let's
+ * double check.
+ */
+ if (unlikely(meta->table[index].handle ||
+ zram_test_flag(meta, index, ZRAM_ZERO)))
+ zram_free_page(zram, index);
- kunmap_atomic(user_mem);
- if (is_partial_io(bvec))
- kfree(uncmem);
+ ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
+ meta->compress_workmem);
+
+ if (!is_partial_io(bvec)) {
+ kunmap_atomic(user_mem);
+ user_mem = NULL;
+ uncmem = NULL;
+ }
if (unlikely(ret != LZO_E_OK)) {
pr_err("Compression failed! err=%d\n", ret);
goto out;
}
- /*
- * Page is incompressible. Store it as-is (uncompressed)
- * since we do not want to return too many disk write
- * errors which has side effect of hanging the system.
- */
if (unlikely(clen > max_zpage_size)) {
+ zram->stats.bad_compress++;
clen = PAGE_SIZE;
- page_store = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
- if (unlikely(!page_store)) {
- pr_info("Error allocating memory for "
- "incompressible page: %u\n", index);
- ret = -ENOMEM;
- goto out;
- }
-
- store_offset = 0;
- zram_set_flag(zram, index, ZRAM_UNCOMPRESSED);
- zram_stat_inc(&zram->stats.pages_expand);
- handle = page_store;
- src = kmap_atomic(page);
- cmem = kmap_atomic(page_store);
- goto memstore;
+ src = NULL;
+ if (is_partial_io(bvec))
+ src = uncmem;
}
- handle = zs_malloc(zram->mem_pool, clen + sizeof(*zheader));
+ handle = zs_malloc(meta->mem_pool, clen);
if (!handle) {
- pr_info("Error allocating memory for compressed "
- "page: %u, size=%zu\n", index, clen);
+ pr_info("Error allocating memory for compressed page: %u, size=%zu\n",
+ index, clen);
ret = -ENOMEM;
goto out;
}
- cmem = zs_map_object(zram->mem_pool, handle);
+ cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO);
-memstore:
-#if 0
- /* Back-reference needed for memory defragmentation */
- if (!zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)) {
- zheader = (struct zobj_header *)cmem;
- zheader->table_idx = index;
- cmem += sizeof(*zheader);
- }
-#endif
-
- memcpy(cmem, src, clen);
-
- if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
- kunmap_atomic(cmem);
+ if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) {
+ src = kmap_atomic(page);
+ copy_page(cmem, src);
kunmap_atomic(src);
} else {
- zs_unmap_object(zram->mem_pool, handle);
+ memcpy(cmem, src, clen);
}
- zram->table[index].handle = handle;
- zram->table[index].size = clen;
+ zs_unmap_object(meta->mem_pool, handle);
+
+ /*
+ * Free memory associated with this sector
+ * before overwriting unused sectors.
+ */
+ zram_free_page(zram, index);
+
+ meta->table[index].handle = handle;
+ meta->table[index].size = clen;
/* Update stats */
- zram_stat64_add(zram, &zram->stats.compr_size, clen);
- zram_stat_inc(&zram->stats.pages_stored);
+ atomic64_add(clen, &zram->stats.compr_size);
+ zram->stats.pages_stored++;
if (clen <= PAGE_SIZE / 2)
- zram_stat_inc(&zram->stats.good_compress);
-
- return 0;
+ zram->stats.good_compress++;
out:
+ if (is_partial_io(bvec))
+ kfree(uncmem);
+
if (ret)
- zram_stat64_inc(zram, &zram->stats.failed_writes);
+ atomic64_inc(&zram->stats.failed_writes);
return ret;
}
+static void handle_pending_slot_free(struct zram *zram)
+{
+ struct zram_slot_free *free_rq;
+
+ spin_lock(&zram->slot_free_lock);
+ while (zram->slot_free_rq) {
+ free_rq = zram->slot_free_rq;
+ zram->slot_free_rq = free_rq->next;
+ zram_free_page(zram, free_rq->index);
+ kfree(free_rq);
+ }
+ spin_unlock(&zram->slot_free_lock);
+}
+
static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
int offset, struct bio *bio, int rw)
{
@@ -457,10 +534,12 @@
if (rw == READ) {
down_read(&zram->lock);
+ handle_pending_slot_free(zram);
ret = zram_bvec_read(zram, bvec, index, offset, bio);
up_read(&zram->lock);
} else {
down_write(&zram->lock);
+ handle_pending_slot_free(zram);
ret = zram_bvec_write(zram, bvec, index, offset);
up_write(&zram->lock);
}
@@ -468,11 +547,124 @@
return ret;
}
-static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
+static void zram_reset_device(struct zram *zram, bool reset_capacity)
{
- if (*offset + bvec->bv_len >= PAGE_SIZE)
- (*index)++;
- *offset = (*offset + bvec->bv_len) % PAGE_SIZE;
+ size_t index;
+ struct zram_meta *meta;
+
+ flush_work(&zram->free_work);
+
+ down_write(&zram->init_lock);
+ if (!zram->init_done) {
+ up_write(&zram->init_lock);
+ return;
+ }
+
+ meta = zram->meta;
+ zram->init_done = 0;
+
+ /* Free all pages that are still in this zram device */
+ for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
+ unsigned long handle = meta->table[index].handle;
+ if (!handle)
+ continue;
+
+ zs_free(meta->mem_pool, handle);
+ }
+
+ zram_meta_free(zram->meta);
+ zram->meta = NULL;
+ /* Reset stats */
+ memset(&zram->stats, 0, sizeof(zram->stats));
+
+ zram->disksize = 0;
+ if (reset_capacity)
+ set_capacity(zram->disk, 0);
+ up_write(&zram->init_lock);
+}
+
+static void zram_init_device(struct zram *zram, struct zram_meta *meta)
+{
+ if (zram->disksize > 2 * (totalram_pages << PAGE_SHIFT)) {
+ pr_info(
+ "There is little point creating a zram of greater than "
+ "twice the size of memory since we expect a 2:1 compression "
+ "ratio. Note that zram uses about 0.1%% of the size of "
+ "the disk when not in use so a huge zram is "
+ "wasteful.\n"
+ "\tMemory Size: %lu kB\n"
+ "\tSize you selected: %llu kB\n"
+ "Continuing anyway ...\n",
+ (totalram_pages << PAGE_SHIFT) >> 10, zram->disksize >> 10
+ );
+ }
+
+ /* zram devices sort of resembles non-rotational disks */
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
+
+ zram->meta = meta;
+ zram->init_done = 1;
+
+ pr_debug("Initialization done!\n");
+}
+
+static ssize_t disksize_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ u64 disksize;
+ struct zram_meta *meta;
+ struct zram *zram = dev_to_zram(dev);
+
+ disksize = memparse(buf, NULL);
+ if (!disksize)
+ return -EINVAL;
+
+ disksize = PAGE_ALIGN(disksize);
+ meta = zram_meta_alloc(disksize);
+ down_write(&zram->init_lock);
+ if (zram->init_done) {
+ up_write(&zram->init_lock);
+ zram_meta_free(meta);
+ pr_info("Cannot change disksize for initialized device\n");
+ return -EBUSY;
+ }
+
+ zram->disksize = disksize;
+ set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
+ zram_init_device(zram, meta);
+ up_write(&zram->init_lock);
+
+ return len;
+}
+
+static ssize_t reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ int ret;
+ unsigned short do_reset;
+ struct zram *zram;
+ struct block_device *bdev;
+
+ zram = dev_to_zram(dev);
+ bdev = bdget_disk(zram->disk, 0);
+
+ /* Do not reset an active device! */
+ if (bdev->bd_holders)
+ return -EBUSY;
+
+ ret = kstrtou16(buf, 10, &do_reset);
+ if (ret)
+ return ret;
+
+ if (!do_reset)
+ return -EINVAL;
+
+ /* Make sure all pending I/O is finished */
+ if (bdev)
+ fsync_bdev(bdev);
+
+ zram_reset_device(zram, true);
+ return len;
}
static void __zram_make_request(struct zram *zram, struct bio *bio, int rw)
@@ -483,10 +675,10 @@
switch (rw) {
case READ:
- zram_stat64_inc(zram, &zram->stats.num_reads);
+ atomic64_inc(&zram->stats.num_reads);
break;
case WRITE:
- zram_stat64_inc(zram, &zram->stats.num_writes);
+ atomic64_inc(&zram->stats.num_writes);
break;
}
@@ -531,39 +723,19 @@
}
/*
- * Check if request is within bounds and aligned on zram logical blocks.
- */
-static inline int valid_io_request(struct zram *zram, struct bio *bio)
-{
- if (unlikely(
- (bio->bi_sector >= (zram->disksize >> SECTOR_SHIFT)) ||
- (bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)) ||
- (bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))) {
-
- return 0;
- }
-
- /* I/O request is valid */
- return 1;
-}
-
-/*
* Handler function for all zram I/O requests.
*/
static void zram_make_request(struct request_queue *queue, struct bio *bio)
{
struct zram *zram = queue->queuedata;
- if (unlikely(!zram->init_done) && zram_init_device(zram))
- goto error;
-
down_read(&zram->init_lock);
if (unlikely(!zram->init_done))
- goto error_unlock;
+ goto error;
if (!valid_io_request(zram, bio)) {
- zram_stat64_inc(zram, &zram->stats.invalid_io);
- goto error_unlock;
+ atomic64_inc(&zram->stats.invalid_io);
+ goto error;
}
__zram_make_request(zram, bio, bio_data_dir(bio));
@@ -571,129 +743,45 @@
return;
-error_unlock:
- up_read(&zram->init_lock);
error:
+ up_read(&zram->init_lock);
bio_io_error(bio);
}
-void __zram_reset_device(struct zram *zram)
+static void zram_slot_free(struct work_struct *work)
{
- size_t index;
+ struct zram *zram;
- zram->init_done = 0;
-
- /* Free various per-device buffers */
- kfree(zram->compress_workmem);
- free_pages((unsigned long)zram->compress_buffer, 1);
-
- zram->compress_workmem = NULL;
- zram->compress_buffer = NULL;
-
- /* Free all pages that are still in this zram device */
- for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
- void *handle = zram->table[index].handle;
- if (!handle)
- continue;
-
- if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED)))
- __free_page(handle);
- else
- zs_free(zram->mem_pool, handle);
- }
-
- vfree(zram->table);
- zram->table = NULL;
-
- zs_destroy_pool(zram->mem_pool);
- zram->mem_pool = NULL;
-
- /* Reset stats */
- memset(&zram->stats, 0, sizeof(zram->stats));
-
- zram->disksize = 0;
+ zram = container_of(work, struct zram, free_work);
+ down_write(&zram->lock);
+ handle_pending_slot_free(zram);
+ up_write(&zram->lock);
}
-void zram_reset_device(struct zram *zram)
+static void add_slot_free(struct zram *zram, struct zram_slot_free *free_rq)
{
- down_write(&zram->init_lock);
- __zram_reset_device(zram);
- up_write(&zram->init_lock);
-}
-
-int zram_init_device(struct zram *zram)
-{
- int ret;
- size_t num_pages;
-
- down_write(&zram->init_lock);
-
- if (zram->init_done) {
- up_write(&zram->init_lock);
- return 0;
- }
-
- zram_set_disksize(zram, totalram_pages << PAGE_SHIFT);
-
- zram->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
- if (!zram->compress_workmem) {
- pr_err("Error allocating compressor working memory!\n");
- ret = -ENOMEM;
- goto fail_no_table;
- }
-
- zram->compress_buffer =
- (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
- if (!zram->compress_buffer) {
- pr_err("Error allocating compressor buffer space\n");
- ret = -ENOMEM;
- goto fail_no_table;
- }
-
- num_pages = zram->disksize >> PAGE_SHIFT;
- zram->table = vzalloc(num_pages * sizeof(*zram->table));
- if (!zram->table) {
- pr_err("Error allocating zram address table\n");
- ret = -ENOMEM;
- goto fail_no_table;
- }
-
- set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
-
- /* zram devices sort of resembles non-rotational disks */
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
-
- zram->mem_pool = zs_create_pool("zram", GFP_NOIO | __GFP_HIGHMEM);
- if (!zram->mem_pool) {
- pr_err("Error creating memory pool\n");
- ret = -ENOMEM;
- goto fail;
- }
-
- zram->init_done = 1;
- up_write(&zram->init_lock);
-
- pr_debug("Initialization done!\n");
- return 0;
-
-fail_no_table:
- /* To prevent accessing table entries during cleanup */
- zram->disksize = 0;
-fail:
- __zram_reset_device(zram);
- up_write(&zram->init_lock);
- pr_err("Initialization failed: err=%d\n", ret);
- return ret;
+ spin_lock(&zram->slot_free_lock);
+ free_rq->next = zram->slot_free_rq;
+ zram->slot_free_rq = free_rq;
+ spin_unlock(&zram->slot_free_lock);
}
static void zram_slot_free_notify(struct block_device *bdev,
unsigned long index)
{
struct zram *zram;
+ struct zram_slot_free *free_rq;
zram = bdev->bd_disk->private_data;
- zram_free_page(zram, index);
- zram_stat64_inc(zram, &zram->stats.notify_free);
+ atomic64_inc(&zram->stats.notify_free);
+
+ free_rq = kmalloc(sizeof(struct zram_slot_free), GFP_ATOMIC);
+ if (!free_rq)
+ return;
+
+ free_rq->index = index;
+ add_slot_free(zram, free_rq);
+ schedule_work(&zram->free_work);
}
static const struct block_device_operations zram_devops = {
@@ -701,19 +789,53 @@
.owner = THIS_MODULE
};
+static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
+ disksize_show, disksize_store);
+static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
+static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
+static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL);
+static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL);
+static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL);
+static DEVICE_ATTR(notify_free, S_IRUGO, notify_free_show, NULL);
+static DEVICE_ATTR(zero_pages, S_IRUGO, zero_pages_show, NULL);
+static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL);
+static DEVICE_ATTR(compr_data_size, S_IRUGO, compr_data_size_show, NULL);
+static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL);
+
+static struct attribute *zram_disk_attrs[] = {
+ &dev_attr_disksize.attr,
+ &dev_attr_initstate.attr,
+ &dev_attr_reset.attr,
+ &dev_attr_num_reads.attr,
+ &dev_attr_num_writes.attr,
+ &dev_attr_invalid_io.attr,
+ &dev_attr_notify_free.attr,
+ &dev_attr_zero_pages.attr,
+ &dev_attr_orig_data_size.attr,
+ &dev_attr_compr_data_size.attr,
+ &dev_attr_mem_used_total.attr,
+ NULL,
+};
+
+static struct attribute_group zram_disk_attr_group = {
+ .attrs = zram_disk_attrs,
+};
+
static int create_device(struct zram *zram, int device_id)
{
- int ret = 0;
+ int ret = -ENOMEM;
init_rwsem(&zram->lock);
init_rwsem(&zram->init_lock);
- spin_lock_init(&zram->stat64_lock);
+
+ INIT_WORK(&zram->free_work, zram_slot_free);
+ spin_lock_init(&zram->slot_free_lock);
+ zram->slot_free_rq = NULL;
zram->queue = blk_alloc_queue(GFP_KERNEL);
if (!zram->queue) {
pr_err("Error allocating disk queue for device %d\n",
device_id);
- ret = -ENOMEM;
goto out;
}
@@ -723,11 +845,9 @@
/* gendisk structure */
zram->disk = alloc_disk(1);
if (!zram->disk) {
- blk_cleanup_queue(zram->queue);
- pr_warning("Error allocating disk structure for device %d\n",
+ pr_warn("Error allocating disk structure for device %d\n",
device_id);
- ret = -ENOMEM;
- goto out;
+ goto out_free_queue;
}
zram->disk->major = zram_major;
@@ -755,12 +875,18 @@
ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj,
&zram_disk_attr_group);
if (ret < 0) {
- pr_warning("Error creating sysfs group");
- goto out;
+ pr_warn("Error creating sysfs group");
+ goto out_free_disk;
}
zram->init_done = 0;
+ return 0;
+out_free_disk:
+ del_gendisk(zram->disk);
+ put_disk(zram->disk);
+out_free_queue:
+ blk_cleanup_queue(zram->queue);
out:
return ret;
}
@@ -779,17 +905,12 @@
blk_cleanup_queue(zram->queue);
}
-unsigned int zram_get_num_devices(void)
-{
- return num_devices;
-}
-
static int __init zram_init(void)
{
int ret, dev_id;
if (num_devices > max_num_devices) {
- pr_warning("Invalid value for num_devices: %u\n",
+ pr_warn("Invalid value for num_devices: %u\n",
num_devices);
ret = -EINVAL;
goto out;
@@ -797,18 +918,12 @@
zram_major = register_blkdev(0, "zram");
if (zram_major <= 0) {
- pr_warning("Unable to get major number\n");
+ pr_warn("Unable to get major number\n");
ret = -EBUSY;
goto out;
}
- if (!num_devices) {
- pr_info("num_devices not specified. Using default: 1\n");
- num_devices = 1;
- }
-
/* Allocate the device array and initialize each one */
- pr_info("Creating %u devices ...\n", num_devices);
zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
if (!zram_devices) {
ret = -ENOMEM;
@@ -821,6 +936,8 @@
goto free_devices;
}
+ pr_info("Created %u device(s) ...\n", num_devices);
+
return 0;
free_devices:
@@ -842,8 +959,11 @@
zram = &zram_devices[i];
destroy_device(zram);
- if (zram->init_done)
- zram_reset_device(zram);
+ /*
+ * Shouldn't access zram->disk after destroy_device
+ * because destroy_device already released zram->disk.
+ */
+ zram_reset_device(zram, false);
}
unregister_blkdev(zram_major, "zram");
@@ -852,12 +972,13 @@
pr_debug("Cleanup done!\n");
}
-module_param(num_devices, uint, 0);
-MODULE_PARM_DESC(num_devices, "Number of zram devices");
-
module_init(zram_init);
module_exit(zram_exit);
+module_param(num_devices, uint, 0);
+MODULE_PARM_DESC(num_devices, "Number of zram devices");
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
MODULE_DESCRIPTION("Compressed RAM Block Device");
+MODULE_ALIAS("devname:zram");
diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h
index fbe8ac9..97a3acf 100644
--- a/drivers/staging/zram/zram_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -26,23 +26,8 @@
*/
static const unsigned max_num_devices = 32;
-/*
- * Stored at beginning of each compressed object.
- *
- * It stores back-reference to table entry which points to this
- * object. This is required to support memory defragmentation.
- */
-struct zobj_header {
-#if 0
- u32 table_idx;
-#endif
-};
-
/*-- Configurable parameters */
-/* Default zram disk size: 25% of total RAM */
-static const unsigned default_disksize_perc_ram = 25;
-
/*
* Pages that compress to size greater than this are stored
* uncompressed in memory.
@@ -51,8 +36,8 @@
/*
* NOTE: max_zpage_size must be less than or equal to:
- * ZS_MAX_ALLOC_SIZE - sizeof(struct zobj_header)
- * otherwise, xv_malloc() would always return failure.
+ * ZS_MAX_ALLOC_SIZE. Otherwise, zs_malloc() would
+ * always return failure.
*/
/*-- End of configurable params */
@@ -68,9 +53,6 @@
/* Flags for zram pages (table[page_no].flags) */
enum zram_pageflags {
- /* Page is stored uncompressed */
- ZRAM_UNCOMPRESSED,
-
/* Page consists entirely of zeros */
ZRAM_ZERO,
@@ -81,34 +63,51 @@
/* Allocated for each disk page */
struct table {
- void *handle;
+ unsigned long handle;
u16 size; /* object size (excluding header) */
u8 count; /* object ref count (not yet used) */
u8 flags;
-} __attribute__((aligned(4)));
+} __aligned(4);
+/*
+ * All 64bit fields should only be manipulated by 64bit atomic accessors.
+ * All modifications to 32bit counter should be protected by zram->lock.
+ */
struct zram_stats {
- u64 compr_size; /* compressed size of pages stored */
- u64 num_reads; /* failed + successful */
- u64 num_writes; /* --do-- */
- u64 failed_reads; /* should NEVER! happen */
- u64 failed_writes; /* can happen when memory is too low */
- u64 invalid_io; /* non-page-aligned I/O requests */
- u64 notify_free; /* no. of swap slot free notifications */
+ atomic64_t compr_size; /* compressed size of pages stored */
+ atomic64_t num_reads; /* failed + successful */
+ atomic64_t num_writes; /* --do-- */
+ atomic64_t failed_reads; /* should NEVER! happen */
+ atomic64_t failed_writes; /* can happen when memory is too low */
+ atomic64_t invalid_io; /* non-page-aligned I/O requests */
+ atomic64_t notify_free; /* no. of swap slot free notifications */
u32 pages_zero; /* no. of zero filled pages */
u32 pages_stored; /* no. of pages currently stored */
u32 good_compress; /* % of pages with compression ratio<=50% */
- u32 pages_expand; /* % of incompressible pages */
+ u32 bad_compress; /* % of pages with compression ratio>=75% */
};
-struct zram {
- struct zs_pool *mem_pool;
+struct zram_meta {
void *compress_workmem;
void *compress_buffer;
struct table *table;
- spinlock_t stat64_lock; /* protect 64-bit stats */
- struct rw_semaphore lock; /* protect compression buffers and table
- * against concurrent read and writes */
+ struct zs_pool *mem_pool;
+};
+
+struct zram_slot_free {
+ unsigned long index;
+ struct zram_slot_free *next;
+};
+
+struct zram {
+ struct zram_meta *meta;
+ struct rw_semaphore lock; /* protect compression buffers, table,
+ * 32bit stat counters against concurrent
+ * notifications, reads and writes */
+
+ struct work_struct free_work; /* handle pending free request */
+ struct zram_slot_free *slot_free_rq; /* list head of free request */
+
struct request_queue *queue;
struct gendisk *disk;
int init_done;
@@ -119,17 +118,8 @@
* we can store in a disk.
*/
u64 disksize; /* bytes */
+ spinlock_t slot_free_lock;
struct zram_stats stats;
};
-
-extern struct zram *zram_devices;
-unsigned int zram_get_num_devices(void);
-#ifdef CONFIG_SYSFS
-extern struct attribute_group zram_disk_attr_group;
-#endif
-
-extern int zram_init_device(struct zram *zram);
-extern void __zram_reset_device(struct zram *zram);
-
#endif
diff --git a/drivers/staging/zram/zram_sysfs.c b/drivers/staging/zram/zram_sysfs.c
deleted file mode 100644
index a7f3771..0000000
--- a/drivers/staging/zram/zram_sysfs.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Compressed RAM block device
- *
- * Copyright (C) 2008, 2009, 2010 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the licence that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- *
- * Project home: http://compcache.googlecode.com/
- */
-
-#include <linux/device.h>
-#include <linux/genhd.h>
-#include <linux/mm.h>
-
-#include "zram_drv.h"
-
-static u64 zram_stat64_read(struct zram *zram, u64 *v)
-{
- u64 val;
-
- spin_lock(&zram->stat64_lock);
- val = *v;
- spin_unlock(&zram->stat64_lock);
-
- return val;
-}
-
-static struct zram *dev_to_zram(struct device *dev)
-{
- int i;
- struct zram *zram = NULL;
-
- for (i = 0; i < zram_get_num_devices(); i++) {
- zram = &zram_devices[i];
- if (disk_to_dev(zram->disk) == dev)
- break;
- }
-
- return zram;
-}
-
-static ssize_t disksize_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n", zram->disksize);
-}
-
-static ssize_t disksize_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
-{
- int ret;
- u64 disksize;
- struct zram *zram = dev_to_zram(dev);
-
- ret = kstrtoull(buf, 10, &disksize);
- if (ret)
- return ret;
-
- down_write(&zram->init_lock);
- if (zram->init_done) {
- up_write(&zram->init_lock);
- pr_info("Cannot change disksize for initialized device\n");
- return -EBUSY;
- }
-
- zram->disksize = PAGE_ALIGN(disksize);
- set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
- up_write(&zram->init_lock);
-
- return len;
-}
-
-static ssize_t initstate_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%u\n", zram->init_done);
-}
-
-static ssize_t reset_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
-{
- int ret;
- unsigned short do_reset;
- struct zram *zram;
- struct block_device *bdev;
-
- zram = dev_to_zram(dev);
- bdev = bdget_disk(zram->disk, 0);
-
- /* Do not reset an active device! */
- if (bdev->bd_holders)
- return -EBUSY;
-
- ret = kstrtou16(buf, 10, &do_reset);
- if (ret)
- return ret;
-
- if (!do_reset)
- return -EINVAL;
-
- /* Make sure all pending I/O is finished */
- if (bdev)
- fsync_bdev(bdev);
-
- down_write(&zram->init_lock);
- if (zram->init_done)
- __zram_reset_device(zram);
- up_write(&zram->init_lock);
-
- return len;
-}
-
-static ssize_t num_reads_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.num_reads));
-}
-
-static ssize_t num_writes_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.num_writes));
-}
-
-static ssize_t invalid_io_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.invalid_io));
-}
-
-static ssize_t notify_free_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.notify_free));
-}
-
-static ssize_t zero_pages_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%u\n", zram->stats.pages_zero);
-}
-
-static ssize_t orig_data_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- (u64)(zram->stats.pages_stored) << PAGE_SHIFT);
-}
-
-static ssize_t compr_data_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct zram *zram = dev_to_zram(dev);
-
- return sprintf(buf, "%llu\n",
- zram_stat64_read(zram, &zram->stats.compr_size));
-}
-
-static ssize_t mem_used_total_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- u64 val = 0;
- struct zram *zram = dev_to_zram(dev);
-
- if (zram->init_done) {
- val = zs_get_total_size_bytes(zram->mem_pool) +
- ((u64)(zram->stats.pages_expand) << PAGE_SHIFT);
- }
-
- return sprintf(buf, "%llu\n", val);
-}
-
-static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
- disksize_show, disksize_store);
-static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
-static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
-static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL);
-static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL);
-static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL);
-static DEVICE_ATTR(notify_free, S_IRUGO, notify_free_show, NULL);
-static DEVICE_ATTR(zero_pages, S_IRUGO, zero_pages_show, NULL);
-static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL);
-static DEVICE_ATTR(compr_data_size, S_IRUGO, compr_data_size_show, NULL);
-static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL);
-
-static struct attribute *zram_disk_attrs[] = {
- &dev_attr_disksize.attr,
- &dev_attr_initstate.attr,
- &dev_attr_reset.attr,
- &dev_attr_num_reads.attr,
- &dev_attr_num_writes.attr,
- &dev_attr_invalid_io.attr,
- &dev_attr_notify_free.attr,
- &dev_attr_zero_pages.attr,
- &dev_attr_orig_data_size.attr,
- &dev_attr_compr_data_size.attr,
- &dev_attr_mem_used_total.attr,
- NULL,
-};
-
-struct attribute_group zram_disk_attr_group = {
- .attrs = zram_disk_attrs,
-};
diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig
index a5ab720..7fab032 100644
--- a/drivers/staging/zsmalloc/Kconfig
+++ b/drivers/staging/zsmalloc/Kconfig
@@ -1,9 +1,5 @@
config ZSMALLOC
- tristate "Memory allocator for compressed pages"
- # X86 dependency is because of the use of __flush_tlb_one and set_pte
- # in zsmalloc-main.c.
- # TODO: convert these to portable functions
- depends on X86
+ bool "Memory allocator for compressed pages"
default n
help
zsmalloc is a slab-based memory allocator designed to store
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 917461c..1a67537 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -10,6 +10,54 @@
* Released under the terms of GNU General Public License Version 2.0
*/
+
+/*
+ * This allocator is designed for use with zcache and zram. Thus, the
+ * allocator is supposed to work well under low memory conditions. In
+ * particular, it never attempts higher order page allocation which is
+ * very likely to fail under memory pressure. On the other hand, if we
+ * just use single (0-order) pages, it would suffer from very high
+ * fragmentation -- any object of size PAGE_SIZE/2 or larger would occupy
+ * an entire page. This was one of the major issues with its predecessor
+ * (xvmalloc).
+ *
+ * To overcome these issues, zsmalloc allocates a bunch of 0-order pages
+ * and links them together using various 'struct page' fields. These linked
+ * pages act as a single higher-order page i.e. an object can span 0-order
+ * page boundaries. The code refers to these linked pages as a single entity
+ * called zspage.
+ *
+ * Following is how we use various fields and flags of underlying
+ * struct page(s) to form a zspage.
+ *
+ * Usage of struct page fields:
+ * page->first_page: points to the first component (0-order) page
+ * page->index (union with page->freelist): offset of the first object
+ * starting in this page. For the first page, this is
+ * always 0, so we use this field (aka freelist) to point
+ * to the first free object in zspage.
+ * page->lru: links together all component pages (except the first page)
+ * of a zspage
+ *
+ * For _first_ page only:
+ *
+ * page->private (union with page->first_page): refers to the
+ * component page after the first page
+ * page->freelist: points to the first free object in zspage.
+ * Free objects are linked together using in-place
+ * metadata.
+ * page->objects: maximum number of objects we can store in this
+ * zspage (class->zspage_order * PAGE_SIZE / class->size)
+ * page->lru: links together first pages of various zspages.
+ * Basically forming list of zspages in a fullness group.
+ * page->mapping: class index and fullness group of the zspage
+ *
+ * Usage of struct page flags:
+ * PG_private: identifies the first component page
+ * PG_private2: identifies the last component page
+ *
+ */
+
#ifdef CONFIG_ZSMALLOC_DEBUG
#define DEBUG
#endif
@@ -27,9 +75,139 @@
#include <linux/cpumask.h>
#include <linux/cpu.h>
#include <linux/vmalloc.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
#include "zsmalloc.h"
-#include "zsmalloc_int.h"
+
+/*
+ * This must be power of 2 and greater than of equal to sizeof(link_free).
+ * These two conditions ensure that any 'struct link_free' itself doesn't
+ * span more than 1 page which avoids complex case of mapping 2 pages simply
+ * to restore link_free pointer values.
+ */
+#define ZS_ALIGN 8
+
+/*
+ * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
+ * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
+ */
+#define ZS_MAX_ZSPAGE_ORDER 2
+#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
+
+/*
+ * Object location (<PFN>, <obj_idx>) is encoded as
+ * as single (void *) handle value.
+ *
+ * Note that object index <obj_idx> is relative to system
+ * page <PFN> it is stored in, so for each sub-page belonging
+ * to a zspage, obj_idx starts with 0.
+ *
+ * This is made more complicated by various memory models and PAE.
+ */
+
+#ifndef MAX_PHYSMEM_BITS
+#ifdef CONFIG_HIGHMEM64G
+#define MAX_PHYSMEM_BITS 36
+#else /* !CONFIG_HIGHMEM64G */
+/*
+ * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
+ * be PAGE_SHIFT
+ */
+#define MAX_PHYSMEM_BITS BITS_PER_LONG
+#endif
+#endif
+#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT)
+#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
+#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
+#define ZS_MIN_ALLOC_SIZE \
+ MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
+#define ZS_MAX_ALLOC_SIZE PAGE_SIZE
+
+/*
+ * On systems with 4K page size, this gives 254 size classes! There is a
+ * trader-off here:
+ * - Large number of size classes is potentially wasteful as free page are
+ * spread across these classes
+ * - Small number of size classes causes large internal fragmentation
+ * - Probably its better to use specific size classes (empirically
+ * determined). NOTE: all those class sizes must be set as multiple of
+ * ZS_ALIGN to make sure link_free itself never has to span 2 pages.
+ *
+ * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
+ * (reason above)
+ */
+#define ZS_SIZE_CLASS_DELTA (PAGE_SIZE >> 8)
+#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
+ ZS_SIZE_CLASS_DELTA + 1)
+
+/*
+ * We do not maintain any list for completely empty or full pages
+ */
+enum fullness_group {
+ ZS_ALMOST_FULL,
+ ZS_ALMOST_EMPTY,
+ _ZS_NR_FULLNESS_GROUPS,
+
+ ZS_EMPTY,
+ ZS_FULL
+};
+
+/*
+ * We assign a page to ZS_ALMOST_EMPTY fullness group when:
+ * n <= N / f, where
+ * n = number of allocated objects
+ * N = total number of objects zspage can store
+ * f = 1/fullness_threshold_frac
+ *
+ * Similarly, we assign zspage to:
+ * ZS_ALMOST_FULL when n > N / f
+ * ZS_EMPTY when n == 0
+ * ZS_FULL when n == N
+ *
+ * (see: fix_fullness_group())
+ */
+static const int fullness_threshold_frac = 4;
+
+struct size_class {
+ /*
+ * Size of objects stored in this class. Must be multiple
+ * of ZS_ALIGN.
+ */
+ int size;
+ unsigned int index;
+
+ /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+ int pages_per_zspage;
+
+ spinlock_t lock;
+
+ /* stats */
+ u64 pages_allocated;
+
+ struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
+};
+
+/*
+ * Placed within free objects to form a singly linked list.
+ * For every zspage, first_page->freelist gives head of this list.
+ *
+ * This must be power of 2 and less than or equal to ZS_ALIGN
+ */
+struct link_free {
+ /* Handle of next free chunk (encodes <PFN, obj_idx>) */
+ void *next;
+};
+
+struct zs_pool {
+ struct size_class size_class[ZS_SIZE_CLASSES];
+
+ gfp_t flags; /* allocation flags used when growing pool */
+};
/*
* A zspage's class index and fullness group
@@ -40,17 +218,39 @@
#define CLASS_IDX_MASK ((1 << CLASS_IDX_BITS) - 1)
#define FULLNESS_MASK ((1 << FULLNESS_BITS) - 1)
+/*
+ * By default, zsmalloc uses a copy-based object mapping method to access
+ * allocations that span two pages. However, if a particular architecture
+ * performs VM mapping faster than copying, then it should be added here
+ * so that USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use
+ * page table mapping rather than copying for object mapping.
+ */
+#if defined(CONFIG_ARM) && !defined(MODULE)
+#define USE_PGTABLE_MAPPING
+#endif
+
+struct mapping_area {
+#ifdef USE_PGTABLE_MAPPING
+ struct vm_struct *vm; /* vm area for mapping object that span pages */
+#else
+ char *vm_buf; /* copy buffer for objects that span pages */
+#endif
+ char *vm_addr; /* address of kmap_atomic()'ed pages */
+ enum zs_mapmode vm_mm; /* mapping mode */
+};
+
+
/* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
static int is_first_page(struct page *page)
{
- return test_bit(PG_private, &page->flags);
+ return PagePrivate(page);
}
static int is_last_page(struct page *page)
{
- return test_bit(PG_private_2, &page->flags);
+ return PagePrivate2(page);
}
static void get_zspage_mapping(struct page *page, unsigned int *class_idx,
@@ -180,7 +380,7 @@
* link together 3 PAGE_SIZE sized pages to form a zspage
* since then we can perfectly fit in 8 such objects.
*/
-static int get_zspage_order(int class_size)
+static int get_pages_per_zspage(int class_size)
{
int i, max_usedpc = 0;
/* zspage order which gives maximum used size per KB */
@@ -223,7 +423,7 @@
if (is_last_page(page))
next = NULL;
else if (is_first_page(page))
- next = (struct page *)page->private;
+ next = (struct page *)page_private(page);
else
next = list_entry(page->lru.next, struct page, lru);
@@ -247,13 +447,11 @@
}
/* Decode <page, obj_idx> pair from the given object handle */
-static void obj_handle_to_location(void *handle, struct page **page,
+static void obj_handle_to_location(unsigned long handle, struct page **page,
unsigned long *obj_idx)
{
- unsigned long hval = (unsigned long)handle;
-
- *page = pfn_to_page(hval >> OBJ_INDEX_BITS);
- *obj_idx = hval & OBJ_INDEX_MASK;
+ *page = pfn_to_page(handle >> OBJ_INDEX_BITS);
+ *obj_idx = handle & OBJ_INDEX_MASK;
}
static unsigned long obj_idx_to_offset(struct page *page,
@@ -274,7 +472,7 @@
set_page_private(page, 0);
page->mapping = NULL;
page->freelist = NULL;
- reset_page_mapcount(page);
+ page_mapcount_reset(page);
}
static void free_zspage(struct page *first_page)
@@ -354,7 +552,7 @@
static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
{
int i, error;
- struct page *first_page = NULL;
+ struct page *first_page = NULL, *uninitialized_var(prev_page);
/*
* Allocate individual pages and link them together as:
@@ -368,8 +566,8 @@
* identify the last page.
*/
error = -ENOMEM;
- for (i = 0; i < class->zspage_order; i++) {
- struct page *page, *prev_page;
+ for (i = 0; i < class->pages_per_zspage; i++) {
+ struct page *page;
page = alloc_page(flags);
if (!page)
@@ -377,20 +575,19 @@
INIT_LIST_HEAD(&page->lru);
if (i == 0) { /* first page */
- set_bit(PG_private, &page->flags);
+ SetPagePrivate(page);
set_page_private(page, 0);
first_page = page;
first_page->inuse = 0;
}
if (i == 1)
- first_page->private = (unsigned long)page;
+ set_page_private(first_page, (unsigned long)page);
if (i >= 1)
page->first_page = first_page;
if (i >= 2)
list_add(&page->lru, &prev_page->lru);
- if (i == class->zspage_order - 1) /* last page */
- set_bit(PG_private_2, &page->flags);
-
+ if (i == class->pages_per_zspage - 1) /* last page */
+ SetPagePrivate2(page);
prev_page = page;
}
@@ -398,7 +595,7 @@
first_page->freelist = obj_location_to_handle(first_page, 0);
/* Maximum number of objects we can store in this zspage */
- first_page->objects = class->zspage_order * PAGE_SIZE / class->size;
+ first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size;
error = 0; /* Success */
@@ -425,34 +622,141 @@
return page;
}
+#ifdef USE_PGTABLE_MAPPING
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+ /*
+ * Make sure we don't leak memory if a cpu UP notification
+ * and zs_init() race and both call zs_cpu_up() on the same cpu
+ */
+ if (area->vm)
+ return 0;
+ area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL);
+ if (!area->vm)
+ return -ENOMEM;
+ return 0;
+}
-/*
- * If this becomes a separate module, register zs_init() with
- * module_init(), zs_exit with module_exit(), and remove zs_initialized
-*/
-static int zs_initialized;
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+ if (area->vm)
+ free_vm_area(area->vm);
+ area->vm = NULL;
+}
+
+static inline void *__zs_map_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, &pages));
+ area->vm_addr = area->vm->addr;
+ return area->vm_addr + off;
+}
+
+static inline void __zs_unmap_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ unsigned long addr = (unsigned long)area->vm_addr;
+
+ unmap_kernel_range(addr, PAGE_SIZE * 2);
+}
+
+#else /* USE_PGTABLE_MAPPING */
+
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+ /*
+ * Make sure we don't leak memory if a cpu UP notification
+ * and zs_init() race and both call zs_cpu_up() on the same cpu
+ */
+ if (area->vm_buf)
+ return 0;
+ area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
+ if (!area->vm_buf)
+ return -ENOMEM;
+ return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+ if (area->vm_buf)
+ free_page((unsigned long)area->vm_buf);
+ area->vm_buf = NULL;
+}
+
+static void *__zs_map_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ int sizes[2];
+ void *addr;
+ char *buf = area->vm_buf;
+
+ /* disable page faults to match kmap_atomic() return conditions */
+ pagefault_disable();
+
+ /* no read fastpath */
+ if (area->vm_mm == ZS_MM_WO)
+ goto out;
+
+ sizes[0] = PAGE_SIZE - off;
+ sizes[1] = size - sizes[0];
+
+ /* copy object to per-cpu buffer */
+ addr = kmap_atomic(pages[0]);
+ memcpy(buf, addr + off, sizes[0]);
+ kunmap_atomic(addr);
+ addr = kmap_atomic(pages[1]);
+ memcpy(buf + sizes[0], addr, sizes[1]);
+ kunmap_atomic(addr);
+out:
+ return area->vm_buf;
+}
+
+static void __zs_unmap_object(struct mapping_area *area,
+ struct page *pages[2], int off, int size)
+{
+ int sizes[2];
+ void *addr;
+ char *buf = area->vm_buf;
+
+ /* no write fastpath */
+ if (area->vm_mm == ZS_MM_RO)
+ goto out;
+
+ sizes[0] = PAGE_SIZE - off;
+ sizes[1] = size - sizes[0];
+
+ /* copy per-cpu buffer to object */
+ addr = kmap_atomic(pages[0]);
+ memcpy(addr + off, buf, sizes[0]);
+ kunmap_atomic(addr);
+ addr = kmap_atomic(pages[1]);
+ memcpy(addr, buf + sizes[0], sizes[1]);
+ kunmap_atomic(addr);
+
+out:
+ /* enable page faults to match kunmap_atomic() return conditions */
+ pagefault_enable();
+}
+
+#endif /* USE_PGTABLE_MAPPING */
static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
void *pcpu)
{
- int cpu = (long)pcpu;
+ int ret, cpu = (long)pcpu;
struct mapping_area *area;
switch (action) {
case CPU_UP_PREPARE:
area = &per_cpu(zs_map_area, cpu);
- if (area->vm)
- break;
- area->vm = alloc_vm_area(2 * PAGE_SIZE, area->vm_ptes);
- if (!area->vm)
- return notifier_from_errno(-ENOMEM);
+ ret = __zs_cpu_up(area);
+ if (ret)
+ return notifier_from_errno(ret);
break;
case CPU_DEAD:
case CPU_UP_CANCELED:
area = &per_cpu(zs_map_area, cpu);
- if (area->vm)
- free_vm_area(area->vm);
- area->vm = NULL;
+ __zs_cpu_down(area);
break;
}
@@ -488,14 +792,21 @@
return notifier_to_errno(ret);
}
-struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
+/**
+ * zs_create_pool - Creates an allocation pool to work from.
+ * @flags: allocation flags used to allocate pool metadata
+ *
+ * This function must be called before anything when using
+ * the zsmalloc allocator.
+ *
+ * On success, a pointer to the newly created pool is returned,
+ * otherwise NULL.
+ */
+struct zs_pool *zs_create_pool(gfp_t flags)
{
- int i, error, ovhd_size;
+ int i, ovhd_size;
struct zs_pool *pool;
- if (!name)
- return NULL;
-
ovhd_size = roundup(sizeof(*pool), PAGE_SIZE);
pool = kzalloc(ovhd_size, GFP_KERNEL);
if (!pool)
@@ -513,31 +824,11 @@
class->size = size;
class->index = i;
spin_lock_init(&class->lock);
- class->zspage_order = get_zspage_order(size);
+ class->pages_per_zspage = get_pages_per_zspage(size);
}
- /*
- * If this becomes a separate module, register zs_init with
- * module_init, and remove this block
- */
- if (!zs_initialized) {
- error = zs_init();
- if (error)
- goto cleanup;
- zs_initialized = 1;
- }
-
pool->flags = flags;
- pool->name = name;
-
- error = 0; /* Success */
-
-cleanup:
- if (error) {
- zs_destroy_pool(pool);
- pool = NULL;
- }
return pool;
}
@@ -553,8 +844,7 @@
for (fg = 0; fg < _ZS_NR_FULLNESS_GROUPS; fg++) {
if (class->fullness_list[fg]) {
- pr_info("Freeing non-empty class with size "
- "%db, fullness group %d\n",
+ pr_info("Freeing non-empty class with size %db, fullness group %d\n",
class->size, fg);
}
}
@@ -567,18 +857,14 @@
* zs_malloc - Allocate block of given size from pool.
* @pool: pool to allocate from
* @size: size of block to allocate
- * @page: page no. that holds the object
- * @offset: location of object within page
*
- * On success, <page, offset> identifies block allocated
- * and 0 is returned. On failure, <page, offset> is set to
- * 0 and -ENOMEM is returned.
- *
+ * On success, handle to the allocated object is returned,
+ * otherwise 0.
* Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
*/
-void *zs_malloc(struct zs_pool *pool, size_t size)
+unsigned long zs_malloc(struct zs_pool *pool, size_t size)
{
- void *obj;
+ unsigned long obj;
struct link_free *link;
int class_idx;
struct size_class *class;
@@ -587,7 +873,7 @@
unsigned long m_objidx, m_offset;
if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
- return NULL;
+ return 0;
class_idx = get_size_class_index(size);
class = &pool->size_class[class_idx];
@@ -600,14 +886,14 @@
spin_unlock(&class->lock);
first_page = alloc_zspage(class, pool->flags);
if (unlikely(!first_page))
- return NULL;
+ return 0;
set_zspage_mapping(first_page, class->index, ZS_EMPTY);
spin_lock(&class->lock);
- class->pages_allocated += class->zspage_order;
+ class->pages_allocated += class->pages_per_zspage;
}
- obj = first_page->freelist;
+ obj = (unsigned long)first_page->freelist;
obj_handle_to_location(obj, &m_page, &m_objidx);
m_offset = obj_idx_to_offset(m_page, m_objidx, class->size);
@@ -626,7 +912,7 @@
}
EXPORT_SYMBOL_GPL(zs_malloc);
-void zs_free(struct zs_pool *pool, void *obj)
+void zs_free(struct zs_pool *pool, unsigned long obj)
{
struct link_free *link;
struct page *first_page, *f_page;
@@ -653,13 +939,13 @@
+ f_offset);
link->next = first_page->freelist;
kunmap_atomic(link);
- first_page->freelist = obj;
+ first_page->freelist = (void *)obj;
first_page->inuse--;
fullness = fix_fullness_group(pool, first_page);
if (fullness == ZS_EMPTY)
- class->pages_allocated -= class->zspage_order;
+ class->pages_allocated -= class->pages_per_zspage;
spin_unlock(&class->lock);
@@ -668,7 +954,22 @@
}
EXPORT_SYMBOL_GPL(zs_free);
-void *zs_map_object(struct zs_pool *pool, void *handle)
+/**
+ * zs_map_object - get address of allocated object from handle.
+ * @pool: pool from which the object was allocated
+ * @handle: handle returned from zs_malloc
+ *
+ * Before using an object allocated from zs_malloc, it must be mapped using
+ * this function. When done with the object, it must be unmapped using
+ * zs_unmap_object.
+ *
+ * Only one object can be mapped per cpu at a time. There is no protection
+ * against nested mappings.
+ *
+ * This function returns with preemption and page faults disabled.
+ */
+void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+ enum zs_mapmode mm)
{
struct page *page;
unsigned long obj_idx, off;
@@ -677,38 +978,40 @@
enum fullness_group fg;
struct size_class *class;
struct mapping_area *area;
+ struct page *pages[2];
BUG_ON(!handle);
+ /*
+ * Because we use per-cpu mapping areas shared among the
+ * pools/users, we can't allow mapping in interrupt context
+ * because it can corrupt another users mappings.
+ */
+ BUG_ON(in_interrupt());
+
obj_handle_to_location(handle, &page, &obj_idx);
get_zspage_mapping(get_first_page(page), &class_idx, &fg);
class = &pool->size_class[class_idx];
off = obj_idx_to_offset(page, obj_idx, class->size);
area = &get_cpu_var(zs_map_area);
+ area->vm_mm = mm;
if (off + class->size <= PAGE_SIZE) {
/* this object is contained entirely within a page */
area->vm_addr = kmap_atomic(page);
- } else {
- /* this object spans two pages */
- struct page *nextp;
-
- nextp = get_next_page(page);
- BUG_ON(!nextp);
-
-
- set_pte(area->vm_ptes[0], mk_pte(page, PAGE_KERNEL));
- set_pte(area->vm_ptes[1], mk_pte(nextp, PAGE_KERNEL));
-
- /* We pre-allocated VM area so mapping can never fail */
- area->vm_addr = area->vm->addr;
+ return area->vm_addr + off;
}
- return area->vm_addr + off;
+ /* this object spans two pages */
+ pages[0] = page;
+ pages[1] = get_next_page(page);
+ BUG_ON(!pages[1]);
+
+ return __zs_map_object(area, pages, off, class->size);
}
EXPORT_SYMBOL_GPL(zs_map_object);
-void zs_unmap_object(struct zs_pool *pool, void *handle)
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
{
struct page *page;
unsigned long obj_idx, off;
@@ -726,13 +1029,16 @@
off = obj_idx_to_offset(page, obj_idx, class->size);
area = &__get_cpu_var(zs_map_area);
- if (off + class->size <= PAGE_SIZE) {
+ if (off + class->size <= PAGE_SIZE)
kunmap_atomic(area->vm_addr);
- } else {
- set_pte(area->vm_ptes[0], __pte(0));
- set_pte(area->vm_ptes[1], __pte(0));
- __flush_tlb_one((unsigned long)area->vm_addr);
- __flush_tlb_one((unsigned long)area->vm_addr + PAGE_SIZE);
+ else {
+ struct page *pages[2];
+
+ pages[0] = page;
+ pages[1] = get_next_page(page);
+ BUG_ON(!pages[1]);
+
+ __zs_unmap_object(area, pages, off, class->size);
}
put_cpu_var(zs_map_area);
}
@@ -749,3 +1055,9 @@
return npages << PAGE_SHIFT;
}
EXPORT_SYMBOL_GPL(zs_get_total_size_bytes);
+
+module_init(zs_init);
+module_exit(zs_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
diff --git a/drivers/staging/zsmalloc/zsmalloc.h b/drivers/staging/zsmalloc/zsmalloc.h
index 949384e..fbe6bec 100644
--- a/drivers/staging/zsmalloc/zsmalloc.h
+++ b/drivers/staging/zsmalloc/zsmalloc.h
@@ -15,16 +15,28 @@
#include <linux/types.h>
+/*
+ * zsmalloc mapping modes
+ *
+ * NOTE: These only make a difference when a mapped object spans pages
+ */
+enum zs_mapmode {
+ ZS_MM_RW, /* normal read-write mapping */
+ ZS_MM_RO, /* read-only (no copy-out at unmap time) */
+ ZS_MM_WO /* write-only (no copy-in at map time) */
+};
+
struct zs_pool;
-struct zs_pool *zs_create_pool(const char *name, gfp_t flags);
+struct zs_pool *zs_create_pool(gfp_t flags);
void zs_destroy_pool(struct zs_pool *pool);
-void *zs_malloc(struct zs_pool *pool, size_t size);
-void zs_free(struct zs_pool *pool, void *obj);
+unsigned long zs_malloc(struct zs_pool *pool, size_t size);
+void zs_free(struct zs_pool *pool, unsigned long obj);
-void *zs_map_object(struct zs_pool *pool, void *handle);
-void zs_unmap_object(struct zs_pool *pool, void *handle);
+void *zs_map_object(struct zs_pool *pool, unsigned long handle,
+ enum zs_mapmode mm);
+void zs_unmap_object(struct zs_pool *pool, unsigned long handle);
u64 zs_get_total_size_bytes(struct zs_pool *pool);
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h
deleted file mode 100644
index 92eefc6..0000000
--- a/drivers/staging/zsmalloc/zsmalloc_int.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * zsmalloc memory allocator
- *
- * Copyright (C) 2011 Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the license that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-#ifndef _ZS_MALLOC_INT_H_
-#define _ZS_MALLOC_INT_H_
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-/*
- * This must be power of 2 and greater than of equal to sizeof(link_free).
- * These two conditions ensure that any 'struct link_free' itself doesn't
- * span more than 1 page which avoids complex case of mapping 2 pages simply
- * to restore link_free pointer values.
- */
-#define ZS_ALIGN 8
-
-/*
- * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
- * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
- */
-#define ZS_MAX_ZSPAGE_ORDER 2
-#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
-
-/*
- * Object location (<PFN>, <obj_idx>) is encoded as
- * as single (void *) handle value.
- *
- * Note that object index <obj_idx> is relative to system
- * page <PFN> it is stored in, so for each sub-page belonging
- * to a zspage, obj_idx starts with 0.
- *
- * This is made more complicated by various memory models and PAE.
- */
-
-#ifndef MAX_PHYSMEM_BITS
-#ifdef CONFIG_HIGHMEM64G
-#define MAX_PHYSMEM_BITS 36
-#else /* !CONFIG_HIGHMEM64G */
-/*
- * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
- * be PAGE_SHIFT
- */
-#define MAX_PHYSMEM_BITS BITS_PER_LONG
-#endif
-#endif
-#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT)
-#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
-#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
-
-#define MAX(a, b) ((a) >= (b) ? (a) : (b))
-/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
-#define ZS_MIN_ALLOC_SIZE \
- MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
-#define ZS_MAX_ALLOC_SIZE PAGE_SIZE
-
-/*
- * On systems with 4K page size, this gives 254 size classes! There is a
- * trader-off here:
- * - Large number of size classes is potentially wasteful as free page are
- * spread across these classes
- * - Small number of size classes causes large internal fragmentation
- * - Probably its better to use specific size classes (empirically
- * determined). NOTE: all those class sizes must be set as multiple of
- * ZS_ALIGN to make sure link_free itself never has to span 2 pages.
- *
- * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
- * (reason above)
- */
-#define ZS_SIZE_CLASS_DELTA 16
-#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
- ZS_SIZE_CLASS_DELTA + 1)
-
-/*
- * We do not maintain any list for completely empty or full pages
- */
-enum fullness_group {
- ZS_ALMOST_FULL,
- ZS_ALMOST_EMPTY,
- _ZS_NR_FULLNESS_GROUPS,
-
- ZS_EMPTY,
- ZS_FULL
-};
-
-/*
- * We assign a page to ZS_ALMOST_EMPTY fullness group when:
- * n <= N / f, where
- * n = number of allocated objects
- * N = total number of objects zspage can store
- * f = 1/fullness_threshold_frac
- *
- * Similarly, we assign zspage to:
- * ZS_ALMOST_FULL when n > N / f
- * ZS_EMPTY when n == 0
- * ZS_FULL when n == N
- *
- * (see: fix_fullness_group())
- */
-static const int fullness_threshold_frac = 4;
-
-struct mapping_area {
- struct vm_struct *vm;
- pte_t *vm_ptes[2];
- char *vm_addr;
-};
-
-struct size_class {
- /*
- * Size of objects stored in this class. Must be multiple
- * of ZS_ALIGN.
- */
- int size;
- unsigned int index;
-
- /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
- int zspage_order;
-
- spinlock_t lock;
-
- /* stats */
- u64 pages_allocated;
-
- struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
-};
-
-/*
- * Placed within free objects to form a singly linked list.
- * For every zspage, first_page->freelist gives head of this list.
- *
- * This must be power of 2 and less than or equal to ZS_ALIGN
- */
-struct link_free {
- /* Handle of next free chunk (encodes <PFN, obj_idx>) */
- void *next;
-};
-
-struct zs_pool {
- struct size_class size_class[ZS_SIZE_CLASSES];
-
- gfp_t flags; /* allocation flags used when growing pool */
- const char *name;
-};
-
-#endif
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 00df613..c6f6f03 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -32,7 +32,6 @@
#include <linux/types.h>
#include <linux/android_alarm.h>
#include <linux/thermal.h>
-#include <mach/cpufreq.h>
#include <mach/rpm-regulator.h>
#include <mach/rpm-regulator-smd.h>
#include <linux/regulator/consumer.h>
@@ -40,7 +39,8 @@
#define MAX_RAILS 5
static struct msm_thermal_data msm_thermal_info;
-static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
+static uint32_t limited_max_freq = UINT_MAX;
+static uint32_t limited_min_freq;
static struct delayed_work check_temp_work;
static bool core_control_enabled;
static uint32_t cpus_offlined;
@@ -154,6 +154,25 @@
#define PSM_REG_MODE_FROM_ATTRIBS(attr) \
(container_of(attr, struct psm_rail, mode_attr));
+
+static int msm_thermal_cpufreq_callback(struct notifier_block *nfb,
+ unsigned long event, void *data)
+{
+ struct cpufreq_policy *policy = data;
+
+ switch (event) {
+ case CPUFREQ_INCOMPATIBLE:
+ cpufreq_verify_within_limits(policy, limited_min_freq,
+ limited_max_freq);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block msm_thermal_cpufreq_notifier = {
+ .notifier_call = msm_thermal_cpufreq_callback,
+};
+
/* If freq table exists, then we can send freq request */
static int check_freq_table(void)
{
@@ -174,37 +193,26 @@
{
int cpu = 0;
int ret = 0;
- struct cpufreq_policy *policy = NULL;
if (!freq_table_get) {
ret = check_freq_table();
if (ret) {
- pr_err("%s:Fail to get freq table\n", __func__);
+ pr_err("%s:Fail to get freq table\n", KBUILD_MODNAME);
return ret;
}
}
/* If min is larger than allowed max */
- if (min != MSM_CPUFREQ_NO_LIMIT &&
- min > table[limit_idx_high].frequency)
- min = table[limit_idx_high].frequency;
+ min = min(min, table[limit_idx_high].frequency);
- for_each_possible_cpu(cpu) {
- ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
- if (ret) {
- pr_err("%s:Fail to set limits for cpu%d\n",
- __func__, cpu);
- return ret;
- }
+ limited_min_freq = min;
- if (cpu_online(cpu)) {
- policy = cpufreq_cpu_get(cpu);
- if (!policy)
- continue;
- cpufreq_driver_target(policy, policy->cur,
- CPUFREQ_RELATION_L);
- cpufreq_cpu_put(policy);
- }
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpufreq_update_policy(cpu))
+ pr_info("%s: Unable to update policy for cpu:%d\n",
+ KBUILD_MODNAME, cpu);
}
+ put_online_cpus();
return ret;
}
@@ -599,26 +607,19 @@
{
int ret = 0;
- ret = msm_cpufreq_set_freq_limits(cpu, MSM_CPUFREQ_NO_LIMIT, max_freq);
- if (ret)
- return ret;
-
- limited_max_freq = max_freq;
- if (max_freq != MSM_CPUFREQ_NO_LIMIT)
+ if (max_freq != UINT_MAX)
pr_info("%s: Limiting cpu%d max frequency to %d\n",
KBUILD_MODNAME, cpu, max_freq);
else
pr_info("%s: Max frequency reset for cpu%d\n",
KBUILD_MODNAME, cpu);
-
- if (cpu_online(cpu)) {
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- if (!policy)
- return ret;
- ret = cpufreq_driver_target(policy, policy->cur,
- CPUFREQ_RELATION_H);
- cpufreq_cpu_put(policy);
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpufreq_update_policy(cpu))
+ pr_info("%s: Unable to update policy for cpu:%d\n",
+ KBUILD_MODNAME, cpu);
}
+ put_online_cpus();
return ret;
}
@@ -835,7 +836,6 @@
static void __ref do_freq_control(long temp)
{
- int ret = 0;
int cpu = 0;
uint32_t max_freq = limited_max_freq;
@@ -855,7 +855,7 @@
limit_idx += msm_thermal_info.freq_step;
if (limit_idx >= limit_idx_high) {
limit_idx = limit_idx_high;
- max_freq = MSM_CPUFREQ_NO_LIMIT;
+ max_freq = UINT_MAX;
} else
max_freq = table[limit_idx].frequency;
}
@@ -863,17 +863,13 @@
if (max_freq == limited_max_freq)
return;
+ limited_max_freq = max_freq;
/* Update new limits */
for_each_possible_cpu(cpu) {
if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
continue;
- ret = update_cpu_max_freq(cpu, max_freq);
- if (ret)
- pr_debug(
- "%s: Unable to limit cpu%d max freq to %d\n",
- KBUILD_MODNAME, cpu, max_freq);
+ update_cpu_max_freq(cpu, max_freq);
}
-
}
static void __ref check_temp(struct work_struct *work)
@@ -1086,12 +1082,17 @@
cancel_delayed_work(&check_temp_work);
flush_scheduled_work();
- if (limited_max_freq == MSM_CPUFREQ_NO_LIMIT)
+ if (limited_max_freq == UINT_MAX)
return;
- for_each_possible_cpu(cpu) {
- update_cpu_max_freq(cpu, MSM_CPUFREQ_NO_LIMIT);
+ limited_max_freq = UINT_MAX;
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpufreq_update_policy(cpu))
+ pr_info("%s: Unable to update policy for cpu:%d\n",
+ KBUILD_MODNAME, cpu);
}
+ put_online_cpus();
}
static int __ref set_enabled(const char *val, const struct kernel_param *kp)
@@ -1104,7 +1105,7 @@
hotplug_init();
} else
pr_info("%s: no action for enabled = %d\n",
- KBUILD_MODNAME, enabled);
+ KBUILD_MODNAME, enabled);
pr_info("%s: enabled = %d\n", KBUILD_MODNAME, enabled);
@@ -1346,6 +1347,12 @@
enabled = 1;
+ ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
+ CPUFREQ_POLICY_NOTIFIER);
+ if (ret)
+ pr_err("%s: cannot register cpufreq notifier\n",
+ KBUILD_MODNAME);
+
INIT_DELAYED_WORK(&check_temp_work, check_temp);
schedule_delayed_work(&check_temp_work, 0);
@@ -1659,7 +1666,7 @@
key = "qcom,freq-req";
rails[i].freq_req = of_property_read_bool(child_node, key);
if (rails[i].freq_req)
- rails[i].min_level = MSM_CPUFREQ_NO_LIMIT;
+ rails[i].min_level = 0;
else {
key = "qcom,min-level";
ret = of_property_read_u32(child_node, key,
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index a243a05..078929b 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -155,7 +155,6 @@
struct tasklet_struct tlet;
struct msm_hs_sps_ep_conn_data prod;
};
-
enum buffer_states {
NONE_PENDING = 0x0,
FIFO_OVERRUN = 0x1,
@@ -219,6 +218,7 @@
struct msm_bus_scale_pdata *bus_scale_table;
bool rx_discard_flush_issued;
int rx_count_callback;
+ bool rx_bam_inprogress;
unsigned int *reg_ptr;
};
@@ -998,6 +998,14 @@
mutex_lock(&msm_uport->clk_mutex);
msm_hs_write(uport, UART_DM_IMR, 0);
+ /* Clear the Rx Ready Ctl bit - This ensures that
+ * flow control lines stop the other side from sending
+ * data while we change the parameters
+ */
+ data = msm_hs_read(uport, UART_DM_MR1);
+ data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
+ msm_hs_write(uport, UART_DM_MR1, data);
+
/*
* Disable Rx channel of UARTDM
* DMA Rx Stall happens if enqueue and flush of Rx command happens
@@ -1071,18 +1079,6 @@
/* write parity/bits per char/stop bit configuration */
msm_hs_write(uport, UART_DM_MR2, data);
- /* Configure HW flow control */
- 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);
-
uport->ignore_status_mask = termios->c_iflag & INPCK;
uport->ignore_status_mask |= termios->c_iflag & IGNPAR;
uport->ignore_status_mask |= termios->c_iflag & IGNBRK;
@@ -1106,6 +1102,10 @@
*/
mb();
if (is_blsp_uart(msm_uport)) {
+ if (msm_uport->rx_bam_inprogress)
+ ret = wait_event_timeout(msm_uport->rx.wait,
+ msm_uport->rx_bam_inprogress == false,
+ RX_FLUSH_COMPLETE_TIMEOUT);
ret = sps_disconnect(sps_pipe_handle);
if (ret)
pr_err("%s(): sps_disconnect failed\n",
@@ -1127,6 +1127,20 @@
}
}
+ /* Configure HW flow control
+ * UART Core would see status of CTS line when it is sending data
+ * to remote uart to confirm that it can receive or not.
+ * UART Core would trigger RFR if it is not having any space with
+ * RX FIFO.
+ */
+ 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);
mb();
mutex_unlock(&msm_uport->clk_mutex);
@@ -1358,10 +1372,13 @@
msm_uport->rx.flush = FLUSH_NONE;
if (is_blsp_uart(msm_uport)) {
+ msm_uport->rx_bam_inprogress = true;
sps_pipe_handle = rx->prod.pipe_handle;
/* Queue transfer request to SPS */
sps_transfer_one(sps_pipe_handle, rx->rbuffer,
UARTDM_RX_BUF_SIZE, msm_uport, flags);
+ msm_uport->rx_bam_inprogress = false;
+ wake_up(&msm_uport->rx.wait);
} else {
msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel,
&msm_uport->rx.xfer);
@@ -1531,10 +1548,13 @@
if (!msm_uport->rx.buffer_pending) {
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;
/* 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;
+ wake_up(&msm_uport->rx.wait);
} else {
msm_hs_start_rx_locked(uport);
}
@@ -2832,9 +2852,9 @@
/* Now save the sps pipe handle */
ep->pipe_handle = sps_pipe_handle;
pr_debug("msm_serial_hs: success !! %s: pipe_handle=0x%x\n"
- "desc_fifo.phys_base=0x%x\n",
+ "desc_fifo.phys_base=0x%llx\n",
is_producer ? "READ" : "WRITE",
- (u32)sps_pipe_handle, sps_config->desc.phys_base);
+ (u32) sps_pipe_handle, (u64) sps_config->desc.phys_base);
return 0;
get_config_err:
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 554cce8..97592c4 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2288,8 +2288,12 @@
if (mdwc->otg_xceiv && !mdwc->ext_inuse &&
(mdwc->ext_xceiv.otg_capability || !init)) {
mdwc->ext_xceiv.bsv = val->intval;
+ /*
+ * set debouncing delay to 120msec. Otherwise battery
+ * charging CDP complaince test fails if delay > 120ms.
+ */
queue_delayed_work(system_nrt_wq,
- &mdwc->resume_work, 20);
+ &mdwc->resume_work, 12);
if (!init)
init = true;
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 9599936..cacd635 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -93,6 +93,19 @@
return 0;
}
+static void dwc3_otg_set_hsphy_auto_suspend(struct dwc3_otg *dotg, bool susp)
+{
+ struct dwc3 *dwc = dotg->dwc;
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ if (susp)
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ else
+ reg &= ~(DWC3_GUSB2PHYCFG_SUSPHY);
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
/**
* dwc3_otg_set_host_power - Enable port power control for host operation
*
@@ -194,6 +207,7 @@
* remove_hcd, But we may not use standard set_host method
* anymore.
*/
+ dwc3_otg_set_hsphy_auto_suspend(dotg, true);
dwc3_otg_set_host_regs(dotg);
/*
* FIXME If micro A cable is disconnected during system suspend,
@@ -242,6 +256,7 @@
ext_xceiv->ext_block_reset)
ext_xceiv->ext_block_reset(ext_xceiv, true);
+ dwc3_otg_set_hsphy_auto_suspend(dotg, false);
dwc3_otg_set_peripheral_regs(dotg);
/* re-init core and OTG registers as block reset clears these */
@@ -309,12 +324,14 @@
ext_xceiv->ext_block_reset)
ext_xceiv->ext_block_reset(ext_xceiv, false);
+ dwc3_otg_set_hsphy_auto_suspend(dotg, true);
dwc3_otg_set_peripheral_regs(dotg);
usb_gadget_vbus_connect(otg->gadget);
} else {
dev_dbg(otg->phy->dev, "%s: turn off gadget %s\n",
__func__, otg->gadget->name);
usb_gadget_vbus_disconnect(otg->gadget);
+ dwc3_otg_set_hsphy_auto_suspend(dotg, false);
}
return 0;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 38c4b86..ad3a3a9 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2623,13 +2623,10 @@
}
}
- /*
- * Notify suspend only to gadget driver, but not resume. Resume is
- * notified as part of wakeup event in dwc3_gadget_wakeup_interrupt().
- */
if (next == DWC3_LINK_STATE_U0) {
if (dwc->link_state == DWC3_LINK_STATE_U3) {
dbg_event(0xFF, "RESUME", 0);
+ dwc->gadget_driver->resume(&dwc->gadget);
}
} else if (next == DWC3_LINK_STATE_U3) {
dbg_event(0xFF, "SUSPEND", 0);
@@ -2920,7 +2917,11 @@
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
- dwc3_gadget_usb2_phy_suspend(dwc, true);
+ /*
+ * Clear autosuspend bit in dwc3 register for USB2. It will be
+ * enabled before setting run/stop bit.
+ */
+ dwc3_gadget_usb2_phy_suspend(dwc, false);
dwc3_gadget_usb3_phy_suspend(dwc, true);
}
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 6765078..c65ed25 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -2181,6 +2181,22 @@
}
}
+static inline void check_streaming_func(struct usb_gadget *gadget,
+ struct android_usb_platform_data *pdata,
+ char *name)
+{
+ int i;
+
+ for (i = 0; i < pdata->streaming_func_count; i++) {
+ if (!strcmp(name,
+ pdata->streaming_func[i])) {
+ pr_debug("set streaming_enabled to true\n");
+ gadget->streaming_enabled = true;
+ break;
+ }
+ }
+}
+
static int android_enable_function(struct android_dev *dev,
struct android_configuration *conf,
char *name)
@@ -2188,6 +2204,9 @@
struct android_usb_function **functions = dev->functions;
struct android_usb_function *f;
struct android_usb_function_holder *f_holder;
+ struct android_usb_platform_data *pdata = dev->pdata;
+ struct usb_gadget *gadget = dev->cdev->gadget;
+
while ((f = *functions++)) {
if (!strcmp(name, f->name)) {
if (f->android_dev && f->android_dev != dev)
@@ -2205,6 +2224,13 @@
f_holder->f = f;
list_add_tail(&f_holder->enabled_list,
&conf->enabled_functions);
+ pr_debug("func:%s is enabled.\n", f->name);
+ /*
+ * compare enable function with streaming func
+ * list and based on the same request streaming.
+ */
+ check_streaming_func(gadget, pdata, f->name);
+
return 0;
}
}
@@ -2577,6 +2603,10 @@
{
struct android_dev *dev = cdev_to_android_dev(c->cdev);
+ if (c->cdev->gadget->streaming_enabled) {
+ c->cdev->gadget->streaming_enabled = false;
+ pr_debug("setting streaming_enabled to false.\n");
+ }
android_unbind_enabled_functions(dev, c);
}
@@ -2745,8 +2775,10 @@
unsigned long flags;
spin_lock_irqsave(&cdev->lock, flags);
- dev->suspended = 1;
- schedule_work(&dev->work);
+ if (!dev->suspended) {
+ dev->suspended = 1;
+ schedule_work(&dev->work);
+ }
spin_unlock_irqrestore(&cdev->lock, flags);
composite_suspend(gadget);
@@ -2759,8 +2791,10 @@
unsigned long flags;
spin_lock_irqsave(&cdev->lock, flags);
- dev->suspended = 0;
- schedule_work(&dev->work);
+ if (dev->suspended) {
+ dev->suspended = 0;
+ schedule_work(&dev->work);
+ }
spin_unlock_irqrestore(&cdev->lock, flags);
composite_resume(gadget);
@@ -2895,7 +2929,7 @@
struct android_usb_platform_data *pdata;
struct android_dev *android_dev;
struct resource *res;
- int ret = 0;
+ int ret = 0, i, len = 0;
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
@@ -2912,6 +2946,33 @@
"qcom,android-usb-cdrom");
pdata->internal_ums = of_property_read_bool(pdev->dev.of_node,
"qcom,android-usb-internal-ums");
+ len = of_property_count_strings(pdev->dev.of_node,
+ "qcom,streaming-func");
+ if (len > MAX_STREAMING_FUNCS) {
+ pr_err("Invalid number of functions used.\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i++) {
+ const char *name = NULL;
+
+ of_property_read_string_index(pdev->dev.of_node,
+ "qcom,streaming-func", i, &name);
+ if (!name)
+ continue;
+
+ if (sizeof(name) > FUNC_NAME_LEN) {
+ pr_err("Function name is bigger than allowed.\n");
+ continue;
+ }
+
+ strlcpy(pdata->streaming_func[i], name,
+ sizeof(pdata->streaming_func[i]));
+ pr_debug("name of streaming function:%s\n",
+ pdata->streaming_func[i]);
+ }
+
+ pdata->streaming_func_count = len;
} else {
pdata = pdev->dev.platform_data;
}
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index a9c073b..f1e4220 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -271,6 +271,10 @@
1 << (pdata->log2_itc-1);
is_l1_supported = pdata->l1_supported;
+ /* Set ahb2ahb bypass flag if it is requested. */
+ if (pdata->enable_ahb2ahb_bypass)
+ ci13xxx_msm_udc_driver.flags |=
+ CI13XXX_ENABLE_AHB2AHB_BYPASS;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 3f8d924..6a92684 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -70,10 +70,6 @@
#include <mach/usb_trace.h>
#include "ci13xxx_udc.h"
-/* Turns on streaming. overrides CI13XXX_DISABLE_STREAMING */
-static unsigned int streaming;
-module_param(streaming, uint, S_IRUGO | S_IWUSR);
-
/******************************************************************************
* DEFINE
*****************************************************************************/
@@ -392,20 +388,32 @@
static int hw_device_state(u32 dma)
{
struct ci13xxx *udc = _udc;
+ struct usb_gadget *gadget = &udc->gadget;
if (dma) {
- if (streaming || !(udc->udc_driver->flags &
- CI13XXX_DISABLE_STREAMING))
+ if (gadget->streaming_enabled || !(udc->udc_driver->flags &
+ CI13XXX_DISABLE_STREAMING)) {
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, 0);
- else
+ pr_debug("%s(): streaming mode is enabled. USBMODE:%x\n",
+ __func__, hw_cread(CAP_USBMODE, ~0));
+ } else {
hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
-
+ pr_debug("%s(): streaming mode is disabled. USBMODE:%x\n",
+ __func__, hw_cread(CAP_USBMODE, ~0));
+ }
hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
if (udc->udc_driver->notify_event)
udc->udc_driver->notify_event(udc,
CI13XXX_CONTROLLER_CONNECT_EVENT);
+ /* Set BIT(31) to enable AHB2AHB Bypass functionality */
+ if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+ hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, AHB2AHB_BYPASS);
+ pr_debug("%s(): ByPass Mode is enabled. AHBMODE:%x\n",
+ __func__, hw_aread(ABS_AHBMODE, ~0));
+ }
+
/* interrupt, error, port change, reset, sleep/suspend */
hw_cwrite(CAP_USBINTR, ~0,
USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
@@ -413,6 +421,12 @@
} else {
hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
hw_cwrite(CAP_USBINTR, ~0, 0);
+ /* Clear BIT(31) to disable AHB2AHB Bypass functionality */
+ if (udc->udc_driver->flags & CI13XXX_ENABLE_AHB2AHB_BYPASS) {
+ hw_awrite(ABS_AHBMODE, AHB2AHB_BYPASS, 0);
+ pr_debug("%s(): ByPass Mode is disabled. AHBMODE:%x\n",
+ __func__, hw_aread(ABS_AHBMODE, ~0));
+ }
}
return 0;
}
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index f90ea86..47fe138 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -136,6 +136,7 @@
#define CI13XXX_DISABLE_STREAMING BIT(3)
#define CI13XXX_ZERO_ITC BIT(4)
#define CI13XXX_IS_OTG BIT(5)
+#define CI13XXX_ENABLE_AHB2AHB_BYPASS BIT(6)
#define CI13XXX_CONTROLLER_RESET_EVENT 0
#define CI13XXX_CONTROLLER_CONNECT_EVENT 1
@@ -197,6 +198,9 @@
/* TESTMODE */
#define TESTMODE_FORCE BIT(0)
+/* AHB_MODE */
+#define AHB2AHB_BYPASS BIT(31)
+
/* USBCMD */
#define USBCMD_RS BIT(0)
#define USBCMD_RST BIT(1)
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index f649248..7e474f3 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -18,6 +18,7 @@
#include <linux/usb/usb_qdss.h>
#include <linux/usb/msm_hsusb.h>
+#include "gadget_chips.h"
#include "f_qdss.h"
#include "u_qdss.c"
@@ -395,7 +396,9 @@
goto fail;
}
}
- dwc3_tx_fifo_resize_request(qdss->data, true);
+
+ if (gadget_is_dwc3(gadget))
+ dwc3_tx_fifo_resize_request(qdss->data, true);
return 0;
fail:
@@ -408,12 +411,15 @@
static void qdss_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_qdss *qdss = func_to_qdss(f);
+ struct usb_gadget *gadget = c->cdev->gadget;
pr_debug("qdss_unbind\n");
- dwc3_tx_fifo_resize_request(qdss->data, false);
+ if (gadget_is_dwc3(gadget))
+ dwc3_tx_fifo_resize_request(qdss->data, false);
+
clear_eps(f);
- clear_desc(c->cdev->gadget, f);
+ clear_desc(gadget, f);
}
static void qdss_eps_disable(struct usb_function *f)
@@ -605,7 +611,7 @@
spin_lock_irqsave(&d_lock, flags);
list_for_each_entry(ch, &usb_qdss_ch_list, list) {
- if (!strncmp(name, ch->name, sizeof(ch->name))) {
+ if (!strcmp(name, ch->name)) {
found = 1;
break;
}
@@ -767,7 +773,7 @@
spin_lock_irqsave(&d_lock, flags);
/* Check if we already have a channel with this name */
list_for_each_entry(ch, &usb_qdss_ch_list, list) {
- if (!strncmp(name, ch->name, sizeof(ch->name))) {
+ if (!strcmp(name, ch->name)) {
found = 1;
break;
}
@@ -824,7 +830,8 @@
ch->app_conn = 0;
spin_unlock_irqrestore(&d_lock, flags);
- msm_dwc3_restart_usb_session(gadget);
+ if (gadget_is_dwc3(gadget))
+ msm_dwc3_restart_usb_session(gadget);
}
EXPORT_SYMBOL(usb_qdss_close);
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 7903764..aee7b58 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -379,13 +379,35 @@
struct sk_buff *skb)
{
struct sk_buff *skb2;
+ struct rndis_packet_msg_type *header = NULL;
+ struct f_rndis *rndis = func_to_rndis(&port->func);
- skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
- if (skb2)
- rndis_add_hdr(skb2);
+ if (rndis->port.multi_pkt_xfer) {
+ if (port->header) {
+ header = port->header;
+ memset(header, 0, sizeof(*header));
+ header->MessageType = cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
+ header->MessageLength = cpu_to_le32(skb->len +
+ sizeof(*header));
+ header->DataOffset = cpu_to_le32(36);
+ header->DataLength = cpu_to_le32(skb->len);
+ pr_debug("MessageLength:%d DataLength:%d\n",
+ header->MessageLength,
+ header->DataLength);
+ return skb;
+ } else {
+ pr_err("RNDIS header is NULL.\n");
+ return NULL;
+ }
+ } else {
+ skb2 = skb_realloc_headroom(skb,
+ sizeof(struct rndis_packet_msg_type));
+ if (skb2)
+ rndis_add_hdr(skb2);
- dev_kfree_skb_any(skb);
- return skb2;
+ dev_kfree_skb_any(skb);
+ return skb2;
+ }
}
static void rndis_response_available(void *_rndis)
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 9e789c5..734619f 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -197,6 +197,7 @@
}
static void rx_complete(struct usb_ep *ep, struct usb_request *req);
+static void tx_complete(struct usb_ep *ep, struct usb_request *req);
static int
rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
@@ -256,7 +257,6 @@
req->buf = skb->data;
req->length = size;
- req->complete = rx_complete;
req->context = skb;
retval = usb_ep_queue(out, req, gfp_flags);
@@ -349,6 +349,7 @@
{
unsigned i;
struct usb_request *req;
+ bool usb_in;
if (!n)
return -ENOMEM;
@@ -359,10 +360,22 @@
if (i-- == 0)
goto extra;
}
+
+ if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ usb_in = true;
+ else
+ usb_in = false;
+
while (i--) {
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
if (!req)
return list_empty(list) ? -ENOMEM : 0;
+ /* update completion handler */
+ if (usb_in)
+ req->complete = tx_complete;
+ else
+ req->complete = rx_complete;
+
list_add(&req->list, list);
}
return 0;
@@ -479,7 +492,7 @@
static void tx_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct sk_buff *skb = req->context;
+ struct sk_buff *skb;
struct eth_dev *dev;
struct net_device *net;
struct usb_request *new_req;
@@ -553,7 +566,6 @@
}
new_req->length = length;
- new_req->complete = tx_complete;
retval = usb_ep_queue(in, new_req, GFP_ATOMIC);
switch (retval) {
default:
@@ -585,6 +597,7 @@
spin_unlock(&dev->req_lock);
}
} else {
+ skb = req->context;
spin_unlock(&dev->req_lock);
dev_kfree_skb_any(skb);
}
@@ -613,7 +626,7 @@
list_for_each(act, &dev->tx_reqs) {
req = container_of(act, struct usb_request, list);
if (!req->buf)
- req->buf = kmalloc(dev->tx_req_bufsize,
+ req->buf = kzalloc(dev->tx_req_bufsize,
GFP_ATOMIC);
if (!req->buf)
goto free_buf;
@@ -626,6 +639,7 @@
list_for_each(act, &dev->tx_reqs) {
req = container_of(act, struct usb_request, list);
kfree(req->buf);
+ req->buf = NULL;
}
return -ENOMEM;
}
@@ -710,28 +724,37 @@
* or the hardware can't use skb buffers.
* or there's not enough space for extra headers we need
*/
+ spin_lock_irqsave(&dev->lock, flags);
if (dev->wrap) {
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
if (dev->port_usb)
skb = dev->wrap(dev->port_usb, skb);
- spin_unlock_irqrestore(&dev->lock, flags);
- if (!skb)
+ if (!skb) {
+ spin_unlock_irqrestore(&dev->lock, flags);
goto drop;
+ }
}
- spin_lock_irqsave(&dev->req_lock, flags);
- dev->tx_skb_hold_count++;
- spin_unlock_irqrestore(&dev->req_lock, flags);
-
if (multi_pkt_xfer) {
+
+ pr_debug("req->length:%d header_len:%u\n"
+ "skb->len:%d skb->data_len:%d\n",
+ req->length, dev->header_len,
+ skb->len, skb->data_len);
+ /* Add RNDIS Header */
+ memcpy(req->buf + req->length, dev->port_usb->header,
+ dev->header_len);
+ /* Increment req length by header size */
+ req->length += dev->header_len;
+ spin_unlock_irqrestore(&dev->lock, flags);
+ /* Copy received IP data from SKB */
memcpy(req->buf + req->length, skb->data, skb->len);
- req->length = req->length + skb->len;
+ /* Increment req length by skb data length */
+ req->length += skb->len;
length = req->length;
dev_kfree_skb_any(skb);
spin_lock_irqsave(&dev->req_lock, flags);
+ dev->tx_skb_hold_count++;
if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
list_add(&req->list, &dev->tx_reqs);
@@ -741,19 +764,15 @@
}
dev->no_tx_req_used++;
- spin_unlock_irqrestore(&dev->req_lock, flags);
-
- spin_lock_irqsave(&dev->lock, flags);
dev->tx_skb_hold_count = 0;
- spin_unlock_irqrestore(&dev->lock, flags);
+ spin_unlock_irqrestore(&dev->req_lock, flags);
} else {
+ spin_unlock_irqrestore(&dev->lock, flags);
length = skb->len;
req->buf = skb->data;
req->context = skb;
}
- req->complete = tx_complete;
-
/* NCM requires no zlp if transfer is dwNtbInMaxSize */
if (dev->port_usb->is_fixed &&
length == dev->port_usb->fixed_in_len &&
@@ -806,7 +825,7 @@
spin_lock_irqsave(&dev->req_lock, flags);
if (list_empty(&dev->tx_reqs))
netif_start_queue(net);
- list_add(&req->list, &dev->tx_reqs);
+ list_add_tail(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
}
success:
@@ -1085,6 +1104,14 @@
if (!dev)
return ERR_PTR(-EINVAL);
+ link->header = kzalloc(sizeof(struct rndis_packet_msg_type),
+ GFP_ATOMIC);
+ if (!link->header) {
+ pr_err("RNDIS header memory allocation failed.\n");
+ result = -ENOMEM;
+ goto fail;
+ }
+
link->in_ep->driver_data = dev;
result = usb_ep_enable(link->in_ep);
if (result != 0) {
@@ -1105,6 +1132,7 @@
result = alloc_requests(dev, link, qlen(dev->gadget));
if (result == 0) {
+
dev->zlp = link->is_zlp_ok;
DBG(dev, "qlen %d\n", qlen(dev->gadget));
@@ -1139,10 +1167,15 @@
fail1:
(void) usb_ep_disable(link->in_ep);
}
-fail0:
+
/* caller is responsible for cleanup on error */
- if (result < 0)
+ if (result < 0) {
+fail0:
+ kfree(link->header);
+fail:
return ERR_PTR(result);
+ }
+
return dev->net;
}
@@ -1184,11 +1217,16 @@
list_del(&req->list);
spin_unlock(&dev->req_lock);
- if (link->multi_pkt_xfer)
+ if (link->multi_pkt_xfer) {
kfree(req->buf);
+ req->buf = NULL;
+ }
usb_ep_free_request(link->in_ep, req);
spin_lock(&dev->req_lock);
}
+ /* Free rndis header buffer memory */
+ kfree(link->header);
+ link->header = NULL;
spin_unlock(&dev->req_lock);
link->in_ep->driver_data = NULL;
link->in_ep->desc = NULL;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 05984d8..2c5da77 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -66,6 +66,8 @@
/* called on network open/close */
void (*open)(struct gether *);
void (*close)(struct gether *);
+ struct rndis_packet_msg_type *header;
+
};
#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
diff --git a/drivers/usb/gadget/u_qdss.c b/drivers/usb/gadget/u_qdss.c
index e241e29..23d4d06 100644
--- a/drivers/usb/gadget/u_qdss.c
+++ b/drivers/usb/gadget/u_qdss.c
@@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/usb/msm_hsusb.h>
#include <mach/usb_bam.h>
+#include "gadget_chips.h"
struct usb_qdss_bam_connect_info {
u32 usb_bam_pipe_idx;
@@ -88,8 +89,11 @@
&bam_info.usb_bam_pipe_idx, &bam_info.peer_pipe_idx,
NULL, bam_info.data_fifo);
- msm_data_fifo_config(data_ep, bam_info.data_fifo->phys_base,
- bam_info.data_fifo->size, bam_info.usb_bam_pipe_idx);
+ if (gadget_is_dwc3(gadget))
+ msm_data_fifo_config(data_ep,
+ bam_info.data_fifo->phys_base,
+ bam_info.data_fifo->size,
+ bam_info.usb_bam_pipe_idx);
} else {
kfree(bam_info.data_fifo);
res = usb_bam_disconnect_pipe(idx);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 5d58f16..5f20ad1 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1947,7 +1947,6 @@
if (pdev->dev.of_node) {
dev_dbg(&pdev->dev, "device tree enabled\n");
pdev->dev.platform_data = msm_hsic_dt_to_pdata(pdev);
- dev_set_name(&pdev->dev, ehci_msm_hsic_driver.driver.name);
} else {
/* explicitly pass wakeup_irq flag for !DT */
wakeup_irq_flags = IRQF_TRIGGER_HIGH;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 276bbb0..45fbfa8 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -470,6 +470,20 @@
int ret;
struct msm_otg_platform_data *pdata = motg->pdata;
+ /*
+ * AHB2AHB Bypass mode shouldn't be enable before doing
+ * async clock reset. If it is enable, disable the same.
+ */
+ val = readl_relaxed(USB_AHBMODE);
+ if (val & AHB2AHB_BYPASS) {
+ pr_err("%s(): AHB2AHB_BYPASS SET: AHBMODE:%x\n",
+ __func__, val);
+ val &= ~AHB2AHB_BYPASS_BIT_MASK;
+ writel_relaxed(val | AHB2AHB_BYPASS_CLEAR, USB_AHBMODE);
+ pr_err("%s(): AHBMODE: %x\n", __func__,
+ readl_relaxed(USB_AHBMODE));
+ }
+
ret = msm_otg_link_clk_reset(motg, 1);
if (ret)
return ret;
@@ -1275,7 +1289,8 @@
else if (motg->chg_type == USB_CDP_CHARGER)
charger_type = POWER_SUPPLY_TYPE_USB_CDP;
else if (motg->chg_type == USB_DCP_CHARGER ||
- motg->chg_type == USB_PROPRIETARY_CHARGER)
+ motg->chg_type == USB_PROPRIETARY_CHARGER ||
+ motg->chg_type == USB_FLOATED_CHARGER)
charger_type = POWER_SUPPLY_TYPE_USB_DCP;
else if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
motg->chg_type == USB_ACA_A_CHARGER ||
@@ -3834,6 +3849,8 @@
ci_pdata.log2_itc = otg_pdata->log2_itc;
ci_pdata.usb_core_id = 0;
ci_pdata.l1_supported = otg_pdata->l1_supported;
+ ci_pdata.enable_ahb2ahb_bypass =
+ otg_pdata->enable_ahb2ahb_bypass;
retval = platform_device_add_data(pdev, &ci_pdata,
sizeof(ci_pdata));
if (retval)
@@ -4164,6 +4181,8 @@
pdata->l1_supported = of_property_read_bool(node,
"qcom,hsusb-l1-supported");
+ pdata->enable_ahb2ahb_bypass = of_property_read_bool(node,
+ "qcom,ahb-async-bridge-bypass");
return pdata;
}
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index 5c3960d..31e93a5 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -166,6 +166,9 @@
int tooff = 0, fromoff = 0;
int size;
+ if (!to || !from)
+ return -EINVAL;
+
if (to->start > from->start)
fromoff = to->start - from->start;
else
@@ -177,9 +180,12 @@
return -EINVAL;
size *= sizeof(u16);
- memcpy(to->red+tooff, from->red+fromoff, size);
- memcpy(to->green+tooff, from->green+fromoff, size);
- memcpy(to->blue+tooff, from->blue+fromoff, size);
+ if (from->red && to->red)
+ memcpy(to->red+tooff, from->red+fromoff, size);
+ if (from->green && to->green)
+ memcpy(to->green+tooff, from->green+fromoff, size);
+ if (from->blue && to->blue)
+ memcpy(to->blue+tooff, from->blue+fromoff, size);
if (from->transp && to->transp)
memcpy(to->transp+tooff, from->transp+fromoff, size);
return 0;
@@ -190,6 +196,9 @@
int tooff = 0, fromoff = 0;
int size;
+ if (!to || !from)
+ return -EINVAL;
+
if (to->start > from->start)
fromoff = to->start - from->start;
else
@@ -201,12 +210,15 @@
return -EINVAL;
size *= sizeof(u16);
- if (copy_to_user(to->red+tooff, from->red+fromoff, size))
- return -EFAULT;
- if (copy_to_user(to->green+tooff, from->green+fromoff, size))
- return -EFAULT;
- if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
- return -EFAULT;
+ if (from->red && to->red)
+ if (copy_to_user(to->red+tooff, from->red+fromoff, size))
+ return -EFAULT;
+ if (from->green && to->green)
+ if (copy_to_user(to->green+tooff, from->green+fromoff, size))
+ return -EFAULT;
+ if (from->blue && to->blue)
+ if (copy_to_user(to->blue+tooff, from->blue+fromoff, size))
+ return -EFAULT;
if (from->transp && to->transp)
if (copy_to_user(to->transp+tooff, from->transp+fromoff, size))
return -EFAULT;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index d6a664a..6b84107 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1113,6 +1113,10 @@
if (copy_from_user(&cmap, argp, sizeof(cmap)))
return -EFAULT;
ret = fb_set_user_cmap(&cmap, info);
+ if (ret) {
+ if (info)
+ fb_dealloc_cmap(&info->cmap);
+ }
break;
case FBIOGETCMAP:
if (copy_from_user(&cmap, argp, sizeof(cmap)))
diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig
index 7682a49..b49e08e 100644
--- a/drivers/video/msm/mdss/Kconfig
+++ b/drivers/video/msm/mdss/Kconfig
@@ -20,3 +20,11 @@
Support the HDMI to MHL conversion.
MHL (Mobile High-Definition Link) technology
uses USB connector to output HDMI content
+
+config FB_MSM_MDSS_DSI_CTRL_STATUS
+ tristate "DSI controller status check feature"
+ ---help---
+ Check DSI controller status periodically (default period is 5
+ seconds) by sending Bus-Turn-Around (BTA) command. If DSI controller
+ fails to acknowledge the BTA command, it sends PANEL_ALIVE=0 status
+ to HAL layer to reset the controller.
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index ba14d67..8f5fa26 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -41,3 +41,5 @@
obj-$(CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL) += qpic_panel_ili_qvga.o
obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+
+obj-$(CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS) += mdss_dsi_status.o
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index e416a55..7d57f64 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -77,7 +77,7 @@
if (status) {
MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -88,7 +88,7 @@
status = MIPI_INP(ctrl_base + DSI_TIMEOUT_STATUS);
if (status & 0x0111) {
MIPI_OUTP(ctrl_base + DSI_TIMEOUT_STATUS, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -100,7 +100,7 @@
if (status & 0x011111) {
MIPI_OUTP(ctrl_base + DSI_DLN0_PHY_ERR, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -112,7 +112,7 @@
if (status & 0x44444489) {
MIPI_OUTP(ctrl_base + DSI_FIFO_STATUS, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
@@ -124,7 +124,7 @@
if (status & 0x80000000) {
MIPI_OUTP(ctrl_base + DSI_STATUS, status);
- pr_debug("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
}
}
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 638fcb3..d642093 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -1726,7 +1726,7 @@
rc = (status == 0x080000);
}
- mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_S_IBUF_ADDR);
+ mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_ADDR);
mdp3_clk_update(MDP3_CLK_AHB, 0);
mdp3_clk_update(MDP3_CLK_CORE, 0);
@@ -1859,6 +1859,52 @@
mdp3_res->underrun_cnt);
}
+static ssize_t mdp3_show_capabilities(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ size_t len = PAGE_SIZE;
+ int cnt = 0;
+
+#define SPRINT(fmt, ...) \
+ (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
+
+ SPRINT("mdp_version=3\n");
+ SPRINT("hw_rev=%d\n", 304);
+ SPRINT("dma_pipes=%d\n", 1);
+ SPRINT("\n");
+
+ return cnt;
+}
+
+static DEVICE_ATTR(caps, S_IRUGO, mdp3_show_capabilities, NULL);
+
+static struct attribute *mdp3_fs_attrs[] = {
+ &dev_attr_caps.attr,
+ NULL
+};
+
+static struct attribute_group mdp3_fs_attr_group = {
+ .attrs = mdp3_fs_attrs
+};
+
+static int mdp3_register_sysfs(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int rc;
+
+ rc = sysfs_create_group(&dev->kobj, &mdp3_fs_attr_group);
+
+ return rc;
+}
+
+int mdp3_create_sysfs_link(struct device *dev)
+{
+ int rc;
+ rc = sysfs_create_link_nowarn(&dev->kobj,
+ &mdp3_res->pdev->dev.kobj, "mdp");
+
+ return rc;
+}
static int mdp3_probe(struct platform_device *pdev)
{
@@ -1918,6 +1964,10 @@
goto probe_done;
}
+ rc = mdp3_register_sysfs(pdev);
+ if (rc)
+ pr_err("unable to register mdp sysfs nodes\n");
+
rc = mdss_fb_register_mdp_instance(&mdp3_interface);
if (rc)
pr_err("unable to register mdp instance\n");
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 4480c20..e66b5ac 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -186,6 +186,7 @@
void mdp3_free(void);
int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd);
void mdp3_release_splash_memory(void);
+int mdp3_create_sysfs_link(struct device *dev);
#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index e92e178..b123ccb 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -509,6 +509,9 @@
panel = mdp3_session->panel;
mutex_lock(&mdp3_session->lock);
+ if (panel && panel->set_backlight)
+ panel->set_backlight(panel, 0);
+
if (!mdp3_session->status) {
pr_debug("fb%d is off already", mfd->index);
goto off_error;
@@ -1355,7 +1358,7 @@
int rc = -EINVAL;
struct mdp3_session_data *mdp3_session;
struct msmfb_metadata metadata;
- struct mdp_overlay req;
+ struct mdp_overlay *req = NULL;
struct msmfb_overlay_data ov_data;
int val;
@@ -1363,6 +1366,8 @@
if (!mdp3_session)
return -ENODEV;
+ req = &mdp3_session->req_overlay;
+
if (!mdp3_session->status && cmd != MSMFB_METADATA_GET) {
pr_err("mdp3_ctrl_ioctl_handler, display off!\n");
return -EPERM;
@@ -1402,23 +1407,23 @@
rc = copy_to_user(argp, &metadata, sizeof(metadata));
break;
case MSMFB_OVERLAY_GET:
- rc = copy_from_user(&req, argp, sizeof(req));
+ rc = copy_from_user(req, argp, sizeof(*req));
if (!rc) {
- rc = mdp3_overlay_get(mfd, &req);
+ rc = mdp3_overlay_get(mfd, req);
if (!IS_ERR_VALUE(rc))
- rc = copy_to_user(argp, &req, sizeof(req));
+ rc = copy_to_user(argp, req, sizeof(*req));
}
if (rc)
pr_err("OVERLAY_GET failed (%d)\n", rc);
break;
case MSMFB_OVERLAY_SET:
- rc = copy_from_user(&req, argp, sizeof(req));
+ rc = copy_from_user(req, argp, sizeof(*req));
if (!rc) {
- rc = mdp3_overlay_set(mfd, &req);
+ rc = mdp3_overlay_set(mfd, req);
if (!IS_ERR_VALUE(rc))
- rc = copy_to_user(argp, &req, sizeof(req));
+ rc = copy_to_user(argp, req, sizeof(*req));
}
if (rc)
pr_err("OVERLAY_SET failed (%d)\n", rc);
@@ -1525,6 +1530,10 @@
goto init_done;
}
+ rc = mdp3_create_sysfs_link(dev);
+ if (rc)
+ pr_warn("problem creating link to mdp sysfs\n");
+
kobject_uevent(&dev->kobj, KOBJ_ADD);
pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 7c4f6ac..66ed3d5 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -45,6 +45,7 @@
int vsync_period;
struct sysfs_dirent *vsync_event_sd;
struct mdp_overlay overlay;
+ struct mdp_overlay req_overlay;
struct mdp3_buffer_queue bufq_in;
struct mdp3_buffer_queue bufq_out;
int histo_status;
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 865775a..bb1f8ae 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -1216,7 +1216,8 @@
}
}
- if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+ if (gpio_is_valid(ctrl_pdata->disp_te_gpio) &&
+ pinfo->type == MIPI_CMD_PANEL) {
rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
if (rc) {
pr_err("request TE gpio failed, rc=%d\n",
@@ -1304,6 +1305,7 @@
}
ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
+ ctrl_pdata->check_status = mdss_dsi_bta_status_check;
if (ctrl_pdata->bklt_ctrl == BL_PWM)
mdss_dsi_panel_pwm_cfg(ctrl_pdata);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 13dad06..7202c62 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -118,6 +118,8 @@
#define DSI_INTR_ERROR_MASK BIT(25)
#define DSI_INTR_ERROR BIT(24)
+#define DSI_INTR_BTA_DONE_MASK BIT(21)
+#define DSI_INTR_BTA_DONE BIT(20)
#define DSI_INTR_VIDEO_DONE_MASK BIT(17)
#define DSI_INTR_VIDEO_DONE BIT(16)
#define DSI_INTR_CMD_MDP_DONE_MASK BIT(9)
@@ -133,6 +135,7 @@
#define DSI_VIDEO_TERM BIT(16)
#define DSI_MDP_TERM BIT(8)
+#define DSI_BTA_TERM BIT(1)
#define DSI_CMD_TERM BIT(0)
extern struct device dsi_dev;
@@ -315,6 +318,7 @@
int (*on) (struct mdss_panel_data *pdata);
int (*off) (struct mdss_panel_data *pdata);
int (*partial_update_fnc) (struct mdss_panel_data *pdata);
+ int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
struct mdss_panel_data panel_data;
unsigned char *ctrl_base;
int reg_size;
@@ -360,6 +364,7 @@
struct completion dma_comp;
struct completion mdp_comp;
struct completion video_comp;
+ struct completion bta_comp;
spinlock_t irq_lock;
spinlock_t mdp_lock;
int mdp_busy;
@@ -428,6 +433,7 @@
struct dcs_cmd_req *cmdreq);
struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_cmdlist_kickoff(int intf);
+int mdss_dsi_bta_status_check(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 bb2818b..750fbf3 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -49,6 +49,8 @@
#define DSI_EVENT_Q_MAX 4
+#define DSI_BTA_EVENT_TIMEOUT (HZ / 10)
+
/* event */
struct dsi_event_q {
struct mdss_dsi_ctrl_pdata *ctrl;
@@ -98,6 +100,7 @@
init_completion(&ctrl->dma_comp);
init_completion(&ctrl->mdp_comp);
init_completion(&ctrl->video_comp);
+ init_completion(&ctrl->bta_comp);
spin_lock_init(&ctrl->irq_lock);
spin_lock_init(&ctrl->mdp_lock);
mutex_init(&ctrl->mutex);
@@ -1107,14 +1110,14 @@
if (mode == DSI_VIDEO_MODE) {
dsi_ctrl |= 0x03;
- intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK;
+ intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_BTA_DONE_MASK;
} else { /* command mode */
dsi_ctrl |= 0x05;
if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
dsi_ctrl |= 0x02;
intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK |
- DSI_INTR_CMD_MDP_DONE_MASK;
+ DSI_INTR_CMD_MDP_DONE_MASK | DSI_INTR_BTA_DONE_MASK;
}
if (ctrl_pdata->shared_pdata.broadcast_enable)
@@ -1160,6 +1163,45 @@
pr_debug("%s: BTA done, status = %d\n", __func__, status);
}
+int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ int ret = 0;
+ unsigned long flag;
+
+ if (ctrl_pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+
+ /*
+ * This should not return error otherwise
+ * BTA status thread will treat it as dead panel scenario
+ * and request for blank/unblank
+ */
+ return 0;
+ }
+
+ pr_debug("%s: Checking BTA status\n", __func__);
+
+ mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ spin_lock_irqsave(&ctrl_pdata->mdp_lock, flag);
+ INIT_COMPLETION(ctrl_pdata->bta_comp);
+ mdss_dsi_enable_irq(ctrl_pdata, DSI_BTA_TERM);
+ spin_unlock_irqrestore(&ctrl_pdata->mdp_lock, flag);
+ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x098, 0x01); /* trigger */
+ wmb();
+
+ ret = wait_for_completion_killable_timeout(&ctrl_pdata->bta_comp,
+ DSI_BTA_EVENT_TIMEOUT);
+ if (ret <= 0) {
+ mdss_dsi_disable_irq(ctrl_pdata, DSI_BTA_TERM);
+ pr_err("%s: DSI BTA error: %i\n", __func__, ret);
+ }
+
+ mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+ pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
+
+ return ret;
+}
+
static char set_tear_on[2] = {0x35, 0x00};
static struct dsi_cmd_desc dsi_tear_on_cmd = {
{DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on)}, set_tear_on};
@@ -2078,5 +2120,12 @@
spin_unlock(&ctrl->mdp_lock);
}
+ if (isr & DSI_INTR_BTA_DONE) {
+ spin_lock(&ctrl->mdp_lock);
+ mdss_dsi_disable_irq_nosync(ctrl, DSI_BTA_TERM);
+ complete(&ctrl->bta_comp);
+ spin_unlock(&ctrl->mdp_lock);
+ }
+
return IRQ_HANDLED;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 9932186..890066e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -293,6 +293,15 @@
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
+ /*
+ * Some backlight controllers specify a minimum duty cycle
+ * for the backlight brightness. If the brightness is less
+ * than it, the controller can malfunction.
+ */
+
+ if ((bl_level < pdata->panel_info.bl_min) && (bl_level != 0))
+ bl_level = pdata->panel_info.bl_min;
+
switch (ctrl_pdata->bklt_ctrl) {
case BL_WLED:
led_trigger_event(bl_led_trigger, bl_level);
diff --git a/drivers/video/msm/mdss/mdss_dsi_status.c b/drivers/video/msm/mdss/mdss_dsi_status.c
new file mode 100644
index 0000000..f0c4f4c
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_dsi_status.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/notifier.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/iopoll.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+
+#include "mdss_fb.h"
+#include "mdss_dsi.h"
+#include "mdss_panel.h"
+#include "mdss_mdp.h"
+
+#define STATUS_CHECK_INTERVAL 5000
+
+struct dsi_status_data {
+ struct notifier_block fb_notifier;
+ struct delayed_work check_status;
+ struct msm_fb_data_type *mfd;
+ uint32_t check_interval;
+};
+struct dsi_status_data *pstatus_data;
+static uint32_t interval = STATUS_CHECK_INTERVAL;
+
+/*
+ * check_dsi_ctrl_status() - Check DSI controller status periodically.
+ * @work : dsi controller status data
+ *
+ * This function calls check_status API on DSI controller to send the BTA
+ * command. If DSI controller fails to acknowledge the BTA command, it sends
+ * the PANEL_ALIVE=0 status to HAL layer.
+ */
+static void check_dsi_ctrl_status(struct work_struct *work)
+{
+ struct dsi_status_data *pdsi_status = NULL;
+ struct mdss_panel_data *pdata = NULL;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mdss_overlay_private *mdp5_data = NULL;
+ struct mdss_mdp_ctl *ctl = NULL;
+ int ret = 0;
+
+ pdsi_status = container_of(to_delayed_work(work),
+ struct dsi_status_data, check_status);
+ if (!pdsi_status) {
+ pr_err("%s: DSI status data not available\n", __func__);
+ return;
+ }
+
+ pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev);
+ if (!pdata) {
+ pr_err("%s: Panel data not available\n", __func__);
+ return;
+ }
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+ if (!ctrl_pdata || !ctrl_pdata->check_status) {
+ pr_err("%s: DSI ctrl or status_check callback not available\n",
+ __func__);
+ return;
+ }
+
+ mdp5_data = mfd_to_mdp5_data(pdsi_status->mfd);
+ ctl = mfd_to_ctl(pdsi_status->mfd);
+
+ if (ctl->shared_lock)
+ mutex_lock(ctl->shared_lock);
+ mutex_lock(&mdp5_data->ov_lock);
+
+ /*
+ * For the command mode panels, we return pan display
+ * IOCTL on vsync interrupt. So, after vsync interrupt comes
+ * and when DMA_P is in progress, if the panel stops responding
+ * and if we trigger BTA before DMA_P finishes, then the DSI
+ * FIFO will not be cleared since the DSI data bus control
+ * doesn't come back to the host after BTA. This may cause the
+ * display reset not to be proper. Hence, wait for DMA_P done
+ * for command mode panels before triggering BTA.
+ */
+ if (ctl->wait_pingpong)
+ ctl->wait_pingpong(ctl, NULL);
+
+ pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ ret = ctrl_pdata->check_status(ctrl_pdata);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ mutex_unlock(&mdp5_data->ov_lock);
+ if (ctl->shared_lock)
+ mutex_unlock(ctl->shared_lock);
+
+ if ((pdsi_status->mfd->panel_power_on)) {
+ if (ret > 0) {
+ schedule_delayed_work(&pdsi_status->check_status,
+ msecs_to_jiffies(pdsi_status->check_interval));
+ } else {
+ char *envp[2] = {"PANEL_ALIVE=0", NULL};
+ pdata->panel_info.panel_dead = true;
+ ret = kobject_uevent_env(
+ &pdsi_status->mfd->fbi->dev->kobj,
+ KOBJ_CHANGE, envp);
+ pr_err("%s: Panel has gone bad, sending uevent - %s\n",
+ __func__, envp[0]);
+ }
+ }
+}
+
+/*
+ * fb_event_callback() - Call back function for the fb_register_client()
+ * notifying events
+ * @self : notifier block
+ * @event : The event that was triggered
+ * @data : Of type struct fb_event
+ *
+ * This function listens for FB_BLANK_UNBLANK and FB_BLANK_POWERDOWN events
+ * from frame buffer. DSI status check work is either scheduled again after
+ * PANEL_STATUS_CHECK_INTERVAL or cancelled based on the event.
+ */
+static int fb_event_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ struct dsi_status_data *pdata = container_of(self,
+ struct dsi_status_data, fb_notifier);
+ pdata->mfd = evdata->info->par;
+
+ if (event == FB_EVENT_BLANK && evdata) {
+ int *blank = evdata->data;
+ switch (*blank) {
+ case FB_BLANK_UNBLANK:
+ schedule_delayed_work(&pdata->check_status,
+ msecs_to_jiffies(pdata->check_interval));
+ break;
+ case FB_BLANK_POWERDOWN:
+ cancel_delayed_work(&pdata->check_status);
+ break;
+ }
+ }
+ return 0;
+}
+
+int __init mdss_dsi_status_init(void)
+{
+ int rc = 0;
+
+ pstatus_data = kzalloc(sizeof(struct dsi_status_data), GFP_KERNEL);
+ if (!pstatus_data) {
+ pr_err("%s: can't allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ pstatus_data->fb_notifier.notifier_call = fb_event_callback;
+
+ rc = fb_register_client(&pstatus_data->fb_notifier);
+ if (rc < 0) {
+ pr_err("%s: fb_register_client failed, returned with rc=%d\n",
+ __func__, rc);
+ kfree(pstatus_data);
+ return -EPERM;
+ }
+
+ pstatus_data->check_interval = interval;
+ pr_info("%s: DSI status check interval:%d\n", __func__, interval);
+
+ INIT_DELAYED_WORK(&pstatus_data->check_status, check_dsi_ctrl_status);
+
+ pr_debug("%s: DSI ctrl status work queue initialized\n", __func__);
+
+ return rc;
+}
+
+void __exit mdss_dsi_status_exit(void)
+{
+ fb_unregister_client(&pstatus_data->fb_notifier);
+ cancel_delayed_work_sync(&pstatus_data->check_status);
+ kfree(pstatus_data);
+ pr_debug("%s: DSI ctrl status work queue removed\n", __func__);
+}
+
+module_param(interval, uint, 0);
+MODULE_PARM_DESC(interval,
+ "Duration in milliseconds to send BTA command for checking"
+ "DSI status periodically");
+
+module_init(mdss_dsi_status_init);
+module_exit(mdss_dsi_status_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 105dd1a..81473db 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -98,8 +98,10 @@
void mdss_fb_no_update_notify_timer_cb(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
- if (!mfd)
+ if (!mfd) {
pr_err("%s mfd NULL\n", __func__);
+ return;
+ }
mfd->no_update.value = NOTIFY_TYPE_NO_UPDATE;
complete(&mfd->no_update.comp);
}
@@ -107,9 +109,10 @@
static int mdss_fb_notify_update(struct msm_fb_data_type *mfd,
unsigned long *argp)
{
- int ret, notify, to_user;
+ int ret;
+ unsigned long notify = 0x0, to_user = 0x0;
- ret = copy_from_user(¬ify, argp, sizeof(int));
+ ret = copy_from_user(¬ify, argp, sizeof(unsigned long));
if (ret) {
pr_err("%s:ioctl failed\n", __func__);
return ret;
@@ -122,12 +125,12 @@
INIT_COMPLETION(mfd->update.comp);
ret = wait_for_completion_interruptible_timeout(
&mfd->update.comp, 4 * HZ);
- to_user = mfd->update.value;
+ to_user = (unsigned int)mfd->update.value;
} else if (notify == NOTIFY_UPDATE_STOP) {
INIT_COMPLETION(mfd->no_update.comp);
ret = wait_for_completion_interruptible_timeout(
&mfd->no_update.comp, 4 * HZ);
- to_user = mfd->no_update.value;
+ to_user = (unsigned int)mfd->no_update.value;
} else {
if (mfd->panel_power_on) {
INIT_COMPLETION(mfd->power_off_comp);
@@ -139,7 +142,7 @@
if (ret == 0)
ret = -ETIMEDOUT;
else if (ret > 0)
- ret = copy_to_user(argp, &to_user, sizeof(int));
+ ret = copy_to_user(argp, &to_user, sizeof(unsigned long));
return ret;
}
@@ -616,11 +619,11 @@
* scaling fraction (x/1024)
*/
temp = (temp * mfd->bl_scale) / 1024;
- }
- /*if less than minimum level, use min level*/
- else if ((temp < mfd->bl_min_lvl) && (0 != temp))
- temp = mfd->bl_min_lvl;
+ /*if less than minimum level, use min level*/
+ if (temp < mfd->bl_min_lvl)
+ temp = mfd->bl_min_lvl;
+ }
pr_debug("output = %d", temp);
(*bl_lvl) = temp;
@@ -635,11 +638,8 @@
if (((!mfd->panel_power_on && mfd->dcm_state != DCM_ENTER)
|| !mfd->bl_updated) && !IS_CALIB_MODE_BL(mfd)) {
- if (bkl_lvl < mfd->bl_min_lvl)
- mfd->unset_bl_level = mfd->bl_min_lvl;
- else
- mfd->unset_bl_level = bkl_lvl;
- return;
+ mfd->unset_bl_level = bkl_lvl;
+ return;
} else {
mfd->unset_bl_level = 0;
}
@@ -708,8 +708,10 @@
case FB_BLANK_UNBLANK:
if (!mfd->panel_power_on && mfd->mdp.on_fnc) {
ret = mfd->mdp.on_fnc(mfd);
- if (ret == 0)
+ if (ret == 0) {
mfd->panel_power_on = true;
+ mfd->panel_info->panel_dead = false;
+ }
mutex_lock(&mfd->update.lock);
mfd->update.type = NOTIFY_TYPE_UPDATE;
mutex_unlock(&mfd->update.lock);
@@ -1413,7 +1415,7 @@
u32 wait_for_finish = disp_commit->wait_for_finish;
int ret = 0;
- if ((!mfd->op_enable) || (!mfd->panel_power_on))
+ if (!mfd || (!mfd->op_enable) || (!mfd->panel_power_on))
return -EPERM;
if (var->xoffset > (info->var.xres_virtual - info->var.xres))
@@ -1972,7 +1974,8 @@
return -EINVAL;
mfd = (struct msm_fb_data_type *)info->par;
mdss_fb_power_setting_idle(mfd);
- if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL))
+ if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
+ (cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT))
mdss_fb_pan_idle(mfd);
switch (cmd) {
diff --git a/drivers/video/msm/mdss/mdss_hdmi_edid.c b/drivers/video/msm/mdss/mdss_hdmi_edid.c
index cf0c287..a45876b 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_edid.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_edid.c
@@ -16,6 +16,13 @@
#include "mdss_hdmi_edid.h"
#define DBC_START_OFFSET 4
+
+/*
+ * As per CEA-861-E specification 7.5.2, there can be
+ * upto 31 bytes following any tag (data block type).
+ */
+#define MAX_DATA_BLOCK_SIZE 31
+
#define HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd) \
(!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
@@ -32,6 +39,17 @@
/* Support for first 5 EDID blocks */
#define MAX_EDID_BLOCK_SIZE (0x80 * 5)
+enum data_block_types {
+ RESERVED,
+ AUDIO_DATA_BLOCK,
+ VIDEO_DATA_BLOCK,
+ VENDOR_SPECIFIC_DATA_BLOCK,
+ SPEAKER_ALLOCATION_DATA_BLOCK,
+ VESA_DTC_DATA_BLOCK,
+ RESERVED2,
+ USE_EXTENDED_TAG
+};
+
struct hdmi_edid_sink_data {
u32 disp_mode_list[HDMI_VFRMT_MAX];
u32 disp_3d_mode_list[HDMI_VFRMT_MAX];
@@ -524,7 +542,8 @@
}
/* A Tage code of 7 identifies extended data blocks */
- etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+ etag = hdmi_edid_find_block(in_buf, start_offset, USE_EXTENDED_TAG,
+ &len);
while (etag != NULL) {
/* The extended data block should at least be 2 bytes long */
@@ -570,7 +589,8 @@
/* There could be more that one extended data block */
start_offset = etag - in_buf + len + 1;
- etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len);
+ etag = hdmi_edid_find_block(in_buf, start_offset,
+ USE_EXTENDED_TAG, &len);
}
} /* hdmi_edid_extract_extended_data_blocks */
@@ -585,11 +605,12 @@
return;
}
- vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+ VENDOR_SPECIFIC_DATA_BLOCK, &len);
edid_ctrl->present_3d = 0;
- if (vsd == NULL || len < 9) {
- DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+ if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+ DEV_DBG("%s: No/Invalid vendor Specific Data Block\n",
__func__);
return;
}
@@ -616,9 +637,13 @@
return;
}
- adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, &len);
- if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE))
+ adb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, AUDIO_DATA_BLOCK,
+ &len);
+ if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE)) {
+ DEV_DBG("%s: No/Invalid Audio Data Block\n",
+ __func__);
return;
+ }
memcpy(edid_ctrl->audio_data_block, adb + 1, len);
edid_ctrl->adb_size = len;
@@ -644,9 +669,13 @@
return;
}
- sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, &len);
- if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE))
+ sadb = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+ SPEAKER_ALLOCATION_DATA_BLOCK, &len);
+ if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)) {
+ DEV_DBG("%s: No/Invalid Speaker Allocation Data Block\n",
+ __func__);
return;
+ }
memcpy(edid_ctrl->spkr_alloc_data_block, sadb + 1, len);
edid_ctrl->sadb_size = len;
@@ -673,9 +702,11 @@
return;
}
- vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+ VENDOR_SPECIFIC_DATA_BLOCK, &len);
- if (vsd == NULL || len < 12 || !(vsd[8] & BIT(7))) {
+ if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE ||
+ !(vsd[8] & BIT(7))) {
edid_ctrl->video_latency = (u16)-1;
edid_ctrl->audio_latency = (u16)-1;
DEV_DBG("%s: EDID: No audio/video latency present\n", __func__);
@@ -699,9 +730,14 @@
return 0;
}
- vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &len);
- if (vsd == NULL || len < 8)
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+ VENDOR_SPECIFIC_DATA_BLOCK, &len);
+
+ if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+ DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n",
+ __func__);
return 0;
+ }
DEV_DBG("%s: EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n", __func__,
((u32)vsd[4] << 8) + (u32)vsd[5], (u32)vsd[7] * 5);
@@ -898,11 +934,14 @@
u16 structure_all, structure_mask;
const u8 *vsd = num_of_cea_blocks ?
hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
- 3, &len) : NULL;
+ VENDOR_SPECIFIC_DATA_BLOCK, &len) : NULL;
int i;
- if (!vsd)
+ if (vsd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+ DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n",
+ __func__);
return -ENXIO;
+ }
offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
if (offset >= len - 1)
@@ -1044,10 +1083,11 @@
return;
}
- vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, &db_len);
+ vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET,
+ VENDOR_SPECIFIC_DATA_BLOCK, &db_len);
- if (vsd == NULL || db_len < 9) {
- DEV_DBG("%s: blk-id 3 not found or not long enough\n",
+ if (vsd == NULL || db_len == 0 || db_len > MAX_DATA_BLOCK_SIZE) {
+ DEV_DBG("%s: No/Invalid Vendor Specific Data Block\n",
__func__);
return;
}
@@ -1097,8 +1137,14 @@
edid_blk0 = &data_buf[0x0];
edid_blk1 = &data_buf[0x80];
svd = num_of_cea_blocks ?
- hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, 2,
- &len) : NULL;
+ hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET,
+ VIDEO_DATA_BLOCK, &len) : NULL;
+
+ if (svd == NULL || len == 0 || len > MAX_DATA_BLOCK_SIZE) {
+ DEV_DBG("%s: No/Invalid Video Data Block\n",
+ __func__);
+ return;
+ }
sink_data = &edid_ctrl->sink_data;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index 80b27ed..ca21b51 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -289,6 +289,10 @@
}
DEV_DBG("%s: %s: BCAPS=%02x\n", __func__, HDCP_STATE_NAME, bcaps);
+ /* receiver (0), repeater (1) */
+ hdcp_ctrl->current_tp.ds_type =
+ (bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
+
/*
* HDCP setup prior to enabling HDCP_CTRL.
* Setup seed values for random number An.
@@ -644,40 +648,12 @@
memset(ksv_fifo, 0,
sizeof(hdcp_ctrl->current_tp.ksv_list));
- /* Read BCAPS at offset 0x40 */
- memset(&ddc_data, 0, sizeof(ddc_data));
- ddc_data.dev_addr = 0x74;
- ddc_data.offset = 0x40;
- ddc_data.data_buf = &bcaps;
- ddc_data.data_len = 1;
- ddc_data.request_len = 1;
- ddc_data.retry = 5;
- ddc_data.what = "Bcaps";
- ddc_data.no_align = false;
- rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl, &ddc_data);
- if (rc) {
- DEV_ERR("%s: %s: BCAPS read failed\n", __func__,
- HDCP_STATE_NAME);
- goto error;
- }
- DEV_DBG("%s: %s: BCAPS=%02x (%s)\n", __func__, HDCP_STATE_NAME, bcaps,
- (bcaps & BIT(6)) ? "repeater" : "no repeater");
-
- /* receiver (0), repeater (1) */
- hdcp_ctrl->current_tp.ds_type =
- (bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
-
- /* if REPEATER (Bit 6), perform Part2 Authentication */
- if (!(bcaps & BIT(6))) {
- DEV_INFO("%s: %s: auth part II skipped, no repeater\n",
- __func__, HDCP_STATE_NAME);
- return 0;
- }
-
- /* Wait until READY bit is set in BCAPS */
+ /*
+ * Wait until READY bit is set in BCAPS, as per HDCP specifications
+ * maximum permitted time to check for READY bit is five seconds.
+ */
timeout_count = 50;
- while (!(bcaps & BIT(5)) && timeout_count) {
- msleep(100);
+ do {
timeout_count--;
/* Read BCAPS at offset 0x40 */
memset(&ddc_data, 0, sizeof(ddc_data));
@@ -695,7 +671,8 @@
HDCP_STATE_NAME);
goto error;
}
- }
+ msleep(100);
+ } while (!(bcaps & BIT(5)) && timeout_count);
/* Read BSTATUS at offset 0x41 */
memset(&ddc_data, 0, sizeof(ddc_data));
@@ -976,11 +953,15 @@
goto error;
}
- rc = hdmi_hdcp_authentication_part2(hdcp_ctrl);
- if (rc) {
- DEV_DBG("%s: %s: HDCP Auth Part II failed\n", __func__,
- HDCP_STATE_NAME);
- goto error;
+ if (hdcp_ctrl->current_tp.ds_type == DS_REPEATER) {
+ rc = hdmi_hdcp_authentication_part2(hdcp_ctrl);
+ if (rc) {
+ DEV_DBG("%s: %s: HDCP Auth Part II failed\n", __func__,
+ HDCP_STATE_NAME);
+ goto error;
+ }
+ } else {
+ DEV_INFO("%s: Downstream device is not a repeater\n", __func__);
}
/* Disabling software DDC before going into part3 to make sure
* there is no Arbitration between software and hardware for DDC */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 0cd0543..87b7526 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -2493,6 +2493,10 @@
mutex_unlock(&hdmi_ctrl->mutex);
DEV_INFO("%s: HDMI Core: OFF\n", __func__);
+
+ if (hdmi_ctrl->hdmi_tx_hpd_done)
+ hdmi_ctrl->hdmi_tx_hpd_done(
+ hdmi_ctrl->downstream_data);
} /* hdmi_tx_power_off_work */
static int hdmi_tx_power_off(struct mdss_panel_data *panel_data)
@@ -2595,6 +2599,9 @@
hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_DISCONNECT_POLARITY);
+ if (hdmi_ctrl->hdmi_tx_hpd_done)
+ hdmi_ctrl->hdmi_tx_hpd_done(hdmi_ctrl->downstream_data);
+
return 0;
} /* hdmi_tx_power_on */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 5f2a23e..66071e9 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -86,6 +86,9 @@
struct hdmi_tx_ddc_ctrl ddc_ctrl;
+ void (*hdmi_tx_hpd_done) (void *data);
+ void *downstream_data;
+
void *feature_data[HDMI_TX_FEAT_MAX];
};
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 5442d9d..d140ea0 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -37,7 +37,6 @@
#define MAX_IMG_HEIGHT 0x3FFF
#define MAX_DST_W MAX_MIXER_WIDTH
#define MAX_DST_H MAX_MIXER_HEIGHT
-#define MAX_PLANES 4
#define MAX_DOWNSCALE_RATIO 4
#define MAX_UPSCALE_RATIO 20
#define MAX_DECIMATION 4
@@ -52,6 +51,11 @@
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
#define KOFF_TIMEOUT msecs_to_jiffies(84)
+#define OVERFETCH_DISABLE_TOP BIT(0)
+#define OVERFETCH_DISABLE_BOTTOM BIT(1)
+#define OVERFETCH_DISABLE_LEFT BIT(2)
+#define OVERFETCH_DISABLE_RIGHT BIT(3)
+
#ifdef MDSS_MDP_DEBUG_REG
static inline void mdss_mdp_reg_write(u32 addr, u32 val)
{
@@ -341,9 +345,6 @@
u8 vert_deci;
struct mdss_mdp_img_rect src;
struct mdss_mdp_img_rect dst;
- u32 phase_step_x;
- u32 phase_step_y;
-
struct mdss_mdp_format_params *src_fmt;
struct mdss_mdp_plane_sizes src_planes;
@@ -370,11 +371,13 @@
struct mdp_overlay_pp_params pp_cfg;
struct mdss_pipe_pp_res pp_res;
+ struct mdp_scale_data scale;
+ u8 chroma_sample_h;
+ u8 chroma_sample_v;
};
struct mdss_mdp_writeback_arg {
struct mdss_mdp_data *data;
- void (*callback_fnc) (void *arg);
void *priv_data;
};
@@ -633,6 +636,7 @@
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);
+int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
(mfd->mdp.private1))->mdata)
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 82937e3..aa7c4dd 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -28,7 +28,7 @@
#define MDSS_MDP_BUS_FUDGE_FACTOR_IB(val) (((val) / 2) * 3)
#define MDSS_MDP_BUS_FUDGE_FACTOR_HIGH_IB(val) (val << 1)
#define MDSS_MDP_BUS_FUDGE_FACTOR_AB(val) (val << 1)
-#define MDSS_MDP_BUS_FLOOR_BW (3200000000ULL >> MDSS_MDP_BUS_FACTOR_SHIFT)
+#define MDSS_MDP_BUS_FLOOR_BW (1600000000ULL >> MDSS_MDP_BUS_FACTOR_SHIFT)
/* 1.25 clock fudge factor */
#define MDSS_MDP_CLK_FUDGE_FACTOR(val) (((val) * 5) / 4)
@@ -1560,9 +1560,17 @@
struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux)
{
struct mdss_mdp_mixer *mixer = NULL;
- struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd);
- if (!ctl)
+ struct mdss_overlay_private *mdp5_data = NULL;
+ if (!ctl || !ctl->mfd) {
+ pr_err("ctl not initialized\n");
return NULL;
+ }
+
+ mdp5_data = mfd_to_mdp5_data(ctl->mfd);
+ if (!mdp5_data) {
+ pr_err("ctl not initialized\n");
+ return NULL;
+ }
switch (mux) {
case MDSS_MDP_MIXER_MUX_DEFAULT:
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index c8af903..52ca42c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -201,6 +201,9 @@
#define MDSS_MDP_REG_SSPP_CURRENT_SRC2_ADDR 0x0AC
#define MDSS_MDP_REG_SSPP_CURRENT_SRC3_ADDR 0x0B0
#define MDSS_MDP_REG_SSPP_DECIMATION_CONFIG 0x0B4
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_LR 0x100
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_TB 0x104
+#define MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_REQ_PIXELS 0x108
#define MDSS_MDP_REG_VIG_OP_MODE 0x200
#define MDSS_MDP_REG_VIG_QSEED2_CONFIG 0x204
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 6056f21..d3e18ac 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -532,6 +532,7 @@
int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_cmd_ctx *ctx;
+ struct mdss_panel_info *pinfo;
unsigned long flags;
struct mdss_mdp_vsync_handler *tmp, *handle;
int need_wait = 0;
@@ -555,9 +556,23 @@
if (need_wait)
if (wait_for_completion_timeout(&ctx->stop_comp, STOP_TIMEOUT)
- <= 0)
+ <= 0) {
WARN(1, "stop cmd time out\n");
+ if (IS_ERR_OR_NULL(ctl->panel_data)) {
+ pr_err("no panel data\n");
+ } else {
+ pinfo = &ctl->panel_data->panel_info;
+
+ if (pinfo->panel_dead) {
+ mdss_mdp_irq_disable
+ (MDSS_MDP_IRQ_PING_PONG_RD_PTR,
+ ctx->pp_num);
+ ctx->rdptr_enabled = 0;
+ }
+ }
+ }
+
if (cancel_work_sync(&ctx->clk_work))
pr_debug("no pending clk work\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 7c79ceb..bd1c3eb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -294,6 +294,7 @@
struct mdss_mdp_video_ctx *ctx;
struct mdss_mdp_vsync_handler *tmp, *handle;
int rc;
+ u32 frame_rate = 0;
pr_debug("stop ctl=%d\n", ctl->num);
@@ -313,6 +314,14 @@
WARN(rc, "intf %d blank error (%d)\n", ctl->intf_num, rc);
mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+ /* wait for at least one VSYNC on HDMI intf for proper TG OFF */
+ if (MDSS_INTF_HDMI == ctx->intf_type) {
+ frame_rate = mdss_panel_get_framerate
+ (&(ctl->panel_data->panel_info));
+ if (!(frame_rate >= 24 && frame_rate <= 240))
+ frame_rate = 24;
+ msleep((1000/frame_rate) + 1);
+ }
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
ctx->timegen_en = false;
@@ -429,10 +438,9 @@
} else {
rc = 0;
}
-
- mdss_mdp_ctl_notify(ctl,
- rc ? MDP_NOTIFY_FRAME_TIMEOUT : MDP_NOTIFY_FRAME_DONE);
}
+ mdss_mdp_ctl_notify(ctl,
+ rc ? MDP_NOTIFY_FRAME_TIMEOUT : MDP_NOTIFY_FRAME_DONE);
if (ctx->wait_pending) {
ctx->wait_pending = 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 3929501..ff55c57 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -46,8 +46,6 @@
struct mdss_mdp_plane_sizes dst_planes;
- void (*callback_fnc) (void *arg);
- void *callback_arg;
spinlock_t wb_lock;
struct list_head vsync_handlers;
};
@@ -365,6 +363,8 @@
mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
NULL, NULL);
+ complete_all(&ctx->wb_comp);
+
ctl->priv_data = NULL;
ctx->ref_cnt--;
}
@@ -389,9 +389,6 @@
mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num);
- if (ctx->callback_fnc)
- ctx->callback_fnc(ctx->callback_arg);
-
spin_lock(&ctx->wb_lock);
list_for_each_entry(tmp, &ctx->vsync_handlers, list) {
tmp->vsync_handler(ctl, vsync_time);
@@ -467,9 +464,6 @@
mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
mdss_mdp_writeback_intr_done, ctl);
- ctx->callback_fnc = wb_args->callback_fnc;
- ctx->callback_arg = wb_args->priv_data;
-
flush_bits = BIT(16); /* WB */
mdp_wb_write(ctx, MDSS_MDP_REG_WB_DST_ADDR_SW_STATUS, ctl->is_secure);
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush_bits);
@@ -529,6 +523,8 @@
int mdss_mdp_writeback_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
{
+ int ret = 0;
+
if (ctl->shared_lock && !mutex_is_locked(ctl->shared_lock)) {
pr_err("shared mutex is not locked before commit on ctl=%d\n",
ctl->num);
@@ -542,5 +538,10 @@
ctl->mixer_right->params_changed++;
}
- return mdss_mdp_display_commit(ctl, arg);
+ ret = mdss_mdp_display_commit(ctl, arg);
+
+ if (!IS_ERR_VALUE(ret))
+ mdss_mdp_display_wait4comp(ctl);
+
+ return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c296edb..0fb01ad 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -282,7 +282,12 @@
int rc;
src = pipe->src.w >> pipe->horz_deci;
- rc = mdss_mdp_calc_phase_step(src, pipe->dst.w, &pipe->phase_step_x);
+
+ if (pipe->scale.enable_pxl_ext)
+ return 0;
+ memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
+ rc = mdss_mdp_calc_phase_step(src, pipe->dst.w,
+ &pipe->scale.phase_step_x[0]);
if (rc) {
pr_err("Horizontal scaling calculation failed=%d! %d->%d\n",
rc, src, pipe->dst.w);
@@ -290,16 +295,43 @@
}
src = pipe->src.h >> pipe->vert_deci;
- rc = mdss_mdp_calc_phase_step(src, pipe->dst.h, &pipe->phase_step_y);
+ rc = mdss_mdp_calc_phase_step(src, pipe->dst.h,
+ &pipe->scale.phase_step_y[0]);
if (rc) {
pr_err("Vertical scaling calculation failed=%d! %d->%d\n",
rc, src, pipe->dst.h);
return rc;
}
-
+ pipe->scale.init_phase_x[0] = (pipe->scale.phase_step_x[0] -
+ (1 << PHASE_STEP_SHIFT)) / 2;
+ pipe->scale.init_phase_y[0] = (pipe->scale.phase_step_y[0] -
+ (1 << PHASE_STEP_SHIFT)) / 2;
return 0;
}
+static inline void __mdss_mdp_overlay_set_chroma_sample(
+ struct mdss_mdp_pipe *pipe)
+{
+ pipe->chroma_sample_v = pipe->chroma_sample_h = 0;
+
+ switch (pipe->src_fmt->chroma_sample) {
+ case MDSS_MDP_CHROMA_H1V2:
+ pipe->chroma_sample_v = 1;
+ break;
+ case MDSS_MDP_CHROMA_H2V1:
+ pipe->chroma_sample_h = 1;
+ break;
+ case MDSS_MDP_CHROMA_420:
+ pipe->chroma_sample_v = 1;
+ pipe->chroma_sample_h = 1;
+ break;
+ }
+ if (pipe->horz_deci)
+ pipe->chroma_sample_h = 0;
+ if (pipe->vert_deci)
+ pipe->chroma_sample_v = 0;
+}
+
static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
struct mdp_overlay *req,
struct mdss_mdp_pipe **ppipe)
@@ -442,7 +474,10 @@
pipe->dst.h = req->dst_rect.h;
pipe->horz_deci = req->horz_deci;
pipe->vert_deci = req->vert_deci;
+
+ memcpy(&pipe->scale, &req->scale, sizeof(struct mdp_scale_data));
pipe->src_fmt = fmt;
+ __mdss_mdp_overlay_set_chroma_sample(pipe);
pipe->mixer_stage = req->z_order;
pipe->is_fg = req->is_fg;
@@ -458,8 +493,17 @@
pr_debug("Unintended blend_op %d on layer with no alpha plane\n",
pipe->blend_op);
- pipe->overfetch_disable = fmt->is_yuv &&
- !(pipe->flags & MDP_SOURCE_ROTATED_90);
+ if (fmt->is_yuv && !(pipe->flags & MDP_SOURCE_ROTATED_90) &&
+ !pipe->scale.enable_pxl_ext) {
+ pipe->overfetch_disable = OVERFETCH_DISABLE_BOTTOM;
+
+ if (!(pipe->flags & MDSS_MDP_DUAL_PIPE) ||
+ (pipe->flags & MDSS_MDP_RIGHT_MIXER))
+ pipe->overfetch_disable |= OVERFETCH_DISABLE_RIGHT;
+ pr_debug("overfetch flags=%x\n", pipe->overfetch_disable);
+ } else {
+ pipe->overfetch_disable = 0;
+ }
req->id = pipe->ndx;
pipe->req_data = *req;
@@ -516,7 +560,7 @@
}
}
- if (pipe->flags & MDP_DEINTERLACE) {
+ if ((pipe->flags & MDP_DEINTERLACE) && !pipe->scale.enable_pxl_ext) {
if (pipe->flags & MDP_SOURCE_ROTATED_90) {
pipe->src.w /= 2;
pipe->img_width /= 2;
@@ -539,6 +583,12 @@
!mdp5_data->mdata->has_wfd_blk)
mdss_mdp_smp_release(pipe);
+ /*
+ * Clear previous SMP reservations and reserve according to the
+ * latest configuration
+ */
+ mdss_mdp_smp_unreserve(pipe);
+
ret = mdss_mdp_smp_reserve(pipe);
if (ret) {
pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
@@ -1475,15 +1525,26 @@
static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
ktime_t t)
{
- struct msm_fb_data_type *mfd = ctl->mfd;
- struct mdss_overlay_private *mdp5_data;
+ struct msm_fb_data_type *mfd = NULL;
+ struct mdss_overlay_private *mdp5_data = NULL;
+ if (!ctl) {
+ pr_err("ctl is NULL\n");
+ return;
+ }
+
+ mfd = ctl->mfd;
if (!mfd || !mfd->mdp.private1) {
pr_warn("Invalid handle for vsync\n");
return;
}
mdp5_data = mfd_to_mdp5_data(mfd);
+ if (!mdp5_data) {
+ pr_err("mdp5_data is NULL\n");
+ return;
+ }
+
pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
mdp5_data->vsync_time = t;
@@ -2111,7 +2172,7 @@
u32 cmd, void __user *argp)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- struct mdp_overlay req;
+ struct mdp_overlay *req = NULL;
int val, ret = -ENOSYS;
struct msmfb_metadata metadata;
@@ -2127,12 +2188,15 @@
break;
case MSMFB_OVERLAY_GET:
- ret = copy_from_user(&req, argp, sizeof(req));
+ req = kmalloc(sizeof(struct mdp_overlay), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ ret = copy_from_user(req, argp, sizeof(*req));
if (!ret) {
- ret = mdss_mdp_overlay_get(mfd, &req);
+ ret = mdss_mdp_overlay_get(mfd, req);
if (!IS_ERR_VALUE(ret))
- ret = copy_to_user(argp, &req, sizeof(req));
+ ret = copy_to_user(argp, req, sizeof(*req));
}
if (ret)
@@ -2140,12 +2204,15 @@
break;
case MSMFB_OVERLAY_SET:
- ret = copy_from_user(&req, argp, sizeof(req));
+ req = kmalloc(sizeof(struct mdp_overlay), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ ret = copy_from_user(req, argp, sizeof(*req));
if (!ret) {
- ret = mdss_mdp_overlay_set(mfd, &req);
+ ret = mdss_mdp_overlay_set(mfd, req);
if (!IS_ERR_VALUE(ret))
- ret = copy_to_user(argp, &req, sizeof(req));
+ ret = copy_to_user(argp, req, sizeof(*req));
}
if (ret)
pr_debug("OVERLAY_SET failed (%d)\n", ret);
@@ -2230,6 +2297,7 @@
break;
}
+ kfree(req);
return ret;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 779f74c..25cb9dd 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -581,6 +581,8 @@
mdss_mdp_smp_free(pipe);
pipe->flags = 0;
pipe->bwc_mode = 0;
+ memset(&pipe->scale, 0, sizeof(struct mdp_scale_data));
+
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
return 0;
@@ -728,24 +730,43 @@
dst = pipe->dst;
src = pipe->src;
- mdss_mdp_crop_rect(&src, &dst, &sci);
+ if (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+ mdss_mdp_crop_rect(&src, &dst, &sci);
src_size = (src.h << 16) | src.w;
src_xy = (src.y << 16) | src.x;
dst_size = (dst.h << 16) | dst.w;
dst_xy = (dst.y << 16) | dst.x;
- img_size = (height << 16) | width;
-
ystride0 = (pipe->src_planes.ystride[0]) |
(pipe->src_planes.ystride[1] << 16);
ystride1 = (pipe->src_planes.ystride[2]) |
(pipe->src_planes.ystride[3] << 16);
- if (pipe->overfetch_disable) {
- img_size = src_size;
- src_xy = 0;
+ /*
+ * Software overfetch is used when scalar pixel extension is
+ * not enabled
+ */
+ if (pipe->overfetch_disable && !pipe->scale.enable_pxl_ext) {
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_BOTTOM) {
+ height = pipe->src.h;
+ if (!(pipe->overfetch_disable & OVERFETCH_DISABLE_TOP))
+ height += pipe->src.y;
+ }
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_RIGHT) {
+ width = pipe->src.w;
+ if (!(pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT))
+ width += pipe->src.x;
+ }
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT)
+ src_xy &= ~0xFFFF;
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_TOP)
+ src_xy &= ~(0xFFFF << 16);
+
+ pr_debug("overfetch w=%d/%d h=%d/%d src_xy=0x%08x\n", width,
+ pipe->img_width, height, pipe->img_height, src_xy);
}
+ img_size = (height << 16) | width;
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_IMG_SIZE, img_size);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_SIZE, src_size);
@@ -812,6 +833,9 @@
mdss_mdp_pipe_sspp_setup(pipe, &opmode);
+ if (pipe->scale.enable_pxl_ext)
+ opmode |= (1 << 31);
+
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT, src_format);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN, unpack);
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
@@ -843,33 +867,42 @@
}
static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
- struct mdss_mdp_data *data)
+ struct mdss_mdp_data *src_data)
{
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ struct mdss_mdp_data data = *src_data;
int ret = 0;
pr_debug("pnum=%d\n", pipe->num);
- data->bwc_enabled = pipe->bwc_mode;
+ data.bwc_enabled = pipe->bwc_mode;
- ret = mdss_mdp_data_check(data, &pipe->src_planes);
+ ret = mdss_mdp_data_check(&data, &pipe->src_planes);
if (ret)
return ret;
- if (pipe->overfetch_disable)
- mdss_mdp_data_calc_offset(data, pipe->src.x, pipe->src.y,
+ if (pipe->overfetch_disable && !pipe->scale.enable_pxl_ext) {
+ u32 x = 0, y = 0;
+
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_LEFT)
+ x = pipe->src.x;
+ if (pipe->overfetch_disable & OVERFETCH_DISABLE_TOP)
+ y = pipe->src.y;
+
+ mdss_mdp_data_calc_offset(&data, x, y,
&pipe->src_planes, pipe->src_fmt);
+ }
/* planar format expects YCbCr, swap chroma planes if YCrCb */
if (mdata->mdp_rev < MDSS_MDP_HW_REV_102 &&
(pipe->src_fmt->fetch_planes == MDSS_MDP_PLANE_PLANAR)
&& (pipe->src_fmt->element[0] == C1_B_Cb))
- swap(data->p[1].addr, data->p[2].addr);
+ swap(data.p[1].addr, data.p[2].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data->p[0].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data->p[1].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data->p[2].addr);
- mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data->p[3].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data.p[0].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data.p[1].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data.p[2].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data.p[3].addr);
return 0;
}
@@ -900,8 +933,9 @@
struct mdss_mdp_data *src_data)
{
int ret = 0;
- u32 params_changed, opmode;
struct mdss_mdp_ctl *ctl;
+ u32 params_changed;
+ u32 opmode = 0;
if (!pipe) {
pr_err("pipe not setup properly for queue\n");
@@ -982,3 +1016,53 @@
{
return (pipe == pipe->mixer->stage_pipe[pipe->mixer_stage]);
}
+
+static inline void __mdss_mdp_pipe_program_pixel_extn_helper(
+ struct mdss_mdp_pipe *pipe, u32 plane, u32 off)
+{
+ u32 src_h = pipe->src.h >> pipe->vert_deci;
+ u32 mask = 0xFF;
+
+ /*
+ * CB CR plane required pxls need to be accounted
+ * for chroma decimation.
+ */
+ if (plane == 1)
+ src_h >>= pipe->chroma_sample_v;
+ writel_relaxed(((pipe->scale.right_ftch[plane] & mask) << 24)|
+ ((pipe->scale.right_rpt[plane] & mask) << 16)|
+ ((pipe->scale.left_ftch[plane] & mask) << 8)|
+ (pipe->scale.left_rpt[plane] & mask), pipe->base +
+ MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_LR + off);
+ writel_relaxed(((pipe->scale.btm_ftch[plane] & mask) << 24)|
+ ((pipe->scale.btm_rpt[plane] & mask) << 16)|
+ ((pipe->scale.top_ftch[plane] & mask) << 8)|
+ (pipe->scale.top_rpt[plane] & mask), pipe->base +
+ MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_TB + off);
+ mask = 0xFFFF;
+ writel_relaxed((((src_h + pipe->scale.num_ext_pxls_top[plane] +
+ pipe->scale.num_ext_pxls_btm[plane]) & mask) << 16) |
+ ((pipe->scale.roi_w[plane] +
+ pipe->scale.num_ext_pxls_left[plane] +
+ pipe->scale.num_ext_pxls_right[plane]) & mask), pipe->base +
+ MDSS_MDP_REG_SSPP_SW_PIX_EXT_C0_REQ_PIXELS + off);
+}
+
+/**
+ * mdss_mdp_pipe_program_pixel_extn - Program the source pipe's
+ * sw pixel extension
+ * @pipe: Source pipe struct containing pixel extn values
+ *
+ * Function programs the pixel extn values calculated during
+ * scale setup.
+ */
+int mdss_mdp_pipe_program_pixel_extn(struct mdss_mdp_pipe *pipe)
+{
+ /* Y plane pixel extn */
+ __mdss_mdp_pipe_program_pixel_extn_helper(pipe, 0, 0);
+ /* CB CR plane pixel extn */
+ __mdss_mdp_pipe_program_pixel_extn_helper(pipe, 1, 16);
+ /* Alpha plane pixel extn */
+ __mdss_mdp_pipe_program_pixel_extn_helper(pipe, 3, 32);
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index b31f6c1..dc7b8b3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -629,7 +629,7 @@
}
}
- *op = opmode;
+ *op |= opmode;
return 0;
}
@@ -637,12 +637,15 @@
static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
{
u32 scale_config = 0;
- u32 phasex_step = 0, phasey_step = 0;
+ int init_phasex = 0, init_phasey = 0;
+ int phasex_step = 0, phasey_step = 0;
u32 chroma_sample;
u32 filter_mode;
struct mdss_data_type *mdata;
u32 src_w, src_h;
+ pr_debug("pipe=%d, change pxl ext=%d\n", pipe->num,
+ pipe->scale.enable_pxl_ext);
mdata = mdss_mdp_get_mdata();
if (mdata->mdp_rev >= MDSS_MDP_HW_REV_102 && pipe->src_fmt->is_yuv)
filter_mode = MDSS_MDP_SCALE_FILTER_CA;
@@ -689,7 +692,8 @@
if ((src_h != pipe->dst.h) ||
(pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) ||
(chroma_sample == MDSS_MDP_CHROMA_420) ||
- (chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
+ (chroma_sample == MDSS_MDP_CHROMA_H1V2) ||
+ pipe->scale.enable_pxl_ext) {
pr_debug("scale y - src_h=%d dst_h=%d\n", src_h, pipe->dst.h);
if ((src_h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
@@ -699,7 +703,8 @@
}
scale_config |= MDSS_MDP_SCALEY_EN;
- phasey_step = pipe->phase_step_y;
+ phasey_step = pipe->scale.phase_step_y[0];
+ init_phasey = pipe->scale.init_phase_y[0];
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
u32 chroma_shift = 0;
@@ -708,11 +713,11 @@
(chroma_sample == MDSS_MDP_CHROMA_H1V2)))
chroma_shift = 1; /* 2x upsample chroma */
- if (src_h <= pipe->dst.h) {
+ if (src_h <= pipe->dst.h)
scale_config |= /* G/Y, A */
(filter_mode << 10) |
(MDSS_MDP_SCALE_FILTER_BIL << 18);
- } else
+ else
scale_config |= /* G/Y, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
(MDSS_MDP_SCALE_FILTER_PCMN << 18);
@@ -724,6 +729,8 @@
scale_config |= /* CrCb */
(MDSS_MDP_SCALE_FILTER_PCMN << 14);
+ writel_relaxed(init_phasey, pipe->base +
+ MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
writel_relaxed(phasey_step >> chroma_shift, pipe->base +
MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
} else {
@@ -741,7 +748,8 @@
if ((src_w != pipe->dst.w) ||
(pipe->pp_res.pp_sts.sharp_sts & PP_STS_ENABLE) ||
(chroma_sample == MDSS_MDP_CHROMA_420) ||
- (chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
+ (chroma_sample == MDSS_MDP_CHROMA_H2V1) ||
+ pipe->scale.enable_pxl_ext) {
pr_debug("scale x - src_w=%d dst_w=%d\n", src_w, pipe->dst.w);
if ((src_w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
@@ -751,7 +759,8 @@
}
scale_config |= MDSS_MDP_SCALEX_EN;
- phasex_step = pipe->phase_step_x;
+ init_phasex = pipe->scale.init_phase_x[0];
+ phasex_step = pipe->scale.phase_step_x[0];
if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
u32 chroma_shift = 0;
@@ -761,11 +770,11 @@
(chroma_sample == MDSS_MDP_CHROMA_H2V1)))
chroma_shift = 1; /* 2x upsample chroma */
- if (src_w <= pipe->dst.w) {
+ if (src_w <= pipe->dst.w)
scale_config |= /* G/Y, A */
(filter_mode << 8) |
(MDSS_MDP_SCALE_FILTER_BIL << 16);
- } else
+ else
scale_config |= /* G/Y, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
(MDSS_MDP_SCALE_FILTER_PCMN << 16);
@@ -777,6 +786,8 @@
scale_config |= /* CrCb */
(MDSS_MDP_SCALE_FILTER_PCMN << 12);
+ writel_relaxed(init_phasex, pipe->base +
+ MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
writel_relaxed(phasex_step >> chroma_shift, pipe->base +
MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
} else {
@@ -791,12 +802,44 @@
}
}
+ if (pipe->scale.enable_pxl_ext &&
+ pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+
+ /*program x,y initial phase and phase step*/
+ writel_relaxed(pipe->scale.init_phase_x[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX);
+ writel_relaxed(pipe->scale.phase_step_x[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX);
+ writel_relaxed(pipe->scale.init_phase_x[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX);
+ writel_relaxed(pipe->scale.phase_step_x[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX);
+
+ writel_relaxed(pipe->scale.init_phase_y[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY);
+ writel_relaxed(pipe->scale.phase_step_y[0],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY);
+ writel_relaxed(pipe->scale.init_phase_y[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY);
+ writel_relaxed(pipe->scale.phase_step_y[1],
+ pipe->base + MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY);
+
+ /*program pixel extn values for the SSPP*/
+ mdss_mdp_pipe_program_pixel_extn(pipe);
+ } else {
+ writel_relaxed(phasex_step, pipe->base +
+ MDSS_MDP_REG_SCALE_PHASE_STEP_X);
+ writel_relaxed(phasey_step, pipe->base +
+ MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
+ writel_relaxed(init_phasex, pipe->base +
+ MDSS_MDP_REG_SCALE_INIT_PHASE_X);
+ writel_relaxed(init_phasey, pipe->base +
+ MDSS_MDP_REG_SCALE_INIT_PHASE_Y);
+ }
+
writel_relaxed(scale_config, pipe->base +
MDSS_MDP_REG_SCALE_CONFIG);
- writel_relaxed(phasex_step, pipe->base +
- MDSS_MDP_REG_SCALE_PHASE_STEP_X);
- writel_relaxed(phasey_step, pipe->base +
- MDSS_MDP_REG_SCALE_PHASE_STEP_Y);
+
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 1d172f3..057914b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -137,7 +137,6 @@
{
int ret;
struct mdss_mdp_writeback_arg wb_args = {
- .callback_fnc = NULL,
.data = dst_data,
.priv_data = rot,
};
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 1170d1e..b680823 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -592,7 +592,7 @@
return -EINVAL;
unit = 1 << PHASE_STEP_SHIFT;
- *out_phase = mult_frac(src, unit, dst);
+ *out_phase = mult_frac(unit, src, dst);
/* check if overflow is possible */
if (src > dst) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index c0e49c8..5789341 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -164,6 +164,16 @@
return -EINVAL;
}
+ if (!ctl || !ctl->mdata) {
+ pr_err("%s : ctl is NULL", __func__);
+ return -EINVAL;
+ }
+
+ if (!wb) {
+ pr_err("unable to start, writeback is not initialized\n");
+ return -ENODEV;
+ }
+
ctl->is_secure = enable;
wb->is_secure = enable;
@@ -508,23 +518,13 @@
return ret;
}
-static void mdss_mdp_wb_callback(void *arg)
-{
- if (arg)
- complete((struct completion *) arg);
-}
-
int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_wb *wb = mfd_to_wb(mfd);
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
struct mdss_mdp_wb_data *node = NULL;
int ret = 0;
- DECLARE_COMPLETION_ONSTACK(comp);
- struct mdss_mdp_writeback_arg wb_args = {
- .callback_fnc = mdss_mdp_wb_callback,
- .priv_data = &comp,
- };
+ struct mdss_mdp_writeback_arg wb_args;
if (!ctl->power_on)
return 0;
@@ -566,12 +566,6 @@
goto kickoff_fail;
}
- ret = wait_for_completion_timeout(&comp, KOFF_TIMEOUT);
- if (ret == 0)
- WARN(1, "wfd kick off time out=%d ctl=%d", ret, ctl->num);
- else
- ret = 0;
-
if (wb && node) {
mutex_lock(&wb->lock);
list_add_tail(&node->active_entry, &wb->busy_queue);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 75fc095..b859598 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -299,6 +299,8 @@
struct ion_handle *splash_ihdl;
u32 panel_power_on;
+ uint32_t panel_dead;
+
struct lcd_panel_info lcdc;
struct fbc_panel_info fbc;
struct mipi_panel_info mipi;
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index a759e86..ab01566 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -1463,7 +1463,7 @@
static struct regulator *reg_8941_l02;
static struct regulator *reg_8941_smps3a;
static struct regulator *reg_8941_vdda;
- int rc;
+ int rc = -EINVAL;
pr_debug("%s\n", __func__);
if (!reg_8941_l24) {
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 0739ece..d525e84 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -726,25 +726,27 @@
};
/* LOG CODES */
+static const uint32_t log_code_last_tbl[] = {
+ 0x0, /* EQUIP ID 0 */
+ 0x182F, /* EQUIP ID 1 */
+ 0x0, /* EQUIP ID 2 */
+ 0x0, /* EQUIP ID 3 */
+ 0x4910, /* EQUIP ID 4 */
+ 0x5420, /* EQUIP ID 5 */
+ 0x0, /* EQUIP ID 6 */
+ 0x74FF, /* EQUIP ID 7 */
+ 0x0, /* EQUIP ID 8 */
+ 0x0, /* EQUIP ID 9 */
+ 0xA38A, /* EQUIP ID 10 */
+ 0xB201, /* EQUIP ID 11 */
+ 0x0, /* EQUIP ID 12 */
+ 0x0, /* EQUIP ID 13 */
+ 0x0, /* EQUIP ID 14 */
+ 0x0, /* EQUIP ID 15 */
+};
-#define LOG_0 0x0
-#define LOG_1 0x1808
-#define LOG_2 0x0
-#define LOG_3 0x0
-#define LOG_4 0x4910
-#define LOG_5 0x5420
-#define LOG_6 0x0
-#define LOG_7 0x74FF
-#define LOG_8 0x0
-#define LOG_9 0x0
-#define LOG_10 0xA38A
-#define LOG_11 0xB201
-#define LOG_12 0x0
-#define LOG_13 0x0
-#define LOG_14 0x0
-#define LOG_15 0x0
-
-#define LOG_GET_ITEM_NUM(xx_code) (xx_code & 0x0FFF)
-#define LOG_GET_EQUIP_ID(xx_code) ((xx_code & 0xF000) >> 12)
+#define LOG_GET_ITEM_NUM(xx_code) (xx_code & 0x0FFF)
+#define LOG_GET_EQUIP_ID(xx_code) ((xx_code & 0xF000) >> 12)
+#define LOG_ITEMS_TO_SIZE(num_items) ((num_items+7)/8)
#endif
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a5fa304..2218ac4 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -806,6 +806,17 @@
return (void *)((unsigned long)page->mapping & ~PAGE_MAPPING_FLAGS);
}
+extern struct address_space *__page_file_mapping(struct page *);
+
+static inline
+struct address_space *page_file_mapping(struct page *page)
+{
+ if (unlikely(PageSwapCache(page)))
+ return __page_file_mapping(page);
+
+ return page->mapping;
+}
+
static inline int PageAnon(struct page *page)
{
return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0;
@@ -822,6 +833,20 @@
return page->index;
}
+extern pgoff_t __page_file_index(struct page *page);
+
+/*
+ * Return the file index of the page. Regular pagecache pages use ->index
+ * whereas swapcache pages use swp_offset(->private)
+ */
+static inline pgoff_t page_file_index(struct page *page)
+{
+ if (unlikely(PageSwapCache(page)))
+ return __page_file_index(page);
+
+ return page->index;
+}
+
/*
* Return true if this page is mapped into pagetables.
*/
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index 227fd3e..9a584c0 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -2,6 +2,7 @@
#define LINUX_MM_INLINE_H
#include <linux/huge_mm.h>
+#include <linux/swap.h>
/**
* page_is_file_cache - should the page be on a file LRU or anon LRU?
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d0ad3e4..1bcfd28 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -219,6 +219,7 @@
MMC_BLK_NEW_REQUEST,
MMC_BLK_URGENT,
MMC_BLK_URGENT_DONE,
+ MMC_BLK_NO_REQ_TO_STOP,
};
struct mmc_wr_pack_stats {
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 7539e03..381fff5 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -375,7 +375,6 @@
* free areas of different sizes
*/
spinlock_t lock;
- int all_unreclaimable; /* All pages pinned */
#if defined CONFIG_COMPACTION || defined CONFIG_CMA
/* Set to true when the PG_migrate_skip bits should be cleared */
bool compact_blockskip_flush;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index de31795..3425386 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -156,6 +156,7 @@
#define MDSS_MDP_ROT_ONLY 0x80
#define MDSS_MDP_RIGHT_MIXER 0x100
+#define MDSS_MDP_DUAL_PIPE 0x200
/* mdp_blit_req flag values */
#define MDP_ROT_NOP 0
@@ -451,6 +452,33 @@
BLEND_OP_MAX,
};
+#define MAX_PLANES 4
+struct mdp_scale_data {
+ uint8_t enable_pxl_ext;
+
+ int init_phase_x[MAX_PLANES];
+ int phase_step_x[MAX_PLANES];
+ int init_phase_y[MAX_PLANES];
+ int phase_step_y[MAX_PLANES];
+
+ int num_ext_pxls_left[MAX_PLANES];
+ int num_ext_pxls_right[MAX_PLANES];
+ int num_ext_pxls_top[MAX_PLANES];
+ int num_ext_pxls_btm[MAX_PLANES];
+
+ int left_ftch[MAX_PLANES];
+ int left_rpt[MAX_PLANES];
+ int right_ftch[MAX_PLANES];
+ int right_rpt[MAX_PLANES];
+
+ int top_rpt[MAX_PLANES];
+ int btm_rpt[MAX_PLANES];
+ int top_ftch[MAX_PLANES];
+ int btm_ftch[MAX_PLANES];
+
+ uint32_t roi_w[MAX_PLANES];
+};
+
struct mdp_overlay {
struct msmfb_img src;
struct mdp_rect src_rect;
@@ -466,6 +494,7 @@
uint8_t horz_deci;
uint8_t vert_deci;
struct mdp_overlay_pp_params overlay_pp_cfg;
+ struct mdp_scale_data scale;
};
struct msmfb_overlay_3d {
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 0844dc3..696ca39 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -295,6 +295,11 @@
return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
}
+static inline loff_t page_file_offset(struct page *page)
+{
+ return ((loff_t)page_file_index(page)) << PAGE_CACHE_SHIFT;
+}
+
extern pgoff_t linear_hugepage_index(struct vm_area_struct *vma,
unsigned long address);
diff --git a/include/linux/swap.h b/include/linux/swap.h
index d5bd6ee..c1fcf34 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -197,6 +197,18 @@
struct block_device *bdev; /* swap device or bdev of swap file */
struct file *swap_file; /* seldom referenced */
unsigned int old_block_size; /* seldom referenced */
+ spinlock_t lock; /*
+ * protect map scan related fields like
+ * swap_map, lowest_bit, highest_bit,
+ * inuse_pages, cluster_next,
+ * cluster_nr, lowest_alloc and
+ * highest_alloc. other fields are only
+ * changed at swapon/swapoff, so are
+ * protected by swap_lock. changing
+ * flags need hold this lock and
+ * swap_lock. If both locks need hold,
+ * hold swap_lock first.
+ */
};
struct swap_list_t {
@@ -204,9 +216,6 @@
int next; /* swapfile to be used next */
};
-/* Swap 50% full? Release swapcache more aggressively.. */
-#define vm_swap_full() (nr_swap_pages*2 < total_swap_pages)
-
/* linux/mm/page_alloc.c */
extern unsigned long totalram_pages;
extern unsigned long totalreserve_pages;
@@ -335,8 +344,20 @@
struct vm_area_struct *vma, unsigned long addr);
/* linux/mm/swapfile.c */
-extern long nr_swap_pages;
+extern atomic_long_t nr_swap_pages;
extern long total_swap_pages;
+
+/* Swap 50% full? Release swapcache more aggressively.. */
+static inline bool vm_swap_full(void)
+{
+ return atomic_long_read(&nr_swap_pages) * 2 < total_swap_pages;
+}
+
+static inline long get_nr_swap_pages(void)
+{
+ return atomic_long_read(&nr_swap_pages);
+}
+
extern void si_swapinfo(struct sysinfo *);
extern swp_entry_t get_swap_page(void);
extern swp_entry_t get_swap_page_of_type(int);
@@ -351,6 +372,8 @@
extern unsigned int count_swap_pages(int, int);
extern sector_t map_swap_page(struct page *, struct block_device **);
extern sector_t swapdev_block(int, pgoff_t);
+extern int page_swapcount(struct page *);
+extern struct swap_info_struct *page_swap_info(struct page *);
extern int reuse_swap_page(struct page *);
extern int try_to_free_swap(struct page *);
struct backing_dev_info;
@@ -368,9 +391,10 @@
#else /* CONFIG_SWAP */
-#define nr_swap_pages 0L
+#define get_nr_swap_pages() 0L
#define total_swap_pages 0L
#define total_swapcache_pages 0UL
+#define vm_swap_full() 0
#define si_swapinfo(val) \
do { (val)->freeswap = (val)->totalswap = 0; } while (0)
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index e17e978..8d5e51b 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -19,12 +19,16 @@
#include <linux/usb/composite.h>
+#define MAX_STREAMING_FUNCS 3
+#define FUNC_NAME_LEN 10
struct android_usb_platform_data {
int (*update_pid_and_serial_num)(uint32_t, const char *);
u32 swfi_latency;
u8 usb_core_id;
bool cdrom;
bool internal_ums;
+ char streaming_func[MAX_STREAMING_FUNCS][FUNC_NAME_LEN];
+ int streaming_func_count;
};
#ifndef CONFIG_TARGET_CORE
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index fea832e..3844f41 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -508,6 +508,7 @@
* @dev: Driver model state for this abstract device.
* @usb_core_id: Identifies the usb core controlled by this usb_gadget.
* Used in case of more then one core operates concurrently.
+ * @streaming_enabled: Enable streaming mode with usb core.
*
* Gadgets have a mostly-portable "gadget driver" implementing device
* functions, handling all usb configurations and interfaces. Gadget
@@ -546,6 +547,7 @@
struct device dev;
u8 usb_core_id;
bool l1_supported;
+ bool streaming_enabled;
};
static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 07f9b90..9eb9cd8 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -229,7 +229,9 @@
* between 1 to 7.
* @l1_supported: enable link power management support.
* @dpdm_pulldown_added: Indicates whether pull down resistors are
- connected on data lines or not.
+ * connected on data lines or not.
+ * @enable_ahb2ahb_bypass: Indicates whether enable AHB2AHB BYPASS
+ * mode with controller in device mode.
*/
struct msm_otg_platform_data {
int *phy_init_seq;
@@ -258,6 +260,7 @@
int log2_itc;
bool l1_supported;
bool dpdm_pulldown_added;
+ bool enable_ahb2ahb_bypass;
};
/* phy related flags */
@@ -462,6 +465,7 @@
int log2_itc;
void *prv_data;
bool l1_supported;
+ bool enable_ahb2ahb_bypass;
};
/**
diff --git a/include/linux/usb/msm_hsusb_hw.h b/include/linux/usb/msm_hsusb_hw.h
index 58ab4eb..2a5ebd4 100644
--- a/include/linux/usb/msm_hsusb_hw.h
+++ b/include/linux/usb/msm_hsusb_hw.h
@@ -49,6 +49,10 @@
#define L1_CONFIG_PHY_LPM BIT(10)
#define L1_CONFIG_PLL BIT(11)
+#define AHB2AHB_BYPASS BIT(31)
+#define AHB2AHB_BYPASS_BIT_MASK BIT(31)
+#define AHB2AHB_BYPASS_CLEAR (0 << 31)
+
#define PORTSC_PHCD (1 << 23) /* phy suspend mode */
#define PORTSC_PTS_MASK (3 << 30)
#define PORTSC_PTS_ULPI (3 << 30)
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 1d10474..2d59889 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -140,7 +140,6 @@
}
extern unsigned long global_reclaimable_pages(void);
-extern unsigned long zone_reclaimable_pages(struct zone *zone);
#ifdef CONFIG_NUMA
/*
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index bbda72e..b62a759 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -3676,6 +3676,7 @@
} __packed;
#define ASM_SESSION_CMD_PAUSE 0x00010BD3
+#define ASM_SESSION_CMD_SUSPEND 0x00010DEC
#define ASM_SESSION_CMD_GET_SESSIONTIME_V3 0x00010D9D
#define ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS 0x00010BD5
@@ -4698,6 +4699,25 @@
} __packed;
+
+/*
+ Indicates the number of samples per channel to be removed from the
+ beginning of the stream.
+*/
+#define ASM_DATA_CMD_REMOVE_INITIAL_SILENCE 0x00010D67
+/*
+ Indicates the number of samples per channel to be removed from
+ the end of the stream.
+*/
+#define ASM_DATA_CMD_REMOVE_TRAILING_SILENCE 0x00010D68
+struct asm_data_cmd_remove_silence {
+ struct apr_hdr hdr;
+ u32 num_samples_to_remove;
+ /**< Number of samples per channel to be removed.
+
+ @values 0 to (2@sscr{32}-1) */
+} __packed;
+
#define ASM_STREAM_CMD_OPEN_READ_COMPRESSED 0x00010D95
struct asm_stream_cmd_open_read_compressed {
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 3cc476f..eb3b41a 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -54,6 +54,7 @@
#define CMD_EOS 0x0003
#define CMD_CLOSE 0x0004
#define CMD_OUT_FLUSH 0x0005
+#define CMD_SUSPEND 0x0006
/* bit 0:1 represents priority of stream */
#define STREAM_PRIORITY_NORMAL 0x0000
@@ -80,6 +81,9 @@
#define SESSION_MAX 0x08
#define ASM_CONTROL_SESSION 0x0F
+#define ASM_SHIFT_GAPLESS_MODE_FLAG 31
+#define ASM_SHIFT_LAST_BUFFER_FLAG 30
+
/* payload structure bytes */
#define READDONE_IDX_STATUS 0
#define READDONE_IDX_BUFADD_LSW 1
@@ -130,6 +134,7 @@
uint32_t msw_ts;
uint32_t flags;
uint32_t metadata_len;
+ uint32_t last_buffer;
};
struct audio_aio_read_param {
@@ -162,12 +167,14 @@
uint64_t time_stamp;
struct apr_svc *apr;
struct apr_svc *mmap_apr;
+ struct apr_svc *apr2;
struct mutex cmd_lock;
/* idx:1 out port, 0: in port*/
struct audio_port_data port[2];
wait_queue_head_t cmd_wait;
wait_queue_head_t time_wait;
bool perf_mode;
+ int stream_id;
/* audio cache operations fptr*/
int (*fptr_cache_ops)(struct audio_buffer *abuff, int cache_op);
};
@@ -203,6 +210,10 @@
int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample);
+int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode);
+
int q6asm_open_read_write(struct audio_client *ac,
uint32_t rd_format,
uint32_t wr_format);
@@ -239,12 +250,22 @@
int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
uint32_t msw_ts, uint32_t lsw_ts);
+int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id);
+
int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable);
+int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable);
+
int q6asm_cmd(struct audio_client *ac, int cmd);
+int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id);
+
int q6asm_cmd_nowait(struct audio_client *ac, int cmd);
+int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
+ uint32_t stream_id);
+
void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac,
uint32_t *size, uint32_t *idx);
@@ -316,6 +337,9 @@
int q6asm_media_format_block_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
+int q6asm_stream_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg, int stream_id);
+
int q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg);
@@ -363,4 +387,8 @@
*/
int q6asm_media_format_block(struct audio_client *ac, uint32_t format);
+/* Send the meta data to remove initial and trailing silence */
+int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
+ uint32_t trailing_samples);
+
#endif /* __Q6_ASM_H__ */
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index fed2e0a..4a606af 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -442,6 +442,11 @@
snd_soc_dapm_siggen, /* signal generator */
};
+enum snd_soc_dapm_subclass {
+ SND_SOC_DAPM_CLASS_INIT = 0,
+ SND_SOC_DAPM_CLASS_PCM = 1,
+};
+
/*
* DAPM audio route definition.
*
diff --git a/mm/internal.h b/mm/internal.h
index 3439ef4..f5369cc 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -90,6 +90,8 @@
*/
extern int isolate_lru_page(struct page *page);
extern void putback_lru_page(struct page *page);
+extern unsigned long zone_reclaimable_pages(struct zone *zone);
+extern bool zone_reclaimable(struct zone *zone);
/*
* in mm/page_alloc.c
diff --git a/mm/mmap.c b/mm/mmap.c
index 848ef52..9932edb 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -133,7 +133,7 @@
*/
free -= global_page_state(NR_SHMEM);
- free += nr_swap_pages;
+ free += get_nr_swap_pages();
/*
* Any slabs which are created with the
diff --git a/mm/nommu.c b/mm/nommu.c
index bb8f4f0..6bb7042 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1928,7 +1928,7 @@
*/
free -= global_page_state(NR_SHMEM);
- free += nr_swap_pages;
+ free += get_nr_swap_pages();
/*
* Any slabs which are created with the
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 26adea8..a5e8dc2 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -34,8 +34,11 @@
#include <linux/syscalls.h>
#include <linux/buffer_head.h> /* __set_page_dirty_buffers */
#include <linux/pagevec.h>
+#include <linux/mm_inline.h>
#include <trace/events/writeback.h>
+#include "internal.h"
+
/*
* Sleep at most 200ms at a time in balance_dirty_pages().
*/
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 46ccd2f..a1e4f77 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -57,6 +57,7 @@
#include <linux/ftrace_event.h>
#include <linux/memcontrol.h>
#include <linux/prefetch.h>
+#include <linux/mm_inline.h>
#include <linux/migrate.h>
#include <linux/page-debug-flags.h>
@@ -647,7 +648,6 @@
int mt = 0;
spin_lock(&zone->lock);
- zone->all_unreclaimable = 0;
zone->pages_scanned = 0;
while (to_free) {
@@ -693,7 +693,6 @@
int migratetype)
{
spin_lock(&zone->lock);
- zone->all_unreclaimable = 0;
zone->pages_scanned = 0;
__free_one_page(page, zone, order, migratetype);
@@ -2997,7 +2996,7 @@
K(zone_page_state(zone, NR_FREE_CMA_PAGES)),
K(zone_page_state(zone, NR_WRITEBACK_TEMP)),
zone->pages_scanned,
- (zone->all_unreclaimable ? "yes" : "no")
+ (!zone_reclaimable(zone) ? "yes" : "no")
);
printk("lowmem_reserve[]:");
for (i = 0; i < MAX_NR_ZONES; i++)
diff --git a/mm/page_io.c b/mm/page_io.c
index dc76b4d..e60e43f 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -1,3 +1,4 @@
+
/*
* linux/mm/page_io.c
*
@@ -18,6 +19,7 @@
#include <linux/bio.h>
#include <linux/swapops.h>
#include <linux/writeback.h>
+#include <linux/blkdev.h>
#include <asm/pgtable.h>
static struct bio *get_swap_bio(gfp_t gfp_flags,
@@ -78,9 +80,54 @@
imajor(bio->bi_bdev->bd_inode),
iminor(bio->bi_bdev->bd_inode),
(unsigned long long)bio->bi_sector);
- } else {
- SetPageUptodate(page);
+ goto out;
}
+
+ SetPageUptodate(page);
+
+ /*
+ * There is no guarantee that the page is in swap cache - the software
+ * suspend code (at least) uses end_swap_bio_read() against a non-
+ * swapcache page. So we must check PG_swapcache before proceeding with
+ * this optimization.
+ */
+ if (likely(PageSwapCache(page))) {
+ struct swap_info_struct *sis;
+
+ sis = page_swap_info(page);
+ if (sis->flags & SWP_BLKDEV) {
+ /*
+ * The swap subsystem performs lazy swap slot freeing,
+ * expecting that the page will be swapped out again.
+ * So we can avoid an unnecessary write if the page
+ * isn't redirtied.
+ * This is good for real swap storage because we can
+ * reduce unnecessary I/O and enhance wear-leveling
+ * if an SSD is used as the as swap device.
+ * But if in-memory swap device (eg zram) is used,
+ * this causes a duplicated copy between uncompressed
+ * data in VM-owned memory and compressed data in
+ * zram-owned memory. So let's free zram-owned memory
+ * and make the VM-owned decompressed page *dirty*,
+ * so the page should be swapped out somewhere again if
+ * we again wish to reclaim it.
+ */
+ struct gendisk *disk = sis->bdev->bd_disk;
+ if (disk->fops->swap_slot_free_notify) {
+ swp_entry_t entry;
+ unsigned long offset;
+
+ entry.val = page_private(page);
+ offset = swp_offset(entry);
+
+ SetPageDirty(page);
+ disk->fops->swap_slot_free_notify(sis->bdev,
+ offset);
+ }
+ }
+ }
+
+out:
unlock_page(page);
bio_put(bio);
}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 4c5ff7f..eb6a79c 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -58,7 +58,8 @@
printk("Swap cache stats: add %lu, delete %lu, find %lu/%lu\n",
swap_cache_info.add_total, swap_cache_info.del_total,
swap_cache_info.find_success, swap_cache_info.find_total);
- printk("Free swap = %ldkB\n", nr_swap_pages << (PAGE_SHIFT - 10));
+ printk("Free swap = %ldkB\n",
+ get_nr_swap_pages() << (PAGE_SHIFT - 10));
printk("Total swap = %lukB\n", total_swap_pages << (PAGE_SHIFT - 10));
}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index fafc26d..9ae4c8d 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -31,6 +31,7 @@
#include <linux/memcontrol.h>
#include <linux/poll.h>
#include <linux/oom.h>
+#include <linux/export.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
@@ -44,9 +45,11 @@
static DEFINE_SPINLOCK(swap_lock);
static unsigned int nr_swapfiles;
-long nr_swap_pages;
+atomic_long_t nr_swap_pages;
+/* protected with swap_lock. reading in vm_swap_full() doesn't need lock */
long total_swap_pages;
static int least_priority;
+static atomic_t highest_priority_index = ATOMIC_INIT(-1);
static const char Bad_file[] = "Bad swap file entry ";
static const char Unused_file[] = "Unused swap file entry ";
@@ -220,7 +223,7 @@
si->lowest_alloc = si->max;
si->highest_alloc = 0;
}
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
/*
* If seek is expensive, start searching for new cluster from
@@ -239,7 +242,7 @@
if (si->swap_map[offset])
last_in_cluster = offset + SWAPFILE_CLUSTER;
else if (offset == last_in_cluster) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
offset -= SWAPFILE_CLUSTER - 1;
si->cluster_next = offset;
si->cluster_nr = SWAPFILE_CLUSTER - 1;
@@ -260,7 +263,7 @@
if (si->swap_map[offset])
last_in_cluster = offset + SWAPFILE_CLUSTER;
else if (offset == last_in_cluster) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
offset -= SWAPFILE_CLUSTER - 1;
si->cluster_next = offset;
si->cluster_nr = SWAPFILE_CLUSTER - 1;
@@ -274,7 +277,7 @@
}
offset = scan_base;
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
si->cluster_nr = SWAPFILE_CLUSTER - 1;
si->lowest_alloc = 0;
}
@@ -290,9 +293,9 @@
/* reuse swap entry of cache-only swap if not busy. */
if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
int swap_was_freed;
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
swap_was_freed = __try_to_reclaim_swap(si, offset);
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
/* entry was freed successfully, try to use this again */
if (swap_was_freed)
goto checks;
@@ -332,13 +335,13 @@
si->lowest_alloc <= last_in_cluster)
last_in_cluster = si->lowest_alloc - 1;
si->flags |= SWP_DISCARDING;
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
if (offset < last_in_cluster)
discard_swap_cluster(si, offset,
last_in_cluster - offset + 1);
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
si->lowest_alloc = 0;
si->flags &= ~SWP_DISCARDING;
@@ -352,10 +355,10 @@
* could defer that delay until swap_writepage,
* but it's easier to keep this self-contained.
*/
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
wait_on_bit(&si->flags, ilog2(SWP_DISCARDING),
wait_for_discard, TASK_UNINTERRUPTIBLE);
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
} else {
/*
* Note pages allocated by racing tasks while
@@ -371,14 +374,14 @@
return offset;
scan:
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
while (++offset <= si->highest_bit) {
if (!si->swap_map[offset]) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
goto checks;
}
if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
goto checks;
}
if (unlikely(--latency_ration < 0)) {
@@ -389,11 +392,11 @@
offset = si->lowest_bit;
while (++offset < scan_base) {
if (!si->swap_map[offset]) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
goto checks;
}
if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
goto checks;
}
if (unlikely(--latency_ration < 0)) {
@@ -401,7 +404,7 @@
latency_ration = LATENCY_LIMIT;
}
}
- spin_lock(&swap_lock);
+ spin_lock(&si->lock);
no_page:
si->flags -= SWP_SCANNING;
@@ -414,13 +417,34 @@
pgoff_t offset;
int type, next;
int wrapped = 0;
+ int hp_index;
spin_lock(&swap_lock);
- if (nr_swap_pages <= 0)
+ if (atomic_long_read(&nr_swap_pages) <= 0)
goto noswap;
- nr_swap_pages--;
+ atomic_long_dec(&nr_swap_pages);
for (type = swap_list.next; type >= 0 && wrapped < 2; type = next) {
+ hp_index = atomic_xchg(&highest_priority_index, -1);
+ /*
+ * highest_priority_index records current highest priority swap
+ * type which just frees swap entries. If its priority is
+ * higher than that of swap_list.next swap type, we use it. It
+ * isn't protected by swap_lock, so it can be an invalid value
+ * if the corresponding swap type is swapoff. We double check
+ * the flags here. It's even possible the swap type is swapoff
+ * and swapon again and its priority is changed. In such rare
+ * case, low prority swap type might be used, but eventually
+ * high priority swap will be used after several rounds of
+ * swap.
+ */
+ if (hp_index != -1 && hp_index != type &&
+ swap_info[type]->prio < swap_info[hp_index]->prio &&
+ (swap_info[hp_index]->flags & SWP_WRITEOK)) {
+ type = hp_index;
+ swap_list.next = type;
+ }
+
si = swap_info[type];
next = si->next;
if (next < 0 ||
@@ -429,22 +453,29 @@
wrapped++;
}
- if (!si->highest_bit)
+ spin_lock(&si->lock);
+ if (!si->highest_bit) {
+ spin_unlock(&si->lock);
continue;
- if (!(si->flags & SWP_WRITEOK))
+ }
+ if (!(si->flags & SWP_WRITEOK)) {
+ spin_unlock(&si->lock);
continue;
+ }
swap_list.next = next;
+
+ spin_unlock(&swap_lock);
/* This is called for allocating swap entry for cache */
offset = scan_swap_map(si, SWAP_HAS_CACHE);
- if (offset) {
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
+ if (offset)
return swp_entry(type, offset);
- }
+ spin_lock(&swap_lock);
next = swap_list.next;
}
- nr_swap_pages++;
+ atomic_long_inc(&nr_swap_pages);
noswap:
spin_unlock(&swap_lock);
return (swp_entry_t) {0};
@@ -456,19 +487,19 @@
struct swap_info_struct *si;
pgoff_t offset;
- spin_lock(&swap_lock);
si = swap_info[type];
+ spin_lock(&si->lock);
if (si && (si->flags & SWP_WRITEOK)) {
- nr_swap_pages--;
+ atomic_long_dec(&nr_swap_pages);
/* This is called for allocating swap entry, not cache */
offset = scan_swap_map(si, 1);
if (offset) {
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
return swp_entry(type, offset);
}
- nr_swap_pages++;
+ atomic_long_inc(&nr_swap_pages);
}
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
return (swp_entry_t) {0};
}
@@ -490,7 +521,7 @@
goto bad_offset;
if (!p->swap_map[offset])
goto bad_free;
- spin_lock(&swap_lock);
+ spin_lock(&p->lock);
return p;
bad_free:
@@ -508,6 +539,27 @@
return NULL;
}
+/*
+ * This swap type frees swap entry, check if it is the highest priority swap
+ * type which just frees swap entry. get_swap_page() uses
+ * highest_priority_index to search highest priority swap type. The
+ * swap_info_struct.lock can't protect us if there are multiple swap types
+ * active, so we use atomic_cmpxchg.
+ */
+static void set_highest_priority_index(int type)
+{
+ int old_hp_index, new_hp_index;
+
+ do {
+ old_hp_index = atomic_read(&highest_priority_index);
+ if (old_hp_index != -1 &&
+ swap_info[old_hp_index]->prio >= swap_info[type]->prio)
+ break;
+ new_hp_index = type;
+ } while (atomic_cmpxchg(&highest_priority_index,
+ old_hp_index, new_hp_index) != old_hp_index);
+}
+
static unsigned char swap_entry_free(struct swap_info_struct *p,
swp_entry_t entry, unsigned char usage)
{
@@ -551,10 +603,8 @@
p->lowest_bit = offset;
if (offset > p->highest_bit)
p->highest_bit = offset;
- if (swap_list.next >= 0 &&
- p->prio > swap_info[swap_list.next]->prio)
- swap_list.next = p->type;
- nr_swap_pages++;
+ set_highest_priority_index(p->type);
+ atomic_long_inc(&nr_swap_pages);
p->inuse_pages--;
if ((p->flags & SWP_BLKDEV) &&
disk->fops->swap_slot_free_notify)
@@ -575,7 +625,7 @@
p = swap_info_get(entry);
if (p) {
swap_entry_free(p, entry, 1);
- spin_unlock(&swap_lock);
+ spin_unlock(&p->lock);
}
}
@@ -592,7 +642,7 @@
count = swap_entry_free(p, entry, SWAP_HAS_CACHE);
if (page)
mem_cgroup_uncharge_swapcache(page, entry, count != 0);
- spin_unlock(&swap_lock);
+ spin_unlock(&p->lock);
}
}
@@ -601,7 +651,7 @@
* This does not give an exact answer when swap count is continued,
* but does include the high COUNT_CONTINUED flag to allow for that.
*/
-static inline int page_swapcount(struct page *page)
+int page_swapcount(struct page *page)
{
int count = 0;
struct swap_info_struct *p;
@@ -611,7 +661,7 @@
p = swap_info_get(entry);
if (p) {
count = swap_count(p->swap_map[swp_offset(entry)]);
- spin_unlock(&swap_lock);
+ spin_unlock(&p->lock);
}
return count;
}
@@ -699,7 +749,7 @@
page = NULL;
}
}
- spin_unlock(&swap_lock);
+ spin_unlock(&p->lock);
}
if (page) {
/*
@@ -828,11 +878,13 @@
if ((unsigned int)type < nr_swapfiles) {
struct swap_info_struct *sis = swap_info[type];
+ spin_lock(&sis->lock);
if (sis->flags & SWP_WRITEOK) {
n = sis->pages;
if (free)
n -= sis->inuse_pages;
}
+ spin_unlock(&sis->lock);
}
spin_unlock(&swap_lock);
return n;
@@ -1528,7 +1580,7 @@
p->prio = --least_priority;
p->swap_map = swap_map;
p->flags |= SWP_WRITEOK;
- nr_swap_pages += p->pages;
+ atomic_long_add(p->pages, &nr_swap_pages);
total_swap_pages += p->pages;
/* insert swap space into swap_list: */
@@ -1605,14 +1657,16 @@
/* just pick something that's safe... */
swap_list.next = swap_list.head;
}
+ spin_lock(&p->lock);
if (p->prio < 0) {
for (i = p->next; i >= 0; i = swap_info[i]->next)
swap_info[i]->prio = p->prio--;
least_priority++;
}
- nr_swap_pages -= p->pages;
+ atomic_long_sub(p->pages, &nr_swap_pages);
total_swap_pages -= p->pages;
p->flags &= ~SWP_WRITEOK;
+ spin_unlock(&p->lock);
spin_unlock(&swap_lock);
oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX);
@@ -1637,14 +1691,17 @@
mutex_lock(&swapon_mutex);
spin_lock(&swap_lock);
+ spin_lock(&p->lock);
drain_mmlist();
/* wait for anyone still in scan_swap_map */
p->highest_bit = 0; /* cuts scans short */
while (p->flags >= SWP_SCANNING) {
+ spin_unlock(&p->lock);
spin_unlock(&swap_lock);
schedule_timeout_uninterruptible(1);
spin_lock(&swap_lock);
+ spin_lock(&p->lock);
}
swap_file = p->swap_file;
@@ -1653,6 +1710,7 @@
swap_map = p->swap_map;
p->swap_map = NULL;
p->flags = 0;
+ spin_unlock(&p->lock);
spin_unlock(&swap_lock);
mutex_unlock(&swapon_mutex);
vfree(swap_map);
@@ -1856,6 +1914,7 @@
p->flags = SWP_USED;
p->next = -1;
spin_unlock(&swap_lock);
+ spin_lock_init(&p->lock);
return p;
}
@@ -2177,7 +2236,7 @@
if ((si->flags & SWP_USED) && !(si->flags & SWP_WRITEOK))
nr_to_be_unused += si->inuse_pages;
}
- val->freeswap = nr_swap_pages + nr_to_be_unused;
+ val->freeswap = atomic_long_read(&nr_swap_pages) + nr_to_be_unused;
val->totalswap = total_swap_pages + nr_to_be_unused;
spin_unlock(&swap_lock);
}
@@ -2210,7 +2269,7 @@
p = swap_info[type];
offset = swp_offset(entry);
- spin_lock(&swap_lock);
+ spin_lock(&p->lock);
if (unlikely(offset >= p->max))
goto unlock_out;
@@ -2245,7 +2304,7 @@
p->swap_map[offset] = count | has_cache;
unlock_out:
- spin_unlock(&swap_lock);
+ spin_unlock(&p->lock);
out:
return err;
@@ -2292,6 +2351,31 @@
return __swap_duplicate(entry, SWAP_HAS_CACHE);
}
+struct swap_info_struct *page_swap_info(struct page *page)
+{
+ swp_entry_t swap = { .val = page_private(page) };
+ BUG_ON(!PageSwapCache(page));
+ return swap_info[swp_type(swap)];
+}
+
+/*
+ * out-of-line __page_file_ methods to avoid include hell.
+ */
+struct address_space *__page_file_mapping(struct page *page)
+{
+ VM_BUG_ON(!PageSwapCache(page));
+ return page_swap_info(page)->swap_file->f_mapping;
+}
+EXPORT_SYMBOL_GPL(__page_file_mapping);
+
+pgoff_t __page_file_index(struct page *page)
+{
+ swp_entry_t swap = { .val = page_private(page) };
+ VM_BUG_ON(!PageSwapCache(page));
+ return swp_offset(swap);
+}
+EXPORT_SYMBOL_GPL(__page_file_index);
+
/*
* add_swap_count_continuation - called when a swap count is duplicated
* beyond SWAP_MAP_MAX, it allocates a new page and links that to the entry's
@@ -2345,7 +2429,7 @@
}
if (!page) {
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
return -ENOMEM;
}
@@ -2393,7 +2477,7 @@
list_add_tail(&page->lru, &head->lru);
page = NULL; /* now it's attached, don't free it */
out:
- spin_unlock(&swap_lock);
+ spin_unlock(&si->lock);
outer:
if (page)
__free_page(page);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 1438de9..9e95109 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -158,8 +158,28 @@
return &mz->zone->reclaim_stat;
}
+unsigned long zone_reclaimable_pages(struct zone *zone)
+{
+ int nr;
+
+ nr = zone_page_state(zone, NR_ACTIVE_FILE) +
+ zone_page_state(zone, NR_INACTIVE_FILE);
+
+ if (get_nr_swap_pages() > 0)
+ nr += zone_page_state(zone, NR_ACTIVE_ANON) +
+ zone_page_state(zone, NR_INACTIVE_ANON);
+
+ return nr;
+}
+
+bool zone_reclaimable(struct zone *zone)
+{
+ return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
+}
+
static unsigned long zone_nr_lru_pages(struct mem_cgroup_zone *mz,
enum lru_list lru)
+
{
if (!mem_cgroup_disabled())
return mem_cgroup_zone_nr_lru_pages(mz->mem_cgroup,
@@ -1648,13 +1668,13 @@
* latencies, so it's better to scan a minimum amount there as
* well.
*/
- if (current_is_kswapd() && mz->zone->all_unreclaimable)
+ if (current_is_kswapd() && !zone_reclaimable(mz->zone))
force_scan = true;
if (!global_reclaim(sc))
force_scan = true;
/* If we have no swap space, do not bother scanning anon pages. */
- if (!sc->may_swap || (nr_swap_pages <= 0)) {
+ if (!sc->may_swap || (get_nr_swap_pages() <= 0)) {
noswap = 1;
fraction[0] = 0;
fraction[1] = 1;
@@ -1798,7 +1818,7 @@
*/
pages_for_compaction = (2UL << sc->order);
inactive_lru_pages = zone_nr_lru_pages(mz, LRU_INACTIVE_FILE);
- if (nr_swap_pages > 0)
+ if (get_nr_swap_pages() > 0)
inactive_lru_pages += zone_nr_lru_pages(mz, LRU_INACTIVE_ANON);
if (sc->nr_reclaimed < pages_for_compaction &&
inactive_lru_pages > pages_for_compaction)
@@ -1995,8 +2015,8 @@
if (global_reclaim(sc)) {
if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
continue;
- if (zone->all_unreclaimable &&
- sc->priority != DEF_PRIORITY)
+ if (sc->priority != DEF_PRIORITY &&
+ !zone_reclaimable(zone))
continue; /* Let kswapd poll it */
if (COMPACTION_BUILD) {
/*
@@ -2034,11 +2054,6 @@
return aborted_reclaim;
}
-static bool zone_reclaimable(struct zone *zone)
-{
- return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
-}
-
/* All zones in zonelist are unreclaimable? */
static bool all_unreclaimable(struct zonelist *zonelist,
struct scan_control *sc)
@@ -2052,7 +2067,7 @@
continue;
if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
continue;
- if (!zone->all_unreclaimable)
+ if (zone_reclaimable(zone))
return false;
}
@@ -2377,7 +2392,7 @@
* they must be considered balanced here as well if kswapd
* is to sleep
*/
- if (zone->all_unreclaimable) {
+ if (!zone_reclaimable(zone)) {
balanced += zone->present_pages;
continue;
}
@@ -2470,8 +2485,8 @@
if (!populated_zone(zone))
continue;
- if (zone->all_unreclaimable &&
- sc.priority != DEF_PRIORITY)
+ if (sc.priority != DEF_PRIORITY &&
+ !zone_reclaimable(zone))
continue;
/*
@@ -2525,8 +2540,8 @@
if (!populated_zone(zone))
continue;
- if (zone->all_unreclaimable &&
- sc.priority != DEF_PRIORITY)
+ if (sc.priority != DEF_PRIORITY &&
+ !zone_reclaimable(zone))
continue;
sc.nr_scanned = 0;
@@ -2576,8 +2591,6 @@
sc.nr_reclaimed += reclaim_state->reclaimed_slab;
total_scanned += sc.nr_scanned;
- if (nr_slab == 0 && !zone_reclaimable(zone))
- zone->all_unreclaimable = 1;
}
/*
@@ -2589,7 +2602,7 @@
total_scanned > sc.nr_reclaimed + sc.nr_reclaimed / 2)
sc.may_writepage = 1;
- if (zone->all_unreclaimable) {
+ if (!zone_reclaimable(zone)) {
if (end_zone && end_zone == i)
end_zone--;
continue;
@@ -2912,27 +2925,13 @@
nr = global_page_state(NR_ACTIVE_FILE) +
global_page_state(NR_INACTIVE_FILE);
- if (nr_swap_pages > 0)
+ if (get_nr_swap_pages() > 0)
nr += global_page_state(NR_ACTIVE_ANON) +
global_page_state(NR_INACTIVE_ANON);
return nr;
}
-unsigned long zone_reclaimable_pages(struct zone *zone)
-{
- int nr;
-
- nr = zone_page_state(zone, NR_ACTIVE_FILE) +
- zone_page_state(zone, NR_INACTIVE_FILE);
-
- if (nr_swap_pages > 0)
- nr += zone_page_state(zone, NR_ACTIVE_ANON) +
- zone_page_state(zone, NR_INACTIVE_ANON);
-
- return nr;
-}
-
#ifdef CONFIG_HIBERNATION
/*
* Try to free `nr_to_reclaim' of memory, system-wide, and return the number of
@@ -3227,7 +3226,7 @@
zone_page_state(zone, NR_SLAB_RECLAIMABLE) <= zone->min_slab_pages)
return ZONE_RECLAIM_FULL;
- if (zone->all_unreclaimable)
+ if (!zone_reclaimable(zone))
return ZONE_RECLAIM_FULL;
/*
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 959a558..9559032 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -19,6 +19,9 @@
#include <linux/math64.h>
#include <linux/writeback.h>
#include <linux/compaction.h>
+#include <linux/mm_inline.h>
+
+#include "internal.h"
#ifdef CONFIG_VM_EVENT_COUNTERS
DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
@@ -1027,7 +1030,7 @@
"\n all_unreclaimable: %u"
"\n start_pfn: %lu"
"\n inactive_ratio: %u",
- zone->all_unreclaimable,
+ !zone_reclaimable(zone),
zone->zone_start_pfn,
zone->inactive_ratio);
seq_putc(m, '\n');
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 6785fe1..52af21c 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -3007,10 +3007,21 @@
return NULL;
}
+static int msm8x10_wcd_device_down(struct snd_soc_codec *codec)
+{
+ dev_dbg(codec->dev, "%s: device down!\n", __func__);
+
+ snd_soc_card_change_online_state(codec->card, 0);
+ return 0;
+}
static int msm8x10_wcd_device_up(struct snd_soc_codec *codec)
{
- pr_debug("%s: device up!\n", __func__);
+ dev_dbg(codec->dev, "%s: device up!\n", __func__);
+
+ snd_soc_card_change_online_state(codec->card, 1);
+ /* delay is required to make sure sound card state updated */
+ usleep_range(5000, 5100);
mutex_lock(&codec->mutex);
@@ -3029,7 +3040,9 @@
bool timedout;
unsigned long timeout;
- if (value == SUBSYS_AFTER_POWERUP) {
+ if (value == SUBSYS_BEFORE_SHUTDOWN)
+ msm8x10_wcd_device_down(registered_codec);
+ else if (value == SUBSYS_AFTER_POWERUP) {
pr_debug("%s: ADSP is about to power up. bring up codec\n",
__func__);
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index da99254..aaa132e 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -3154,13 +3154,27 @@
struct snd_soc_dai *dai)
{
struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
+ struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
+ u32 active = 0;
+
dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
__func__, substream->name, substream->stream);
+
+ if (dai->id <= NUM_CODEC_DAIS) {
+ if (tapan->dai[dai->id].ch_mask) {
+ active = 1;
+ dev_dbg(dai->codec->dev, "%s(): Codec DAI: chmask[%d] = 0x%lx\n",
+ __func__, dai->id,
+ tapan->dai[dai->id].ch_mask);
+ }
+ }
if ((tapan_core != NULL) &&
(tapan_core->dev != NULL) &&
- (tapan_core->dev->parent != NULL)) {
+ (tapan_core->dev->parent != NULL) &&
+ (active == 0)) {
pm_runtime_mark_last_busy(tapan_core->dev->parent);
pm_runtime_put(tapan_core->dev->parent);
+ dev_dbg(dai->codec->dev, "%s: unvote requested", __func__);
}
}
@@ -3920,6 +3934,13 @@
dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
__func__, ret);
}
+ if ((core != NULL) &&
+ (core->dev != NULL) &&
+ (core->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(core->dev->parent);
+ pm_runtime_put(core->dev->parent);
+ dev_dbg(codec->dev, "%s: unvote requested", __func__);
+ }
break;
}
return ret;
@@ -3967,6 +3988,13 @@
dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
__func__, ret);
}
+ if ((core != NULL) &&
+ (core->dev != NULL) &&
+ (core->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(core->dev->parent);
+ pm_runtime_put(core->dev->parent);
+ dev_dbg(codec->dev, "%s: unvote requested", __func__);
+ }
break;
}
return ret;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 673b634..725c51f 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1235,49 +1235,49 @@
SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
line_gain),
- SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
- -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
+ 0, -84, 40, digital_gain),
- SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
- digital_gain),
- SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
+ SOC_SINGLE_SX_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, 0, -84,
40, digital_gain),
- SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
+ SOC_SINGLE_SX_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, 0, -84,
40, digital_gain),
- SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
+ SOC_SINGLE_SX_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, 0, -84,
40, digital_gain),
- SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
+ SOC_SINGLE_SX_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, 0, -84,
40, digital_gain),
- SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
+ SOC_SINGLE_SX_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, 0, -84,
40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, 0, -84,
+ 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, 0, -84,
+ 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, 0, -84,
+ 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, 0, -84,
+ 40, digital_gain),
+ SOC_SINGLE_SX_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, 0,
+ -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, 0,
+ -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, 0,
+ -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, 0,
+ -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, 0,
+ -84, 40, digital_gain),
SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
@@ -2155,7 +2155,7 @@
goto err;
}
rtn:
- snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
mutex_unlock(&codec->mutex);
return 0;
err:
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 9cad1e5..6dc2ec0 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4974,12 +4974,6 @@
/*Enable spkr VI clocks*/
snd_soc_update_bits(codec,
TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0xC, 0xC);
- /*Enable Voltage Decimator*/
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x1F, 0x12);
- /*Enable Current Decimator*/
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x13);
(void) taiko_codec_enable_slim_chmask(dai, true);
ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
dai->rate, dai->bit_width,
@@ -4991,13 +4985,6 @@
if (ret)
pr_err("%s error in close_slim_sch_tx %d\n",
__func__, ret);
- /*Disable Voltage decimator*/
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x1F, 0x0);
- /*Disable Current decimator*/
- snd_soc_update_bits(codec,
- TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x1F, 0x0);
- /*Disable spkr VI clocks*/
snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL,
0xC, 0x0);
/*Disable V&I sensing*/
@@ -5988,6 +5975,10 @@
/* Set HPH Path to low power mode */
TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x55),
+
+ /* BUCK default */
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
};
static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
@@ -5996,13 +5987,9 @@
* Taiko 2.0 will have appropriate defaults for these registers.
*/
- /* BUCK default */
- TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x50),
-
/* Required defaults for class H operation */
TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xF4),
TAIKO_REG_VAL(TAIKO_A_BIAS_CURR_CTL_2, 0x08),
- TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
/* Choose max non-overlap time for NCP */
@@ -6053,7 +6040,7 @@
TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_6_ADC_IB, 0x44),
TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x8),
- TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
+ TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x51),
TAIKO_REG_VAL(TAIKO_A_NCP_DTEST, 0x10),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xA4),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_OCP_CTL, 0x69),
@@ -6094,6 +6081,7 @@
TAIKO_REG_VAL(TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL, 0x0),
TAIKO_REG_VAL(TAIKO_A_CDC_COMP0_B4_CTL, 0x37),
TAIKO_REG_VAL(TAIKO_A_CDC_COMP0_B5_CTL, 0x7f),
+ TAIKO_REG_VAL(TAIKO_A_CDC_COMP0_B5_CTL, 0x7f),
};
static void taiko_update_reg_defaults(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index 05f2191..b104a6b 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -22,12 +22,11 @@
#define CLSH_COMPUTE_HPH_L 0x02
#define CLSH_COMPUTE_HPH_R 0x03
+#define BUCK_VREF_0P494V 0x3F
#define BUCK_VREF_2V 0xFF
+#define BUCK_VREF_0P494V 0x3F
#define BUCK_VREF_1P8V 0xE6
-#define NCP_FCLK_LEVEL_8 0x08
-#define NCP_FCLK_LEVEL_5 0x05
-
#define BUCK_SETTLE_TIME_US 50
#define NCP_SETTLE_TIME_US 50
@@ -414,12 +413,16 @@
{32164, 22},
};
-static inline void wcd9xxx_enable_clsh_block(
- struct snd_soc_codec *codec,
- bool on)
+static inline void
+wcd9xxx_enable_clsh_block(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d, bool enable)
{
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
- 0x01, on ? 0x01 : 0x00);
+ if ((enable && ++clsh_d->clsh_users == 1) ||
+ (!enable && --clsh_d->clsh_users == 0))
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+ 0x01, enable ? 0x01 : 0x00);
+ dev_dbg(codec->dev, "%s: clsh_users %d, enable %d", __func__,
+ clsh_d->clsh_users, enable);
}
static inline void wcd9xxx_enable_anc_delay(
@@ -430,64 +433,56 @@
0x02, on ? 0x02 : 0x00);
}
-static inline void wcd9xxx_enable_ncp(
- struct snd_soc_codec *codec,
- bool on)
+static inline void
+wcd9xxx_enable_buck(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d, bool enable)
{
- snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
- 0x01, on ? 0x01 : 0x00);
+ if ((enable && ++clsh_d->buck_users == 1) ||
+ (!enable && --clsh_d->buck_users == 0))
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+ 0x80, enable ? 0x80 : 0x00);
+ dev_dbg(codec->dev, "%s: buck_users %d, enable %d", __func__,
+ clsh_d->buck_users, enable);
}
-static inline void wcd9xxx_enable_buck(
- struct snd_soc_codec *codec,
- bool on)
-{
- snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
- 0x80, on ? 0x80 : 0x00);
-}
+static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_codec *,
+ struct wcd9xxx_clsh_cdc_data *,
+ u8 req_state, bool req_type);
-static int cdc_lo_count;
-
-static void (*clsh_state_fp[NUM_CLSH_STATES])
- (struct snd_soc_codec *,
- struct wcd9xxx_clsh_cdc_data *,
- u8 req_state, bool req_type);
-
-static const char *state_to_str(u8 state)
-{
- if (state == WCD9XXX_CLSH_STATE_IDLE)
- return "STATE_IDLE";
- else if (state == WCD9XXX_CLSH_STATE_EAR)
- return "STATE_EAR";
- else if (state == WCD9XXX_CLSH_STATE_HPHL)
- return "STATE_HPH_L";
- else if (state == WCD9XXX_CLSH_STATE_HPHR)
- return "STATE_HPH_R";
- else if (state == (WCD9XXX_CLSH_STATE_HPHL
- | WCD9XXX_CLSH_STATE_HPHR))
- return "STATE_HPH_L_R";
- else if (state == WCD9XXX_CLSH_STATE_LO)
- return "STATE_LO";
-
- return "UNKNOWN_STATE";
-}
-
-static void wcd9xxx_cfg_clsh_buck(
- struct snd_soc_codec *codec)
+static const char *state_to_str(u8 state, char *buf, size_t buflen)
{
int i;
- const struct wcd9xxx_reg_mask_val reg_set[] = {
- {WCD9XXX_A_BUCK_CTRL_CCL_4, 0x0B, 0x00},
- {WCD9XXX_A_BUCK_CTRL_CCL_1, 0xF0, 0x50},
- {WCD9XXX_A_BUCK_CTRL_CCL_3, 0x03, 0x00},
- {WCD9XXX_A_BUCK_CTRL_CCL_3, 0x0B, 0x00},
+ int cnt = 0;
+ /*
+ * This array of strings should match with enum wcd9xxx_clsh_state_bit.
+ */
+ const char *states[] = {
+ "STATE_EAR",
+ "STATE_HPH_L",
+ "STATE_HPH_R",
+ "STATE_LO",
};
- for (i = 0; i < ARRAY_SIZE(reg_set); i++)
- snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
- reg_set[i].val);
+ if (state == WCD9XXX_CLSH_STATE_IDLE) {
+ snprintf(buf, buflen, "[STATE_IDLE]");
+ goto done;
+ }
- dev_dbg(codec->dev, "%s: Programmed buck parameters", __func__);
+ buf[0] = '\0';
+ for (i = 0; i < ARRAY_SIZE(states); i++) {
+ if (!(state & (1 << i)))
+ continue;
+ cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf,
+ buf[0] == '\0' ? "[" : "|",
+ states[i]);
+ }
+ if (cnt > 0)
+ strlcat(buf + cnt, "]", buflen);
+
+done:
+ if (buf[0] == '\0')
+ snprintf(buf, buflen, "[STATE_UNKNOWN]");
+ return buf;
}
static void wcd9xxx_cfg_clsh_param_common(
@@ -515,26 +510,25 @@
__func__);
}
-static void wcd9xxx_chargepump_request(
- struct snd_soc_codec *codec, bool on)
+static void wcd9xxx_chargepump_request(struct snd_soc_codec *codec, bool on)
{
static int cp_count;
if (on && (++cp_count == 1)) {
snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
- 0x01, 0x01);
+ 0x01, 0x01);
dev_dbg(codec->dev, "%s: Charge Pump enabled, count = %d\n",
- __func__, cp_count);
- }
-
- else if (!on) {
+ __func__, cp_count);
+ } else if (!on) {
if (--cp_count < 0) {
- dev_dbg(codec->dev, "%s: Unbalanced disable for charge pump\n",
+ dev_dbg(codec->dev,
+ "%s: Unbalanced disable for charge pump\n",
+ __func__);
+ if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL) &
+ 0x01) {
+ dev_dbg(codec->dev,
+ "%s: Actual chargepump is ON\n",
__func__);
- if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
- & 0x01) {
- dev_dbg(codec->dev, "%s: Actual chargepump is ON\n",
- __func__);
}
cp_count = 0;
WARN_ON(1);
@@ -542,9 +536,10 @@
if (cp_count == 0) {
snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
- 0x01, 0x00);
- dev_dbg(codec->dev, "%s: Charge pump disabled, count = %d\n",
- __func__, cp_count);
+ 0x01, 0x00);
+ dev_dbg(codec->dev,
+ "%s: Charge pump disabled, count = %d\n",
+ __func__, cp_count);
}
}
}
@@ -617,7 +612,6 @@
}
}
-
int wcd9xxx_soc_update_bits_push(struct snd_soc_codec *codec,
struct list_head *list,
uint16_t reg, uint8_t mask,
@@ -657,18 +651,15 @@
}
EXPORT_SYMBOL(wcd9xxx_restore_registers);
-static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
- u8 buck_vref)
+static void wcd9xxx_set_buck_mode(struct snd_soc_codec *codec, u8 buck_vref)
{
int i;
const struct wcd9xxx_reg_mask_val reg_set[] = {
- {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x03},
+ {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x02},
{WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
{WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
- {WCD9XXX_A_BUCK_MODE_1, 0x08, 0x00},
{WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
{WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
- {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x80},
};
for (i = 0; i < ARRAY_SIZE(reg_set); i++)
@@ -704,25 +695,51 @@
}
-static void wcd9xxx_set_fclk_enable_ncp(struct snd_soc_codec *codec,
- u8 fclk_level)
+static void wcd9xxx_set_fclk_get_ncp(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ enum ncp_fclk_level fclk_level)
{
- int i;
- const struct wcd9xxx_reg_mask_val reg_set[] = {
- {WCD9XXX_A_NCP_STATIC, 0x20, 0x20},
- {WCD9XXX_A_NCP_EN, 0x01, 0x01},
- };
- snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
- 0x010, 0x00);
- snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
- 0x0F, fclk_level);
- for (i = 0; i < ARRAY_SIZE(reg_set); i++)
- snd_soc_update_bits(codec, reg_set[i].reg,
- reg_set[i].mask, reg_set[i].val);
+ clsh_d->ncp_users[fclk_level]++;
- usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
+ pr_debug("%s: enter ncp type %d users fclk8 %d, fclk5 %d\n", __func__,
+ fclk_level, clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
+ clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
- dev_dbg(codec->dev, "%s: set ncp done\n", __func__);
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x10, 0x00);
+ /* fclk level 8 dominates level 5 */
+ if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] > 0)
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x08);
+ else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_5] > 0)
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x05);
+ else
+ WARN_ONCE(1, "Unexpected users %d,%d\n",
+ clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
+ clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x20, 0x20);
+
+ /* enable NCP and wait until settles down */
+ if (snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x01))
+ usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
+ pr_debug("%s: leave\n", __func__);
+}
+
+static void wcd9xxx_set_fclk_put_ncp(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ enum ncp_fclk_level fclk_level)
+{
+ clsh_d->ncp_users[fclk_level]--;
+
+ pr_debug("%s: enter ncp type %d users fclk8 %d, fclk5 %d\n", __func__,
+ fclk_level, clsh_d->ncp_users[NCP_FCLK_LEVEL_8],
+ clsh_d->ncp_users[NCP_FCLK_LEVEL_5]);
+
+ if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0 &&
+ clsh_d->ncp_users[NCP_FCLK_LEVEL_5] == 0)
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN, 0x01, 0x00);
+ else if (clsh_d->ncp_users[NCP_FCLK_LEVEL_8] == 0)
+ /* if dominating level 8 has gone, switch to 5 */
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC, 0x0F, 0x05);
+ pr_debug("%s: leave\n", __func__);
}
static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
@@ -790,72 +807,30 @@
__func__);
}
-static void wcd9xxx_clsh_turnoff_postpa
- (struct snd_soc_codec *codec)
-{
-
- int i;
-
- const struct wcd9xxx_reg_mask_val reg_set[] = {
- {WCD9XXX_A_NCP_EN, 0x01, 0x00},
- {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x00},
- {WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10, 0x00},
- };
-
- wcd9xxx_chargepump_request(codec, false);
-
- for (i = 0; i < ARRAY_SIZE(reg_set); i++)
- snd_soc_update_bits(codec, reg_set[i].reg,
- reg_set[i].mask, reg_set[i].val);
-
- wcd9xxx_enable_clsh_block(codec, false);
-
- dev_dbg(codec->dev, "%s: Done\n", __func__);
-}
-
-static void wcd9xxx_clsh_state_idle(struct snd_soc_codec *codec,
- struct wcd9xxx_clsh_cdc_data *clsh_d,
- u8 req_state, bool is_enable)
-{
- if (is_enable) {
- dev_dbg(codec->dev, "%s: wrong transition, cannot enable IDLE state\n",
- __func__);
- } else {
- if (req_state == WCD9XXX_CLSH_STATE_EAR) {
- wcd9xxx_clsh_turnoff_postpa(codec);
- } else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
- false);
- wcd9xxx_clsh_turnoff_postpa(codec);
- } else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
- false);
- wcd9xxx_clsh_turnoff_postpa(codec);
- } else if (req_state == WCD9XXX_CLSH_STATE_LO) {
- wcd9xxx_enable_ncp(codec, false);
- wcd9xxx_enable_buck(codec, false);
- }
- }
-}
-
static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
+ pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
if (is_enable) {
- wcd9xxx_cfg_clsh_buck(codec);
wcd9xxx_cfg_clsh_param_common(codec);
wcd9xxx_cfg_clsh_param_ear(codec);
- wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, true);
wcd9xxx_chargepump_request(codec, true);
wcd9xxx_enable_anc_delay(codec, true);
wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
- wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
- wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+ wcd9xxx_set_buck_mode(codec, BUCK_VREF_2V);
+ wcd9xxx_enable_buck(codec, clsh_d, true);
+ wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
} else {
dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
+ wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+ wcd9xxx_enable_buck(codec, clsh_d, false);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_EAR, true);
+ wcd9xxx_chargepump_request(codec, false);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, false);
}
}
@@ -863,26 +838,26 @@
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
+ pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
+
if (is_enable) {
- wcd9xxx_cfg_clsh_buck(codec);
wcd9xxx_cfg_clsh_param_common(codec);
wcd9xxx_cfg_clsh_param_hph(codec);
- wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, true);
wcd9xxx_chargepump_request(codec, true);
wcd9xxx_enable_anc_delay(codec, true);
wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
- wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
- wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+ wcd9xxx_set_buck_mode(codec, BUCK_VREF_0P494V);
+ wcd9xxx_enable_buck(codec, clsh_d, true);
+ wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
dev_dbg(codec->dev, "%s: Done\n", __func__);
} else {
- if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R,
- false);
- } else {
- dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
- __func__);
- }
+ wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+ wcd9xxx_enable_buck(codec, clsh_d, false);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, false);
+ wcd9xxx_chargepump_request(codec, false);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, false);
}
}
@@ -890,27 +865,26 @@
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
- if (is_enable) {
+ pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
- wcd9xxx_cfg_clsh_buck(codec);
+ if (is_enable) {
wcd9xxx_cfg_clsh_param_common(codec);
wcd9xxx_cfg_clsh_param_hph(codec);
- wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, true);
wcd9xxx_chargepump_request(codec, true);
wcd9xxx_enable_anc_delay(codec, true);
wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
- wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
- wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+ wcd9xxx_set_buck_mode(codec, BUCK_VREF_0P494V);
+ wcd9xxx_enable_buck(codec, clsh_d, true);
+ wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
dev_dbg(codec->dev, "%s: Done\n", __func__);
} else {
- if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L,
- false);
- } else {
- dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
- __func__);
- }
+ wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_8);
+ wcd9xxx_enable_buck(codec, clsh_d, false);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, false);
+ wcd9xxx_chargepump_request(codec, false);
+ wcd9xxx_enable_clsh_block(codec, clsh_d, false);
}
}
@@ -918,9 +892,11 @@
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
+ pr_debug("%s: enter %s\n", __func__, is_enable ? "enable" : "disable");
+
if (is_enable) {
wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_L, true);
- wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
+ wcd9xxx_clsh_comp_req(codec, clsh_d, CLSH_COMPUTE_HPH_R, true);
} else {
dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
}
@@ -930,38 +906,36 @@
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
- if (is_enable) {
- if (++cdc_lo_count > 1)
- return;
+ pr_debug("%s: enter %s, buck_mv %d\n", __func__,
+ is_enable ? "enable" : "disable", clsh_d->buck_mv);
- wcd9xxx_enable_buck_mode(codec, BUCK_VREF_1P8V);
- wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_5);
+ if (is_enable) {
+ wcd9xxx_set_buck_mode(codec, BUCK_VREF_1P8V);
+ wcd9xxx_enable_buck(codec, clsh_d, true);
+ wcd9xxx_set_fclk_get_ncp(codec, clsh_d, NCP_FCLK_LEVEL_5);
if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
- wcd9xxx_enable_buck(codec, false);
+ wcd9xxx_enable_buck(codec, clsh_d, false);
snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
- 0x20, 0x01);
- wcd9xxx_enable_ncp(codec, true);
+ 1 << 4, 1 << 4);
/* NCP settle time recommended by codec specification */
usleep_range(NCP_SETTLE_TIME_US,
- NCP_SETTLE_TIME_US + 10);
-
+ NCP_SETTLE_TIME_US + 10);
} else {
- snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
- 0x40, 0x00);
- wcd9xxx_enable_ncp(codec, true);
/* NCP settle time recommended by codec specification */
usleep_range(NCP_SETTLE_TIME_US,
- NCP_SETTLE_TIME_US + 10);
+ NCP_SETTLE_TIME_US + 10);
snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
- 0x01, 0x01);
+ 0x01, (0x01 & 0x03));
snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
- 0xFB, (0x02 << 2));
+ 0xFC, (0xFC & 0xB));
}
- snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
- 0x04, 0x00);
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1, 0x04, 0x00);
} else {
dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
+ wcd9xxx_set_fclk_put_ncp(codec, clsh_d, NCP_FCLK_LEVEL_5);
+ if (clsh_d->buck_mv != WCD9XXX_CDC_BUCK_MV_1P8)
+ wcd9xxx_enable_buck(codec, clsh_d, false);
}
}
@@ -969,9 +943,12 @@
struct wcd9xxx_clsh_cdc_data *clsh_d,
u8 req_state, bool is_enable)
{
- dev_dbg(codec->dev, "%s Wrong request for class H state machine requested to %s %s"
- , __func__, is_enable ? "enable" : "disable",
- state_to_str(req_state));
+ char msg[128];
+
+ dev_dbg(codec->dev,
+ "%s Wrong request for class H state machine requested to %s %s",
+ __func__, is_enable ? "enable" : "disable",
+ state_to_str(req_state, msg, sizeof(msg)));
WARN_ON(1);
}
@@ -980,51 +957,45 @@
u8 req_state, bool req_type, u8 clsh_event)
{
u8 old_state, new_state;
+ char msg0[128], msg1[128];
switch (clsh_event) {
-
case WCD9XXX_CLSH_EVENT_PRE_DAC:
-
/* PRE_DAC event should be used only for Enable */
BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
old_state = cdc_clsh_d->state;
new_state = old_state | req_state;
- (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
- req_state, req_type);
+ (*clsh_state_fp[req_state]) (codec, cdc_clsh_d, req_state,
+ req_type);
cdc_clsh_d->state = new_state;
dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
- __func__, state_to_str(old_state),
- state_to_str(cdc_clsh_d->state));
+ __func__, state_to_str(old_state, msg0, sizeof(msg0)),
+ state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
break;
-
case WCD9XXX_CLSH_EVENT_POST_PA:
-
if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
- if (req_state == WCD9XXX_CLSH_STATE_LO
- && --cdc_lo_count > 0)
- break;
-
old_state = cdc_clsh_d->state;
new_state = old_state & (~req_state);
if (new_state < NUM_CLSH_STATES) {
- (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
- req_state, req_type);
+ (*clsh_state_fp[req_state]) (codec, cdc_clsh_d,
+ req_state,
+ req_type);
cdc_clsh_d->state = new_state;
dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
- __func__, state_to_str(old_state),
- state_to_str(cdc_clsh_d->state));
+ __func__, state_to_str(old_state, msg0,
+ sizeof(msg0)),
+ state_to_str(cdc_clsh_d->state, msg1,
+ sizeof(msg1)));
} else {
dev_dbg(codec->dev, "%s: wrong new state = %x\n",
__func__, new_state);
}
-
-
- } else if (req_state != WCD9XXX_CLSH_STATE_LO) {
+ } else if (!(cdc_clsh_d->state & WCD9XXX_CLSH_STATE_LO)) {
wcd9xxx_clsh_enable_post_pa(codec, cdc_clsh_d);
}
@@ -1044,7 +1015,6 @@
for (i = 0; i < NUM_CLSH_STATES; i++)
clsh_state_fp[i] = wcd9xxx_clsh_state_err;
- clsh_state_fp[WCD9XXX_CLSH_STATE_IDLE] = wcd9xxx_clsh_state_idle;
clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
wcd9xxx_clsh_state_hph_l;
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
index 0239c86..324f6e9 100644
--- a/sound/soc/codecs/wcd9xxx-common.h
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -63,11 +63,20 @@
u8 val;
};
+enum ncp_fclk_level {
+ NCP_FCLK_LEVEL_8,
+ NCP_FCLK_LEVEL_5,
+ NCP_FCLK_LEVEL_MAX,
+};
+
/* Class H data that the codec driver will maintain */
struct wcd9xxx_clsh_cdc_data {
u8 state;
int buck_mv;
bool is_dynamic_vdd_cp;
+ int clsh_users;
+ int buck_users;
+ int ncp_users[NCP_FCLK_LEVEL_MAX];
struct wcd9xxx_resmgr *resmgr;
};
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 8d6c4bc..ec99c5f 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -222,6 +222,19 @@
pr_debug("Polling is not active, do not start polling\n");
return;
}
+
+ /*
+ * setup internal micbias if codec uses internal micbias for
+ * headset detection
+ */
+ if (mbhc->mbhc_cfg->use_int_rbias && !mbhc->int_rbias_on) {
+ if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+ mbhc->mbhc_cb->setup_int_rbias(codec, true);
+ else
+ pr_err("%s: internal bias requested but codec did not provide callback\n",
+ __func__);
+ }
+
snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mux_bias_block)
mbhc->mbhc_cb->enable_mux_bias_block(codec);
@@ -1090,12 +1103,12 @@
* setup internal micbias if codec uses internal micbias for
* headset detection
*/
- if (mbhc->mbhc_cfg->use_int_rbias) {
+ if (mbhc->mbhc_cfg->use_int_rbias && !mbhc->int_rbias_on) {
if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
mbhc->mbhc_cb->setup_int_rbias(codec, true);
else
- pr_err("%s: internal bias is requested but codec did not provide callback\n",
- __func__);
+ pr_err("%s: internal bias requested but codec did not provide callback\n",
+ __func__);
}
snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x01);
@@ -1289,6 +1302,7 @@
const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
s16 hs_max, no_mic, dce_z;
+ int highhph_cnt = 0;
pr_debug("%s: enter\n", __func__);
pr_debug("%s: event_state 0x%lx\n", __func__, event_state);
@@ -1313,9 +1327,10 @@
d->_vdces = vdce;
if (d->_vdces < no_mic)
d->_type = PLUG_TYPE_HEADPHONE;
- else if (d->_vdces >= hs_max)
+ else if (d->_vdces >= hs_max) {
d->_type = PLUG_TYPE_HIGH_HPH;
- else
+ highhph_cnt++;
+ } else
d->_type = PLUG_TYPE_HEADSET;
pr_debug("%s: DCE #%d, %04x, V %04d(%04d), HPHL %d TYPE %d\n",
@@ -1350,7 +1365,8 @@
goto exit;
}
- delta_thr = highhph ? WCD9XXX_MB_MEAS_DELTA_MAX_MV :
+ delta_thr = ((highhph_cnt == sz) || highhph) ?
+ WCD9XXX_MB_MEAS_DELTA_MAX_MV :
WCD9XXX_CS_MEAS_DELTA_MAX_MV;
for (i = 0, d = dt; i < sz; i++, d++) {
@@ -2842,6 +2858,10 @@
if (wcd9xxx_cancel_btn_work(mbhc))
pr_debug("%s: button press is canceled\n", __func__);
+ /* cancel detect plug */
+ wcd9xxx_cancel_hs_detect_plug(mbhc,
+ &mbhc->correct_plug_swch);
+
insert = !wcd9xxx_swch_level_remove(mbhc);
pr_debug("%s: Current plug type %d, insert %d\n", __func__,
mbhc->current_plug, insert);
@@ -2849,9 +2869,6 @@
mbhc->lpi_enabled = false;
wmb();
- /* cancel detect plug */
- wcd9xxx_cancel_hs_detect_plug(mbhc,
- &mbhc->correct_plug_swch);
if ((mbhc->current_plug != PLUG_TYPE_NONE) &&
!(snd_soc_read(codec, WCD9XXX_A_MBHC_INSERT_DETECT) &
(1 << 1)))
@@ -2866,10 +2883,6 @@
mbhc->lpi_enabled = false;
wmb();
- /* cancel detect plug */
- wcd9xxx_cancel_hs_detect_plug(mbhc,
- &mbhc->correct_plug_swch);
-
if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
is_removed = true;
@@ -3171,6 +3184,19 @@
goto done;
}
+ /*
+ * setup internal micbias if codec uses internal micbias for
+ * headset detection
+ */
+ if (mbhc->mbhc_cfg->use_int_rbias && !mbhc->int_rbias_on) {
+ if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+ mbhc->mbhc_cb->setup_int_rbias(codec, true);
+ else
+ pr_err("%s: internal bias requested but codec did not provide callback\n",
+ __func__);
+ }
+
+
/* Measure scaled HW DCE */
vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
mbhc->mbhc_micbias_switched);
@@ -3991,11 +4017,13 @@
* headset detection
*/
if (mbhc->mbhc_cfg->use_int_rbias) {
- if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias)
+ if (mbhc->mbhc_cb && mbhc->mbhc_cb->setup_int_rbias) {
mbhc->mbhc_cb->setup_int_rbias(codec, true);
- else
- pr_info("%s: internal bias is requested but codec did not provide callback\n",
+ mbhc->int_rbias_on = true;
+ } else {
+ pr_info("%s: internal bias requested but codec did not provide callback\n",
__func__);
+ }
}
/*
@@ -4150,6 +4178,7 @@
case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
+ mbhc->int_rbias_on = true;
if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
wcd9xxx_event_to_micbias(event)) {
wcd9xxx_switch_micbias(mbhc, 0);
@@ -4177,6 +4206,7 @@
case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
+ mbhc->int_rbias_on = false;
if (mbhc->mbhc_cfg && mbhc->mbhc_cfg->micbias ==
wcd9xxx_event_to_micbias(event)) {
if (mbhc->event_state &
@@ -4472,6 +4502,7 @@
mbhc->mbhc_cb = mbhc_cb;
mbhc->intr_ids = mbhc_cdc_intr_ids;
mbhc->impedance_detect = impedance_det_en;
+ mbhc->int_rbias_on = false;
if (mbhc->intr_ids == NULL) {
pr_err("%s: Interrupt mapping not provided\n", __func__);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 9d0afe9..7fe9538 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -336,7 +336,7 @@
u32 rco_clk_rate;
bool update_z;
-
+ bool int_rbias_on;
/* Holds codec specific interrupt mapping */
const struct wcd9xxx_mbhc_intr *intr_ids;
diff --git a/sound/soc/msm/msm-pcm-host-voice.c b/sound/soc/msm/msm-pcm-host-voice.c
index 2eafc1d..1b68bcf 100644
--- a/sound/soc/msm/msm-pcm-host-voice.c
+++ b/sound/soc/msm/msm-pcm-host-voice.c
@@ -989,7 +989,7 @@
spin_unlock_irqrestore(&dai_data->dsp_lock, dsp_flags);
ret = copy_to_user(buf,
&buf_node->frame.voc_pkt,
- count);
+ buf_node->frame.len);
if (ret) {
pr_err("%s: Copy to user retuned %d\n",
__func__, ret);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 01b7956..99f196c 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -58,16 +58,9 @@
#define LO_2_SPK_AMP 0x4
#define LO_4_SPK_AMP 0x8
-#define LPAIF_OFFSET 0xFE000000
-#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
-#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
-#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
-#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
-
#define I2S_PCM_SEL 1
#define I2S_PCM_SEL_OFFSET 1
-
#define WCD9XXX_MBHC_DEF_BUTTONS 8
#define WCD9XXX_MBHC_DEF_RLOADS 5
#define TAIKO_EXT_CLK_RATE 9600000
@@ -146,6 +139,7 @@
struct msm_auxpcm_ctrl {
struct msm_auxpcm_gpio *pin_data;
u32 cnt;
+ void __iomem *mux;
};
struct msm8974_asoc_mach_data {
@@ -173,9 +167,6 @@
{"SEC_AUXPCM_DOUT", "qcom,sec-auxpcm-gpio-dout"},
};
-void *lpaif_pri_muxsel_virt_addr;
-void *lpaif_sec_muxsel_virt_addr;
-
struct msm8974_liquid_dock_dev {
int dock_plug_gpio;
int dock_plug_irq;
@@ -1192,12 +1183,14 @@
goto err;
}
if (atomic_inc_return(&prim_auxpcm_rsc_ref) == 1) {
- if (lpaif_pri_muxsel_virt_addr != NULL)
+ if (auxpcm_ctrl->mux != NULL) {
iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
- lpaif_pri_muxsel_virt_addr);
- else
- pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
- __func__);
+ auxpcm_ctrl->mux);
+ } else {
+ pr_err("%s: Pri AUXPCM MUX addr is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
}
if (ret < 0) {
@@ -1247,12 +1240,14 @@
goto err;
}
if (atomic_inc_return(&sec_auxpcm_rsc_ref) == 1) {
- if (lpaif_sec_muxsel_virt_addr != NULL)
+ if (auxpcm_ctrl->mux != NULL) {
iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
- lpaif_sec_muxsel_virt_addr);
- else
- pr_err("%s lpaif_sec_muxsel_virt_addr is NULL\n",
- __func__);
+ auxpcm_ctrl->mux);
+ } else {
+ pr_err("%s Sec AUXPCM MUX addr is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
}
if (ret < 0) {
@@ -2667,6 +2662,8 @@
int ret;
const char *auxpcm_pri_gpio_set = NULL;
const char *prop_name_ult_lo_gpio = "qcom,ext-ult-lo-amp-gpio";
+ struct resource *pri_muxsel;
+ struct resource *sec_muxsel;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "No platform supplied from device tree\n");
@@ -2794,7 +2791,6 @@
}
}
-
pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,us-euro-gpios", 0);
if (pdata->us_euro_gpio < 0) {
@@ -2821,28 +2817,49 @@
goto err1;
}
if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
- lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+ pri_muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "lpaif_pri_mode_muxsel");
} else if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-tert")) {
- lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_TER_MODE_MUXSEL, 4);
+ pri_muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "lpaif_tert_mode_muxsel");
} else {
dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
auxpcm_pri_gpio_set);
ret = -EINVAL;
goto err1;
}
- if (lpaif_pri_muxsel_virt_addr == NULL) {
- pr_err("%s Pri muxsel virt addr is null\n", __func__);
- ret = -EINVAL;
- goto err1;
+ if (!pri_muxsel) {
+ dev_err(&pdev->dev, "MUX addr invalid for primary AUXPCM\n");
+ ret = -ENODEV;
+ goto err1;
+ } else {
+ pdata->pri_auxpcm_ctrl->mux = ioremap(pri_muxsel->start,
+ resource_size(pri_muxsel));
+ if (pdata->pri_auxpcm_ctrl->mux == NULL) {
+ pr_err("%s Pri muxsel virt addr is null\n", __func__);
+ ret = -EINVAL;
+ goto err1;
+ }
}
- lpaif_sec_muxsel_virt_addr = ioremap(LPAIF_SEC_MODE_MUXSEL, 4);
- if (lpaif_sec_muxsel_virt_addr == NULL) {
+
+ sec_muxsel = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "lpaif_sec_mode_muxsel");
+ if (!sec_muxsel) {
+ dev_err(&pdev->dev, "MUX addr invalid for secondary AUXPCM\n");
+ ret = -ENODEV;
+ goto err2;
+ }
+ pdata->sec_auxpcm_ctrl->mux = ioremap(sec_muxsel->start,
+ resource_size(sec_muxsel));
+ if (pdata->sec_auxpcm_ctrl->mux == NULL) {
pr_err("%s Sec muxsel virt addr is null\n", __func__);
ret = -EINVAL;
- goto err1;
+ goto err2;
}
return 0;
+err2:
+ iounmap(pdata->pri_auxpcm_ctrl->mux);
err1:
if (ext_ult_lo_amp_gpio >= 0)
gpio_free(ext_ult_lo_amp_gpio);
@@ -2896,8 +2913,8 @@
msm8974_liquid_dock_dev = NULL;
}
- iounmap(lpaif_pri_muxsel_virt_addr);
- iounmap(lpaif_sec_muxsel_virt_addr);
+ iounmap(pdata->pri_auxpcm_ctrl->mux);
+ iounmap(pdata->sec_auxpcm_ctrl->mux);
snd_soc_unregister_card(card);
return 0;
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 01422cf..8187616 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -38,64 +38,60 @@
#define MAX_HW_DELAY_ENTRIES 25
-struct sidetone_atomic_cal {
- atomic_t enable;
- atomic_t gain;
-};
-
-
struct acdb_data {
+ uint32_t usage_count;
+
struct mutex acdb_mutex;
/* ANC Cal */
- struct acdb_atomic_cal_block anc_cal;
+ struct acdb_cal_block anc_cal;
/* AANC Cal */
- struct acdb_atomic_cal_block aanc_cal;
+ struct acdb_cal_block aanc_cal;
/* LSM Cal */
- struct acdb_atomic_cal_block lsm_cal;
+ struct acdb_cal_block lsm_cal;
/* AudProc Cal */
- atomic_t asm_topology;
- atomic_t adm_topology[MAX_AUDPROC_TYPES];
- struct acdb_atomic_cal_block audproc_cal[MAX_AUDPROC_TYPES];
- struct acdb_atomic_cal_block audstrm_cal[MAX_AUDPROC_TYPES];
- struct acdb_atomic_cal_block audvol_cal[MAX_AUDPROC_TYPES];
+ uint32_t asm_topology;
+ uint32_t adm_topology[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block audproc_cal[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block audstrm_cal[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block audvol_cal[MAX_AUDPROC_TYPES];
/* VocProc Cal */
- atomic_t voice_rx_topology;
- atomic_t voice_tx_topology;
- struct acdb_atomic_cal_block vocproc_cal;
- struct acdb_atomic_cal_block vocstrm_cal;
- struct acdb_atomic_cal_block vocvol_cal;
+ uint32_t voice_rx_topology;
+ uint32_t voice_tx_topology;
+ struct acdb_cal_block vocproc_cal;
+ struct acdb_cal_block vocstrm_cal;
+ struct acdb_cal_block vocvol_cal;
/* Voice Column data */
- struct acdb_atomic_cal_block vocproc_col_cal[MAX_VOCPROC_TYPES];
+ struct acdb_cal_block vocproc_col_cal[MAX_VOCPROC_TYPES];
uint32_t *col_data[MAX_VOCPROC_TYPES];
/* VocProc dev cfg cal*/
- struct acdb_atomic_cal_block vocproc_dev_cal;
+ struct acdb_cal_block vocproc_dev_cal;
/* Custom topology */
- struct acdb_atomic_cal_block adm_custom_topology;
- struct acdb_atomic_cal_block asm_custom_topology;
- atomic_t valid_adm_custom_top;
- atomic_t valid_asm_custom_top;
+ struct acdb_cal_block adm_custom_topology;
+ struct acdb_cal_block asm_custom_topology;
+ uint32_t valid_adm_custom_top;
+ uint32_t valid_asm_custom_top;
/* AFE cal */
- struct acdb_atomic_cal_block afe_cal[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block afe_cal[MAX_AUDPROC_TYPES];
/* Sidetone Cal */
- struct sidetone_atomic_cal sidetone_cal;
+ struct sidetone_cal sidetone_cal;
/* Allocation information */
struct ion_client *ion_client;
struct ion_handle *ion_handle;
- atomic_t map_handle;
- atomic64_t paddr;
- atomic64_t kvaddr;
- atomic64_t mem_len;
+ uint32_t map_handle;
+ uint64_t paddr;
+ uint64_t kvaddr;
+ uint64_t mem_len;
/* Speaker protection */
struct msm_spk_prot_cfg spk_prot_cfg;
@@ -106,62 +102,63 @@
};
static struct acdb_data acdb_data;
-static atomic_t usage_count;
uint32_t get_voice_rx_topology(void)
{
- return atomic_read(&acdb_data.voice_rx_topology);
+ return acdb_data.voice_rx_topology;
}
void store_voice_rx_topology(uint32_t topology)
{
- atomic_set(&acdb_data.voice_rx_topology, topology);
+ acdb_data.voice_rx_topology = topology;
}
uint32_t get_voice_tx_topology(void)
{
- return atomic_read(&acdb_data.voice_tx_topology);
+ return acdb_data.voice_tx_topology;
}
void store_voice_tx_topology(uint32_t topology)
{
- atomic_set(&acdb_data.voice_tx_topology, topology);
+ acdb_data.voice_tx_topology = topology;
}
uint32_t get_adm_rx_topology(void)
{
- return atomic_read(&acdb_data.adm_topology[RX_CAL]);
+ return acdb_data.adm_topology[RX_CAL];
}
void store_adm_rx_topology(uint32_t topology)
{
- atomic_set(&acdb_data.adm_topology[RX_CAL], topology);
+ acdb_data.adm_topology[RX_CAL] = topology;
}
uint32_t get_adm_tx_topology(void)
{
- return atomic_read(&acdb_data.adm_topology[TX_CAL]);
+ return acdb_data.adm_topology[TX_CAL];
}
void store_adm_tx_topology(uint32_t topology)
{
- atomic_set(&acdb_data.adm_topology[TX_CAL], topology);
+ acdb_data.adm_topology[TX_CAL] = topology;
}
uint32_t get_asm_topology(void)
{
- return atomic_read(&acdb_data.asm_topology);
+ return acdb_data.asm_topology;
}
void store_asm_topology(uint32_t topology)
{
- atomic_set(&acdb_data.asm_topology, topology);
+ acdb_data.asm_topology = topology;
}
void reset_custom_topology_flags(void)
{
- atomic_set(&acdb_data.valid_adm_custom_top, 1);
- atomic_set(&acdb_data.valid_asm_custom_top, 1);
+ mutex_lock(&acdb_data.acdb_mutex);
+ acdb_data.valid_adm_custom_top = 1;
+ acdb_data.valid_asm_custom_top = 1;
+ mutex_unlock(&acdb_data.acdb_mutex);
}
int get_adm_custom_topology(struct acdb_cal_block *cal_block)
@@ -175,19 +172,19 @@
goto done;
}
+ mutex_lock(&acdb_data.acdb_mutex);
/* Only return allow one access after memory registered */
- if (atomic_read(&acdb_data.valid_adm_custom_top) == 0) {
+ if (acdb_data.valid_adm_custom_top == 0) {
cal_block->cal_size = 0;
- goto done;
+ goto unlock;
}
- atomic_set(&acdb_data.valid_adm_custom_top, 0);
+ acdb_data.valid_adm_custom_top = 0;
- cal_block->cal_size =
- atomic_read(&acdb_data.adm_custom_topology.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.adm_custom_topology.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.adm_custom_topology.cal_kvaddr);
+ cal_block->cal_size = acdb_data.adm_custom_topology.cal_size;
+ cal_block->cal_paddr = acdb_data.adm_custom_topology.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.adm_custom_topology.cal_kvaddr;
+unlock:
+ mutex_unlock(&acdb_data.acdb_mutex);
done:
return result;
}
@@ -197,21 +194,18 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.adm_custom_topology.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.adm_custom_topology.cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.adm_custom_topology.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
+ acdb_data.adm_custom_topology.cal_size = cal_block->cal_size;
+ acdb_data.adm_custom_topology.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.adm_custom_topology.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -227,19 +221,19 @@
goto done;
}
+ mutex_lock(&acdb_data.acdb_mutex);
/* Only return allow one access after memory registered */
- if (atomic_read(&acdb_data.valid_asm_custom_top) == 0) {
+ if (acdb_data.valid_asm_custom_top == 0) {
cal_block->cal_size = 0;
- goto done;
+ goto unlock;
}
- atomic_set(&acdb_data.valid_asm_custom_top, 0);
+ acdb_data.valid_asm_custom_top = 0;
- cal_block->cal_size =
- atomic_read(&acdb_data.asm_custom_topology.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.asm_custom_topology.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.asm_custom_topology.cal_kvaddr);
+ cal_block->cal_size = acdb_data.asm_custom_topology.cal_size;
+ cal_block->cal_paddr = acdb_data.asm_custom_topology.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.asm_custom_topology.cal_kvaddr;
+unlock:
+ mutex_unlock(&acdb_data.acdb_mutex);
done:
return result;
}
@@ -249,21 +243,18 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.asm_custom_topology.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.asm_custom_topology.cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.asm_custom_topology.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
+ acdb_data.asm_custom_topology.cal_size = cal_block->cal_size;
+ acdb_data.asm_custom_topology.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.asm_custom_topology.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -280,10 +271,8 @@
}
cal_block->cal_size = ACDB_TOTAL_VOICE_ALLOCATION;
- cal_block->cal_paddr =
- atomic_read(&acdb_data.vocproc_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.vocproc_cal.cal_kvaddr);
+ cal_block->cal_paddr = acdb_data.vocproc_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.vocproc_cal.cal_kvaddr;
done:
return result;
}
@@ -299,12 +288,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.aanc_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.aanc_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.aanc_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.aanc_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.aanc_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.aanc_cal.cal_kvaddr;
done:
return result;
}
@@ -314,20 +300,18 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.aanc_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.aanc_cal.cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.aanc_cal.cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.aanc_cal.cal_size = cal_block->cal_size;
+ acdb_data.aanc_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.aanc_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -343,12 +327,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.lsm_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.lsm_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.lsm_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.lsm_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.lsm_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.lsm_cal.cal_kvaddr;
done:
return result;
}
@@ -358,20 +339,18 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.lsm_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.lsm_cal.cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.lsm_cal.cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.lsm_cal.cal_size = cal_block->cal_size;
+ acdb_data.lsm_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.lsm_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -470,7 +449,6 @@
pr_debug("ACDB=> %s : Path = %d num_entries = %d\n",
__func__, path, delay.num_entries);
- mutex_lock(&acdb_data.acdb_mutex);
if (path == RX_CAL)
delay_dest = &acdb_data.hw_delay_rx;
else if (path == TX_CAL)
@@ -487,7 +465,6 @@
__func__, result, path);
result = -EFAULT;
}
- mutex_unlock(&acdb_data.acdb_mutex);
done:
return result;
}
@@ -503,12 +480,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.anc_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.anc_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.anc_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.anc_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.anc_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.anc_cal.cal_kvaddr;
done:
return result;
}
@@ -518,20 +492,18 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.anc_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.anc_cal.cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.anc_cal.cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.anc_cal.cal_size = cal_block->cal_size;
+ acdb_data.anc_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.anc_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -541,10 +513,9 @@
int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
@@ -555,12 +526,11 @@
goto done;
}
- atomic_set(&acdb_data.afe_cal[path].cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.afe_cal[path].cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.afe_cal[path].cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.afe_cal[path].cal_size = cal_block->cal_size;
+ acdb_data.afe_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.afe_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -582,12 +552,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.afe_cal[path].cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.afe_cal[path].cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.afe_cal[path].cal_kvaddr);
+ cal_block->cal_size = acdb_data.afe_cal[path].cal_size;
+ cal_block->cal_paddr = acdb_data.afe_cal[path].cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.afe_cal[path].cal_kvaddr;
done:
return result;
}
@@ -597,10 +564,9 @@
int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
@@ -611,12 +577,11 @@
goto done;
}
- atomic_set(&acdb_data.audproc_cal[path].cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.audproc_cal[path].cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.audproc_cal[path].cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.audproc_cal[path].cal_size = cal_block->cal_size;
+ acdb_data.audproc_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audproc_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -638,12 +603,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.audproc_cal[path].cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.audproc_cal[path].cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.audproc_cal[path].cal_kvaddr);
+ cal_block->cal_size = acdb_data.audproc_cal[path].cal_size;
+ cal_block->cal_paddr = acdb_data.audproc_cal[path].cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.audproc_cal[path].cal_kvaddr;
done:
return result;
}
@@ -653,10 +615,9 @@
int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
@@ -667,12 +628,11 @@
goto done;
}
- atomic_set(&acdb_data.audstrm_cal[path].cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.audstrm_cal[path].cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.audstrm_cal[path].cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.audstrm_cal[path].cal_size = cal_block->cal_size;
+ acdb_data.audstrm_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audstrm_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -694,12 +654,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.audstrm_cal[path].cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.audstrm_cal[path].cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.audstrm_cal[path].cal_kvaddr);
+ cal_block->cal_size = acdb_data.audstrm_cal[path].cal_size;
+ cal_block->cal_paddr = acdb_data.audstrm_cal[path].cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.audstrm_cal[path].cal_kvaddr;
done:
return result;
}
@@ -709,10 +666,9 @@
int result = 0;
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
result = -EINVAL;
goto done;
}
@@ -723,12 +679,11 @@
goto done;
}
- atomic_set(&acdb_data.audvol_cal[path].cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.audvol_cal[path].cal_paddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.audvol_cal[path].cal_kvaddr,
- cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+ acdb_data.audvol_cal[path].cal_size = cal_block->cal_size;
+ acdb_data.audvol_cal[path].cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.audvol_cal[path].cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -750,12 +705,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.audvol_cal[path].cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.audvol_cal[path].cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.audvol_cal[path].cal_kvaddr);
+ cal_block->cal_size = acdb_data.audvol_cal[path].cal_size;
+ cal_block->cal_paddr = acdb_data.audvol_cal[path].cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.audvol_cal[path].cal_kvaddr;
done:
return result;
}
@@ -767,21 +719,18 @@
pr_debug("%s,\n", __func__);
if (cal_size > MAX_COL_SIZE) {
- pr_err("%s: col size is to big %d\n", __func__,
- cal_size);
+ pr_err("%s: col size is to big %d\n", __func__, cal_size);
result = -EINVAL;
goto done;
}
if (copy_from_user(acdb_data.col_data[vocproc_type],
(void *)((uint8_t *)cal_block + sizeof(cal_size)),
cal_size)) {
- pr_err("%s: fail to copy col size %d\n",
- __func__, cal_size);
+ pr_err("%s: fail to copy col size %d\n", __func__, cal_size);
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.vocproc_col_cal[vocproc_type].cal_size,
- cal_size);
+ acdb_data.vocproc_col_cal[vocproc_type].cal_size = cal_size;
done:
return result;
}
@@ -798,12 +747,12 @@
goto done;
}
- cal_block->cal_size = atomic_read(&acdb_data.
- vocproc_col_cal[vocproc_type].cal_size);
- cal_block->cal_paddr = atomic_read(&acdb_data.
- vocproc_col_cal[vocproc_type].cal_paddr);
- cal_block->cal_kvaddr = atomic_read(&acdb_data.
- vocproc_col_cal[vocproc_type].cal_kvaddr);
+ cal_block->cal_size = acdb_data.
+ vocproc_col_cal[vocproc_type].cal_size;
+ cal_block->cal_paddr = acdb_data.
+ vocproc_col_cal[vocproc_type].cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.
+ vocproc_col_cal[vocproc_type].cal_kvaddr;
done:
return result;
}
@@ -815,24 +764,19 @@
if (cal_block->cal_offset >
- atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
- atomic_set(&acdb_data.vocproc_dev_cal.cal_size, 0);
+ acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
+ acdb_data.vocproc_dev_cal.cal_size = 0;
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.vocproc_dev_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.vocproc_dev_cal.cal_paddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.vocproc_dev_cal.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
-
+ acdb_data.vocproc_dev_cal.cal_size = cal_block->cal_size;
+ acdb_data.vocproc_dev_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.vocproc_dev_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -848,12 +792,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.vocproc_dev_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.vocproc_dev_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.vocproc_dev_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.vocproc_dev_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.vocproc_dev_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.vocproc_dev_cal.cal_kvaddr;
done:
return result;
}
@@ -866,24 +807,19 @@
pr_debug("%s,\n", __func__);
if (cal_block->cal_offset >
- atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
- atomic_set(&acdb_data.vocproc_cal.cal_size, 0);
+ acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
+ acdb_data.vocproc_cal.cal_size = 0;
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.vocproc_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.vocproc_cal.cal_paddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.vocproc_cal.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
-
+ acdb_data.vocproc_cal.cal_size = cal_block->cal_size;
+ acdb_data.vocproc_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.vocproc_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -899,12 +835,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.vocproc_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.vocproc_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.vocproc_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.vocproc_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.vocproc_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.vocproc_cal.cal_kvaddr;
done:
return result;
}
@@ -915,24 +848,19 @@
pr_debug("%s,\n", __func__);
if (cal_block->cal_offset >
- atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
- atomic_set(&acdb_data.vocstrm_cal.cal_size, 0);
+ acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
+ acdb_data.vocstrm_cal.cal_size = 0;
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.vocstrm_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.vocstrm_cal.cal_paddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.vocstrm_cal.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
-
+ acdb_data.vocstrm_cal.cal_size = cal_block->cal_size;
+ acdb_data.vocstrm_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.vocstrm_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -948,12 +876,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.vocstrm_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.vocstrm_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.vocstrm_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.vocstrm_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.vocstrm_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.vocstrm_cal.cal_kvaddr;
done:
return result;
}
@@ -963,25 +888,19 @@
int result = 0;
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset >
- atomic64_read(&acdb_data.mem_len)) {
- pr_err("%s: offset %d is > mem_len %ld\n",
- __func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.mem_len));
- atomic_set(&acdb_data.vocvol_cal.cal_size, 0);
+ if (cal_block->cal_offset > acdb_data.mem_len) {
+ pr_err("%s: offset %d is > mem_len %llu\n",
+ __func__, cal_block->cal_offset, acdb_data.mem_len);
+ acdb_data.vocvol_cal.cal_size = 0;
result = -EINVAL;
goto done;
}
- atomic_set(&acdb_data.vocvol_cal.cal_size,
- cal_block->cal_size);
- atomic_set(&acdb_data.vocvol_cal.cal_paddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.paddr));
- atomic_set(&acdb_data.vocvol_cal.cal_kvaddr,
- cal_block->cal_offset +
- atomic64_read(&acdb_data.kvaddr));
-
+ acdb_data.vocvol_cal.cal_size = cal_block->cal_size;
+ acdb_data.vocvol_cal.cal_paddr =
+ cal_block->cal_offset + acdb_data.paddr;
+ acdb_data.vocvol_cal.cal_kvaddr =
+ cal_block->cal_offset + acdb_data.kvaddr;
done:
return result;
}
@@ -997,12 +916,9 @@
goto done;
}
- cal_block->cal_size =
- atomic_read(&acdb_data.vocvol_cal.cal_size);
- cal_block->cal_paddr =
- atomic_read(&acdb_data.vocvol_cal.cal_paddr);
- cal_block->cal_kvaddr =
- atomic_read(&acdb_data.vocvol_cal.cal_kvaddr);
+ cal_block->cal_size = acdb_data.vocvol_cal.cal_size;
+ cal_block->cal_paddr = acdb_data.vocvol_cal.cal_paddr;
+ cal_block->cal_kvaddr = acdb_data.vocvol_cal.cal_kvaddr;
done:
return result;
}
@@ -1011,8 +927,8 @@
{
pr_debug("%s,\n", __func__);
- atomic_set(&acdb_data.sidetone_cal.enable, cal_data->enable);
- atomic_set(&acdb_data.sidetone_cal.gain, cal_data->gain);
+ acdb_data.sidetone_cal.enable = cal_data->enable;
+ acdb_data.sidetone_cal.gain = cal_data->gain;
}
int get_sidetone_cal(struct sidetone_cal *cal_data)
@@ -1026,8 +942,10 @@
goto done;
}
- cal_data->enable = atomic_read(&acdb_data.sidetone_cal.enable);
- cal_data->gain = atomic_read(&acdb_data.sidetone_cal.gain);
+ mutex_lock(&acdb_data.acdb_mutex);
+ cal_data->enable = acdb_data.sidetone_cal.enable;
+ cal_data->gain = acdb_data.sidetone_cal.gain;
+ mutex_unlock(&acdb_data.acdb_mutex);
done:
return result;
}
@@ -1111,14 +1029,15 @@
s32 result = 0;
pr_debug("%s\n", __func__);
- if (atomic64_read(&acdb_data.mem_len)) {
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.mem_len)
pr_debug("%s: ACDB opened but memory allocated, using existing allocation!\n",
__func__);
- }
- atomic_set(&acdb_data.valid_adm_custom_top, 1);
- atomic_set(&acdb_data.valid_asm_custom_top, 1);
- atomic_inc(&usage_count);
+ acdb_data.valid_adm_custom_top = 1;
+ acdb_data.valid_asm_custom_top = 1;
+ acdb_data.usage_count++;
+ mutex_unlock(&acdb_data.acdb_mutex);
return result;
}
@@ -1195,30 +1114,31 @@
int i;
pr_debug("%s\n", __func__);
- mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.mem_len == 0)
+ goto done;
+
+ pr_debug("Remove existing memory\n");
+ acdb_data.mem_len = 0;
+
+ /* unmap all cal data */
+ result = unmap_cal_tables();
+ if (result < 0)
+ pr_err("%s: unmap_cal_tables failed, err = %d\n",
+ __func__, result);
+
+ msm_audio_ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+ acdb_data.ion_client = NULL;
+ acdb_data.ion_handle = NULL;
+
+ for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+ kfree(acdb_data.col_data[i]);
+ acdb_data.col_data[i] = NULL;
+ }
+
kfree(acdb_data.hw_delay_tx.delay_info);
kfree(acdb_data.hw_delay_rx.delay_info);
-
- if (atomic64_read(&acdb_data.mem_len)) {
- /* unmap all cal data */
- result = unmap_cal_tables();
- if (result < 0)
- pr_err("%s: unmap_cal_tables failed, err = %d\n",
- __func__, result);
-
- atomic64_set(&acdb_data.mem_len, 0);
-
- for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
- kfree(acdb_data.col_data[i]);
- acdb_data.col_data[i] = NULL;
- }
- msm_audio_ion_free(acdb_data.ion_client, acdb_data.ion_handle);
- acdb_data.ion_client = NULL;
- acdb_data.ion_handle = NULL;
- mutex_unlock(&acdb_data.acdb_mutex);
- }
- mutex_unlock(&acdb_data.acdb_mutex);
- return 0;
+done:
+ return result;
}
static int register_memory(void)
@@ -1231,42 +1151,38 @@
unsigned long mem_len;
pr_debug("%s\n", __func__);
- mutex_lock(&acdb_data.acdb_mutex);
- allocate_hw_delay_entries();
- for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
- acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
- atomic_set(&acdb_data.vocproc_col_cal[i].cal_kvaddr,
- (uint32_t)acdb_data.col_data[i]);
- }
-
result = msm_audio_ion_import("audio_acdb_client",
&acdb_data.ion_client,
&acdb_data.ion_handle,
- atomic_read(&acdb_data.map_handle),
+ acdb_data.map_handle,
NULL, 0,
&paddr, (size_t *)&mem_len, &kvptr);
if (result) {
pr_err("%s: audio ION alloc failed, rc = %d\n",
__func__, result);
- result = PTR_ERR(acdb_data.ion_client);
goto err_ion_handle;
}
- kvaddr = (unsigned long)kvptr;
- atomic64_set(&acdb_data.paddr, paddr);
- atomic64_set(&acdb_data.kvaddr, kvaddr);
- atomic64_set(&acdb_data.mem_len, mem_len);
- mutex_unlock(&acdb_data.acdb_mutex);
- pr_debug("%s done! paddr = 0x%lx, kvaddr = 0x%lx, len = x%lx\n",
- __func__,
- (long)atomic64_read(&acdb_data.paddr),
- (long)atomic64_read(&acdb_data.kvaddr),
- (long)atomic64_read(&acdb_data.mem_len));
+ allocate_hw_delay_entries();
+
+ for (i = 0; i < MAX_VOCPROC_TYPES; i++) {
+ acdb_data.col_data[i] = kmalloc(MAX_COL_SIZE, GFP_KERNEL);
+ acdb_data.vocproc_col_cal[i].cal_kvaddr =
+ (uint32_t)acdb_data.col_data[i];
+ }
+
+ kvaddr = (unsigned long)kvptr;
+ acdb_data.paddr = paddr;
+ acdb_data.kvaddr = kvaddr;
+ acdb_data.mem_len = mem_len;
+
+ pr_debug("%s done! paddr = 0x%llx, kvaddr = 0x%llx, len = 0x%llx\n",
+ __func__, acdb_data.paddr, acdb_data.kvaddr,
+ acdb_data.mem_len);
return result;
err_ion_handle:
- atomic64_set(&acdb_data.mem_len, 0);
- mutex_unlock(&acdb_data.acdb_mutex);
+ acdb_data.mem_len = 0;
return result;
}
static long acdb_ioctl(struct file *f,
@@ -1281,26 +1197,26 @@
struct msm_spk_prot_status acdb_spk_status;
pr_debug("%s\n", __func__);
+ mutex_lock(&acdb_data.acdb_mutex);
switch (cmd) {
case AUDIO_REGISTER_PMEM:
pr_debug("AUDIO_REGISTER_PMEM\n");
- if (atomic_read(&acdb_data.mem_len)) {
- deregister_memory();
- pr_debug("Remove the existing memory\n");
- }
+ result = deregister_memory();
+ if (result < 0)
+ pr_err("%s: deregister_memory failed returned %d!\n",
+ __func__, result);
if (copy_from_user(&map_fd, (void *)arg, sizeof(map_fd))) {
pr_err("%s: fail to copy memory handle!\n", __func__);
result = -EFAULT;
} else {
- atomic_set(&acdb_data.map_handle, map_fd);
+ acdb_data.map_handle = map_fd;
result = register_memory();
}
goto done;
-
case AUDIO_DEREGISTER_PMEM:
pr_debug("AUDIO_DEREGISTER_PMEM\n");
- deregister_memory();
+ result = deregister_memory();
goto done;
case AUDIO_SET_VOICE_RX_TOPOLOGY:
if (copy_from_user(&topology, (void *)arg,
@@ -1343,16 +1259,13 @@
store_asm_topology(topology);
goto done;
case AUDIO_SET_SPEAKER_PROT:
- mutex_lock(&acdb_data.acdb_mutex);
if (copy_from_user(&acdb_data.spk_prot_cfg, (void *)arg,
sizeof(acdb_data.spk_prot_cfg))) {
pr_err("%s fail to copy spk_prot_cfg\n", __func__);
result = -EFAULT;
}
- mutex_unlock(&acdb_data.acdb_mutex);
goto done;
case AUDIO_GET_SPEAKER_PROT:
- mutex_lock(&acdb_data.acdb_mutex);
/*Indicates calibration was succesfull*/
if (acdb_data.spk_prot_cfg.mode == MSM_SPKR_PROT_CALIBRATED) {
prot_status.r0 = acdb_data.spk_prot_cfg.r0;
@@ -1379,7 +1292,6 @@
sizeof(prot_status))) {
pr_err("%s: Failed to update prot_status\n", __func__);
}
- mutex_unlock(&acdb_data.acdb_mutex);
goto done;
case AUDIO_REGISTER_VOCPROC_VOL_TABLE:
result = register_vocvol_table();
@@ -1502,23 +1414,25 @@
}
done:
+ mutex_unlock(&acdb_data.acdb_mutex);
return result;
}
static int acdb_mmap(struct file *file, struct vm_area_struct *vma)
{
int result = 0;
- uint32_t size = vma->vm_end - vma->vm_start;
+ size_t size = vma->vm_end - vma->vm_start;
pr_debug("%s\n", __func__);
- if (atomic64_read(&acdb_data.mem_len)) {
- if (size <= atomic64_read(&acdb_data.mem_len)) {
+ mutex_lock(&acdb_data.acdb_mutex);
+ if (acdb_data.mem_len) {
+ if (size <= acdb_data.mem_len) {
vma->vm_page_prot = pgprot_noncached(
vma->vm_page_prot);
result = remap_pfn_range(vma,
vma->vm_start,
- atomic64_read(&acdb_data.paddr) >> PAGE_SHIFT,
+ acdb_data.paddr >> PAGE_SHIFT,
size,
vma->vm_page_prot);
} else {
@@ -1529,25 +1443,29 @@
pr_err("%s: memory is not allocated, yet!\n", __func__);
result = -ENODEV;
}
+ mutex_unlock(&acdb_data.acdb_mutex);
return result;
}
static int acdb_release(struct inode *inode, struct file *f)
{
- s32 result = 0;
+ int result = 0;
+ pr_debug("%s\n", __func__);
- atomic_dec(&usage_count);
- atomic_read(&usage_count);
+ mutex_lock(&acdb_data.acdb_mutex);
+ acdb_data.usage_count--;
- pr_debug("%s: ref count %d!\n", __func__,
- atomic_read(&usage_count));
+ pr_debug("%s: ref count %d!\n", __func__, acdb_data.usage_count);
- if (atomic_read(&usage_count) >= 1)
+ if (acdb_data.usage_count > 0) {
result = -EBUSY;
- else
- result = deregister_memory();
+ goto done;
+ }
+ result = deregister_memory();
+done:
+ mutex_unlock(&acdb_data.acdb_mutex);
return result;
}
@@ -1571,9 +1489,9 @@
/*Speaker protection disabled*/
acdb_data.spk_prot_cfg.mode = MSM_SPKR_PROT_DISABLED;
mutex_init(&acdb_data.acdb_mutex);
- atomic_set(&usage_count, 0);
- atomic_set(&acdb_data.valid_adm_custom_top, 1);
- atomic_set(&acdb_data.valid_asm_custom_top, 1);
+ acdb_data.usage_count = 0;
+ acdb_data.valid_adm_custom_top = 1;
+ acdb_data.valid_asm_custom_top = 1;
return misc_register(&acdb_misc);
}
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index e2ca395..45a83f6 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -35,12 +35,6 @@
uint32_t cal_paddr;
};
-struct acdb_atomic_cal_block {
- atomic_t cal_size;
- atomic_t cal_kvaddr;
- atomic_t cal_paddr;
-};
-
struct hw_delay_entry {
uint32_t sample_rate;
uint32_t delay_usec;
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 93b3597..4a25606 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -879,6 +879,15 @@
pr_debug("%s\n", __func__);
+ audio_ocmem_lcl.audio_hdl = ocmem_notifier_register(OCMEM_LP_AUDIO,
+ &audio_ocmem_client_nb);
+ if (PTR_RET(audio_ocmem_lcl.audio_hdl) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ else if (!audio_ocmem_lcl.audio_hdl) {
+ pr_err("%s: Failed to get ocmem handle %d\n", __func__,
+ OCMEM_LP_AUDIO);
+ return -ENODEV;
+ }
subsys_notif_register_notifier("adsp", &anb);
audio_ocmem_lcl.ocmem_dump_addr =
@@ -944,12 +953,6 @@
ret = -EFAULT;
goto destroy_voice_wq;
}
- audio_ocmem_lcl.audio_hdl = ocmem_notifier_register(OCMEM_LP_AUDIO,
- &audio_ocmem_client_nb);
- if (audio_ocmem_lcl.audio_hdl == NULL) {
- pr_err("%s: Failed to get ocmem handle %d\n", __func__,
- OCMEM_LP_AUDIO);
- }
audio_ocmem_lcl.lp_memseg_ptr = NULL;
return 0;
destroy_voice_wq:
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index fb362a1..b626fa4 100755
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -987,7 +987,7 @@
struct snd_dec_ddp *ddp =
&compr->info.codec_param.codec.options.ddp;
uint32_t params_length = ddp->params_length*sizeof(int);
- if(params_length > MAX_AC3_PARAM_SIZE) {
+ if (params_length > MAX_AC3_PARAM_SIZE) {
/*MAX is 36*sizeof(int) this should not happen*/
pr_err("params_length(%d) is greater than %d",
params_length, MAX_AC3_PARAM_SIZE);
@@ -1024,7 +1024,7 @@
struct snd_dec_ddp *ddp =
&compr->info.codec_param.codec.options.ddp;
uint32_t params_length = ddp->params_length*sizeof(int);
- if(params_length > MAX_AC3_PARAM_SIZE) {
+ if (params_length > MAX_AC3_PARAM_SIZE) {
/*MAX is 36*sizeof(int) this should not happen*/
pr_err("params_length(%d) is greater than %d",
params_length, MAX_AC3_PARAM_SIZE);
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index da36f7f..79f0a97 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -44,6 +44,12 @@
#include "msm-pcm-routing-v2.h"
#include "audio_ocmem.h"
+#define DSP_PP_BUFFERING_IN_MSEC 25
+#define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC 150
+#define MP3_OUTPUT_FRAME_SZ 1152
+#define AAC_OUTPUT_FRAME_SZ 1024
+#define DSP_NUM_OUTPUT_FRAME_BUFFERED 2
+
/* Default values used if user space does not set */
#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
@@ -54,6 +60,13 @@
const DECLARE_TLV_DB_LINEAR(msm_compr_vol_gain, 0,
COMPRESSED_LR_VOL_MAX_STEPS);
+struct msm_compr_gapless_state {
+ bool set_next_stream_id;
+ int32_t stream_opened[2];
+ uint32_t initial_samples_drop;
+ uint32_t trailing_samples_drop;
+};
+
struct msm_compr_pdata {
atomic_t audio_ocmem_req;
struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX];
@@ -75,6 +88,9 @@
uint32_t byte_offset;
uint32_t copied_total;
uint32_t bytes_received;
+ int32_t first_buffer;
+ int32_t last_buffer;
+ int32_t partial_drain_delay;
uint16_t session_id;
@@ -85,14 +101,19 @@
uint32_t cmd_interrupt;
uint32_t drain_ready;
+ struct msm_compr_gapless_state gapless_state;
+
atomic_t start;
atomic_t eos;
atomic_t drain;
atomic_t xrun;
+ atomic_t close;
+ atomic_t wait_on_close;
wait_queue_head_t eos_wait;
wait_queue_head_t drain_wait;
wait_queue_head_t flush_wait;
+ wait_queue_head_t close_wait;
spinlock_t lock;
};
@@ -143,6 +164,17 @@
pr_debug("%s: bytes_received = %d copied_total = %d\n",
__func__, prtd->bytes_received, prtd->copied_total);
+ /*
+ * FIXME: Initial and trailing silence removal API call to DSP results
+ * to a glitch during the stream transition for gapless playback.
+ * Add this when the issue is fixed from DSP.
+ */
+/*
+ if (prtd->first_buffer)
+ q6asm_send_meta_data(prtd->audio_client,
+ prtd->gapless_state.initial_samples_drop,
+ prtd->gapless_state.trailing_samples_drop);
+*/
buffer_length = prtd->codec_param.buffer.fragment_size;
bytes_available = prtd->bytes_received - prtd->copied_total;
if (bytes_available < prtd->codec_param.buffer.fragment_size)
@@ -153,7 +185,10 @@
pr_debug("wrap around situation, send partial data %d now", buffer_length);
}
- param.paddr = prtd->buffer_paddr + prtd->byte_offset;
+ if (buffer_length)
+ param.paddr = prtd->buffer_paddr + prtd->byte_offset;
+ else
+ param.paddr = prtd->buffer_paddr;
WARN(param.paddr % 32 != 0, "param.paddr %lx not multiple of 32", param.paddr);
param.len = buffer_length;
@@ -162,11 +197,16 @@
param.flags = NO_TIMESTAMP;
param.uid = buffer_length;
param.metadata_len = 0;
+ param.last_buffer = prtd->last_buffer;
pr_debug("%s: sending %d bytes to DSP byte_offset = %d\n",
__func__, buffer_length, prtd->byte_offset);
- if (q6asm_async_write(prtd->audio_client, ¶m) < 0)
+ if (q6asm_async_write(prtd->audio_client, ¶m) < 0) {
pr_err("%s:q6asm_async_write failed\n", __func__);
+ } else {
+ if (prtd->first_buffer)
+ prtd->first_buffer = 0;
+ }
return 0;
}
@@ -176,9 +216,10 @@
{
struct msm_compr_audio *prtd = priv;
struct snd_compr_stream *cstream = prtd->cstream;
+ struct audio_client *ac = prtd->audio_client;
uint32_t chan_mode = 0;
uint32_t sample_rate = 0;
- int bytes_available;
+ int bytes_available, stream_id;
pr_debug("%s opcode =%08x\n", __func__, opcode);
switch (opcode) {
@@ -217,12 +258,19 @@
pr_debug("WRITE_DONE Insufficient data to send. break out\n");
atomic_set(&prtd->xrun, 1);
+ if (prtd->last_buffer)
+ prtd->last_buffer = 0;
if (atomic_read(&prtd->drain)) {
- pr_debug("wake up on drain");
+ pr_debug("wake up on drain\n");
prtd->drain_ready = 1;
wake_up(&prtd->drain_wait);
atomic_set(&prtd->drain, 0);
}
+ } else if ((bytes_available == cstream->runtime->fragment_size)
+ && atomic_read(&prtd->drain)) {
+ prtd->last_buffer = 1;
+ msm_compr_send_buffer(prtd);
+ prtd->last_buffer = 0;
} else
msm_compr_send_buffer(prtd);
@@ -230,12 +278,24 @@
break;
case ASM_DATA_EVENT_RENDERED_EOS:
pr_debug("ASM_DATA_CMDRSP_EOS\n");
- if (atomic_read(&prtd->eos)) {
+ spin_lock(&prtd->lock);
+ if (atomic_read(&prtd->eos) &&
+ !prtd->gapless_state.set_next_stream_id) {
pr_debug("ASM_DATA_CMDRSP_EOS wake up\n");
prtd->cmd_ack = 1;
wake_up(&prtd->eos_wait);
- atomic_set(&prtd->eos, 0);
}
+ atomic_set(&prtd->eos, 0);
+ stream_id = ac->stream_id^1; /*prev stream */
+ if (prtd->gapless_state.set_next_stream_id &&
+ prtd->gapless_state.stream_opened[stream_id]) {
+ q6asm_stream_cmd_nowait(prtd->audio_client,
+ CMD_CLOSE, stream_id);
+ atomic_set(&prtd->close, 1);
+ prtd->gapless_state.stream_opened[stream_id] = 0;
+ prtd->gapless_state.set_next_stream_id = false;
+ }
+ spin_unlock(&prtd->lock);
break;
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: {
@@ -271,6 +331,21 @@
prtd->cmd_ack = 1;
wake_up(&prtd->flush_wait);
break;
+ case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
+ pr_debug("ASM_DATA_CMD_REMOVE_INITIAL_SILENCE\n");
+ break;
+ case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
+ pr_debug("ASM_DATA_CMD_REMOVE_TRAILING_SILENCE\n");
+ break;
+ case ASM_STREAM_CMD_CLOSE:
+ pr_debug("ASM_DATA_CMD_CLOSE\n");
+ if (atomic_read(&prtd->close) &&
+ atomic_read(&prtd->wait_on_close)) {
+ prtd->cmd_ack = 1;
+ wake_up(&prtd->close_wait);
+ }
+ atomic_set(&prtd->close, 0);
+ break;
default:
break;
}
@@ -302,7 +377,8 @@
prtd->compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
}
-static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream)
+static int msm_compr_send_media_format_block(struct snd_compr_stream *cstream,
+ int stream_id)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct msm_compr_audio *prtd = runtime->private_data;
@@ -319,8 +395,8 @@
aac_cfg.format = 0x03;
aac_cfg.ch_cfg = prtd->num_channels;
aac_cfg.sample_rate = prtd->sample_rate;
- ret = q6asm_media_format_block_aac(prtd->audio_client,
- &aac_cfg);
+ ret = q6asm_stream_media_format_block_aac(prtd->audio_client,
+ &aac_cfg, stream_id);
if (ret < 0)
pr_err("%s: CMD Format block failed\n", __func__);
break;
@@ -338,6 +414,7 @@
struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data;
uint16_t bits_per_sample = 16;
int dir = IN, ret = 0;
+ struct audio_client *ac = prtd->audio_client;
struct asm_softpause_params softpause = {
.enable = SOFT_PAUSE_ENABLE,
.period = SOFT_PAUSE_PERIOD,
@@ -351,16 +428,18 @@
};
pr_debug("%s\n", __func__);
- ret = q6asm_open_write_v2(prtd->audio_client,
- prtd->codec, bits_per_sample);
+ ret = q6asm_stream_open_write_v2(ac,
+ prtd->codec, bits_per_sample,
+ ac->stream_id, true/*gapless*/);
if (ret < 0) {
pr_err("%s: Session out open failed\n", __func__);
return -ENOMEM;
}
+ prtd->gapless_state.stream_opened[ac->stream_id] = 1;
pr_debug("%s be_id %d\n", __func__, soc_prtd->dai_link->be_id);
msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
- prtd->audio_client->perf_mode,
+ ac->perf_mode,
prtd->session_id,
SNDRV_PCM_STREAM_PLAYBACK);
@@ -368,19 +447,17 @@
if (ret < 0)
pr_err("%s : Set Volume failed : %d", __func__, ret);
- ret = q6asm_set_softpause(prtd->audio_client,
- &softpause);
+ ret = q6asm_set_softpause(ac, &softpause);
if (ret < 0)
pr_err("%s: Send SoftPause Param failed ret=%d\n",
__func__, ret);
- ret = q6asm_set_softvolume(prtd->audio_client, &softvol);
+ ret = q6asm_set_softvolume(ac, &softvol);
if (ret < 0)
pr_err("%s: Send SoftVolume Param failed ret=%d\n",
__func__, ret);
- ret = q6asm_set_io_mode(prtd->audio_client,
- (COMPRESSED_IO | ASYNC_IO_MODE));
+ ret = q6asm_set_io_mode(ac, (COMPRESSED_IO | ASYNC_IO_MODE));
if (ret < 0) {
pr_err("%s: Set IO mode failed\n", __func__);
return -EINVAL;
@@ -391,8 +468,7 @@
pr_debug("allocate %d buffers each of size %d\n",
runtime->fragments,
runtime->fragment_size);
- ret = q6asm_audio_client_buf_alloc_contiguous(dir,
- prtd->audio_client,
+ ret = q6asm_audio_client_buf_alloc_contiguous(dir, ac,
runtime->fragment_size,
runtime->fragments);
if (ret < 0) {
@@ -404,15 +480,13 @@
prtd->copied_total = 0;
prtd->app_pointer = 0;
prtd->bytes_received = 0;
- prtd->buffer = prtd->audio_client->port[dir].buf[0].data;
- prtd->buffer_paddr = prtd->audio_client->port[dir].buf[0].phys;
+ prtd->buffer = ac->port[dir].buf[0].data;
+ prtd->buffer_paddr = ac->port[dir].buf[0].phys;
prtd->buffer_size = runtime->fragments * runtime->fragment_size;
- ret = msm_compr_send_media_format_block(cstream);
-
- if (ret < 0) {
+ ret = msm_compr_send_media_format_block(cstream, ac->stream_id);
+ if (ret < 0)
pr_err("%s, failed to send media format block\n", __func__);
- }
return ret;
}
@@ -452,6 +526,10 @@
prtd->sample_rate = 44100;
prtd->num_channels = 2;
prtd->drain_ready = 0;
+ prtd->last_buffer = 0;
+ prtd->first_buffer = 1;
+ prtd->partial_drain_delay = 0;
+ memset(&prtd->gapless_state, 0, sizeof(struct msm_compr_gapless_state));
spin_lock_init(&prtd->lock);
@@ -459,10 +537,13 @@
atomic_set(&prtd->start, 0);
atomic_set(&prtd->drain, 0);
atomic_set(&prtd->xrun, 0);
+ atomic_set(&prtd->close, 0);
+ atomic_set(&prtd->wait_on_close, 0);
init_waitqueue_head(&prtd->eos_wait);
init_waitqueue_head(&prtd->drain_wait);
init_waitqueue_head(&prtd->flush_wait);
+ init_waitqueue_head(&prtd->close_wait);
runtime->private_data = prtd;
populate_codec_list(prtd);
@@ -488,7 +569,9 @@
struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data;
struct msm_compr_pdata *pdata =
snd_soc_platform_get_drvdata(soc_prtd->platform);
- int dir = IN, ret = 0;
+ struct audio_client *ac = prtd->audio_client;
+ int dir = IN, ret = 0, stream_id;
+ unsigned long flags;
pr_debug("%s\n", __func__);
pdata->cstream[soc_prtd->dai_link->be_id] = NULL;
@@ -511,13 +594,34 @@
if (!ret)
pr_err("%s: CMD_EOS failed\n", __func__);
}
+ if (atomic_read(&prtd->close)) {
+ prtd->cmd_ack = 0;
+ atomic_set(&prtd->wait_on_close, 1);
+ ret = wait_event_timeout(prtd->close_wait,
+ prtd->cmd_ack, 5 * HZ);
+ if (!ret)
+ pr_err("%s: CMD_CLOSE failed\n", __func__);
+ }
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ spin_lock_irqsave(&prtd->lock, flags);
+ stream_id = ac->stream_id;
+ if (prtd->gapless_state.stream_opened[stream_id^1]) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ q6asm_stream_cmd(ac, CMD_CLOSE, stream_id^1);
+ spin_lock_irqsave(&prtd->lock, flags);
+ }
+ if (prtd->gapless_state.stream_opened[stream_id]) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ q6asm_stream_cmd(ac, CMD_CLOSE, stream_id);
+ spin_lock_irqsave(&prtd->lock, flags);
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
- q6asm_audio_client_buf_free_contiguous(dir,
- prtd->audio_client);
+ /* client buf alloc was with stream id 0, so free with the same */
+ ac->stream_id = 0;
+ q6asm_audio_client_buf_free_contiguous(dir, ac);
- q6asm_audio_client_free(prtd->audio_client);
+ q6asm_audio_client_free(ac);
kfree(prtd);
@@ -530,7 +634,7 @@
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct msm_compr_audio *prtd = runtime->private_data;
- int ret = 0;
+ int ret = 0, frame_sz = 0, delay_time_ms = 0;
pr_debug("%s\n", __func__);
@@ -570,12 +674,14 @@
case SND_AUDIOCODEC_MP3: {
pr_debug("SND_AUDIOCODEC_MP3\n");
prtd->codec = FORMAT_MP3;
+ frame_sz = MP3_OUTPUT_FRAME_SZ;
break;
}
case SND_AUDIOCODEC_AAC: {
pr_debug("SND_AUDIOCODEC_AAC\n");
prtd->codec = FORMAT_MPEG4_AAC;
+ frame_sz = AAC_OUTPUT_FRAME_SZ;
break;
}
@@ -584,11 +690,40 @@
return -EINVAL;
}
+ delay_time_ms = ((DSP_NUM_OUTPUT_FRAME_BUFFERED * frame_sz * 1000) /
+ prtd->sample_rate) + DSP_PP_BUFFERING_IN_MSEC;
+ delay_time_ms = delay_time_ms > PARTIAL_DRAIN_ACK_EARLY_BY_MSEC ?
+ delay_time_ms - PARTIAL_DRAIN_ACK_EARLY_BY_MSEC : 0;
+ prtd->partial_drain_delay = delay_time_ms;
+
ret = msm_compr_configure_dsp(cstream);
return ret;
}
+static int msm_compr_drain_buffer(struct msm_compr_audio *prtd,
+ unsigned long *flags)
+{
+ int rc = 0;
+
+ atomic_set(&prtd->drain, 1);
+ prtd->drain_ready = 0;
+ spin_unlock_irqrestore(&prtd->lock, *flags);
+ pr_debug("%s: wait for buffer to be drained\n", __func__);
+ rc = wait_event_interruptible(prtd->drain_wait,
+ prtd->drain_ready ||
+ prtd->cmd_interrupt ||
+ atomic_read(&prtd->xrun));
+ pr_debug("%s: out of buffer drain wait\n", __func__);
+ spin_lock_irqsave(&prtd->lock, *flags);
+ if (prtd->cmd_interrupt) {
+ pr_debug("%s: buffer drain interrupted by flush)\n", __func__);
+ rc = -EINTR;
+ prtd->cmd_interrupt = 0;
+ }
+ return rc;
+}
+
static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
{
struct snd_compr_runtime *runtime = cstream->runtime;
@@ -597,9 +732,11 @@
struct msm_compr_pdata *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
uint32_t *volume = pdata->volume[rtd->dai_link->be_id];
+ struct audio_client *ac = prtd->audio_client;
int rc = 0;
int bytes_to_write;
unsigned long flags;
+ int stream_id;
if (cstream->direction != SND_COMPRESS_PLAYBACK) {
pr_err("%s: Unsupported stream type\n", __func__);
@@ -621,20 +758,37 @@
pr_debug("%s: SNDRV_PCM_TRIGGER_STOP\n", __func__);
spin_lock_irqsave(&prtd->lock, flags);
+ stream_id = ac->stream_id;
+ if (prtd->gapless_state.set_next_stream_id &&
+ prtd->first_buffer) {
+ /*
+ * Stream just switched for gapless, no buffers sent.
+ * So seek needs to be applied to previous stream
+ */
+ pr_debug("Seek previous stream as next stream hasn't started\n");
+ stream_id = stream_id^1;
+ ac->stream_id = stream_id;
+ prtd->first_buffer = 0;
+ }
atomic_set(&prtd->start, 0);
if (atomic_read(&prtd->eos)) {
- pr_debug("%s: interrupt drain and eos wait queues", __func__);
+ pr_debug("%s: interrupt eos wait queues", __func__);
prtd->cmd_interrupt = 1;
- prtd->drain_ready = 1;
- wake_up(&prtd->drain_wait);
wake_up(&prtd->eos_wait);
atomic_set(&prtd->eos, 0);
}
-
- pr_debug("issue CMD_FLUSH \n");
+ if (atomic_read(&prtd->drain)) {
+ pr_debug("%s: interrupt drain wait queues", __func__);
+ prtd->cmd_interrupt = 1;
+ prtd->drain_ready = 1;
+ wake_up(&prtd->drain_wait);
+ atomic_set(&prtd->drain, 0);
+ }
+ prtd->last_buffer = 0;
+ pr_debug("issue CMD_FLUSH\n");
prtd->cmd_ack = 0;
spin_unlock_irqrestore(&prtd->lock, flags);
- rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+ rc = q6asm_stream_cmd(prtd->audio_client, CMD_FLUSH, stream_id);
if (rc < 0) {
pr_err("%s: flush cmd failed rc=%d\n",
__func__, rc);
@@ -681,15 +835,15 @@
spin_unlock_irqrestore(&prtd->lock, flags);
break;
}
- atomic_set(&prtd->eos, 1);
-
if (prtd->bytes_received > prtd->copied_total) {
- atomic_set(&prtd->drain, 1);
- prtd->drain_ready = 0;
- spin_unlock_irqrestore(&prtd->lock, flags);
pr_debug("%s: wait till all the data is sent to dsp\n",
__func__);
-
+ rc = msm_compr_drain_buffer(prtd, &flags);
+ if (rc || !atomic_read(&prtd->start)) {
+ rc = -EINTR;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
/*
* FIXME: Bug.
* Write(32767)
@@ -698,47 +852,107 @@
* sol1 : if (prtd->copied_total) then wait?
* sol2 : prtd->cmd_interrupt || prtd->drain_ready || atomic_read(xrun)
*/
- rc = wait_event_interruptible(prtd->drain_wait,
- prtd->cmd_interrupt || prtd->drain_ready ||
- atomic_read(&prtd->xrun));
+ bytes_to_write = prtd->bytes_received - prtd->copied_total;
+ WARN(bytes_to_write > runtime->fragment_size,
+ "last write %d cannot be > than fragment_size",
+ bytes_to_write);
- spin_lock_irqsave(&prtd->lock, flags);
- if (!prtd->cmd_interrupt) {
- bytes_to_write = prtd->bytes_received - prtd->copied_total;
- WARN(bytes_to_write > runtime->fragment_size,
- "last write %d cannot be > than fragment_size",
- bytes_to_write);
-
- if (bytes_to_write > 0) {
- pr_debug("%s: send %d partial bytes at the end",
- __func__, bytes_to_write);
- atomic_set(&prtd->xrun, 0);
- msm_compr_send_buffer(prtd);
- }
+ if (bytes_to_write > 0) {
+ pr_debug("%s: send %d partial bytes at the end",
+ __func__, bytes_to_write);
+ atomic_set(&prtd->xrun, 0);
+ prtd->last_buffer = 1;
+ msm_compr_send_buffer(prtd);
}
}
- if (!atomic_read(&prtd->start) || prtd->cmd_interrupt) {
- pr_debug("%s: stream is not started (interrupted by flush?)\n", __func__);
- rc = -EINTR;
- prtd->cmd_interrupt = 0;
+ if ((cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN) &&
+ (prtd->gapless_state.set_next_stream_id)) {
+ /* wait for the last buffer to be returned */
+ if (prtd->last_buffer) {
+ pr_debug("%s: last buffer drain\n", __func__);
+ rc = msm_compr_drain_buffer(prtd, &flags);
+ if (rc) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+ }
+
+ /* send EOS */
+ prtd->cmd_ack = 0;
+ atomic_set(&prtd->eos, 1);
+ q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ pr_info("PARTIAL DRAIN, do not wait for EOS ack\n");
+
+ /* send a zero length buffer */
+ atomic_set(&prtd->xrun, 0);
+ msm_compr_send_buffer(prtd);
+
+ /* wait for the zero length buffer to be returned */
+ pr_debug("%s: zero length buffer drain\n", __func__);
+ rc = msm_compr_drain_buffer(prtd, &flags);
+ if (rc) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+
+ /* sleep for additional duration partial drain */
+ atomic_set(&prtd->drain, 1);
+ prtd->drain_ready = 0;
+ pr_debug("%s, additional sleep: %d\n", __func__,
+ prtd->partial_drain_delay);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ rc = wait_event_timeout(prtd->drain_wait,
+ prtd->drain_ready || prtd->cmd_interrupt,
+ msecs_to_jiffies(prtd->partial_drain_delay));
+ pr_debug("%s: out of additional wait for low sample rate\n",
+ __func__);
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (prtd->cmd_interrupt) {
+ pr_debug("%s: additional wait interrupted by flush)\n",
+ __func__);
+ rc = -EINTR;
+ prtd->cmd_interrupt = 0;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+
+ /* move to next stream and reset vars */
+ pr_debug("%s: Moving to next stream in gapless\n", __func__);
+ ac->stream_id ^= 1;
+ prtd->byte_offset = 0;
+ prtd->app_pointer = 0;
+ prtd->first_buffer = 1;
+ prtd->last_buffer = 0;
+ /*
+ Don't reset these as these vars map to
+ total_bytes_transferred and total_bytes_available
+ directly, only total_bytes_transferred will be updated
+ in the next avail() ioctl
+ prtd->copied_total = 0;
+ prtd->bytes_received = 0;
+ */
+ atomic_set(&prtd->drain, 0);
+ atomic_set(&prtd->xrun, 1);
+ pr_debug("%s: issue CMD_RUN", __func__);
+ q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
spin_unlock_irqrestore(&prtd->lock, flags);
break;
}
-
+ /*
+ moving to next stream failed, so reset the gapless state
+ set next stream id for the same session so that the same
+ stream can be used for gapless playback
+ */
+ prtd->gapless_state.set_next_stream_id = false;
pr_debug("%s: CMD_EOS\n", __func__);
prtd->cmd_ack = 0;
+ atomic_set(&prtd->eos, 1);
q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
spin_unlock_irqrestore(&prtd->lock, flags);
-/*
- if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN) {
- pr_err("PARTIAL DRAIN, do not wait for EOS ack");
- break;
- }
-*/
/* Wait indefinitely for DRAIN. Flush can also signal this*/
rc = wait_event_interruptible(prtd->eos_wait,
@@ -754,6 +968,10 @@
/*FIXME : what if a flush comes while PC is here */
if (rc == 0 && (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN)) {
+ /*
+ * Failed to open second stream in DSP for gapless
+ * so prepare the current stream in session for gapless playback
+ */
spin_lock_irqsave(&prtd->lock, flags);
pr_debug("%s: issue CMD_PAUSE ", __func__);
q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
@@ -765,27 +983,55 @@
prtd->cmd_ack, 1 * HZ / 4);
spin_lock_irqsave(&prtd->lock, flags);
+ /*
+ Don't reset these as these vars map to
+ total_bytes_transferred and total_bytes_available
+ directly, only total_bytes_transferred will be updated
+ in the next avail() ioctl
+ prtd->copied_total = 0;
+ prtd->bytes_received = 0;
+ */
prtd->byte_offset = 0;
prtd->app_pointer = 0;
- /* Don't reset these as these vars map
- to total_bytes_transferred and total_bytes_available directly,
- only total_bytes_transferred will be updated in the next avail()
- ioctl
- prtd->copied_total = 0;
- prtd->bytes_received = 0;
- */
+ prtd->first_buffer = 1;
+ prtd->last_buffer = 0;
atomic_set(&prtd->drain, 0);
atomic_set(&prtd->xrun, 1);
- pr_debug("%s: issue CMD_RESUME", __func__);
q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
spin_unlock_irqrestore(&prtd->lock, flags);
}
- pr_debug("%s: out of drain", __func__);
-
prtd->cmd_interrupt = 0;
break;
case SND_COMPR_TRIGGER_NEXT_TRACK:
pr_debug("%s: SND_COMPR_TRIGGER_NEXT_TRACK\n", __func__);
+ spin_lock_irqsave(&prtd->lock, flags);
+ rc = 0;
+ stream_id = ac->stream_id^1; /*next stream in gapless*/
+ if (prtd->gapless_state.stream_opened[stream_id]) {
+ pr_debug("next session is already in opened state\n");
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ rc = q6asm_stream_open_write_v2(prtd->audio_client,
+ prtd->codec, 16,
+ stream_id,
+ true /*gapless*/);
+ if (rc < 0) {
+ pr_err("%s: Session out open failed for gapless\n",
+ __func__);
+ break;
+ }
+ rc = msm_compr_send_media_format_block(cstream, stream_id);
+ if (rc < 0) {
+ pr_err("%s, failed to send media format block\n",
+ __func__);
+ break;
+ }
+ spin_lock_irqsave(&prtd->lock, flags);
+ prtd->gapless_state.stream_opened[stream_id] = 1;
+ prtd->gapless_state.set_next_stream_id = true;
+ spin_unlock_irqrestore(&prtd->lock, flags);
break;
}
@@ -799,7 +1045,7 @@
struct msm_compr_audio *prtd = runtime->private_data;
struct snd_compr_tstamp tstamp;
uint64_t timestamp = 0;
- int rc = 0;
+ int rc = 0, first_buffer;
unsigned long flags;
pr_debug("%s\n", __func__);
@@ -809,13 +1055,14 @@
tstamp.sampling_rate = prtd->sample_rate;
tstamp.byte_offset = prtd->byte_offset;
tstamp.copied_total = prtd->copied_total;
+ first_buffer = prtd->first_buffer;
spin_unlock_irqrestore(&prtd->lock, flags);
/*
Query timestamp from DSP if some data is with it.
This prevents timeouts.
*/
- if (prtd->copied_total) {
+ if (!first_buffer) {
rc = q6asm_get_session_time(prtd->audio_client, ×tamp);
if (rc < 0) {
pr_err("%s: Get Session Time return value =%lld\n",
@@ -991,15 +1238,24 @@
static int msm_compr_set_metadata(struct snd_compr_stream *cstream,
struct snd_compr_metadata *metadata)
{
+ struct msm_compr_audio *prtd;
+ struct audio_client *ac;
pr_debug("%s\n", __func__);
if (!metadata || !cstream)
return -EINVAL;
+ prtd = cstream->runtime->private_data;
+ if (!prtd && !prtd->audio_client)
+ return -EINVAL;
+
+ ac = prtd->audio_client;
if (metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) {
pr_debug("%s, got encoder padding %u", __func__, metadata->value[0]);
+ prtd->gapless_state.trailing_samples_drop = metadata->value[0];
} else if (metadata->key == SNDRV_COMPRESS_ENCODER_DELAY) {
pr_debug("%s, got encoder delay %u", __func__, metadata->value[0]);
+ prtd->gapless_state.initial_samples_drop = metadata->value[0];
}
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index d80ca19..0612805 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -40,8 +40,8 @@
#define MIN_CAPTURE_PERIOD_SIZE (128 * 2 * 4)
#define MAX_CAPTURE_PERIOD_SIZE (128 * 2 * 2 * 6 * 4)
-#define MIN_CAPTURE_NUM_PERIODS (32)
-#define MAX_CAPTURE_NUM_PERIODS (384)
+#define MIN_CAPTURE_NUM_PERIODS (32 * 4)
+#define MAX_CAPTURE_NUM_PERIODS (384 * 4)
static struct snd_pcm_hardware msm_afe_hardware_playback = {
.info = (SNDRV_PCM_INFO_MMAP |
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index af25454..97c7b5d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -48,6 +48,9 @@
#define MODE_PCM 0xC
#define MODE_4GV_NW 0xE
+#define VOIP_MODE_MAX MODE_4GV_NW
+#define VOIP_RATE_MAX 23850
+
enum format {
FORMAT_S16_LE = 2,
FORMAT_SPECIAL = 31,
@@ -153,10 +156,14 @@
uint32_t rate,
uint32_t *rate_type);
static int voip_config_vocoder(struct snd_pcm_substream *substream);
-static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_mode_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_mode_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
@@ -267,11 +274,12 @@
SOC_SINGLE_MULTI_EXT("Voip Rx Gain", SND_SOC_NOPM, 0,
MAX_RAMP_DURATION,
0, 2, NULL, msm_voip_gain_put),
- SOC_SINGLE_MULTI_EXT("Voip Mode Rate Config", SND_SOC_NOPM, 0, 23850,
- 0, 2, msm_voip_mode_rate_config_get,
- msm_voip_mode_rate_config_put),
+ SOC_SINGLE_EXT("Voip Mode Config", SND_SOC_NOPM, 0, VOIP_MODE_MAX, 0,
+ msm_voip_mode_config_get, msm_voip_mode_config_put),
+ SOC_SINGLE_EXT("Voip Rate Config", SND_SOC_NOPM, 0, VOIP_RATE_MAX, 0,
+ msm_voip_rate_config_get, msm_voip_rate_config_put),
SOC_SINGLE_MULTI_EXT("Voip Evrc Min Max Rate Config", SND_SOC_NOPM,
- 0, 4, 0, 2, msm_voip_evrc_min_max_rate_config_get,
+ 0, VOC_1_RATE, 0, 2, msm_voip_evrc_min_max_rate_config_get,
msm_voip_evrc_min_max_rate_config_put),
SOC_SINGLE_EXT("Voip Dtx Mode", SND_SOC_NOPM, 0, 1, 0,
msm_voip_dtx_mode_get, msm_voip_dtx_mode_put),
@@ -439,6 +447,8 @@
list_add_tail(&buf_node->list, &prtd->free_in_queue);
}
}
+ pr_debug("%s: frame.pktlen=%d\n", __func__, buf_node->frame.pktlen);
+
prtd->pcm_playback_irq_pos += prtd->pcm_count;
spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
snd_pcm_period_elapsed(prtd->playback_substream);
@@ -800,26 +810,20 @@
uint32_t evrc_min_rate_type = 0;
uint32_t evrc_max_rate_type = 0;
- if ((runtime->format != FORMAT_SPECIAL) &&
- ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
+ pr_debug("%s(): mode=%d, playback sample rate=%d, capture sample rate=%d\n",
+ __func__, prtd->mode, prtd->play_samp_rate, prtd->cap_samp_rate);
+
+ if ((runtime->format != FORMAT_S16_LE) && ((prtd->mode == MODE_PCM) ||
+ (prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
(prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
(prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW))) {
- pr_err("%s(): mode:%d and format:%u are not mached\n",
+ pr_err("%s(): mode:%d and format:%u are not matched\n",
__func__, prtd->mode, (uint32_t)runtime->format);
ret = -EINVAL;
goto done;
}
- if ((runtime->format != FORMAT_S16_LE) &&
- (prtd->mode == MODE_PCM)) {
- pr_err("%s(): mode:%d and format:%u are not mached\n",
- __func__, prtd->mode, (uint32_t)runtime->format);
-
- ret = -EINVAL;
- goto done;
- }
-
ret = voip_get_media_type(prtd->mode,
prtd->play_samp_rate,
&media_type);
@@ -1057,29 +1061,52 @@
return 0;
}
-static int msm_voip_mode_rate_config_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voip_mode_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
mutex_lock(&voip_info.lock);
ucontrol->value.integer.value[0] = voip_info.mode;
- ucontrol->value.integer.value[1] = voip_info.rate;
mutex_unlock(&voip_info.lock);
return 0;
}
-static int msm_voip_mode_rate_config_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int msm_voip_mode_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
mutex_lock(&voip_info.lock);
voip_info.mode = ucontrol->value.integer.value[0];
- voip_info.rate = ucontrol->value.integer.value[1];
- pr_debug("%s: mode=%d,rate=%d\n", __func__, voip_info.mode,
- voip_info.rate);
+ pr_debug("%s: mode=%d\n", __func__, voip_info.mode);
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+
+static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ ucontrol->value.integer.value[0] = voip_info.rate;
+
+ mutex_unlock(&voip_info.lock);
+
+ return 0;
+}
+
+static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ mutex_lock(&voip_info.lock);
+
+ voip_info.rate = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
mutex_unlock(&voip_info.lock);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 3785a3e..3ae5221 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -811,6 +811,10 @@
(apr_fn)q6asm_callback,\
((ac->session) << 8 | 0x0001),\
ac);
+ ac->apr2 = apr_register("ADSP", "ASM", \
+ (apr_fn)q6asm_callback,\
+ ((ac->session) << 8 | 0x0002),\
+ ac);
if (ac->apr == NULL) {
pr_err("%s Registration with APR failed\n", __func__);
@@ -1210,7 +1214,8 @@
data->token, data->payload_size, data->src_port,
data->dest_port);
if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
- (data->opcode != ASM_DATA_EVENT_EOS))
+ (data->opcode != ASM_DATA_EVENT_EOS) &&
+ (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW))
pr_debug("%s:Payload = [0x%x] status[0x%x]\n",
__func__, payload[0], payload[1]);
if (data->opcode == APR_BASIC_RSP_RESULT) {
@@ -1225,6 +1230,7 @@
data->payload_size))
break;
case ASM_SESSION_CMD_PAUSE:
+ case ASM_SESSION_CMD_SUSPEND:
case ASM_DATA_CMD_EOS:
case ASM_STREAM_CMD_CLOSE:
case ASM_STREAM_CMD_FLUSH:
@@ -1243,6 +1249,9 @@
case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_CMD_ADD_TOPOLOGIES:
+ case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
+ case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
+ case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
__func__, payload[0], payload[1]);
if (atomic_read(&ac->cmd_state) && wakeup_flag) {
@@ -1366,7 +1375,10 @@
__func__, data->opcode);
break;
case ASM_SESSION_EVENTX_OVERFLOW:
- pr_err("ASM_SESSION_EVENTX_OVERFLOW\n");
+ pr_debug("ASM_SESSION_EVENTX_OVERFLOW\n");
+ break;
+ case ASM_SESSION_EVENT_RX_UNDERFLOW:
+ pr_debug("ASM_SESSION_EVENT_RX_UNDERFLOW\n");
break;
case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
@@ -1518,11 +1530,11 @@
return ret;
}
-static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
- uint32_t pkt_size, uint32_t cmd_flg)
+static void __q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
{
- pr_debug("%s:pkt_size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
- cmd_flg, ac->session);
+ pr_debug("%s:pkt_size=%d cmd_flg=%d session=%d stream_id=%d\n",
+ __func__, pkt_size, cmd_flg, ac->session, stream_id);
if (ac->apr == NULL) {
pr_err("%s: ac->apr is NULL", __func__);
return;
@@ -1536,8 +1548,8 @@
hdr->src_domain = APR_DOMAIN_APPS;
hdr->dest_svc = APR_SVC_ASM;
hdr->dest_domain = APR_DOMAIN_ADSP;
- hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
- hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+ hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
+ hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
if (cmd_flg) {
hdr->token = ac->session;
atomic_set(&ac->cmd_state, 1);
@@ -1547,11 +1559,25 @@
return;
}
-static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
uint32_t pkt_size, uint32_t cmd_flg)
{
- pr_debug("pkt_size = %d, cmd_flg = %d, session = %d\n",
- pkt_size, cmd_flg, ac->session);
+ __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
+ return;
+}
+
+static void q6asm_stream_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg, int32_t stream_id)
+{
+ __q6asm_add_hdr(ac, hdr, pkt_size, cmd_flg, stream_id);
+ return;
+}
+
+static void __q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg, uint32_t stream_id)
+{
+ pr_debug("%s pkt_size = %d, cmd_flg = %d, session = %d stream_id=%d\n",
+ __func__, pkt_size, cmd_flg, ac->session, stream_id);
hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
APR_HDR_LEN(sizeof(struct apr_hdr)),\
APR_PKT_VER);
@@ -1563,8 +1589,8 @@
hdr->src_domain = APR_DOMAIN_APPS;
hdr->dest_svc = APR_SVC_ASM;
hdr->dest_domain = APR_DOMAIN_ADSP;
- hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
- hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+ hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
+ hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id+1);
if (cmd_flg) {
hdr->token = ac->session;
atomic_set(&ac->cmd_state, 1);
@@ -1573,6 +1599,21 @@
return;
}
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+ uint32_t pkt_size, uint32_t cmd_flg)
+{
+ __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg, ac->stream_id);
+ return;
+}
+
+static void q6asm_stream_add_hdr_async(struct audio_client *ac,
+ struct apr_hdr *hdr, uint32_t pkt_size,
+ uint32_t cmd_flg, int32_t stream_id)
+{
+ __q6asm_add_hdr_async(ac, hdr, pkt_size, cmd_flg, stream_id);
+ return;
+}
+
static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
u32 pkt_size, u32 cmd_flg, u32 token)
{
@@ -1681,7 +1722,8 @@
}
static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
- uint16_t bits_per_sample)
+ uint16_t bits_per_sample, uint32_t stream_id,
+ bool is_gapless_mode)
{
int rc = 0x00;
struct asm_stream_cmd_open_write_v3 open;
@@ -1693,14 +1735,17 @@
pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
format);
- q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+ q6asm_stream_add_hdr(ac, &open.hdr, sizeof(open), TRUE, stream_id);
open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3;
open.mode_flags = 0x00;
if (ac->perf_mode)
open.mode_flags |= ASM_ULTRA_LOW_LATENCY_STREAM_SESSION;
- else
+ else {
open.mode_flags |= ASM_LEGACY_STREAM_SESSION;
+ if (is_gapless_mode)
+ open.mode_flags |= 1 << ASM_SHIFT_GAPLESS_MODE_FLAG;
+ }
/* source endpoint : matrix */
open.sink_endpointype = ASM_END_POINT_DEVICE_MATRIX;
@@ -1759,13 +1804,23 @@
int q6asm_open_write(struct audio_client *ac, uint32_t format)
{
- return __q6asm_open_write(ac, format, 16);
+ return __q6asm_open_write(ac, format, 16, ac->stream_id,
+ false /*gapless*/);
}
int q6asm_open_write_v2(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample)
{
- return __q6asm_open_write(ac, format, bits_per_sample);
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ ac->stream_id, false /*gapless*/);
+}
+
+int q6asm_stream_open_write_v2(struct audio_client *ac, uint32_t format,
+ uint16_t bits_per_sample, int32_t stream_id,
+ bool is_gapless_mode)
+{
+ return __q6asm_open_write(ac, format, bits_per_sample,
+ stream_id, is_gapless_mode);
}
int q6asm_open_read_write(struct audio_client *ac,
@@ -1919,8 +1974,8 @@
return -EINVAL;
}
-int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
- uint32_t msw_ts, uint32_t lsw_ts)
+static int __q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
{
struct asm_session_cmd_run_v2 run;
int rc;
@@ -1929,7 +1984,7 @@
return -EINVAL;
}
pr_debug("session[%d]", ac->session);
- q6asm_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE);
+ q6asm_stream_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE, stream_id);
run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
run.flags = flags;
@@ -1947,6 +2002,17 @@
return 0;
}
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts)
+{
+ return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, ac->stream_id);
+}
+
+int q6asm_stream_run_nowait(struct audio_client *ac, uint32_t flags,
+ uint32_t msw_ts, uint32_t lsw_ts, uint32_t stream_id)
+{
+ return __q6asm_run_nowait(ac, flags, msw_ts, lsw_ts, stream_id);
+}
int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
uint32_t frames_per_buf,
@@ -2439,12 +2505,6 @@
}
-int q6asm_media_format_block_aac(struct audio_client *ac,
- struct asm_aac_cfg *cfg)
-{
- return q6asm_media_format_block_multi_aac(ac, cfg);
-}
-
static int __q6asm_media_format_block_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels,
uint16_t bits_per_sample)
@@ -2575,8 +2635,8 @@
bits_per_sample);
}
-int q6asm_media_format_block_multi_aac(struct audio_client *ac,
- struct asm_aac_cfg *cfg)
+static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg, int stream_id)
{
struct asm_aac_fmt_blk_v2 fmt;
int rc = 0;
@@ -2584,7 +2644,7 @@
pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
cfg->sample_rate, cfg->ch_cfg);
- q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2618,6 +2678,24 @@
return -EINVAL;
}
+int q6asm_media_format_block_multi_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg)
+{
+ return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
+}
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg)
+{
+ return __q6asm_media_format_block_multi_aac(ac, cfg, ac->stream_id);
+}
+
+int q6asm_stream_media_format_block_aac(struct audio_client *ac,
+ struct asm_aac_cfg *cfg, int stream_id)
+{
+ return __q6asm_media_format_block_multi_aac(ac, cfg, stream_id);
+}
+
int q6asm_media_format_block_wma(struct audio_client *ac,
void *cfg)
{
@@ -3602,7 +3680,7 @@
write.flags = (0x00000000 | (param->flags & 0x800000FF));
else
write.flags = (0x80000000 | param->flags);
-
+ write.flags |= param->last_buffer << ASM_SHIFT_LAST_BUFFER_FLAG;
write.seq_id = param->uid;
list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
buf_node = list_entry(ptr, struct asm_buffer_node,
@@ -3852,7 +3930,7 @@
return -EINVAL;
}
-int q6asm_cmd(struct audio_client *ac, int cmd)
+static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
{
struct apr_hdr hdr;
int rc;
@@ -3863,13 +3941,18 @@
pr_err("APR handle NULL\n");
return -EINVAL;
}
- q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+ q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
switch (cmd) {
case CMD_PAUSE:
pr_debug("%s:CMD_PAUSE\n", __func__);
hdr.opcode = ASM_SESSION_CMD_PAUSE;
state = &ac->cmd_state;
break;
+ case CMD_SUSPEND:
+ pr_debug("%s:CMD_SUSPEND\n", __func__);
+ hdr.opcode = ASM_SESSION_CMD_SUSPEND;
+ state = &ac->cmd_state;
+ break;
case CMD_FLUSH:
pr_debug("%s:CMD_FLUSH\n", __func__);
hdr.opcode = ASM_STREAM_CMD_FLUSH;
@@ -3936,7 +4019,18 @@
return -EINVAL;
}
-int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+int q6asm_cmd(struct audio_client *ac, int cmd)
+{
+ return __q6asm_cmd(ac, cmd, ac->stream_id);
+}
+
+int q6asm_stream_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
+{
+ return __q6asm_cmd(ac, cmd, stream_id);
+}
+
+static int __q6asm_cmd_nowait(struct audio_client *ac, int cmd,
+ uint32_t stream_id)
{
struct apr_hdr hdr;
int rc;
@@ -3945,7 +4039,7 @@
pr_err("%s:APR handle NULL\n", __func__);
return -EINVAL;
}
- q6asm_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE);
+ q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
switch (cmd) {
case CMD_PAUSE:
pr_debug("%s:CMD_PAUSE\n", __func__);
@@ -3955,6 +4049,10 @@
pr_debug("%s:CMD_EOS\n", __func__);
hdr.opcode = ASM_DATA_CMD_EOS;
break;
+ case CMD_CLOSE:
+ pr_debug("%s:CMD_CLOSE\n", __func__);
+ hdr.opcode = ASM_STREAM_CMD_CLOSE;
+ break;
default:
pr_err("%s:Invalid format[%d]\n", __func__, cmd);
goto fail_cmd;
@@ -3975,6 +4073,54 @@
return -EINVAL;
}
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+{
+ pr_debug("%s: stream_id: %d\n", __func__, ac->stream_id);
+ return __q6asm_cmd_nowait(ac, cmd, ac->stream_id);
+}
+
+int q6asm_stream_cmd_nowait(struct audio_client *ac, int cmd,
+ uint32_t stream_id)
+{
+ pr_debug("%s: stream_id: %d\n", __func__, stream_id);
+ return __q6asm_cmd_nowait(ac, cmd, stream_id);
+}
+
+int q6asm_send_meta_data(struct audio_client *ac, uint32_t initial_samples,
+ uint32_t trailing_samples)
+{
+ struct asm_data_cmd_remove_silence silence;
+ int rc = 0;
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s session[%d]", __func__, ac->session);
+ q6asm_add_hdr_async(ac, &silence.hdr, sizeof(silence), FALSE);
+
+ silence.hdr.opcode = ASM_DATA_CMD_REMOVE_INITIAL_SILENCE;
+ silence.num_samples_to_remove = initial_samples;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
+ if (rc < 0) {
+ pr_err("Commmand silence failed[%d]", rc);
+ goto fail_cmd;
+ }
+
+ silence.hdr.opcode = ASM_DATA_CMD_REMOVE_TRAILING_SILENCE;
+ silence.num_samples_to_remove = trailing_samples;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &silence);
+ if (rc < 0) {
+ pr_err("Commmand silence failed[%d]", rc);
+ goto fail_cmd;
+ }
+
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
static void q6asm_reset_buf_state(struct audio_client *ac)
{
int cnt = 0;
@@ -4034,6 +4180,35 @@
return -EINVAL;
}
+int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable)
+{
+ struct asm_session_cmd_rgstr_rx_underflow rx_underflow;
+ int rc;
+
+ if (!ac || ac->apr == NULL) {
+ pr_err("APR handle NULL\n");
+ return -EINVAL;
+ }
+ pr_debug("%s:session[%d]enable[%d]\n", __func__,
+ ac->session, enable);
+ q6asm_add_hdr_async(ac, &rx_underflow.hdr, sizeof(rx_underflow), FALSE);
+
+ rx_underflow.hdr.opcode = \
+ ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS;
+ /* tx overflow event: enable */
+ rx_underflow.enable_flag = enable;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &rx_underflow);
+ if (rc < 0) {
+ pr_err("tx overflow op[0x%x]rc[%d]\n", \
+ rx_underflow.hdr.opcode, rc);
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return -EINVAL;
+}
+
int q6asm_get_apr_service_id(int session_id)
{
pr_debug("%s\n", __func__);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 2cb3576..021d731 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3240,7 +3240,7 @@
mutex_init(&card->mutex);
mutex_init(&card->dpcm_mutex);
mutex_init(&card->dapm_power_mutex);
-
+ mutex_init(&card->dapm_mutex);
ret = snd_soc_instantiate_card(card);
if (ret != 0) {
soc_cleanup_card_debugfs(card);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 99047178..bc3f6a7 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1866,7 +1866,7 @@
#endif
/* test and update the power status of a mux widget */
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol, int change,
int mux, struct soc_enum *e)
{
@@ -1915,10 +1915,22 @@
return 0;
}
+
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int change,
+ int mux, struct soc_enum *e)
+{
+ struct snd_soc_card *card = widget->dapm->card;
+ int ret;
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ ret = soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
+ mutex_unlock(&card->dapm_mutex);
+ return ret;
+}
EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
/* test and update the power status of a mixer or switch widget */
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol, int connect)
{
struct snd_soc_dapm_path *path;
@@ -1952,6 +1964,17 @@
return 0;
}
+
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int connect)
+{
+ struct snd_soc_card *card = widget->dapm->card;
+ int ret;
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
+ mutex_unlock(&card->dapm_mutex);
+ return ret;
+}
EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
/* show dapm widget status in sys fs */
@@ -2108,6 +2131,8 @@
*/
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
{
+ int ret;
+
/*
* Suppress early reports (eg, jacks syncing their state) to avoid
* silly DAPM runs during card startup.
@@ -2115,7 +2140,10 @@
if (!dapm->card || !dapm->card->instantiated)
return 0;
- return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
+ ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_unlock(&dapm->card->dapm_mutex);
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
@@ -2279,6 +2307,7 @@
{
int i, ret;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
ret = snd_soc_dapm_add_route(dapm, route);
if (ret < 0) {
@@ -2288,6 +2317,7 @@
}
route++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
@@ -2360,12 +2390,14 @@
int i, err;
int ret = 0;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
err = snd_soc_dapm_weak_route(dapm, route);
if (err)
ret = err;
route++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
return ret;
}
@@ -2384,6 +2416,8 @@
struct snd_soc_dapm_widget *w;
unsigned int val;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+
list_for_each_entry(w, &dapm->card->widgets, list)
{
if (w->new)
@@ -2393,8 +2427,10 @@
w->kcontrols = kzalloc(w->num_kcontrols *
sizeof(struct snd_kcontrol *),
GFP_KERNEL);
- if (!w->kcontrols)
+ if (!w->kcontrols) {
+ mutex_unlock(&dapm->card->dapm_mutex);
return -ENOMEM;
+ }
}
switch(w->id) {
@@ -2434,6 +2470,7 @@
}
dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2493,6 +2530,7 @@
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
@@ -2519,7 +2557,7 @@
/* old connection must be powered down */
connect = invert ? 1 : 0;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = snd_soc_test_bits(widget->codec, reg, mask, val);
if (change) {
@@ -2535,13 +2573,13 @@
update.val = val;
widget->dapm->update = &update;
- snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
+ soc_dapm_mixer_update_power(widget, kcontrol, connect);
widget->dapm->update = NULL;
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -2590,6 +2628,7 @@
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change;
unsigned int mask, bitmask;
@@ -2610,7 +2649,7 @@
mask |= (bitmask - 1) << e->shift_r;
}
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
if (change) {
@@ -2626,13 +2665,13 @@
update.val = val;
widget->dapm->update = &update;
- snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
+ soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
widget->dapm->update = NULL;
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -2669,6 +2708,7 @@
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e =
(struct soc_enum *)kcontrol->private_value;
int change;
@@ -2678,7 +2718,7 @@
if (ucontrol->value.enumerated.item[0] >= e->max)
return -EINVAL;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = widget->value != ucontrol->value.enumerated.item[0];
if (change) {
@@ -2687,12 +2727,12 @@
widget->value = ucontrol->value.enumerated.item[0];
- snd_soc_dapm_mux_update_power(widget, kcontrol, change,
+ soc_dapm_mux_update_power(widget, kcontrol, change,
widget->value, e);
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2757,6 +2797,7 @@
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change;
unsigned int mask;
@@ -2775,7 +2816,7 @@
mask |= e->mask << e->shift_r;
}
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
if (change) {
@@ -2791,13 +2832,13 @@
update.val = val;
widget->dapm->update = &update;
- snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
+ soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
widget->dapm->update = NULL;
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2831,15 +2872,15 @@
int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
const char *pin = (const char *)kcontrol->private_value;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
ucontrol->value.integer.value[0] =
- snd_soc_dapm_get_pin_status(&codec->dapm, pin);
+ snd_soc_dapm_get_pin_status(&card->dapm, pin);
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return 0;
}
@@ -2854,20 +2895,19 @@
int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
const char *pin = (const char *)kcontrol->private_value;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
if (ucontrol->value.integer.value[0])
- snd_soc_dapm_enable_pin(&codec->dapm, pin);
+ snd_soc_dapm_enable_pin(&card->dapm, pin);
else
- snd_soc_dapm_disable_pin(&codec->dapm, pin);
+ snd_soc_dapm_disable_pin(&card->dapm, pin);
- snd_soc_dapm_sync(&codec->dapm);
+ mutex_unlock(&card->dapm_mutex);
- mutex_unlock(&codec->mutex);
-
+ snd_soc_dapm_sync(&card->dapm);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
@@ -2975,6 +3015,7 @@
{
int i, ret;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
ret = snd_soc_dapm_new_control(dapm, widget);
if (ret < 0) {
@@ -2985,6 +3026,7 @@
}
widget++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
@@ -3099,7 +3141,6 @@
mutex_lock(&codec->mutex);
soc_dapm_stream_event(&codec->dapm, stream, event);
mutex_unlock(&codec->mutex);
-
return 0;
}