Merge "msm: ipa: Bug fix in A2 service"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index 31600ca..23498e5 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -56,15 +56,15 @@
Optional child nodes
- qcom,<vdd restriction child node name>: Define the name of the child node.
- If this property exisits, qcom,vdd-rstr-reg, qcom,levels,
- qcom,min-level and qcom,freq-req need to exist, otherwise
- we return an error.
+ If this property exisits, qcom,vdd-rstr-reg, qcom,levels
+ need to exist. qcom,min-level is optional if qcom,freq-req
+ exists, otherwise it's required.
- qcom,vdd-rstr-reg: Name of the rail
- qcom,levels: Array of the level values. Unit is corner voltage for voltage request
or kHz for frequency request.
- qcom,min-level: Request this level as minimum level when disabling voltage
- restriction. Unit is corner voltage for voltage request
- or kHz for frequency request.
+ restriction. Unit is corner voltage for voltage request.
+ This will not be required if qcom,freq-req exists.
- qcom,freq-req: Flag to determine if we should restrict frequency on this rail
instead of voltage.
@@ -92,5 +92,11 @@
qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
qcom,min-level = <1>; /* No Request */
};
+
+ qcom,vdd-apps-rstr{
+ qcom,vdd-rstr-reg = "vdd_apps";
+ qcom,levels = <1881600 1958400 2265600>;
+ qcom,freq-req;
+ };
};
diff --git a/Documentation/devicetree/bindings/coresight/coresight.txt b/Documentation/devicetree/bindings/coresight/coresight.txt
index 25219cd..ce797d3 100644
--- a/Documentation/devicetree/bindings/coresight/coresight.txt
+++ b/Documentation/devicetree/bindings/coresight/coresight.txt
@@ -19,7 +19,8 @@
"arm,coresight-stm" for coresight stm trace device,
"arm,coresight-etm" for coresight etm trace devices,
"qcom,coresight-csr" for coresight csr device,
- "arm,coresight-cti" for coresight cti devices
+ "arm,coresight-cti" for coresight cti devices,
+ "qcom,coresight-hwevent" for coresight hardware event devices
- reg : physical base address and length of the register set(s) of the component
- reg-names : names corresponding to each reg property value. The reg-names that
need to be used with corresponding compatible string for a coresight device
@@ -61,6 +62,12 @@
compatible : should be "arm,coresight-cti"
reg-names : should be:
"cti<num>-base" - physical base address of cti registers
+ - for coresight hardware event devices:
+ compatible : should be "qcom,coresight-hwevent"
+ reg-names : should be:
+ "<ss-mux>" - physical base address of hardware event mux
+ control registers where <ss-mux> is subsystem mux it
+ represents
- coresight-id : unique integer identifier for the component
- coresight-name : unique descriptive name of the component
- coresight-nr-inports : number of input ports on the component
@@ -105,6 +112,7 @@
- qcom,setb-gpios-drv : active drive strength for set B gpios
- qcom,setb-gpios-pull : active pull configuration for set B gpios
- qcom,setb-gpios-dir : active direction for set B gpios
+- qcom,hwevent-clks : list of clocks required by hardware event driver
Examples:
@@ -213,3 +221,17 @@
coresight-name = "coresight-cti1";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@fdf30018 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xfdf30018 0x80>,
+ <0xf9011080 0x80>,
+ <0xfd4ab160 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+ coresight-id = <29>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ qcom,hwevent-clks = "core_mmss_clk";
+ };
diff --git a/Documentation/devicetree/bindings/input/gen_vkeys.txt b/Documentation/devicetree/bindings/input/gen_vkeys.txt
index da99e19..76cacd8 100644
--- a/Documentation/devicetree/bindings/input/gen_vkeys.txt
+++ b/Documentation/devicetree/bindings/input/gen_vkeys.txt
@@ -11,7 +11,7 @@
- qcom,panel-maxx : Maximum x-coordinate of touch panel
- qcom,panel-maxy : Maximum y-coordinate of touch panel
- qcom,key-codes : Array of key codes for virtual keys
-
+ - qcom,y-offset : Offset of y-location for virtual keys
Example:
gen-vkeys {
compatible = "qcom,gen-vkeys";
@@ -21,4 +21,5 @@
qcom,panel-maxx = <760>;
qcom,panel-maxy = <1424>;
qcom,key-codes = <158 139 102 217>;
+ qcom,y-offset = <35>;
};
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
index cc1ffc2..3c3a242 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v0.txt
@@ -11,17 +11,18 @@
- qcom,iommu-pmu-ngroups: Number of Performance Monitor Unit (PMU) groups.
- qcom,iommu-pmu-ncounters: Number of PMU counters per group.
- qcom,iommu-pmu-event-classes: List of event classes supported.
+
- List of sub nodes, one for each of the translation context banks supported.
- Each sub node has the following required properties:
+ Required properties for each sub-node:
- - reg : offset and length of the register set for the context bank.
- - interrupts : should contain the context bank interrupt.
- - qcom,iommu-ctx-mids : List of machine identifiers associated with this
- translation context.
- - label : Name of the context bank
+ - reg : offset and length of the register set for the context bank.
+ - interrupts : should contain the context bank interrupt.
+ - qcom,iommu-ctx-mids : List of machine identifiers associated with this
+ translation context.
+ - label : Name of the context bank
-Optional properties:
- - none
+ Optional properties for each sub-node:
+ - none
Example:
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 96d95da..c409ea6 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -45,6 +45,7 @@
- qcom,saftey-timer: include for safety timer use, otherwise watchdog timer will be used
- linux,default-trigger: trigger the led from external modules such as display
- qcom,default-state: default state of the led, should be "on" or "off"
+- qcom,torch-enable: set flash led to torch mode
RGB Led is a tri-colored led, Red, Blue & Green.
diff --git a/Documentation/devicetree/bindings/pil/pil-pronto.txt b/Documentation/devicetree/bindings/pil/pil-pronto.txt
index 199862f..85ccc5d 100644
--- a/Documentation/devicetree/bindings/pil/pil-pronto.txt
+++ b/Documentation/devicetree/bindings/pil/pil-pronto.txt
@@ -14,6 +14,7 @@
- vdd_pronto_pll-supply: regulator to supply pronto pll.
- qcom,firmware-name: Base name of the firmware image. Ex. "wcnss"
- qcom,gpio-err-fatal: GPIO used by the wcnss to indicate error fatal to the Apps.
+- qcom,gpio-err-ready: GPIO used by the wcnss to indicate error ready to the Apps.
- qcom,gpio-proxy-unvote: GPIO used by the wcnss to trigger proxy unvoting in
the Apps
- qcom,gpio-force-stop: GPIO used by the Apps to force the wcnss to shutdown.
@@ -32,6 +33,7 @@
/* GPIO input from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 2d20794..c3d929c 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -17,6 +17,7 @@
- vdd_mx-supply: Reference to the regulator that supplies the memory rail.
- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
- qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps.
+- qcom,gpio-err-ready: GPIO used by the modem to indicate error ready to the apps.
- qcom,gpio-proxy-unvote: GPIO used by the modem to trigger proxy unvoting in
the apps.
- qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown.
@@ -49,6 +50,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index eb62ea1..f2cfe34 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -11,9 +11,10 @@
Optional properties:
- parent-supply: phandle to the parent supply/regulator node
- - qcom,retain-mems: For Oxili GDSCs only: Presence currently denotes a hardware
- requirement to assert the forced memory retention signals
- in the core's clock branch control register.
+ - qcom,clock-names: List of string names for core clocks
+ - qcom,retain-mems: Presence denotes a hardware requirement to leave the
+ forced memory retention signals in the core's clock
+ branch control register asserted.
Example:
gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
@@ -21,4 +22,5 @@
regulator-name = "gdsc_oxili_gx";
parent-supply = <&pm8841_s4>;
reg = <0xfd8c4024 0x4>;
+ qcom,clock-names = "core_clk";
};
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 777933a..9abf54e 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -76,6 +76,8 @@
dynamically.
Supplies in this list are off by default.
+ - qcom,cdc-micbias2-headset-only: Boolean. Allow micbias 2 only to headset mic.
+
Example:
taiko_codec {
@@ -138,6 +140,7 @@
qcom,cdc-slim-ifd = "taiko-slim-ifd";
qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
qcom,cdc-dmic-sample-rate = <4800000>;
+ qcom,cdc-micbias2-headset-only;
};
Wcd9xxx audio CODEC in I2C mode
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
new file mode 100644
index 0000000..c56f06a
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -0,0 +1,609 @@
+/* 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/ "dsi-panel-sharp-qhd-video.dtsi"
+/include/ "msm8974-leds.dtsi"
+
+/ {
+ serial@f991e000 {
+ status = "ok";
+ };
+
+ qcom,mdss_dsi_sharp_qhd_video {
+ status = "ok";
+ };
+
+ qcom,hdmi_tx@fd922100 {
+ status = "ok";
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ general {
+ label = "general";
+ gpios = <&pm8941_gpios 23 0x1>;
+ linux,input-type = <1>;
+ linux,code = <102>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ bt_ar3002 {
+ compatible = "qca,ar3002";
+ qca,bt-reset-gpio = <&pm8941_gpios 34 0>;
+ };
+
+ hsic_hub {
+ compatible = "qcom,hsic-smsc-hub";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ smsc,reset-gpio = <&pm8941_gpios 8 0x00>;
+
+ hsic_host: hsic@f9a00000 {
+ compatible = "qcom,hsic-host";
+ reg = <0xf9a00000 0x400>;
+ #address-cells = <0>;
+ interrupt-parent = <&hsic_host>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 136 0
+ 1 &intc 0 148 0
+ 2 &msmgpio 144 0x8>;
+ interrupt-names = "core_irq", "async_irq", "wakeup";
+ HSIC_VDDCX-supply = <&pm8841_s2>;
+ HSIC_GDSC-supply = <&gdsc_usb_hsic>;
+ hsic,strobe-gpio = <&msmgpio 144 0x00>;
+ hsic,data-gpio = <&msmgpio 145 0x00>;
+ hsic,ignore-cal-pad-config;
+ hsic,strobe-pad-offset = <0x2050>;
+ hsic,data-pad-offset = <0x2054>;
+
+ qcom,msm-bus,name = "hsic";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <85 512 0 0>,
+ <85 512 40000 160000>;
+ };
+ };
+
+ i2c@f9923000 {
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <61 0x2>;
+ vdd_ana-supply = <&pm8941_l18>;
+ vcc_i2c-supply = <&pm8941_s3>;
+ atmel,reset-gpio = <&msmgpio 60 0x00>;
+ atmel,irq-gpio = <&msmgpio 61 0x00>;
+ atmel,panel-coords = <0 0 566 1067>;
+ atmel,display-coords = <0 0 540 960>;
+ atmel,i2c-pull-up;
+ atmel,cfg_1 {
+ atmel,family-id = <0x81>;
+ atmel,variant-id = <0x19>;
+ atmel,version = <0x10>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 38, Instance = 0 */
+ 0F 02 00 17 04 0C 00 00
+ /* Object 7, Instance = 0 */
+ 30 FF 19
+ /* Object 8, Instance = 0 */
+ 1B 00 05 01 00 00 08 08 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 13 0B 00 10 23 01 03
+ 0A 0F 01 0B 04 05 28 0A 2B 04
+ 36 02 00 00 00 00 8F 28 8F 50
+ 12 0F 32 32 02
+ /* Object 15, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00
+ /* Object 23, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ /* Object 40, Instance = 0 */
+ 00 00 00 00 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 00 03 10 30 00 00 01 00 00
+ /* Object 47, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 48, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ ];
+ };
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "atmel_mxt_ts";
+ qcom,disp-maxx = <540>;
+ qcom,disp-maxy = <960>;
+ qcom,panel-maxx = <566>;
+ qcom,panel-maxy = <1067>;
+ qcom,key-codes = <158 139 102 217>;
+ };
+
+ sound {
+ qcom,model = "apq8074-taiko-db-snd-card";
+ qcom,hdmi-audio-rx;
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "AMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Analog Mic4",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Analog Mic6",
+ "AMIC6", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Analog Mic7",
+ "DMIC1", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4",
+ "DMIC5", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic5",
+ "DMIC6", "MIC BIAS4 External",
+ "MIC BIAS4 External", "Digital Mic6";
+ };
+};
+
+&mdss_fb0 {
+ qcom,memory-reservation-size = <0x1000000>; /* size 16MB */
+};
+
+&sdcc3 {
+ qcom,sup-voltages = <2000 2000>;
+ status = "ok";
+};
+
+&pm8941_l19 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3300000>;
+ regulator-always-on;
+};
+
+&pm8941_l10 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ regulator-always-on;
+};
+
+&uart7 {
+ status = "ok";
+ qcom,tx-gpio = <&msmgpio 41 0x00>;
+ qcom,rx-gpio = <&msmgpio 42 0x00>;
+ qcom,cts-gpio = <&msmgpio 43 0x00>;
+ qcom,rfr-gpio = <&msmgpio 44 0x00>;
+};
+
+&usb3 {
+ qcom,charging-disabled;
+};
+
+&slim_msm {
+ taiko_codec {
+ qcom,cdc-micbias2-ext-cap;
+ qcom,cdc-micbias3-ext-cap;
+ };
+};
+
+&pm8941_gpios {
+ gpio@c000 { /* GPIO 1 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,src-sel = <0>;
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,src-sel = <0>;
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,src-sel = <0>;
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ /* TUSB3_HUB-RESET */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <0>; /* QPNP_PIN_PULL_30 */
+ qcom,vin-sel = <0>; /* QPNP_PIN_VIN0 VPH */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,invert = <1>; /* Keep it out of reset */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ /* HSIC_HUB-RESET */
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,pull = <5>; /* PULL_NO */
+ qcom,out-strength = <2>; /* STRENGTH_MED */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c800 { /* GPIO 9 */
+ /* GbE_RST_N */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <0>; /* QPNP_PIN_PULL_30 */
+ qcom,vin-sel = <0>; /* QPNP_PIN_VIN0 VPH */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,invert = <1>; /* Keep it out of reset */
+ qcom,master-en = <1>;
+ };
+
+ gpio@c900 { /* GPIO 10 */
+ /* SATA_RST_N */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <0>; /* QPNP_PIN_PULL_30 */
+ qcom,vin-sel = <0>; /* QPNP_PIN_VIN0 VPH */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,invert = <1>; /* Keep it out of reset */
+ qcom,master-en = <1>;
+ };
+
+ gpio@ca00 { /* GPIO 11 */
+ };
+
+ gpio@cb00 { /* GPIO 12 */
+ };
+
+ gpio@cc00 { /* GPIO 13 */
+ };
+
+ gpio@cd00 { /* GPIO 14 */
+ };
+
+ gpio@ce00 { /* GPIO 15 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@cf00 { /* GPIO 16 */
+ };
+
+ gpio@d000 { /* GPIO 17 */
+ };
+
+ gpio@d100 { /* GPIO 18 */
+ };
+
+ gpio@d200 { /* GPIO 19 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,master-en = <1>;
+ };
+
+ gpio@d300 { /* GPIO 20 */
+ };
+
+ gpio@d400 { /* GPIO 21 */
+ };
+
+ gpio@d500 { /* GPIO 22 */
+ };
+
+ gpio@d600 { /* GPIO 23 */
+ };
+
+ gpio@d700 { /* GPIO 24 */
+ };
+
+ gpio@d800 { /* GPIO 25 */
+ };
+
+ gpio@d900 { /* GPIO 26 */
+ };
+
+ gpio@da00 { /* GPIO 27 */
+ };
+
+ gpio@db00 { /* GPIO 28 */
+ };
+
+ gpio@dc00 { /* GPIO 29 */
+ qcom,pull = <0>; /* set to default pull */
+ qcom,master-en = <1>;
+ qcom,vin-sel = <2>; /* select 1.8 V source */
+ };
+
+ gpio@dd00 { /* GPIO 30 */
+ };
+
+ gpio@de00 { /* GPIO 31 */
+ };
+
+ gpio@df00 { /* GPIO 32 */
+ };
+
+ gpio@e000 { /* GPIO 33 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,invert = <1>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@e100 { /* GPIO 34 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <2>; /* QPNP_PIN_OUT_STRENGTH_MED */
+ qcom,src-sel = <0>; /* QPNP_PIN_SEL_FUNC_CONSTANT */
+ qcom,invert = <0>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@e200 { /* GPIO 35 */
+ };
+
+ gpio@e300 { /* GPIO 36 */
+ qcom,mode = <1>; /* QPNP_PIN_MODE_DIG_OUT */
+ qcom,output-type = <0>; /* QPNP_PIN_OUT_BUF_CMOS */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,out-strength = <3>; /* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <3>; /* QPNP_PIN_SEL_FUNC_2 */
+ qcom,master-en = <1>;
+ };
+};
+
+&pm8941_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8841_mpps {
+
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3*/
+ };
+
+ mpp@a300 { /* MPP 4*/
+ };
+};
+
+&spi_epm {
+ epm-adc@0 {
+ compatible = "cy,epm-adc-cy8c5568lti-114";
+ reg = <0>;
+ interrupt-parent = <&msmgpio>;
+ spi-max-frequency = <960000>;
+ qcom,channels = <31>;
+ qcom,gain = <50 50 50 50 50 100 50 50 50 50
+ 50 50 50 50 100 50 50 50 50 100
+ 50 50 50 100 50 50 50 1 1 1
+ 1>;
+ qcom,rsense = <40 10 10 25 10 1000 75 25 10 25
+ 33 500 200 10 500 100 33 200 25 100
+ 75 500 50 200 5 5 3 1 1 1
+ 1>;
+ qcom,channel-type = <0xf0000000>;
+ };
+};
+
+&spmi_bus {
+ qcom,pm8941@1 {
+ qcom,leds@d000 {
+ qcom,rgb_2 {
+ status = "ok";
+ qcom,default-state = "on";
+ qcom,turn-off-delay-ms = <1000>;
+ };
+ };
+
+ 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 = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <2>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
+ };
+ };
+};
+
+&pm8941_chg {
+ status = "ok";
+
+ qcom,chg-charging-disabled;
+
+ qcom,chg-chgr@1000 {
+ status = "ok";
+ };
+
+ qcom,chg-buck@1100 {
+ status = "ok";
+ };
+
+ qcom,chg-usb-chgpth@1300 {
+ status = "ok";
+ };
+
+ qcom,chg-dc-chgpth@1400 {
+ status = "ok";
+ };
+
+ qcom,chg-boost@1500 {
+ status = "ok";
+ };
+
+ qcom,chg-misc@1600 {
+ status = "ok";
+ };
+};
+
+&sdhc_1 {
+ vdd-supply = <&pm8941_l20>;
+ vdd-io-supply = <&pm8941_s3>;
+
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ 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,nonremovable;
+ status = "ok";
+};
+
+&sdhc_2 {
+ #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 62 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 62 0x1>;
+
+ vdd-supply = <&pm8941_l21>;
+ vdd-io-supply = <&pm8941_l13>;
+
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ 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 */
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/apq8074-v2-dragonboard.dts b/arch/arm/boot/dts/apq8074-v2-dragonboard.dts
new file mode 100644
index 0000000..5a6f5f3
--- /dev/null
+++ b/arch/arm/boot/dts/apq8074-v2-dragonboard.dts
@@ -0,0 +1,22 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "apq8074-v2.dtsi"
+/include/ "apq8074-dragonboard.dtsi"
+
+/ {
+ model = "Qualcomm APQ 8074v2 DRAGONBOARD";
+ compatible = "qcom,apq8074-dragonboard", "qcom,apq8074", "qcom,dragonboard";
+ qcom,msm-id = <184 10 0x20000>;
+};
diff --git a/arch/arm/boot/dts/apq8074-v2.dtsi b/arch/arm/boot/dts/apq8074-v2.dtsi
index 3b65236..9c93ed4 100644
--- a/arch/arm/boot/dts/apq8074-v2.dtsi
+++ b/arch/arm/boot/dts/apq8074-v2.dtsi
@@ -18,7 +18,7 @@
/include/ "msm8974-v2.dtsi"
-/ {
+&soc {
qcom,qseecom@a700000 {
compatible = "qcom,qseecom";
reg = <0x0a700000 0x500000>;
diff --git a/arch/arm/boot/dts/apq8084-ion.dtsi b/arch/arm/boot/dts/apq8084-ion.dtsi
index aac4230..ea954b8 100644
--- a/arch/arm/boot/dts/apq8084-ion.dtsi
+++ b/arch/arm/boot/dts/apq8084-ion.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/apq8084-sim.dts b/arch/arm/boot/dts/apq8084-sim.dts
index 93803dbe..e206d4d 100644
--- a/arch/arm/boot/dts/apq8084-sim.dts
+++ b/arch/arm/boot/dts/apq8084-sim.dts
@@ -22,7 +22,9 @@
aliases {
serial0 = &uart0;
};
+};
+&soc {
uart0: serial@f991f000 {
status = "ok";
};
@@ -165,3 +167,7 @@
mpp@a700 { /* MPP 8 */
};
};
+
+&usb3 {
+ qcom,skip-charger-detection;
+};
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index bc6f030..2543c40 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -11,12 +11,20 @@
*/
/include/ "skeleton.dtsi"
-/include/ "apq8084-ion.dtsi"
/ {
model = "Qualcomm APQ 8084";
compatible = "qcom,apq8084";
interrupt-parent = <&intc>;
+ soc: soc { };
+};
+
+/include/ "apq8084-ion.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
@@ -126,6 +134,73 @@
interrupt-controller;
#interrupt-cells = <3>;
};
+
+ usb3: qcom,ssusb@f9200000 {
+ compatible = "qcom,dwc-usb3-msm";
+ reg = <0xf9200000 0xfc000>,
+ <0xfd4ab000 0x4>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ interrupts = <0 133 0>;
+ interrupt-names = "hs_phy_irq";
+ ssusb_vdd_dig-supply = <&pma8084_s1>;
+ SSUSB_1p8-supply = <&pma8084_l6>;
+ hsusb_vdd_dig-supply = <&pma8084_s1>;
+ HSUSB_1p8-supply = <&pma8084_l6>;
+ HSUSB_3p3-supply = <&pma8084_l24>;
+ qcom,dwc-usb3-msm-dbm-eps = <4>;
+ qcom,vdd-voltage-level = <0 900000 1050000>;
+
+ dwc3@f9200000 {
+ compatible = "synopsys,dwc3";
+ reg = <0xf9200000 0xfc000>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 131 0>, <0 179 0>;
+ interrupt-names = "irq", "otg_irq";
+ tx-fifo-resize;
+ };
+ };
+
+ android_usb {
+ compatible = "qcom,android-usb";
+ };
+
+ qcom,ocmem@fdd00000 {
+ compatible = "qcom,msm-ocmem";
+ reg = <0xfdd00000 0x2000>,
+ <0xfdd02000 0x2000>,
+ <0xfe039000 0x400>,
+ <0xfec00000 0x200000>;
+ reg-names = "ocmem_ctrl_physical", "dm_ctrl_physical", "br_ctrl_physical", "ocmem_physical";
+ interrupts = <0 76 0 0 77 0>;
+ interrupt-names = "ocmem_irq", "dm_irq";
+ qcom,ocmem-num-regions = <0x4>;
+ qcom,ocmem-num-macros = <0x20>;
+ qcom,resource-type = <0x706d636f>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xfec00000 0x200000>;
+
+ partition@0 {
+ reg = <0x0 0x180000>;
+ qcom,ocmem-part-name = "graphics";
+ qcom,ocmem-part-min = <0x80000>;
+ };
+
+ partition@80000 {
+ reg = <0x180000 0x80000>;
+ qcom,ocmem-part-name = "lp_audio";
+ qcom,ocmem-part-min = <0x80000>;
+ };
+
+ partition@100000 {
+ reg = <0x180000 0x80000>;
+ qcom,ocmem-part-name = "video";
+ qcom,ocmem-part-min = <0x55000>;
+ };
+
+ };
};
/include/ "msm-pma8084.dtsi"
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index c0c9107..10ca8a8 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_nt35590_720p_video {
compatible = "qcom,mdss-dsi-panel";
label = "nt35590 720p video mode dsi panel";
diff --git a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
index 448d357..a27a88a 100644
--- a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_orise_720p_video {
compatible = "qcom,mdss-dsi-panel";
label = "orise 720p video mode dsi panel";
diff --git a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
index f853285..d182bac 100644
--- a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_sharp_qhd_video {
compatible = "qcom,mdss-dsi-panel";
label = "sharp QHD LS043T1LE01 video mode dsi panel";
diff --git a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
index 9a734a0..3b39dea 100644
--- a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_sim_video {
compatible = "qcom,mdss-dsi-panel";
diff --git a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
index 2937cde..82b57cd 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_dsi_toshiba_720p_video {
compatible = "qcom,mdss-dsi-panel";
diff --git a/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
new file mode 100644
index 0000000..a3718aa
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-v2-panel-truly-wvga-video.dtsi
@@ -0,0 +1,120 @@
+/* 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.
+ */
+
+/ {
+ qcom,dsi_v2_truly_wvga_video {
+ compatible = "qcom,dsi-panel-v2";
+ label = "Truly WVGA video mode dsi panel";
+ qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+ qcom,rst-gpio = <&msmgpio 41 0>;
+ qcom,mode-selection-gpio = <&msmgpio 7 0>;
+ vdda-supply = <&pm8110_l19>;
+ vddio-supply=<&pm8110_l14>;
+ qcom,mdss-pan-res = <480 800>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-dest = "display_1";
+ qcom,mdss-pan-porch-values = <40 8 160 10 2 12>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-levels = <1 255>;
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+ qcom,mdss-pan-dsi-mode = <0>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <0>;
+ qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <1>;
+ qcom,mdss-pan-dsi-dst-format = <3>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+ qcom,mdss-pan-dsi-dlane-swap = <0>;
+ qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x0>;/*todo*/
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-dsi-frame-rate = <60>;
+ qcom,panel-phy-regulatorSettings =[09 08 05 00 20 03];
+ qcom,panel-phy-timingSettings = [5D 12 0C 00 33 38
+ 10 16 1E 03 04 00];
+ qcom,panel-phy-strengthCtrl = [ff 06];
+ qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
+ qcom,panel-phy-laneConfig =
+ [80 45 00 00 01 66 /*lane0**/
+ 80 45 00 00 01 66 /*lane1*/
+ 80 45 00 00 01 66 /*lane2*/
+ 80 45 00 00 01 66 /*lane3*/
+ 40 67 00 00 01 88]; /*Clk*/
+
+ qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+ qcom,panel-on-cmds = [
+ 05 01 00 00 01 02
+ 01 00
+ 23 01 00 00 01 02
+ b0 04
+ 29 01 00 00 01 03
+ b3 02 00
+ 23 01 00 00 01 02
+ bd 00
+ 29 01 00 00 01 03
+ c0 18 66
+ 29 01 00 00 01 10
+ c1 23 31 99 21 20 00 30 28 0c 0c
+ 00 00 00 21 01
+ 29 01 00 00 01 07
+ c2 10 06 06 01 03 00
+ 29 01 00 00 01 19
+ c8 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 01 19
+ c9 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 01 19
+ ca 04 10 18 20 2e 46 3c 28 1f 18
+ 10 04 04 10 18 20 2e 46 3c 28 1f 18 10 04
+ 29 01 00 00 01 11
+ d0 29 03 ce a6 00 43 20 10 01 00
+ 01 01 00 03 01 00
+ 29 01 00 00 01 08
+ d1 18 0C 23 03 75 02 50
+ 23 01 00 00 01 02
+ d3 11
+ 29 01 00 00 01 03
+ d5 2a 2a
+ 29 01 00 00 01 03
+ de 01 41
+ 23 01 00 00 01 02
+ e6 51
+ 23 01 00 00 01 02
+ fa 03
+ 23 01 00 00 64 02
+ d6 28
+ 39 01 00 00 01 05
+ 2a 00 00 01 df
+ 39 01 00 00 01 05
+ 2b 00 00 03 1f
+ 15 01 00 00 01 02
+ 35 00
+ 39 01 00 00 01 03
+ 44 00 50
+ 15 01 00 00 01 02
+ 36 c1
+ 15 01 00 00 01 02
+ 3a 77
+ 05 01 00 00 96 02
+ 11 00
+ 05 01 00 00 64 02
+ 29 00
+ ];
+ qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+ 05 01 00 00 78 02 10 00];
+ qcom,off-cmds-dsi-state = "DSI_LP_MODE";
+ };
+};
diff --git a/arch/arm/boot/dts/mpq8092-ion.dtsi b/arch/arm/boot/dts/mpq8092-ion.dtsi
index 2cd2f7b..ee3fbc4 100644
--- a/arch/arm/boot/dts/mpq8092-ion.dtsi
+++ b/arch/arm/boot/dts/mpq8092-ion.dtsi
@@ -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
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index fc07c59..ce97d4d 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -18,7 +18,9 @@
model = "Qualcomm MPQ8092 Simulator";
compatible = "qcom,mpq8092-sim", "qcom,mpq8092";
qcom,msm-id = <126 16 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index c92dad9..4dea9e0 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -11,15 +11,24 @@
*/
/include/ "skeleton.dtsi"
-/include/ "mpq8092-iommu.dtsi"
-/include/ "msm-gdsc.dtsi"
-/include/ "mpq8092-ion.dtsi"
/ {
model = "Qualcomm MPQ8092";
compatible = "qcom,mpq8092";
interrupt-parent = <&intc>;
+ soc: soc { };
+};
+
+/include/ "mpq8092-iommu.dtsi"
+/include/ "msm-gdsc.dtsi"
+/include/ "mpq8092-ion.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
index cfd68fa..d4c5061 100644
--- a/arch/arm/boot/dts/msm-gdsc.dtsi
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,7 +13,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
gdsc_venus: qcom,gdsc@fd8c1024 {
compatible = "qcom,gdsc";
regulator-name = "gdsc_venus";
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 0c44fb5..1cc3c59 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
lpass_iommu: qcom,iommu@fd000000 {
compatible = "qcom,msm-smmu-v0";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index 71dcc6a..f495850 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
jpeg_iommu: qcom,iommu@fda64000 {
compatible = "qcom,msm-smmu-v1";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
index 689bf0f..fad9d86 100755
--- a/arch/arm/boot/dts/msm-pm8019.dtsi
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -196,6 +196,21 @@
qcom,fast-avg-setup = <0>;
};
};
+
+ pm8019_adc_tm: vadc@3400 {
+ compatible = "qcom,qpnp-adc-tm";
+ reg = <0x3400 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x34 0x0>,
+ <0x0 0x34 0x3>,
+ <0x0 0x34 0x4>;
+ interrupt-names = "eoc-int-en-set",
+ "high-thr-en-set",
+ "low-thr-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+ };
};
qcom,pm8019@1 {
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 79760c1..bce9806 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -22,6 +22,29 @@
#address-cells = <1>;
#size-cells = <1>;
+ qcom,power-on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0x0>,
+ <0x0 0x8 0x1>,
+ <0x0 0x8 0x4>;
+ interrupt-names = "kpdpwr", "resin", "resin-bark";
+ qcom,pon-dbc-delay = <15625>;
+ qcom,system-reset;
+
+ qcom,pon_1 {
+ qcom,pon-type = <0>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+
+ qcom,pon_2 {
+ qcom,pon-type = <1>;
+ qcom,pull-up = <1>;
+ linux,code = <114>;
+ };
+ };
+
pm8110_chg: qcom,charger {
spmi-dev-container;
compatible = "qcom,qpnp-charger";
@@ -260,6 +283,12 @@
};
};
+ qcom,leds@a100 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa100 0x100>;
+ label = "mpp";
+ };
+
qcom,leds@a200 {
compatible = "qcom,leds-qpnp";
reg = <0xa200 0x100>;
@@ -492,5 +521,12 @@
reg = <0x5500 0x100>;
status = "disabled";
};
+
+ qcom,vibrator@c000 {
+ compatible = "qcom,qpnp-vibrator";
+ reg = <0xc000 0x100>;
+ label = "vibrator";
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8226-bus.dtsi b/arch/arm/boot/dts/msm8226-bus.dtsi
index 3c41e9e..d87aa3e 100644
--- a/arch/arm/boot/dts/msm8226-bus.dtsi
+++ b/arch/arm/boot/dts/msm8226-bus.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm-mmss-noc@fc478000 {
compatible = "msm-bus-fabric";
reg = <0xfc478000 0x00004000>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index c47d48d..07f16b9 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
led_flash0: qcom,camera-led-flash {
cell-index = <0>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 1f7ba89..f06033e 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
led_flash0: qcom,camera-led-flash {
cell-index = <0>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 5ea02b4..47f4049 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
led_flash0: qcom,camera-led-flash {
cell-index = <0>;
diff --git a/arch/arm/boot/dts/msm8226-camera.dtsi b/arch/arm/boot/dts/msm8226-camera.dtsi
index e94459e..0dae162 100644
--- a/arch/arm/boot/dts/msm8226-camera.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera.dtsi
@@ -11,7 +11,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,msm-cam@fd8c0000 {
compatible = "qcom,msm-cam";
reg = <0xfd8c0000 0x10000>;
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index b203540..f887740 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -19,7 +19,9 @@
model = "Qualcomm MSM 8226 CDP";
compatible = "qcom,msm8226-cdp", "qcom,msm8226", "qcom,cdp";
qcom,msm-id = <145 1 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-coresight.dtsi b/arch/arm/boot/dts/msm8226-coresight.dtsi
index 993b4e6..e4a42fa 100644
--- a/arch/arm/boot/dts/msm8226-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8226-coresight.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
tmc_etr: tmc@fc322000 {
compatible = "arm,coresight-tmc";
reg = <0xfc322000 0x1000>,
diff --git a/arch/arm/boot/dts/msm8226-fluid.dts b/arch/arm/boot/dts/msm8226-fluid.dts
index d70ef6e..7b11200 100644
--- a/arch/arm/boot/dts/msm8226-fluid.dts
+++ b/arch/arm/boot/dts/msm8226-fluid.dts
@@ -17,7 +17,9 @@
model = "Qualcomm MSM 8226 FLUID";
compatible = "qcom,msm8226-fluid", "qcom,msm8226", "qcom,fluid";
qcom,msm-id = <145 3 0>;
+};
+&soc {
serial@f991f000 {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/msm8226-gpu.dtsi b/arch/arm/boot/dts/msm8226-gpu.dtsi
index bb2f0d4..d83df1e 100644
--- a/arch/arm/boot/dts/msm8226-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8226-gpu.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm_gpu: qcom,kgsl-3d0@fdb00000 {
label = "kgsl-3d0";
compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
@@ -22,8 +22,7 @@
qcom,chipid = <0x03000510>;
- qcom,initial-pwrlevel = <2>;
- qcom,step-pwrlevel = <2>;
+ qcom,initial-pwrlevel = <1>;
qcom,idle-timeout = <8>; //<HZ/12>
qcom,nap-allowed = <1>;
diff --git a/arch/arm/boot/dts/msm8226-iommu-domains.dtsi b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
index 6ea5b9e..25fca2a 100644
--- a/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
+++ b/arch/arm/boot/dts/msm8226-iommu-domains.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,iommu-domains {
compatible = "qcom,iommu-domains";
diff --git a/arch/arm/boot/dts/msm8226-ion.dtsi b/arch/arm/boot/dts/msm8226-ion.dtsi
index 9ada271..dee64e5 100644
--- a/arch/arm/boot/dts/msm8226-ion.dtsi
+++ b/arch/arm/boot/dts/msm8226-ion.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 5aa39d3..f580897 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_mdp@fd900000 {
compatible = "qcom,mdss_mdp";
reg = <0xfd900000 0x22100>,
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 1f8a773..3dd517b 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -19,7 +19,9 @@
model = "Qualcomm MSM 8226 MTP";
compatible = "qcom,msm8226-mtp", "qcom,msm8226", "qcom,mtp";
qcom,msm-id = <145 8 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index c62fb3e..3240efb 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -12,7 +12,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
#address-cells = <1>;
@@ -114,7 +114,7 @@
qcom,type = <0x61706d73>; /* "smpa" */
qcom,id = <0x01>;
qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <5>; /* Super Turbo */
+ qcom,init-value = <3>; /* SVS SOC */
};
qcom,lpm-resources@1 {
@@ -123,7 +123,7 @@
qcom,type = <0x616F646C>; /* "ldoa" */
qcom,id = <0x03>;
qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* Active */
+ qcom,init-value = <3>; /* SVS SOC */
};
qcom,lpm-resources@2 {
@@ -153,10 +153,10 @@
qcom,mode = "wfi";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <1>;
@@ -170,10 +170,10 @@
qcom,mode = "standalone_pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <3000>;
@@ -187,10 +187,10 @@
qcom,mode = "pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_retention";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <8000>;
@@ -204,10 +204,10 @@
qcom,mode = "pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <3>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <2>; /* SVS SOC */
+ qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <9000>;
@@ -221,10 +221,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,latency-us = <16300>;
qcom,ss-power = <63>;
qcom,energy-overhead = <2128000>;
@@ -236,10 +236,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <3>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <2>; /* SVS SOC */
+ qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,latency-us = <24000>;
qcom,ss-power = <10>;
qcom,energy-overhead = <3202600>;
@@ -251,10 +251,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <2>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <0>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <0>; /* RETENTION */
+ qcom,vdd-mem-upper-bound = <3>; /* SVS SOC */
+ qcom,vdd-mem-lower-bound = <1>; /* RETENTION */
+ qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
qcom,latency-us = <26000>;
qcom,ss-power = <2>;
qcom,energy-overhead = <4252000>;
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index 660fb3e..721bcbb 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -19,7 +19,9 @@
model = "Qualcomm MSM 8226 QRD";
compatible = "qcom,msm8226-qrd", "qcom,msm8226", "qcom,qrd";
qcom,msm-id = <145 11 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 70731d2..7fa9081 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -26,7 +26,7 @@
/* CPR controlled regulator */
-/ {
+&soc {
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
@@ -67,7 +67,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
- qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
+ qcom,consumer-supplies = "vdd_dig", "";
};
pm8226_s1_corner_ao: regulator-s1-corner-ao {
compatible = "qcom,rpm-regulator-smd";
@@ -76,6 +76,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
+ qcom,consumer-supplies = "vdd_sr2_dig", "";
};
};
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 00c0e2e..3cca8b0 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -18,7 +18,9 @@
model = "Qualcomm MSM 8226 Simulator";
compatible = "qcom,msm8226-sim", "qcom,msm8226", "qcom,sim";
qcom,msm-id = <145 16 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8226-smp2p.dtsi b/arch/arm/boot/dts/msm8226-smp2p.dtsi
index 079e4ca..3921a68 100644
--- a/arch/arm/boot/dts/msm8226-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8226-smp2p.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
reg = <0xf9011008 0x4>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 631d3a3..53e4392 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -11,6 +11,35 @@
*/
/include/ "skeleton.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8226";
+ compatible = "qcom,msm8226";
+ interrupt-parent = <&intc>;
+
+ aliases {
+ spi0 = &spi_0;
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+ sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+ };
+
+ memory {
+ secure_mem: secure_region {
+ linux,contiguous-region;
+ reg = <0 0x3800000>;
+ label = "secure_mem";
+ };
+
+ qsecom_mem: qsecom_region {
+ linux,contiguous-region;
+ reg = <0 0x780000>;
+ label = "qsecom_mem";
+ };
+ };
+
+ soc: soc { };
+};
+
/include/ "msm8226-ion.dtsi"
/include/ "msm8226-camera.dtsi"
/include/ "msm-gdsc.dtsi"
@@ -22,10 +51,11 @@
/include/ "msm8226-mdss.dtsi"
/include/ "msm8226-coresight.dtsi"
/include/ "msm8226-iommu-domains.dtsi"
-/ {
- model = "Qualcomm MSM 8226";
- compatible = "qcom,msm8226";
- interrupt-parent = <&intc>;
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
@@ -47,25 +77,10 @@
qcom,direct-connect-irqs = <8>;
};
- aliases {
- spi0 = &spi_0;
- sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
- sdhc2 = &sdhc_2; /* SDC2 SD card slot */
- };
-
- memory {
- secure_mem: secure_region {
- linux,contiguous-region;
- reg = <0 0x3800000>;
- label = "secure_mem";
- };
-
- qsecom_mem: qsecom_region {
- linux,contiguous-region;
- reg = <0 0x780000>;
- label = "qsecom_mem";
- };
-
+ qcom,mpm2-sleep-counter@fc4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0xfc4a3000 0x1000>;
+ clock-frequency = <32768>;
};
timer {
@@ -687,7 +702,7 @@
reg = <0xf9927000 0x1000>;
interrupt-names = "qup_err_intr";
interrupts = <0 99 0>;
- qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-bus-freq = <384000>;
qcom,i2c-src-freq = <19200000>;
};
@@ -744,6 +759,7 @@
/* GPIO inputs from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
@@ -796,6 +812,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
@@ -963,22 +980,27 @@
};
&gdsc_venus {
+ qcom,clock-names = "core_clk";
status = "ok";
};
&gdsc_mdss {
+ qcom,clock-names = "core_clk", "lut_clk";
status = "ok";
};
&gdsc_jpeg {
+ qcom,clock-names = "core_clk";
status = "ok";
};
&gdsc_vfe {
+ qcom,clock-names = "core_clk", "csi_clk", "cpp_clk";
status = "ok";
};
&gdsc_oxili_cx {
+ qcom,clock-names = "core_clk";
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index 50066f3..2e7ba25 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm-mmss-noc@fc478000 {
compatible = "msm-bus-fabric";
reg = <0xfc478000 0x00004000>;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dts
index 84eebbf..1bf7c2b 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -13,26 +13,150 @@
/dts-v1/;
/include/ "msm8610.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
/ {
model = "Qualcomm MSM 8610 CDP";
compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
<163 1 0>, <164 1 0>, <166 1 0>;
+};
+&soc {
serial@f991e000 {
status = "ok";
};
+
+ i2c@f9923000{
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2>;
+ vdd_ana-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ atmel,reset-gpio = <&msmgpio 0 0x00>;
+ atmel,irq-gpio = <&msmgpio 1 0x00>;
+ atmel,panel-coords = <0 0 508 880>;
+ atmel,display-coords = <0 0 480 800>;
+ atmel,i2c-pull-up;
+ atmel,no-force-update;
+ atmel,cfg_1 {
+ atmel,family-id = <0x81>;
+ atmel,variant-id = <0x15>;
+ atmel,version = <0x11>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 1D 01 00 0C 04 0D 00 00
+ /* Object 7, Instance = 0 */
+ 20 08 32
+ /* Object 8, Instance = 0 */
+ 19 00 14 14 FF 00 FF 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 13 0B 00 20 32 01 03
+ 00 32 05 30 0A 05 0A 00 70 03
+ FC 01 00 36 2F 2C 00 00 40 00
+ 00 0A 00 00 02
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 03 00 18 79 A8 61
+ /* Object 58, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 04 03 08 10 00 00 00 00 00
+ /* Object 47, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 48, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00
+ ];
+ };
+ };
+ };
+};
+
+&i2c_cdc {
+ msm8x10_wcd_codec@0d{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x0d>;
+ cdc-vdda-cp-supply = <&pm8110_s4>;
+ qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-current = <650000>;
+
+ cdc-vdda-h-supply = <&pm8110_l6>;
+ qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdda-h-current = <250000>;
+
+ cdc-vdd-px-supply = <&pm8110_l6>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-1p2v-supply = <&pm8110_l4>;
+ qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-1p2v-current = <5000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <25000>;
+
+ qcom,cdc-micbias-cfilt-sel = <0x0>;
+ qcom,cdc-micbias-cfilt-mv = <1800000>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+ };
+
+ msm8x10_wcd_codec@77{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x77>;
+ };
+
+ msm8x10_wcd_codec@66{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x66>;
+ };
+
+ msm8x10_wcd_codec@55{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x55>;
+ };
};
&spmi_bus {
qcom,pm8110@0 {
+ 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,max-current = <40>;
+ qcom,id = <6>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
qcom,leds@a200 {
status = "okay";
qcom,led_mpp_3 {
label = "mpp";
linux,name = "wled-backlight";
- linux-default-trigger = "none";
+ linux,default-trigger = "bkl-trigger";
qcom,default-state = "on";
qcom,max-current = <40>;
qcom,id = <6>;
@@ -75,6 +199,27 @@
};
};
+&spmi_bus {
+ qcom,pm8110@1 {
+ qcom,vibrator@c000 {
+ status = "okay";
+ qcom,vib-timeout-ms = <15000>;
+ qcom,vib-vtg-level-mV = <3100>;
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "atmel_mxt_ts";
+ qcom,disp-maxx = <480>;
+ qcom,disp-maxy = <800>;
+ qcom,panel-maxx = <508>;
+ qcom,panel-maxy = <880>;
+ qcom,key-codes = <158 102 139>;
+ qcom,y-offset = <35>;
+ };
+};
+
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
qcom,vdd-always-on;
@@ -152,3 +297,33 @@
status = "ok";
};
};
+
+&pm8110_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+};
+
+&pm8110_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ status = "disabled";
+ };
+
+ mpp@a200 { /* MPP 3 */
+ status = "disabled";
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index a0a2c14..4945693 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
tmc_etr: tmc@fc326000 {
compatible = "arm,coresight-tmc";
reg = <0xfc326000 0x1000>,
diff --git a/arch/arm/boot/dts/msm8610-gpu.dtsi b/arch/arm/boot/dts/msm8610-gpu.dtsi
index 5580f73..d1b30ee 100644
--- a/arch/arm/boot/dts/msm8610-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8610-gpu.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm_gpu: qcom,kgsl-3d0@fdc00000 {
label = "kgsl-3d0";
compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
diff --git a/arch/arm/boot/dts/msm8610-iommu-domains.dtsi b/arch/arm/boot/dts/msm8610-iommu-domains.dtsi
index 0f48517..6f43897 100644
--- a/arch/arm/boot/dts/msm8610-iommu-domains.dtsi
+++ b/arch/arm/boot/dts/msm8610-iommu-domains.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,iommu-domains {
compatible = "qcom,iommu-domains";
diff --git a/arch/arm/boot/dts/msm8610-ion.dtsi b/arch/arm/boot/dts/msm8610-ion.dtsi
index 7d7d8fd..456b60c 100644
--- a/arch/arm/boot/dts/msm8610-ion.dtsi
+++ b/arch/arm/boot/dts/msm8610-ion.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
index 42fa149..1766422 100644
--- a/arch/arm/boot/dts/msm8610-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_mdp@fd900000 {
compatible = "qcom,mdss_mdp3";
reg = <0xfd900000 0x100000>;
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 90d4a0e..3fbc820 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -13,26 +13,150 @@
/dts-v1/;
/include/ "msm8610.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
/ {
model = "Qualcomm MSM 8610 MTP";
compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
<163 8 0>, <164 8 0>, <166 8 0>;
+};
+&soc {
serial@f991e000 {
status = "ok";
};
+
+ i2c@f9923000{
+ atmel_mxt_ts@4a {
+ compatible = "atmel,mxt-ts";
+ reg = <0x4a>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <1 0x2>;
+ vdd_ana-supply = <&pm8110_l19>;
+ vcc_i2c-supply = <&pm8110_l14>;
+ atmel,reset-gpio = <&msmgpio 0 0x00>;
+ atmel,irq-gpio = <&msmgpio 1 0x00>;
+ atmel,panel-coords = <0 0 508 880>;
+ atmel,display-coords = <0 0 480 800>;
+ atmel,i2c-pull-up;
+ atmel,no-force-update;
+ atmel,cfg_1 {
+ atmel,family-id = <0x81>;
+ atmel,variant-id = <0x15>;
+ atmel,version = <0x11>;
+ atmel,build = <0xaa>;
+ atmel,config = [
+ /* Object 6, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 38, Instance = 0 */
+ 1D 01 00 0C 04 0D 00 00
+ /* Object 7, Instance = 0 */
+ 20 08 32
+ /* Object 8, Instance = 0 */
+ 19 00 14 14 FF 00 FF 00 00 00
+ /* Object 9, Instance = 0 */
+ 83 00 00 13 0B 00 20 32 01 03
+ 00 32 05 30 0A 05 0A 00 70 03
+ FC 01 00 36 2F 2C 00 00 40 00
+ 00 0A 00 00 02
+ /* Object 18, Instance = 0 */
+ 00 00
+ /* Object 19, Instance = 0 */
+ 00 00 00 00 00 00
+ /* Object 25, Instance = 0 */
+ 03 00 18 79 A8 61
+ /* Object 58, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00
+ /* Object 42, Instance = 0 */
+ 00 00 00 00 00 00 00 00
+ /* Object 46, Instance = 0 */
+ 04 03 08 10 00 00 00 00 00
+ /* Object 47, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ /* Object 48, Instance = 0 */
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00
+ /* Object 55, Instance = 0 */
+ 00 00 00 00
+ ];
+ };
+ };
+ };
+};
+
+&i2c_cdc {
+ msm8x10_wcd_codec@0d{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x0d>;
+ cdc-vdda-cp-supply = <&pm8110_s4>;
+ qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-current = <650000>;
+
+ cdc-vdda-h-supply = <&pm8110_l6>;
+ qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdda-h-current = <250000>;
+
+ cdc-vdd-px-supply = <&pm8110_l6>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-1p2v-supply = <&pm8110_l4>;
+ qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-1p2v-current = <5000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <25000>;
+
+ qcom,cdc-micbias-cfilt-sel = <0x0>;
+ qcom,cdc-micbias-cfilt-mv = <1800000>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+ };
+
+ msm8x10_wcd_codec@77{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x77>;
+ };
+
+ msm8x10_wcd_codec@66{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x66>;
+ };
+
+ msm8x10_wcd_codec@55{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x55>;
+ };
};
&spmi_bus {
qcom,pm8110@0 {
+ 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,max-current = <40>;
+ qcom,id = <6>;
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
qcom,leds@a200 {
status = "okay";
qcom,led_mpp_3 {
label = "mpp";
linux,name = "wled-backlight";
- linux-default-trigger = "none";
+ linux,default-trigger = "bkl-trigger";
qcom,default-state = "on";
qcom,max-current = <40>;
qcom,id = <6>;
@@ -75,6 +199,27 @@
};
};
+&spmi_bus {
+ qcom,pm8110@1 {
+ qcom,vibrator@c000 {
+ status = "okay";
+ qcom,vib-timeout-ms = <15000>;
+ qcom,vib-vtg-level-mV = <3100>;
+ };
+ };
+
+ gen-vkeys {
+ compatible = "qcom,gen-vkeys";
+ label = "atmel_mxt_ts";
+ qcom,disp-maxx = <480>;
+ qcom,disp-maxy = <800>;
+ qcom,panel-maxx = <508>;
+ qcom,panel-maxy = <880>;
+ qcom,key-codes = <158 102 139>;
+ qcom,y-offset = <35>;
+ };
+};
+
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
qcom,vdd-always-on;
@@ -155,3 +300,33 @@
status = "ok";
};
};
+
+&pm8110_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+};
+
+&pm8110_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ status = "disabled";
+ };
+
+ mpp@a200 { /* MPP 3 */
+ status = "disabled";
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index baae269..938b2aa 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -12,7 +12,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
#address-cells = <1>;
@@ -114,7 +114,7 @@
qcom,type = <0x61706d73>; /* "smpa" */
qcom,id = <0x01>;
qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <5>; /* Super Turbo */
+ qcom,init-value = <3>; /* SVS SOC */
};
qcom,lpm-resources@1 {
@@ -123,7 +123,7 @@
qcom,type = <0x616F646C>; /* "ldoa" */
qcom,id = <0x03>;
qcom,key = <0x6e726f63>; /* "corn" */
- qcom,init-value = <3>; /* Active */
+ qcom,init-value = <3>; /* SVS SOC */
};
qcom,lpm-resources@2 {
@@ -153,10 +153,10 @@
qcom,mode = "wfi";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <1>;
@@ -170,10 +170,10 @@
qcom,mode = "standalone_pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_active";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <3000>;
@@ -187,10 +187,10 @@
qcom,mode = "pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_retention";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <8000>;
@@ -204,10 +204,10 @@
qcom,mode = "pc";
qcom,xo = "xo_on";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <3>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <2>; /* SVS SOC */
+ qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,irqs-detectable;
qcom,gpio-detectable;
qcom,latency-us = <9000>;
@@ -221,10 +221,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-mem-lower-bound = <3>; /* NORMAL */
- qcom,vdd-dig-upper-bound = <5>; /* SUPER TURBO */
- qcom,vdd-dig-lower-bound = <3>; /* NORMAL */
+ qcom,vdd-mem-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-mem-lower-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-upper-bound = <6>; /* SUPER TURBO */
+ qcom,vdd-dig-lower-bound = <4>; /* NORMAL */
qcom,latency-us = <16300>;
qcom,ss-power = <63>;
qcom,energy-overhead = <2128000>;
@@ -236,10 +236,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <3>; /* NORMAL */
- qcom,vdd-mem-lower-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-upper-bound = <3>; /* NORMAL */
- qcom,vdd-dig-lower-bound = <2>; /* SVS SOC */
+ qcom,vdd-mem-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-mem-lower-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-upper-bound = <4>; /* NORMAL */
+ qcom,vdd-dig-lower-bound = <3>; /* SVS SOC */
qcom,latency-us = <24000>;
qcom,ss-power = <10>;
qcom,energy-overhead = <3202600>;
@@ -251,10 +251,10 @@
qcom,mode = "pc";
qcom,xo = "xo_off";
qcom,l2 = "l2_cache_pc";
- qcom,vdd-mem-upper-bound = <2>; /* SVS SOC */
- qcom,vdd-mem-lower-bound = <0>; /* RETENTION */
- qcom,vdd-dig-upper-bound = <2>; /* SVS SOC */
- qcom,vdd-dig-lower-bound = <0>; /* RETENTION */
+ qcom,vdd-mem-upper-bound = <3>; /* SVS SOC */
+ qcom,vdd-mem-lower-bound = <1>; /* RETENTION */
+ qcom,vdd-dig-upper-bound = <3>; /* SVS SOC */
+ qcom,vdd-dig-lower-bound = <1>; /* RETENTION */
qcom,latency-us = <26000>;
qcom,ss-power = <2>;
qcom,energy-overhead = <4252000>;
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index 67eee5c..3df428a 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -26,7 +26,7 @@
/* CPR controlled regulator */
-/ {
+&soc {
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
@@ -44,6 +44,9 @@
qcom,pvs-corner-ceiling-nom = <975000 1075000 1200000 1200000>;
qcom,pvs-corner-ceiling-fast = <900000 1000000 1140000 1140000>;
vdd-apc-supply = <&pm8110_s2>;
+ vdd-mx-supply = <&pm8110_l3_ao>;
+ qcom,vdd-mx-vmax = <1350000>;
+ qcom,vdd-mx-vmin-method = <1>;
};
};
@@ -66,7 +69,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
- qcom,consumer-supplies = "vdd_dig", "", "vdd_sr2_dig", "";
+ qcom,consumer-supplies = "vdd_dig", "";
};
pm8110_s1_corner_ao: regulator-s1-corner-ao {
@@ -76,6 +79,7 @@
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,use-voltage-corner;
+ qcom,consumer-supplies = "vdd_sr2_dig", "";
};
};
diff --git a/arch/arm/boot/dts/msm8610-rumi.dts b/arch/arm/boot/dts/msm8610-rumi.dts
index cab7560..7f06485 100644
--- a/arch/arm/boot/dts/msm8610-rumi.dts
+++ b/arch/arm/boot/dts/msm8610-rumi.dts
@@ -18,7 +18,9 @@
model = "Qualcomm MSM 8610 Rumi";
compatible = "qcom,msm8610-rumi", "qcom,msm8610", "qcom,rumi";
qcom,msm-id = <147 15 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8610-sim.dts b/arch/arm/boot/dts/msm8610-sim.dts
index 1838b94..7c57fe6 100644
--- a/arch/arm/boot/dts/msm8610-sim.dts
+++ b/arch/arm/boot/dts/msm8610-sim.dts
@@ -18,8 +18,55 @@
model = "Qualcomm MSM 8610 Simulator";
compatible = "qcom,msm8610-sim", "qcom,msm8610", "qcom,sim";
qcom,msm-id = <147 16 0>;
+};
+&soc {
serial@f991f000 {
status = "ok";
};
};
+
+&i2c_cdc {
+ msm8x10_wcd_codec@0d{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x0d>;
+ cdc-vdda-cp-supply = <&pm8110_s4>;
+ qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
+ qcom,cdc-vdda-cp-current = <650000>;
+
+ cdc-vdda-h-supply = <&pm8110_l6>;
+ qcom,cdc-vdda-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdda-h-current = <250000>;
+
+ cdc-vdd-px-supply = <&pm8110_l6>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-1p2v-supply = <&pm8110_l4>;
+ qcom,cdc-vdd-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-1p2v-current = <5000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8110_l20>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <25000>;
+
+ qcom,cdc-micbias-cfilt-sel = <0x0>;
+ qcom,cdc-micbias-cfilt-mv = <1800000>;
+ qcom,cdc-mclk-clk-rate = <12288000>;
+ };
+
+ msm8x10_wcd_codec@77{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x77>;
+ };
+
+ msm8x10_wcd_codec@66{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x66>;
+ };
+
+ msm8x10_wcd_codec@55{
+ compatible = "qcom,msm8x10-wcd-i2c";
+ reg = <0x55>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-smp2p.dtsi b/arch/arm/boot/dts/msm8610-smp2p.dtsi
index 079e4ca..3921a68 100644
--- a/arch/arm/boot/dts/msm8610-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8610-smp2p.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
reg = <0xf9011008 0x4>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 84fe7d2..4b861ed 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -11,6 +11,28 @@
*/
/include/ "skeleton.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610";
+ compatible = "qcom,msm8610";
+ interrupt-parent = <&intc>;
+
+ memory {
+ qsecom_mem: qsecom_region {
+ linux,contiguous-region;
+ reg = <0 0x100000>;
+ label = "qsecom_mem";
+ };
+ };
+
+ aliases {
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+ sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+ };
+
+ soc: soc { };
+};
+
/include/ "msm-iommu-v0.dtsi"
/include/ "msm8610-ion.dtsi"
/include/ "msm8610-gpu.dtsi"
@@ -21,10 +43,10 @@
/include/ "msm8610-bus.dtsi"
/include/ "msm8610-mdss.dtsi"
-/ {
- model = "Qualcomm MSM 8610";
- compatible = "qcom,msm8610";
- interrupt-parent = <&intc>;
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
@@ -46,20 +68,10 @@
qcom,direct-connect-irqs = <8>;
};
- memory {
-
- qsecom_mem: qsecom_region {
- linux,contiguous-region;
- reg = <0 0x100000>;
- label = "qsecom_mem";
- };
-
- };
-
- aliases {
- spi0 = &spi_0;
- sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
- sdhc2 = &sdhc_2; /* SDC2 SD card slot */
+ qcom,mpm2-sleep-counter@fc4a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0xfc4a3000 0x1000>;
+ clock-frequency = <32768>;
};
timer {
@@ -159,7 +171,7 @@
qcom,buffer-type-tz-usage-map = <0x1 0x1>,
<0x1fe 0x2>;
qcom,hfi = "q6";
- qcom,max-hw-load = <97200>; /* FWVGA @ 30 * 2 */
+ qcom,max-hw-load = <108000>; /* 720p @ 30 * 1 */
};
qcom,usbbam@f9a44000 {
@@ -428,18 +440,33 @@
qcom,pmic-arb-channel = <0>;
};
- i2c@f9925000 { /* BLSP-1 QUP-3 */
- cell-index = <0>;
+ i2c@f9923000 { /* BLSP-1 QUP-1 */
+ cell-index = <1>;
compatible = "qcom,i2c-qup";
#address-cells = <1>;
#size-cells = <0>;
reg-names = "qup_phys_addr";
- reg = <0xf9925000 0x1000>;
+ reg = <0xf9923000 0x1000>;
interrupt-names = "qup_err_intr";
- interrupts = <0 97 0>;
+ interrupts = <0 95 0>;
qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,sda-gpio = <&msmgpio 2 0>;
+ qcom,scl-gpio = <&msmgpio 3 0>;
};
+ i2c_cdc: i2c@f9927000 { /* BLSP1 QUP5 */
+ cell-index = <5>;
+ compatible = "qcom,i2c-qup";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0xf9927000 0x1000>;
+ interrupt-names = "qup_err_intr";
+ interrupts = <0 99 0>;
+ qcom,i2c-bus-freq = <100000>;
+ };
+
i2c@f9928000 { /* BLSP1 QUP6 */
cell-index = <6>;
compatible = "qcom,i2c-qup";
@@ -455,27 +482,16 @@
qcom,scl-gpio = <&msmgpio 17 0>;
};
- spi_0: spi@f9923000 { /* BLSP1 QUP1 */
- compatible = "qcom,spi-qup-v2";
+ i2c@f9925000 { /* BLSP-1 QUP-3 */
+ cell-index = <0>;
+ compatible = "qcom,i2c-qup";
#address-cells = <1>;
#size-cells = <0>;
- reg-names = "spi_physical", "spi_bam_physical";
- reg = <0xf9923000 0x1000>,
- <0xf9904000 0xF000>;
- interrupt-names = "spi_irq", "spi_bam_irq";
- interrupts = <0 95 0>, <0 238 0>;
- spi-max-frequency = <19200000>;
-
- gpios = <&msmgpio 3 0>, /* CLK */
- <&msmgpio 1 0>, /* MISO */
- <&msmgpio 0 0>; /* MOSI */
- cs-gpios = <&msmgpio 2 0>;
-
- qcom,infinite-mode = <0>;
- qcom,use-bam;
- qcom,ver-reg-exists;
- qcom,bam-consumer-pipe-index = <12>;
- qcom,bam-producer-pipe-index = <13>;
+ reg-names = "qup_phys_addr";
+ reg = <0xf9925000 0x1000>;
+ interrupt-names = "qup_err_intr";
+ interrupts = <0 97 0>;
+ qcom,i2c-bus-freq = <100000>;
};
qcom,pronto@fb21b000 {
@@ -491,6 +507,7 @@
/* GPIO inputs from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
@@ -508,6 +525,13 @@
qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
};
qcom,msm-pcm-routing {
@@ -547,15 +571,15 @@
qcom,msm-dai-q6-mi2s-prim {
compatible = "qcom,msm-dai-q6-mi2s";
qcom,msm-dai-q6-mi2s-dev-id = <0>;
- qcom,msm-mi2s-rx-lines = <1>;
- qcom,msm-mi2s-tx-lines = <0>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
};
qcom,msm-dai-q6-mi2s-sec {
compatible = "qcom,msm-dai-q6-mi2s";
qcom,msm-dai-q6-mi2s-dev-id = <1>;
- qcom,msm-mi2s-rx-lines = <0>;
- qcom,msm-mi2s-tx-lines = <3>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
};
};
@@ -600,6 +624,21 @@
compatible = "qcom,msm-dai-q6-dev";
qcom,msm-dai-q6-dev-id = <240>;
};
+
+ qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
};
qcom,msm-pcm-hostless {
@@ -648,6 +687,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
@@ -731,6 +771,12 @@
qcom,msm-rng-iface-clk;
};
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,memory-reservation-type = "EBI1";
+ qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
+ };
+
jtag_mm0: jtagmm@fc34c000 {
compatible = "qcom,jtag-mm";
reg = <0xfc34c000 0x1000>,
@@ -819,7 +865,7 @@
label = "vchg_sns";
reg = <2>;
qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <3>;
+ qcom,pre-div-channel-scaling = <2>;
qcom,calibration-type = "absolute";
qcom,scale-function = <0>;
qcom,hw-settle-time = <0>;
diff --git a/arch/arm/boot/dts/msm8974-bus.dtsi b/arch/arm/boot/dts/msm8974-bus.dtsi
index 3e0ef04..bfe955e 100644
--- a/arch/arm/boot/dts/msm8974-bus.dtsi
+++ b/arch/arm/boot/dts/msm8974-bus.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm-mmss-noc@fc478000 {
compatible = "msm-bus-fabric";
reg = <0xfc478000 0x00004000>;
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 94a28f7..786e9e3 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -13,7 +13,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,msm-cam@fd8C0000 {
compatible = "qcom,msm-cam";
reg = <0xfd8C0000 0x10000>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 9cfc5fd..5fa7c08 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -15,7 +15,7 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-cdp.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -195,6 +195,7 @@
qcom,model = "msm8974-taiko-cdp-snd-card";
qcom,hdmi-audio-rx;
qcom,us-euro-gpios = <&pm8941_gpios 20 0>;
+ qcom,cdc-micbias2-headset-only;
};
usb2_otg_sw: regulator-tpd4s214 {
@@ -499,7 +500,7 @@
qcom,output-type = <0>;
qcom,pull = <5>;
qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
+ qcom,out-strength = <1>;
qcom,src-sel = <2>;
qcom,master-en = <1>;
};
diff --git a/arch/arm/boot/dts/msm8974-coresight.dtsi b/arch/arm/boot/dts/msm8974-coresight.dtsi
index c064b59..1610f1f 100644
--- a/arch/arm/boot/dts/msm8974-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8974-coresight.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
tmc_etr: tmc@fc322000 {
compatible = "arm,coresight-tmc";
reg = <0xfc322000 0x1000>,
@@ -364,4 +364,18 @@
coresight-name = "coresight-cti-cpu3";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@fdf30018 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xfdf30018 0x80>,
+ <0xf9011080 0x80>,
+ <0xfd4ab160 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+ coresight-id = <29>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ qcom,hwevent-clks = "core_mmss_clk";
+ };
};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 7f46a54..ad5f175 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -14,7 +14,7 @@
/include/ "msm8974-camera-sensor-fluid.dtsi"
/include/ "msm8974-leds.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -230,6 +230,7 @@
qcom,hdmi-audio-rx;
qcom,ext-ult-lo-amp-gpio = <&pm8941_gpios 6 0>;
+ qcom,cdc-micbias2-headset-only;
};
};
@@ -505,7 +506,7 @@
qcom,output-type = <0>;
qcom,pull = <5>;
qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
+ qcom,out-strength = <1>;
qcom,src-sel = <2>;
qcom,master-en = <1>;
};
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 3779dbd..669097e 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
msm_gpu: qcom,kgsl-3d0@fdb00000 {
label = "kgsl-3d0";
compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index cfe39fc..ee8152d 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8974-leds.dtsi b/arch/arm/boot/dts/msm8974-leds.dtsi
index befd206..b39cc21 100644
--- a/arch/arm/boot/dts/msm8974-leds.dtsi
+++ b/arch/arm/boot/dts/msm8974-leds.dtsi
@@ -93,6 +93,20 @@
linux,name = "led:flash_1";
qcom,current = <625>;
};
+
+ pm8941_torch: qcom,flash_torch {
+ qcom,max-current = <200>;
+ qcom,default-state = "off";
+ qcom,headroom = <0>;
+ qcom,startup-dly = <1>;
+ linux,default-trigger =
+ "torch_trigger";
+ label = "flash";
+ qcom,id = <2>;
+ linux,name = "led:flash_torch";
+ qcom,current = <200>;
+ qcom,torch-enable;
+ };
};
qcom,leds@d400 {
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index d8a090b..e63b53b 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -13,7 +13,7 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-liquid.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -511,7 +511,7 @@
qcom,output-type = <0>;
qcom,pull = <5>;
qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
+ qcom,out-strength = <1>;
qcom,src-sel = <2>;
qcom,master-en = <1>;
};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 86f8141..6b8d600 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
mdss_mdp: qcom,mdss_mdp@fd900000 {
compatible = "qcom,mdss_mdp";
reg = <0xfd900000 0x22100>,
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index ca5f663..4d28a1d 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -14,7 +14,7 @@
/include/ "msm8974-camera-sensor-mtp.dtsi"
/include/ "msm8974-leds.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -187,6 +187,7 @@
sound {
qcom,model = "msm8974-taiko-mtp-snd-card";
+ qcom,cdc-micbias2-headset-only;
};
};
@@ -489,7 +490,7 @@
qcom,output-type = <0>;
qcom,pull = <5>;
qcom,vin-sel = <2>;
- qcom,out-strength = <3>;
+ qcom,out-strength = <1>;
qcom,src-sel = <2>;
qcom,master-en = <1>;
};
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index d1b3334..2cd3d24 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -458,7 +458,7 @@
};
};
-/ {
+&soc {
krait_pdn: krait-pdn@f9011000 {
reg = <0xf9011000 0x1000>;
reg-names = "apcs_gcc";
diff --git a/arch/arm/boot/dts/msm8974-rumi.dtsi b/arch/arm/boot/dts/msm8974-rumi.dtsi
index c569e58..c01a4e5 100644
--- a/arch/arm/boot/dts/msm8974-rumi.dtsi
+++ b/arch/arm/boot/dts/msm8974-rumi.dtsi
@@ -13,7 +13,7 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-cdp.dtsi"
-/ {
+&soc {
timer {
clock-frequency = <5000000>;
};
diff --git a/arch/arm/boot/dts/msm8974-sim.dtsi b/arch/arm/boot/dts/msm8974-sim.dtsi
index 786c50c..24b8d18 100644
--- a/arch/arm/boot/dts/msm8974-sim.dtsi
+++ b/arch/arm/boot/dts/msm8974-sim.dtsi
@@ -14,7 +14,7 @@
/include/ "msm8974-leds.dtsi"
/include/ "msm8974-camera-sensor-cdp.dtsi"
-/ {
+&soc {
qcom,mdss_dsi@fd922800 {
qcom,mdss_dsi_sim_video {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8974-smp2p.dtsi b/arch/arm/boot/dts/msm8974-smp2p.dtsi
index 079e4ca..3921a68 100644
--- a/arch/arm/boot/dts/msm8974-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm8974-smp2p.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
reg = <0xf9011008 0x4>;
diff --git a/arch/arm/boot/dts/msm8974-v1-iommu-domains.dtsi b/arch/arm/boot/dts/msm8974-v1-iommu-domains.dtsi
index 6ea5b9e..25fca2a 100644
--- a/arch/arm/boot/dts/msm8974-v1-iommu-domains.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-iommu-domains.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,iommu-domains {
compatible = "qcom,iommu-domains";
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index f9c0920..1a88749 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -12,7 +12,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 62837a1..caec2dc 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -21,7 +21,7 @@
/include/ "msm8974-v1-iommu-domains.dtsi"
/include/ "msm8974-v1-pm.dtsi"
-/ {
+&soc {
android_usb@fc42b0c8 {
compatible = "qcom,android-usb";
reg = <0xfc42b0c8 0xc8>;
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu-domains.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu-domains.dtsi
index a83815e..01c94d0 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu-domains.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu-domains.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,iommu-domains {
compatible = "qcom,iommu-domains";
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index 5a1c047..f8492c0 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -12,7 +12,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index def7b8c..75dce17 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -21,7 +21,7 @@
/include/ "msm8974-v2-iommu-domains.dtsi"
/include/ "msm8974-v2-pm.dtsi"
-/ {
+&soc {
android_usb@fe8050c8 {
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index d4f6bb7..71bbdc5 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -11,14 +11,6 @@
*/
/include/ "skeleton.dtsi"
-/include/ "msm8974-camera.dtsi"
-/include/ "msm8974-coresight.dtsi"
-/include/ "msm-gdsc.dtsi"
-/include/ "msm8974-ion.dtsi"
-/include/ "msm8974-gpu.dtsi"
-/include/ "msm8974-mdss.dtsi"
-/include/ "msm8974-smp2p.dtsi"
-/include/ "msm8974-bus.dtsi"
/ {
model = "Qualcomm MSM 8974";
@@ -35,7 +27,6 @@
};
memory {
-
secure_mem: secure_region {
linux,contiguous-region;
reg = <0 0xFC00000>;
@@ -56,6 +47,23 @@
};
+ soc: soc { };
+};
+
+/include/ "msm8974-camera.dtsi"
+/include/ "msm8974-coresight.dtsi"
+/include/ "msm-gdsc.dtsi"
+/include/ "msm8974-ion.dtsi"
+/include/ "msm8974-gpu.dtsi"
+/include/ "msm8974-mdss.dtsi"
+/include/ "msm8974-smp2p.dtsi"
+/include/ "msm8974-bus.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
intc: interrupt-controller@F9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -732,6 +740,22 @@
qcom,i2c-src-freq = <50000000>;
};
+ i2c_1: i2c@f9923000 {
+ cell-index = <1>;
+ compatible = "qcom,i2c-qup";
+ reg = <0xf9923000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 95 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,scl-gpio = <&msmgpio 3 0>;
+ qcom,sda-gpio = <&msmgpio 2 0>;
+ status = "disabled";
+ };
+
i2c_2: i2c@f9924000 {
cell-index = <2>;
compatible = "qcom,i2c-qup";
@@ -1109,6 +1133,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
@@ -1128,6 +1153,7 @@
/* GPIO inputs from wcnss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_4_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_4_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_4_in 2 0>;
/* GPIO output to wcnss */
@@ -1169,7 +1195,7 @@
interrupts = <0 76 0 0 77 0>;
interrupt-names = "ocmem_irq", "dm_irq";
qcom,ocmem-num-regions = <0x3>;
- qcom,ocmem-num-macros = <0x8>;
+ qcom,ocmem-num-macros = <0x18>;
qcom,resource-type = <0x706d636f>;
#address-cells = <1>;
#size-cells = <1>;
@@ -1416,6 +1442,11 @@
qcom,min-level = <1>; /* No Request */
};
+ qcom,vdd-apps-rstr{
+ qcom,vdd-rstr-reg = "vdd_apps";
+ qcom,levels = <1881600 1958400 2265600>;
+ qcom,freq-req;
+ };
};
qcom,bam_dmux@fc834000 {
@@ -1551,22 +1582,28 @@
};
&gdsc_venus {
+ qcom,clock-names = "core_clk";
status = "ok";
};
&gdsc_mdss {
+ qcom,clock-names = "core_clk", "lut_clk";
status = "ok";
};
&gdsc_jpeg {
+ qcom,clock-names = "core0_clk", "core1_clk", "core2_clk";
status = "ok";
};
&gdsc_vfe {
+ qcom,clock-names = "core0_clk", "core1_clk", "csi0_clk", "csi1_clk",
+ "cpp_clk";
status = "ok";
};
&gdsc_oxili_gx {
+ qcom,clock-names = "core_clk";
qcom,retain-mems;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm9625-cdp.dtsi b/arch/arm/boot/dts/msm9625-cdp.dtsi
index 1f9cbb0..6ddb50b 100644
--- a/arch/arm/boot/dts/msm9625-cdp.dtsi
+++ b/arch/arm/boot/dts/msm9625-cdp.dtsi
@@ -13,7 +13,7 @@
/include/ "msm9625-display.dtsi"
/include/ "qpic-panel-ili-qvga.dtsi"
-/ {
+&soc {
i2c@f9925000 {
charger@57 {
compatible = "summit,smb137c";
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 69a1d7b..8520b19 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
tmc_etr: tmc@fc322000 {
compatible = "arm,coresight-tmc";
reg = <0xfc322000 0x1000>,
diff --git a/arch/arm/boot/dts/msm9625-display.dtsi b/arch/arm/boot/dts/msm9625-display.dtsi
index a160bae..287a63a 100644
--- a/arch/arm/boot/dts/msm9625-display.dtsi
+++ b/arch/arm/boot/dts/msm9625-display.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,msm_qpic@f9ac0000 {
compatible = "qcom,mdss_qpic";
reg = <0xf9ac0000 0x24000>;
diff --git a/arch/arm/boot/dts/msm9625-ion.dtsi b/arch/arm/boot/dts/msm9625-ion.dtsi
index 8183264..2a3e4b5 100644
--- a/arch/arm/boot/dts/msm9625-ion.dtsi
+++ b/arch/arm/boot/dts/msm9625-ion.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,ion {
compatible = "qcom,msm-ion";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm9625-mtp.dtsi b/arch/arm/boot/dts/msm9625-mtp.dtsi
index cc0bf5e..79c873f 100644
--- a/arch/arm/boot/dts/msm9625-mtp.dtsi
+++ b/arch/arm/boot/dts/msm9625-mtp.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
i2c@f9925000 {
charger@57 {
compatible = "summit,smb137c";
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 3e421a8..6c45f80 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -12,7 +12,7 @@
/include/ "skeleton.dtsi"
-/ {
+&soc {
qcom,spm@f9009000 {
compatible = "qcom,spm-v2";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm9625-regulator.dtsi b/arch/arm/boot/dts/msm9625-regulator.dtsi
index 24f616d..ee48b7f 100644
--- a/arch/arm/boot/dts/msm9625-regulator.dtsi
+++ b/arch/arm/boot/dts/msm9625-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -260,7 +260,7 @@
};
};
-/ {
+&soc {
ext_2p95v: regulator-isl80101 {
compatible = "regulator-fixed";
regulator-name = "ext_2p95v";
diff --git a/arch/arm/boot/dts/msm9625-smp2p.dtsi b/arch/arm/boot/dts/msm9625-smp2p.dtsi
index 46af1b2..f8ad351 100644
--- a/arch/arm/boot/dts/msm9625-smp2p.dtsi
+++ b/arch/arm/boot/dts/msm9625-smp2p.dtsi
@@ -9,7 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,smp2p-modem {
compatible = "qcom,smp2p";
reg = <0xf9011008 0x4>;
diff --git a/arch/arm/boot/dts/msm9625-v1.dtsi b/arch/arm/boot/dts/msm9625-v1.dtsi
index de88ff1..b238ba5 100644
--- a/arch/arm/boot/dts/msm9625-v1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v1.dtsi
@@ -18,7 +18,7 @@
/include/ "msm9625.dtsi"
-/ {
+&soc {
qcom,msm-imem@fc42a800 {
compatible = "qcom,msm-imem";
reg = <0xfc42a800 0x1000>; /* Address and size of IMEM */
diff --git a/arch/arm/boot/dts/msm9625-v2-mtp.dts b/arch/arm/boot/dts/msm9625-v2-mtp.dts
index 5324e2c..27d0066 100644
--- a/arch/arm/boot/dts/msm9625-v2-mtp.dts
+++ b/arch/arm/boot/dts/msm9625-v2-mtp.dts
@@ -21,7 +21,9 @@
qcom,msm-id = <134 7 0x20000>, <152 7 0x20000>, <149 7 0x20000>,
<150 7 0x20000>, <151 7 0x20000>, <148 7 0x20000>,
<173 7 0x20000>, <174 7 0x20000>, <175 7 0x20000>;
+};
+&soc {
i2c@f9925000 {
charger@57 {
compatible = "summit,smb137c";
diff --git a/arch/arm/boot/dts/msm9625-v2.1.dtsi b/arch/arm/boot/dts/msm9625-v2.1.dtsi
index c3c2c49..65ff96a 100644
--- a/arch/arm/boot/dts/msm9625-v2.1.dtsi
+++ b/arch/arm/boot/dts/msm9625-v2.1.dtsi
@@ -18,7 +18,7 @@
/include/ "msm9625.dtsi"
-/ {
+&soc {
qcom,msm-imem@fe807800 {
compatible = "qcom,msm-imem";
reg = <0xfe807800 0x1000>; /* Address and size of IMEM */
diff --git a/arch/arm/boot/dts/msm9625-v2.dtsi b/arch/arm/boot/dts/msm9625-v2.dtsi
index 81d8e00..b078309 100644
--- a/arch/arm/boot/dts/msm9625-v2.dtsi
+++ b/arch/arm/boot/dts/msm9625-v2.dtsi
@@ -18,7 +18,7 @@
/include/ "msm9625.dtsi"
-/ {
+&soc {
qcom,msm-imem@fe807800 {
compatible = "qcom,msm-imem";
reg = <0xfe807800 0x1000>; /* Address and size of IMEM */
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index abfd7ec..5abfab8 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -11,10 +11,6 @@
*/
/include/ "skeleton.dtsi"
-/include/ "msm9625-ion.dtsi"
-/include/ "msm9625-pm.dtsi"
-/include/ "msm9625-coresight.dtsi"
-/include/ "msm9625-smp2p.dtsi"
/ {
model = "Qualcomm MSM 9625";
@@ -25,6 +21,19 @@
spi0 = &spi_0;
};
+ soc: soc { };
+};
+
+/include/ "msm9625-ion.dtsi"
+/include/ "msm9625-pm.dtsi"
+/include/ "msm9625-coresight.dtsi"
+/include/ "msm9625-smp2p.dtsi"
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
intc: interrupt-controller@F9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -757,6 +766,7 @@
/* GPIO inputs from mss */
qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
/* GPIO output to mss */
@@ -957,3 +967,32 @@
qcom,fast-avg-setup = <0>;
};
};
+
+&pm8019_adc_tm {
+ /* Channel Node */
+ chan@33 {
+ label = "pa_therm0";
+ reg = <0x33>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x48>;
+ qcom,thermal-node;
+ };
+
+ chan@34 {
+ label = "pa_therm1";
+ reg = <0x34>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x68>;
+ qcom,thermal-node;
+ };
+};
diff --git a/arch/arm/boot/dts/msmkrypton.dtsi b/arch/arm/boot/dts/msmkrypton.dtsi
index 3f51659..4b032d8 100644
--- a/arch/arm/boot/dts/msmkrypton.dtsi
+++ b/arch/arm/boot/dts/msmkrypton.dtsi
@@ -17,6 +17,14 @@
compatible = "qcom,msmkrypton";
interrupt-parent = <&intc>;
+ soc: soc { };
+};
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
intc: interrupt-controller@f9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
diff --git a/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi b/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi
index a0c906e..089f112 100644
--- a/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi
+++ b/arch/arm/boot/dts/qpic-panel-ili-qvga.dtsi
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-/ {
+&soc {
qcom,mdss_lcdc_ili9341_qvga {
compatible = "qcom,mdss-qpic-panel";
label = "ili qvga lcdc panel";
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 03ac944..e45024e 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-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_MODULES=y
@@ -61,6 +62,7 @@
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 3322896..bff59db 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -59,7 +59,6 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_ADSP_LOADER=m
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
@@ -69,6 +68,8 @@
CONFIG_SENSORS_ADSP=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -214,6 +215,7 @@
CONFIG_INPUT_EVBUG=m
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
@@ -278,7 +280,6 @@
CONFIG_ION_MSM=y
CONFIG_MSM_KGSL=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/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index dc84558..8ebe7d4 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -443,15 +443,6 @@
CONFIG_IOMMU_PGTABLES_L2=y
CONFIG_MOBICORE_SUPPORT=m
CONFIG_MOBICORE_API=m
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_TMC=y
-CONFIG_CORESIGHT_TPIU=y
-CONFIG_CORESIGHT_FUNNEL=y
-CONFIG_CORESIGHT_REPLICATOR=y
-CONFIG_CORESIGHT_STM=y
-CONFIG_CORESIGHT_ETM=y
-CONFIG_CORESIGHT_ETM_PCSAVE_DEFAULT_ENABLE=y
-CONFIG_CORESIGHT_EVENT=m
CONFIG_BIF=y
CONFIG_BIF_QPNP=y
CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 1e0134a..662d555 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -225,6 +225,7 @@
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -278,14 +279,6 @@
CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_IPA=y
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_TMC=y
-CONFIG_CORESIGHT_TPIU=y
-CONFIG_CORESIGHT_FUNNEL=y
-CONFIG_CORESIGHT_REPLICATOR=y
-CONFIG_CORESIGHT_STM=y
-CONFIG_CORESIGHT_ETM=y
-CONFIG_CORESIGHT_EVENT=m
CONFIG_EXT3_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index f7c3bff..7e92748 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -225,6 +225,7 @@
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index a70e6c6..0eecffd 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -418,6 +418,7 @@
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
+ select ARM_TICKET_LOCKS
select GPIO_MSM_V3
select MSM_GPIOMUX
select MSM_NATIVE_RESTART
@@ -459,6 +460,7 @@
select MAY_HAVE_SPARSE_IRQ
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
+ select ARM_TICKET_LOCKS
select GPIO_MSM_V3
select MSM_GPIOMUX
select MSM_NATIVE_RESTART
@@ -1113,14 +1115,14 @@
config KERNEL_PMEM_SMI_REGION
bool "Enable in-kernel PMEM region for SMI"
default y if ARCH_MSM8X60
- depends on ANDROID_PMEM && ((ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM))
+ depends on (ARCH_QSD8X50 && !PMEM_GPU0) || (ARCH_MSM8X60 && !VCM)
help
Enable the in-kernel PMEM allocator to use SMI memory.
config PMEM_GPU0
bool "Enable PMEM GPU0 region"
default y
- depends on ARCH_QSD8X50 && ANDROID_PMEM
+ depends on ARCH_QSD8X50
help
Enable the PMEM GPU0 device on SMI Memory.
@@ -1856,7 +1858,6 @@
config MSM_HW3D
tristate "MSM Hardware 3D Register Driver"
- depends on ANDROID_PMEM
help
Provides access to registers needed by the userspace OpenGL|ES
library.
@@ -1864,7 +1865,6 @@
config MSM_ADSP
depends on (ARCH_MSM7X01A || ARCH_MSM7X25 || ARCH_MSM7X27)
tristate "MSM ADSP driver"
- depends on ANDROID_PMEM
default y
help
Provides access to registers needed by the userspace aDSP library.
@@ -1890,7 +1890,7 @@
config MSM7KV2_AUDIO
bool "MSM7K v2 audio"
- depends on (ARCH_MSM7X30 && ANDROID_PMEM)
+ depends on ARCH_MSM7X30
default y
help
Enables QDSP5V2-based audio drivers for audio playbacks and
@@ -1906,14 +1906,14 @@
config MSM_QDSP6
tristate "QDSP6 support"
- depends on ARCH_QSD8X50 && ANDROID_PMEM
+ depends on ARCH_QSD8X50
default y
help
Enable support for qdsp6. This provides audio and video functionality.
config MSM8X60_AUDIO
tristate "MSM8X60 audio support"
- depends on ARCH_MSM8X60 && ANDROID_PMEM
+ depends on ARCH_MSM8X60
default y
help
Enable support for qdsp6v2. This provides audio functionality.
@@ -1972,7 +1972,7 @@
config QSD_AUDIO
bool "QSD audio"
- depends on ARCH_MSM_SCORPION && MSM_DALRPC && ANDROID_PMEM && !MSM_SMP
+ depends on ARCH_MSM_SCORPION && MSM_DALRPC && !MSM_SMP
default y
help
Provides PCM, MP3, and AAC audio playback.
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 43b243d..8efc000 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -4,7 +4,7 @@
ifndef CONFIG_ARM_ARCH_TIMER
obj-y += timer.o
endif
-obj-y += clock.o clock-voter.o clock-dummy.o
+obj-y += clock.o clock-voter.o clock-dummy.o clock-generic.o
obj-y += modem_notifier.o
obj-$(CONFIG_USE_OF) += board-dt.o
obj-$(CONFIG_DEBUG_FS) += nohlt.o clock-debug.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index d57709d..2827e65 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -58,6 +58,7 @@
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-liquid.dtb
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v2-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2-liquid.dtb
+ dtb-$(CONFIG_ARCH_MSM8974) += apq8074-v2-dragonboard.dtb
# APQ8084
zreladdr-$(CONFIG_ARCH_APQ8084) := 0x00008000
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 153be21..a6f772d 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -65,7 +65,6 @@
* 3) Depending on Frodo version, may need minimum of LVL_NOM
*/
static struct clkctl_acpu_speed acpu_freq_tbl_8226[] = {
- { 0, 19200, CXO, 0, 0, CPR_CORNER_SVS, 0, 0 },
{ 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 4 },
{ 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 0, 4 },
{ 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 6 },
@@ -77,7 +76,6 @@
};
static struct clkctl_acpu_speed acpu_freq_tbl_8610[] = {
- { 0, 19200, CXO, 0, 0, CPR_CORNER_SVS, 0, 0 },
{ 1, 300000, PLL0, 4, 2, CPR_CORNER_SVS, 0, 3 },
{ 1, 384000, ACPUPLL, 5, 0, CPR_CORNER_SVS, 0, 3 },
{ 1, 600000, PLL0, 4, 0, CPR_CORNER_NORMAL, 0, 4 },
diff --git a/arch/arm/mach-msm/board-8064-gpiomux.c b/arch/arm/mach-msm/board-8064-gpiomux.c
index 0f88287..ede53bc 100644
--- a/arch/arm/mach-msm/board-8064-gpiomux.c
+++ b/arch/arm/mach-msm/board-8064-gpiomux.c
@@ -968,7 +968,6 @@
.pull = GPIOMUX_PULL_DOWN,
};
-
static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_4MA,
diff --git a/arch/arm/mach-msm/board-8084.c b/arch/arm/mach-msm/board-8084.c
index 0a13c56..c20ba92 100644
--- a/arch/arm/mach-msm/board-8084.c
+++ b/arch/arm/mach-msm/board-8084.c
@@ -120,7 +120,7 @@
pr_err("%s: socinfo_init() failed\n", __func__);
apq8084_init_gpiomux();
- of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+ board_dt_populate(adata);
apq8084_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index b4c63f9..3da3e2d 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -102,7 +102,7 @@
mpq8092_init_gpiomux();
msm_clock_init(&mpq8092_clock_init_data);
- of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+ board_dt_populate(adata);
}
static const char *mpq8092_dt_match[] __initconst = {
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index a892e32..521898e 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -129,7 +129,7 @@
pr_err("%s: socinfo_init() failed\n", __func__);
msm8226_init_gpiomux();
- of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+ board_dt_populate(adata);
msm8226_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 93645c7..593e2b1 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -29,14 +29,26 @@
.pull = GPIOMUX_PULL_NONE,
};
-static struct gpiomux_setting gpio_spi_config = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_NONE,
+static struct gpiomux_setting atmel_int_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
};
-static struct gpiomux_setting gpio_spi_cs_config = {
- .func = GPIOMUX_FUNC_1,
+static struct gpiomux_setting atmel_int_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_reset_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_reset_sus_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_6MA,
.pull = GPIOMUX_PULL_DOWN,
};
@@ -97,6 +109,18 @@
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
+ .gpio = 2, /* BLSP1 QUP1 I2C_SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
+ .gpio = 3, /* BLSP1 QUP1 I2C_SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
.gpio = 10, /* BLSP1 QUP3 I2C_SDA */
.settings = {
[GPIOMUX_SUSPENDED] = &gpio_i2c_config,
@@ -120,28 +144,21 @@
[GPIOMUX_SUSPENDED] = &gpio_cam_i2c_config,
},
},
+};
+
+static struct msm_gpiomux_config msm_atmel_configs[] __initdata = {
{
- .gpio = 0, /* BLSP1 QUP1 SPI_DATA_MOSI */
+ .gpio = 0, /* TOUCH RESET */
.settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ [GPIOMUX_ACTIVE] = &atmel_reset_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_reset_sus_cfg,
},
},
{
- .gpio = 1, /* BLSP1 QUP1 SPI_DATA_MISO */
+ .gpio = 1, /* TOUCH INT */
.settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
- },
- },
- {
- .gpio = 3, /* BLSP1 QUP1 SPI_CLK */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_config,
- },
- },
- {
- .gpio = 2, /* BLSP1 QUP1 SPI_CS1 */
- .settings = {
- [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ [GPIOMUX_ACTIVE] = &atmel_int_act_cfg,
+ [GPIOMUX_SUSPENDED] = &atmel_int_sus_cfg,
},
},
};
@@ -243,6 +260,8 @@
}
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+ msm_gpiomux_install(msm_atmel_configs,
+ ARRAY_SIZE(msm_atmel_configs));
msm_gpiomux_install(wcnss_5wire_interface,
ARRAY_SIZE(wcnss_5wire_interface));
msm_gpiomux_install(msm_lcd_configs, ARRAY_SIZE(msm_lcd_configs));
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index 2cd7134..962ed65 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -125,7 +125,7 @@
pr_err("%s: socinfo_init() failed\n", __func__);
msm8610_init_gpiomux();
- of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+ board_dt_populate(adata);
msm8610_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8038.c b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
index c34394e..8ed93ea 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8038.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8038.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -95,7 +95,7 @@
REGULATOR_SUPPLY("VDDIO_CDC", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar1p1-slim"),
- REGULATOR_SUPPLY("vddp", "0-0048"),
+ REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("mhl_iovcc18", "0-0039"),
REGULATOR_SUPPLY("vdd-io", "spi0.0"),
REGULATOR_SUPPLY("vdd-phy", "spi0.0"),
@@ -209,7 +209,6 @@
REGULATOR_SUPPLY("8038_lvs2", NULL),
REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
- REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("vddio", "12-0018"),
REGULATOR_SUPPLY("vlogic", "12-0068"),
};
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index 8f853a4..cdc419f 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -194,7 +194,7 @@
REGULATOR_SUPPLY("VDDIO_CDC", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar1p1-slim"),
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar1p1-slim"),
- REGULATOR_SUPPLY("vddp", "0-0048"),
+ REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("mhl_iovcc18", "0-0039"),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDD_CP", "sitar1p1-slim"),
@@ -233,7 +233,6 @@
REGULATOR_SUPPLY("8917_lvs4", NULL),
REGULATOR_SUPPLY("vcc_i2c", "3-004a"),
REGULATOR_SUPPLY("vcc_i2c", "3-0024"),
- REGULATOR_SUPPLY("vcc_i2c", "0-0048"),
REGULATOR_SUPPLY("vddio", "12-0018"),
REGULATOR_SUPPLY("vlogic", "12-0068"),
};
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index f404e42..ccea956 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1718,12 +1718,6 @@
static struct isa1200_regulator isa1200_reg_data[] = {
{
- .name = "vddp",
- .min_uV = ISA_I2C_VTG_MIN_UV,
- .max_uV = ISA_I2C_VTG_MAX_UV,
- .load_uA = ISA_I2C_CURR_UA,
- },
- {
.name = "vcc_i2c",
.min_uV = ISA_I2C_VTG_MIN_UV,
.max_uV = ISA_I2C_VTG_MAX_UV,
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 705275c..76dbaef 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -20,6 +20,98 @@
#define KS8851_IRQ_GPIO 94
+static struct gpiomux_setting ap2mdm_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mdm2ap_status_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting mdm2ap_errfatal_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting mdm2ap_pblrdy = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_IN,
+};
+
+
+static struct gpiomux_setting ap2mdm_soft_reset_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting ap2mdm_wakeup = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config mdm_configs[] __initdata = {
+ /* AP2MDM_STATUS */
+ {
+ .gpio = 105,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+ }
+ },
+ /* MDM2AP_STATUS */
+ {
+ .gpio = 46,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_status_cfg,
+ }
+ },
+ /* MDM2AP_ERRFATAL */
+ {
+ .gpio = 82,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_errfatal_cfg,
+ }
+ },
+ /* AP2MDM_ERRFATAL */
+ {
+ .gpio = 106,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_cfg,
+ }
+ },
+ /* AP2MDM_SOFT_RESET, aka AP2MDM_PON_RESET_N */
+ {
+ .gpio = 24,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_soft_reset_cfg,
+ }
+ },
+ /* AP2MDM_WAKEUP */
+ {
+ .gpio = 104,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &ap2mdm_wakeup,
+ }
+ },
+ /* MDM2AP_PBL_READY*/
+ {
+ .gpio = 80,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &mdm2ap_pblrdy,
+ }
+ },
+};
+
static struct gpiomux_setting gpio_uart_config = {
.func = GPIOMUX_FUNC_2,
.drv = GPIOMUX_DRV_16MA,
@@ -1079,6 +1171,23 @@
static void msm_gpiomux_sdc4_install(void) {}
#endif /* CONFIG_MMC_MSM_SDC4_SUPPORT */
+static struct msm_gpiomux_config apq8074_dragonboard_ts_config[] __initdata = {
+ {
+ /* BLSP1 QUP I2C_DATA */
+ .gpio = 2,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
+ /* BLSP1 QUP I2C_CLK */
+ .gpio = 3,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+};
+
void __init msm_8974_init_gpiomux(void)
{
int rc;
@@ -1140,4 +1249,12 @@
if (of_board_is_rumi())
msm_gpiomux_install(msm_rumi_blsp_configs,
ARRAY_SIZE(msm_rumi_blsp_configs));
+
+ if (socinfo_get_platform_subtype() == PLATFORM_SUBTYPE_MDM)
+ msm_gpiomux_install(mdm_configs,
+ ARRAY_SIZE(mdm_configs));
+
+ if (of_board_is_dragonboard() && machine_is_apq8074())
+ msm_gpiomux_install(apq8074_dragonboard_ts_config,
+ ARRAY_SIZE(apq8074_dragonboard_ts_config));
}
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 3eed219..35e46fc 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -163,7 +163,7 @@
msm_8974_init_gpiomux();
regulator_has_full_constraints();
- of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
+ board_dt_populate(adata);
msm8974_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 3bb00bb..6bb5655 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -247,8 +247,7 @@
pr_err("%s: socinfo_init() failed\n", __func__);
msm9625_init_gpiomux();
- of_platform_populate(NULL, of_default_bus_match_table,
- msm9625_auxdata_lookup, NULL);
+ board_dt_populate(msm9625_auxdata_lookup);
msm9625_add_drivers();
}
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index 5d2fdf9..1f77b4c 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -115,3 +115,14 @@
return 1;
}
+
+void __init board_dt_populate(struct of_dev_auxdata *adata)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+ /* Explicitly parent the /soc devices to the root node to preserve
+ * the kernel ABI (sysfs structure, etc) until userspace is updated
+ */
+ of_platform_populate(of_find_node_by_path("/soc"),
+ of_default_bus_match_table, adata, NULL);
+}
diff --git a/arch/arm/mach-msm/board-dt.h b/arch/arm/mach-msm/board-dt.h
index 03ffa0b..d79e414 100644
--- a/arch/arm/mach-msm/board-dt.h
+++ b/arch/arm/mach-msm/board-dt.h
@@ -10,9 +10,12 @@
* GNU General Public License for more details.
*/
+#include <linux/of_platform.h>
+
extern struct sys_timer msm_dt_timer;
void __init msm_dt_init_irq(void);
void __init msm_dt_init_irq_nompm(void);
void __init msm_dt_init_irq_l2x0(void);
int __init msm_scan_dt_map_imem(unsigned long node, const char *uname,
int depth, void *data);
+void __init board_dt_populate(struct of_dev_auxdata *adata);
diff --git a/arch/arm/mach-msm/board-krypton.c b/arch/arm/mach-msm/board-krypton.c
index aada3b0..7b7b7cd 100644
--- a/arch/arm/mach-msm/board-krypton.c
+++ b/arch/arm/mach-msm/board-krypton.c
@@ -64,7 +64,7 @@
pr_err("%s: socinfo_init() failed\n", __func__);
msmkrypton_init_gpiomux();
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ board_dt_populate(adata);
msmkrypton_add_drivers();
}
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 1090d89..6212a4d 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -169,14 +169,14 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
[VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
#define RPM_MISC_CLK_TYPE 0x306b6c63
#define RPM_BUS_CLK_TYPE 0x316b6c63
@@ -2753,14 +2753,15 @@
VDD_SR2_PLL_NUM
};
-static const int *vdd_sr2_levels[] = {
+static int *vdd_sr2_levels[] = {
[VDD_SR2_PLL_OFF] = VDD_UV(0, RPM_REGULATOR_CORNER_NONE),
[VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
[VDD_SR2_PLL_TUR] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2, vdd_sr2_levels);
+static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
+ vdd_sr2_levels, NULL);
static struct pll_freq_tbl apcs_pll_freq[] = {
F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
@@ -3137,10 +3138,10 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.etm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.etm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.etm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33c000.jtagmm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33d000.jtagmm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33e000.jtagmm"),
- CLK_LOOKUP("core_a_clk", qdss_clk.c, "fc33f000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33c000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33d000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33e000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc33f000.jtagmm"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
@@ -3278,6 +3279,15 @@
CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
+ CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fd8c1024.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd8c2304.qcom,gdsc"),
+ CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd8c2304.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", camss_jpeg_jpeg0_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", camss_vfe_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("csi_clk", camss_csi_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("cpp_clk", camss_vfe_cpp_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
+
/* MM sensor clocks */
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6f.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk1_clk_src.c, "90.qcom,camera"),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 478f77f..5e60bd5 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -434,14 +434,14 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
[VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
#define RPM_MISC_CLK_TYPE 0x306b6c63
#define RPM_BUS_CLK_TYPE 0x316b6c63
@@ -533,14 +533,15 @@
VDD_SR2_PLL_NUM
};
-static const int *vdd_sr2_levels[] = {
+static int *vdd_sr2_levels[] = {
[VDD_SR2_PLL_OFF] = VDD_UV(0, RPM_REGULATOR_CORNER_NONE),
[VDD_SR2_PLL_SVS] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_SR2_PLL_NOM] = VDD_UV(1800000, RPM_REGULATOR_CORNER_NORMAL),
[VDD_SR2_PLL_TUR] = VDD_UV(1800000, RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2, vdd_sr2_levels);
+static DEFINE_VDD_REGULATORS(vdd_sr2_pll, VDD_SR2_PLL_NUM, 2,
+ vdd_sr2_levels, NULL);
static struct pll_freq_tbl apcs_pll_freq[] = {
F_APCS_PLL( 384000000, 20, 0x0, 0x1, 0x0, 0x0, 0x0),
@@ -2017,7 +2018,7 @@
},
};
-static struct mux_clk csi0phy_mux_clk = {
+static struct cam_mux_clk csi0phy_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(11),
.select_reg = MMSS_CAMSS_MISC,
@@ -2029,13 +2030,13 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "csi0phy_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(csi0phy_mux_clk.c),
+ .dbg_name = "csi0phy_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(csi0phy_cam_mux_clk.c),
},
};
-static struct mux_clk csi1phy_mux_clk = {
+static struct cam_mux_clk csi1phy_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(10),
.select_reg = MMSS_CAMSS_MISC,
@@ -2047,13 +2048,13 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "csi1phy_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(csi1phy_mux_clk.c),
+ .dbg_name = "csi1phy_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(csi1phy_cam_mux_clk.c),
},
};
-static struct mux_clk csi0pix_mux_clk = {
+static struct cam_mux_clk csi0pix_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(7),
.select_reg = MMSS_CAMSS_MISC,
@@ -2065,14 +2066,14 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "csi0pix_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(csi0pix_mux_clk.c),
+ .dbg_name = "csi0pix_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(csi0pix_cam_mux_clk.c),
},
};
-static struct mux_clk rdi2_mux_clk = {
+static struct cam_mux_clk rdi2_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(6),
.select_reg = MMSS_CAMSS_MISC,
@@ -2084,13 +2085,13 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "rdi2_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(rdi2_mux_clk.c),
+ .dbg_name = "rdi2_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(rdi2_cam_mux_clk.c),
},
};
-static struct mux_clk rdi1_mux_clk = {
+static struct cam_mux_clk rdi1_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(5),
.select_reg = MMSS_CAMSS_MISC,
@@ -2102,13 +2103,13 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "rdi1_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(rdi1_mux_clk.c),
+ .dbg_name = "rdi1_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(rdi1_cam_mux_clk.c),
},
};
-static struct mux_clk rdi0_mux_clk = {
+static struct cam_mux_clk rdi0_cam_mux_clk = {
.enable_reg = MMSS_CAMSS_MISC,
.enable_mask = BIT(4),
.select_reg = MMSS_CAMSS_MISC,
@@ -2120,9 +2121,9 @@
},
.base = &virt_bases[MMSS_BASE],
.c = {
- .dbg_name = "rdi0_mux_clk",
- .ops = &clk_ops_mux,
- CLK_INIT(rdi0_mux_clk.c),
+ .dbg_name = "rdi0_cam_mux_clk",
+ .ops = &clk_ops_cam_mux,
+ CLK_INIT(rdi0_cam_mux_clk.c),
},
};
@@ -2495,7 +2496,7 @@
{ &gcc_ce1_axi_clk.c, GCC_BASE, 0x0139},
{ &gcc_ce1_ahb_clk.c, GCC_BASE, 0x013a},
{ &gcc_xo_clk_src.c, GCC_BASE, 0x0149},
- { &bimc_clk.c, GCC_BASE, 0x0154},
+ { &bimc_clk.c, GCC_BASE, 0x015d},
{ &gcc_bimc_smmu_clk.c, GCC_BASE, 0x015e},
{ &gcc_lpass_q6_axi_clk.c, GCC_BASE, 0x0160},
@@ -2539,11 +2540,11 @@
{ &q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
{ &q6ss_xo_clk.c, LPASS_BASE, 0x002b},
- {&apc0_m_clk, APCS_BASE, 0x10},
- {&apc1_m_clk, APCS_BASE, 0x11},
- {&apc2_m_clk, APCS_BASE, 0x12},
- {&apc3_m_clk, APCS_BASE, 0x13},
- {&l2_m_clk, APCS_BASE, 0x15},
+ {&apc0_m_clk, APCS_BASE, 0x00010},
+ {&apc1_m_clk, APCS_BASE, 0x00114},
+ {&apc2_m_clk, APCS_BASE, 0x00220},
+ {&apc3_m_clk, APCS_BASE, 0x00324},
+ {&l2_m_clk, APCS_BASE, 0x01000},
{&dummy_clk, N_BASES, 0x0000},
};
@@ -2610,6 +2611,8 @@
clk->multiplier = 4;
clk_sel = 0x16A;
regval = measure_mux[i].debug_mux;
+ /* Use a divider value of 4. */
+ regval |= BVAL(31, 30, 0x3);
writel_relaxed(regval, APCS_REG_BASE(GLB_CLK_DIAG));
break;
@@ -2872,17 +2875,18 @@
CLK_LOOKUP("core_clk_src", sdcc1_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", sdcc2_apps_clk_src.c, ""),
CLK_LOOKUP("core_clk_src", usb_hs_system_clk_src.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.i2c"),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
- CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9923000.spi"),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, "f9923000.spi"),
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9927000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, "f9923000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, "f9927000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9928000.i2c"),
CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, "f9928000.i2c"),
@@ -2967,12 +2971,12 @@
CLK_LOOKUP("core_clk", vfe_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", vfe_axi_clk.c, ""),
- CLK_LOOKUP("core_clk", csi0pix_mux_clk.c, ""),
- CLK_LOOKUP("core_clk", csi0phy_mux_clk.c, ""),
- CLK_LOOKUP("core_clk", csi1phy_mux_clk.c, ""),
- CLK_LOOKUP("core_clk", rdi2_mux_clk.c, ""),
- CLK_LOOKUP("core_clk", rdi1_mux_clk.c, ""),
- CLK_LOOKUP("core_clk", rdi0_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0pix_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi0phy_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", csi1phy_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", rdi2_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", rdi1_cam_mux_clk.c, ""),
+ CLK_LOOKUP("core_clk", rdi0_cam_mux_clk.c, ""),
CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fdc00000.qcom,kgsl-3d0"),
CLK_LOOKUP("iface_clk", oxili_ahb_clk.c, "fdc00000.qcom,kgsl-3d0"),
@@ -3105,23 +3109,6 @@
.main_output_mask = BIT(0),
};
-#define PLL_AUX_OUTPUT_BIT 1
-#define PLL_AUX2_OUTPUT_BIT 2
-
-#define PWR_ON_MASK BIT(31)
-#define EN_REST_WAIT_MASK (0xF << 20)
-#define EN_FEW_WAIT_MASK (0xF << 16)
-#define CLK_DIS_WAIT_MASK (0xF << 12)
-#define SW_OVERRIDE_MASK BIT(2)
-#define HW_CONTROL_MASK BIT(1)
-#define SW_COLLAPSE_MASK BIT(0)
-
-/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
-#define EN_REST_WAIT_VAL (0x2 << 20)
-#define EN_FEW_WAIT_VAL (0x2 << 16)
-#define CLK_DIS_WAIT_VAL (0x2 << 12)
-#define GDSC_TIMEOUT_US 50000
-
static void __init reg_init(void)
{
u32 regval;
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index be6d965..9ee4476 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -6406,79 +6406,14 @@
.main_output_mask = BIT(23),
};
-static void __init reg_init(void)
+
+static void __init init_mm_cc(void)
{
- void __iomem *imem_reg;
-
- /* Deassert MM SW_RESET_ALL signal. */
- writel_relaxed(0, SW_RESET_ALL_REG);
-
/*
- * Some bits are only used on 8960 or 8064 or 8930 and are marked as
- * reserved bits on the other SoCs. Writing to these reserved bits
- * should have no effect.
- */
- /*
- * Initialize MM AHB registers: Enable the FPB clock and disable HW
- * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
- * FORCE_CORE_ON bit to prevent its memory from being collapsed when
- * the clock is halted. The sleep and wake-up delays are set to safe
- * values.
- */
- if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
- rmwreg(0x00000003, AHB_EN_REG, 0x6C000103);
- writel_relaxed(0x000007F9, AHB_EN2_REG);
- } else {
- rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
- writel_relaxed(0x3C7097F9, AHB_EN2_REG);
- }
-
- if (soc_class_is_apq8064())
- rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
-
- /* Deassert all locally-owned MM AHB resets. */
- rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
- rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
-
- /* Initialize MM AXI registers: Enable HW gating for all clocks that
- * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
- * delays to safe values. */
- if ((cpu_is_msm8960() &&
- SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) ||
- cpu_is_msm8627() || cpu_is_msm8930ab()) {
- rmwreg(0x000007F9, MAXI_EN_REG, 0x0803FFFF);
- rmwreg(0x3027FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
- } else {
- rmwreg(0x0003AFF9, MAXI_EN_REG, 0x0803FFFF);
- rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
- }
-
- rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
- rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
-
- if (soc_class_is_apq8064())
- rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
- if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627() ||
- cpu_is_msm8930ab())
- rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
- if (cpu_is_msm8960ab())
- rmwreg(0x009FE000, MAXI_EN5_REG, 0x01FFE000);
-
- if (cpu_is_msm8627() || cpu_is_msm8930ab())
- rmwreg(0x000003C7, SAXI_EN_REG, 0x00003FFF);
- else
- rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
-
- /* Enable IMEM's clk_on signal */
- imem_reg = ioremap(0x04b00040, 4);
- if (imem_reg) {
- writel_relaxed(0x3, imem_reg);
- iounmap(imem_reg);
- }
-
- /* Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
+ * Initialize MM CC registers: Set MM FORCE_CORE_ON bits so that core
* memories retain state even when not clocked. Also, set sleep and
- * wake-up delays to safe values. */
+ * wake-up delays to safe values.
+ */
rmwreg(0x00000000, CSI0_CC_REG, 0x00000410);
rmwreg(0x00000000, CSI1_CC_REG, 0x00000410);
rmwreg(0x80FF0000, DSI1_BYTE_CC_REG, 0xE0FF0010);
@@ -6493,28 +6428,72 @@
rmwreg(0x80FF0000, VFE_CC_REG, 0xE0FF4010);
rmwreg(0x800000FF, VFE_CC2_REG, 0xE00000FF);
rmwreg(0x80FF0000, VPE_CC_REG, 0xE0FF0010);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064()) {
- rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
- rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
- rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
- }
- if (cpu_is_msm8960ab())
- rmwreg(0x00000001, DSI2_PIXEL_CC2_REG, 0x00000001);
+}
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8930aa() ||
- cpu_is_msm8627() || cpu_is_msm8930ab())
- rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
- if (cpu_is_msm8960ab())
- rmwreg(0x00000000, TV_CC_REG, 0x00004010);
+static void __init enable_imem_clk(unsigned long phys)
+{
+ void __iomem *imem_reg;
- if (cpu_is_msm8960()) {
- rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
- rmwreg(0x80FF0000, GFX2D1_CC_REG, 0xE0FF0010);
+ /* Enable IMEM's clk_on signal */
+ imem_reg = ioremap(phys, SZ_4);
+ if (imem_reg) {
+ writel_relaxed(0x3, imem_reg);
+ iounmap(imem_reg);
}
- if (soc_class_is_apq8064()) {
- rmwreg(0x00000000, TV_CC_REG, 0x00004010);
- rmwreg(0x80FF0000, VCAP_CC_REG, 0xE0FF1010);
+}
+
+static void __init reg_init_8930(void)
+{
+ /* MM-AHB default values */
+ u32 en_reg = 0x40000000, en2_reg = 0x3C7097F9;
+ /* MM-AXI default values */
+ u32 aen_reg = 0x0003AFF9, aen2_reg = 0x3A27FCFF,
+ saen_reg = 0x00003C38;
+
+
+ /* Deassert MM SW_RESET_ALL signal. */
+ writel_relaxed(0, SW_RESET_ALL_REG);
+
+ /*
+ * Initialize MM AHB registers: Enable the FPB clock and disable HW
+ * gating on 8627 and 8930ab for all clocks. Also set VFE_AHB's
+ * FORCE_CORE_ON bit to prevent its memory from being collapsed when
+ * the clock is halted. The sleep and wake-up delays are set to safe
+ * values.
+ */
+ if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
+ en_reg = 0x00000003;
+ en2_reg = 0x000007F9;
}
+ rmwreg(en_reg, AHB_EN_REG, 0x6C000103);
+ writel_relaxed(en2_reg, AHB_EN2_REG);
+
+ /* Deassert all locally-owned MM AHB resets. */
+ rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+ rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+ /*
+ * Initialize MM AXI registers: Enable HW gating for all clocks that
+ * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+ * delays to safe values.
+ */
+ if (cpu_is_msm8627() || cpu_is_msm8930ab()) {
+ aen_reg = 0x000007F9;
+ aen2_reg = 0x3027FCFF;
+ }
+ rmwreg(aen_reg, MAXI_EN_REG, 0x0803FFFF);
+ rmwreg(aen2_reg, MAXI_EN2_REG, 0x3A3FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+ rmwreg(0x000004FF, MAXI_EN5_REG, 0x00000FFF);
+ if (cpu_is_msm8627() || cpu_is_msm8930ab())
+ saen_reg = 0x000003C7;
+ rmwreg(saen_reg, SAXI_EN_REG, 0x00003FFF);
+
+ enable_imem_clk(0x04b00040);
+
+ init_mm_cc();
+ rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
/*
* Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
@@ -6522,10 +6501,6 @@
* and wake-up value to max.
*/
rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
- if (soc_class_is_apq8064()) {
- rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
- rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
- }
/* De-assert MM AXI resets to all hardware blocks. */
writel_relaxed(0, SW_RESET_AXI_REG);
@@ -6538,88 +6513,231 @@
writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
writel_relaxed(BIT(15), PDM_CLK_NS_REG);
- /* Source SLIMBus xo src from slimbus reference clock */
- if (cpu_is_msm8960ab() || cpu_is_msm8960())
- writel_relaxed(0x3, SLIMBUS_XO_SRC_CLK_CTL_REG);
-
- /* Source the dsi_byte_clks from the DSI PHY PLLs */
+ /* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || soc_class_is_apq8064())
- rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
-
- /* Source the dsi1_esc_clk from the DSI1 PHY PLLs */
rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
/*
+ * Change PLL15 configuration based on the SoC we're running on.
+ *
+ * Default pll15 l, m, n values for 8930/8930aa/8627()
+ */
+ pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
+ pll15_config.m = 0x1;
+ pll15_config.n = 0x3;
+
+ if (cpu_is_msm8930ab()) {
+ pll15_config.l = 0x25 | BVAL(31, 7, 0x600);
+ pll15_config.m = 0x25;
+ pll15_config.n = 0x3E7;
+ }
+ configure_sr_pll(&pll15_config, &pll15_regs, 0);
+
+ /* Disable AUX and BIST outputs */
+ writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+}
+
+static void __init reg_init_8064(void)
+{
+ u32 is_pll_enabled;
+
+ /* Deassert MM SW_RESET_ALL signal. */
+ writel_relaxed(0, SW_RESET_ALL_REG);
+
+ /*
+ * Initialize MM AHB registers:
+ * Also set VFE_AHB's FORCE_CORE_ON bit to prevent its memory
+ * from being collapsed when the clock is halted. The sleep and
+ * wake-up delays are set to safe values.
+ */
+ rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
+ writel_relaxed(0x3C7097F9, AHB_EN2_REG);
+ rmwreg(0x00000000, AHB_EN3_REG, 0x00000001);
+
+ /* Deassert all locally-owned MM AHB resets. */
+ rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+ rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+ /*
+ * Initialize MM AXI registers: Enable HW gating for all clocks that
+ * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+ * delays to safe values.
+ */
+ rmwreg(0x0003AFF9, MAXI_EN_REG, 0x0803FFFF);
+ rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+ rmwreg(0x019FECFF, MAXI_EN5_REG, 0x01FFEFFF);
+ rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
+
+ enable_imem_clk(0x04b00040);
+
+ init_mm_cc();
+ rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
+ rmwreg(0x00000000, TV_CC_REG, 0x00004010);
+ rmwreg(0x80FF0000, VCAP_CC_REG, 0xE0FF1010);
+
+ /*
+ * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
+ * core remain active during halt state of the clk. Also, set sleep
+ * and wake-up value to max.
+ */
+ rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
+ rmwreg(0x0000004F, USB_HS3_HCLK_FS_REG, 0x0000007F);
+ rmwreg(0x0000004F, USB_HS4_HCLK_FS_REG, 0x0000007F);
+
+ /* De-assert MM AXI resets to all hardware blocks. */
+ writel_relaxed(0, SW_RESET_AXI_REG);
+
+ /* Deassert all MM core resets. */
+ writel_relaxed(0, SW_RESET_CORE_REG);
+ writel_relaxed(0, SW_RESET_CORE2_REG);
+
+ /* Enable TSSC and PDM PXO sources. */
+ writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
+ writel_relaxed(BIT(15), PDM_CLK_NS_REG);
+
+ /* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
+ rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
+ rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
+
+ /* Source the dsi2_byte_clks from the DSI PHY PLLs */
+ rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
+
+ /*
* Source the sata_phy_ref_clk from PXO and set predivider of
* sata_pmalive_clk to 1.
*/
- if (soc_class_is_apq8064()) {
- rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
- rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
- }
+ rmwreg(0, SATA_PHY_REF_CLK_CTL_REG, 0x1);
+ rmwreg(0, SATA_PMALIVE_CLK_CTL_REG, 0x3);
/*
* TODO: Programming below PLLs and prng_clk is temporary and
* needs to be removed after bootloaders program them.
*/
- if (soc_class_is_apq8064()) {
- u32 is_pll_enabled;
- /* Program pxo_src_clk to source from PXO */
- rmwreg(0x1, PXO_SRC_CLK_CTL_REG, 0x7);
+ /* Program pxo_src_clk to source from PXO */
+ rmwreg(0x1, PXO_SRC_CLK_CTL_REG, 0x7);
- /* Check if PLL14 is active */
- is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
- if (!is_pll_enabled)
- /* Ref clk = 27MHz and program pll14 to 480MHz */
- configure_sr_pll(&pll14_config, &pll14_regs, 1);
+ /* Check if PLL14 is active */
+ is_pll_enabled = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
+ if (!is_pll_enabled)
+ /* Ref clk = 27MHz and program pll14 to 480MHz */
+ configure_sr_pll(&pll14_config, &pll14_regs, 1);
- /* Check if PLL4 is active */
- is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
- if (!is_pll_enabled)
- /* Ref clk = 27MHz and program pll4 to 393.2160MHz */
- configure_sr_pll(&pll4_config_393, &pll4_regs, 1);
+ /* Check if PLL4 is active */
+ is_pll_enabled = readl_relaxed(LCC_PLL0_STATUS_REG) & BIT(16);
+ if (!is_pll_enabled)
+ /* Ref clk = 27MHz and program pll4 to 393.2160MHz */
+ configure_sr_pll(&pll4_config_393, &pll4_regs, 1);
- /* Enable PLL4 source on the LPASS Primary PLL Mux */
- writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
+ /* Enable PLL4 source on the LPASS Primary PLL Mux */
+ writel_relaxed(0x1, LCC_PRI_PLL_CLK_CTL_REG);
- /* Program prng_clk to 64MHz if it isn't configured */
- if (!readl_relaxed(PRNG_CLK_NS_REG))
- writel_relaxed(0x2B, PRNG_CLK_NS_REG);
- }
+ /* Program prng_clk to 64MHz if it isn't configured */
+ if (!readl_relaxed(PRNG_CLK_NS_REG))
+ writel_relaxed(0x2B, PRNG_CLK_NS_REG);
- if (cpu_is_apq8064() || cpu_is_apq8064aa()) {
- /* Program PLL15 to 975MHz with ref clk = 27MHz */
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- } else if (cpu_is_apq8064ab()) {
+ if (cpu_is_apq8064ab()) {
/* Program PLL15 to 900MHZ */
pll15_config.l = 0x21 | BVAL(31, 7, 0x620);
pll15_config.m = 0x1;
pll15_config.n = 0x3;
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- } else if (cpu_is_msm8960ab()) {
- pll3_clk.c.rate = 880000000;
- configure_sr_pll(&pll3_config, &pll3_regs, 0);
+ }
+ /*
+ * Default Program PLL15 to 975MHz with ref clk = 27MHz
+ * In case of apq8064ab PLL15 is set to 900MHZ
+ */
+ configure_sr_pll(&pll15_config, &pll15_regs, 0);
+}
+
+static void __init reg_init_8960(void)
+{
+ u32 aen_reg = 0x0003AFF9, aen2_reg = 0x3A27FCFF;
+
+ /* Deassert MM SW_RESET_ALL signal. */
+ writel_relaxed(0, SW_RESET_ALL_REG);
+
+ /*
+ * Initialize MM AHB registers:
+ * Also set VFE_AHB's FORCE_CORE_ON bit to prevent its memory
+ * from being collapsed when the clock is halted. The sleep and
+ * wake-up delays are set to safe values.
+ */
+ rmwreg(0x40000000, AHB_EN_REG, 0x6C000103);
+ writel_relaxed(0x3C7097F9, AHB_EN2_REG);
+
+ /* Deassert all locally-owned MM AHB resets. */
+ rmwreg(0, SW_RESET_AHB_REG, 0xFFF7DFFF);
+ rmwreg(0, SW_RESET_AHB2_REG, 0x0000000F);
+
+ /*
+ * Initialize MM AXI registers: Enable HW gating for all clocks that
+ * support it. Also set FORCE_CORE_ON bits, and any sleep and wake-up
+ * delays to safe values.
+ */
+ if (cpu_is_msm8960() &&
+ SOCINFO_VERSION_MAJOR(socinfo_get_version()) < 3) {
+ aen_reg = 0x000007F9;
+ aen2_reg = 0x3027FCFF;
+ }
+ rmwreg(aen_reg, MAXI_EN_REG, 0x0803FFFF);
+ rmwreg(aen2_reg, MAXI_EN2_REG, 0x3A3FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN3_REG, 0x003FFFFF);
+ rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+ if (cpu_is_msm8960ab())
+ rmwreg(0x009FE000, MAXI_EN5_REG, 0x01FFE000);
+ rmwreg(0x00003C38, SAXI_EN_REG, 0x00003FFF);
+
+ enable_imem_clk(0x04b00040);
+
+ init_mm_cc();
+ rmwreg(0x80FF0000, DSI2_BYTE_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, DSI2_PIXEL_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, JPEGD_CC_REG, 0xE0FF0010);
+ if (cpu_is_msm8960ab()) {
+ rmwreg(0x00000001, DSI2_PIXEL_CC2_REG, 0x00000001);
+ rmwreg(0x00000000, TV_CC_REG, 0x00004010);
+ }
+ if (cpu_is_msm8960()) {
+ rmwreg(0x80FF0000, TV_CC_REG, 0xE1FFC010);
+ rmwreg(0x80FF0000, GFX2D0_CC_REG, 0xE0FF0010);
+ rmwreg(0x80FF0000, GFX2D1_CC_REG, 0xE0FF0010);
}
/*
- * Change PLL15 configuration based on the SoC we're running on.
+ * Initialize USB_HS_HCLK_FS registers: Set FORCE_C_ON bits so that
+ * core remain active during halt state of the clk. Also, set sleep
+ * and wake-up value to max.
*/
- if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
- pll15_config.l = 0x21 | BVAL(31, 7, 0x600);
- pll15_config.m = 0x1;
- pll15_config.n = 0x3;
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- /* Disable AUX and BIST outputs */
- writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
- } else if (cpu_is_msm8930ab()) {
- pll15_config.l = 0x25 | BVAL(31, 7, 0x600);
- pll15_config.m = 0x25;
- pll15_config.n = 0x3E7;
- configure_sr_pll(&pll15_config, &pll15_regs, 0);
- /* Disable AUX and BIST outputs */
- writel_relaxed(0, MM_PLL3_TEST_CTL_REG);
+ rmwreg(0x0000004F, USB_HS1_HCLK_FS_REG, 0x0000007F);
+
+ /* De-assert MM AXI resets to all hardware blocks. */
+ writel_relaxed(0, SW_RESET_AXI_REG);
+
+ /* Deassert all MM core resets. */
+ writel_relaxed(0, SW_RESET_CORE_REG);
+ writel_relaxed(0, SW_RESET_CORE2_REG);
+
+ /* Enable TSSC and PDM PXO sources. */
+ writel_relaxed(BIT(11), TSSC_CLK_CTL_REG);
+ writel_relaxed(BIT(15), PDM_CLK_NS_REG);
+
+ /* Source the dsi1_byte_clks/dsi1_esc_clk from the DSI PHY PLLs */
+ rmwreg(0x1, DSI1_BYTE_NS_REG, 0x7);
+ rmwreg(0x1, DSI1_ESC_NS_REG, 0x7);
+
+ /* Source SLIMBus xo src from slimbus reference clock */
+ writel_relaxed(0x3, SLIMBUS_XO_SRC_CLK_CTL_REG);
+
+ /* Source the dsi2_byte_clks from the DSI PHY PLLs */
+ rmwreg(0x2, DSI2_BYTE_NS_REG, 0x7);
+
+ if (cpu_is_msm8960ab()) {
+ pll3_clk.c.rate = 880000000;
+ configure_sr_pll(&pll3_config, &pll3_regs, 0);
}
}
@@ -6645,13 +6763,15 @@
}
struct clock_init_data msm8960_clock_init_data __initdata;
+
static void __init msm8960_clock_pre_init(void)
{
- /* Initialize clock registers. */
- reg_init();
+ struct clk_lookup *clk_lkup;
+ size_t clk_size;
+ struct clk_freq_tbl *tbl;
- if (soc_class_is_apq8064())
- vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
+ /* Initialize clock registers. */
+ reg_init_8960();
/* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
@@ -6665,73 +6785,120 @@
pcm_clk.freq_tbl = clk_tbl_pcm_492;
}
- if (cpu_is_msm8960() || cpu_is_msm8960ab())
- memcpy(msm_clocks_8960, msm_clocks_8960_common,
- sizeof(msm_clocks_8960_common));
- if (cpu_is_msm8960ab()) {
- gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960ab;
- mdp_clk.c.fmax = fmax_mdp_8960ab;
-
- gfx3d_clk.c.fmax = select_gfx_fmax_plan(fmax_gfx3d_8960ab,
- ARRAY_SIZE(fmax_gfx3d_8960ab));
-
- memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
- msm_clocks_8960ab_only, sizeof(msm_clocks_8960ab_only));
- msm8960_clock_init_data.size -=
- ARRAY_SIZE(msm_clocks_8960_only);
-
- gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
- } else if (cpu_is_msm8960()) {
- gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8960;
- memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
- msm_clocks_8960_only, sizeof(msm_clocks_8960_only));
+ if (cpu_is_msm8960()) {
+ tbl = clk_tbl_gfx3d_8960;
+ clk_lkup = msm_clocks_8960_only;
+ clk_size = sizeof(msm_clocks_8960_only);
msm8960_clock_init_data.size -=
ARRAY_SIZE(msm_clocks_8960ab_only);
}
- /*
- * Change the freq tables for and voltage requirements for
- * clocks which differ between chips.
- */
- if (cpu_is_apq8064() || cpu_is_apq8064aa())
- gfx3d_clk.c.fmax = fmax_gfx3d_8064;
+
+ if (cpu_is_msm8960ab()) {
+ mdp_clk.c.fmax = fmax_mdp_8960ab;
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+ tbl = clk_tbl_gfx3d_8960ab;
+ gfx3d_clk.c.fmax = select_gfx_fmax_plan(fmax_gfx3d_8960ab,
+ ARRAY_SIZE(fmax_gfx3d_8960ab));
+
+ clk_lkup = msm_clocks_8960ab_only;
+ clk_size = sizeof(msm_clocks_8960ab_only);
+ msm8960_clock_init_data.size -=
+ ARRAY_SIZE(msm_clocks_8960_only);
+ }
+
+ gfx3d_clk.freq_tbl = tbl;
+
+ memcpy(msm_clocks_8960, msm_clocks_8960_common,
+ sizeof(msm_clocks_8960_common));
+ memcpy(msm_clocks_8960 + ARRAY_SIZE(msm_clocks_8960_common),
+ clk_lkup, clk_size);
+
+ if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+ prng_clk.freq_tbl = clk_tbl_prng_64;
+
+ clk_ops_local_pll.enable = sr_pll_clk_enable;
+}
+
+static void __init msm8064_clock_pre_init(void)
+{
+ unsigned long *fmax = fmax_gfx3d_8064;
+
+ /* Initialize clock registers. */
+ reg_init_8064();
+
+ vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8064;
+
+ /* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
+ if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
+ pll4_clk.c.rate = 491520000;
+ audio_slimbus_clk.freq_tbl = clk_tbl_aif_osr_492;
+ mi2s_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ pcm_clk.freq_tbl = clk_tbl_pcm_492;
+ }
if (cpu_is_apq8064ab())
- gfx3d_clk.c.fmax = fmax_gfx3d_8064ab;
+ fmax = fmax_gfx3d_8064ab;
if ((cpu_is_apq8064() &&
SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 2) ||
cpu_is_apq8064ab() || cpu_is_apq8064aa()) {
-
vcodec_clk.c.fmax = fmax_vcodec_8064v2;
ce3_src_clk.c.fmax = fmax_ce3_8064v2;
sdc1_clk.c.fmax = fmax_sdc1_8064v2;
}
- if (soc_class_is_apq8064()) {
- ijpeg_clk.c.fmax = fmax_ijpeg_8064;
- mdp_clk.c.fmax = fmax_mdp_8064;
- tv_src_clk.c.fmax = fmax_tv_src_8064;
- vfe_clk.c.fmax = fmax_vfe_8064;
- gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+
+ gfx3d_clk.c.fmax = fmax;
+ ijpeg_clk.c.fmax = fmax_ijpeg_8064;
+ mdp_clk.c.fmax = fmax_mdp_8064;
+ tv_src_clk.c.fmax = fmax_tv_src_8064;
+ vfe_clk.c.fmax = fmax_vfe_8064;
+
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk.c;
+
+ if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
+ prng_clk.freq_tbl = clk_tbl_prng_64;
+
+ clk_ops_local_pll.enable = sr_pll_clk_enable;
+}
+
+static void __init __msm8930_clock_pre_init(void)
+{
+ unsigned long rate = 900000000;
+ unsigned long *fmax = fmax_gfx3d_8930;
+
+ /* Initialize clock registers. */
+ reg_init_8930();
+
+ /* Detect PLL4 programmed for alternate 491.52MHz clock plan. */
+ if (readl_relaxed(LCC_PLL0_L_VAL_REG) == 0x12) {
+ pll4_clk.c.rate = 491520000;
+ audio_slimbus_clk.freq_tbl = clk_tbl_aif_osr_492;
+ mi2s_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_mic_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_spkr_osr_clk.freq_tbl = clk_tbl_aif_osr_492;
+ pcm_clk.freq_tbl = clk_tbl_pcm_492;
}
- /*
- * Change the freq tables and voltage requirements for
- * clocks which differ between 8960 and 8930.
- */
- if (cpu_is_msm8930() || cpu_is_msm8627())
- gfx3d_clk.c.fmax = fmax_gfx3d_8930;
- else if (cpu_is_msm8930aa())
- gfx3d_clk.c.fmax = fmax_gfx3d_8930aa;
- if (cpu_is_msm8930() || cpu_is_msm8930aa() || cpu_is_msm8627()) {
- pll15_clk.c.rate = 900000000;
- gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
- } else if (cpu_is_msm8930ab()) {
+ if (cpu_is_msm8930aa())
+ fmax = fmax_gfx3d_8930aa;
+
+ if (cpu_is_msm8930ab()) {
+ rate = 1000000000;
+ fmax = fmax_gfx3d_8930ab;
gfx3d_clk.freq_tbl = clk_tbl_gfx3d_8930ab;
- pll15_clk.c.rate = 1000000000;
- gfx3d_clk.c.fmax = fmax_gfx3d_8930ab;
- gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
vcodec_clk.c.fmax = fmax_vcodec_8930ab;
}
+
+ pll15_clk.c.rate = rate;
+ gfx3d_clk.c.fmax = fmax;
+ gmem_axi_clk.c.depends = &gfx3d_axi_clk_8930.c;
+
if ((readl_relaxed(PRNG_CLK_NS_REG) & 0x7F) == 0x2B)
prng_clk.freq_tbl = clk_tbl_prng_64;
@@ -6746,7 +6913,7 @@
rpm_vreg_dig_8930 = RPM_VREG_ID_PM8917_VDD_DIG_CORNER;
vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930_pm8917;
- msm8960_clock_pre_init();
+ __msm8930_clock_pre_init();
}
static void __init msm8930_clock_pre_init(void)
@@ -6754,10 +6921,10 @@
vdd_dig.set_vdd = set_vdd_dig_8930;
vdd_sr2_hdmi_pll.set_vdd = set_vdd_sr2_hdmi_pll_8930;
- msm8960_clock_pre_init();
+ __msm8930_clock_pre_init();
}
-static void __init msm8960_clock_post_init(void)
+static void __init common_clock_post_init(void)
{
/* Keep PXO on whenever APPS cpu is active */
clk_prepare_enable(&pxo_a_clk.c);
@@ -6777,18 +6944,12 @@
clk_set_rate(&tsif_ref_clk.c, 105000);
clk_set_rate(&tssc_clk.c, 27000000);
clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
- if (soc_class_is_apq8064()) {
- clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
- clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
- }
clk_set_rate(&usb_fs1_src_clk.c, 60000000);
- if (cpu_is_msm8960ab() || cpu_is_msm8960() || cpu_is_msm8930() ||
- cpu_is_msm8930aa() || cpu_is_msm8627() || cpu_is_msm8930ab())
- clk_set_rate(&usb_fs2_src_clk.c, 60000000);
clk_set_rate(&usb_hsic_xcvr_fs_clk.c, 60000000);
clk_set_rate(&usb_hsic_hsic_src_clk.c, 480000000);
clk_set_rate(&usb_hsic_hsio_cal_clk.c, 9000000);
clk_set_rate(&usb_hsic_system_clk.c, 60000000);
+
/*
* Set the CSI rates to a safe default to avoid warnings when
* switching csi pix and rdi clocks.
@@ -6817,6 +6978,19 @@
clk_prepare_enable(&sfab_tmr_a_clk.c);
}
+static void __init msm8960_clock_post_init(void)
+{
+ common_clock_post_init();
+ clk_set_rate(&usb_fs2_src_clk.c, 60000000);
+}
+
+static void __init msm8064_clock_post_init(void)
+{
+ common_clock_post_init();
+ clk_set_rate(&usb_hs3_xcvr_clk.c, 60000000);
+ clk_set_rate(&usb_hs4_xcvr_clk.c, 60000000);
+}
+
static int __init msm8960_clock_late_init(void)
{
int rc;
@@ -6859,8 +7033,8 @@
struct clock_init_data apq8064_clock_init_data __initdata = {
.table = msm_clocks_8064,
.size = ARRAY_SIZE(msm_clocks_8064),
- .pre_init = msm8960_clock_pre_init,
- .post_init = msm8960_clock_post_init,
+ .pre_init = msm8064_clock_pre_init,
+ .post_init = msm8064_clock_post_init,
.late_init = msm8960_clock_late_init,
};
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 707e6b6..75919149 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -638,14 +638,14 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
[VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
#define RPM_MISC_CLK_TYPE 0x306b6c63
#define RPM_BUS_CLK_TYPE 0x316b6c63
@@ -920,6 +920,7 @@
};
static struct clk_freq_tbl ftbl_gcc_blsp1_2_qup1_6_i2c_apps_clk[] = {
+ F(19200000, cxo, 1, 0, 0),
F(50000000, gpll0, 12, 0, 0),
F_END
};
@@ -4894,6 +4895,7 @@
CLK_LOOKUP("alt_iface_clk", mdss_hdmi_ahb_clk.c,
"fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, "fd922100.qcom,hdmi_tx"),
+ CLK_LOOKUP("mdp_core_clk", mdss_mdp_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("extp_clk", mdss_extpclk_clk.c, "fd922100.qcom,hdmi_tx"),
CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
@@ -5121,6 +5123,17 @@
CLK_LOOKUP("bus_clk", venus0_axi_clk.c, "fdc00000.qcom,vidc"),
CLK_LOOKUP("mem_clk", venus0_ocmemnoc_clk.c, "fdc00000.qcom,vidc"),
+ CLK_LOOKUP("core_clk", venus0_vcodec0_clk.c, "fd8c1024.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "fd8c2304.qcom,gdsc"),
+ CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "fd8c2304.qcom,gdsc"),
+ CLK_LOOKUP("core0_clk", camss_jpeg_jpeg0_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core1_clk", camss_jpeg_jpeg1_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core2_clk", camss_jpeg_jpeg2_clk.c, "fd8c35a4.qcom,gdsc"),
+ CLK_LOOKUP("core0_clk", camss_vfe_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("core1_clk", camss_vfe_vfe1_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("csi0_clk", camss_csi_vfe0_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("csi1_clk", camss_csi_vfe1_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("cpp_clk", camss_vfe_cpp_clk.c, "fd8c36a4.qcom,gdsc"),
CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4024.qcom,gdsc"),
/* LPASS clocks */
@@ -5194,6 +5207,7 @@
CLK_LOOKUP("core_clk", qdss_clk.c, "fc342000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc343000.cti"),
CLK_LOOKUP("core_clk", qdss_clk.c, "fc344000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fdf30018.hwevent"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
@@ -5223,6 +5237,9 @@
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc342000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc343000.cti"),
CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc344000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fdf30018.hwevent"),
+
+ CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fdf30018.hwevent"),
CLK_LOOKUP("l2_m_clk", l2_m_clk, ""),
CLK_LOOKUP("krait0_m_clk", krait0_m_clk, ""),
@@ -5343,20 +5360,6 @@
.main_output_mask = BIT(0),
};
-#define PWR_ON_MASK BIT(31)
-#define EN_REST_WAIT_MASK (0xF << 20)
-#define EN_FEW_WAIT_MASK (0xF << 16)
-#define CLK_DIS_WAIT_MASK (0xF << 12)
-#define SW_OVERRIDE_MASK BIT(2)
-#define HW_CONTROL_MASK BIT(1)
-#define SW_COLLAPSE_MASK BIT(0)
-
-/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
-#define EN_REST_WAIT_VAL (0x2 << 20)
-#define EN_FEW_WAIT_VAL (0x2 << 16)
-#define CLK_DIS_WAIT_VAL (0x2 << 12)
-#define GDSC_TIMEOUT_US 50000
-
static void __init reg_init(void)
{
u32 regval;
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index 9a768e5..313e04c 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -280,14 +280,14 @@
VDD_DIG_NUM
};
-static const int *vdd_corner[] = {
+static int *vdd_corner[] = {
[VDD_DIG_NONE] = VDD_UV(RPM_REGULATOR_CORNER_NONE),
[VDD_DIG_LOW] = VDD_UV(RPM_REGULATOR_CORNER_SVS_SOC),
[VDD_DIG_NOMINAL] = VDD_UV(RPM_REGULATOR_CORNER_NORMAL),
[VDD_DIG_HIGH] = VDD_UV(RPM_REGULATOR_CORNER_SUPER_TURBO),
};
-static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
/* TODO: Needs to confirm the below values */
#define RPM_MISC_CLK_TYPE 0x306b6c63
diff --git a/arch/arm/mach-msm/clock-generic.c b/arch/arm/mach-msm/clock-generic.c
new file mode 100644
index 0000000..4d74533
--- /dev/null
+++ b/arch/arm/mach-msm/clock-generic.c
@@ -0,0 +1,405 @@
+/*
+ * 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/errno.h>
+
+#include <linux/clk.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 i;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ if (mux->parents[i].src == p)
+ return mux->parents[i].sel;
+ }
+
+ return -EINVAL;
+}
+
+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);
+ struct clk *old_parent;
+ int rc = 0;
+ unsigned long flags;
+
+ if (sel < 0)
+ return sel;
+
+ rc = __clk_pre_reparent(c, p, &flags);
+ if (rc)
+ goto out;
+
+ rc = mux->ops->set_mux_sel(mux, sel);
+ if (rc)
+ goto set_fail;
+
+ old_parent = c->parent;
+ c->parent = p;
+ __clk_post_reparent(c, old_parent, &flags);
+
+ return 0;
+
+set_fail:
+ __clk_post_reparent(c, p, &flags);
+out:
+ return rc;
+}
+
+static long mux_round_rate(struct clk *c, unsigned long rate)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int i;
+ long prate, max_prate = 0, rrate = LONG_MAX;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ prate = clk_round_rate(mux->parents[i].src, rate);
+ if (prate < rate) {
+ max_prate = max(prate, max_prate);
+ continue;
+ }
+
+ rrate = min(rrate, prate);
+ }
+ if (rrate == LONG_MAX)
+ rrate = max_prate;
+
+ return rrate ? rrate : -EINVAL;
+}
+
+static int mux_set_rate(struct clk *c, unsigned long rate)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ struct clk *new_parent = NULL;
+ int rc = 0, i;
+ unsigned long new_par_curr_rate;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ if (clk_round_rate(mux->parents[i].src, rate) == rate) {
+ new_parent = mux->parents[i].src;
+ break;
+ }
+ }
+ if (new_parent == NULL)
+ return -EINVAL;
+
+ /*
+ * Switch to safe parent since the old and new parent might be the
+ * same and the parent might temporarily turn off while switching
+ * rates.
+ */
+ if (mux->safe_sel >= 0)
+ rc = mux->ops->set_mux_sel(mux, mux->safe_sel);
+ if (rc)
+ return rc;
+
+ new_par_curr_rate = clk_get_rate(new_parent);
+ rc = clk_set_rate(new_parent, rate);
+ if (rc)
+ goto set_rate_fail;
+
+ rc = mux_set_parent(c, new_parent);
+ if (rc)
+ goto set_par_fail;
+
+ return 0;
+
+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)),
+ "Set rate failed for %s. Also in bad state!\n", c->dbg_name);
+ return rc;
+}
+
+static int mux_enable(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ if (mux->ops->enable)
+ return mux->ops->enable(mux);
+ return 0;
+}
+
+static void mux_disable(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ if (mux->ops->disable)
+ return mux->ops->disable(mux);
+}
+
+static struct clk *mux_get_parent(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int sel = mux->ops->get_mux_sel(mux);
+ int i;
+
+ for (i = 0; i < mux->num_parents; i++) {
+ if (mux->parents[i].sel == sel)
+ return mux->parents[i].src;
+ }
+
+ /* Unfamiliar parent. */
+ return NULL;
+}
+
+static enum handoff mux_handoff(struct clk *c)
+{
+ 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);
+
+ if (mux->en_mask && mux->ops && mux->ops->is_enabled)
+ return mux->ops->is_enabled(mux)
+ ? HANDOFF_ENABLED_CLK
+ : HANDOFF_DISABLED_CLK;
+
+ /*
+ * If this function returns 'enabled' even when the clock downstream
+ * of this clock is disabled, then handoff code will unnecessarily
+ * enable the current parent of this clock. If this function always
+ * returns 'disabled' and a clock downstream is on, the clock handoff
+ * code will bump up the ref count for this clock and its current
+ * parent as necessary. So, clocks without an actual HW gate can
+ * always return disabled.
+ */
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_gen_mux = {
+ .enable = mux_enable,
+ .disable = mux_disable,
+ .set_parent = mux_set_parent,
+ .round_rate = mux_round_rate,
+ .set_rate = mux_set_rate,
+ .handoff = mux_handoff,
+ .get_parent = mux_get_parent,
+};
+
+
+/* ==================== Divider clock ==================== */
+
+static long __div_round_rate(struct clk *c, unsigned long rate, int *best_div)
+{
+ struct div_clk *d = to_div_clk(c);
+ unsigned int div, min_div, max_div;
+ long p_rrate, rrate = LONG_MAX;
+
+ 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) (LONG_MAX / rate));
+ }
+
+ for (div = min_div; div <= max_div; div++) {
+ p_rrate = clk_round_rate(c->parent, rate * div);
+ if (p_rrate < 0)
+ break;
+
+ p_rrate /= div;
+ /*
+ * Trying higher dividers is only going to ask the parent for
+ * a higher rate. If it can't even output a rate higher than
+ * the one we request for this divider, the parent is not
+ * 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 == LONG_MAX) {
+ rrate = p_rrate;
+ if (best_div)
+ *best_div = div;
+ }
+ break;
+ }
+ if (p_rrate < rrate) {
+ rrate = p_rrate;
+ if (best_div)
+ *best_div = div;
+ }
+
+ if (rrate <= rate + d->rate_margin)
+ break;
+ }
+
+ if (rrate == LONG_MAX)
+ return -EINVAL;
+
+ return rrate;
+}
+
+static long div_round_rate(struct clk *c, unsigned long rate)
+{
+ return __div_round_rate(c, rate, 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;
+
+ rrate = __div_round_rate(c, rate, &div);
+ if (rrate != rate)
+ return -EINVAL;
+
+ if (div > d->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);
+ if (rc)
+ goto set_rate_fail;
+
+ if (div < d->div)
+ rc = d->ops->set_div(d, div);
+ if (rc)
+ goto div_dec_fail;
+
+ d->div = div;
+
+ return 0;
+
+div_dec_fail:
+ 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),
+ "Set rate failed for %s. Also in bad state!\n",
+ c->dbg_name);
+ return rc;
+}
+
+static int div_enable(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+ if (d->ops->enable)
+ return d->ops->enable(d);
+ return 0;
+}
+
+static void div_disable(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+ if (d->ops->disable)
+ return d->ops->disable(d);
+}
+
+static enum handoff div_handoff(struct clk *c)
+{
+ struct div_clk *d = to_div_clk(c);
+
+ if (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;
+
+ if (d->en_mask && d->ops && d->ops->is_enabled)
+ return d->ops->is_enabled(d)
+ ? HANDOFF_ENABLED_CLK
+ : HANDOFF_DISABLED_CLK;
+
+ /*
+ * If this function returns 'enabled' even when the clock downstream
+ * of this clock is disabled, then handoff code will unnecessarily
+ * enable the current parent of this clock. If this function always
+ * returns 'disabled' and a clock downstream is on, the clock handoff
+ * code will bump up the ref count for this clock and its current
+ * parent as necessary. So, clocks without an actual HW gate can
+ * always return disabled.
+ */
+ return HANDOFF_DISABLED_CLK;
+}
+
+struct clk_ops clk_ops_div = {
+ .enable = div_enable,
+ .disable = div_disable,
+ .round_rate = div_round_rate,
+ .set_rate = div_set_rate,
+ .handoff = div_handoff,
+};
+
+static long __slave_div_round_rate(struct clk *c, unsigned long rate,
+ int *best_div)
+{
+ struct div_clk *d = to_div_clk(c);
+ unsigned int div, min_div, max_div;
+ long p_rate;
+
+ 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;
+ }
+
+ p_rate = clk_get_rate(c->parent);
+ div = p_rate / rate;
+ div = max(div, min_div);
+ div = min(div, max_div);
+ if (best_div)
+ *best_div = div;
+
+ return p_rate / div;
+}
+
+static long slave_div_round_rate(struct clk *c, unsigned long rate)
+{
+ return __slave_div_round_rate(c, rate, NULL);
+}
+
+static int slave_div_set_rate(struct clk *c, unsigned long rate)
+{
+ struct div_clk *d = to_div_clk(c);
+ int div, rc = 0;
+ long rrate;
+
+ rrate = __slave_div_round_rate(c, rate, &div);
+ if (rrate != rate)
+ return -EINVAL;
+
+ if (div == d->div)
+ return 0;
+
+ if (d->ops->set_div)
+ rc = d->ops->set_div(d, div);
+ if (rc)
+ return rc;
+
+ d->div = div;
+
+ return 0;
+}
+
+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,
+ .handoff = div_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 8915bad..e67d973 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -815,18 +815,18 @@
/*
* mux clock functions
*/
-static void mux_clk_halt_check(void)
+static void cam_mux_clk_halt_check(void)
{
/* Ensure that the delay starts after the mux disable/enable. */
mb();
udelay(HALT_CHECK_DELAY_US);
}
-static int mux_clk_enable(struct clk *c)
+static int cam_mux_clk_enable(struct clk *c)
{
unsigned long flags;
u32 regval;
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
spin_lock_irqsave(&local_clock_reg_lock, flags);
regval = readl_relaxed(ENABLE_REG(mux));
@@ -835,15 +835,15 @@
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
/* Wait for clock to enable before continuing. */
- mux_clk_halt_check();
+ cam_mux_clk_halt_check();
return 0;
}
-static void mux_clk_disable(struct clk *c)
+static void cam_mux_clk_disable(struct clk *c)
{
unsigned long flags;
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
u32 regval;
spin_lock_irqsave(&local_clock_reg_lock, flags);
@@ -853,10 +853,10 @@
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
/* Wait for clock to disable before continuing. */
- mux_clk_halt_check();
+ cam_mux_clk_halt_check();
}
-static int mux_source_switch(struct mux_clk *mux, struct mux_source *dest)
+static int mux_source_switch(struct cam_mux_clk *mux, struct mux_source *dest)
{
unsigned long flags;
u32 regval;
@@ -879,9 +879,9 @@
return ret;
}
-static int mux_clk_set_parent(struct clk *c, struct clk *parent)
+static int cam_mux_clk_set_parent(struct clk *c, struct clk *parent)
{
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
struct mux_source *dest = NULL;
int ret;
@@ -908,9 +908,9 @@
return 0;
}
-static enum handoff mux_clk_handoff(struct clk *c)
+static enum handoff cam_mux_clk_handoff(struct clk *c)
{
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
u32 mask = mux->enable_mask;
u32 regval = readl_relaxed(ENABLE_REG(mux));
@@ -922,9 +922,9 @@
return HANDOFF_DISABLED_CLK;
}
-static struct clk *mux_clk_get_parent(struct clk *c)
+static struct clk *cam_mux_clk_get_parent(struct clk *c)
{
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
struct mux_source *parent = NULL;
u32 regval = readl_relaxed(SELECT_REG(mux));
@@ -943,9 +943,9 @@
return ERR_PTR(-EPERM);
}
-static int mux_clk_list_rate(struct clk *c, unsigned n)
+static int cam_mux_clk_list_rate(struct clk *c, unsigned n)
{
- struct mux_clk *mux = to_mux_clk(c);
+ struct cam_mux_clk *mux = to_cam_mux_clk(c);
int i;
for (i = 0; i < n; i++)
@@ -1022,13 +1022,13 @@
.handoff = local_vote_clk_handoff,
};
-struct clk_ops clk_ops_mux = {
- .enable = mux_clk_enable,
- .disable = mux_clk_disable,
- .set_parent = mux_clk_set_parent,
- .get_parent = mux_clk_get_parent,
- .handoff = mux_clk_handoff,
- .list_rate = mux_clk_list_rate,
+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,
};
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index f33cf9c..f307a2f 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -163,7 +163,7 @@
};
/**
- * struct mux_clk - branch clock
+ * 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
@@ -172,7 +172,7 @@
* @sources: list of mux sources
* @base: pointer to base address of ioremapped registers.
*/
-struct mux_clk {
+struct cam_mux_clk {
struct clk c;
const u32 enable_reg;
const u32 select_reg;
@@ -184,9 +184,9 @@
void *const __iomem *base;
};
-static inline struct mux_clk *to_mux_clk(struct clk *clk)
+static inline struct cam_mux_clk *to_cam_mux_clk(struct clk *clk)
{
- return container_of(clk, struct mux_clk, c);
+ return container_of(clk, struct cam_mux_clk, c);
}
/*
@@ -200,7 +200,7 @@
*/
extern spinlock_t local_clock_reg_lock;
-extern struct clk_ops clk_ops_mux;
+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;
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 044fc2c..08817c0 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -62,7 +62,8 @@
{
int level, rc = 0, i;
struct regulator **r = vdd_class->regulator;
- const int **vdd_uv = vdd_class->vdd_uv;
+ int **vdd_uv = vdd_class->vdd_uv;
+ int **vdd_ua = vdd_class->vdd_ua;
int max_level = vdd_class->num_levels - 1;
for (level = max_level; level > 0; level--)
@@ -77,20 +78,36 @@
vdd_uv[max_level][i]);
if (rc)
goto set_voltage_fail;
+
+ if (!vdd_ua)
+ continue;
+
+ rc = regulator_set_optimum_mode(r[i], vdd_ua[level][i]);
+ if (rc < 0)
+ goto set_mode_fail;
}
if (vdd_class->set_vdd && !vdd_class->num_regulators)
rc = vdd_class->set_vdd(vdd_class, level);
- if (!rc)
+ if (rc < 0)
vdd_class->cur_level = level;
- return rc;
+ return 0;
+
+set_mode_fail:
+ regulator_set_voltage(r[i], vdd_uv[vdd_class->cur_level][i],
+ vdd_uv[max_level][i]);
set_voltage_fail:
- level = vdd_class->cur_level;
- for (i--; i >= 0; i--)
- regulator_set_voltage(r[i], vdd_uv[level][i],
- vdd_uv[max_level][i]);
+ for (i--; i >= 0; i--) {
+ regulator_set_voltage(r[i], vdd_uv[vdd_class->cur_level][i],
+ vdd_uv[max_level][i]);
+
+ if (!vdd_ua)
+ continue;
+ regulator_set_optimum_mode(r[i],
+ vdd_ua[vdd_class->cur_level][i]);
+ }
return rc;
}
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 24a1e96..d5084e4 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -3,7 +3,7 @@
* MSM architecture cpufreq driver
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
* Author: Mike A. Chan <mikechan@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -261,6 +261,7 @@
{
int cur_freq;
int index;
+ int ret = 0;
struct cpufreq_frequency_table *table;
struct cpufreq_work_struct *cpu_work = NULL;
@@ -296,19 +297,16 @@
policy->cpu, cur_freq);
return -EINVAL;
}
-
- if (cur_freq != table[index].frequency) {
- int ret = 0;
- ret = acpuclk_set_rate(policy->cpu, table[index].frequency,
- SETRATE_CPUFREQ);
- if (ret)
- return ret;
- pr_info("cpufreq: cpu%d init at %d switching to %d\n",
- policy->cpu, cur_freq, table[index].frequency);
- cur_freq = table[index].frequency;
- }
-
- policy->cur = cur_freq;
+ /*
+ * 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);
+ if (ret)
+ return ret;
+ pr_debug("cpufreq: cpu%d init at %d switching to %d\n",
+ policy->cpu, cur_freq, table[index].frequency);
+ policy->cur = table[index].frequency;
policy->cpuinfo.transition_latency =
acpuclk_get_switch_time() * NSEC_PER_USEC;
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 6665d66..30a034e 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -22,6 +22,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
#include <linux/clk.h>
#include <mach/clk.h>
@@ -44,7 +45,9 @@
struct regulator_dev *rdev;
struct regulator_desc rdesc;
void __iomem *gdscr;
- struct clk *core_clk;
+ struct clk **clocks;
+ int clock_count;
+ bool toggle_mems;
};
static int gdsc_is_enabled(struct regulator_dev *rdev)
@@ -58,7 +61,7 @@
{
struct gdsc *sc = rdev_get_drvdata(rdev);
uint32_t regval;
- int ret;
+ int i, ret;
regval = readl_relaxed(sc->gdscr);
regval &= ~SW_COLLAPSE_MASK;
@@ -71,9 +74,18 @@
return ret;
}
+ if (sc->toggle_mems) {
+ for (i = 0; i < sc->clock_count; i++) {
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+ }
+ }
+
/*
* If clocks to this power domain were already on, they will take an
* additional 4 clock cycles to re-enable after the rail is enabled.
+ * Delay to account for this. A delay is also needed to ensure clocks
+ * are not enabled within 400ns of enabling power to the memories.
*/
udelay(1);
@@ -84,7 +96,7 @@
{
struct gdsc *sc = rdev_get_drvdata(rdev);
uint32_t regval;
- int ret;
+ int i, ret;
regval = readl_relaxed(sc->gdscr);
regval |= SW_COLLAPSE_MASK;
@@ -95,6 +107,13 @@
if (ret)
dev_err(&rdev->dev, "%s disable timed out\n", sc->rdesc.name);
+ if (sc->toggle_mems) {
+ for (i = 0; i < sc->clock_count; i++) {
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+ }
+ }
+
return ret;
}
@@ -112,7 +131,7 @@
struct gdsc *sc;
uint32_t regval;
bool retain_mems;
- int ret;
+ int i, ret;
sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
if (sc == NULL)
@@ -137,6 +156,34 @@
if (sc->gdscr == NULL)
return -ENOMEM;
+ sc->clock_count = of_property_count_strings(pdev->dev.of_node,
+ "qcom,clock-names");
+ if (sc->clock_count == -EINVAL) {
+ sc->clock_count = 0;
+ } else if (IS_ERR_VALUE(sc->clock_count)) {
+ dev_err(&pdev->dev, "Failed to get clock names\n");
+ return -EINVAL;
+ }
+
+ sc->clocks = devm_kzalloc(&pdev->dev,
+ sizeof(struct clk *) * sc->clock_count, GFP_KERNEL);
+ if (!sc->clocks)
+ return -ENOMEM;
+ for (i = 0; i < sc->clock_count; i++) {
+ const char *clock_name;
+ of_property_read_string_index(pdev->dev.of_node,
+ "qcom,clock-names", i,
+ &clock_name);
+ sc->clocks[i] = devm_clk_get(&pdev->dev, clock_name);
+ if (IS_ERR(sc->clocks[i])) {
+ int rc = PTR_ERR(sc->clocks[i]);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get %s\n",
+ clock_name);
+ return rc;
+ }
+ }
+
sc->rdesc.id = atomic_inc_return(&gdsc_count);
sc->rdesc.ops = &gdsc_ops;
sc->rdesc.type = REGULATOR_VOLTAGE;
@@ -157,13 +204,16 @@
retain_mems = of_property_read_bool(pdev->dev.of_node,
"qcom,retain-mems");
- if (retain_mems) {
- sc->core_clk = devm_clk_get(&pdev->dev, "core_clk");
- if (IS_ERR(sc->core_clk))
- return PTR_ERR(sc->core_clk);
- clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_MEM);
- clk_set_flags(sc->core_clk, CLKFLAG_RETAIN_PERIPH);
+ for (i = 0; i < sc->clock_count; i++) {
+ if (retain_mems || (regval & PWR_ON_MASK)) {
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+ } else {
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+ }
}
+ sc->toggle_mems = !retain_mems;
sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
pdev->dev.of_node);
diff --git a/arch/arm/mach-msm/include/mach/clk-provider.h b/arch/arm/mach-msm/include/mach/clk-provider.h
index 2a33228..0dd4957 100644
--- a/arch/arm/mach-msm/include/mach/clk-provider.h
+++ b/arch/arm/mach-msm/include/mach/clk-provider.h
@@ -49,6 +49,8 @@
* @set_vdd: function to call when applying a new voltage setting.
* @vdd_uv: sorted 2D array of legal voltage settings. Indexed by level, then
regulator.
+ * @vdd_ua: sorted 2D array of legal cureent settings. Indexed by level, then
+ regulator. Optional parameter.
* @level_votes: array of votes for each level.
* @num_levels: specifies the size of level_votes array.
* @cur_level: the currently set voltage level
@@ -59,7 +61,8 @@
struct regulator **regulator;
int num_regulators;
int (*set_vdd)(struct clk_vdd_class *v_class, int level);
- const int **vdd_uv;
+ int **vdd_uv;
+ int **vdd_ua;
int *level_votes;
int num_levels;
unsigned long cur_level;
@@ -76,10 +79,12 @@
.lock = __MUTEX_INITIALIZER(_name.lock) \
}
-#define DEFINE_VDD_REGULATORS(_name, _num_levels, _num_regulators, _vdd_uv) \
+#define DEFINE_VDD_REGULATORS(_name, _num_levels, _num_regulators, _vdd_uv, \
+ _vdd_ua) \
struct clk_vdd_class _name = { \
.class_name = #_name, \
.vdd_uv = _vdd_uv, \
+ .vdd_ua = _vdd_ua, \
.regulator = (struct regulator * [_num_regulators]) {}, \
.num_regulators = _num_regulators, \
.level_votes = (int [_num_levels]) {}, \
@@ -89,6 +94,7 @@
}
#define VDD_UV(...) ((int []){__VA_ARGS__})
+#define VDD_UA(...) ((int []){__VA_ARGS__})
enum handoff {
HANDOFF_ENABLED_CLK,
diff --git a/arch/arm/mach-msm/include/mach/clock-generic.h b/arch/arm/mach-msm/include/mach/clock-generic.h
new file mode 100644
index 0000000..0f689f1
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/clock-generic.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MACH_CLOCK_GENERIC_H
+#define __MACH_CLOCK_GENERIC_H
+
+#include <mach/clk-provider.h>
+
+/* ==================== Mux clock ==================== */
+
+struct clk_src {
+ struct clk *src;
+ int sel;
+};
+
+struct mux_clk;
+
+struct clk_mux_ops {
+ int (*set_mux_sel)(struct mux_clk *clk, int sel);
+ int (*get_mux_sel)(struct mux_clk *clk);
+
+ /* Optional */
+ bool (*is_enabled)(struct mux_clk *clk);
+ int (*enable)(struct mux_clk *clk);
+ void (*disable)(struct mux_clk *clk);
+};
+
+#define MUX_SRC_LIST(...) \
+ .parents = (struct clk_src[]){__VA_ARGS__}, \
+ .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__}))
+
+struct mux_clk {
+ /* Parents in decreasing order of preference for obtaining rates. */
+ struct clk_src *parents;
+ int num_parents;
+ struct clk *safe_parent;
+ int safe_sel;
+ struct clk_mux_ops *ops;
+
+ /* Fields not used by helper function. */
+ void *const __iomem *base;
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ u32 en_mask;
+ void *priv;
+
+ struct clk c;
+};
+
+static inline struct mux_clk *to_mux_clk(struct clk *c)
+{
+ return container_of(c, struct mux_clk, c);
+}
+
+extern struct clk_ops clk_ops_gen_mux;
+
+/* ==================== Divider clock ==================== */
+
+struct div_clk;
+
+struct clk_div_ops {
+ int (*set_div)(struct div_clk *clk, int div);
+ int (*get_div)(struct div_clk *clk);
+
+ /* Optional */
+ bool (*is_enabled)(struct div_clk *clk);
+ int (*enable)(struct div_clk *clk);
+ void (*disable)(struct div_clk *clk);
+};
+
+struct div_clk {
+ unsigned int div;
+ unsigned int min_div;
+ unsigned int max_div;
+ unsigned long rate_margin;
+ struct clk_div_ops *ops;
+
+ /* Fields not used by helper function. */
+ void *const __iomem *base;
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ u32 en_mask;
+ void *priv;
+ struct clk c;
+};
+
+static inline struct div_clk *to_div_clk(struct clk *c)
+{
+ return container_of(c, struct div_clk, c);
+}
+
+extern struct clk_ops clk_ops_div;
+extern struct clk_ops clk_ops_slave_div;
+
+#define DEFINE_FIXED_DIV_CLK(clk_name, _div, _parent) \
+static struct div_clk clk_name = { \
+ .div = _div, \
+ .c = { \
+ .parent = _parent, \
+ .dbg_name = #clk_name, \
+ .ops = &clk_ops_div, \
+ CLK_INIT(clk_name.c), \
+ } \
+}
+
+#define DEFINE_FIXED_SLAVE_DIV_CLK(clk_name, _div, _parent) \
+static struct div_clk clk_name = { \
+ .div = _div, \
+ .c = { \
+ .parent = _parent, \
+ .dbg_name = #clk_name, \
+ .ops = &clk_ops_slave_div, \
+ CLK_INIT(clk_name.c), \
+ } \
+}
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ecm_ipa.h b/arch/arm/mach-msm/include/mach/ecm_ipa.h
index 008a659..f6afb2a 100644
--- a/arch/arm/mach-msm/include/mach/ecm_ipa.h
+++ b/arch/arm/mach-msm/include/mach/ecm_ipa.h
@@ -24,15 +24,35 @@
enum ipa_dp_evt_type evt,
unsigned long data);
+/*
+ * struct ecm_ipa_params - parameters for ecm_ipa initialization API
+ *
+ * @ecm_ipa_rx_dp_notify: ecm_ipa will set this callback (out parameter).
+ * this callback shall be supplied for ipa_connect upon pipe
+ * connection (USB->IPA), once IPA driver receive data packets
+ * from USB pipe destined for Apps this callback will be called.
+ * @ecm_ipa_tx_dp_notify: ecm_ipa will set this callback (out parameter).
+ * this callback shall be supplied for ipa_connect upon pipe
+ * connection (IPA->USB), once IPA driver send packets destined
+ * for USB, IPA BAM will notify for Tx-complete.
+ * @priv: ecm_ipa will set this pointer (out parameter).
+ * This pointer will hold the network device for later interaction
+ * with ecm_ipa APIs
+ * @host_ethaddr: host Ethernet address in network order
+ * @device_ethaddr: device Ethernet address in network order
+ */
+struct ecm_ipa_params {
+ ecm_ipa_callback ecm_ipa_rx_dp_notify;
+ ecm_ipa_callback ecm_ipa_tx_dp_notify;
+ u8 host_ethaddr[ETH_ALEN];
+ u8 device_ethaddr[ETH_ALEN];
+ void *private;
+};
+
#ifdef CONFIG_ECM_IPA
-int ecm_ipa_init(ecm_ipa_callback * ecm_ipa_rx_dp_notify,
- ecm_ipa_callback * ecm_ipa_tx_dp_notify,
- void **priv);
-
-int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
- void *priv);
+int ecm_ipa_init(struct ecm_ipa_params *params);
int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
void *priv);
@@ -43,15 +63,7 @@
#else /* CONFIG_ECM_IPA*/
-static inline int ecm_ipa_init(ecm_ipa_callback *ecm_ipa_rx_dp_notify,
- ecm_ipa_callback *ecm_ipa_tx_dp_notify,
- void **priv)
-{
- return 0;
-}
-
-static inline int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
- void *priv)
+int ecm_ipa_init(struct ecm_ipa_params *params)
{
return 0;
}
diff --git a/arch/arm/mach-msm/include/mach/ipa.h b/arch/arm/mach-msm/include/mach/ipa.h
index b4fbaee..db5e126 100644
--- a/arch/arm/mach-msm/include/mach/ipa.h
+++ b/arch/arm/mach-msm/include/mach/ipa.h
@@ -464,6 +464,13 @@
int ipa_disconnect(u32 clnt_hdl);
/*
+ * Resume / Suspend
+ */
+int ipa_resume(u32 clnt_hdl);
+
+int ipa_suspend(u32 clnt_hdl);
+
+/*
* Configuration
*/
int ipa_cfg_ep(u32 clnt_hdl, const struct ipa_ep_cfg *ipa_ep_cfg);
@@ -696,6 +703,19 @@
}
/*
+ * Resume / Suspend
+ */
+static inline int ipa_resume(u32 clnt_hdl)
+{
+ return -EPERM;
+}
+
+static inline int ipa_suspend(u32 clnt_hdl)
+{
+ return -EPERM;
+}
+
+/*
* Configuration
*/
static inline int ipa_cfg_ep(u32 clnt_hdl,
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
index 2a62460..18e448d 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8610.h
@@ -24,6 +24,9 @@
#define MSM8610_MSM_SHARED_RAM_PHYS 0x0D900000
+#define MSM8610_QGIC_DIST_PHYS 0xF9000000
+#define MSM8610_QGIC_DIST_SIZE SZ_4K
+
#define MSM8610_APCS_GCC_PHYS 0xF9011000
#define MSM8610_APCS_GCC_SIZE SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index d4ea4ac..64531f0 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -36,11 +36,14 @@
#define of_board_is_rumi() of_machine_is_compatible("qcom,rumi")
#define of_board_is_fluid() of_machine_is_compatible("qcom,fluid")
#define of_board_is_liquid() of_machine_is_compatible("qcom,liquid")
+#define of_board_is_dragonboard() \
+ of_machine_is_compatible("qcom,dragonboard")
#define machine_is_msm8974() of_machine_is_compatible("qcom,msm8974")
#define machine_is_msm9625() of_machine_is_compatible("qcom,msm9625")
#define machine_is_msm8610() of_machine_is_compatible("qcom,msm8610")
#define machine_is_msm8226() of_machine_is_compatible("qcom,msm8226")
+#define machine_is_apq8074() of_machine_is_compatible("qcom,apq8074")
#define early_machine_is_msm8610() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8610")
@@ -55,11 +58,13 @@
#define of_board_is_rumi() 0
#define of_board_is_fluid() 0
#define of_board_is_liquid() 0
+#define of_board_is_dragonboard() 0
#define machine_is_msm8974() 0
#define machine_is_msm9625() 0
#define machine_is_msm8610() 0
#define machine_is_msm8226() 0
+#define machine_is_apq8074() 0
#define early_machine_is_msm8610() 0
#define early_machine_is_mpq8092() 0
@@ -67,6 +72,7 @@
#define early_machine_is_msmkrypton() 0
#endif
+#define PLATFORM_SUBTYPE_MDM 1
#define PLATFORM_SUBTYPE_SGLTE 6
enum msm_cpu {
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 4d4703f..893db0b 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,6 +41,7 @@
* @powerup: Start a subsystem
* @crash_shutdown: Shutdown a subsystem when the system crashes (can't sleep)
* @ramdump: Collect a ramdump of the subsystem
+ * @is_loadable: Indicate if subsystem firmware is loadable via pil framework
*/
struct subsys_desc {
const char *name;
@@ -56,6 +57,7 @@
void (*crash_shutdown)(const struct subsys_desc *desc);
int (*ramdump)(int, const struct subsys_desc *desc);
unsigned int err_ready_irq;
+ int is_loadable;
};
#if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 37dbbab..1c4a317 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -574,6 +574,7 @@
#ifdef CONFIG_ARCH_MSM8610
static struct map_desc msm8610_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(QGIC_DIST, MSM8610),
MSM_CHIP_DEVICE(APCS_GCC, MSM8610),
MSM_CHIP_DEVICE(TLMM, MSM8610),
MSM_CHIP_DEVICE(MPM2_PSHOLD, MSM8610),
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 33a0aff..9014f37 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -133,6 +133,7 @@
#define LDO_DELTA_MIN 10000
#define LDO_DELTA_MAX 100000
+#define MSM_L2_SAW_PHYS 0xf9012000
/**
* struct pmic_gang_vreg -
* @name: the string used to represent the gang
@@ -1336,6 +1337,7 @@
void secondary_cpu_hs_init(void *base_ptr)
{
uint32_t reg_val;
+ void *l2_saw_base;
/* Turn on the BHS, turn off LDO Bypass and power down LDO */
reg_val = BHS_CNT_DEFAULT << BHS_CNT_BIT_POS
@@ -1361,9 +1363,26 @@
/* Finally turn on the bypass so that BHS supplies power */
reg_val |= LDO_BYP_MASK;
writel_relaxed(reg_val, base_ptr + APC_PWR_GATE_CTL);
+
+ if (the_gang && the_gang->manage_phases)
+ return;
+
+ /*
+ * If the driver has not yet started to manage phases then enable
+ * max phases.
+ */
+ l2_saw_base = ioremap_nocache(MSM_L2_SAW_PHYS, SZ_4K);
+ if (!l2_saw_base) {
+ __WARN();
+ return;
+ }
+ writel_relaxed(0x10003, l2_saw_base + 0x1c);
+ mb();
+ udelay(PHASE_SETTLING_TIME_US);
+
+ iounmap(l2_saw_base);
}
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("KRAIT POWER regulator driver");
-MODULE_VERSION("1.0");
MODULE_ALIAS("platform:"KRAIT_REGULATOR_DRIVER_NAME);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 6ff8152..5002a7d 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -574,6 +574,10 @@
curr = client->curr;
pdata = client->pdata;
+ if (!pdata) {
+ MSM_BUS_ERR("Null pdata passed to update-request\n");
+ return -ENXIO;
+ }
if (index >= pdata->num_usecases) {
MSM_BUS_ERR("Client %u passed invalid index: %d\n",
@@ -718,7 +722,7 @@
{
int i, src, pnode, index;
struct msm_bus_client *client = (struct msm_bus_client *)(cl);
- if (IS_ERR(client)) {
+ if (IS_ERR_OR_NULL(client)) {
MSM_BUS_ERR("msm_bus_scale_reset_pnodes error\n");
return;
}
@@ -739,7 +743,7 @@
void msm_bus_scale_unregister_client(uint32_t cl)
{
struct msm_bus_client *client = (struct msm_bus_client *)(cl);
- if (IS_ERR(client) || (!client))
+ if (IS_ERR_OR_NULL(client))
return;
if (client->curr != 0)
msm_bus_scale_client_update_request(cl, 0);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
index b45efad..ff3dc21 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
@@ -437,10 +437,7 @@
},
};
-static int mport_mdp[] = {
- MSM_BUS_MASTER_PORT_MDP_PORT0,
- MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
static int mport_graphics_3d_port0[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT0,};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
index 91d106e..af51355 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8930.c
@@ -377,10 +377,7 @@
},
};
-static int mport_mdp[] = {
- MSM_BUS_MASTER_PORT_MDP_PORT0,
- MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
index 158dee3..295b91b 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8960.c
@@ -440,10 +440,7 @@
},
};
-static int mport_mdp[] = {
- MSM_BUS_MASTER_PORT_MDP_PORT0,
- MSM_BUS_MASTER_PORT_MDP_PORT1,
-};
+static int mport_mdp[] = {MSM_BUS_MASTER_PORT_MDP_PORT0,};
static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
static int mport_graphics_3d[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D,};
diff --git a/arch/arm/mach-msm/ocmem_core.c b/arch/arm/mach-msm/ocmem_core.c
index 4ed4eda..9b18c59 100644
--- a/arch/arm/mach-msm/ocmem_core.c
+++ b/arch/arm/mach-msm/ocmem_core.c
@@ -66,7 +66,7 @@
#define NUM_PORTS_SHIFT (0)
#define GFX_MPU_SHIFT (12)
-#define NUM_MACROS_MASK (0xF << 8)
+#define NUM_MACROS_MASK (0x3F << 8)
#define NUM_MACROS_SHIFT (8)
#define INTERLEAVING_MASK (0x1 << 17)
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index cf29cf1..b186a4d 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -515,6 +515,17 @@
drv->subsys_desc.start = pronto_start;
drv->subsys_desc.stop = pronto_stop;
+ ret = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-err-ready", 0);
+ if (ret < 0)
+ return ret;
+
+ ret = gpio_to_irq(ret);
+ if (ret < 0)
+ return ret;
+
+ drv->subsys_desc.err_ready_irq = ret;
+
INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
drv->subsys = subsys_register(&drv->subsys_desc);
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index c1c3100..e993282 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -92,7 +92,6 @@
void *smem_ramdump_dev;
bool crash_shutdown;
bool ignore_errors;
- int is_loadable;
int err_fatal_irq;
int force_stop_gpio;
};
@@ -502,7 +501,7 @@
{
struct mba_data *drv = subsys_to_drv(subsys);
- if (!drv->is_loadable)
+ if (!subsys->is_loadable)
return 0;
pil_shutdown(&drv->desc);
pil_shutdown(&drv->q6->desc);
@@ -514,7 +513,7 @@
struct mba_data *drv = subsys_to_drv(subsys);
int ret;
- if (!drv->is_loadable)
+ if (!subsys->is_loadable)
return 0;
/*
* At this time, the modem is shutdown. Therefore this function cannot
@@ -601,7 +600,7 @@
int ret;
struct mba_data *drv = subsys_to_drv(desc);
- if (!drv->is_loadable)
+ if (!desc->is_loadable)
return 0;
ret = pil_boot(&drv->q6->desc);
@@ -624,7 +623,7 @@
{
struct mba_data *drv = subsys_to_drv(desc);
- if (!drv->is_loadable)
+ if (!desc->is_loadable)
return;
pil_shutdown(&drv->desc);
@@ -650,6 +649,17 @@
drv->subsys_desc.start = mss_start;
drv->subsys_desc.stop = mss_stop;
+ ret = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,gpio-err-ready", 0);
+ if (ret < 0)
+ return ret;
+
+ ret = gpio_to_irq(ret);
+ if (ret < 0)
+ return ret;
+
+ drv->subsys_desc.err_ready_irq = ret;
+
drv->subsys = subsys_register(&drv->subsys_desc);
if (IS_ERR(drv->subsys)) {
ret = PTR_ERR(drv->subsys);
@@ -815,16 +825,17 @@
static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
{
struct mba_data *drv;
- int ret, err_fatal_gpio;
+ int ret, err_fatal_gpio, is_loadable;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
return -ENOMEM;
platform_set_drvdata(pdev, drv);
- drv->is_loadable = of_property_read_bool(pdev->dev.of_node,
+ is_loadable = of_property_read_bool(pdev->dev.of_node,
"qcom,is-loadable");
- if (drv->is_loadable) {
+ if (is_loadable) {
+ drv->subsys_desc.is_loadable = 1;
ret = pil_mss_loadable_init(drv, pdev);
if (ret)
return ret;
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
index ff7ba33..a3af3e78 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/version_b/q6usm_b.c
@@ -17,7 +17,7 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/msm_audio.h>
-#include <sound/apr_audio.h>
+#include <sound/apr_audio-v2.h>
#include <mach/qdsp6v2/apr_us_b.h>
#include "q6usm.h"
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index fb44e16..9479d46c 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -495,6 +495,9 @@
if (ret)
return ret;
+ if (!subsys->desc->is_loadable)
+ return 0;
+
ret = wait_for_err_ready(subsys);
if (ret)
/* pil-boot succeeded but we need to shutdown
diff --git a/block/blk-core.c b/block/blk-core.c
index 69764df..2b6595c 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1123,7 +1123,7 @@
* urgent requests. We want to be able to track this
* down.
*/
- pr_err("%s(): requeueing an URGENT request", __func__);
+ pr_err("%s(): reinserting an URGENT request", __func__);
WARN_ON(!q->dispatched_urgent);
q->dispatched_urgent = false;
}
@@ -2018,6 +2018,10 @@
* not be passed by new incoming requests
*/
rq->cmd_flags |= REQ_STARTED;
+ if (rq->cmd_flags & REQ_URGENT) {
+ WARN_ON(q->dispatched_urgent);
+ q->dispatched_urgent = true;
+ }
trace_block_rq_issue(q, rq);
}
@@ -2151,13 +2155,8 @@
struct request *rq;
rq = blk_peek_request(q);
- if (rq) {
- if (rq->cmd_flags & REQ_URGENT) {
- WARN_ON(q->dispatched_urgent);
- q->dispatched_urgent = true;
- }
+ if (rq)
blk_start_request(rq);
- }
return rq;
}
EXPORT_SYMBOL(blk_fetch_request);
diff --git a/drivers/coresight/Kconfig b/drivers/coresight/Kconfig
index 5e00570..7ec83dd 100644
--- a/drivers/coresight/Kconfig
+++ b/drivers/coresight/Kconfig
@@ -105,6 +105,16 @@
If unsure, say 'N' here to avoid potential power and performance
penalty.
+config CORESIGHT_HWEVENT
+ bool "CoreSight Hardware Event driver"
+ depends on CORESIGHT_STM
+ select CORESIGHT_CSR
+ help
+ This driver provides support for monitoring and tracing CoreSight
+ Hardware Event across STM interface. It configures Coresight
+ Hardware Event mux control registers to select hardware events
+ based on user input.
+
config CORESIGHT_ETM
bool "CoreSight Embedded Trace Macrocell driver"
help
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 0595064..0e2e2d9 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -11,5 +11,6 @@
obj-$(CONFIG_CORESIGHT_FUNNEL) += coresight-funnel.o
obj-$(CONFIG_CORESIGHT_REPLICATOR) += coresight-replicator.o
obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
+obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
obj-$(CONFIG_CORESIGHT_ETM) += coresight-etm.o coresight-etm-cp14.o
obj-$(CONFIG_CORESIGHT_EVENT) += coresight-event.o
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 1c2ab25..8195184 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -73,6 +73,7 @@
struct csr_drvdata {
void __iomem *base;
+ phys_addr_t pbase;
struct device *dev;
struct coresight_device *csdev;
uint32_t blksize;
@@ -134,6 +135,30 @@
}
EXPORT_SYMBOL(msm_qdss_csr_disable_flush);
+int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val)
+{
+ struct csr_drvdata *drvdata = csrdrvdata;
+ int ret = 0;
+
+ CSR_UNLOCK(drvdata);
+
+ if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL0))
+ csr_writel(drvdata, val, CSR_STMEXTHWCTRL0);
+ else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL1))
+ csr_writel(drvdata, val, CSR_STMEXTHWCTRL1);
+ else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL2))
+ csr_writel(drvdata, val, CSR_STMEXTHWCTRL2);
+ else if (addr == (drvdata->pbase + CSR_STMEXTHWCTRL3))
+ csr_writel(drvdata, val, CSR_STMEXTHWCTRL3);
+ else
+ ret = -EINVAL;
+
+ CSR_LOCK(drvdata);
+
+ return ret;
+}
+EXPORT_SYMBOL(coresight_csr_hwctrl_set);
+
static int __devinit csr_probe(struct platform_device *pdev)
{
int ret;
@@ -161,6 +186,7 @@
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr-base");
if (!res)
return -ENODEV;
+ drvdata->pbase = res->start;
drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
if (!drvdata->base)
diff --git a/drivers/coresight/coresight-hwevent.c b/drivers/coresight/coresight-hwevent.c
new file mode 100644
index 0000000..777484d
--- /dev/null
+++ b/drivers/coresight/coresight-hwevent.c
@@ -0,0 +1,341 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/of_coresight.h>
+#include <linux/coresight.h>
+#include <linux/of.h>
+
+#include "coresight-priv.h"
+
+struct hwevent_mux {
+ phys_addr_t start;
+ phys_addr_t end;
+};
+
+struct hwevent_drvdata {
+ struct device *dev;
+ struct coresight_device *csdev;
+ struct clk *clk;
+ struct mutex mutex;
+ int nr_hclk;
+ struct clk **hclk;
+ int nr_hmux;
+ struct hwevent_mux *hmux;
+ bool enable;
+};
+
+static int hwevent_enable(struct hwevent_drvdata *drvdata)
+{
+ int ret, i;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (drvdata->enable)
+ goto out;
+
+ ret = clk_prepare_enable(drvdata->clk);
+ if (ret)
+ goto err0;
+ for (i = 0; i < drvdata->nr_hclk; i++) {
+ ret = clk_prepare_enable(drvdata->hclk[i]);
+ if (ret)
+ goto err1;
+ }
+ drvdata->enable = true;
+ dev_info(drvdata->dev, "Hardware Event driver enabled\n");
+out:
+ mutex_unlock(&drvdata->mutex);
+ return 0;
+err1:
+ clk_disable_unprepare(drvdata->clk);
+ for (i--; i >= 0; i--)
+ clk_disable_unprepare(drvdata->hclk[i]);
+err0:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+
+static void hwevent_disable(struct hwevent_drvdata *drvdata)
+{
+ int i;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (!drvdata->enable)
+ goto out;
+
+ drvdata->enable = false;
+ clk_disable_unprepare(drvdata->clk);
+ for (i = 0; i < drvdata->nr_hclk; i++)
+ clk_disable_unprepare(drvdata->hclk[i]);
+ dev_info(drvdata->dev, "Hardware Event driver disabled\n");
+out:
+ mutex_unlock(&drvdata->mutex);
+}
+
+static ssize_t hwevent_show_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val = drvdata->enable;
+
+ return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t hwevent_store_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+ int ret = 0;
+
+ if (sscanf(buf, "%lx", &val) != 1)
+ return -EINVAL;
+
+ if (val)
+ ret = hwevent_enable(drvdata);
+ else
+ hwevent_disable(drvdata);
+
+ if (ret)
+ return ret;
+ return size;
+}
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, hwevent_show_enable,
+ hwevent_store_enable);
+
+static ssize_t hwevent_store_setreg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ void *hwereg;
+ phys_addr_t addr;
+ uint32_t val;
+ int ret, i;
+
+ if (sscanf(buf, "%x %x", &addr, &val) != 2)
+ return -EINVAL;
+
+ mutex_lock(&drvdata->mutex);
+
+ if (!drvdata->enable) {
+ dev_err(dev, "Hardware Event driver not enabled\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < drvdata->nr_hmux; i++) {
+ if ((addr >= drvdata->hmux[i].start) &&
+ (addr < drvdata->hmux[i].end)) {
+ hwereg = devm_ioremap(dev,
+ drvdata->hmux[i].start,
+ drvdata->hmux[i].end -
+ drvdata->hmux[i].start);
+ if (!hwereg) {
+ dev_err(dev, "unable to map address 0x%x\n",
+ addr);
+ ret = -ENOMEM;
+ goto err;
+ }
+ writel_relaxed(val, hwereg + addr -
+ drvdata->hmux[i].start);
+ /* Ensure writes to hwevent control registers
+ are completed before unmapping the address
+ */
+ mb();
+ devm_iounmap(dev, hwereg);
+ break;
+ }
+ }
+
+ if (i == drvdata->nr_hmux) {
+ ret = coresight_csr_hwctrl_set(addr, val);
+ if (ret) {
+ dev_err(dev, "invalid mux control register address\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ mutex_unlock(&drvdata->mutex);
+ return size;
+err:
+ mutex_unlock(&drvdata->mutex);
+ return ret;
+}
+static DEVICE_ATTR(setreg, S_IWUSR, NULL, hwevent_store_setreg);
+
+static struct attribute *hwevent_attrs[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_setreg.attr,
+ NULL,
+};
+
+static struct attribute_group hwevent_attr_grp = {
+ .attrs = hwevent_attrs,
+};
+
+static const struct attribute_group *hwevent_attr_grps[] = {
+ &hwevent_attr_grp,
+ NULL,
+};
+
+static int __devinit hwevent_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct hwevent_drvdata *drvdata;
+ struct coresight_desc *desc;
+ struct coresight_platform_data *pdata;
+ struct resource *res;
+ int ret, i;
+ const char *hmux_name, *hclk_name;
+
+ if (pdev->dev.of_node) {
+ pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ pdev->dev.platform_data = pdata;
+ }
+
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ if (pdev->dev.of_node)
+ drvdata->nr_hmux = of_property_count_strings(pdev->dev.of_node,
+ "reg-names");
+
+ if (drvdata->nr_hmux > 0) {
+ drvdata->hmux = devm_kzalloc(dev, drvdata->nr_hmux *
+ sizeof(*drvdata->hmux),
+ GFP_KERNEL);
+ if (!drvdata->hmux)
+ return -ENOMEM;
+ for (i = 0; i < drvdata->nr_hmux; i++) {
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "reg-names", i,
+ &hmux_name);
+ if (ret)
+ return ret;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ hmux_name);
+ if (!res)
+ return -ENODEV;
+ drvdata->hmux[i].start = res->start;
+ drvdata->hmux[i].end = res->end;
+ }
+ } else if (drvdata->nr_hmux < 0) {
+ return drvdata->nr_hmux;
+ } else {
+ /* return error if reg-names in dt node is empty string */
+ return -ENODEV;
+ }
+
+ mutex_init(&drvdata->mutex);
+
+ drvdata->clk = devm_clk_get(dev, "core_clk");
+ if (IS_ERR(drvdata->clk))
+ return PTR_ERR(drvdata->clk);
+
+ ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
+ if (ret)
+ return ret;
+
+ if (pdev->dev.of_node)
+ drvdata->nr_hclk = of_property_count_strings(pdev->dev.of_node,
+ "qcom,hwevent-clks");
+ if (drvdata->nr_hclk > 0) {
+ drvdata->hclk = devm_kzalloc(dev, drvdata->nr_hclk *
+ sizeof(*drvdata->hclk),
+ GFP_KERNEL);
+ if (!drvdata->hclk)
+ return -ENOMEM;
+ for (i = 0; i < drvdata->nr_hclk; i++) {
+ ret = of_property_read_string_index(pdev->dev.of_node,
+ "qcom,hwevent-clks",
+ i, &hclk_name);
+ if (ret)
+ return ret;
+ drvdata->hclk[i] = devm_clk_get(dev, hclk_name);
+ if (IS_ERR(drvdata->hclk[i]))
+ return PTR_ERR(drvdata->hclk[i]);
+ }
+ }
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->type = CORESIGHT_DEV_TYPE_NONE;
+ desc->pdata = pdev->dev.platform_data;
+ desc->dev = &pdev->dev;
+ desc->groups = hwevent_attr_grps;
+ desc->owner = THIS_MODULE;
+ drvdata->csdev = coresight_register(desc);
+ if (IS_ERR(drvdata->csdev))
+ return PTR_ERR(drvdata->csdev);
+
+ dev_info(dev, "Hardware Event driver initialized\n");
+ return 0;
+}
+
+static int __devexit hwevent_remove(struct platform_device *pdev)
+{
+ struct hwevent_drvdata *drvdata = platform_get_drvdata(pdev);
+
+ coresight_unregister(drvdata->csdev);
+ return 0;
+}
+
+static struct of_device_id hwevent_match[] = {
+ {.compatible = "qcom,coresight-hwevent"},
+ {}
+};
+
+static struct platform_driver hwevent_driver = {
+ .probe = hwevent_probe,
+ .remove = __devexit_p(hwevent_remove),
+ .driver = {
+ .name = "coresight-hwevent",
+ .owner = THIS_MODULE,
+ .of_match_table = hwevent_match,
+ },
+};
+
+static int __init hwevent_init(void)
+{
+ return platform_driver_register(&hwevent_driver);
+}
+module_init(hwevent_init);
+
+static void __exit hwevent_exit(void)
+{
+ platform_driver_unregister(&hwevent_driver);
+}
+module_exit(hwevent_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight Hardware Event driver");
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 258ff09..f208185 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -40,10 +40,13 @@
extern void msm_qdss_csr_enable_bam_to_usb(void);
extern void msm_qdss_csr_disable_bam_to_usb(void);
extern void msm_qdss_csr_disable_flush(void);
+extern int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val);
#else
static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_flush(void) {}
+static inline int coresight_csr_hwctrl_set(phys_addr_t addr,
+ uint32_t val) { return -ENOSYS; }
#endif
#ifdef CONFIG_CORESIGHT_ETM
extern unsigned int etm_readl_cp14(uint32_t off);
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 1f16497..58fa5c9 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1704,7 +1704,14 @@
bam.summing_threshold = 64;
/* SPS driver wll handle the crypto BAM IRQ */
bam.irq = (u32)pce_dev->ce_sps.bam_irq;
- bam.manage = SPS_BAM_MGR_LOCAL;
+ /*
+ * Set flag to indicate BAM global device control is managed
+ * remotely.
+ */
+ if (pce_dev->support_cmd_dscr == false)
+ bam.manage = SPS_BAM_MGR_DEVICE_REMOTE;
+ else
+ bam.manage = SPS_BAM_MGR_LOCAL;
bam.ee = 1;
pr_debug("bam physical base=0x%x\n", (u32)bam.phys_addr);
@@ -2990,8 +2997,6 @@
pce_dev->dir = c_req->dir;
if ((pce_dev->ce_sps.minor_version == 0) && (c_req->dir == QCE_DECRYPT)
&& (c_req->mode == QCE_MODE_CBC)) {
- struct ablkcipher_request *areq =
- (struct ablkcipher_request *)pce_dev->areq;
memcpy(pce_dev->dec_iv, (unsigned char *)sg_virt(areq->src) +
areq->src->length - 16,
NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE);
@@ -3140,8 +3145,6 @@
pce_dev->is_shared = of_property_read_bool((&pdev->dev)->of_node,
"qcom,ce-hw-shared");
- pce_dev->support_cmd_dscr = of_property_read_bool((&pdev->dev)->of_node,
- "qcom,ce-hw-support-cmd-dscr");
if (of_property_read_u32((&pdev->dev)->of_node,
"qcom,bam-pipe-pair",
&pce_dev->ce_sps.pipe_pair_index)) {
@@ -3176,7 +3179,7 @@
pce_dev->ce_sps.bam_mem = resource->start;
pce_dev->ce_sps.bam_iobase = ioremap_nocache(resource->start,
resource_size(resource));
- if (!pce_dev->iobase) {
+ if (!pce_dev->ce_sps.bam_iobase) {
rc = -ENOMEM;
pr_err("Can not map BAM io memory\n");
goto err_getting_bam_info;
@@ -3189,7 +3192,6 @@
pr_warn("ce_bam_phy_reg_base=0x%x ", pce_dev->ce_sps.bam_mem);
pr_warn("ce_bam_virt_reg_base=0x%x\n",
(uint32_t)pce_dev->ce_sps.bam_iobase);
-
resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (resource) {
pce_dev->ce_sps.bam_irq = resource->start;
@@ -3355,6 +3357,7 @@
void *qce_open(struct platform_device *pdev, int *rc)
{
struct qce_device *pce_dev;
+ uint32_t bam_cfg = 0 ;
pce_dev = kzalloc(sizeof(struct qce_device), GFP_KERNEL);
if (!pce_dev) {
@@ -3396,10 +3399,16 @@
goto err;
}
*rc = 0;
+
+ bam_cfg = readl_relaxed(pce_dev->ce_sps.bam_iobase +
+ CRYPTO_BAM_CNFG_BITS_REG);
+ pce_dev->support_cmd_dscr = (bam_cfg & CRYPTO_BAM_CD_ENABLE_MASK) ?
+ true : false;
qce_init_ce_cfg_val(pce_dev);
qce_setup_ce_sps_data(pce_dev);
qce_sps_init(pce_dev);
+
qce_disable_clk(pce_dev);
return pce_dev;
@@ -3429,6 +3438,9 @@
if (handle == NULL)
return -ENODEV;
+ qce_enable_clk(pce_dev);
+ qce_sps_exit(pce_dev);
+
if (pce_dev->iobase)
iounmap(pce_dev->iobase);
if (pce_dev->coh_vmem)
@@ -3438,7 +3450,6 @@
qce_disable_clk(pce_dev);
__qce_deinit_clk(pce_dev);
- qce_sps_exit(pce_dev);
kfree(handle);
return 0;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 7666e74..a09bb42 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -323,10 +323,10 @@
u32 qcedev_sha_fail;
};
-static struct qcedev_stat _qcedev_stat[MAX_QCE_DEVICE];
+static struct qcedev_stat _qcedev_stat;
static struct dentry *_debug_dent;
static char _debug_read_buf[DEBUG_MAX_RW_BUF];
-static int _debug_qcedev[MAX_QCE_DEVICE];
+static int _debug_qcedev;
static struct qcedev_control *qcedev_minor_to_control(unsigned n)
{
@@ -693,7 +693,7 @@
if (ret)
qcedev_areq->err = -EIO;
- pstat = &_qcedev_stat[podev->pdev->id];
+ pstat = &_qcedev_stat;
if (qcedev_areq->op_type == QCEDEV_CRYPTO_OPER_CIPHER) {
switch (qcedev_areq->cipher_op_req.op) {
case QCEDEV_OPER_DEC:
@@ -1739,7 +1739,7 @@
return -ENOTTY;
init_completion(&qcedev_areq.complete);
- pstat = &_qcedev_stat[podev->pdev->id];
+ pstat = &_qcedev_stat;
switch (cmd) {
case QCEDEV_IOCTL_LOCK_CE:
@@ -2026,11 +2026,7 @@
struct qcedev_stat *pstat;
int len = 0;
- if (id < 0) {
- pr_err("Crypto id is %d, cannot be negative\n", id);
- return len;
- }
- pstat = &_qcedev_stat[id];
+ pstat = &_qcedev_stat;
len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
"\nQualcomm QCE dev driver %d Statistics:\n",
id + 1);
@@ -2076,10 +2072,7 @@
static ssize_t _debug_stats_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
-
- int qcedev = *((int *) file->private_data);
-
- memset((char *)&_qcedev_stat[qcedev], 0, sizeof(struct qcedev_stat));
+ memset((char *)&_qcedev_stat, 0, sizeof(struct qcedev_stat));
return count;
};
@@ -2093,7 +2086,6 @@
{
int rc;
char name[DEBUG_MAX_FNAME];
- int i;
struct dentry *dent;
_debug_dent = debugfs_create_dir("qcedev", NULL);
@@ -2103,17 +2095,15 @@
return PTR_ERR(_debug_dent);
}
- for (i = 0; i < MAX_QCE_DEVICE; i++) {
- snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
- _debug_qcedev[i] = i;
- dent = debugfs_create_file(name, 0644, _debug_dent,
- &_debug_qcedev[i], &_debug_stats_ops);
- if (dent == NULL) {
- pr_err("qcedev debugfs_create_file fail, error %ld\n",
- PTR_ERR(dent));
- rc = PTR_ERR(dent);
- goto err;
- }
+ snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", 1);
+ _debug_qcedev = 0;
+ dent = debugfs_create_file(name, 0644, _debug_dent,
+ &_debug_qcedev, &_debug_stats_ops);
+ if (dent == NULL) {
+ pr_err("qcedev debugfs_create_file fail, error %ld\n",
+ PTR_ERR(dent));
+ rc = PTR_ERR(dent);
+ goto err;
}
return 0;
err:
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 40fb29ac..d1cb933 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -42,7 +42,6 @@
#include "qce.h"
-#define MAX_CRYPTO_DEVICE 3
#define DEBUG_MAX_FNAME 16
#define DEBUG_MAX_RW_BUF 1024
@@ -53,6 +52,8 @@
u32 aead_sha1_des_dec;
u32 aead_sha1_3des_enc;
u32 aead_sha1_3des_dec;
+ u32 aead_ccm_aes_enc;
+ u32 aead_ccm_aes_dec;
u32 aead_op_success;
u32 aead_op_fail;
u32 ablk_cipher_aes_enc;
@@ -72,7 +73,7 @@
u32 sha_hmac_op_success;
u32 sha_hmac_op_fail;
};
-static struct crypto_stat _qcrypto_stat[MAX_CRYPTO_DEVICE];
+static struct crypto_stat _qcrypto_stat;
static struct dentry *_debug_dent;
static char _debug_read_buf[DEBUG_MAX_RW_BUF];
@@ -405,6 +406,39 @@
return i;
}
+size_t qcrypto_sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen)
+{
+ int i;
+ size_t offset, len;
+
+ for (i = 0, offset = 0; i < nents; ++i) {
+ len = sg_copy_from_buffer(sgl, 1, buf, buflen);
+ buf += len;
+ buflen -= len;
+ offset += len;
+ sgl = scatterwalk_sg_next(sgl);
+ }
+
+ return offset;
+}
+
+size_t qcrypto_sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen)
+{
+ int i;
+ size_t offset, len;
+
+ for (i = 0, offset = 0; i < nents; ++i) {
+ len = sg_copy_to_buffer(sgl, 1, buf, buflen);
+ buf += len;
+ buflen -= len;
+ offset += len;
+ sgl = scatterwalk_sg_next(sgl);
+ }
+
+ return offset;
+}
static struct qcrypto_alg *_qcrypto_sha_alg_alloc(struct crypto_priv *cp,
struct ahash_alg *template)
{
@@ -581,11 +615,7 @@
struct crypto_stat *pstat;
int len = 0;
- if (id < 0) {
- pr_err("Crypto id is %d, cannot be negative\n", id);
- return len;
- }
- pstat = &_qcrypto_stat[id];
+ pstat = &_qcrypto_stat;
len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
"\nQualcomm crypto accelerator %d Statistics:\n",
id + 1);
@@ -641,6 +671,13 @@
pstat->aead_sha1_3des_dec);
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD CCM-AES encryption : %d\n",
+ pstat->aead_ccm_aes_enc);
+ len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
+ " AEAD CCM-AES decryption : %d\n",
+ pstat->aead_ccm_aes_dec);
+
+ len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" AEAD operation success : %d\n",
pstat->aead_op_success);
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
@@ -858,7 +895,7 @@
uint32_t diglen = crypto_ahash_digestsize(ahash);
uint32_t *auth32 = (uint32_t *)authdata;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qce_ahash_complete: %p ret %d\n",
@@ -916,7 +953,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qce_ablk_cipher_complete: %p ret %d\n",
@@ -943,7 +980,7 @@
areq->dst = rctx->orig_dst;
num_sg = qcrypto_count_sg(areq->dst, areq->nbytes);
- bytes = sg_copy_from_buffer(areq->dst, num_sg,
+ bytes = qcrypto_sg_copy_from_buffer(areq->dst, num_sg,
rctx->data, areq->nbytes);
if (bytes != areq->nbytes)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
@@ -967,7 +1004,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
@@ -988,7 +1025,7 @@
nbytes = areq->cryptlen -
crypto_aead_authsize(aead);
num_sg = qcrypto_count_sg(areq->dst, nbytes);
- bytes = sg_copy_from_buffer(areq->dst, num_sg,
+ bytes = qcrypto_sg_copy_from_buffer(areq->dst, num_sg,
((char *)rctx->data + areq->assoclen),
nbytes);
if (bytes != nbytes)
@@ -1118,7 +1155,7 @@
qreq->assoclen = ALIGN((alen + len), 16);
num_sg = qcrypto_count_sg(sg, alen);
- bytes = sg_copy_to_buffer(sg, num_sg, adata, alen);
+ bytes = qcrypto_sg_copy_to_buffer(sg, num_sg, adata, alen);
if (bytes != alen)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes, alen);
@@ -1145,7 +1182,7 @@
rctx->orig_src = req->src;
rctx->orig_dst = req->dst;
- rctx->data = kzalloc((req->nbytes + 64), GFP_KERNEL);
+ rctx->data = kzalloc((req->nbytes + 64), GFP_ATOMIC);
if (rctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld for 0x%x\n",
@@ -1153,7 +1190,7 @@
return -ENOMEM;
}
num_sg = qcrypto_count_sg(req->src, req->nbytes);
- bytes = sg_copy_to_buffer(req->src, num_sg, rctx->data,
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, rctx->data,
req->nbytes);
if (bytes != req->nbytes)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
@@ -1294,7 +1331,7 @@
rctx->orig_src = req->src;
rctx->orig_dst = req->dst;
rctx->data = kzalloc((req->cryptlen + qreq.assoclen +
- qreq.authsize + 64*2), GFP_KERNEL);
+ qreq.authsize + 64*2), GFP_ATOMIC);
if (rctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld\n",
PTR_ERR(rctx->data));
@@ -1305,7 +1342,7 @@
memcpy((char *)rctx->data, qreq.assoc, qreq.assoclen);
num_sg = qcrypto_count_sg(req->src, req->cryptlen);
- bytes = sg_copy_to_buffer(req->src, num_sg,
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg,
rctx->data + qreq.assoclen , req->cryptlen);
if (bytes != req->cryptlen)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x",
@@ -1358,7 +1395,7 @@
int ret = 0;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
again:
spin_lock_irqsave(&cp->lock, flags);
@@ -1434,7 +1471,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1458,7 +1495,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1482,7 +1519,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1506,7 +1543,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1533,7 +1570,7 @@
(ctx->auth_key_len != AES_KEYSIZE_256))
return -EINVAL;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -1542,7 +1579,7 @@
rctx->mode = QCE_MODE_CCM;
rctx->iv = req->iv;
- pstat->aead_sha1_aes_enc++;
+ pstat->aead_ccm_aes_enc++;
return _qcrypto_queue_req(cp, &req->base);
}
@@ -1553,7 +1590,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1574,7 +1611,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1595,7 +1632,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1616,7 +1653,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1637,7 +1674,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1661,7 +1698,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1686,7 +1723,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1712,7 +1749,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1733,7 +1770,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1754,7 +1791,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1775,7 +1812,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1796,7 +1833,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
BUG_ON(crypto_tfm_alg_type(req->base.tfm) !=
CRYPTO_ALG_TYPE_ABLKCIPHER);
@@ -1824,7 +1861,7 @@
(ctx->auth_key_len != AES_KEYSIZE_256))
return -EINVAL;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -1833,7 +1870,7 @@
rctx->mode = QCE_MODE_CCM;
rctx->iv = req->iv;
- pstat->aead_sha1_aes_dec++;
+ pstat->aead_ccm_aes_dec++;
return _qcrypto_queue_req(cp, &req->base);
}
@@ -1939,7 +1976,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qcrypto_aead_encrypt_aes_cbc: %p\n", req);
@@ -1963,7 +2000,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
#ifdef QCRYPTO_DEBUG
dev_info(&cp->pdev->dev, "_qcrypto_aead_decrypt_aes_cbc: %p\n", req);
@@ -1988,7 +2025,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2012,7 +2049,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2032,7 +2069,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2057,7 +2094,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2081,7 +2118,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2101,7 +2138,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2123,7 +2160,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2146,7 +2183,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2166,7 +2203,7 @@
struct crypto_priv *cp = ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(req);
rctx->aead = 1;
@@ -2188,7 +2225,7 @@
struct qcrypto_cipher_req_ctx *rctx;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
rctx = aead_request_ctx(areq);
rctx->aead = 1;
@@ -2220,10 +2257,9 @@
static int _sha1_init(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
_sha_init(sha_ctx);
sha_ctx->alg = QCE_HASH_SHA1;
@@ -2241,10 +2277,9 @@
static int _sha256_init(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
_sha_init(sha_ctx);
sha_ctx->alg = QCE_HASH_SHA256;
@@ -2347,7 +2382,7 @@
srctx = ahash_request_ctx(req);
srctx->orig_src = req->src;
- srctx->data = kzalloc((req->nbytes + 64), GFP_KERNEL);
+ srctx->data = kzalloc((req->nbytes + 64), GFP_ATOMIC);
if (srctx->data == NULL) {
pr_err("Mem Alloc fail rctx->data, err %ld for 0x%x\n",
PTR_ERR(srctx->data), (req->nbytes + 64));
@@ -2355,7 +2390,8 @@
}
num_sg = qcrypto_count_sg(req->src, req->nbytes);
- bytes = sg_copy_to_buffer(req->src, num_sg, srctx->data, req->nbytes);
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, srctx->data,
+ req->nbytes);
if (bytes != req->nbytes)
pr_warn("bytes copied=0x%x bytes to copy= 0x%x", bytes,
req->nbytes);
@@ -2390,7 +2426,7 @@
if (total <= sha_block_size) {
k_src = &sha_ctx->trailing_buf[sha_ctx->trailing_buf_len];
num_sg = qcrypto_count_sg(req->src, len);
- bytes = sg_copy_to_buffer(req->src, num_sg, k_src, len);
+ bytes = qcrypto_sg_copy_to_buffer(req->src, num_sg, k_src, len);
sha_ctx->trailing_buf_len = total;
if (sha_ctx->alg == QCE_HASH_SHA1)
@@ -2431,13 +2467,13 @@
if (sha_ctx->trailing_buf_len) {
if (cp->ce_support.aligned_only) {
sha_ctx->sg = kzalloc(sizeof(struct scatterlist),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (sha_ctx->sg == NULL) {
pr_err("MemAlloc fail sha_ctx->sg, error %ld\n",
PTR_ERR(sha_ctx->sg));
return -ENOMEM;
}
- rctx->data2 = kzalloc((req->nbytes + 64), GFP_KERNEL);
+ rctx->data2 = kzalloc((req->nbytes + 64), GFP_ATOMIC);
if (rctx->data2 == NULL) {
pr_err("Mem Alloc fail srctx->data2, err %ld\n",
PTR_ERR(rctx->data2));
@@ -2458,7 +2494,7 @@
} else {
sg_mark_end(sg_last);
sha_ctx->sg = kzalloc(2 * (sizeof(struct scatterlist)),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (sha_ctx->sg == NULL) {
pr_err("MEMalloc fail sha_ctx->sg, error %ld\n",
PTR_ERR(sha_ctx->sg));
@@ -2688,7 +2724,7 @@
struct crypto_stat *pstat;
int ret = 0;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha1_hmac_digest++;
_sha_init(sha_ctx);
@@ -2715,7 +2751,7 @@
struct crypto_stat *pstat;
int ret = 0;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha256_hmac_digest++;
_sha_init(sha_ctx);
@@ -2853,10 +2889,9 @@
static int _sha1_hmac_digest(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha1_hmac_digest++;
_sha_init(sha_ctx);
@@ -2871,10 +2906,9 @@
static int _sha256_hmac_digest(struct ahash_request *req)
{
struct qcrypto_sha_ctx *sha_ctx = crypto_tfm_ctx(req->base.tfm);
- struct crypto_priv *cp = sha_ctx->cp;
struct crypto_stat *pstat;
- pstat = &_qcrypto_stat[cp->pdev->id];
+ pstat = &_qcrypto_stat;
pstat->sha256_hmac_digest++;
_sha_init(sha_ctx);
@@ -3327,12 +3361,6 @@
int i;
struct msm_ce_hw_support *platform_support;
- if (pdev->id >= MAX_CRYPTO_DEVICE) {
- pr_err("%s: device id %d exceeds allowed %d\n",
- __func__, pdev->id, MAX_CRYPTO_DEVICE);
- return -ENOENT;
- }
-
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp) {
pr_err("qcrypto Memory allocation of q_alg FAIL, error %ld\n",
@@ -3572,7 +3600,7 @@
},
};
-static int _debug_qcrypto[MAX_CRYPTO_DEVICE];
+static int _debug_qcrypto;
static int _debug_stats_open(struct inode *inode, struct file *file)
{
@@ -3599,9 +3627,7 @@
size_t count, loff_t *ppos)
{
- int qcrypto = *((int *) file->private_data);
-
- memset((char *)&_qcrypto_stat[qcrypto], 0, sizeof(struct crypto_stat));
+ memset((char *)&_qcrypto_stat, 0, sizeof(struct crypto_stat));
return count;
};
@@ -3615,7 +3641,6 @@
{
int rc;
char name[DEBUG_MAX_FNAME];
- int i;
struct dentry *dent;
_debug_dent = debugfs_create_dir("qcrypto", NULL);
@@ -3625,17 +3650,15 @@
return PTR_ERR(_debug_dent);
}
- for (i = 0; i < MAX_CRYPTO_DEVICE; i++) {
- snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
- _debug_qcrypto[i] = i;
- dent = debugfs_create_file(name, 0644, _debug_dent,
- &_debug_qcrypto[i], &_debug_stats_ops);
- if (dent == NULL) {
- pr_err("qcrypto debugfs_create_file fail, error %ld\n",
- PTR_ERR(dent));
- rc = PTR_ERR(dent);
- goto err;
- }
+ snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", 1);
+ _debug_qcrypto = 0;
+ dent = debugfs_create_file(name, 0644, _debug_dent,
+ &_debug_qcrypto, &_debug_stats_ops);
+ if (dent == NULL) {
+ pr_err("qcrypto debugfs_create_file fail, error %ld\n",
+ PTR_ERR(dent));
+ rc = PTR_ERR(dent);
+ goto err;
}
return 0;
err:
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 245d737..1be2702 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,10 @@
#define _DRIVERS_CRYPTO_MSM_QCRYPTOHW_50_H_
+#define CRYPTO_BAM_CNFG_BITS_REG 0x0007C
+#define CRYPTO_BAM_CD_ENABLE 27
+#define CRYPTO_BAM_CD_ENABLE_MASK (1 << CRYPTO_BAM_CD_ENABLE)
+
#define QCE_AUTH_REG_BYTE_COUNT 4
#define CRYPTO_VERSION_REG 0x1A000
@@ -28,7 +32,7 @@
#define CRYPTO_DATA_OUT3_REG 0x1A02C
#define CRYPTO_STATUS_REG 0x1A100
-#define CRYPTO_STATUS2_REG 0x1A100
+#define CRYPTO_STATUS2_REG 0x1A104
#define CRYPTO_ENGINES_AVAIL 0x1A108
#define CRYPTO_FIFO_SIZES_REG 0x1A10C
@@ -64,9 +68,9 @@
#define CRYPTO_ENCR_PIPE0_KEY2_REG 0x1E008
#define CRYPTO_ENCR_PIPE0_KEY3_REG 0x1E00C
#define CRYPTO_ENCR_PIPE0_KEY4_REG 0x1E010
-#define CRYPTO_ENCR_PIPE0_KEY5_REG 0x1E004
-#define CRYPTO_ENCR_PIPE0_KEY6_REG 0x1E008
-#define CRYPTO_ENCR_PIPE0_KEY7_REG 0x1E00C
+#define CRYPTO_ENCR_PIPE0_KEY5_REG 0x1E014
+#define CRYPTO_ENCR_PIPE0_KEY6_REG 0x1E018
+#define CRYPTO_ENCR_PIPE0_KEY7_REG 0x1E01C
#define CRYPTO_ENCR_PIPE1_KEY0_REG 0x1E020
#define CRYPTO_ENCR_PIPE1_KEY1_REG 0x1E024
@@ -185,56 +189,56 @@
#define CRYPTO_AUTH_PIPE0_KEY14_REG 0x1E838
#define CRYPTO_AUTH_PIPE0_KEY15_REG 0x1E83C
-#define CRYPTO_AUTH_PIPE1_KEY0_REG 0x1E800
-#define CRYPTO_AUTH_PIPE1_KEY1_REG 0x1E804
-#define CRYPTO_AUTH_PIPE1_KEY2_REG 0x1E808
-#define CRYPTO_AUTH_PIPE1_KEY3_REG 0x1E80C
-#define CRYPTO_AUTH_PIPE1_KEY4_REG 0x1E810
-#define CRYPTO_AUTH_PIPE1_KEY5_REG 0x1E814
-#define CRYPTO_AUTH_PIPE1_KEY6_REG 0x1E818
-#define CRYPTO_AUTH_PIPE1_KEY7_REG 0x1E81C
-#define CRYPTO_AUTH_PIPE1_KEY8_REG 0x1E820
-#define CRYPTO_AUTH_PIPE1_KEY9_REG 0x1E824
-#define CRYPTO_AUTH_PIPE1_KEY10_REG 0x1E828
-#define CRYPTO_AUTH_PIPE1_KEY11_REG 0x1E82C
-#define CRYPTO_AUTH_PIPE1_KEY12_REG 0x1E830
-#define CRYPTO_AUTH_PIPE1_KEY13_REG 0x1E834
-#define CRYPTO_AUTH_PIPE1_KEY14_REG 0x1E838
-#define CRYPTO_AUTH_PIPE1_KEY15_REG 0x1E83C
+#define CRYPTO_AUTH_PIPE1_KEY0_REG 0x1E880
+#define CRYPTO_AUTH_PIPE1_KEY1_REG 0x1E884
+#define CRYPTO_AUTH_PIPE1_KEY2_REG 0x1E888
+#define CRYPTO_AUTH_PIPE1_KEY3_REG 0x1E88C
+#define CRYPTO_AUTH_PIPE1_KEY4_REG 0x1E890
+#define CRYPTO_AUTH_PIPE1_KEY5_REG 0x1E894
+#define CRYPTO_AUTH_PIPE1_KEY6_REG 0x1E898
+#define CRYPTO_AUTH_PIPE1_KEY7_REG 0x1E89C
+#define CRYPTO_AUTH_PIPE1_KEY8_REG 0x1E8A0
+#define CRYPTO_AUTH_PIPE1_KEY9_REG 0x1E8A4
+#define CRYPTO_AUTH_PIPE1_KEY10_REG 0x1E8A8
+#define CRYPTO_AUTH_PIPE1_KEY11_REG 0x1E8AC
+#define CRYPTO_AUTH_PIPE1_KEY12_REG 0x1E8B0
+#define CRYPTO_AUTH_PIPE1_KEY13_REG 0x1E8B4
+#define CRYPTO_AUTH_PIPE1_KEY14_REG 0x1E8B8
+#define CRYPTO_AUTH_PIPE1_KEY15_REG 0x1E8BC
-#define CRYPTO_AUTH_PIPE2_KEY0_REG 0x1E840
-#define CRYPTO_AUTH_PIPE2_KEY1_REG 0x1E844
-#define CRYPTO_AUTH_PIPE2_KEY2_REG 0x1E848
-#define CRYPTO_AUTH_PIPE2_KEY3_REG 0x1E84C
-#define CRYPTO_AUTH_PIPE2_KEY4_REG 0x1E850
-#define CRYPTO_AUTH_PIPE2_KEY5_REG 0x1E854
-#define CRYPTO_AUTH_PIPE2_KEY6_REG 0x1E858
-#define CRYPTO_AUTH_PIPE2_KEY7_REG 0x1E85C
-#define CRYPTO_AUTH_PIPE2_KEY8_REG 0x1E860
-#define CRYPTO_AUTH_PIPE2_KEY9_REG 0x1E864
-#define CRYPTO_AUTH_PIPE2_KEY10_REG 0x1E868
-#define CRYPTO_AUTH_PIPE2_KEY11_REG 0x1E86C
-#define CRYPTO_AUTH_PIPE2_KEY12_REG 0x1E870
-#define CRYPTO_AUTH_PIPE2_KEY13_REG 0x1E874
-#define CRYPTO_AUTH_PIPE2_KEY14_REG 0x1E878
-#define CRYPTO_AUTH_PIPE2_KEY15_REG 0x1E87C
+#define CRYPTO_AUTH_PIPE2_KEY0_REG 0x1E900
+#define CRYPTO_AUTH_PIPE2_KEY1_REG 0x1E904
+#define CRYPTO_AUTH_PIPE2_KEY2_REG 0x1E908
+#define CRYPTO_AUTH_PIPE2_KEY3_REG 0x1E90C
+#define CRYPTO_AUTH_PIPE2_KEY4_REG 0x1E910
+#define CRYPTO_AUTH_PIPE2_KEY5_REG 0x1E914
+#define CRYPTO_AUTH_PIPE2_KEY6_REG 0x1E918
+#define CRYPTO_AUTH_PIPE2_KEY7_REG 0x1E91C
+#define CRYPTO_AUTH_PIPE2_KEY8_REG 0x1E920
+#define CRYPTO_AUTH_PIPE2_KEY9_REG 0x1E924
+#define CRYPTO_AUTH_PIPE2_KEY10_REG 0x1E928
+#define CRYPTO_AUTH_PIPE2_KEY11_REG 0x1E92C
+#define CRYPTO_AUTH_PIPE2_KEY12_REG 0x1E930
+#define CRYPTO_AUTH_PIPE2_KEY13_REG 0x1E934
+#define CRYPTO_AUTH_PIPE2_KEY14_REG 0x1E938
+#define CRYPTO_AUTH_PIPE2_KEY15_REG 0x1E93C
-#define CRYPTO_AUTH_PIPE3_KEY0_REG 0x1E880
-#define CRYPTO_AUTH_PIPE3_KEY1_REG 0x1E884
-#define CRYPTO_AUTH_PIPE3_KEY2_REG 0x1E888
-#define CRYPTO_AUTH_PIPE3_KEY3_REG 0x1E88C
-#define CRYPTO_AUTH_PIPE3_KEY4_REG 0x1E890
-#define CRYPTO_AUTH_PIPE3_KEY5_REG 0x1E894
-#define CRYPTO_AUTH_PIPE3_KEY6_REG 0x1E898
-#define CRYPTO_AUTH_PIPE3_KEY7_REG 0x1E89C
-#define CRYPTO_AUTH_PIPE3_KEY8_REG 0x1E8A0
-#define CRYPTO_AUTH_PIPE3_KEY9_REG 0x1E8A4
-#define CRYPTO_AUTH_PIPE3_KEY10_REG 0x1E8A8
-#define CRYPTO_AUTH_PIPE3_KEY11_REG 0x1E8AC
-#define CRYPTO_AUTH_PIPE3_KEY12_REG 0x1E8B0
-#define CRYPTO_AUTH_PIPE3_KEY13_REG 0x1E8B4
-#define CRYPTO_AUTH_PIPE3_KEY14_REG 0x1E8B8
-#define CRYPTO_AUTH_PIPE3_KEY15_REG 0x1E8BC
+#define CRYPTO_AUTH_PIPE3_KEY0_REG 0x1E980
+#define CRYPTO_AUTH_PIPE3_KEY1_REG 0x1E984
+#define CRYPTO_AUTH_PIPE3_KEY2_REG 0x1E988
+#define CRYPTO_AUTH_PIPE3_KEY3_REG 0x1E98C
+#define CRYPTO_AUTH_PIPE3_KEY4_REG 0x1E990
+#define CRYPTO_AUTH_PIPE3_KEY5_REG 0x1E994
+#define CRYPTO_AUTH_PIPE3_KEY6_REG 0x1E998
+#define CRYPTO_AUTH_PIPE3_KEY7_REG 0x1E99C
+#define CRYPTO_AUTH_PIPE3_KEY8_REG 0x1E9A0
+#define CRYPTO_AUTH_PIPE3_KEY9_REG 0x1E9A4
+#define CRYPTO_AUTH_PIPE3_KEY10_REG 0x1E9A8
+#define CRYPTO_AUTH_PIPE3_KEY11_REG 0x1E9AC
+#define CRYPTO_AUTH_PIPE3_KEY12_REG 0x1E9B0
+#define CRYPTO_AUTH_PIPE3_KEY13_REG 0x1E9B4
+#define CRYPTO_AUTH_PIPE3_KEY14_REG 0x1E9B8
+#define CRYPTO_AUTH_PIPE3_KEY15_REG 0x1E9BC
#define CRYPTO_AUTH_IV0_REG 0x1A310
@@ -375,7 +379,7 @@
#define CRYPTO_FIRST 17
#define CRYPTO_LAST 16
-#define CRYPTO_AUTH_POS 15 /* bit 15 .. 14*/
+#define CRYPTO_AUTH_POS 14 /* bit 15 .. 14*/
#define CRYPTO_AUTH_POS_MASK (0x3 << CRYPTO_AUTH_POS)
#define CRYPTO_AUTH_POS_BEFORE 0
#define CRYPTO_AUTH_POS_AFTER 1
@@ -421,6 +425,7 @@
#define CRYPTO_AUTH_ALG_AES 2
#define CRYPTO_AUTH_ALG_KASUMI 3
#define CRYPTO_AUTH_ALG_SNOW3G 4
+#define CRYPTO_AUTH_ALG_ZUC 5
/* encr_xts_du_size reg */
#define CRYPTO_ENCR_XTS_DU_SIZE 0 /* bit 19-0 */
@@ -471,33 +476,49 @@
#define CRYPTO_ENCR_KEY_SZ_3DES 1
#define CRYPTO_ENCR_KEY_SZ_AES128 0
#define CRYPTO_ENCR_KEY_SZ_AES256 2
-#define CRYPTO_ENCR_KEY_SZ_UEA1 0
-#define CRYPTO_ENCR_KEY_SZ_UEA2 1
#define CRYPTO_ENCR_ALG 0 /* bit 2-0 */
#define CRYPTO_ENCR_ALG_MASK (7 << CRYPTO_ENCR_ALG)
#define CRYPTO_ENCR_ALG_NONE 0
#define CRYPTO_ENCR_ALG_DES 1
#define CRYPTO_ENCR_ALG_AES 2
-#define CRYPTO_ENCR_ALG_KASUMI 3
+#define CRYPTO_ENCR_ALG_KASUMI 4
#define CRYPTO_ENCR_ALG_SNOW_3G 5
+#define CRYPTO_ENCR_ALG_ZUC 6
/* goproc reg */
#define CRYPTO_GO 0
#define CRYPTO_CLR_CNTXT 1
#define CRYPTO_RESULTS_DUMP 2
+/* F8 definition of CRYPTO_ENCR_CNTR1_IV1 REG */
+#define CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT 16 /* bit 31 - 16 */
+#define CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT_MASK \
+ (0xffff << CRYPTO_CNTR1_IV1_REG_F8_PKT_CNT)
+
+#define CRYPTO_CNTR1_IV1_REG_F8_BEARER 0 /* bit 4 - 0 */
+#define CRYPTO_CNTR1_IV1_REG_F8_BEARER_MASK \
+ (0x1f << CRYPTO_CNTR1_IV1_REG_F8_BEARER)
+
+/* F9 definition of CRYPTO_AUTH_IV4 REG */
+#define CRYPTO_AUTH_IV4_REG_F9_VALID_BIS 0 /* bit 2 - 0 */
+#define CRYPTO_AUTH_IV4_REG_F9_VALID_BIS_MASK \
+ (0x7 << CRYPTO_AUTH_IV4_REG_F9_VALID_BIS)
/* engines_avail */
#define CRYPTO_ENCR_AES_SEL 0
-#define CRYPTO_DES_SEL 3
-#define CRYPTO_ENCR_SNOW3G_SEL 4
-#define CRYPTO_ENCR_KASUMI_SEL 5
-#define CRYPTO_SHA_SEL 6
-#define CRYPTO_SHA512_SEL 7
-#define CRYPTO_AUTH_AES_SEL 8
-#define CRYPTO_AUTH_SNOW3G_SEL 9
-#define CRYPTO_AUTH_KASUMI_SEL 10
-#define CRYPTO_BAM_SEL 11
-
+#define CRYPTO_DES_SEL 1
+#define CRYPTO_ENCR_SNOW3G_SEL 2
+#define CRYPTO_ENCR_KASUMI_SEL 3
+#define CRYPTO_SHA_SEL 4
+#define CRYPTO_SHA512_SEL 5
+#define CRYPTO_AUTH_AES_SEL 6
+#define CRYPTO_AUTH_SNOW3G_SEL 7
+#define CRYPTO_AUTH_KASUMI_SEL 8
+#define CRYPTO_BAM_PIPE_SETS 9 /* bit 12 - 9 */
+#define CRYPTO_AXI_WR_BEATS 13 /* bit 18 - 13 */
+#define CRYPTO_AXI_RD_BEATS 19 /* bit 24 - 19 */
+#define CRYPTO_ENCR_ZUC_SEL 26
+#define CRYPTO_AUTH_ZUC_SEL 27
+#define CRYPTO_ZUC_ENABLE 28
#endif /* _DRIVERS_CRYPTO_MSM_QCRYPTOHW_50_H_ */
diff --git a/drivers/gpu/ion/msm/ion_iommu_map.c b/drivers/gpu/ion/msm/ion_iommu_map.c
index 5ce03db..0a4fe1f 100644
--- a/drivers/gpu/ion/msm/ion_iommu_map.c
+++ b/drivers/gpu/ion/msm/ion_iommu_map.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/dma-buf.h>
#include <linux/export.h>
#include <linux/iommu.h>
#include <linux/ion.h>
@@ -69,6 +70,7 @@
struct sg_table *table;
unsigned long size;
struct mutex lock;
+ struct dma_buf *dbuf;
};
static struct rb_root iommu_root;
@@ -85,9 +87,9 @@
parent = *p;
entry = rb_entry(parent, struct ion_iommu_meta, node);
- if (meta->handle < entry->handle) {
+ if (meta->table < entry->table) {
p = &(*p)->rb_left;
- } else if (meta->handle > entry->handle) {
+ } else if (meta->table > entry->table) {
p = &(*p)->rb_right;
} else {
pr_err("%s: handle %p already exists\n", __func__,
@@ -101,7 +103,7 @@
}
-static struct ion_iommu_meta *ion_iommu_meta_lookup(struct ion_handle *handle)
+static struct ion_iommu_meta *ion_iommu_meta_lookup(struct sg_table *table)
{
struct rb_root *root = &iommu_root;
struct rb_node **p = &root->rb_node;
@@ -112,9 +114,9 @@
parent = *p;
entry = rb_entry(parent, struct ion_iommu_meta, node);
- if (handle < entry->handle)
+ if (table < entry->table)
p = &(*p)->rb_left;
- else if (handle > entry->handle)
+ else if (table > entry->table)
p = &(*p)->rb_right;
else
return entry;
@@ -319,7 +321,8 @@
return ERR_PTR(ret);
}
-static struct ion_iommu_meta *ion_iommu_meta_create(struct ion_handle *handle,
+static struct ion_iommu_meta *ion_iommu_meta_create(struct ion_client *client,
+ struct ion_handle *handle,
struct sg_table *table,
unsigned long size)
{
@@ -333,6 +336,7 @@
meta->handle = handle;
meta->table = table;
meta->size = size;
+ meta->dbuf = ion_share_dma_buf(client, handle);
kref_init(&meta->ref);
mutex_init(&meta->lock);
ion_iommu_meta_add(meta);
@@ -347,6 +351,7 @@
rb_erase(&meta->node, &iommu_root);
+ dma_buf_put(meta->dbuf);
kfree(meta);
}
@@ -427,13 +432,13 @@
}
mutex_lock(&msm_iommu_map_mutex);
- iommu_meta = ion_iommu_meta_lookup(handle);
+ iommu_meta = ion_iommu_meta_lookup(table);
if (!iommu_meta)
- iommu_meta = ion_iommu_meta_create(handle, table, size);
+ iommu_meta = ion_iommu_meta_create(client, handle, table, size);
else
kref_get(&iommu_meta->ref);
-
+ BUG_ON(iommu_meta->size != size);
mutex_unlock(&msm_iommu_map_mutex);
iommu_map = ion_iommu_lookup(iommu_meta, domain_num, partition_num);
@@ -493,6 +498,7 @@
{
struct ion_iommu_map *iommu_map;
struct ion_iommu_meta *meta;
+ struct sg_table *table;
if (IS_ERR_OR_NULL(client)) {
pr_err("%s: client pointer is invalid\n", __func__);
@@ -503,13 +509,14 @@
return;
}
+ table = ion_sg_table(client, handle);
mutex_lock(&msm_iommu_map_mutex);
- meta = ion_iommu_meta_lookup(handle);
+ meta = ion_iommu_meta_lookup(table);
if (!meta) {
WARN(1, "%s: (%d,%d) was never mapped for %p\n", __func__,
domain_num, partition_num, handle);
- mutex_lock(&msm_iommu_map_mutex);
+ mutex_unlock(&msm_iommu_map_mutex);
goto out;
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index e6c345b..d95c12b 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1719,6 +1719,7 @@
{
int status = -EINVAL;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ unsigned int state = device->state;
kgsl_cffdump_open(device);
@@ -1780,8 +1781,11 @@
kgsl_mmu_stop(&device->mmu);
error_clk_off:
- if (KGSL_STATE_DUMP_AND_FT != device->state)
+ if (KGSL_STATE_DUMP_AND_FT != device->state) {
kgsl_pwrctrl_disable(device);
+ /* set the state back to original state */
+ kgsl_pwrctrl_set_state(device, state);
+ }
return status;
}
@@ -2773,9 +2777,6 @@
unsigned long wait;
unsigned long timeout = jiffies + msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
- if (!(rb->flags & KGSL_FLAGS_STARTED))
- return 0;
-
/*
* The first time into the loop, wait for 100 msecs and kick wptr again
* to ensure that the hardware has updated correctly. After that, kick
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 5275267..7cd9943 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -144,10 +144,13 @@
* @ptbase - the pagetable base of the object
* @gpuaddr - the GPU address of the object
* @size - Size of the region to search
+ *
+ * Caller must kgsl_mem_entry_put() the returned entry when finished using it.
*/
-struct kgsl_mem_entry *kgsl_get_mem_entry(struct kgsl_device *device,
- unsigned int ptbase, unsigned int gpuaddr, unsigned int size)
+struct kgsl_mem_entry * __must_check
+kgsl_get_mem_entry(struct kgsl_device *device, unsigned int ptbase,
+ unsigned int gpuaddr, unsigned int size)
{
struct kgsl_process_private *priv;
struct kgsl_mem_entry *entry;
@@ -157,15 +160,12 @@
list_for_each_entry(priv, &kgsl_driver.process_list, list) {
if (!kgsl_mmu_pt_equal(&device->mmu, priv->pagetable, ptbase))
continue;
- spin_lock(&priv->mem_lock);
entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
if (entry) {
- spin_unlock(&priv->mem_lock);
mutex_unlock(&kgsl_driver.process_mutex);
return entry;
}
- spin_unlock(&priv->mem_lock);
}
mutex_unlock(&kgsl_driver.process_mutex);
@@ -913,8 +913,17 @@
return result;
}
-/*call with private->mem_lock locked */
-struct kgsl_mem_entry *
+/**
+ * kgsl_sharedmem_find_region() - Find a gpu memory allocation
+ *
+ * @private: private data for the process to check.
+ * @gpuaddr: start address of the region
+ * @size: size of the region
+ *
+ * Find a gpu allocation. Caller must kgsl_mem_entry_put()
+ * the returned entry when finished using it.
+ */
+struct kgsl_mem_entry * __must_check
kgsl_sharedmem_find_region(struct kgsl_process_private *private,
unsigned int gpuaddr, size_t size)
{
@@ -923,46 +932,57 @@
if (!kgsl_mmu_gpuaddr_in_range(private->pagetable, gpuaddr))
return NULL;
+ spin_lock(&private->mem_lock);
while (node != NULL) {
struct kgsl_mem_entry *entry;
entry = rb_entry(node, struct kgsl_mem_entry, node);
-
- if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size))
+ if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size)) {
+ kgsl_mem_entry_get(entry);
+ spin_unlock(&private->mem_lock);
return entry;
-
+ }
if (gpuaddr < entry->memdesc.gpuaddr)
node = node->rb_left;
else if (gpuaddr >=
(entry->memdesc.gpuaddr + entry->memdesc.size))
node = node->rb_right;
else {
+ spin_unlock(&private->mem_lock);
return NULL;
}
}
+ spin_unlock(&private->mem_lock);
return NULL;
}
EXPORT_SYMBOL(kgsl_sharedmem_find_region);
-/*call with private->mem_lock locked */
-static inline struct kgsl_mem_entry *
+/**
+ * kgsl_sharedmem_find() - Find a gpu memory allocation
+ *
+ * @private: private data for the process to check.
+ * @gpuaddr: start address of the region
+ *
+ * Find a gpu allocation. Caller must kgsl_mem_entry_put()
+ * the returned entry when finished using it.
+ */
+static inline struct kgsl_mem_entry * __must_check
kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr)
{
return kgsl_sharedmem_find_region(private, gpuaddr, 1);
}
/**
- * kgsl_sharedmem_region_empty - Check if an addression region is empty
+ * kgsl_sharedmem_region_empty() - Check if an addression region is empty
*
* @private: private data for the process to check.
* @gpuaddr: start address of the region
* @size: length of the region.
*
* Checks that there are no existing allocations within an address
- * region. Note that unlike other kgsl_sharedmem* search functions,
- * this one manages locking on its own.
+ * region.
*/
int
kgsl_sharedmem_region_empty(struct kgsl_process_private *private,
@@ -1006,19 +1026,24 @@
}
/**
- * kgsl_sharedmem_find_id - find a memory entry by id
+ * kgsl_sharedmem_find_id() - find a memory entry by id
* @process: the owning process
* @id: id to find
*
* @returns - the mem_entry or NULL
+ *
+ * Caller must kgsl_mem_entry_put() the returned entry, when finished using
+ * it.
*/
-static inline struct kgsl_mem_entry *
+static inline struct kgsl_mem_entry * __must_check
kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id)
{
struct kgsl_mem_entry *entry;
rcu_read_lock();
entry = idr_find(&process->mem_idr, id);
+ if (entry)
+ kgsl_mem_entry_get(entry);
rcu_read_unlock();
return entry;
@@ -1314,15 +1339,12 @@
struct kgsl_device *device = dev_priv->device;
unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
- spin_lock(&dev_priv->process_priv->mem_lock);
entry = kgsl_sharedmem_find(dev_priv->process_priv, gpuaddr);
- spin_unlock(&dev_priv->process_priv->mem_lock);
if (!entry) {
KGSL_DRV_ERR(dev_priv->device,
"invalid gpuaddr %08x\n", gpuaddr);
- result = -EINVAL;
- goto done;
+ return -EINVAL;
}
trace_kgsl_mem_timestamp_queue(device, entry, context_id,
kgsl_readtimestamp(device, context,
@@ -1330,7 +1352,7 @@
timestamp);
result = kgsl_add_event(dev_priv->device, context_id, timestamp,
kgsl_freemem_event_cb, entry, dev_priv);
-done:
+ kgsl_mem_entry_put(entry);
return result;
}
@@ -1416,15 +1438,13 @@
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
-
if (!entry) {
KGSL_MEM_INFO(dev_priv->device, "invalid gpuaddr %08x\n",
param->gpuaddr);
return -EINVAL;
}
+
trace_kgsl_mem_free(entry);
kgsl_memfree_hist_set_event(entry->priv->pid,
@@ -1433,6 +1453,7 @@
entry->memdesc.flags);
kgsl_mem_entry_detach_process(entry);
+ kgsl_mem_entry_put(entry);
return 0;
}
@@ -1457,6 +1478,7 @@
entry->memdesc.flags);
kgsl_mem_entry_detach_process(entry);
+ kgsl_mem_entry_put(entry);
return 0;
}
@@ -1842,6 +1864,9 @@
if (!kgsl_mmu_use_cpu_map(private->pagetable->mmu))
entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
+ if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
+ entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE;
+
switch (memtype) {
case KGSL_USER_MEM_TYPE_PMEM:
if (param->fd == 0 || param->len == 0)
@@ -1990,6 +2015,7 @@
struct kgsl_gpumem_sync_cache *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
+ long ret;
if (param->id != 0) {
entry = kgsl_sharedmem_find_id(private, param->id);
@@ -1999,9 +2025,7 @@
return -EINVAL;
}
} else if (param->gpuaddr != 0) {
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
if (entry == NULL) {
KGSL_MEM_INFO(dev_priv->device,
"can't find gpuaddr %x\n",
@@ -2012,7 +2036,9 @@
return -EINVAL;
}
- return _kgsl_gpumem_sync_cache(entry, param->op);
+ ret = _kgsl_gpumem_sync_cache(entry, param->op);
+ kgsl_mem_entry_put(entry);
+ return ret;
}
/* Legacy cache function, does a flush (clean + invalidate) */
@@ -2024,10 +2050,9 @@
struct kgsl_sharedmem_free *param = data;
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
+ long ret;
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
if (entry == NULL) {
KGSL_MEM_INFO(dev_priv->device,
"can't find gpuaddr %x\n",
@@ -2035,7 +2060,9 @@
return -EINVAL;
}
- return _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+ ret = _kgsl_gpumem_sync_cache(entry, KGSL_GPUMEM_CACHE_FLUSH);
+ kgsl_mem_entry_put(entry);
+ return ret;
}
/*
@@ -2064,6 +2091,9 @@
if (entry == NULL)
return -ENOMEM;
+ if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
+ entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE;
+
result = kgsl_allocate_user(&entry->memdesc, private->pagetable, size,
flags);
if (result != 0)
@@ -2173,9 +2203,7 @@
return -EINVAL;
}
} else if (param->gpuaddr != 0) {
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, param->gpuaddr);
- spin_unlock(&private->mem_lock);
if (entry == NULL) {
KGSL_MEM_INFO(dev_priv->device,
"can't find gpuaddr %lx\n",
@@ -2191,6 +2219,8 @@
param->size = entry->memdesc.size;
param->mmapsize = kgsl_memdesc_mmapsize(&entry->memdesc);
param->useraddr = entry->memdesc.useraddr;
+
+ kgsl_mem_entry_put(entry);
return result;
}
@@ -2202,14 +2232,14 @@
struct kgsl_process_private *private = dev_priv->process_priv;
struct kgsl_mem_entry *entry = NULL;
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find_region(private, param->gpuaddr, param->len);
- if (entry)
- kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
- param->len, true);
- else
- result = -EINVAL;
- spin_unlock(&private->mem_lock);
+ if (!entry)
+ return -EINVAL;
+
+ kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
+ param->len, true);
+
+ kgsl_mem_entry_put(entry);
return result;
}
@@ -2601,21 +2631,17 @@
struct kgsl_mem_entry **out_entry, unsigned long pgoff,
unsigned long len)
{
- int ret = -EINVAL;
+ int ret = 0;
struct kgsl_mem_entry *entry;
entry = kgsl_sharedmem_find_id(private, pgoff);
if (entry == NULL) {
- spin_lock(&private->mem_lock);
entry = kgsl_sharedmem_find(private, pgoff << PAGE_SHIFT);
- spin_unlock(&private->mem_lock);
}
if (!entry)
return -EINVAL;
- kgsl_mem_entry_get(entry);
-
if (!entry->memdesc.ops ||
!entry->memdesc.ops->vmflags ||
!entry->memdesc.ops->vmfault) {
@@ -2768,6 +2794,10 @@
if (vma_offset == device->memstore.gpuaddr)
return kgsl_mmap_memstore(device, vma);
+ /*
+ * The reference count on the entry that we get from
+ * get_mmap_entry() will be held until kgsl_gpumem_vm_close().
+ */
ret = get_mmap_entry(private, &entry, vma->vm_pgoff,
vma->vm_end - vma->vm_start);
if (ret)
@@ -2817,10 +2847,6 @@
int sglen = entry->memdesc.sglen;
unsigned long addr = vma->vm_start;
- /* don't map in the guard page, it should always fault */
- if (kgsl_memdesc_has_guard_page(&entry->memdesc))
- sglen--;
-
for_each_sg(entry->memdesc.sg, s, sglen, i) {
int j;
for (j = 0; j < (sg_dma_len(s) >> PAGE_SHIFT); j++) {
@@ -2837,7 +2863,6 @@
entry->memdesc.useraddr = vma->vm_start;
trace_kgsl_mem_mmap(entry);
-
return 0;
}
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index abe9100..d63aa79 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -251,6 +251,10 @@
static inline int kgsl_gpuaddr_in_memdesc(const struct kgsl_memdesc *memdesc,
unsigned int gpuaddr, unsigned int size)
{
+ /* set a minimum size to search for */
+ if (!size)
+ size = 1;
+
/* don't overflow */
if ((gpuaddr + size) < gpuaddr)
return 0;
diff --git a/drivers/gpu/msm/kgsl_cffdump.c b/drivers/gpu/msm/kgsl_cffdump.c
index ef2a19a..c3bdf80 100644
--- a/drivers/gpu/msm/kgsl_cffdump.c
+++ b/drivers/gpu/msm/kgsl_cffdump.c
@@ -360,6 +360,8 @@
void kgsl_cffdump_open(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ if (!kgsl_cff_dump_enable)
+ return;
if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) {
kgsl_cffdump_memory_base(device->id,
@@ -379,24 +381,33 @@
void kgsl_cffdump_memory_base(enum kgsl_deviceid device_id, unsigned int base,
unsigned int range, unsigned gmemsize)
{
+ if (!kgsl_cff_dump_enable)
+ return;
cffdump_printline(device_id, CFF_OP_MEMORY_BASE, base,
range, gmemsize, 0, 0);
}
void kgsl_cffdump_hang(enum kgsl_deviceid device_id)
{
+ if (!kgsl_cff_dump_enable)
+ return;
cffdump_printline(device_id, CFF_OP_HANG, 0, 0, 0, 0, 0);
}
void kgsl_cffdump_close(enum kgsl_deviceid device_id)
{
+ if (!kgsl_cff_dump_enable)
+ return;
cffdump_printline(device_id, CFF_OP_EOF, 0, 0, 0, 0, 0);
}
+
void kgsl_cffdump_user_event(unsigned int cff_opcode, unsigned int op1,
unsigned int op2, unsigned int op3,
unsigned int op4, unsigned int op5)
{
+ if (!kgsl_cff_dump_enable)
+ return;
cffdump_printline(-1, cff_opcode, op1, op2, op3, op4, op5);
}
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 8d071d1..6f139b9 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -615,7 +615,7 @@
{
unsigned int numpages;
unsigned int pte, ptefirst, ptelast, superpte;
- unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ unsigned int range = memdesc->size;
struct kgsl_gpummu_pt *gpummu_pt = pt->priv;
/* All GPU addresses as assigned are page aligned, but some
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 869ab25..3057723 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -84,6 +84,13 @@
struct remote_iommu_petersons_spinlock kgsl_iommu_sync_lock_vars;
+/*
+ * One page allocation for a guard region to protect against over-zealous
+ * GPU pre-fetch
+ */
+
+static struct page *kgsl_guard_page;
+
static int get_iommu_unit(struct device *dev, struct kgsl_mmu **mmu_out,
struct kgsl_iommu_unit **iommu_unit_out)
{
@@ -268,6 +275,8 @@
void *base = kgsl_driver.memfree_hist.base_hist_rb;
struct kgsl_memfree_hist_elem *wptr;
struct kgsl_memfree_hist_elem *p;
+ char name[32];
+ memset(name, 0, sizeof(name));
mutex_lock(&kgsl_driver.memfree_hist_mutex);
wptr = kgsl_driver.memfree_hist.wptr;
@@ -277,12 +286,15 @@
if (addr >= p->gpuaddr &&
addr < (p->gpuaddr + p->size)) {
+ kgsl_get_memory_usage(name, sizeof(name) - 1,
+ p->flags),
KGSL_LOG_DUMP(iommu_dev->kgsldev,
"---- premature free ----\n");
KGSL_LOG_DUMP(iommu_dev->kgsldev,
- "[%8.8X-%8.8X] was already freed by pid %d\n",
+ "[%8.8X-%8.8X] (%s) was already freed by pid %d\n",
p->gpuaddr,
p->gpuaddr + p->size,
+ name,
p->pid);
}
p++;
@@ -347,22 +359,17 @@
KGSL_IOMMU_V1_FSYNR0_WNR_SHIFT)) ? 1 : 0);
pid = kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase);
- KGSL_MEM_CRIT(iommu_dev->kgsldev,
- "GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
- KGSL_MEM_CRIT(iommu_dev->kgsldev,
- "context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n",
- iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
- write ? "write" : "read");
if (adreno_dev->ft_pf_policy & KGSL_FT_PAGEFAULT_LOG_ONE_PER_PAGE)
no_page_fault_log = kgsl_mmu_log_fault_addr(mmu, ptbase, addr);
if (!no_page_fault_log) {
KGSL_MEM_CRIT(iommu_dev->kgsldev,
- "GPU PAGE FAULT: addr = %lX pid = %d\n",
- addr, kgsl_mmu_get_ptname_from_ptbase(mmu, ptbase));
- KGSL_MEM_CRIT(iommu_dev->kgsldev, "context = %d FSR = %X\n",
- iommu_dev->ctx_id, fsr);
+ "GPU PAGE FAULT: addr = %lX pid = %d\n", addr, pid);
+ KGSL_MEM_CRIT(iommu_dev->kgsldev,
+ "context = %d FSR = %X FSYNR0 = %X FSYNR1 = %X(%s fault)\n",
+ iommu_dev->ctx_id, fsr, fsynr0, fsynr1,
+ write ? "write" : "read");
_check_if_freed(iommu_dev, addr, pid);
@@ -1378,6 +1385,15 @@
iommu_ops.mmu_cleanup_pt = kgsl_iommu_cleanup_regs;
}
+ if (kgsl_guard_page == NULL) {
+ kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO |
+ __GFP_HIGHMEM);
+ if (kgsl_guard_page == NULL) {
+ status = -ENOMEM;
+ goto done;
+ }
+ }
+
dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
__func__);
done:
@@ -1628,7 +1644,7 @@
unsigned int *tlb_flags)
{
int ret;
- unsigned int range = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ unsigned int range = memdesc->size;
struct kgsl_iommu_pt *iommu_pt = pt->priv;
/* All GPU addresses as assigned are page aligned, but some
@@ -1640,6 +1656,9 @@
if (range == 0 || gpuaddr == 0)
return 0;
+ if (kgsl_memdesc_has_guard_page(memdesc))
+ range += PAGE_SIZE;
+
ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
if (ret)
KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
@@ -1664,14 +1683,10 @@
int ret;
unsigned int iommu_virt_addr;
struct kgsl_iommu_pt *iommu_pt = pt->priv;
- int size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ int size = memdesc->size;
BUG_ON(NULL == iommu_pt);
- /* if there's a guard page, we'll map it read only below */
- if ((protflags & IOMMU_WRITE) && kgsl_memdesc_has_guard_page(memdesc))
- size -= PAGE_SIZE;
-
iommu_virt_addr = memdesc->gpuaddr;
ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
@@ -1682,16 +1697,14 @@
protflags, ret);
return ret;
}
- if ((protflags & IOMMU_WRITE) && kgsl_memdesc_has_guard_page(memdesc)) {
- struct scatterlist *sg = &memdesc->sg[memdesc->sglen - 1];
-
+ if (kgsl_memdesc_has_guard_page(memdesc)) {
ret = iommu_map(iommu_pt->domain, iommu_virt_addr + size,
- kgsl_get_sg_pa(sg), PAGE_SIZE,
+ page_to_phys(kgsl_guard_page), PAGE_SIZE,
protflags & ~IOMMU_WRITE);
if (ret) {
- KGSL_CORE_ERR("iommu_map(%p, %x, %x, %x) err: %d\n",
+ KGSL_CORE_ERR("iommu_map(%p, %x, guard, %x) err: %d\n",
iommu_pt->domain, iommu_virt_addr + size,
- kgsl_get_sg_pa(sg), protflags & ~IOMMU_WRITE,
+ protflags & ~IOMMU_WRITE,
ret);
/* cleanup the partial mapping */
iommu_unmap_range(iommu_pt->domain, iommu_virt_addr,
@@ -1771,6 +1784,11 @@
kfree(iommu);
+ if (kgsl_guard_page != NULL) {
+ __free_page(kgsl_guard_page);
+ kgsl_guard_page = NULL;
+ }
+
return 0;
}
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 6e41707..3ebfdcd 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -640,7 +640,10 @@
}
}
- size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ /* Add space for the guard page when allocating the mmu VA. */
+ size = memdesc->size;
+ if (kgsl_memdesc_has_guard_page(memdesc))
+ size += PAGE_SIZE;
pool = pagetable->pool;
@@ -738,7 +741,10 @@
return 0;
}
- size = kgsl_sg_size(memdesc->sg, memdesc->sglen);
+ /* Add space for the guard page when freeing the mmu VA. */
+ size = memdesc->size;
+ if (kgsl_memdesc_has_guard_page(memdesc))
+ size += PAGE_SIZE;
start_addr = memdesc->gpuaddr;
end_addr = (memdesc->gpuaddr + size);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 62db513..b9bc432 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -65,14 +65,6 @@
mem_entry_max_show), \
}
-
-/*
- * One page allocation for a guard region to protect against over-zealous
- * GPU pre-fetch
- */
-
-static struct page *kgsl_guard_page;
-
/**
* Given a kobj, find the process structure attached to it
*/
@@ -364,10 +356,6 @@
struct scatterlist *sg;
int sglen = memdesc->sglen;
- /* Don't free the guard page if it was used */
- if (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE)
- sglen--;
-
kgsl_driver.stats.page_alloc -= memdesc->size;
if (memdesc->hostptr) {
@@ -402,10 +390,6 @@
int sglen = memdesc->sglen;
int i, count = 0;
- /* Don't map the guard page if it exists */
- if (memdesc->priv & KGSL_MEMDESC_GUARD_PAGE)
- sglen--;
-
/* create a list of pages to call vmap */
pages = vmalloc(npages * sizeof(struct page *));
if (!pages) {
@@ -564,14 +548,6 @@
sglen_alloc = PAGE_ALIGN(size) >> PAGE_SHIFT;
- /*
- * Add guard page to the end of the allocation when the
- * IOMMU is in use.
- */
-
- if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU)
- sglen_alloc++;
-
memdesc->size = size;
memdesc->pagetable = pagetable;
memdesc->ops = &kgsl_page_alloc_ops;
@@ -647,26 +623,6 @@
len -= page_size;
}
- /* Add the guard page to the end of the sglist */
-
- if (kgsl_mmu_get_mmutype() == KGSL_MMU_TYPE_IOMMU) {
- /*
- * It doesn't matter if we use GFP_ZERO here, this never
- * gets mapped, and we only allocate it once in the life
- * of the system
- */
-
- if (kgsl_guard_page == NULL)
- kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO |
- __GFP_HIGHMEM);
-
- if (kgsl_guard_page != NULL) {
- sg_set_page(&memdesc->sg[sglen++], kgsl_guard_page,
- PAGE_SIZE, 0);
- memdesc->priv |= KGSL_MEMDESC_GUARD_PAGE;
- }
- }
-
memdesc->sglen = sglen;
/*
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 279490f..14ae0dc 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -295,15 +295,4 @@
return ret;
}
-static inline int kgsl_sg_size(struct scatterlist *sg, int sglen)
-{
- int i, size = 0;
- struct scatterlist *s;
-
- for_each_sg(sg, s, sglen, i) {
- size += s->length;
- }
-
- return size;
-}
#endif /* __KGSL_SHAREDMEM_H */
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index abcebfb..4165690 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -345,6 +345,7 @@
struct kgsl_mem_entry *entry;
struct kgsl_snapshot_object *obj;
int offset;
+ int ret = -EINVAL;
entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size);
@@ -358,7 +359,7 @@
if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
KGSL_DRV_ERR(device,
"Only internal GPU buffers can be frozen\n");
- return -EINVAL;
+ goto err_put;
}
/*
@@ -381,7 +382,7 @@
if (size + offset > entry->memdesc.size) {
KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
gpuaddr);
- return -EINVAL;
+ goto err_put;
}
/* If the buffer is already on the list, skip it */
@@ -390,27 +391,24 @@
/* If the size is different, use the bigger size */
if (obj->size < size)
obj->size = size;
-
- return 0;
+ ret = 0;
+ goto err_put;
}
}
if (kgsl_memdesc_map(&entry->memdesc) == NULL) {
KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n",
gpuaddr);
- return -EINVAL;
+ goto err_put;
}
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (obj == NULL) {
KGSL_DRV_ERR(device, "Unable to allocate memory\n");
- return -EINVAL;
+ goto err_put;
}
- /* Ref count the mem entry */
- kgsl_mem_entry_get(entry);
-
obj->type = type;
obj->entry = entry;
obj->gpuaddr = gpuaddr;
@@ -428,12 +426,15 @@
* 0 so it doesn't get counted twice
*/
- if (entry->memdesc.priv & KGSL_MEMDESC_FROZEN)
- return 0;
+ ret = (entry->memdesc.priv & KGSL_MEMDESC_FROZEN) ? 0
+ : entry->memdesc.size;
entry->memdesc.priv |= KGSL_MEMDESC_FROZEN;
- return entry->memdesc.size;
+ return ret;
+err_put:
+ kgsl_mem_entry_put(entry);
+ return ret;
}
EXPORT_SYMBOL(kgsl_snapshot_get_object);
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 813305a..aad8ef1 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -168,7 +168,6 @@
fail_event:
fail_copy_fd:
/* clean up sync_fence_install */
- sync_fence_put(fence);
put_unused_fd(priv.fence_fd);
fail_fd:
/* clean up sync_fence_create */
diff --git a/drivers/gpu/msm/z180_postmortem.c b/drivers/gpu/msm/z180_postmortem.c
index c1e5f07..55b8faa 100644
--- a/drivers/gpu/msm/z180_postmortem.c
+++ b/drivers/gpu/msm/z180_postmortem.c
@@ -168,6 +168,7 @@
KGSL_LOG_DUMP(device,
"Could not map IB to kernel memory, Ringbuffer Slot: %d\n",
rb_slot_num);
+ kgsl_mem_entry_put(entry);
continue;
}
@@ -190,6 +191,7 @@
linebuf);
}
KGSL_LOG_DUMP(device, "IB Dump Finished\n");
+ kgsl_mem_entry_put(entry);
}
}
}
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 0fab4d1..8e350f0 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -130,6 +130,60 @@
{790, 203}
};
+static const struct qpnp_vadc_map_pt adcmap_qrd_btm_threshold[] = {
+ {-200, 1672},
+ {-180, 1656},
+ {-160, 1639},
+ {-140, 1620},
+ {-120, 1599},
+ {-100, 1577},
+ {-80, 1553},
+ {-60, 1527},
+ {-40, 1550},
+ {-20, 1471},
+ {0, 1440},
+ {20, 1408},
+ {40, 1374},
+ {60, 1339},
+ {80, 1303},
+ {100, 1266},
+ {120, 1228},
+ {140, 1190},
+ {160, 1150},
+ {180, 1111},
+ {200, 1071},
+ {220, 1032},
+ {240, 992},
+ {260, 953},
+ {280, 915},
+ {300, 877},
+ {320, 841},
+ {340, 805},
+ {360, 770},
+ {380, 736},
+ {400, 704},
+ {420, 673},
+ {440, 643},
+ {460, 614},
+ {480, 587},
+ {500, 561},
+ {520, 536},
+ {540, 513},
+ {560, 491},
+ {580, 470},
+ {600, 450},
+ {620, 431},
+ {640, 414},
+ {660, 397},
+ {680, 382},
+ {700, 367},
+ {720, 353},
+ {740, 340},
+ {760, 328},
+ {780, 317},
+ {800, 306},
+};
+
/* Voltage to temperature */
static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = {
{1758, -40},
@@ -463,6 +517,24 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
+int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t bat_voltage = 0;
+
+ bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+ adc_properties, chan_properties);
+
+ return qpnp_adc_map_temp_voltage(
+ adcmap_qrd_btm_threshold,
+ ARRAY_SIZE(adcmap_qrd_btm_threshold),
+ bat_voltage,
+ &adc_chan_result->physical);
+}
+EXPORT_SYMBOL(qpnp_adc_scale_qrd_batt_therm);
+
int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
const struct qpnp_vadc_chan_properties *chan_properties,
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index d78d2ea..edb1d66 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -112,6 +112,7 @@
[SCALE_XOTHERM] = {qpnp_adc_tdkntcg_therm},
[SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
+ [SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
};
static int32_t qpnp_vadc_read_reg(int16_t reg, u8 *data)
diff --git a/drivers/input/touchscreen/gen_vkeys.c b/drivers/input/touchscreen/gen_vkeys.c
index fcda6c9..21e4829 100644
--- a/drivers/input/touchscreen/gen_vkeys.c
+++ b/drivers/input/touchscreen/gen_vkeys.c
@@ -105,6 +105,12 @@
return -EINVAL;
}
}
+
+ rc = of_property_read_u32(np, "qcom,y-offset", &pdata->y_offset);
+ if (rc) {
+ dev_err(dev, "Failed to read y position offset\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -147,7 +153,7 @@
width = ((pdata->disp_maxx - (border * (pdata->num_keys - 1)))
/ pdata->num_keys);
height = (pdata->panel_maxy - pdata->disp_maxy);
- center_y = pdata->disp_maxy + (height / 2);
+ center_y = pdata->disp_maxy + (height / 2) + pdata->y_offset;
height = height * HEIGHT_SCALE_NUM / HEIGHT_SCALE_DENOM;
x2 -= border * BORDER_ADJUST_NUM / BORDER_ADJUST_DENOM;
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 986c062..d51481f 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/firmware.h>
+#include <linux/string.h>
#include <linux/input/synaptics_dsx.h>
#include "synaptics_i2c_rmi4.h"
@@ -34,14 +35,7 @@
#define FORCE_UPDATE false
#define INSIDE_FIRMWARE_UPDATE
-#define CHECKSUM_OFFSET 0x00
-#define BOOTLOADER_VERSION_OFFSET 0x07
-#define IMAGE_SIZE_OFFSET 0x08
-#define CONFIG_SIZE_OFFSET 0x0C
-#define PRODUCT_ID_OFFSET 0x10
-#define PRODUCT_INFO_OFFSET 0x1E
#define FW_IMAGE_OFFSET 0x100
-#define PRODUCT_ID_SIZE 10
#define BOOTLOADER_ID_OFFSET 0
#define FLASH_PROPERTIES_OFFSET 2
@@ -59,10 +53,14 @@
#define BLOCK_NUMBER_OFFSET 0
#define BLOCK_DATA_OFFSET 2
-#define UI_CONFIG_AREA 0x00
-#define PERM_CONFIG_AREA 0x01
-#define BL_CONFIG_AREA 0x02
-#define DISP_CONFIG_AREA 0x03
+#define NAME_BUFFER_SIZE 128
+
+enum falsh_config_area {
+ UI_CONFIG_AREA = 0x00,
+ PERM_CONFIG_AREA = 0x01,
+ BL_CONFIG_AREA = 0x02,
+ DISP_CONFIG_AREA = 0x03
+};
enum flash_command {
CMD_WRITE_FW_BLOCK = 0x2,
@@ -70,9 +68,10 @@
CMD_READ_CONFIG_BLOCK = 0x5,
CMD_WRITE_CONFIG_BLOCK = 0x6,
CMD_ERASE_CONFIG = 0x7,
+ CMD_READ_SENSOR_ID = 0x8,
CMD_ERASE_BL_CONFIG = 0x9,
CMD_ERASE_DISP_CONFIG = 0xA,
- CMD_ENABLE_FLASH_PROG = 0xF,
+ CMD_ENABLE_FLASH_PROG = 0xF
};
enum flash_area {
@@ -81,6 +80,11 @@
CONFIG_AREA
};
+enum image_file_option {
+ OPTION_BUILD_INFO = 0,
+ OPTION_CONTAIN_BOOTLOADER = 1,
+};
+
#define SLEEP_MODE_NORMAL (0x00)
#define SLEEP_MODE_SENSOR_SLEEP (0x01)
#define SLEEP_MODE_RESERVED0 (0x02)
@@ -91,6 +95,8 @@
#define ERASE_WAIT_MS (5 * 1000)
#define RESET_WAIT_MS (500)
+#define POLLING_MODE 0
+
#define SLEEP_TIME_US 50
static ssize_t fwu_sysfs_show_image(struct file *data_file,
@@ -101,6 +107,9 @@
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count);
+static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
@@ -139,6 +148,40 @@
static int fwu_wait_for_idle(int timeout_ms);
+struct image_header_data {
+ union {
+ struct {
+ /* 0x00-0x0F */
+ unsigned char file_checksum[4];
+ unsigned char reserved_04;
+ unsigned char reserved_05;
+ unsigned char options_firmware_id:1;
+ unsigned char options_contain_bootloader:1;
+ unsigned char options_reserved:6;
+ unsigned char bootloader_version;
+ unsigned char firmware_size[4];
+ unsigned char config_size[4];
+ /* 0x10-0x1F */
+ unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE];
+ unsigned char reserved_1a;
+ unsigned char reserved_1b;
+ unsigned char reserved_1c;
+ unsigned char reserved_1d;
+ unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
+ /* 0x20-0x2F */
+ unsigned char reserved_20_2f[0x10];
+ /* 0x30-0x3F */
+ unsigned char ds_firmware_id[0x10];
+ /* 0x40-0x4F */
+ unsigned char ds_customize_info[10];
+ unsigned char reserved_4a_4f[6];
+ /* 0x50-0x53*/
+ unsigned char firmware_id[4];
+ } __packed;
+ unsigned char data[54];
+ };
+};
+
struct image_header {
unsigned int checksum;
unsigned int image_size;
@@ -147,6 +190,8 @@
unsigned char bootloader_version;
unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
+ unsigned int firmware_id;
+ bool is_contain_build_info;
};
struct pdt_properties {
@@ -245,6 +290,7 @@
struct f34_flash_properties flash_properties;
struct workqueue_struct *fwu_workqueue;
struct delayed_work fwu_work;
+ char *firmware_name;
};
static struct bin_attribute dev_attr_data = {
@@ -258,6 +304,9 @@
};
static struct device_attribute attrs[] = {
+ __ATTR(forceflash, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_force_reflash_store),
__ATTR(doreflash, S_IWUGO,
synaptics_rmi4_show_error,
fwu_sysfs_do_reflash_store),
@@ -308,18 +357,36 @@
(unsigned int)ptr[3] * 0x1000000;
}
+static unsigned int extract_uint_be(const unsigned char *ptr)
+{
+ return (unsigned int)ptr[3] +
+ (unsigned int)ptr[2] * 0x100 +
+ (unsigned int)ptr[1] * 0x10000 +
+ (unsigned int)ptr[0] * 0x1000000;
+}
+
static void parse_header(struct image_header *header,
const unsigned char *fw_image)
{
- header->checksum = extract_uint(&fw_image[CHECKSUM_OFFSET]);
- header->bootloader_version = fw_image[BOOTLOADER_VERSION_OFFSET];
- header->image_size = extract_uint(&fw_image[IMAGE_SIZE_OFFSET]);
- header->config_size = extract_uint(&fw_image[CONFIG_SIZE_OFFSET]);
- memcpy(header->product_id, &fw_image[PRODUCT_ID_OFFSET],
- SYNAPTICS_RMI4_PRODUCT_ID_SIZE);
- header->product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE] = 0;
- memcpy(header->product_info, &fw_image[PRODUCT_INFO_OFFSET],
- SYNAPTICS_RMI4_PRODUCT_INFO_SIZE);
+ struct image_header_data *data = (struct image_header_data *)fw_image;
+ header->checksum = extract_uint(data->file_checksum);
+ header->bootloader_version = data->bootloader_version;
+ header->image_size = extract_uint(data->firmware_size);
+ header->config_size = extract_uint(data->config_size);
+ memcpy(header->product_id, data->product_id,
+ sizeof(data->product_id));
+ header->product_id[sizeof(data->product_info)] = 0;
+ memcpy(header->product_info, data->product_info,
+ sizeof(data->product_info));
+
+ header->is_contain_build_info =
+ (data->options_firmware_id == (1 << OPTION_BUILD_INFO));
+ if (header->is_contain_build_info) {
+ header->firmware_id = extract_uint(data->firmware_id);
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s Firwmare build id %d\n", __func__,
+ header->firmware_id);
+ }
#ifdef DEBUG_FW_UPDATE
dev_info(&fwu->rmi4_data->i2c_client->dev,
@@ -516,6 +583,9 @@
int count = 0;
int timeout_count = ((timeout_ms * 1000) / SLEEP_TIME_US) + 1;
do {
+ #if POLLING_MODE
+ fwu_read_f34_flash_status();
+ #endif
if (fwu->flash_control.command == 0x00)
return 0;
@@ -533,7 +603,7 @@
return -ETIMEDOUT;
}
-static enum flash_area fwu_go_nogo(void)
+static enum flash_area fwu_go_nogo(struct image_header *header)
{
int retval = 0;
int index = 0;
@@ -569,7 +639,6 @@
goto exit;
}
-
/* device firmware id */
retval = fwu->fn_ptr->read(fwu->rmi4_data,
fwu->f01_fd.query_base_addr + 18,
@@ -577,37 +646,45 @@
sizeof(firmware_id));
if (retval < 0) {
dev_err(&i2c_client->dev,
- "Failed to read firmware ID (code %d).\n", retval);
+ "%s: Failed to read firmware ID (code %d).\n",
+ __func__, retval);
goto exit;
}
firmware_id[3] = 0;
deviceFirmwareID = extract_uint(firmware_id);
/* .img firmware id */
- strptr = strnstr(fwu->rmi4_data->fw_image_name, "PR",
- sizeof(fwu->rmi4_data->fw_image_name));
- if (!strptr) {
+ if (header->is_contain_build_info) {
dev_err(&i2c_client->dev,
- "No valid PR number (PRxxxxxxx)" \
- "found in image file name...\n");
- goto exit;
+ "%s: Image option contains build info.\n",
+ __func__);
+ imageFirmwareID = header->firmware_id;
+ } else {
+ strptr = strnstr(fwu->firmware_name, "PR",
+ sizeof(fwu->firmware_name));
+ if (!strptr) {
+ dev_err(&i2c_client->dev,
+ "No valid PR number (PRxxxxxxx)" \
+ "found in image file name...\n");
+ goto exit;
+ }
+
+ strptr += 2;
+ while (strptr[index] >= '0' && strptr[index] <= '9') {
+ imagePR[index] = strptr[index];
+ index++;
+ }
+ imagePR[index] = 0;
+
+ retval = kstrtoul(imagePR, 10, &imageFirmwareID);
+ if (retval == -EINVAL) {
+ dev_err(&i2c_client->dev,
+ "invalid image firmware id...\n");
+ goto exit;
+ }
}
- strptr += 2;
- while (strptr[index] >= '0' && strptr[index] <= '9') {
- imagePR[index] = strptr[index];
- index++;
- }
- imagePR[index] = 0;
-
- retval = kstrtoul(imagePR, 10, &imageFirmwareID);
- if (retval == -EINVAL) {
- dev_err(&i2c_client->dev,
- "invalid image firmware id...\n");
- goto exit;
- }
-
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
"Device firmware id %d, .img firmware id %d\n",
deviceFirmwareID,
(unsigned int)imageFirmwareID);
@@ -617,7 +694,8 @@
} else if (imageFirmwareID < deviceFirmwareID) {
flash_area = NONE;
dev_info(&i2c_client->dev,
- "Img fw is older than device fw. Skip fw update.\n");
+ "%s: Img fw is older than device fw. Skip fw update.\n",
+ __func__);
goto exit;
}
@@ -628,24 +706,29 @@
sizeof(config_id));
if (retval < 0) {
dev_err(&i2c_client->dev,
- "Failed to read config ID (code %d).\n", retval);
+ "%s: Failed to read config ID (code %d).\n",
+ __func__, retval);
flash_area = NONE;
goto exit;
}
- deviceConfigID = extract_uint(config_id);
+ deviceConfigID = extract_uint_be(config_id);
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
"Device config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
config_id[0], config_id[1], config_id[2], config_id[3]);
/* .img config id */
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
".img config ID 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
fwu->config_data[0],
fwu->config_data[1],
fwu->config_data[2],
fwu->config_data[3]);
- imageConfigID = extract_uint(fwu->config_data);
+ imageConfigID = extract_uint_be(fwu->config_data);
+
+ dev_dbg(&i2c_client->dev,
+ "%s: Device config ID %d, .img config ID %d\n",
+ __func__, deviceConfigID, imageConfigID);
if (imageConfigID > deviceConfigID) {
flash_area = CONFIG_AREA;
@@ -656,10 +739,10 @@
kfree(imagePR);
if (flash_area == NONE)
dev_info(&i2c_client->dev,
- "Nothing needs to be updated\n");
+ "%s: Nothing needs to be updated\n", __func__);
else
dev_info(&i2c_client->dev,
- "Update %s block\n",
+ "%s: Update %s block\n", __func__,
flash_area == UI_FIRMWARE ? "UI FW" : "CONFIG");
return flash_area;
}
@@ -1210,7 +1293,7 @@
static int fwu_start_reflash(void)
{
- int retval;
+ int retval = 0;
struct image_header header;
const unsigned char *fw_image;
const struct firmware *fw_entry = NULL;
@@ -1229,18 +1312,30 @@
if (fwu->ext_data_source)
fw_image = fwu->ext_data_source;
else {
- dev_dbg(&fwu->rmi4_data->i2c_client->dev,
- "%s: Requesting firmware image %s\n",
- __func__, fwu->rmi4_data->fw_image_name);
+ fwu->firmware_name = kcalloc(NAME_BUFFER_SIZE,
+ sizeof(char), GFP_KERNEL);
+ if (!fwu->firmware_name) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s Failed to allocate firmware name (%d).\n",
+ __func__, NAME_BUFFER_SIZE);
+ retval = -ENOMEM;
+ goto memory_exit;
+ }
+
+ snprintf(fwu->firmware_name, NAME_BUFFER_SIZE, "%s",
+ fwu->rmi4_data->fw_image_name);
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Requesting firmware image %s\n",
+ __func__, fwu->firmware_name);
retval = request_firmware(&fw_entry,
- fwu->rmi4_data->fw_image_name,
+ fwu->firmware_name,
&fwu->rmi4_data->i2c_client->dev);
if (retval != 0) {
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: Firmware image %s not available\n",
__func__,
- fwu->rmi4_data->fw_image_name);
+ fwu->firmware_name);
retval = -EINVAL;
goto exit;
}
@@ -1264,7 +1359,7 @@
if (fwu->ext_data_source)
flash_area = UI_FIRMWARE;
else
- flash_area = fwu_go_nogo();
+ flash_area = fwu_go_nogo(&header);
switch (flash_area) {
case NONE:
@@ -1318,6 +1413,8 @@
pr_notice("%s: End of reflash process\n", __func__);
exit:
+ kfree(fwu->firmware_name);
+memory_exit:
return retval;
}
@@ -1371,6 +1468,40 @@
return count;
}
+static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned int input;
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+
+ if (sscanf(buf, "%u", &input) != 1) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (input != 1) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ fwu->force_update = true;
+ retval = synaptics_fw_updater(fwu->ext_data_source);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to do reflash\n",
+ __func__);
+ goto exit;
+ }
+
+ retval = count;
+
+exit:
+ kfree(fwu->ext_data_source);
+ fwu->ext_data_source = NULL;
+ return retval;
+}
+
static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 4a021e1..ed53c41 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -107,13 +107,17 @@
static int synaptics_rmi4_suspend(struct device *dev);
static int synaptics_rmi4_resume(struct device *dev);
-#ifdef CONFIG_HAS_EARLYSUSPEND
+
static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t synaptics_rmi4_full_pm_cycle_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void synaptics_rmi4_early_suspend(struct early_suspend *h);
static void synaptics_rmi4_late_resume(struct early_suspend *h);
@@ -229,7 +233,7 @@
};
static struct device_attribute attrs[] = {
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#ifdef CONFIG_PM
__ATTR(full_pm_cycle, (S_IRUGO | S_IWUGO),
synaptics_rmi4_full_pm_cycle_show,
synaptics_rmi4_full_pm_cycle_store),
@@ -260,8 +264,7 @@
static bool exp_fn_inited;
static struct mutex exp_fn_list_mutex;
static struct list_head exp_fn_list;
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#ifdef CONFIG_PM
static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -284,6 +287,36 @@
return count;
}
+
+#ifdef CONFIG_FB
+static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval = 0;
+
+ rmi4_data->fb_notif.notifier_call = fb_notifier_callback;
+
+ retval = fb_register_client(&rmi4_data->fb_notif);
+ if (retval)
+ dev_err(&rmi4_data->i2c_client->dev,
+ "Unable to register fb_notifier: %d\n", retval);
+ return;
+}
+#elif defined CONFIG_HAS_EARLYSUSPEND
+static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+ rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend;
+ rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume;
+ register_early_suspend(&rmi4_data->early_suspend);
+
+ return;
+}
+#else
+static void configure_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+ return;
+}
+#endif
#endif
static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
@@ -1082,17 +1115,25 @@
bool enable)
{
int retval = 0;
- unsigned char intr_status;
+ unsigned char *intr_status;
if (enable) {
if (rmi4_data->irq_enabled)
return retval;
+ intr_status = kzalloc(rmi4_data->num_of_intr_regs, GFP_KERNEL);
+ if (!intr_status) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc memory\n",
+ __func__);
+ return -ENOMEM;
+ }
/* Clear interrupts first */
retval = synaptics_rmi4_i2c_read(rmi4_data,
rmi4_data->f01_data_base_addr + 1,
- &intr_status,
+ intr_status,
rmi4_data->num_of_intr_regs);
+ kfree(intr_status);
if (retval < 0)
return retval;
@@ -2195,12 +2236,7 @@
goto err_register_input;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
- rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
- rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend;
- rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume;
- register_early_suspend(&rmi4_data->early_suspend);
-#endif
+ configure_sleep(rmi4_data);
if (!exp_fn_inited) {
mutex_init(&exp_fn_list_mutex);
@@ -2438,7 +2474,27 @@
return;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ int *blank;
+ struct synaptics_rmi4_data *rmi4_data =
+ container_of(self, struct synaptics_rmi4_data, fb_notif);
+
+ if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+ rmi4_data && rmi4_data->i2c_client) {
+ blank = evdata->data;
+ if (*blank == FB_BLANK_UNBLANK)
+ synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
+ else if (*blank == FB_BLANK_POWERDOWN)
+ synaptics_rmi4_suspend(&(rmi4_data->input_dev->dev));
+ }
+
+ return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
/**
* synaptics_rmi4_early_suspend()
*
@@ -2621,10 +2677,15 @@
return 0;
}
+#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
.suspend = synaptics_rmi4_suspend,
.resume = synaptics_rmi4_resume,
};
+#else
+static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
+};
+#endif
#endif
static const struct i2c_device_id synaptics_rmi4_id_table[] = {
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 16b1f8f..681b95c 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -24,10 +24,14 @@
#define SYNAPTICS_DS4 (1 << 0)
#define SYNAPTICS_DS5 (1 << 1)
#define SYNAPTICS_DSX_DRIVER_PRODUCT SYNAPTICS_DS4
-#define SYNAPTICS_DSX_DRIVER_VERSION 0x1004
+#define SYNAPTICS_DSX_DRIVER_VERSION 0x1005
#include <linux/version.h>
-#ifdef CONFIG_HAS_EARLYSUSPEND
+
+#ifdef CONFIG_FB
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
@@ -227,6 +231,13 @@
unsigned char *data, unsigned short length);
int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
int (*reset_device)(struct synaptics_rmi4_data *rmi4_data);
+#ifdef CONFIG_FB
+ struct notifier_block fb_notif;
+#else
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+#endif
};
enum exp_fn {
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 5d5ff43..0233e18 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -93,6 +93,7 @@
#define FLASH_LED_STROBE_CTRL(base) (base + 0x47)
#define FLASH_LED_UNLOCK_SECURE(base) (base + 0xD0)
#define FLASH_LED_TORCH(base) (base + 0xE4)
+#define FLASH_FAULT_DETECT(base) (base + 0x51)
#define FLASH_MAX_LEVEL 0x4F
#define FLASH_NO_MASK 0x00
@@ -106,10 +107,9 @@
#define FLASH_TMR_MASK 0x03
#define FLASH_TMR_WATCHDOG 0x03
#define FLASH_TMR_SAFETY 0x00
-
+#define FLASH_FAULT_DETECT_MASK 0X80
#define FLASH_HW_VREG_OK 0x80
#define FLASH_VREG_MASK 0xC0
-
#define FLASH_STARTUP_DLY_MASK 0x02
#define FLASH_ENABLE_ALL 0xE0
@@ -120,6 +120,7 @@
#define FLASH_ENABLE_LED_0 0x40
#define FLASH_ENABLE_LED_1 0x20
#define FLASH_INIT_MASK 0xE0
+#define FLASH_SELFCHECK_ENABLE 0x80
#define FLASH_STROBE_SW 0xC0
#define FLASH_STROBE_HW 0xC4
@@ -130,7 +131,7 @@
#define FLASH_CURRENT_PRGM_MIN 1
#define FLASH_CURRENT_PRGM_SHIFT 1
#define FLASH_CURRENT_MAX 0x4F
-#define FLASH_CURRENT_TORCH 0x0F
+#define FLASH_CURRENT_TORCH 0x07
#define FLASH_DURATION_200ms 0x13
#define FLASH_CLAMP_200mA 0x0F
@@ -171,6 +172,8 @@
#define LED_MPP_SINK_MASK 0x07
#define LED_MPP_MODE_MASK 0x7F
#define LED_MPP_EN_MASK 0x80
+#define LED_MPP_SRC_MASK 0x0F
+#define LED_MPP_MODE_CTRL_MASK 0x70
#define LED_MPP_MODE_SINK (0x06 << 4)
#define LED_MPP_MODE_ENABLE 0x01
@@ -551,7 +554,8 @@
return rc;
}
- val = led->mpp_cfg->source_sel | led->mpp_cfg->mode_ctrl;
+ val = (led->mpp_cfg->source_sel & LED_MPP_SRC_MASK) |
+ (led->mpp_cfg->mode_ctrl & LED_MPP_MODE_CTRL_MASK);
rc = qpnp_led_masked_write(led,
LED_MPP_MODE_CTRL(led->base), LED_MPP_MODE_MASK,
@@ -632,18 +636,10 @@
return rc;
}
- qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
- FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Max current reg write failed(%d)\n",
- rc);
- return rc;
- }
-
rc = qpnp_led_masked_write(led,
led->flash_cfg->current_addr,
- FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+ FLASH_CURRENT_MASK,
+ led->flash_cfg->current_prgm);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Current reg write failed(%d)\n", rc);
@@ -652,7 +648,8 @@
rc = qpnp_led_masked_write(led,
led->flash_cfg->second_addr,
- FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
+ FLASH_CURRENT_MASK,
+ led->flash_cfg->current_prgm);
if (rc) {
dev_err(&led->spmi_dev->dev,
"2nd Current reg write failed(%d)\n",
@@ -660,6 +657,16 @@
return rc;
}
+ qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
+ FLASH_CURRENT_MASK,
+ led->max_current);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Max current reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
rc = qpnp_led_masked_write(led,
FLASH_ENABLE_CONTROL(led->base),
FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
@@ -669,9 +676,22 @@
return rc;
}
} else {
+ /* Set flash safety timer */
rc = qpnp_led_masked_write(led,
- FLASH_MAX_CURR(led->base),
- FLASH_CURRENT_MASK, FLASH_CURRENT_MAX);
+ FLASH_SAFETY_TIMER(led->base),
+ FLASH_SAFETY_TIMER_MASK,
+ led->flash_cfg->duration);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Safety timer reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
+ /* Set max current */
+ rc = qpnp_led_masked_write(led,
+ FLASH_MAX_CURR(led->base), FLASH_CURRENT_MASK,
+ FLASH_MAX_LEVEL);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Max current reg write failed(%d)\n",
@@ -679,6 +699,18 @@
return rc;
}
+ /* Set clamp current */
+ rc = qpnp_led_masked_write(led,
+ FLASH_CLAMP_CURR(led->base),
+ FLASH_CURRENT_MASK,
+ led->flash_cfg->clamp_curr);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Clamp current reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+
/* Write 0x80 to MODULE_ENABLE before writing 0xE0
* in order to avoid reg value goes from 0x00 to
* 0xE0. This causes a hardware bug.
@@ -714,16 +746,6 @@
}
rc = qpnp_led_masked_write(led,
- FLASH_CLAMP_CURR(led->base),
- FLASH_CURRENT_MASK, FLASH_CURRENT_TORCH);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Clamp Current reg write failed(%d)\n",
- rc);
- return rc;
- }
-
- rc = qpnp_led_masked_write(led,
FLASH_ENABLE_CONTROL(led->base),
FLASH_ENABLE_MASK, FLASH_ENABLE_ALL);
if (rc) {
@@ -762,25 +784,16 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Secure reg write failed(%d)\n", rc);
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_TORCH(led->base),
- FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Torch reg write failed(%d)\n", rc);
return rc;
}
rc = qpnp_led_masked_write(led,
- FLASH_SAFETY_TIMER(led->base),
- FLASH_SAFETY_TIMER_MASK,
- led->flash_cfg->duration);
+ FLASH_LED_TORCH(led->base),
+ FLASH_TORCH_MASK,
+ FLASH_LED_TORCH_DISABLE);
if (rc) {
dev_err(&led->spmi_dev->dev,
- "Safety timer reg write failed(%d)\n",
- rc);
+ "Torch reg write failed(%d)\n", rc);
return rc;
}
}
@@ -936,6 +949,7 @@
if (rc < 0)
dev_err(&led->spmi_dev->dev,
"MPP set brightness failed (%d)\n", rc);
+ break;
case QPNP_ID_KPDBL:
rc = qpnp_kpdbl_set(led);
if (rc < 0)
@@ -1208,52 +1222,7 @@
"LED %d flash write failed(%d)\n", led->id, rc);
return rc;
}
- rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_INIT_MASK, FLASH_ENABLE_MODULE);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Enable reg write failed(%d)\n", rc);
- return rc;
- }
- /* Set flash safety timer */
- rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base),
- FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Safety timer reg write failed(%d)\n", rc);
- return rc;
- }
-
- /* Set max current */
- rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
- FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Max current reg write failed(%d)\n", rc);
- return rc;
- }
- /* Set clamp current */
- rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base),
- FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Clamp current reg write failed(%d)\n", rc);
- return rc;
- }
-
- /* Set timer control - safety or watchdog */
- if (led->flash_cfg->safety_timer)
- rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
- FLASH_TMR_MASK, FLASH_TMR_SAFETY);
- else
- rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base),
- FLASH_TMR_MASK, FLASH_TMR_WATCHDOG);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "LED timer ctrl reg write failed(%d)\n", rc);
- return rc;
- }
/* Set headroom */
rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
@@ -1263,6 +1232,47 @@
return rc;
}
+ /* Set startup delay */
+ rc = qpnp_led_masked_write(led,
+ FLASH_STARTUP_DELAY(led->base), FLASH_STARTUP_DLY_MASK,
+ led->flash_cfg->startup_dly);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Startup delay reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ /* Set timer control - safety or watchdog */
+ if (led->flash_cfg->safety_timer) {
+ rc = qpnp_led_masked_write(led,
+ FLASH_LED_TMR_CTRL(led->base),
+ FLASH_TMR_MASK, FLASH_TMR_SAFETY);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "LED timer ctrl reg write failed(%d)\n",
+ rc);
+ return rc;
+ }
+ }
+
+ /* Set Vreg force */
+ rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
+ FLASH_VREG_MASK, FLASH_HW_VREG_OK);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Vreg OK reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ /* Set self fault check */
+ rc = qpnp_led_masked_write(led, FLASH_FAULT_DETECT(led->base),
+ FLASH_FAULT_DETECT_MASK, FLASH_SELFCHECK_ENABLE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Fault detect reg write failed(%d)\n", rc);
+ return rc;
+ }
+
/* Set mask enable */
rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
FLASH_MASK_REG_MASK, FLASH_MASK_1);
@@ -1272,32 +1282,7 @@
return rc;
}
- /* Set startup delay */
- rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base),
- FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Startup delay reg write failed(%d)\n", rc);
- return rc;
- }
-
- rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
- FLASH_VREG_MASK, FLASH_HW_VREG_OK);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Vreg OK reg write failed(%d)\n", rc);
- return rc;
- }
-
- /* Set led current and disable module */
- rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
- FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Current reg write failed(%d)\n", rc);
- return rc;
- }
-
+ /* Disable flash LED module */
rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
if (rc) {
@@ -1306,7 +1291,6 @@
return rc;
}
- led->flash_cfg->torch_enable = false;
led->flash_cfg->strobe_type = 0;
/* dump flash registers */
@@ -1679,6 +1663,9 @@
led->flash_cfg->safety_timer =
of_property_read_bool(node, "qcom,safety-timer");
+ led->flash_cfg->torch_enable =
+ of_property_read_bool(node, "qcom,torch-enable");
+
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 89500f9..fcade49 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -246,7 +246,10 @@
struct dmx_secure_mode *sec_mode);
int (*oob_command) (struct dmx_ts_feed *feed,
struct dmx_oob_command *cmd);
-
+ int (*ts_insertion_init)(struct dmx_ts_feed *feed);
+ int (*ts_insertion_terminate)(struct dmx_ts_feed *feed);
+ int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed,
+ char *data, size_t size);
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 5e7a09e..7347b37 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -34,6 +34,8 @@
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
#include "dmxdev.h"
static int debug;
@@ -416,7 +418,33 @@
return 0;
}
-static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+static inline int dvb_dmxdev_check_data(struct dmxdev_filter *filter,
+ struct dvb_ringbuffer *src)
+{
+ int data_status_change;
+
+ if (filter)
+ if (mutex_lock_interruptible(&filter->mutex))
+ return -ERESTARTSYS;
+
+ if (!src->data ||
+ !dvb_ringbuffer_empty(src) ||
+ src->error ||
+ (filter &&
+ (filter->state != DMXDEV_STATE_GO) &&
+ (filter->state != DMXDEV_STATE_DONE)))
+ data_status_change = 1;
+ else
+ data_status_change = 0;
+
+ if (filter)
+ mutex_unlock(&filter->mutex);
+
+ return data_status_change;
+}
+
+static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_filter *filter,
+ struct dvb_ringbuffer *src,
int non_blocking, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -439,9 +467,26 @@
break;
}
- ret = wait_event_interruptible(src->queue, (!src->data) ||
- !dvb_ringbuffer_empty(src) ||
- (src->error != 0));
+ if (filter) {
+ if ((filter->state == DMXDEV_STATE_DONE) &&
+ dvb_ringbuffer_empty(src))
+ break;
+
+ mutex_unlock(&filter->mutex);
+ }
+
+ ret = wait_event_interruptible(src->queue,
+ dvb_dmxdev_check_data(filter, src));
+
+ if (filter) {
+ if (mutex_lock_interruptible(&filter->mutex))
+ return -ERESTARTSYS;
+
+ if ((filter->state != DMXDEV_STATE_GO) &&
+ (filter->state != DMXDEV_STATE_DONE))
+ return -ENODEV;
+ }
+
if (ret < 0)
break;
@@ -1108,9 +1153,9 @@
if (dmxdev->exit)
return -ENODEV;
- res = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
+ res = dvb_dmxdev_buffer_read(NULL, &dmxdev->dvr_buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
if (res > 0) {
dvb_dmxdev_notify_data_read(dmxdev->dvr_feed, res);
@@ -1751,6 +1796,213 @@
return 0;
}
+static void dvb_dmxdev_ts_insertion_timer(unsigned long data)
+{
+ struct ts_insertion_buffer *ts_buffer =
+ (struct ts_insertion_buffer *)data;
+
+ if (ts_buffer && !ts_buffer->abort)
+ schedule_work(&ts_buffer->work);
+}
+
+static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker)
+{
+ struct ts_insertion_buffer *ts_buffer =
+ container_of(worker, struct ts_insertion_buffer, work);
+ struct dmxdev_feed *feed;
+ size_t free_bytes;
+ struct dmx_ts_feed *ts;
+
+ mutex_lock(&ts_buffer->dmxdevfilter->mutex);
+
+ if (ts_buffer->abort ||
+ (ts_buffer->dmxdevfilter->state != DMXDEV_STATE_GO)) {
+ mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+ return;
+ }
+
+ feed = list_first_entry(&ts_buffer->dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+ ts = feed->ts;
+ free_bytes = dvb_ringbuffer_free(&ts_buffer->dmxdevfilter->buffer);
+
+ mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+
+ if (ts_buffer->size < free_bytes)
+ ts->ts_insertion_insert_buffer(ts,
+ ts_buffer->buffer, ts_buffer->size);
+
+ if (ts_buffer->repetition_time)
+ mod_timer(&ts_buffer->timer, jiffies +
+ msecs_to_jiffies(ts_buffer->repetition_time));
+}
+
+static void dvb_dmxdev_queue_ts_insertion(
+ struct ts_insertion_buffer *ts_buffer)
+{
+ size_t tsp_size;
+
+ if (ts_buffer->dmxdevfilter->dmx_tsp_format == DMX_TSP_FORMAT_188)
+ tsp_size = 188;
+ else
+ tsp_size = 192;
+
+ if (ts_buffer->size % tsp_size) {
+ printk(KERN_ERR "%s: Wrong buffer alignment, size=%d, tsp_size=%d\n",
+ __func__, ts_buffer->size, tsp_size);
+ return;
+ }
+
+ ts_buffer->abort = 0;
+ schedule_work(&ts_buffer->work);
+}
+
+static void dvb_dmxdev_cancel_ts_insertion(
+ struct ts_insertion_buffer *ts_buffer)
+{
+ /*
+ * This function assumes it is called while mutex
+ * of demux filter is taken. Since work in workqueue
+ * captures the filter's mutex to protect against the DB,
+ * mutex needs to be released before waiting for the work
+ * to get finished otherwise work in workqueue will
+ * never be finished.
+ */
+ if (!mutex_is_locked(&ts_buffer->dmxdevfilter->mutex)) {
+ printk(KERN_ERR "%s: mutex is not locked!\n", __func__);
+ return;
+ }
+
+ /*
+ * Work should be stopped first as it might re-trigger the timer
+ * until it is stopped. Timer would not re-schedule the work
+ * due to the abort flag.
+ */
+ ts_buffer->abort = 1;
+
+ mutex_unlock(&ts_buffer->dmxdevfilter->mutex);
+ cancel_work_sync(&ts_buffer->work);
+ del_timer_sync(&ts_buffer->timer);
+ mutex_lock(&ts_buffer->dmxdevfilter->mutex);
+}
+
+static int dvb_dmxdev_set_ts_insertion(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_set_ts_insertion *params)
+{
+ int ret = 0;
+ int first_buffer;
+ struct dmxdev_feed *feed;
+ struct ts_insertion_buffer *ts_buffer;
+
+ if (!params ||
+ !params->size ||
+ !(dmxdevfilter->dev->capabilities & DMXDEV_CAP_TS_INSERTION) ||
+ (dmxdevfilter->state < DMXDEV_STATE_SET) ||
+ (dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+ ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+ (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+ return -EINVAL;
+
+ ts_buffer = vmalloc(sizeof(struct ts_insertion_buffer));
+ if (!ts_buffer)
+ return -ENOMEM;
+
+ ts_buffer->buffer = vmalloc(params->size);
+ if (!ts_buffer->buffer) {
+ vfree(ts_buffer);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(ts_buffer->buffer,
+ params->ts_packets, params->size)) {
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+ return -EFAULT;
+ }
+
+ if (params->repetition_time &&
+ params->repetition_time < DMX_MIN_INSERTION_REPETITION_TIME)
+ params->repetition_time = DMX_MIN_INSERTION_REPETITION_TIME;
+
+ ts_buffer->size = params->size;
+ ts_buffer->identifier = params->identifier;
+ ts_buffer->repetition_time = params->repetition_time;
+ ts_buffer->dmxdevfilter = dmxdevfilter;
+ init_timer(&ts_buffer->timer);
+ ts_buffer->timer.function = dvb_dmxdev_ts_insertion_timer;
+ ts_buffer->timer.data = (unsigned long)ts_buffer;
+ ts_buffer->timer.expires = 0xffffffffL;
+ INIT_WORK(&ts_buffer->work, dvb_dmxdev_ts_insertion_work);
+
+ first_buffer = list_empty(&dmxdevfilter->insertion_buffers);
+ list_add_tail(&ts_buffer->next, &dmxdevfilter->insertion_buffers);
+
+ if (dmxdevfilter->state != DMXDEV_STATE_GO)
+ return 0;
+
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+
+ if (first_buffer && feed->ts->ts_insertion_init)
+ ret = feed->ts->ts_insertion_init(feed->ts);
+
+ if (!ret) {
+ dvb_dmxdev_queue_ts_insertion(ts_buffer);
+ } else {
+ list_del(&ts_buffer->next);
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+ }
+
+ return ret;
+}
+
+static int dvb_dmxdev_abort_ts_insertion(struct dmxdev_filter *dmxdevfilter,
+ struct dmx_abort_ts_insertion *params)
+{
+ int ret = 0;
+ int found_buffer;
+ struct dmxdev_feed *feed;
+ struct ts_insertion_buffer *ts_buffer, *tmp;
+
+ if (!params ||
+ !(dmxdevfilter->dev->capabilities & DMXDEV_CAP_TS_INSERTION) ||
+ (dmxdevfilter->state < DMXDEV_STATE_SET) ||
+ (dmxdevfilter->type != DMXDEV_TYPE_PES) ||
+ ((dmxdevfilter->params.pes.output != DMX_OUT_TS_TAP) &&
+ (dmxdevfilter->params.pes.output != DMX_OUT_TSDEMUX_TAP)))
+ return -EINVAL;
+
+ found_buffer = 0;
+ list_for_each_entry_safe(ts_buffer, tmp,
+ &dmxdevfilter->insertion_buffers, next) {
+ if (ts_buffer->identifier == params->identifier) {
+ list_del(&ts_buffer->next);
+ found_buffer = 1;
+ break;
+ }
+ }
+
+ if (!found_buffer)
+ return -EINVAL;
+
+ if (dmxdevfilter->state == DMXDEV_STATE_GO) {
+ dvb_dmxdev_cancel_ts_insertion(ts_buffer);
+ if (list_empty(&dmxdevfilter->insertion_buffers)) {
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+ if (feed->ts->ts_insertion_terminate)
+ ret = feed->ts->ts_insertion_terminate(
+ feed->ts);
+ }
+ }
+
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+
+ return ret;
+}
+
static int dvb_dmxdev_ts_fullness_callback(struct dmx_ts_feed *filter,
int required_space)
{
@@ -2006,6 +2258,9 @@
dvb_ringbuffer_flush(&dmxdevfilter->buffer);
dvb_dmxdev_notify_data_read(dmxdevfilter, flush_len);
dmxdevfilter->buffer.error = 0;
+ } else if (event->type == DMX_EVENT_SECTION_TIMEOUT) {
+ /* clear buffer error now that user was notified */
+ dmxdevfilter->buffer.error = 0;
}
/*
@@ -2036,10 +2291,13 @@
static void dvb_dmxdev_filter_timeout(unsigned long data)
{
struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
+ struct dmx_filter_event event;
dmxdevfilter->buffer.error = -ETIMEDOUT;
spin_lock_irq(&dmxdevfilter->dev->lock);
dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
+ event.type = DMX_EVENT_SECTION_TIMEOUT;
+ dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
spin_unlock_irq(&dmxdevfilter->dev->lock);
wake_up_all(&dmxdevfilter->buffer.queue);
}
@@ -2612,6 +2870,7 @@
{
struct dmxdev_feed *feed;
struct dmx_demux *demux;
+ struct ts_insertion_buffer *ts_buffer;
if (dmxdevfilter->state < DMXDEV_STATE_GO)
return 0;
@@ -2631,6 +2890,18 @@
case DMXDEV_TYPE_PES:
dvb_dmxdev_feed_stop(dmxdevfilter);
demux = dmxdevfilter->dev->demux;
+
+ if (!list_empty(&dmxdevfilter->insertion_buffers)) {
+ feed = list_first_entry(&dmxdevfilter->feed.ts,
+ struct dmxdev_feed, next);
+
+ list_for_each_entry(ts_buffer,
+ &dmxdevfilter->insertion_buffers, next)
+ dvb_dmxdev_cancel_ts_insertion(ts_buffer);
+ if (feed->ts->ts_insertion_terminate)
+ feed->ts->ts_insertion_terminate(feed->ts);
+ }
+
list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
demux->release_ts_feed(demux, feed->ts);
feed->ts = NULL;
@@ -2971,6 +3242,29 @@
}
dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+
+ if ((filter->type == DMXDEV_TYPE_PES) &&
+ !list_empty(&filter->insertion_buffers)) {
+ struct ts_insertion_buffer *ts_buffer;
+
+ feed = list_first_entry(&filter->feed.ts,
+ struct dmxdev_feed, next);
+
+ ret = 0;
+ if (feed->ts->ts_insertion_init)
+ ret = feed->ts->ts_insertion_init(feed->ts);
+ if (!ret) {
+ list_for_each_entry(ts_buffer,
+ &filter->insertion_buffers, next)
+ dvb_dmxdev_queue_ts_insertion(
+ ts_buffer);
+ } else {
+ printk(KERN_ERR
+ "%s: ts_insertion_init failed, err %d\n",
+ __func__, ret);
+ }
+ }
+
return 0;
}
@@ -3017,6 +3311,8 @@
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
init_timer(&dmxdevfilter->timer);
+ INIT_LIST_HEAD(&dmxdevfilter->insertion_buffers);
+
dmxdevfilter->dmx_tsp_format = DMX_TSP_FORMAT_188;
dvbdev->users++;
@@ -3027,6 +3323,8 @@
static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter)
{
+ struct ts_insertion_buffer *ts_buffer, *tmp;
+
mutex_lock(&dmxdev->mutex);
mutex_lock(&dmxdevfilter->mutex);
@@ -3034,6 +3332,13 @@
dvb_dmxdev_filter_reset(dmxdevfilter);
+ list_for_each_entry_safe(ts_buffer, tmp,
+ &dmxdevfilter->insertion_buffers, next) {
+ list_del(&ts_buffer->next);
+ vfree(ts_buffer->buffer);
+ vfree(ts_buffer);
+ }
+
if (dmxdevfilter->buffer.data) {
void *mem = dmxdevfilter->buffer.data;
@@ -3098,12 +3403,20 @@
static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
struct dmxdev_filter *filter, u16 pid)
{
+ int feed_count;
struct dmxdev_feed *feed, *tmp;
if ((filter->type != DMXDEV_TYPE_PES) ||
(filter->state < DMXDEV_STATE_SET))
return -EINVAL;
+ feed_count = 0;
+ list_for_each_entry(tmp, &filter->feed.ts, next)
+ feed_count++;
+
+ if (feed_count <= 1)
+ return -EINVAL;
+
list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
if (feed->pid == pid) {
if (feed->ts != NULL) {
@@ -3283,7 +3596,7 @@
hcount = 3 + dfil->todo;
if (hcount > count)
hcount = count;
- result = dvb_dmxdev_buffer_read(&dfil->buffer,
+ result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer,
file->f_flags & O_NONBLOCK,
buf, hcount, ppos);
if (result < 0) {
@@ -3304,7 +3617,7 @@
}
if (count > dfil->todo)
count = dfil->todo;
- result = dvb_dmxdev_buffer_read(&dfil->buffer,
+ result = dvb_dmxdev_buffer_read(dfil, &dfil->buffer,
file->f_flags & O_NONBLOCK,
buf, count, ppos);
if (result < 0)
@@ -3333,9 +3646,10 @@
if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
else
- ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
+ ret = dvb_dmxdev_buffer_read(dmxdevfilter,
+ &dmxdevfilter->buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
if (ret > 0) {
dvb_dmxdev_notify_data_read(dmxdevfilter, ret);
@@ -3625,6 +3939,24 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_SET_TS_INSERTION:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_set_ts_insertion(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_ABORT_TS_INSERTION:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_abort_ts_insertion(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 2ed99ae..d8cd982 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -114,6 +114,35 @@
struct dmx_filter_event queue[DMX_EVENT_QUEUE_SIZE];
};
+#define DMX_MIN_INSERTION_REPETITION_TIME 25 /* in msec */
+struct ts_insertion_buffer {
+ /* work scheduled for insertion of this buffer */
+ struct work_struct work;
+
+ struct list_head next;
+
+ /* buffer holding TS packets for insertion */
+ char *buffer;
+
+ /* buffer size */
+ size_t size;
+
+ /* buffer ID from user */
+ u32 identifier;
+
+ /* repetition time for the buffer insertion */
+ u32 repetition_time;
+
+ /* timer used for insertion of the buffer */
+ struct timer_list timer;
+
+ /* the recording filter to which this buffer belongs */
+ struct dmxdev_filter *dmxdevfilter;
+
+ /* indication whether insertion should be aborted */
+ int abort;
+};
+
struct dmxdev_filter {
union {
struct dmx_section_filter *sec;
@@ -145,6 +174,9 @@
enum dmx_tsp_format_t dmx_tsp_format;
u32 rec_chunk_size;
+ /* list of buffers used for insertion (struct ts_insertion_buffer) */
+ struct list_head insertion_buffers;
+
/* End-of-stream indication has been received */
int eos_state;
@@ -170,6 +202,8 @@
#define DMXDEV_CAP_PULL_MODE 0x02
#define DMXDEV_CAP_INDEXING 0x04
#define DMXDEV_CAP_EXTERNAL_BUFFS_ONLY 0x08
+#define DMXDEV_CAP_TS_INSERTION 0x10
+
enum dmx_playback_mode_t playback_mode;
dmx_source_t source;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 3f3d222..939d591 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -2331,6 +2331,25 @@
return ret;
}
+static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed,
+ char *data, size_t size)
+{
+ struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+ struct dvb_demux *demux = feed->demux;
+
+ spin_lock(&demux->lock);
+ if (!ts_feed->is_filtering) {
+ spin_unlock(&demux->lock);
+ return 0;
+ }
+
+ feed->cb.ts(data, size, NULL, 0, ts_feed, DMX_OK);
+
+ spin_unlock(&demux->lock);
+
+ return 0;
+}
+
static int dmx_ts_set_tsp_out_format(
struct dmx_ts_feed *ts_feed,
enum dmx_tsp_format_t tsp_format)
@@ -2401,6 +2420,10 @@
(*ts_feed)->notify_data_read = NULL;
(*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode;
(*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd;
+ (*ts_feed)->ts_insertion_init = NULL;
+ (*ts_feed)->ts_insertion_terminate = NULL;
+ (*ts_feed)->ts_insertion_insert_buffer =
+ dvbdmx_ts_insertion_insert_buffer;
if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
feed->state = DMX_STATE_FREE;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 731056b..756cb41 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -520,26 +520,37 @@
comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
comp_mask &= ~(0x7F << (comp_mask_index * 8));
comp_mask |= (axi_data->composite_info[comp_mask_index].
- stream_composite_mask << (comp_mask_index * 8));
+ stream_composite_mask << (comp_mask_index * 8));
+ if (stream_info->plane_offset[0])
+ comp_mask |= (axi_data->composite_info[comp_mask_index].
+ stream_composite_mask << 24);
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask |= 1 << (comp_mask_index + 25);
+ if (stream_info->plane_offset[0] && (comp_mask >> 24))
+ irq_mask |= BIT(28);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
+ struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
uint32_t comp_mask, comp_mask_index = stream_info->comp_mask_index;
uint32_t irq_mask;
comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
comp_mask &= ~(0x7F << (comp_mask_index * 8));
+ if (stream_info->plane_offset[0])
+ comp_mask &= ~(axi_data->composite_info[comp_mask_index].
+ stream_composite_mask << 24);
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
irq_mask &= ~(1 << (comp_mask_index + 25));
+ if (stream_info->plane_offset[0] && !(comp_mask >> 24))
+ irq_mask &= ~BIT(28);
msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
}
@@ -1219,7 +1230,7 @@
static struct msm_vfe_axi_hardware_info msm_vfe40_axi_hw_info = {
.num_wm = 4,
- .num_comp_mask = 4,
+ .num_comp_mask = 3,
.num_rdi = 3,
.num_rdi_master = 3,
.min_wm_ub = 64,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index f50812c..13160ee 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -399,7 +399,10 @@
uint32_t framedrop_period = msm_isp_get_framedrop_period(
stream_cfg_cmd->frame_skip_pattern);
- stream_info->framedrop_pattern = 0x1;
+ if (stream_cfg_cmd->frame_skip_pattern == SKIP_ALL)
+ stream_info->framedrop_pattern = 0x0;
+ else
+ stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
if (stream_cfg_cmd->init_frame_drop < framedrop_period) {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index 77ed03e..ce71235 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -206,7 +206,11 @@
framedrop_period = msm_isp_get_framedrop_period(
stream_req_cmd->framedrop_pattern);
- stream_info->framedrop_pattern = 0x1;
+
+ if (stream_req_cmd->framedrop_pattern == SKIP_ALL)
+ stream_info->framedrop_pattern = 0x0;
+ else
+ stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
if (!stream_info->composite_flag)
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 c981901..dd8db03 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
@@ -174,6 +174,8 @@
case EVERY_32FRAME:
return 32;
break;
+ case SKIP_ALL:
+ return 1;
default:
return 1;
}
@@ -228,12 +230,12 @@
return rc;
}
-static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, uint32_t rate)
+static int msm_isp_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
{
int rc = 0;
int clk_idx = vfe_dev->hw_info->vfe_clk_idx;
long round_rate =
- clk_round_rate(vfe_dev->vfe_clk[clk_idx], rate);
+ clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate);
if (round_rate < 0) {
pr_err("%s: Invalid vfe clock rate\n", __func__);
return round_rate;
@@ -244,6 +246,7 @@
pr_err("%s: Vfe set rate error\n", __func__);
return rc;
}
+ *rate = round_rate;
return 0;
}
@@ -264,7 +267,7 @@
input_cfg->d.pix_cfg.camif_cfg.pixels_per_line;
rc = msm_isp_set_clk_rate(vfe_dev,
- vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock);
+ &vfe_dev->axi_data.src_info[VFE_PIX_0].pixel_clock);
if (rc < 0) {
pr_err("%s: clock set rate failed\n", __func__);
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 962c079..a95eda7 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -94,7 +94,8 @@
for (i = 0; i < ispif->vfe_info.num_vfe; i++) {
- msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_CTRL_0(i));
+ msm_camera_io_w(1 << PIX0_LINE_BUF_EN_BIT,
+ ispif->base + ISPIF_VFE_m_CTRL_0(i));
msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(i));
msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(i));
msm_camera_io_w(0, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(i));
diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
index 35210a0..b0ff832 100644
--- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -35,7 +35,7 @@
new_entry->vb2_buf = buf_mngr_dev->vb2_ops.get_buf(buf_info->session_id,
buf_info->stream_id);
if (!new_entry->vb2_buf) {
- pr_err("%s:Get buf is null\n", __func__);
+ pr_debug("%s:Get buf is null\n", __func__);
kfree(new_entry);
return -EINVAL;
}
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 8cdaa4b..5a174f5 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
@@ -860,7 +860,7 @@
rc = v4l2_subdev_call(cpp_dev->buf_mgr_subdev, core, ioctl,
buff_mgr_ops, buff_mgr_info);
if (rc < 0)
- pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+ pr_debug("%s: line %d rc = %d\n", __func__, __LINE__, rc);
return rc;
}
@@ -1010,7 +1010,7 @@
&buff_mgr_info);
if (rc < 0) {
rc = -EAGAIN;
- pr_err("error getting buffer rc:%d\n", rc);
+ pr_debug("error getting buffer rc:%d\n", rc);
goto ERROR2;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
index 47e672d..3dd3a4e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c
@@ -42,13 +42,13 @@
e_ctrl->eboard_info->eeprom_name,
sizeof(cdata->cfg.eeprom_name));
break;
- case CFG_EEPROM_GET_DATA:
- CDBG("%s E CFG_EEPROM_GET_DATA\n", __func__);
+ case CFG_EEPROM_GET_CAL_DATA:
+ CDBG("%s E CFG_EEPROM_GET_CAL_DATA\n", __func__);
cdata->cfg.get_data.num_bytes =
e_ctrl->num_bytes;
break;
- case CFG_EEPROM_READ_DATA:
- CDBG("%s E CFG_EEPROM_READ_DATA\n", __func__);
+ case CFG_EEPROM_READ_CAL_DATA:
+ CDBG("%s E CFG_EEPROM_READ_CAL_DATA\n", __func__);
rc = copy_to_user(cdata->cfg.read_data.dbuffer,
e_ctrl->memory_data,
cdata->cfg.read_data.num_bytes);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index 76aa695..ac697fb 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -40,7 +40,7 @@
struct msm_flash_fn_t *func_tbl;
const char *led_trigger_name[MAX_LED_TRIGGERS];
struct led_trigger *led_trigger[MAX_LED_TRIGGERS];
- uint32_t max_current[MAX_LED_TRIGGERS];
+ uint32_t op_current[MAX_LED_TRIGGERS];
void *data;
};
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index 1a75a5a..c6f1f72 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -59,11 +59,11 @@
case MSM_CAMERA_LED_LOW:
led_trigger_event(fctrl->led_trigger[0],
- fctrl->max_current[0] / 2);
+ fctrl->op_current[0] / 2);
break;
case MSM_CAMERA_LED_HIGH:
- led_trigger_event(fctrl->led_trigger[0], fctrl->max_current[0]);
+ led_trigger_event(fctrl->led_trigger[0], fctrl->op_current[0]);
break;
case MSM_CAMERA_LED_INIT:
@@ -144,7 +144,7 @@
CDBG("default trigger %s\n", fctrl.led_trigger_name[i]);
rc = of_property_read_u32(flash_src_node,
- "qcom,max-current", &fctrl.max_current[i]);
+ "qcom,current", &fctrl.op_current[i]);
if (rc < 0) {
pr_err("failed rc %d\n", rc);
of_node_put(flash_src_node);
@@ -153,7 +153,7 @@
of_node_put(flash_src_node);
- CDBG("max_current[%d] %d\n", i, fctrl.max_current[i]);
+ CDBG("max_current[%d] %d\n", i, fctrl.op_current[i]);
led_trigger_register_simple(fctrl.led_trigger_name[i],
&fctrl.led_trigger[i]);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
index 8855e85..29369de 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tsif.c
@@ -703,7 +703,8 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_INDEXING;
+ DMXDEV_CAP_INDEXING |
+ DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_stc = mpq_tsif_dmx_get_stc;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index 43a65e9..5e14d0c 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -1759,7 +1759,8 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_INDEXING;
+ DMXDEV_CAP_INDEXING |
+ DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_stc = mpq_tspp_dmx_get_stc;
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
index c306488..60e3cb4 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v2.c
@@ -143,7 +143,8 @@
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
- DMXDEV_CAP_INDEXING;
+ DMXDEV_CAP_INDEXING |
+ DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 43a3dad..19f5dcd 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -1018,6 +1018,41 @@
callback(SESSION_END_DONE, &cmd_done);
}
+static void hfi_process_session_abort_done(
+ msm_vidc_callback callback, u32 device_id,
+ struct hfi_msg_sys_session_abort_done_packet *pkt)
+{
+ struct msm_vidc_cb_cmd_done cmd_done;
+ struct hal_session *sess_close;
+
+ dprintk(VIDC_DBG, "RECEIVED:SESSION_ABORT_DONE");
+
+ if (!pkt || pkt->size !=
+ sizeof(struct hfi_msg_sys_session_abort_done_packet)) {
+ dprintk(VIDC_ERR, "%s: bad packet/packet size: %d",
+ __func__, pkt ? pkt->size : 0);
+ return;
+ }
+ memset(&cmd_done, 0, sizeof(struct msm_vidc_cb_cmd_done));
+ cmd_done.device_id = device_id;
+ cmd_done.session_id =
+ ((struct hal_session *) pkt->session_id)->session_id;
+ cmd_done.status = hfi_map_err_status((u32)pkt->error_type);
+ cmd_done.data = NULL;
+ cmd_done.size = 0;
+
+ sess_close = (struct hal_session *)pkt->session_id;
+ if (!sess_close) {
+ dprintk(VIDC_ERR, "%s: invalid session pointer\n", __func__);
+ return;
+ }
+ dprintk(VIDC_ERR, "deleted the session: 0x%x",
+ sess_close->session_id);
+ list_del(&sess_close->list);
+ kfree(sess_close);
+ callback(SESSION_ABORT_DONE, &cmd_done);
+}
+
static void hfi_process_session_get_seq_hdr_done(
msm_vidc_callback callback, u32 device_id,
struct hfi_msg_session_get_sequence_header_done_packet *pkt)
@@ -1134,6 +1169,10 @@
hfi_msg_session_release_buffers_done_packet*)
msg_hdr);
break;
+ case HFI_MSG_SYS_SESSION_ABORT_DONE:
+ hfi_process_session_abort_done(callback, device_id, (struct
+ hfi_msg_sys_session_abort_done_packet*) msg_hdr);
+ break;
default:
dprintk(VIDC_ERR, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 1611a09..bf646a2 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -697,32 +697,43 @@
}
int msm_vdec_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a)
{
- u32 us_per_frame = 0;
- int rc = 0;
+ u64 us_per_frame = 0;
+ int rc = 0, fps = 0, rem = 0;
if (a->parm.output.timeperframe.denominator) {
switch (a->type) {
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- us_per_frame = a->parm.output.timeperframe.numerator/
- a->parm.output.timeperframe.denominator;
- break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- us_per_frame = a->parm.capture.timeperframe.numerator/
- a->parm.capture.timeperframe.denominator;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ us_per_frame = a->parm.output.timeperframe.numerator *
+ (u64)USEC_PER_SEC;
+ do_div(us_per_frame, a->parm.output.\
+ timeperframe.denominator);
break;
default:
dprintk(VIDC_ERR,
- "Scale clocks : Unknown buffer type\n");
+ "Scale clocks : Unknown buffer type %d\n",
+ a->type);
break;
}
}
+
if (!us_per_frame) {
dprintk(VIDC_ERR,
- "Failed to scale clocks : time between frames is 0\n");
+ "Failed to scale clocks : time between frames is 0\n");
rc = -EINVAL;
goto exit;
}
- inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
- if (inst->prop.fps) {
+
+ fps = USEC_PER_SEC;
+ rem = do_div(fps, us_per_frame);
+ if (rem) {
+ /* Effectively fps = ceil((float)USEC_PER_SEC/us_per_frame) */
+ fps++;
+ }
+
+ if (inst->prop.fps != fps) {
+ dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
+ inst, inst->prop.fps, fps);
+ inst->prop.fps = fps;
msm_comm_scale_clocks_and_bus(inst);
}
exit:
@@ -1121,11 +1132,24 @@
int rc = 0;
struct v4l2_event dqevent = {0};
struct msm_vidc_core *core = inst->core;
+
+ if (!dec || !inst || !inst->core) {
+ dprintk(VIDC_ERR, "%s invalid params", __func__);
+ return -EINVAL;
+ }
switch (dec->cmd) {
case V4L2_DEC_QCOM_CMD_FLUSH:
rc = msm_comm_flush(inst, dec->flags);
break;
case V4L2_DEC_CMD_STOP:
+ if (core->state != VIDC_CORE_INVALID &&
+ inst->state == MSM_VIDC_CORE_INVALID) {
+ rc = msm_comm_recover_from_session_error(inst);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed to recover from session_error: %d\n",
+ rc);
+ }
rc = msm_comm_release_scratch_buffers(inst);
if (rc)
dprintk(VIDC_ERR,
@@ -1191,7 +1215,6 @@
inst->capability.width.min = MIN_SUPPORTED_WIDTH;
inst->capability.width.max = DEFAULT_WIDTH;
inst->prop.fps = 30;
- inst->prop.prev_time_stamp = 0;
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 66a3b6e..b6e77dc 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1970,7 +1970,7 @@
{
u32 property_id = 0, us_per_frame = 0;
void *pdata;
- int rc = 0;
+ int rc = 0, fps = 0, rem = 0;
struct hal_frame_rate frame_rate;
struct hfi_device *hdev;
@@ -1978,32 +1978,45 @@
dprintk(VIDC_ERR, "%s invalid parameters", __func__);
return -EINVAL;
}
- hdev = inst->core->device;
+ hdev = inst->core->device;
property_id = HAL_CONFIG_FRAME_RATE;
+
if (a->parm.output.timeperframe.denominator) {
switch (a->type) {
- case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
us_per_frame = a->parm.output.timeperframe.numerator *
- USEC_PER_SEC / a->parm.output.\
- timeperframe.denominator;
+ (u64)USEC_PER_SEC;
+ do_div(us_per_frame, a->parm.output.\
+ timeperframe.denominator);
break;
default:
dprintk(VIDC_ERR,
- "Scale clocks : Unknown buffer type\n");
+ "Scale clocks : Unknown buffer type %d\n",
+ a->type);
break;
}
}
if (!us_per_frame) {
dprintk(VIDC_ERR,
- "Failed to scale clocks : time between frames is 0\n");
+ "Failed to scale clocks : time between frames is 0\n");
rc = -EINVAL;
goto exit;
}
- inst->prop.fps = (u8) (USEC_PER_SEC / us_per_frame);
- if (inst->prop.fps) {
+
+ fps = USEC_PER_SEC;
+ rem = do_div(fps, us_per_frame);
+ if (rem) {
+ /* Effectively fps = ceil((float)USEC_PER_SEC/us_per_frame) */
+ fps++;
+ }
+
+ if (inst->prop.fps != fps) {
+ dprintk(VIDC_PROF, "reported fps changed for %p: %d->%d\n",
+ inst, inst->prop.fps, fps);
+ inst->prop.fps = fps;
frame_rate.frame_rate = inst->prop.fps * (0x1<<16);
frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
pdata = &frame_rate;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index feb239e..4fc7518 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -47,8 +47,6 @@
__mbs;\
})
-#define TIME_DIFF_THRESHOLD 200
-
static int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type)
{
@@ -638,56 +636,6 @@
}
}
-static void msm_comm_update_clocks(struct msm_vidc_inst *inst,
- u64 cur_time_stamp)
-{
- u32 new_time_diff = 0, cur_time_diff = 0;
- u8 updated_fps = 0;
- struct v4l2_ctrl *ctrl = NULL;
- u32 output_order = 0;
-
- if (inst->session_type == MSM_VIDC_ENCODER)
- goto exit;
- if (cur_time_stamp >= LLONG_MAX) {
- dprintk(VIDC_DBG,
- "Clock scaling failed : Timestamp invalid\n");
- goto exit;
- }
- ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
- V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER);
- if (!ctrl) {
- dprintk(VIDC_WARN, "Unable to find output order control\n");
- dprintk(VIDC_WARN,
- "Performance might be impacted for higher fps clips\n");
- goto exit;
- }
- output_order = v4l2_ctrl_g_ctrl(ctrl);
- if (output_order == V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) {
- new_time_diff =
- (u32)(cur_time_stamp - inst->prop.prev_time_stamp);
- inst->prop.prev_time_stamp = cur_time_stamp;
- if (!new_time_diff)
- goto exit;
- if (inst->prop.fps)
- cur_time_diff = USEC_PER_SEC / inst->prop.fps;
- cur_time_diff = cur_time_diff > new_time_diff ?
- cur_time_diff - new_time_diff :
- new_time_diff - cur_time_diff;
- if (cur_time_diff > TIME_DIFF_THRESHOLD) {
- updated_fps = (u8) (USEC_PER_SEC / new_time_diff);
- if (updated_fps && (updated_fps != inst->prop.fps)) {
- inst->prop.fps = updated_fps;
- dprintk(VIDC_DBG,
- "Updating clocks: Decoding fps = %d\n",
- inst->prop.fps);
- msm_comm_scale_clocks_and_bus(inst);
- }
- }
- }
-exit:
- return;
-}
-
static void handle_fbd(enum command_response cmd, void *data)
{
struct msm_vidc_cb_data_done *response = data;
@@ -717,7 +665,6 @@
fill_buf_done->timestamp_lo;
vb->v4l2_buf.timestamp =
ns_to_timeval(time_usec * NSEC_PER_USEC);
- msm_comm_update_clocks(inst, time_usec);
}
vb->v4l2_buf.flags = 0;
@@ -726,11 +673,15 @@
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG)
vb->v4l2_buf.flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME)
- vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOSEQ)
vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_EOSEQ;
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DECODEONLY)
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY;
switch (fill_buf_done->picture_type) {
case HAL_PICTURE_IDR:
+ vb->v4l2_buf.flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME;
+ break;
case HAL_PICTURE_I:
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
break;
@@ -859,6 +810,7 @@
handle_release_res_done(cmd, data);
break;
case SESSION_END_DONE:
+ case SESSION_ABORT_DONE:
handle_session_close(cmd, data);
break;
case VIDC_EVENT_CHANGE:
@@ -2260,7 +2212,10 @@
kfree(temp);
}
}
- rc = call_hfi_op(hdev, session_flush, inst->session,
+ /*Do not send flush in case of session_error */
+ if (!(inst->state == MSM_VIDC_CORE_INVALID &&
+ core->state != VIDC_CORE_INVALID))
+ rc = call_hfi_op(hdev, session_flush, inst->session,
HAL_FLUSH_ALL);
}
mutex_unlock(&inst->sync_lock);
@@ -2430,3 +2385,33 @@
}
return rc;
}
+
+int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst)
+{
+ struct hfi_device *hdev;
+ int rc = 0;
+
+ if (!inst || !inst->core || !inst->core->device) {
+ dprintk(VIDC_ERR, "%s: invalid input parameters", __func__);
+ return -EINVAL;
+ }
+ hdev = inst->core->device;
+
+ init_completion(&inst->completions[SESSION_MSG_INDEX
+ (SESSION_ABORT_DONE)]);
+
+ /* We have received session_error. Send session_abort to firmware
+ * to clean up and release the session
+ */
+ rc = call_hfi_op(hdev, session_abort, (void *) inst->session);
+ if (rc) {
+ dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc);
+ return rc;
+ }
+
+ rc = wait_for_sess_signal_receipt(inst, SESSION_ABORT_DONE);
+ if (rc)
+ dprintk(VIDC_ERR, "%s: Wait interrupted or timeout: %d\n",
+ __func__, rc);
+ return rc;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 862dfab..c018345 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -48,3 +48,4 @@
V4L2_CTRL_DRIVER_PRIV(idx))
#endif
+int msm_comm_recover_from_session_error(struct msm_vidc_inst *inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 3208df9..ae1e9b7 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -198,6 +198,7 @@
write_str(&dbg_buf, "core: 0x%p\n", inst->core);
write_str(&dbg_buf, "height: %d\n", inst->prop.height);
write_str(&dbg_buf, "width: %d\n", inst->prop.width);
+ write_str(&dbg_buf, "fps: %d\n", inst->prop.fps);
write_str(&dbg_buf, "state: %d\n", inst->state);
write_str(&dbg_buf, "-----------Formats-------------\n");
for (i = 0; i < MAX_PORT_NUM; i++) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index e5696be..d9a2332 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -130,7 +130,6 @@
u32 height;
u32 fps;
u32 bitrate;
- u64 prev_time_stamp;
};
struct buf_queue {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 3fbfec4..6672d7b 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -482,7 +482,7 @@
HAL_PICTURE_I = 0x01,
HAL_PICTURE_P = 0x02,
HAL_PICTURE_B = 0x04,
- HAL_PICTURE_IDR = 0x7F001000,
+ HAL_PICTURE_IDR = 0x08,
HAL_FRAME_NOTCODED = 0x7F002000,
HAL_FRAME_YUV = 0x7F004000,
HAL_UNUSED_PICT = 0x10000000,
@@ -1020,7 +1020,7 @@
};
#define call_hfi_op(q, op, args...) \
- (((q)->op) ? ((q)->op(args)) : 0)
+ (((q) && (q)->op) ? ((q)->op(args)) : 0)
struct hfi_device {
void *hfi_device_data;
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index 2bb8375..d44792c 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -14,7 +14,7 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/ioctl.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/platform_device.h>
@@ -78,7 +78,8 @@
struct wfd_inst {
struct vb2_queue vid_bufq;
- spinlock_t inst_lock;
+ struct mutex lock;
+ struct mutex vb2_lock;
u32 buf_count;
struct task_struct *mdp_task;
void *mdp_inst;
@@ -114,7 +115,6 @@
{
struct file *priv_data = (struct file *)(q->drv_priv);
struct wfd_inst *inst = file_to_inst(priv_data);
- unsigned long flags;
int i;
WFD_MSG_DBG("In %s\n", __func__);
@@ -122,12 +122,12 @@
return -EINVAL;
*num_planes = 1;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
for (i = 0; i < *num_planes; ++i) {
sizes[i] = inst->out_buf_size;
alloc_ctxs[i] = inst;
}
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return 0;
}
@@ -257,16 +257,15 @@
struct mem_region *enc_mregion, *mdp_mregion;
struct mem_region_pair *mpair;
int rc;
- unsigned long flags;
struct mdp_buf_info mdp_buf = {0};
struct mem_region_map mmap_context = {0};
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (inst->input_bufs_allocated) {
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return 0;
}
inst->input_bufs_allocated = true;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
mpair = kzalloc(sizeof(*mpair), GFP_KERNEL);
@@ -409,15 +408,14 @@
{
struct list_head *ptr, *next;
struct mem_region_pair *mpair;
- unsigned long flags;
int rc = 0;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (!inst->input_bufs_allocated) {
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return;
}
inst->input_bufs_allocated = false;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
if (!list_empty(&inst->input_mem_list)) {
list_for_each_safe(ptr, next,
&inst->input_mem_list) {
@@ -470,8 +468,7 @@
{
struct mem_info_entry *temp;
struct mem_info *ret = NULL;
- unsigned long flags;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (!list_empty(&inst->minfo_list)) {
list_for_each_entry(temp, &inst->minfo_list, list) {
if (temp && temp->userptr == userptr) {
@@ -480,7 +477,7 @@
}
}
}
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return ret;
}
@@ -489,8 +486,7 @@
{
struct list_head *ptr, *next;
struct mem_info_entry *temp;
- unsigned long flags;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (!list_empty(&inst->minfo_list)) {
list_for_each_safe(ptr, next,
&inst->minfo_list) {
@@ -502,7 +498,7 @@
}
}
}
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
}
static void wfd_unregister_out_buf(struct wfd_inst *inst,
struct mem_info *minfo)
@@ -806,7 +802,6 @@
struct v4l2_format *fmt)
{
struct wfd_inst *inst = file_to_inst(filp);
- unsigned long flags;
if (!fmt) {
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
@@ -815,13 +810,13 @@
WFD_MSG_ERR("Only V4L2_BUF_TYPE_VIDEO_CAPTURE is supported\n");
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
fmt->fmt.pix.width = inst->width;
fmt->fmt.pix.height = inst->height;
fmt->fmt.pix.pixelformat = inst->pixelformat;
fmt->fmt.pix.sizeimage = inst->out_buf_size;
fmt->fmt.pix.priv = 0;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return 0;
}
@@ -832,7 +827,6 @@
struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev = video_drvdata(filp);
struct mdp_prop prop;
- unsigned long flags;
struct bufreq breq;
if (!fmt) {
WFD_MSG_ERR("Invalid argument\n");
@@ -864,13 +858,13 @@
WFD_MSG_ERR("Failed to set buffer reqs on encoder\n");
return rc;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
inst->input_buf_size = breq.size;
inst->out_buf_size = fmt->fmt.pix.sizeimage;
prop.height = inst->height = fmt->fmt.pix.height;
prop.width = inst->width = fmt->fmt.pix.width;
prop.inst = inst->mdp_inst;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_SET_PROP,
(void *)&prop);
if (rc)
@@ -882,7 +876,6 @@
{
struct wfd_inst *inst = file_to_inst(filp);
struct wfd_device *wfd_dev = video_drvdata(filp);
- unsigned long flags;
int rc = 0;
if (b->type != V4L2_CAP_VIDEO_CAPTURE ||
@@ -897,9 +890,9 @@
WFD_MSG_ERR("Failed to get buf reqs from encoder\n");
return rc;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
inst->buf_count = b->count;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
rc = vb2_reqbufs(&inst->vid_bufq, b);
return rc;
}
@@ -908,7 +901,6 @@
{
struct mem_info_entry *minfo_entry;
struct mem_info *minfo;
- unsigned long flags;
if (!b || !inst || !b->reserved) {
WFD_MSG_ERR("Invalid arguments\n");
return -EINVAL;
@@ -924,9 +916,9 @@
return -EINVAL;
}
minfo_entry->userptr = b->m.userptr;
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
list_add_tail(&minfo_entry->list, &inst->minfo_list);
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
} else
WFD_MSG_DBG("Buffer already registered\n");
@@ -948,7 +940,10 @@
return rc;
}
+ mutex_lock(&inst->vb2_lock);
rc = vb2_qbuf(&inst->vid_bufq, b);
+ mutex_unlock(&inst->vb2_lock);
+
if (rc)
WFD_MSG_ERR("Failed to queue buffer\n");
else
@@ -962,16 +957,15 @@
{
int rc = 0;
struct wfd_inst *inst = file_to_inst(filp);
- unsigned long flags;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
WFD_MSG_ERR("stream on for buffer type = %d is not "
"supported.\n", i);
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
inst->streamoff = false;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
rc = vb2_streamon(&inst->vid_bufq, i);
if (rc) {
@@ -988,7 +982,6 @@
enum v4l2_buf_type i)
{
struct wfd_inst *inst = file_to_inst(filp);
- unsigned long flags;
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
WFD_MSG_ERR("stream off for buffer type = %d is not "
@@ -996,14 +989,14 @@
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
if (inst->streamoff) {
WFD_MSG_ERR("Module is already in streamoff state\n");
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
return -EINVAL;
}
inst->streamoff = true;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
WFD_MSG_DBG("Calling videobuf_streamoff\n");
vb2_streamoff(&inst->vid_bufq, i);
wake_up(&inst->event_handler.wait);
@@ -1016,7 +1009,10 @@
int rc;
WFD_MSG_DBG("Waiting to dequeue buffer\n");
- rc = vb2_dqbuf(&inst->vid_bufq, b, 0);
+
+ /* XXX: If we switch to non-blocking mode in the future,
+ * we'll need to lock this with vb2_lock */
+ rc = vb2_dqbuf(&inst->vid_bufq, b, false /* blocking */);
if (rc)
WFD_MSG_ERR("Failed to dequeue buffer\n");
@@ -1233,7 +1229,6 @@
};
static int wfd_set_default_properties(struct file *filp)
{
- unsigned long flags;
struct v4l2_format fmt;
struct v4l2_control ctrl;
struct wfd_inst *inst = file_to_inst(filp);
@@ -1241,13 +1236,13 @@
WFD_MSG_ERR("Invalid argument\n");
return -EINVAL;
}
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.height = inst->height = DEFAULT_WFD_HEIGHT;
fmt.fmt.pix.width = inst->width = DEFAULT_WFD_WIDTH;
fmt.fmt.pix.pixelformat = inst->pixelformat
= V4L2_PIX_FMT_H264;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
wfdioc_s_fmt(filp, filp->private_data, &fmt);
ctrl.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
@@ -1258,8 +1253,13 @@
static void venc_op_buffer_done(void *cookie, u32 status,
struct vb2_buffer *buf)
{
+ struct file *filp = cookie;
+ struct wfd_inst *inst = file_to_inst(filp);
+
WFD_MSG_DBG("yay!! got callback\n");
+ mutex_lock(&inst->vb2_lock);
vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
+ mutex_unlock(&inst->vb2_lock);
}
static void venc_ip_buffer_done(void *cookie, u32 status,
@@ -1430,7 +1430,8 @@
goto err_mdp_open;
}
filp->private_data = &inst->event_handler;
- spin_lock_init(&inst->inst_lock);
+ mutex_init(&inst->lock);
+ mutex_init(&inst->vb2_lock);
INIT_LIST_HEAD(&inst->input_mem_list);
INIT_LIST_HEAD(&inst->minfo_list);
@@ -1531,6 +1532,8 @@
wfd_stats_deinit(&inst->stats);
v4l2_fh_del(&inst->event_handler);
+ mutex_destroy(&inst->lock);
+ mutex_destroy(&inst->vb2_lock);
kfree(inst);
}
@@ -1546,22 +1549,21 @@
unsigned int wfd_poll(struct file *filp, struct poll_table_struct *pt)
{
struct wfd_inst *inst = file_to_inst(filp);
- unsigned int poll_flags = 0;
- unsigned long flags;
+ unsigned long flags = 0;
bool streamoff = false;
poll_wait(filp, &inst->event_handler.wait, pt);
- spin_lock_irqsave(&inst->inst_lock, flags);
+ mutex_lock(&inst->lock);
streamoff = inst->streamoff;
- spin_unlock_irqrestore(&inst->inst_lock, flags);
+ mutex_unlock(&inst->lock);
if (v4l2_event_pending(&inst->event_handler))
- poll_flags |= POLLPRI;
+ flags |= POLLPRI;
if (streamoff)
- poll_flags |= POLLERR;
+ flags |= POLLERR;
- return poll_flags;
+ return flags;
}
static const struct v4l2_file_operations g_wfd_fops = {
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 153552d..d673713 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -3790,6 +3790,27 @@
if (retval < 0)
FMDERR("set CF0 Threshold failed\n");
break;
+ case V4L2_CID_PRIVATE_RXREPEATCOUNT:
+ rd.mode = RDS_PS0_XFR_MODE;
+ rd.length = RDS_PS0_LEN;
+ rd.param_len = 0;
+ rd.param = 0;
+
+ retval = hci_def_data_read(&rd, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("default data read failed for PS0 %x", retval);
+ return retval;
+ }
+ wrd.mode = RDS_PS0_XFR_MODE;
+ wrd.length = RDS_PS0_LEN;
+ memcpy(&wrd.data, &radio->default_data.data,
+ radio->default_data.ret_data_len);
+ wrd.data[RX_REPEATE_BYTE_OFFSET] = ctrl->value;
+
+ retval = hci_def_data_write(&wrd, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("set RxRePeat count failed\n");
+ break;
default:
retval = -EINVAL;
}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 046faac..130ff48 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -70,8 +70,7 @@
static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *dest, bool interface_reg)
{
- int ret;
- u8 *buf = dest;
+ int i, ret;
if (bytes <= 0) {
dev_err(wcd9xxx->dev, "Invalid byte read length %d\n", bytes);
@@ -82,9 +81,11 @@
if (ret < 0) {
dev_err(wcd9xxx->dev, "Codec read failed\n");
return ret;
- } else
- dev_dbg(wcd9xxx->dev, "Read 0x%02x from 0x%x\n",
- *buf, reg);
+ } else {
+ for (i = 0; i < bytes; i++)
+ dev_dbg(wcd9xxx->dev, "Read 0x%02x from 0x%x\n",
+ ((u8 *)dest)[i], reg + i);
+ }
return 0;
}
@@ -107,15 +108,16 @@
static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *src, bool interface_reg)
{
- u8 *buf = src;
+ int i;
if (bytes <= 0) {
pr_err("%s: Error, invalid write length\n", __func__);
return -EINVAL;
}
- dev_dbg(wcd9xxx->dev, "Write %02x to 0x%x\n",
- *buf, reg);
+ for (i = 0; i < bytes; i++)
+ dev_dbg(wcd9xxx->dev, "Write %02x to 0x%x\n", ((u8 *)src)[i],
+ reg + i);
return wcd9xxx->write_dev(wcd9xxx, reg, bytes, src, interface_reg);
}
@@ -1147,6 +1149,10 @@
(of_property_read_bool(dev->of_node, "qcom,cdc-micbias4-ext-cap") ?
MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+ micbias->bias2_is_headset_only =
+ of_property_read_bool(dev->of_node,
+ "qcom,cdc-micbias2-headset-only");
+
dev_dbg(dev, "ldoh_v %u cfilt1_mv %u cfilt2_mv %u cfilt3_mv %u",
(u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv,
(u32)micbias->cfilt2_mv, (u32)micbias->cfilt3_mv);
@@ -1162,6 +1168,8 @@
dev_dbg(dev, "bias3_ext_cap %d bias4_ext_cap %d\n",
micbias->bias3_cap_mode, micbias->bias4_cap_mode);
+ dev_dbg(dev, "bias2_is_headset_only %d\n",
+ micbias->bias2_is_headset_only);
return 0;
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 2573a16..a7932ba 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -51,10 +51,6 @@
To compile this driver as a module, choose M here: the
module will be called ad525x_dpot-spi.
-config ANDROID_PMEM
- bool "Android pmem allocator"
- default y
-
config ATMEL_PWM
tristate "Atmel AT32/AT91 PWM support"
depends on HAVE_CLK
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 327d1ec..760f768 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -19,7 +19,6 @@
obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o
obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o
obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o
-obj-$(CONFIG_ANDROID_PMEM) += pmem.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c
deleted file mode 100644
index e91db7a..0000000
--- a/drivers/misc/pmem.c
+++ /dev/null
@@ -1,2961 +0,0 @@
-/* drivers/android/pmem.c
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/export.h>
-#include <linux/miscdevice.h>
-#include <linux/platform_device.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/fmem.h>
-#include <linux/mm.h>
-#include <linux/list.h>
-#include <linux/debugfs.h>
-#include <linux/android_pmem.h>
-#include <linux/mempolicy.h>
-#include <linux/sched.h>
-#include <linux/kobject.h>
-#include <linux/pm_runtime.h>
-#include <linux/memory_alloc.h>
-#include <linux/vmalloc.h>
-#include <linux/io.h>
-#include <linux/mm_types.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/cacheflush.h>
-#include <asm/sizes.h>
-#include <asm/mach/map.h>
-#include <asm/page.h>
-
-#define PMEM_MAX_DEVICES (10)
-
-#define PMEM_MAX_ORDER (128)
-#define PMEM_MIN_ALLOC PAGE_SIZE
-
-#define PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS (64)
-
-#define PMEM_32BIT_WORD_ORDER (5)
-#define PMEM_BITS_PER_WORD_MASK (BITS_PER_LONG - 1)
-
-#ifdef CONFIG_ANDROID_PMEM_DEBUG
-#define PMEM_DEBUG 1
-#else
-#define PMEM_DEBUG 0
-#endif
-
-#define SYSTEM_ALLOC_RETRY 10
-
-/* indicates that a refernce to this file has been taken via get_pmem_file,
- * the file should not be released until put_pmem_file is called */
-#define PMEM_FLAGS_BUSY 0x1
-/* indicates that this is a suballocation of a larger master range */
-#define PMEM_FLAGS_CONNECTED 0x1 << 1
-/* indicates this is a master and not a sub allocation and that it is mmaped */
-#define PMEM_FLAGS_MASTERMAP 0x1 << 2
-/* submap and unsubmap flags indicate:
- * 00: subregion has never been mmaped
- * 10: subregion has been mmaped, reference to the mm was taken
- * 11: subretion has ben released, refernece to the mm still held
- * 01: subretion has been released, reference to the mm has been released
- */
-#define PMEM_FLAGS_SUBMAP 0x1 << 3
-#define PMEM_FLAGS_UNSUBMAP 0x1 << 4
-
-struct pmem_data {
- /* in alloc mode: an index into the bitmap
- * in no_alloc mode: the size of the allocation */
- int index;
- /* see flags above for descriptions */
- unsigned int flags;
- /* protects this data field, if the mm_mmap sem will be held at the
- * same time as this sem, the mm sem must be taken first (as this is
- * the order for vma_open and vma_close ops */
- struct rw_semaphore sem;
- /* info about the mmaping process */
- struct vm_area_struct *vma;
- /* task struct of the mapping process */
- struct task_struct *task;
- /* process id of teh mapping process */
- pid_t pid;
- /* file descriptor of the master */
- int master_fd;
- /* file struct of the master */
- struct file *master_file;
- /* a list of currently available regions if this is a suballocation */
- struct list_head region_list;
- /* a linked list of data so we can access them for debugging */
- struct list_head list;
-#if PMEM_DEBUG
- int ref;
-#endif
-};
-
-struct pmem_bits {
- unsigned allocated:1; /* 1 if allocated, 0 if free */
- unsigned order:7; /* size of the region in pmem space */
-};
-
-struct pmem_region_node {
- struct pmem_region region;
- struct list_head list;
-};
-
-#define PMEM_DEBUG_MSGS 0
-#if PMEM_DEBUG_MSGS
-#define DLOG(fmt,args...) \
- do { pr_debug("[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \
- ##args); } \
- while (0)
-#else
-#define DLOG(x...) do {} while (0)
-#endif
-
-enum pmem_align {
- PMEM_ALIGN_4K,
- PMEM_ALIGN_1M,
-};
-
-#define PMEM_NAME_SIZE 16
-
-struct alloc_list {
- void *addr; /* physical addr of allocation */
- void *aaddr; /* aligned physical addr */
- unsigned int size; /* total size of allocation */
- unsigned char __iomem *vaddr; /* Virtual addr */
- struct list_head allocs;
-};
-
-struct pmem_info {
- struct miscdevice dev;
- /* physical start address of the remaped pmem space */
- unsigned long base;
- /* vitual start address of the remaped pmem space */
- unsigned char __iomem *vbase;
- /* total size of the pmem space */
- unsigned long size;
- /* number of entries in the pmem space */
- unsigned long num_entries;
- /* pfn of the garbage page in memory */
- unsigned long garbage_pfn;
- /* which memory type (i.e. SMI, EBI1) this PMEM device is backed by */
- unsigned memory_type;
-
- char name[PMEM_NAME_SIZE];
-
- /* index of the garbage page in the pmem space */
- int garbage_index;
- /* reserved virtual address range */
- struct vm_struct *area;
-
- enum pmem_allocator_type allocator_type;
-
- int (*allocate)(const int,
- const unsigned long,
- const unsigned int);
- int (*free)(int, int);
- int (*free_space)(int, struct pmem_freespace *);
- unsigned long (*len)(int, struct pmem_data *);
- unsigned long (*start_addr)(int, struct pmem_data *);
-
- /* actual size of memory element, e.g.: (4 << 10) is 4K */
- unsigned int quantum;
-
- /* indicates maps of this region should be cached, if a mix of
- * cached and uncached is desired, set this and open the device with
- * O_SYNC to get an uncached region */
- unsigned cached;
- unsigned buffered;
- union {
- struct {
- /* in all_or_nothing allocator mode the first mapper
- * gets the whole space and sets this flag */
- unsigned allocated;
- } all_or_nothing;
-
- struct {
- /* the buddy allocator bitmap for the region
- * indicating which entries are allocated and which
- * are free.
- */
-
- struct pmem_bits *buddy_bitmap;
- } buddy_bestfit;
-
- struct {
- unsigned int bitmap_free; /* # of zero bits/quanta */
- uint32_t *bitmap;
- int32_t bitmap_allocs;
- struct {
- short bit;
- unsigned short quanta;
- } *bitm_alloc;
- } bitmap;
-
- struct {
- unsigned long used; /* Bytes currently allocated */
- struct list_head alist; /* List of allocations */
- } system_mem;
- } allocator;
-
- int id;
- struct kobject kobj;
-
- /* for debugging, creates a list of pmem file structs, the
- * data_list_mutex should be taken before pmem_data->sem if both are
- * needed */
- struct mutex data_list_mutex;
- struct list_head data_list;
- /* arena_mutex protects the global allocation arena
- *
- * IF YOU TAKE BOTH LOCKS TAKE THEM IN THIS ORDER:
- * down(pmem_data->sem) => mutex_lock(arena_mutex)
- */
- struct mutex arena_mutex;
-
- long (*ioctl)(struct file *, unsigned int, unsigned long);
- int (*release)(struct inode *, struct file *);
- /* reference count of allocations */
- atomic_t allocation_cnt;
- /*
- * request function for a region when the allocation count goes
- * from 0 -> 1
- */
- int (*mem_request)(void *);
- /*
- * release function for a region when the allocation count goes
- * from 1 -> 0
- */
- int (*mem_release)(void *);
- /*
- * private data for the request/release callback
- */
- void *region_data;
- /*
- * map and unmap as needed
- */
- int map_on_demand;
- /*
- * memory will be reused through fmem
- */
- int reusable;
-};
-#define to_pmem_info_id(a) (container_of(a, struct pmem_info, kobj)->id)
-
-static void ioremap_pmem(int id);
-static void pmem_put_region(int id);
-static int pmem_get_region(int id);
-
-static struct pmem_info pmem[PMEM_MAX_DEVICES];
-static int id_count;
-
-#define PMEM_SYSFS_DIR_NAME "pmem_regions" /* under /sys/kernel/ */
-static struct kset *pmem_kset;
-
-#define PMEM_IS_FREE_BUDDY(id, index) \
- (!(pmem[id].allocator.buddy_bestfit.buddy_bitmap[index].allocated))
-#define PMEM_BUDDY_ORDER(id, index) \
- (pmem[id].allocator.buddy_bestfit.buddy_bitmap[index].order)
-#define PMEM_BUDDY_INDEX(id, index) \
- (index ^ (1 << PMEM_BUDDY_ORDER(id, index)))
-#define PMEM_BUDDY_NEXT_INDEX(id, index) \
- (index + (1 << PMEM_BUDDY_ORDER(id, index)))
-#define PMEM_OFFSET(index) (index * pmem[id].quantum)
-#define PMEM_START_ADDR(id, index) \
- (PMEM_OFFSET(index) + pmem[id].base)
-#define PMEM_BUDDY_LEN(id, index) \
- ((1 << PMEM_BUDDY_ORDER(id, index)) * pmem[id].quantum)
-#define PMEM_END_ADDR(id, index) \
- (PMEM_START_ADDR(id, index) + PMEM_LEN(id, index))
-#define PMEM_START_VADDR(id, index) \
- (PMEM_OFFSET(id, index) + pmem[id].vbase)
-#define PMEM_END_VADDR(id, index) \
- (PMEM_START_VADDR(id, index) + PMEM_LEN(id, index))
-#define PMEM_REVOKED(data) (data->flags & PMEM_FLAGS_REVOKED)
-#define PMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK)))
-#define PMEM_IS_SUBMAP(data) \
- ((data->flags & PMEM_FLAGS_SUBMAP) && \
- (!(data->flags & PMEM_FLAGS_UNSUBMAP)))
-
-static int pmem_release(struct inode *, struct file *);
-static int pmem_mmap(struct file *, struct vm_area_struct *);
-static int pmem_open(struct inode *, struct file *);
-static long pmem_ioctl(struct file *, unsigned int, unsigned long);
-
-struct file_operations pmem_fops = {
- .release = pmem_release,
- .mmap = pmem_mmap,
- .open = pmem_open,
- .unlocked_ioctl = pmem_ioctl,
-};
-
-#define PMEM_ATTR(_name, _mode, _show, _store) { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
-}
-
-struct pmem_attr {
- struct attribute attr;
- ssize_t(*show) (const int id, char * const);
- ssize_t(*store) (const int id, const char * const, const size_t count);
-};
-#define to_pmem_attr(a) container_of(a, struct pmem_attr, attr)
-
-#define RW_PMEM_ATTR(name) \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IRUGO | S_IWUSR, show_pmem_## name, store_pmem_## name)
-
-#define RO_PMEM_ATTR(name) \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IRUGO, show_pmem_## name, NULL)
-
-#define WO_PMEM_ATTR(name) \
-static struct pmem_attr pmem_attr_## name = \
- PMEM_ATTR(name, S_IWUSR, NULL, store_pmem_## name)
-
-static ssize_t show_pmem(struct kobject *kobj,
- struct attribute *attr,
- char *buf)
-{
- struct pmem_attr *a = to_pmem_attr(attr);
- return a->show ? a->show(to_pmem_info_id(kobj), buf) : -EIO;
-}
-
-static ssize_t store_pmem(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- struct pmem_attr *a = to_pmem_attr(attr);
- return a->store ? a->store(to_pmem_info_id(kobj), buf, count) : -EIO;
-}
-
-static struct sysfs_ops pmem_ops = {
- .show = show_pmem,
- .store = store_pmem,
-};
-
-static ssize_t show_pmem_base(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%lu(%#lx)\n",
- pmem[id].base, pmem[id].base);
-}
-RO_PMEM_ATTR(base);
-
-static ssize_t show_pmem_size(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%lu(%#lx)\n",
- pmem[id].size, pmem[id].size);
-}
-RO_PMEM_ATTR(size);
-
-static ssize_t show_pmem_allocator_type(int id, char *buf)
-{
- switch (pmem[id].allocator_type) {
- case PMEM_ALLOCATORTYPE_ALLORNOTHING:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "All or Nothing");
- case PMEM_ALLOCATORTYPE_BUDDYBESTFIT:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "Buddy Bestfit");
- case PMEM_ALLOCATORTYPE_BITMAP:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "Bitmap");
- case PMEM_ALLOCATORTYPE_SYSTEM:
- return scnprintf(buf, PAGE_SIZE, "%s\n", "System heap");
- default:
- return scnprintf(buf, PAGE_SIZE,
- "??? Invalid allocator type (%d) for this region! "
- "Something isn't right.\n",
- pmem[id].allocator_type);
- }
-}
-RO_PMEM_ATTR(allocator_type);
-
-static ssize_t show_pmem_mapped_regions(int id, char *buf)
-{
- struct list_head *elt;
- int ret;
-
- ret = scnprintf(buf, PAGE_SIZE,
- "pid #: mapped regions (offset, len) (offset,len)...\n");
-
- mutex_lock(&pmem[id].data_list_mutex);
- list_for_each(elt, &pmem[id].data_list) {
- struct pmem_data *data =
- list_entry(elt, struct pmem_data, list);
- struct list_head *elt2;
-
- down_read(&data->sem);
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "pid %u:",
- data->pid);
- list_for_each(elt2, &data->region_list) {
- struct pmem_region_node *region_node = list_entry(elt2,
- struct pmem_region_node,
- list);
- ret += scnprintf(buf + ret, PAGE_SIZE - ret,
- "(%lx,%lx) ",
- region_node->region.offset,
- region_node->region.len);
- }
- up_read(&data->sem);
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
- }
- mutex_unlock(&pmem[id].data_list_mutex);
- return ret;
-}
-RO_PMEM_ATTR(mapped_regions);
-
-#define PMEM_COMMON_SYSFS_ATTRS \
- &pmem_attr_base.attr, \
- &pmem_attr_size.attr, \
- &pmem_attr_allocator_type.attr, \
- &pmem_attr_mapped_regions.attr
-
-
-static ssize_t show_pmem_allocated(int id, char *buf)
-{
- ssize_t ret;
-
- mutex_lock(&pmem[id].arena_mutex);
- ret = scnprintf(buf, PAGE_SIZE, "%s\n",
- pmem[id].allocator.all_or_nothing.allocated ?
- "is allocated" : "is NOT allocated");
- mutex_unlock(&pmem[id].arena_mutex);
- return ret;
-}
-RO_PMEM_ATTR(allocated);
-
-static struct attribute *pmem_allornothing_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- &pmem_attr_allocated.attr,
-
- NULL
-};
-
-static struct kobj_type pmem_allornothing_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_allornothing_attrs,
-};
-
-static ssize_t show_pmem_total_entries(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%lu\n", pmem[id].num_entries);
-}
-RO_PMEM_ATTR(total_entries);
-
-static ssize_t show_pmem_quantum_size(int id, char *buf)
-{
- return scnprintf(buf, PAGE_SIZE, "%u (%#x)\n",
- pmem[id].quantum, pmem[id].quantum);
-}
-RO_PMEM_ATTR(quantum_size);
-
-static ssize_t show_pmem_buddy_bitmap_dump(int id, char *buf)
-{
- int ret, i;
-
- mutex_lock(&pmem[id].data_list_mutex);
- ret = scnprintf(buf, PAGE_SIZE, "index\torder\tlength\tallocated\n");
-
- for (i = 0; i < pmem[id].num_entries && (PAGE_SIZE - ret);
- i = PMEM_BUDDY_NEXT_INDEX(id, i))
- ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d\t%d\t%d\t%d\n",
- i, PMEM_BUDDY_ORDER(id, i),
- PMEM_BUDDY_LEN(id, i),
- !PMEM_IS_FREE_BUDDY(id, i));
-
- mutex_unlock(&pmem[id].data_list_mutex);
- return ret;
-}
-RO_PMEM_ATTR(buddy_bitmap_dump);
-
-#define PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS \
- &pmem_attr_quantum_size.attr, \
- &pmem_attr_total_entries.attr
-
-static struct attribute *pmem_buddy_bestfit_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS,
-
- &pmem_attr_buddy_bitmap_dump.attr,
-
- NULL
-};
-
-static struct kobj_type pmem_buddy_bestfit_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_buddy_bestfit_attrs,
-};
-
-static ssize_t show_pmem_free_quanta(int id, char *buf)
-{
- ssize_t ret;
-
- mutex_lock(&pmem[id].arena_mutex);
- ret = scnprintf(buf, PAGE_SIZE, "%u\n",
- pmem[id].allocator.bitmap.bitmap_free);
- mutex_unlock(&pmem[id].arena_mutex);
- return ret;
-}
-RO_PMEM_ATTR(free_quanta);
-
-static ssize_t show_pmem_bits_allocated(int id, char *buf)
-{
- ssize_t ret;
- unsigned int i;
-
- mutex_lock(&pmem[id].arena_mutex);
-
- ret = scnprintf(buf, PAGE_SIZE,
- "id: %d\nbitnum\tindex\tquanta allocated\n", id);
-
- for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++)
- if (pmem[id].allocator.bitmap.bitm_alloc[i].bit != -1)
- ret += scnprintf(buf + ret, PAGE_SIZE - ret,
- "%u\t%u\t%u\n",
- i,
- pmem[id].allocator.bitmap.bitm_alloc[i].bit,
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta
- );
-
- mutex_unlock(&pmem[id].arena_mutex);
- return ret;
-}
-RO_PMEM_ATTR(bits_allocated);
-
-static struct attribute *pmem_bitmap_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- PMEM_BITMAP_BUDDY_BESTFIT_COMMON_SYSFS_ATTRS,
-
- &pmem_attr_free_quanta.attr,
- &pmem_attr_bits_allocated.attr,
-
- NULL
-};
-
-static struct attribute *pmem_system_attrs[] = {
- PMEM_COMMON_SYSFS_ATTRS,
-
- NULL
-};
-
-static struct kobj_type pmem_bitmap_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_bitmap_attrs,
-};
-
-static struct kobj_type pmem_system_ktype = {
- .sysfs_ops = &pmem_ops,
- .default_attrs = pmem_system_attrs,
-};
-
-static int pmem_allocate_from_id(const int id, const unsigned long size,
- const unsigned int align)
-{
- int ret;
- ret = pmem_get_region(id);
-
- if (ret)
- return -1;
-
- ret = pmem[id].allocate(id, size, align);
-
- if (ret < 0)
- pmem_put_region(id);
-
- return ret;
-}
-
-static int pmem_free_from_id(const int id, const int index)
-{
- pmem_put_region(id);
- return pmem[id].free(id, index);
-}
-
-static int pmem_get_region(int id)
-{
- /* Must be called with arena mutex locked */
- atomic_inc(&pmem[id].allocation_cnt);
- if (!pmem[id].vbase) {
- DLOG("PMEMDEBUG: mapping for %s", pmem[id].name);
- if (pmem[id].mem_request) {
- int ret = pmem[id].mem_request(pmem[id].region_data);
- if (ret) {
- atomic_dec(&pmem[id].allocation_cnt);
- return 1;
- }
- }
- ioremap_pmem(id);
- }
-
- if (pmem[id].vbase) {
- return 0;
- } else {
- if (pmem[id].mem_release)
- pmem[id].mem_release(pmem[id].region_data);
- atomic_dec(&pmem[id].allocation_cnt);
- return 1;
- }
-}
-
-static void pmem_put_region(int id)
-{
- /* Must be called with arena mutex locked */
- if (atomic_dec_and_test(&pmem[id].allocation_cnt)) {
- DLOG("PMEMDEBUG: unmapping for %s", pmem[id].name);
- BUG_ON(!pmem[id].vbase);
- if (pmem[id].map_on_demand) {
- /* unmap_kernel_range() flushes the caches
- * and removes the page table entries
- */
- unmap_kernel_range((unsigned long)pmem[id].vbase,
- pmem[id].size);
- pmem[id].vbase = NULL;
- if (pmem[id].mem_release) {
- int ret = pmem[id].mem_release(
- pmem[id].region_data);
- WARN(ret, "mem_release failed");
- }
-
- }
- }
-}
-
-static int get_id(struct file *file)
-{
- return MINOR(file->f_dentry->d_inode->i_rdev);
-}
-
-static char *get_name(struct file *file)
-{
- int id = get_id(file);
- return pmem[id].name;
-}
-
-static int is_pmem_file(struct file *file)
-{
- int id;
-
- if (unlikely(!file || !file->f_dentry || !file->f_dentry->d_inode))
- return 0;
-
- id = get_id(file);
- return (unlikely(id >= PMEM_MAX_DEVICES ||
- file->f_dentry->d_inode->i_rdev !=
- MKDEV(MISC_MAJOR, pmem[id].dev.minor))) ? 0 : 1;
-}
-
-static int has_allocation(struct file *file)
-{
- /* must be called with at least read lock held on
- * ((struct pmem_data *)(file->private_data))->sem which
- * means that file is guaranteed not to be NULL upon entry!!
- * check is_pmem_file first if not accessed via pmem_file_ops */
- struct pmem_data *pdata = file->private_data;
- return pdata && pdata->index != -1;
-}
-
-static int is_master_owner(struct file *file)
-{
- struct file *master_file;
- struct pmem_data *data = file->private_data;
- int put_needed, ret = 0;
-
- if (!has_allocation(file))
- return 0;
- if (PMEM_FLAGS_MASTERMAP & data->flags)
- return 1;
- master_file = fget_light(data->master_fd, &put_needed);
- if (master_file && data->master_file == master_file)
- ret = 1;
- if (master_file)
- fput_light(master_file, put_needed);
- return ret;
-}
-
-static int pmem_free_all_or_nothing(int id, int index)
-{
- /* caller should hold the lock on arena_mutex! */
- DLOG("index %d\n", index);
-
- pmem[id].allocator.all_or_nothing.allocated = 0;
- return 0;
-}
-
-static int pmem_free_space_all_or_nothing(int id,
- struct pmem_freespace *fs)
-{
- /* caller should hold the lock on arena_mutex! */
- fs->total = (unsigned long)
- pmem[id].allocator.all_or_nothing.allocated == 0 ?
- pmem[id].size : 0;
-
- fs->largest = fs->total;
- return 0;
-}
-
-
-static int pmem_free_buddy_bestfit(int id, int index)
-{
- /* caller should hold the lock on arena_mutex! */
- int curr = index;
- DLOG("index %d\n", index);
-
-
- /* clean up the bitmap, merging any buddies */
- pmem[id].allocator.buddy_bestfit.buddy_bitmap[curr].allocated = 0;
- /* find a slots buddy Buddy# = Slot# ^ (1 << order)
- * if the buddy is also free merge them
- * repeat until the buddy is not free or end of the bitmap is reached
- */
- do {
- int buddy = PMEM_BUDDY_INDEX(id, curr);
- if (buddy < pmem[id].num_entries &&
- PMEM_IS_FREE_BUDDY(id, buddy) &&
- PMEM_BUDDY_ORDER(id, buddy) ==
- PMEM_BUDDY_ORDER(id, curr)) {
- PMEM_BUDDY_ORDER(id, buddy)++;
- PMEM_BUDDY_ORDER(id, curr)++;
- curr = min(buddy, curr);
- } else {
- break;
- }
- } while (curr < pmem[id].num_entries);
-
- return 0;
-}
-
-
-static int pmem_free_space_buddy_bestfit(int id,
- struct pmem_freespace *fs)
-{
- /* caller should hold the lock on arena_mutex! */
- int curr;
- unsigned long size;
- fs->total = 0;
- fs->largest = 0;
-
- for (curr = 0; curr < pmem[id].num_entries;
- curr = PMEM_BUDDY_NEXT_INDEX(id, curr)) {
- if (PMEM_IS_FREE_BUDDY(id, curr)) {
- size = PMEM_BUDDY_LEN(id, curr);
- if (size > fs->largest)
- fs->largest = size;
- fs->total += size;
- }
- }
- return 0;
-}
-
-
-static inline uint32_t start_mask(int bit_start)
-{
- return (uint32_t)(~0) << (bit_start & PMEM_BITS_PER_WORD_MASK);
-}
-
-static inline uint32_t end_mask(int bit_end)
-{
- return (uint32_t)(~0) >>
- ((BITS_PER_LONG - bit_end) & PMEM_BITS_PER_WORD_MASK);
-}
-
-static inline int compute_total_words(int bit_end, int word_index)
-{
- return ((bit_end + BITS_PER_LONG - 1) >>
- PMEM_32BIT_WORD_ORDER) - word_index;
-}
-
-static void bitmap_bits_clear_all(uint32_t *bitp, int bit_start, int bit_end)
-{
- int word_index = bit_start >> PMEM_32BIT_WORD_ORDER, total_words;
-
- total_words = compute_total_words(bit_end, word_index);
- if (total_words > 0) {
- if (total_words == 1) {
- bitp[word_index] &=
- ~(start_mask(bit_start) & end_mask(bit_end));
- } else {
- bitp[word_index++] &= ~start_mask(bit_start);
- if (total_words > 2) {
- int total_bytes;
-
- total_words -= 2;
- total_bytes = total_words << 2;
-
- memset(&bitp[word_index], 0, total_bytes);
- word_index += total_words;
- }
- bitp[word_index] &= ~end_mask(bit_end);
- }
- }
-}
-
-static int pmem_free_bitmap(int id, int bitnum)
-{
- /* caller should hold the lock on arena_mutex! */
- int i;
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-
- DLOG("bitnum %d\n", bitnum);
-
- for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++) {
- const int curr_bit =
- pmem[id].allocator.bitmap.bitm_alloc[i].bit;
-
- if (curr_bit == bitnum) {
- const int curr_quanta =
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta;
-
- bitmap_bits_clear_all(pmem[id].allocator.bitmap.bitmap,
- curr_bit, curr_bit + curr_quanta);
- pmem[id].allocator.bitmap.bitmap_free += curr_quanta;
- pmem[id].allocator.bitmap.bitm_alloc[i].bit = -1;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
- return 0;
- }
- }
- printk(KERN_ALERT "pmem: %s: Attempt to free unallocated index %d, id"
- " %d, pid %d(%s)\n", __func__, bitnum, id, current->pid,
- get_task_comm(currtask_name, current));
-
- return -1;
-}
-
-static int pmem_free_system(int id, int index)
-{
- /* caller should hold the lock on arena_mutex! */
- struct alloc_list *item;
-
- DLOG("index %d\n", index);
- if (index != 0)
- item = (struct alloc_list *)index;
- else
- return 0;
-
- if (item->vaddr != NULL) {
- iounmap(item->vaddr);
- kfree(__va(item->addr));
- list_del(&item->allocs);
- kfree(item);
- }
-
- return 0;
-}
-
-static int pmem_free_space_bitmap(int id, struct pmem_freespace *fs)
-{
- int i, j;
- int max_allocs = pmem[id].allocator.bitmap.bitmap_allocs;
- int alloc_start = 0;
- int next_alloc;
- unsigned long size = 0;
-
- fs->total = 0;
- fs->largest = 0;
-
- for (i = 0; i < max_allocs; i++) {
-
- int alloc_quanta = 0;
- int alloc_idx = 0;
- next_alloc = pmem[id].num_entries;
-
- /* Look for the lowest bit where next allocation starts */
- for (j = 0; j < max_allocs; j++) {
- const int curr_alloc = pmem[id].allocator.
- bitmap.bitm_alloc[j].bit;
- if (curr_alloc != -1) {
- if (alloc_start == curr_alloc)
- alloc_idx = j;
- if (alloc_start >= curr_alloc)
- continue;
- if (curr_alloc < next_alloc)
- next_alloc = curr_alloc;
- }
- }
- alloc_quanta = pmem[id].allocator.bitmap.
- bitm_alloc[alloc_idx].quanta;
- size = (next_alloc - (alloc_start + alloc_quanta)) *
- pmem[id].quantum;
-
- if (size > fs->largest)
- fs->largest = size;
- fs->total += size;
-
- if (next_alloc == pmem[id].num_entries)
- break;
- else
- alloc_start = next_alloc;
- }
-
- return 0;
-}
-
-static int pmem_free_space_system(int id, struct pmem_freespace *fs)
-{
- fs->total = pmem[id].size;
- fs->largest = pmem[id].size;
-
- return 0;
-}
-
-static void pmem_revoke(struct file *file, struct pmem_data *data);
-
-static int pmem_release(struct inode *inode, struct file *file)
-{
- struct pmem_data *data = file->private_data;
- struct pmem_region_node *region_node;
- struct list_head *elt, *elt2;
- int id = get_id(file), ret = 0;
-
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("releasing memory pid %u(%s) file %p(%ld) dev %s(id: %d)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), get_name(file), id);
- mutex_lock(&pmem[id].data_list_mutex);
- /* if this file is a master, revoke all the memory in the connected
- * files */
- if (PMEM_FLAGS_MASTERMAP & data->flags) {
- list_for_each(elt, &pmem[id].data_list) {
- struct pmem_data *sub_data =
- list_entry(elt, struct pmem_data, list);
- int is_master;
-
- down_read(&sub_data->sem);
- is_master = (PMEM_IS_SUBMAP(sub_data) &&
- file == sub_data->master_file);
- up_read(&sub_data->sem);
-
- if (is_master)
- pmem_revoke(file, sub_data);
- }
- }
- list_del(&data->list);
- mutex_unlock(&pmem[id].data_list_mutex);
-
- down_write(&data->sem);
-
- /* if it is not a connected file and it has an allocation, free it */
- if (!(PMEM_FLAGS_CONNECTED & data->flags) && has_allocation(file)) {
- mutex_lock(&pmem[id].arena_mutex);
- ret = pmem_free_from_id(id, data->index);
- mutex_unlock(&pmem[id].arena_mutex);
- }
-
- /* if this file is a submap (mapped, connected file), downref the
- * task struct */
- if (PMEM_FLAGS_SUBMAP & data->flags)
- if (data->task) {
- put_task_struct(data->task);
- data->task = NULL;
- }
-
- file->private_data = NULL;
-
- list_for_each_safe(elt, elt2, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node, list);
- list_del(elt);
- kfree(region_node);
- }
- BUG_ON(!list_empty(&data->region_list));
-
- up_write(&data->sem);
- kfree(data);
- if (pmem[id].release)
- ret = pmem[id].release(inode, file);
-
- return ret;
-}
-
-static int pmem_open(struct inode *inode, struct file *file)
-{
- struct pmem_data *data;
- int id = get_id(file);
- int ret = 0;
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
- DLOG("pid %u(%s) file %p(%ld) dev %s(id: %d)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), get_name(file), id);
- data = kmalloc(sizeof(struct pmem_data), GFP_KERNEL);
- if (!data) {
- printk(KERN_ALERT "pmem: %s: unable to allocate memory for "
- "pmem metadata.", __func__);
- return -1;
- }
- data->flags = 0;
- data->index = -1;
- data->task = NULL;
- data->vma = NULL;
- data->pid = 0;
- data->master_file = NULL;
-#if PMEM_DEBUG
- data->ref = 0;
-#endif
- INIT_LIST_HEAD(&data->region_list);
- init_rwsem(&data->sem);
-
- file->private_data = data;
- INIT_LIST_HEAD(&data->list);
-
- mutex_lock(&pmem[id].data_list_mutex);
- list_add(&data->list, &pmem[id].data_list);
- mutex_unlock(&pmem[id].data_list_mutex);
- return ret;
-}
-
-static unsigned long pmem_order(unsigned long len, int id)
-{
- int i;
-
- len = (len + pmem[id].quantum - 1)/pmem[id].quantum;
- len--;
- for (i = 0; i < sizeof(len)*8; i++)
- if (len >> i == 0)
- break;
- return i;
-}
-
-static int pmem_allocator_all_or_nothing(const int id,
- const unsigned long len,
- const unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- DLOG("all or nothing\n");
- if ((len > pmem[id].size) ||
- pmem[id].allocator.all_or_nothing.allocated)
- return -1;
- pmem[id].allocator.all_or_nothing.allocated = 1;
- return len;
-}
-
-static int pmem_allocator_buddy_bestfit(const int id,
- const unsigned long len,
- unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- int curr;
- int best_fit = -1;
- unsigned long order;
-
- DLOG("buddy bestfit\n");
- order = pmem_order(len, id);
- if (order > PMEM_MAX_ORDER)
- goto out;
-
- DLOG("order %lx\n", order);
-
- /* Look through the bitmap.
- * If a free slot of the correct order is found, use it.
- * Otherwise, use the best fit (smallest with size > order) slot.
- */
- for (curr = 0;
- curr < pmem[id].num_entries;
- curr = PMEM_BUDDY_NEXT_INDEX(id, curr))
- if (PMEM_IS_FREE_BUDDY(id, curr)) {
- if (PMEM_BUDDY_ORDER(id, curr) ==
- (unsigned char)order) {
- /* set the not free bit and clear others */
- best_fit = curr;
- break;
- }
- if (PMEM_BUDDY_ORDER(id, curr) >
- (unsigned char)order &&
- (best_fit < 0 ||
- PMEM_BUDDY_ORDER(id, curr) <
- PMEM_BUDDY_ORDER(id, best_fit)))
- best_fit = curr;
- }
-
- /* if best_fit < 0, there are no suitable slots; return an error */
- if (best_fit < 0) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: %s: no space left to allocate!\n",
- __func__);
-#endif
- goto out;
- }
-
- /* now partition the best fit:
- * split the slot into 2 buddies of order - 1
- * repeat until the slot is of the correct order
- */
- while (PMEM_BUDDY_ORDER(id, best_fit) > (unsigned char)order) {
- int buddy;
- PMEM_BUDDY_ORDER(id, best_fit) -= 1;
- buddy = PMEM_BUDDY_INDEX(id, best_fit);
- PMEM_BUDDY_ORDER(id, buddy) = PMEM_BUDDY_ORDER(id, best_fit);
- }
- pmem[id].allocator.buddy_bestfit.buddy_bitmap[best_fit].allocated = 1;
-out:
- return best_fit;
-}
-
-
-static inline unsigned long paddr_from_bit(const int id, const int bitnum)
-{
- return pmem[id].base + pmem[id].quantum * bitnum;
-}
-
-static inline unsigned long bit_from_paddr(const int id,
- const unsigned long paddr)
-{
- return (paddr - pmem[id].base) / pmem[id].quantum;
-}
-
-static void bitmap_bits_set_all(uint32_t *bitp, int bit_start, int bit_end)
-{
- int word_index = bit_start >> PMEM_32BIT_WORD_ORDER, total_words;
-
- total_words = compute_total_words(bit_end, word_index);
- if (total_words > 0) {
- if (total_words == 1) {
- bitp[word_index] |=
- (start_mask(bit_start) & end_mask(bit_end));
- } else {
- bitp[word_index++] |= start_mask(bit_start);
- if (total_words > 2) {
- int total_bytes;
-
- total_words -= 2;
- total_bytes = total_words << 2;
-
- memset(&bitp[word_index], ~0, total_bytes);
- word_index += total_words;
- }
- bitp[word_index] |= end_mask(bit_end);
- }
- }
-}
-
-static int
-bitmap_allocate_contiguous(uint32_t *bitp, int num_bits_to_alloc,
- int total_bits, int spacing, int start_bit)
-{
- int bit_start, last_bit, word_index;
-
- if (num_bits_to_alloc <= 0)
- return -1;
-
- for (bit_start = start_bit; ;
- bit_start = ((last_bit +
- (word_index << PMEM_32BIT_WORD_ORDER) + spacing - 1)
- & ~(spacing - 1)) + start_bit) {
- int bit_end = bit_start + num_bits_to_alloc, total_words;
-
- if (bit_end > total_bits)
- return -1; /* out of contiguous memory */
-
- word_index = bit_start >> PMEM_32BIT_WORD_ORDER;
- total_words = compute_total_words(bit_end, word_index);
-
- if (total_words <= 0)
- return -1;
-
- if (total_words == 1) {
- last_bit = fls(bitp[word_index] &
- (start_mask(bit_start) &
- end_mask(bit_end)));
- if (last_bit)
- continue;
- } else {
- int end_word = word_index + (total_words - 1);
- last_bit =
- fls(bitp[word_index] & start_mask(bit_start));
- if (last_bit)
- continue;
-
- for (word_index++;
- word_index < end_word;
- word_index++) {
- last_bit = fls(bitp[word_index]);
- if (last_bit)
- break;
- }
- if (last_bit)
- continue;
-
- last_bit = fls(bitp[word_index] & end_mask(bit_end));
- if (last_bit)
- continue;
- }
- bitmap_bits_set_all(bitp, bit_start, bit_end);
- return bit_start;
- }
- return -1;
-}
-
-static int reserve_quanta(const unsigned int quanta_needed,
- const int id,
- unsigned int align)
-{
- /* alignment should be a valid power of 2 */
- int ret = -1, start_bit = 0, spacing = 1;
-
- /* Sanity check */
- if (quanta_needed > pmem[id].allocator.bitmap.bitmap_free) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: %s: request (%d) too big for"
- " available free (%d)\n", __func__, quanta_needed,
- pmem[id].allocator.bitmap.bitmap_free);
-#endif
- return -1;
- }
-
- start_bit = bit_from_paddr(id,
- (pmem[id].base + align - 1) & ~(align - 1));
- if (start_bit <= -1) {
-#if PMEM_DEBUG
- printk(KERN_ALERT
- "pmem: %s: bit_from_paddr fails for"
- " %u alignment.\n", __func__, align);
-#endif
- return -1;
- }
- spacing = align / pmem[id].quantum;
- spacing = spacing > 1 ? spacing : 1;
-
- ret = bitmap_allocate_contiguous(pmem[id].allocator.bitmap.bitmap,
- quanta_needed,
- (pmem[id].size + pmem[id].quantum - 1) / pmem[id].quantum,
- spacing,
- start_bit);
-
-#if PMEM_DEBUG
- if (ret < 0)
- printk(KERN_ALERT "pmem: %s: not enough contiguous bits free "
- "in bitmap! Region memory is either too fragmented or"
- " request is too large for available memory.\n",
- __func__);
-#endif
-
- return ret;
-}
-
-static int pmem_allocator_bitmap(const int id,
- const unsigned long len,
- const unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- int bitnum, i;
- unsigned int quanta_needed;
-
- DLOG("bitmap id %d, len %ld, align %u\n", id, len, align);
- if (!pmem[id].allocator.bitmap.bitm_alloc) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: bitm_alloc not present! id: %d\n",
- id);
-#endif
- return -1;
- }
-
- quanta_needed = (len + pmem[id].quantum - 1) / pmem[id].quantum;
- DLOG("quantum size %u quanta needed %u free %u id %d\n",
- pmem[id].quantum, quanta_needed,
- pmem[id].allocator.bitmap.bitmap_free, id);
-
- if (pmem[id].allocator.bitmap.bitmap_free < quanta_needed) {
-#if PMEM_DEBUG
- printk(KERN_ALERT "pmem: memory allocation failure. "
- "PMEM memory region exhausted, id %d."
- " Unable to comply with allocation request.\n", id);
-#endif
- return -1;
- }
-
- bitnum = reserve_quanta(quanta_needed, id, align);
- if (bitnum == -1)
- goto leave;
-
- for (i = 0;
- i < pmem[id].allocator.bitmap.bitmap_allocs &&
- pmem[id].allocator.bitmap.bitm_alloc[i].bit != -1;
- i++)
- ;
-
- if (i >= pmem[id].allocator.bitmap.bitmap_allocs) {
- void *temp;
- int32_t new_bitmap_allocs =
- pmem[id].allocator.bitmap.bitmap_allocs << 1;
- int j;
-
- if (!new_bitmap_allocs) { /* failed sanity check!! */
-#if PMEM_DEBUG
- pr_alert("pmem: bitmap_allocs number"
- " wrapped around to zero! Something "
- "is VERY wrong.\n");
-#endif
- return -1;
- }
-
- if (new_bitmap_allocs > pmem[id].num_entries) {
- /* failed sanity check!! */
-#if PMEM_DEBUG
- pr_alert("pmem: required bitmap_allocs"
- " number exceeds maximum entries possible"
- " for current quanta\n");
-#endif
- return -1;
- }
-
- temp = krealloc(pmem[id].allocator.bitmap.bitm_alloc,
- new_bitmap_allocs *
- sizeof(*pmem[id].allocator.bitmap.bitm_alloc),
- GFP_KERNEL);
- if (!temp) {
-#if PMEM_DEBUG
- pr_alert("pmem: can't realloc bitmap_allocs,"
- "id %d, current num bitmap allocs %d\n",
- id, pmem[id].allocator.bitmap.bitmap_allocs);
-#endif
- return -1;
- }
- pmem[id].allocator.bitmap.bitmap_allocs = new_bitmap_allocs;
- pmem[id].allocator.bitmap.bitm_alloc = temp;
-
- for (j = i; j < new_bitmap_allocs; j++) {
- pmem[id].allocator.bitmap.bitm_alloc[j].bit = -1;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
- }
-
- DLOG("increased # of allocated regions to %d for id %d\n",
- pmem[id].allocator.bitmap.bitmap_allocs, id);
- }
-
- DLOG("bitnum %d, bitm_alloc index %d\n", bitnum, i);
-
- pmem[id].allocator.bitmap.bitmap_free -= quanta_needed;
- pmem[id].allocator.bitmap.bitm_alloc[i].bit = bitnum;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = quanta_needed;
-leave:
- return bitnum;
-}
-
-static int pmem_allocator_system(const int id,
- const unsigned long len,
- const unsigned int align)
-{
- /* caller should hold the lock on arena_mutex! */
- struct alloc_list *list;
- unsigned long aligned_len;
- int count = SYSTEM_ALLOC_RETRY;
- void *buf;
-
- DLOG("system id %d, len %ld, align %u\n", id, len, align);
-
- if ((pmem[id].allocator.system_mem.used + len) > pmem[id].size) {
- DLOG("requested size would be larger than quota\n");
- return -1;
- }
-
- /* Handle alignment */
- aligned_len = len + align;
-
- /* Attempt allocation */
- list = kmalloc(sizeof(struct alloc_list), GFP_KERNEL);
- if (list == NULL) {
- printk(KERN_ERR "pmem: failed to allocate system metadata\n");
- return -1;
- }
- list->vaddr = NULL;
-
- buf = NULL;
- while ((buf == NULL) && count--) {
- buf = kmalloc((aligned_len), GFP_KERNEL);
- if (buf == NULL) {
- DLOG("pmem: kmalloc %d temporarily failed len= %ld\n",
- count, aligned_len);
- }
- }
- if (!buf) {
- printk(KERN_CRIT "pmem: kmalloc failed for id= %d len= %ld\n",
- id, aligned_len);
- kfree(list);
- return -1;
- }
- list->size = aligned_len;
- list->addr = (void *)__pa(buf);
- list->aaddr = (void *)(((unsigned int)(list->addr) + (align - 1)) &
- ~(align - 1));
-
- if (!pmem[id].cached)
- list->vaddr = ioremap(__pa(buf), aligned_len);
- else
- list->vaddr = ioremap_cached(__pa(buf), aligned_len);
-
- INIT_LIST_HEAD(&list->allocs);
- list_add(&list->allocs, &pmem[id].allocator.system_mem.alist);
-
- return (int)list;
-}
-
-static pgprot_t pmem_phys_mem_access_prot(struct file *file, pgprot_t vma_prot)
-{
- int id = get_id(file);
-#ifdef pgprot_writecombine
- if (pmem[id].cached == 0 || file->f_flags & O_SYNC)
- /* on ARMv6 and ARMv7 this expands to Normal Noncached */
- return pgprot_writecombine(vma_prot);
-#endif
-#ifdef pgprot_ext_buffered
- else if (pmem[id].buffered)
- return pgprot_ext_buffered(vma_prot);
-#endif
- return vma_prot;
-}
-
-static unsigned long pmem_start_addr_all_or_nothing(int id,
- struct pmem_data *data)
-{
- return PMEM_START_ADDR(id, 0);
-}
-
-static unsigned long pmem_start_addr_buddy_bestfit(int id,
- struct pmem_data *data)
-{
- return PMEM_START_ADDR(id, data->index);
-}
-
-static unsigned long pmem_start_addr_bitmap(int id, struct pmem_data *data)
-{
- return data->index * pmem[id].quantum + pmem[id].base;
-}
-
-static unsigned long pmem_start_addr_system(int id, struct pmem_data *data)
-{
- return (unsigned long)(((struct alloc_list *)(data->index))->aaddr);
-}
-
-static void *pmem_start_vaddr(int id, struct pmem_data *data)
-{
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_SYSTEM)
- return ((struct alloc_list *)(data->index))->vaddr;
- else
- return pmem[id].start_addr(id, data) - pmem[id].base + pmem[id].vbase;
-}
-
-static unsigned long pmem_len_all_or_nothing(int id, struct pmem_data *data)
-{
- return data->index;
-}
-
-static unsigned long pmem_len_buddy_bestfit(int id, struct pmem_data *data)
-{
- return PMEM_BUDDY_LEN(id, data->index);
-}
-
-static unsigned long pmem_len_bitmap(int id, struct pmem_data *data)
-{
- int i;
- unsigned long ret = 0;
-
- mutex_lock(&pmem[id].arena_mutex);
-
- for (i = 0; i < pmem[id].allocator.bitmap.bitmap_allocs; i++)
- if (pmem[id].allocator.bitmap.bitm_alloc[i].bit ==
- data->index) {
- ret = pmem[id].allocator.bitmap.bitm_alloc[i].quanta *
- pmem[id].quantum;
- break;
- }
-
- mutex_unlock(&pmem[id].arena_mutex);
-#if PMEM_DEBUG
- if (i >= pmem[id].allocator.bitmap.bitmap_allocs)
- pr_alert("pmem: %s: can't find bitnum %d in "
- "alloc'd array!\n", __func__, data->index);
-#endif
- return ret;
-}
-
-static unsigned long pmem_len_system(int id, struct pmem_data *data)
-{
- unsigned long ret = 0;
-
- mutex_lock(&pmem[id].arena_mutex);
-
- ret = ((struct alloc_list *)data->index)->size;
- mutex_unlock(&pmem[id].arena_mutex);
-
- return ret;
-}
-
-static int pmem_map_garbage(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- int i, garbage_pages = len >> PAGE_SHIFT;
-
- vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP | VM_SHARED | VM_WRITE;
- for (i = 0; i < garbage_pages; i++) {
- if (vm_insert_pfn(vma, vma->vm_start + offset + (i * PAGE_SIZE),
- pmem[id].garbage_pfn))
- return -EAGAIN;
- }
- return 0;
-}
-
-static int pmem_unmap_pfn_range(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- int garbage_pages;
- DLOG("unmap offset %lx len %lx\n", offset, len);
-
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(len));
-
- garbage_pages = len >> PAGE_SHIFT;
- zap_page_range(vma, vma->vm_start + offset, len, NULL);
- pmem_map_garbage(id, vma, data, offset, len);
- return 0;
-}
-
-static int pmem_map_pfn_range(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- int ret;
- DLOG("map offset %lx len %lx\n", offset, len);
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_start));
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_end));
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(len));
- BUG_ON(!PMEM_IS_PAGE_ALIGNED(offset));
-
- ret = io_remap_pfn_range(vma, vma->vm_start + offset,
- (pmem[id].start_addr(id, data) + offset) >> PAGE_SHIFT,
- len, vma->vm_page_prot);
- if (ret) {
-#if PMEM_DEBUG
- pr_alert("pmem: %s: io_remap_pfn_range fails with "
- "return value: %d!\n", __func__, ret);
-#endif
-
- ret = -EAGAIN;
- }
- return ret;
-}
-
-static int pmem_remap_pfn_range(int id, struct vm_area_struct *vma,
- struct pmem_data *data, unsigned long offset,
- unsigned long len)
-{
- /* hold the mm semp for the vma you are modifying when you call this */
- BUG_ON(!vma);
- zap_page_range(vma, vma->vm_start + offset, len, NULL);
- return pmem_map_pfn_range(id, vma, data, offset, len);
-}
-
-static void pmem_vma_open(struct vm_area_struct *vma)
-{
- struct file *file = vma->vm_file;
- struct pmem_data *data = file->private_data;
- int id = get_id(file);
-
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("Dev %s(id: %d) pid %u(%s) ppid %u file %p count %ld\n",
- get_name(file), id, current->pid,
- get_task_comm(currtask_name, current),
- current->parent->pid, file, file_count(file));
- /* this should never be called as we don't support copying pmem
- * ranges via fork */
- down_read(&data->sem);
- BUG_ON(!has_allocation(file));
- /* remap the garbage pages, forkers don't get access to the data */
- pmem_unmap_pfn_range(id, vma, data, 0, vma->vm_start - vma->vm_end);
- up_read(&data->sem);
-}
-
-static void pmem_vma_close(struct vm_area_struct *vma)
-{
- struct file *file = vma->vm_file;
- struct pmem_data *data = file->private_data;
-
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("Dev %s(id: %d) pid %u(%s) ppid %u file %p count %ld\n",
- get_name(file), get_id(file), current->pid,
- get_task_comm(currtask_name, current),
- current->parent->pid, file, file_count(file));
-
- if (unlikely(!is_pmem_file(file))) {
- pr_warning("pmem: something is very wrong, you are "
- "closing a vm backing an allocation that doesn't "
- "exist!\n");
- return;
- }
-
- down_write(&data->sem);
- if (unlikely(!has_allocation(file))) {
- up_write(&data->sem);
- pr_warning("pmem: something is very wrong, you are "
- "closing a vm backing an allocation that doesn't "
- "exist!\n");
- return;
- }
- if (data->vma == vma) {
- data->vma = NULL;
- if ((data->flags & PMEM_FLAGS_CONNECTED) &&
- (data->flags & PMEM_FLAGS_SUBMAP))
- data->flags |= PMEM_FLAGS_UNSUBMAP;
- }
- /* the kernel is going to free this vma now anyway */
- up_write(&data->sem);
-}
-
-static struct vm_operations_struct vm_ops = {
- .open = pmem_vma_open,
- .close = pmem_vma_close,
-};
-
-static int pmem_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct pmem_data *data = file->private_data;
- int index = -1;
- unsigned long vma_size = vma->vm_end - vma->vm_start;
- int ret = 0, id = get_id(file);
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
- if (!data) {
- pr_err("pmem: Invalid file descriptor, no private data\n");
- return -EINVAL;
- }
- DLOG("pid %u(%s) mmap vma_size %lu on dev %s(id: %d)\n", current->pid,
- get_task_comm(currtask_name, current), vma_size,
- get_name(file), id);
- if (vma->vm_pgoff || !PMEM_IS_PAGE_ALIGNED(vma_size)) {
-#if PMEM_DEBUG
- pr_err("pmem: mmaps must be at offset zero, aligned"
- " and a multiple of pages_size.\n");
-#endif
- return -EINVAL;
- }
-
- down_write(&data->sem);
- /* check this file isn't already mmaped, for submaps check this file
- * has never been mmaped */
- if ((data->flags & PMEM_FLAGS_SUBMAP) ||
- (data->flags & PMEM_FLAGS_UNSUBMAP)) {
-#if PMEM_DEBUG
- pr_err("pmem: you can only mmap a pmem file once, "
- "this file is already mmaped. %x\n", data->flags);
-#endif
- ret = -EINVAL;
- goto error;
- }
- /* if file->private_data == unalloced, alloc*/
- if (data->index == -1) {
- mutex_lock(&pmem[id].arena_mutex);
- index = pmem_allocate_from_id(id,
- vma->vm_end - vma->vm_start,
- SZ_4K);
- mutex_unlock(&pmem[id].arena_mutex);
- /* either no space was available or an error occured */
- if (index == -1) {
- pr_err("pmem: mmap unable to allocate memory"
- "on %s\n", get_name(file));
- ret = -ENOMEM;
- goto error;
- }
- /* store the index of a successful allocation */
- data->index = index;
- }
-
- if (pmem[id].len(id, data) < vma_size) {
-#if PMEM_DEBUG
- pr_err("pmem: mmap size [%lu] does not match"
- " size of backing region [%lu].\n", vma_size,
- pmem[id].len(id, data));
-#endif
- ret = -EINVAL;
- goto error;
- }
-
- vma->vm_pgoff = pmem[id].start_addr(id, data) >> PAGE_SHIFT;
-
- vma->vm_page_prot = pmem_phys_mem_access_prot(file, vma->vm_page_prot);
-
- if (data->flags & PMEM_FLAGS_CONNECTED) {
- struct pmem_region_node *region_node;
- struct list_head *elt;
- if (pmem_map_garbage(id, vma, data, 0, vma_size)) {
- pr_alert("pmem: mmap failed in kernel!\n");
- ret = -EAGAIN;
- goto error;
- }
- list_for_each(elt, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node,
- list);
- DLOG("remapping file: %p %lx %lx\n", file,
- region_node->region.offset,
- region_node->region.len);
- if (pmem_remap_pfn_range(id, vma, data,
- region_node->region.offset,
- region_node->region.len)) {
- ret = -EAGAIN;
- goto error;
- }
- }
- data->flags |= PMEM_FLAGS_SUBMAP;
- get_task_struct(current->group_leader);
- data->task = current->group_leader;
- data->vma = vma;
-#if PMEM_DEBUG
- data->pid = current->pid;
-#endif
- DLOG("submmapped file %p vma %p pid %u\n", file, vma,
- current->pid);
- } else {
- if (pmem_map_pfn_range(id, vma, data, 0, vma_size)) {
- pr_err("pmem: mmap failed in kernel!\n");
- ret = -EAGAIN;
- goto error;
- }
- data->flags |= PMEM_FLAGS_MASTERMAP;
- data->pid = current->pid;
- }
- vma->vm_ops = &vm_ops;
-error:
- up_write(&data->sem);
- return ret;
-}
-
-/* the following are the api for accessing pmem regions by other drivers
- * from inside the kernel */
-int get_pmem_user_addr(struct file *file, unsigned long *start,
- unsigned long *len)
-{
- int ret = -1;
-
- if (is_pmem_file(file)) {
- struct pmem_data *data = file->private_data;
-
- down_read(&data->sem);
- if (has_allocation(file)) {
- if (data->vma) {
- *start = data->vma->vm_start;
- *len = data->vma->vm_end - data->vma->vm_start;
- } else {
- *start = *len = 0;
-#if PMEM_DEBUG
- pr_err("pmem: %s: no vma present.\n",
- __func__);
-#endif
- }
- ret = 0;
- }
- up_read(&data->sem);
- }
-
-#if PMEM_DEBUG
- if (ret)
- pr_err("pmem: %s: requested pmem data from invalid"
- "file.\n", __func__);
-#endif
- return ret;
-}
-
-int get_pmem_addr(struct file *file, unsigned long *start,
- unsigned long *vstart, unsigned long *len)
-{
- int ret = -1;
-
- if (is_pmem_file(file)) {
- struct pmem_data *data = file->private_data;
-
- down_read(&data->sem);
- if (has_allocation(file)) {
- int id = get_id(file);
-
- *start = pmem[id].start_addr(id, data);
- *len = pmem[id].len(id, data);
- *vstart = (unsigned long)
- pmem_start_vaddr(id, data);
- up_read(&data->sem);
-#if PMEM_DEBUG
- down_write(&data->sem);
- data->ref++;
- up_write(&data->sem);
-#endif
- DLOG("returning start %#lx len %lu "
- "vstart %#lx\n",
- *start, *len, *vstart);
- ret = 0;
- } else {
- up_read(&data->sem);
- }
- }
- return ret;
-}
-
-int get_pmem_file(unsigned int fd, unsigned long *start, unsigned long *vstart,
- unsigned long *len, struct file **filp)
-{
- int ret = -1;
- struct file *file = fget(fd);
-
- if (unlikely(file == NULL)) {
- pr_err("pmem: %s: requested data from file "
- "descriptor that doesn't exist.\n", __func__);
- } else {
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("filp %p rdev %d pid %u(%s) file %p(%ld)"
- " dev %s(id: %d)\n", filp,
- file->f_dentry->d_inode->i_rdev,
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), get_name(file), get_id(file));
-
- if (!get_pmem_addr(file, start, vstart, len)) {
- if (filp)
- *filp = file;
- ret = 0;
- } else {
- fput(file);
- }
- }
- return ret;
-}
-EXPORT_SYMBOL(get_pmem_file);
-
-int get_pmem_fd(int fd, unsigned long *start, unsigned long *len)
-{
- unsigned long vstart;
- return get_pmem_file(fd, start, &vstart, len, NULL);
-}
-EXPORT_SYMBOL(get_pmem_fd);
-
-void put_pmem_file(struct file *file)
-{
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("rdev %d pid %u(%s) file %p(%ld)" " dev %s(id: %d)\n",
- file->f_dentry->d_inode->i_rdev, current->pid,
- get_task_comm(currtask_name, current), file,
- file_count(file), get_name(file), get_id(file));
- if (is_pmem_file(file)) {
-#if PMEM_DEBUG
- struct pmem_data *data = file->private_data;
-
- down_write(&data->sem);
- if (!data->ref--) {
- data->ref++;
- pr_alert("pmem: pmem_put > pmem_get %s "
- "(pid %d)\n",
- pmem[get_id(file)].dev.name, data->pid);
- BUG();
- }
- up_write(&data->sem);
-#endif
- fput(file);
- }
-}
-EXPORT_SYMBOL(put_pmem_file);
-
-void put_pmem_fd(int fd)
-{
- int put_needed;
- struct file *file = fget_light(fd, &put_needed);
-
- if (file) {
- put_pmem_file(file);
- fput_light(file, put_needed);
- }
-}
-
-void flush_pmem_fd(int fd, unsigned long offset, unsigned long len)
-{
- int fput_needed;
- struct file *file = fget_light(fd, &fput_needed);
-
- if (file) {
- flush_pmem_file(file, offset, len);
- fput_light(file, fput_needed);
- }
-}
-
-void flush_pmem_file(struct file *file, unsigned long offset, unsigned long len)
-{
- struct pmem_data *data;
- int id;
- void *vaddr;
- struct pmem_region_node *region_node;
- struct list_head *elt;
- void *flush_start, *flush_end;
-#ifdef CONFIG_OUTER_CACHE
- unsigned long phy_start, phy_end;
-#endif
- if (!is_pmem_file(file))
- return;
-
- id = get_id(file);
- if (!pmem[id].cached)
- return;
-
- /* is_pmem_file fails if !file */
- data = file->private_data;
-
- down_read(&data->sem);
- if (!has_allocation(file))
- goto end;
-
- vaddr = pmem_start_vaddr(id, data);
-
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_SYSTEM) {
- dmac_flush_range(vaddr,
- (void *)((unsigned long)vaddr +
- ((struct alloc_list *)(data->index))->size));
-#ifdef CONFIG_OUTER_CACHE
- phy_start = pmem_start_addr_system(id, data);
-
- phy_end = phy_start +
- ((struct alloc_list *)(data->index))->size;
-
- outer_flush_range(phy_start, phy_end);
-#endif
- goto end;
- }
- /* if this isn't a submmapped file, flush the whole thing */
- if (unlikely(!(data->flags & PMEM_FLAGS_CONNECTED))) {
- dmac_flush_range(vaddr, vaddr + pmem[id].len(id, data));
-#ifdef CONFIG_OUTER_CACHE
- phy_start = (unsigned long)vaddr -
- (unsigned long)pmem[id].vbase + pmem[id].base;
-
- phy_end = phy_start + pmem[id].len(id, data);
-
- outer_flush_range(phy_start, phy_end);
-#endif
- goto end;
- }
- /* otherwise, flush the region of the file we are drawing */
- list_for_each(elt, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node, list);
- if ((offset >= region_node->region.offset) &&
- ((offset + len) <= (region_node->region.offset +
- region_node->region.len))) {
- flush_start = vaddr + region_node->region.offset;
- flush_end = flush_start + region_node->region.len;
- dmac_flush_range(flush_start, flush_end);
-#ifdef CONFIG_OUTER_CACHE
-
- phy_start = (unsigned long)flush_start -
- (unsigned long)pmem[id].vbase + pmem[id].base;
-
- phy_end = phy_start + region_node->region.len;
-
- outer_flush_range(phy_start, phy_end);
-#endif
- break;
- }
- }
-end:
- up_read(&data->sem);
-}
-
-int pmem_cache_maint(struct file *file, unsigned int cmd,
- struct pmem_addr *pmem_addr)
-{
- struct pmem_data *data;
- int id;
- unsigned long vaddr, paddr, length, offset,
- pmem_len, pmem_start_addr;
-
- /* Called from kernel-space so file may be NULL */
- if (!file)
- return -EBADF;
-
- /*
- * check that the vaddr passed for flushing is valid
- * so that you don't crash the kernel
- */
- if (!pmem_addr->vaddr)
- return -EINVAL;
-
- data = file->private_data;
- id = get_id(file);
-
- if (!pmem[id].cached)
- return 0;
-
- offset = pmem_addr->offset;
- length = pmem_addr->length;
-
- down_read(&data->sem);
- if (!has_allocation(file)) {
- up_read(&data->sem);
- return -EINVAL;
- }
- pmem_len = pmem[id].len(id, data);
- pmem_start_addr = pmem[id].start_addr(id, data);
- up_read(&data->sem);
-
- if (offset + length > pmem_len)
- return -EINVAL;
-
- vaddr = pmem_addr->vaddr;
- paddr = pmem_start_addr + offset;
-
- DLOG("pmem cache maint on dev %s(id: %d)"
- "(vaddr %lx paddr %lx len %lu bytes)\n",
- get_name(file), id, vaddr, paddr, length);
- if (cmd == PMEM_CLEAN_INV_CACHES)
- clean_and_invalidate_caches(vaddr,
- length, paddr);
- else if (cmd == PMEM_CLEAN_CACHES)
- clean_caches(vaddr, length, paddr);
- else if (cmd == PMEM_INV_CACHES)
- invalidate_caches(vaddr, length, paddr);
-
- return 0;
-}
-EXPORT_SYMBOL(pmem_cache_maint);
-
-static int pmem_connect(unsigned long connect, struct file *file)
-{
- int ret = 0, put_needed;
- struct file *src_file;
-
- if (!file) {
- pr_err("pmem: %s: NULL file pointer passed in, "
- "bailing out!\n", __func__);
- ret = -EINVAL;
- goto leave;
- }
-
- src_file = fget_light(connect, &put_needed);
-
- if (!src_file) {
- pr_err("pmem: %s: src file not found!\n", __func__);
- ret = -EBADF;
- goto leave;
- }
-
- if (src_file == file) { /* degenerative case, operator error */
- pr_err("pmem: %s: src_file and passed in file are "
- "the same; refusing to connect to self!\n", __func__);
- ret = -EINVAL;
- goto put_src_file;
- }
-
- if (unlikely(!is_pmem_file(src_file))) {
- pr_err("pmem: %s: src file is not a pmem file!\n",
- __func__);
- ret = -EINVAL;
- goto put_src_file;
- } else {
- struct pmem_data *src_data = src_file->private_data;
-
- if (!src_data) {
- pr_err("pmem: %s: src file pointer has no"
- "private data, bailing out!\n", __func__);
- ret = -EINVAL;
- goto put_src_file;
- }
-
- down_read(&src_data->sem);
-
- if (unlikely(!has_allocation(src_file))) {
- up_read(&src_data->sem);
- pr_err("pmem: %s: src file has no allocation!\n",
- __func__);
- ret = -EINVAL;
- } else {
- struct pmem_data *data;
- int src_index = src_data->index;
-
- up_read(&src_data->sem);
-
- data = file->private_data;
- if (!data) {
- pr_err("pmem: %s: passed in file "
- "pointer has no private data, bailing"
- " out!\n", __func__);
- ret = -EINVAL;
- goto put_src_file;
- }
-
- down_write(&data->sem);
- if (has_allocation(file) &&
- (data->index != src_index)) {
- up_write(&data->sem);
-
- pr_err("pmem: %s: file is already "
- "mapped but doesn't match this "
- "src_file!\n", __func__);
- ret = -EINVAL;
- } else {
- data->index = src_index;
- data->flags |= PMEM_FLAGS_CONNECTED;
- data->master_fd = connect;
- data->master_file = src_file;
-
- up_write(&data->sem);
-
- DLOG("connect %p to %p\n", file, src_file);
- }
- }
- }
-put_src_file:
- fput_light(src_file, put_needed);
-leave:
- return ret;
-}
-
-static void pmem_unlock_data_and_mm(struct pmem_data *data,
- struct mm_struct *mm)
-{
- up_write(&data->sem);
- if (mm != NULL) {
- up_write(&mm->mmap_sem);
- mmput(mm);
- }
-}
-
-static int pmem_lock_data_and_mm(struct file *file, struct pmem_data *data,
- struct mm_struct **locked_mm)
-{
- int ret = 0;
- struct mm_struct *mm = NULL;
-#if PMEM_DEBUG_MSGS
- char currtask_name[FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
- DLOG("pid %u(%s) file %p(%ld)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file));
-
- *locked_mm = NULL;
-lock_mm:
- down_read(&data->sem);
- if (PMEM_IS_SUBMAP(data)) {
- mm = get_task_mm(data->task);
- if (!mm) {
- up_read(&data->sem);
-#if PMEM_DEBUG
- pr_alert("pmem: can't remap - task is gone!\n");
-#endif
- return -1;
- }
- }
- up_read(&data->sem);
-
- if (mm)
- down_write(&mm->mmap_sem);
-
- down_write(&data->sem);
- /* check that the file didn't get mmaped before we could take the
- * data sem, this should be safe b/c you can only submap each file
- * once */
- if (PMEM_IS_SUBMAP(data) && !mm) {
- pmem_unlock_data_and_mm(data, mm);
- DLOG("mapping contention, repeating mmap op\n");
- goto lock_mm;
- }
- /* now check that vma.mm is still there, it could have been
- * deleted by vma_close before we could get the data->sem */
- if ((data->flags & PMEM_FLAGS_UNSUBMAP) && (mm != NULL)) {
- /* might as well release this */
- if (data->flags & PMEM_FLAGS_SUBMAP) {
- put_task_struct(data->task);
- data->task = NULL;
- /* lower the submap flag to show the mm is gone */
- data->flags &= ~(PMEM_FLAGS_SUBMAP);
- }
- pmem_unlock_data_and_mm(data, mm);
-#if PMEM_DEBUG
- pr_alert("pmem: vma.mm went away!\n");
-#endif
- return -1;
- }
- *locked_mm = mm;
- return ret;
-}
-
-int pmem_remap(struct pmem_region *region, struct file *file,
- unsigned operation)
-{
- int ret;
- struct pmem_region_node *region_node;
- struct mm_struct *mm = NULL;
- struct list_head *elt, *elt2;
- int id = get_id(file);
- struct pmem_data *data;
-
- DLOG("operation %#x, region offset %ld, region len %ld\n",
- operation, region->offset, region->len);
-
- if (!is_pmem_file(file)) {
-#if PMEM_DEBUG
- pr_err("pmem: remap request for non-pmem file descriptor\n");
-#endif
- return -EINVAL;
- }
-
- /* is_pmem_file fails if !file */
- data = file->private_data;
-
- /* pmem region must be aligned on a page boundry */
- if (unlikely(!PMEM_IS_PAGE_ALIGNED(region->offset) ||
- !PMEM_IS_PAGE_ALIGNED(region->len))) {
-#if PMEM_DEBUG
- pr_err("pmem: request for unaligned pmem"
- "suballocation %lx %lx\n",
- region->offset, region->len);
-#endif
- return -EINVAL;
- }
-
- /* if userspace requests a region of len 0, there's nothing to do */
- if (region->len == 0)
- return 0;
-
- /* lock the mm and data */
- ret = pmem_lock_data_and_mm(file, data, &mm);
- if (ret)
- return 0;
-
- /* only the owner of the master file can remap the client fds
- * that back in it */
- if (!is_master_owner(file)) {
-#if PMEM_DEBUG
- pr_err("pmem: remap requested from non-master process\n");
-#endif
- ret = -EINVAL;
- goto err;
- }
-
- /* check that the requested range is within the src allocation */
- if (unlikely((region->offset > pmem[id].len(id, data)) ||
- (region->len > pmem[id].len(id, data)) ||
- (region->offset + region->len > pmem[id].len(id, data)))) {
-#if PMEM_DEBUG
- pr_err("pmem: suballoc doesn't fit in src_file!\n");
-#endif
- ret = -EINVAL;
- goto err;
- }
-
- if (operation == PMEM_MAP) {
- region_node = kmalloc(sizeof(struct pmem_region_node),
- GFP_KERNEL);
- if (!region_node) {
- ret = -ENOMEM;
-#if PMEM_DEBUG
- pr_alert("pmem: No space to allocate remap metadata!");
-#endif
- goto err;
- }
- region_node->region = *region;
- list_add(®ion_node->list, &data->region_list);
- } else if (operation == PMEM_UNMAP) {
- int found = 0;
- list_for_each_safe(elt, elt2, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node,
- list);
- if (region->len == 0 ||
- (region_node->region.offset == region->offset &&
- region_node->region.len == region->len)) {
- list_del(elt);
- kfree(region_node);
- found = 1;
- }
- }
- if (!found) {
-#if PMEM_DEBUG
- pr_err("pmem: Unmap region does not map any"
- " mapped region!");
-#endif
- ret = -EINVAL;
- goto err;
- }
- }
-
- if (data->vma && PMEM_IS_SUBMAP(data)) {
- if (operation == PMEM_MAP)
- ret = pmem_remap_pfn_range(id, data->vma, data,
- region->offset, region->len);
- else if (operation == PMEM_UNMAP)
- ret = pmem_unmap_pfn_range(id, data->vma, data,
- region->offset, region->len);
- }
-
-err:
- pmem_unlock_data_and_mm(data, mm);
- return ret;
-}
-
-static void pmem_revoke(struct file *file, struct pmem_data *data)
-{
- struct pmem_region_node *region_node;
- struct list_head *elt, *elt2;
- struct mm_struct *mm = NULL;
- int id = get_id(file);
- int ret = 0;
-
- data->master_file = NULL;
- ret = pmem_lock_data_and_mm(file, data, &mm);
- /* if lock_data_and_mm fails either the task that mapped the fd, or
- * the vma that mapped it have already gone away, nothing more
- * needs to be done */
- if (ret)
- return;
- /* unmap everything */
- /* delete the regions and region list nothing is mapped any more */
- if (data->vma)
- list_for_each_safe(elt, elt2, &data->region_list) {
- region_node = list_entry(elt, struct pmem_region_node,
- list);
- pmem_unmap_pfn_range(id, data->vma, data,
- region_node->region.offset,
- region_node->region.len);
- list_del(elt);
- kfree(region_node);
- }
- /* delete the master file */
- pmem_unlock_data_and_mm(data, mm);
-}
-
-static void pmem_get_size(struct pmem_region *region, struct file *file)
-{
- /* called via ioctl file op, so file guaranteed to be not NULL */
- struct pmem_data *data = file->private_data;
- int id = get_id(file);
-
- down_read(&data->sem);
- if (!has_allocation(file)) {
- region->offset = 0;
- region->len = 0;
- } else {
- region->offset = pmem[id].start_addr(id, data);
- region->len = pmem[id].len(id, data);
- }
- up_read(&data->sem);
- DLOG("offset 0x%lx len 0x%lx\n", region->offset, region->len);
-}
-
-
-static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- /* called from user space as file op, so file guaranteed to be not
- * NULL
- */
- struct pmem_data *data = file->private_data;
- int id = get_id(file);
-#if PMEM_DEBUG_MSGS
- char currtask_name[
- FIELD_SIZEOF(struct task_struct, comm) + 1];
-#endif
-
- DLOG("pid %u(%s) file %p(%ld) cmd %#x, dev %s(id: %d)\n",
- current->pid, get_task_comm(currtask_name, current),
- file, file_count(file), cmd, get_name(file), id);
-
- switch (cmd) {
- case PMEM_GET_PHYS:
- {
- struct pmem_region region;
-
- DLOG("get_phys\n");
- down_read(&data->sem);
- if (!has_allocation(file)) {
- region.offset = 0;
- region.len = 0;
- } else {
- region.offset = pmem[id].start_addr(id, data);
- region.len = pmem[id].len(id, data);
- }
- up_read(&data->sem);
-
- if (copy_to_user((void __user *)arg, ®ion,
- sizeof(struct pmem_region)))
- return -EFAULT;
-
- DLOG("pmem: successful request for "
- "physical address of pmem region id %d, "
- "offset 0x%lx, len 0x%lx\n",
- id, region.offset, region.len);
-
- break;
- }
- case PMEM_MAP:
- {
- struct pmem_region region;
- DLOG("map\n");
- if (copy_from_user(®ion, (void __user *)arg,
- sizeof(struct pmem_region)))
- return -EFAULT;
- return pmem_remap(®ion, file, PMEM_MAP);
- }
- break;
- case PMEM_UNMAP:
- {
- struct pmem_region region;
- DLOG("unmap\n");
- if (copy_from_user(®ion, (void __user *)arg,
- sizeof(struct pmem_region)))
- return -EFAULT;
- return pmem_remap(®ion, file, PMEM_UNMAP);
- break;
- }
- case PMEM_GET_SIZE:
- {
- struct pmem_region region;
- DLOG("get_size\n");
- pmem_get_size(®ion, file);
- if (copy_to_user((void __user *)arg, ®ion,
- sizeof(struct pmem_region)))
- return -EFAULT;
- break;
- }
- case PMEM_GET_TOTAL_SIZE:
- {
- struct pmem_region region;
- DLOG("get total size\n");
- region.offset = 0;
- get_id(file);
- region.len = pmem[id].size;
- if (copy_to_user((void __user *)arg, ®ion,
- sizeof(struct pmem_region)))
- return -EFAULT;
- break;
- }
- case PMEM_GET_FREE_SPACE:
- {
- struct pmem_freespace fs;
- DLOG("get freespace on %s(id: %d)\n",
- get_name(file), id);
-
- mutex_lock(&pmem[id].arena_mutex);
- pmem[id].free_space(id, &fs);
- mutex_unlock(&pmem[id].arena_mutex);
-
- DLOG("%s(id: %d) total free %lu, largest %lu\n",
- get_name(file), id, fs.total, fs.largest);
-
- if (copy_to_user((void __user *)arg, &fs,
- sizeof(struct pmem_freespace)))
- return -EFAULT;
- break;
- }
-
- case PMEM_ALLOCATE:
- {
- int ret = 0;
- DLOG("allocate, id %d\n", id);
- down_write(&data->sem);
- if (has_allocation(file)) {
- pr_err("pmem: Existing allocation found on "
- "this file descrpitor\n");
- up_write(&data->sem);
- return -EINVAL;
- }
-
- mutex_lock(&pmem[id].arena_mutex);
- data->index = pmem_allocate_from_id(id,
- arg,
- SZ_4K);
- mutex_unlock(&pmem[id].arena_mutex);
- ret = data->index == -1 ? -ENOMEM :
- data->index;
- up_write(&data->sem);
- return ret;
- }
- case PMEM_ALLOCATE_ALIGNED:
- {
- struct pmem_allocation alloc;
- int ret = 0;
-
- if (copy_from_user(&alloc, (void __user *)arg,
- sizeof(struct pmem_allocation)))
- return -EFAULT;
- DLOG("allocate id align %d %u\n", id, alloc.align);
- down_write(&data->sem);
- if (has_allocation(file)) {
- pr_err("pmem: Existing allocation found on "
- "this file descrpitor\n");
- up_write(&data->sem);
- return -EINVAL;
- }
-
- if (alloc.align & (alloc.align - 1)) {
- pr_err("pmem: Alignment is not a power of 2\n");
- return -EINVAL;
- }
-
- if (alloc.align != SZ_4K &&
- (pmem[id].allocator_type !=
- PMEM_ALLOCATORTYPE_BITMAP)) {
- pr_err("pmem: Non 4k alignment requires bitmap"
- " allocator on %s\n", pmem[id].name);
- return -EINVAL;
- }
-
- if (alloc.align > SZ_1M ||
- alloc.align < SZ_4K) {
- pr_err("pmem: Invalid Alignment (%u) "
- "specified\n", alloc.align);
- return -EINVAL;
- }
-
- mutex_lock(&pmem[id].arena_mutex);
- data->index = pmem_allocate_from_id(id,
- alloc.size,
- alloc.align);
- mutex_unlock(&pmem[id].arena_mutex);
- ret = data->index == -1 ? -ENOMEM :
- data->index;
- up_write(&data->sem);
- return ret;
- }
- case PMEM_CONNECT:
- DLOG("connect\n");
- return pmem_connect(arg, file);
- case PMEM_CLEAN_INV_CACHES:
- case PMEM_CLEAN_CACHES:
- case PMEM_INV_CACHES:
- {
- struct pmem_addr pmem_addr;
-
- if (copy_from_user(&pmem_addr, (void __user *)arg,
- sizeof(struct pmem_addr)))
- return -EFAULT;
-
- return pmem_cache_maint(file, cmd, &pmem_addr);
- }
- default:
- if (pmem[id].ioctl)
- return pmem[id].ioctl(file, cmd, arg);
-
- DLOG("ioctl invalid (%#x)\n", cmd);
- return -EINVAL;
- }
- return 0;
-}
-
-static void ioremap_pmem(int id)
-{
- unsigned long addr;
- const struct mem_type *type;
-
- DLOG("PMEMDEBUG: ioremaping for %s\n", pmem[id].name);
- if (pmem[id].map_on_demand) {
- addr = (unsigned long)pmem[id].area->addr;
- if (pmem[id].cached)
- type = get_mem_type(MT_DEVICE_CACHED);
- else
- type = get_mem_type(MT_DEVICE);
- DLOG("PMEMDEBUG: Remap phys %lx to virt %lx on %s\n",
- pmem[id].base, addr, pmem[id].name);
- if (ioremap_pages(addr, pmem[id].base, pmem[id].size, type)) {
- pr_err("pmem: Failed to map pages\n");
- BUG();
- }
- pmem[id].vbase = pmem[id].area->addr;
- /* Flush the cache after installing page table entries to avoid
- * aliasing when these pages are remapped to user space.
- */
- flush_cache_vmap(addr, addr + pmem[id].size);
- } else {
- if (pmem[id].cached)
- pmem[id].vbase = ioremap_cached(pmem[id].base,
- pmem[id].size);
- #ifdef ioremap_ext_buffered
- else if (pmem[id].buffered)
- pmem[id].vbase = ioremap_ext_buffered(pmem[id].base,
- pmem[id].size);
- #endif
- else
- pmem[id].vbase = ioremap(pmem[id].base, pmem[id].size);
- }
-}
-
-int pmem_setup(struct android_pmem_platform_data *pdata,
- long (*ioctl)(struct file *, unsigned int, unsigned long),
- int (*release)(struct inode *, struct file *))
-{
- int i, index = 0, id;
- struct vm_struct *pmem_vma = NULL;
- struct page *page;
-
- if (id_count >= PMEM_MAX_DEVICES) {
- pr_alert("pmem: %s: unable to register driver(%s) - no more "
- "devices available!\n", __func__, pdata->name);
- goto err_no_mem;
- }
-
- if (!pdata->size) {
- pr_alert("pmem: %s: unable to register pmem driver(%s) - zero "
- "size passed in!\n", __func__, pdata->name);
- goto err_no_mem;
- }
-
- id = id_count++;
-
- pmem[id].id = id;
-
- if (pmem[id].allocate) {
- pr_alert("pmem: %s: unable to register pmem driver - "
- "duplicate registration of %s!\n",
- __func__, pdata->name);
- goto err_no_mem;
- }
-
- pmem[id].allocator_type = pdata->allocator_type;
-
- /* 'quantum' is a "hidden" variable that defaults to 0 in the board
- * files */
- pmem[id].quantum = pdata->quantum ?: PMEM_MIN_ALLOC;
- if (pmem[id].quantum < PMEM_MIN_ALLOC ||
- !is_power_of_2(pmem[id].quantum)) {
- pr_alert("pmem: %s: unable to register pmem driver %s - "
- "invalid quantum value (%#x)!\n",
- __func__, pdata->name, pmem[id].quantum);
- goto err_reset_pmem_info;
- }
-
- if (pdata->size % pmem[id].quantum) {
- /* bad alignment for size! */
- pr_alert("pmem: %s: Unable to register driver %s - "
- "memory region size (%#lx) is not a multiple of "
- "quantum size(%#x)!\n", __func__, pdata->name,
- pdata->size, pmem[id].quantum);
- goto err_reset_pmem_info;
- }
-
- pmem[id].cached = pdata->cached;
- pmem[id].buffered = pdata->buffered;
- pmem[id].size = pdata->size;
- pmem[id].memory_type = pdata->memory_type;
- strlcpy(pmem[id].name, pdata->name, PMEM_NAME_SIZE);
-
- pmem[id].num_entries = pmem[id].size / pmem[id].quantum;
-
- memset(&pmem[id].kobj, 0, sizeof(pmem[0].kobj));
- pmem[id].kobj.kset = pmem_kset;
-
- switch (pmem[id].allocator_type) {
- case PMEM_ALLOCATORTYPE_ALLORNOTHING:
- pmem[id].allocate = pmem_allocator_all_or_nothing;
- pmem[id].free = pmem_free_all_or_nothing;
- pmem[id].free_space = pmem_free_space_all_or_nothing;
- pmem[id].len = pmem_len_all_or_nothing;
- pmem[id].start_addr = pmem_start_addr_all_or_nothing;
- pmem[id].num_entries = 1;
- pmem[id].quantum = pmem[id].size;
- pmem[id].allocator.all_or_nothing.allocated = 0;
-
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_allornothing_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- break;
-
- case PMEM_ALLOCATORTYPE_BUDDYBESTFIT:
- pmem[id].allocator.buddy_bestfit.buddy_bitmap = kmalloc(
- pmem[id].num_entries * sizeof(struct pmem_bits),
- GFP_KERNEL);
- if (!pmem[id].allocator.buddy_bestfit.buddy_bitmap)
- goto err_reset_pmem_info;
-
- memset(pmem[id].allocator.buddy_bestfit.buddy_bitmap, 0,
- sizeof(struct pmem_bits) * pmem[id].num_entries);
-
- for (i = sizeof(pmem[id].num_entries) * 8 - 1; i >= 0; i--)
- if ((pmem[id].num_entries) & 1<<i) {
- PMEM_BUDDY_ORDER(id, index) = i;
- index = PMEM_BUDDY_NEXT_INDEX(id, index);
- }
- pmem[id].allocate = pmem_allocator_buddy_bestfit;
- pmem[id].free = pmem_free_buddy_bestfit;
- pmem[id].free_space = pmem_free_space_buddy_bestfit;
- pmem[id].len = pmem_len_buddy_bestfit;
- pmem[id].start_addr = pmem_start_addr_buddy_bestfit;
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_buddy_bestfit_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- break;
-
- case PMEM_ALLOCATORTYPE_BITMAP: /* 0, default if not explicit */
- pmem[id].allocator.bitmap.bitm_alloc = kmalloc(
- PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS *
- sizeof(*pmem[id].allocator.bitmap.bitm_alloc),
- GFP_KERNEL);
- if (!pmem[id].allocator.bitmap.bitm_alloc) {
- pr_alert("pmem: %s: Unable to register pmem "
- "driver %s - can't allocate "
- "bitm_alloc!\n",
- __func__, pdata->name);
- goto err_reset_pmem_info;
- }
-
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_bitmap_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- for (i = 0; i < PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS; i++) {
- pmem[id].allocator.bitmap.bitm_alloc[i].bit = -1;
- pmem[id].allocator.bitmap.bitm_alloc[i].quanta = 0;
- }
-
- pmem[id].allocator.bitmap.bitmap_allocs =
- PMEM_INITIAL_NUM_BITMAP_ALLOCATIONS;
-
- pmem[id].allocator.bitmap.bitmap =
- kcalloc((pmem[id].num_entries + 31) / 32,
- sizeof(unsigned int), GFP_KERNEL);
- if (!pmem[id].allocator.bitmap.bitmap) {
- pr_alert("pmem: %s: Unable to register pmem "
- "driver - can't allocate bitmap!\n",
- __func__);
- goto err_cant_register_device;
- }
- pmem[id].allocator.bitmap.bitmap_free = pmem[id].num_entries;
-
- pmem[id].allocate = pmem_allocator_bitmap;
- pmem[id].free = pmem_free_bitmap;
- pmem[id].free_space = pmem_free_space_bitmap;
- pmem[id].len = pmem_len_bitmap;
- pmem[id].start_addr = pmem_start_addr_bitmap;
-
- DLOG("bitmap allocator id %d (%s), num_entries %u, raw size "
- "%lu, quanta size %u\n",
- id, pdata->name, pmem[id].allocator.bitmap.bitmap_free,
- pmem[id].size, pmem[id].quantum);
- break;
-
- case PMEM_ALLOCATORTYPE_SYSTEM:
-
- INIT_LIST_HEAD(&pmem[id].allocator.system_mem.alist);
-
- pmem[id].allocator.system_mem.used = 0;
- pmem[id].vbase = NULL;
-
- if (kobject_init_and_add(&pmem[id].kobj,
- &pmem_system_ktype, NULL,
- "%s", pdata->name))
- goto out_put_kobj;
-
- pmem[id].allocate = pmem_allocator_system;
- pmem[id].free = pmem_free_system;
- pmem[id].free_space = pmem_free_space_system;
- pmem[id].len = pmem_len_system;
- pmem[id].start_addr = pmem_start_addr_system;
- pmem[id].num_entries = 0;
- pmem[id].quantum = PAGE_SIZE;
-
- DLOG("system allocator id %d (%s), raw size %lu\n",
- id, pdata->name, pmem[id].size);
- break;
-
- default:
- pr_alert("Invalid allocator type (%d) for pmem driver\n",
- pdata->allocator_type);
- goto err_reset_pmem_info;
- }
-
- pmem[id].ioctl = ioctl;
- pmem[id].release = release;
- mutex_init(&pmem[id].arena_mutex);
- mutex_init(&pmem[id].data_list_mutex);
- INIT_LIST_HEAD(&pmem[id].data_list);
-
- pmem[id].dev.name = pdata->name;
- pmem[id].dev.minor = id;
- pmem[id].dev.fops = &pmem_fops;
- pmem[id].reusable = pdata->reusable;
- pr_info("pmem: Initializing %s as %s\n",
- pdata->name, pdata->cached ? "cached" : "non-cached");
-
- if (misc_register(&pmem[id].dev)) {
- pr_alert("Unable to register pmem driver!\n");
- goto err_cant_register_device;
- }
-
- if (!pmem[id].reusable) {
- pmem[id].base = allocate_contiguous_memory_nomap(pmem[id].size,
- pmem[id].memory_type, PAGE_SIZE);
- if (!pmem[id].base) {
- pr_err("pmem: Cannot allocate from reserved memory for %s\n",
- pdata->name);
- goto err_misc_deregister;
- }
- }
-
- /* reusable pmem requires map on demand */
- pmem[id].map_on_demand = pdata->map_on_demand || pdata->reusable;
- if (pmem[id].map_on_demand) {
- if (pmem[id].reusable) {
- const struct fmem_data *fmem_info = fmem_get_info();
- pmem[id].area = fmem_info->area;
- pmem[id].base = fmem_info->phys;
- } else {
- pmem_vma = get_vm_area(pmem[id].size, VM_IOREMAP);
- if (!pmem_vma) {
- pr_err("pmem: Failed to allocate virtual space for "
- "%s\n", pdata->name);
- goto err_free;
- }
- pr_err("pmem: Reserving virtual address range %lx - %lx for"
- " %s\n", (unsigned long) pmem_vma->addr,
- (unsigned long) pmem_vma->addr + pmem[id].size,
- pdata->name);
- pmem[id].area = pmem_vma;
- }
- } else
- pmem[id].area = NULL;
-
- page = alloc_page(GFP_KERNEL);
- if (!page) {
- pr_err("pmem: Failed to allocate page for %s\n", pdata->name);
- goto cleanup_vm;
- }
- pmem[id].garbage_pfn = page_to_pfn(page);
- atomic_set(&pmem[id].allocation_cnt, 0);
-
- if (pdata->setup_region)
- pmem[id].region_data = pdata->setup_region();
-
- if (pdata->request_region)
- pmem[id].mem_request = pdata->request_region;
-
- if (pdata->release_region)
- pmem[id].mem_release = pdata->release_region;
-
- pr_info("allocating %lu bytes at %lx physical for %s\n",
- pmem[id].size, pmem[id].base, pmem[id].name);
-
- return 0;
-
-cleanup_vm:
- if (!pmem[id].reusable)
- remove_vm_area(pmem_vma);
-err_free:
- if (!pmem[id].reusable)
- free_contiguous_memory_by_paddr(pmem[id].base);
-err_misc_deregister:
- misc_deregister(&pmem[id].dev);
-err_cant_register_device:
-out_put_kobj:
- kobject_put(&pmem[id].kobj);
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BUDDYBESTFIT)
- kfree(pmem[id].allocator.buddy_bestfit.buddy_bitmap);
- else if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BITMAP) {
- kfree(pmem[id].allocator.bitmap.bitmap);
- kfree(pmem[id].allocator.bitmap.bitm_alloc);
- }
-err_reset_pmem_info:
- pmem[id].allocate = 0;
- pmem[id].dev.minor = -1;
-err_no_mem:
- return -1;
-}
-
-static int pmem_probe(struct platform_device *pdev)
-{
- struct android_pmem_platform_data *pdata;
-
- if (!pdev || !pdev->dev.platform_data) {
- pr_alert("Unable to probe pmem!\n");
- return -1;
- }
- pdata = pdev->dev.platform_data;
-
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
-
- return pmem_setup(pdata, NULL, NULL);
-}
-
-static int pmem_remove(struct platform_device *pdev)
-{
- int id = pdev->id;
- __free_page(pfn_to_page(pmem[id].garbage_pfn));
- pm_runtime_disable(&pdev->dev);
- if (pmem[id].vbase)
- iounmap(pmem[id].vbase);
- if (pmem[id].map_on_demand && !pmem[id].reusable && pmem[id].area)
- free_vm_area(pmem[id].area);
- if (pmem[id].base)
- free_contiguous_memory_by_paddr(pmem[id].base);
- kobject_put(&pmem[id].kobj);
- if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BUDDYBESTFIT)
- kfree(pmem[id].allocator.buddy_bestfit.buddy_bitmap);
- else if (pmem[id].allocator_type == PMEM_ALLOCATORTYPE_BITMAP) {
- kfree(pmem[id].allocator.bitmap.bitmap);
- kfree(pmem[id].allocator.bitmap.bitm_alloc);
- }
- misc_deregister(&pmem[id].dev);
- return 0;
-}
-
-static int pmem_runtime_suspend(struct device *dev)
-{
- dev_dbg(dev, "pm_runtime: suspending...\n");
- return 0;
-}
-
-static int pmem_runtime_resume(struct device *dev)
-{
- dev_dbg(dev, "pm_runtime: resuming...\n");
- return 0;
-}
-
-static const struct dev_pm_ops pmem_dev_pm_ops = {
- .runtime_suspend = pmem_runtime_suspend,
- .runtime_resume = pmem_runtime_resume,
-};
-
-static struct platform_driver pmem_driver = {
- .probe = pmem_probe,
- .remove = pmem_remove,
- .driver = { .name = "android_pmem",
- .pm = &pmem_dev_pm_ops,
- }
-};
-
-
-static int __init pmem_init(void)
-{
- /* create /sys/kernel/<PMEM_SYSFS_DIR_NAME> directory */
- pmem_kset = kset_create_and_add(PMEM_SYSFS_DIR_NAME,
- NULL, kernel_kobj);
- if (!pmem_kset) {
- pr_err("pmem(%s):kset_create_and_add fail\n", __func__);
- return -ENOMEM;
- }
-
- return platform_driver_register(&pmem_driver);
-}
-
-static void __exit pmem_exit(void)
-{
- platform_driver_unregister(&pmem_driver);
-}
-
-module_init(pmem_init);
-module_exit(pmem_exit);
-
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 9f12142..21e65b9 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -228,6 +228,7 @@
md = mmc_blk_get(dev_to_disk(dev));
card = md->queue.card;
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@@ -240,6 +241,7 @@
card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
if (!ret) {
pr_info("%s: Locking boot partition ro until next power on\n",
@@ -602,7 +604,7 @@
md = mmc_blk_get(bdev->bd_disk);
if (!md) {
err = -EINVAL;
- goto cmd_done;
+ goto blk_err;
}
card = md->queue.card;
@@ -707,6 +709,7 @@
cmd_done:
mmc_blk_put(md);
+blk_err:
kfree(idata->buf);
kfree(idata);
return err;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 73a1b41..9fc599b 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2864,6 +2864,40 @@
return ret;
}
+static int mmc_clk_update_freq(struct mmc_host *host,
+ unsigned long freq, enum mmc_load state)
+{
+ int err = 0;
+
+ if (host->ops->notify_load) {
+ err = host->ops->notify_load(host, state);
+ if (err)
+ goto out;
+ }
+
+ if (freq != host->clk_scaling.curr_freq) {
+ if (!mmc_is_vaild_state_for_clk_scaling(host)) {
+ err = -EAGAIN;
+ goto error;
+ }
+
+ err = host->bus_ops->change_bus_speed(host, &freq);
+ if (!err)
+ host->clk_scaling.curr_freq = freq;
+ else
+ pr_err("%s: %s: failed (%d) at freq=%lu\n",
+ mmc_hostname(host), __func__, err, freq);
+ }
+error:
+ if (err) {
+ /* restore previous state */
+ if (host->ops->notify_load)
+ host->ops->notify_load(host, host->clk_scaling.state);
+ }
+out:
+ return err;
+}
+
/**
* mmc_clk_scaling() - clock scaling decision algorithm
* @host: pointer to mmc host structure
@@ -2889,6 +2923,7 @@
unsigned int up_threshold = host->clk_scaling.up_threshold;
unsigned int down_threshold = host->clk_scaling.down_threshold;
bool queue_scale_down_work = false;
+ enum mmc_load state;
if (!card || !host->bus_ops || !host->bus_ops->change_bus_speed) {
pr_err("%s: %s: invalid entry\n", mmc_hostname(host), __func__);
@@ -2916,6 +2951,7 @@
busy_time_ms = host->clk_scaling.busy_time_us / USEC_PER_MSEC;
freq = host->clk_scaling.curr_freq;
+ state = host->clk_scaling.state;
/*
* Note that the max. and min. frequency should be based
@@ -2924,28 +2960,24 @@
*/
if ((busy_time_ms * 100 > total_time_ms * up_threshold)) {
freq = mmc_get_max_frequency(host);
+ state = MMC_LOAD_HIGH;
} else if ((busy_time_ms * 100 < total_time_ms * down_threshold)) {
if (!from_wq)
queue_scale_down_work = true;
freq = mmc_get_min_frequency(host);
+ state = MMC_LOAD_LOW;
}
- if (freq != host->clk_scaling.curr_freq) {
+ if (state != host->clk_scaling.state) {
if (!queue_scale_down_work) {
if (!from_wq)
cancel_delayed_work_sync(
&host->clk_scaling.work);
-
- if (!mmc_is_vaild_state_for_clk_scaling(host))
- goto bypass_scaling;
-
- err = host->bus_ops->change_bus_speed(host, &freq);
+ err = mmc_clk_update_freq(host, freq, state);
if (!err)
- host->clk_scaling.curr_freq = freq;
- else
- pr_err("%s: %s: failed (%d) at freq=%lu\n",
- mmc_hostname(host), __func__, err,
- freq);
+ host->clk_scaling.state = state;
+ else if (err == -EAGAIN)
+ goto no_reset_stats;
} else {
/*
* We hold claim host while queueing the scale down
@@ -2954,13 +2986,12 @@
*/
queue_delayed_work(system_nrt_wq,
&host->clk_scaling.work, 1);
- host->clk_scaling.in_progress = false;
- goto out;
+ goto no_reset_stats;
}
}
mmc_reset_clk_scale_stats(host);
-bypass_scaling:
+no_reset_stats:
host->clk_scaling.in_progress = false;
out:
return;
@@ -3007,6 +3038,9 @@
INIT_DELAYED_WORK(&host->clk_scaling.work, mmc_clk_scale_work);
host->clk_scaling.curr_freq = mmc_get_max_frequency(host);
+ if (host->ops->notify_load)
+ host->ops->notify_load(host, MMC_LOAD_HIGH);
+ host->clk_scaling.state = MMC_LOAD_HIGH;
mmc_reset_clk_scale_stats(host);
host->clk_scaling.enable = true;
host->clk_scaling.initialized = true;
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 8b7e0bd..903decf 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -176,9 +176,11 @@
if (val > host->f_max)
return -EINVAL;
+ mmc_rpm_hold(host, &host->class_dev);
mmc_claim_host(host);
mmc_set_clock(host, (unsigned int) val);
mmc_release_host(host);
+ mmc_rpm_release(host, &host->class_dev);
return 0;
}
@@ -208,6 +210,7 @@
if (!host || (val < host->f_min))
goto out;
+ mmc_rpm_hold(host, &host->class_dev);
mmc_claim_host(host);
if (host->bus_ops && host->bus_ops->change_bus_speed) {
old_freq = host->f_max;
@@ -219,6 +222,7 @@
host->f_max = old_freq;
}
mmc_release_host(host);
+ mmc_rpm_release(host, &host->class_dev);
out:
return err;
}
@@ -286,6 +290,7 @@
u32 status;
int ret;
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
ret = mmc_send_status(data, &status);
@@ -293,6 +298,7 @@
*val = status;
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
return ret;
}
@@ -319,9 +325,11 @@
goto out_free;
}
+ mmc_rpm_hold(card->host, &card->dev);
mmc_claim_host(card->host);
err = mmc_send_ext_csd(card, ext_csd);
mmc_release_host(card->host);
+ mmc_rpm_release(card->host, &card->dev);
if (err)
goto out_free;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index c0a4cef..6c03bfc 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -466,12 +466,8 @@
goto err;
if (value && !mmc_can_scale_clk(host)) {
- if (mmc_card_ddr_mode(host->card) ||
- mmc_card_hs200(host->card) ||
- mmc_card_uhs(host->card)) {
- host->caps2 |= MMC_CAP2_CLK_SCALE;
- mmc_init_clk_scaling(host);
- }
+ host->caps2 |= MMC_CAP2_CLK_SCALE;
+ mmc_init_clk_scaling(host);
if (!mmc_can_scale_clk(host)) {
host->caps2 &= ~MMC_CAP2_CLK_SCALE;
@@ -487,6 +483,10 @@
if (host->bus_ops->change_bus_speed(host, &freq))
goto err;
}
+ if (host->ops->notify_load &&
+ host->ops->notify_load(host, MMC_LOAD_HIGH))
+ goto err;
+ host->clk_scaling.state = MMC_LOAD_HIGH;
host->clk_scaling.initialized = false;
}
retval = count;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 8a866cf..89f8c91 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1734,9 +1734,7 @@
if (err)
goto remove_card;
- /* Initialize clock scaling only for high frequency modes */
- if (mmc_card_hs200(host->card) || mmc_card_ddr_mode(host->card))
- mmc_init_clk_scaling(host);
+ mmc_init_clk_scaling(host);
return 0;
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 60e0640..ddf9a87 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1415,9 +1415,7 @@
if (err)
goto remove_card;
- /* Initialize clock scaling only for high frequency modes */
- if (mmc_card_uhs(host->card))
- mmc_init_clk_scaling(host);
+ mmc_init_clk_scaling(host);
return 0;
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 3f3687b..caf5fe4 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -958,7 +958,7 @@
struct msmsdcc_nc_dmadata *nc;
dmov_box *box;
uint32_t rows;
- unsigned int n;
+ int n;
int i, err = 0, box_cmd_cnt = 0;
struct scatterlist *sg = data->sg;
unsigned int len, offset;
@@ -4393,6 +4393,39 @@
return data_cnt;
}
+static int msmsdcc_notify_load(struct mmc_host *mmc, enum mmc_load state)
+{
+ int err = 0;
+ unsigned long rate;
+ struct msmsdcc_host *host = mmc_priv(mmc);
+
+ if (IS_ERR_OR_NULL(host->bus_clk))
+ goto out;
+
+ switch (state) {
+ case MMC_LOAD_HIGH:
+ rate = MSMSDCC_BUS_VOTE_MAX_RATE;
+ break;
+ case MMC_LOAD_LOW:
+ rate = MSMSDCC_BUS_VOTE_MIN_RATE;
+ break;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (rate != host->bus_clk_rate) {
+ err = clk_set_rate(host->bus_clk, rate);
+ if (err)
+ pr_err("%s: %s: bus clk set rate %lu Hz err %d\n",
+ mmc_hostname(mmc), __func__, rate, err);
+ else
+ host->bus_clk_rate = rate;
+ }
+out:
+ return err;
+}
+
static const struct mmc_host_ops msmsdcc_ops = {
.enable = msmsdcc_enable,
.disable = msmsdcc_disable,
@@ -4407,6 +4440,7 @@
.hw_reset = msmsdcc_hw_reset,
.stop_request = msmsdcc_stop_request,
.get_xfer_remain = msmsdcc_get_xfer_remain,
+ .notify_load = msmsdcc_notify_load,
};
static void msmsdcc_enable_status_gpio(struct msmsdcc_host *host)
@@ -5975,12 +6009,13 @@
host->bus_clk = clk_get(&pdev->dev, "bus_clk");
if (!IS_ERR_OR_NULL(host->bus_clk)) {
/* Vote for max. clk rate for max. performance */
- ret = clk_set_rate(host->bus_clk, INT_MAX);
+ ret = clk_set_rate(host->bus_clk, MSMSDCC_BUS_VOTE_MAX_RATE);
if (ret)
goto bus_clk_put;
ret = clk_prepare_enable(host->bus_clk);
if (ret)
goto bus_clk_put;
+ host->bus_clk_rate = MSMSDCC_BUS_VOTE_MAX_RATE;
}
/*
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 4ed2d96..bcfde57 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -260,6 +260,12 @@
#define MMC_MAX_DMA_CMDS (MAX_NR_SG_DMA_PIO * (MMC_MAX_REQ_SIZE / \
MMC_MAX_DMA_BOX_LENGTH))
+/*
+ * Peripheral bus clock scaling vote rates
+ */
+#define MSMSDCC_BUS_VOTE_MAX_RATE 64000000 /* Hz */
+#define MSMSDCC_BUS_VOTE_MIN_RATE 32000000 /* Hz */
+
struct clk;
struct msmsdcc_nc_dmadata {
@@ -360,6 +366,7 @@
struct clk *clk; /* main MMC bus clock */
struct clk *pclk; /* SDCC peripheral bus clock */
struct clk *bus_clk; /* SDCC bus voter clock */
+ unsigned long bus_clk_rate; /* peripheral bus clk rate */
atomic_t clks_on; /* set if clocks are enabled */
unsigned int eject; /* eject state */
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 15e36a8..89730b0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2137,6 +2137,7 @@
int ret = 0, dead = 0;
u32 vdd_max_current;
u16 host_version;
+ u32 pwr;
pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -2245,7 +2246,21 @@
}
/* Set SW_RST bit in POWER register (Offset 0x0) */
- writel_relaxed(CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+ writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
+ CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+ /*
+ * SW reset can take upto 10HCLK + 15MCLK cycles.
+ * Calculating based on min clk rates (hclk = 27MHz,
+ * mclk = 400KHz) it comes to ~40us. Let's poll for
+ * max. 1ms for reset completion.
+ */
+ ret = readl_poll_timeout(msm_host->core_mem + CORE_POWER,
+ pwr, !(pwr & CORE_SW_RST), 100, 10);
+
+ if (ret) {
+ dev_err(&pdev->dev, "reset failed (%d)\n", ret);
+ goto vreg_deinit;
+ }
/* Set HC_MODE_EN bit in HC_MODE register */
writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 8f90ddc..726e9a6 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -65,9 +65,9 @@
*/
struct ecm_ipa_dev {
struct net_device *net;
- bool tx_enable;
- bool rx_enable;
- bool rm_enable;
+ u32 tx_enable;
+ u32 rx_enable;
+ u32 rm_enable;
bool dma_enable;
struct dentry *directory;
uint32_t eth_ipv4_hdr_hdl;
@@ -80,25 +80,22 @@
};
/**
- * struct ecm_ipa_ctx - saved pointer for the std ecm network device
+ * struct ecm_ipa_ctx - saved pointer for the ecm_ipa network device
* which allow ecm_ipa to be a singleton
*/
static struct ecm_ipa_dev *ecm_ipa_ctx;
-static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
-static int ecm_ipa_set_device_ethernet_addr(
- u8 *dev_ethaddr, u8 device_ethaddr[]);
-static void ecm_ipa_packet_receive_notify(void *priv,
- enum ipa_dp_evt_type evt,
- unsigned long data);
-static void ecm_ipa_tx_complete_notify(void *priv,
- enum ipa_dp_evt_type evt,
- unsigned long data);
-static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
static int ecm_ipa_open(struct net_device *net);
+static void ecm_ipa_packet_receive_notify(void *priv,
+ enum ipa_dp_evt_type evt, unsigned long data);
+static void ecm_ipa_tx_complete_notify(void *priv,
+ enum ipa_dp_evt_type evt, unsigned long data);
static int ecm_ipa_stop(struct net_device *net);
-static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
- struct net_device *net);
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+ const void *dst_mac, const void *src_mac);
+static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *dev);
+static int ecm_ipa_register_properties(void);
+static void ecm_ipa_deregister_properties(void);
static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
unsigned long data);
static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev);
@@ -106,28 +103,28 @@
static bool rx_filter(struct sk_buff *skb);
static bool tx_filter(struct sk_buff *skb);
static bool rm_enabled(struct ecm_ipa_dev *dev);
-
-static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
- const void *dst_mac, const void *src_mac);
-static int ecm_ipa_register_properties(void);
-static void ecm_ipa_deregister_properties(void);
-static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
-static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
-static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file);
-static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file);
-static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file);
-static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file);
+static int resource_request(struct ecm_ipa_dev *dev);
+static void resource_release(struct ecm_ipa_dev *dev);
+static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
+ struct net_device *net);
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file);
+static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos);
+static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file);
+static ssize_t ecm_ipa_debugfs_enable_write(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos);
static ssize_t ecm_ipa_debugfs_enable_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
static ssize_t ecm_ipa_debugfs_atomic_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
-static ssize_t ecm_ipa_debugfs_enable_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos);
-static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos);
-static void eth_get_drvinfo(struct net_device *net,
- struct ethtool_drvinfo *drv_info);
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
+static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
+static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
+static int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
+ u8 device_ethaddr[]);
+static int ecm_ipa_init_module(void);
+static void ecm_ipa_cleanup_module(void);
static const struct net_device_ops ecm_ipa_netdev_ops = {
.ndo_open = ecm_ipa_open,
@@ -135,38 +132,353 @@
.ndo_start_xmit = ecm_ipa_start_xmit,
.ndo_set_mac_address = eth_mac_addr,
};
-static const struct ethtool_ops ops = {
- .get_drvinfo = eth_get_drvinfo,
- .get_link = ethtool_op_get_link,
-};
-const struct file_operations ecm_ipa_debugfs_tx_ops = {
- .open = ecm_ipa_debugfs_tx_open,
- .read = ecm_ipa_debugfs_enable_read,
- .write = ecm_ipa_debugfs_enable_write,
-};
-const struct file_operations ecm_ipa_debugfs_rx_ops = {
- .open = ecm_ipa_debugfs_rx_open,
- .read = ecm_ipa_debugfs_enable_read,
- .write = ecm_ipa_debugfs_enable_write,
-};
-const struct file_operations ecm_ipa_debugfs_rm_ops = {
- .open = ecm_ipa_debugfs_rm_open,
- .read = ecm_ipa_debugfs_enable_read,
- .write = ecm_ipa_debugfs_enable_write,
-};
+
const struct file_operations ecm_ipa_debugfs_dma_ops = {
- .open = ecm_ipa_debugfs_dma_open,
+ .open = ecm_ipa_debugfs_dma_open,
.read = ecm_ipa_debugfs_enable_read,
.write = ecm_ipa_debugfs_enable_write_dma,
};
const struct file_operations ecm_ipa_debugfs_atomic_ops = {
- .open = ecm_ipa_debugfs_atomic_open,
- .read = ecm_ipa_debugfs_atomic_read,
+ .open = ecm_ipa_debugfs_atomic_open,
+ .read = ecm_ipa_debugfs_atomic_read,
};
/**
- * ecm_ipa_init() - initializes internal data structures
+ * ecm_ipa_init() - create network device and initializes internal
+ * data structures
+ * @params: in/out parameters required for ecm_ipa initialization
+ *
+ * Shall be called prior to pipe connection.
+ * The out parameters (the callbacks) shall be supplied to ipa_connect.
+ * Detailed description:
+ * - allocate the network device
+ * - set default values for driver internals
+ * - create debugfs folder and files
+ * - create IPA resource manager client
+ * - add header insertion rules for IPA driver (based on host/device
+ * Ethernet addresses given in input params)
+ * - register tx/rx properties to IPA driver (will be later used
+ * by IPA configuration manager to configure reset of the IPA rules)
+ * - set the carrier state to "off" (until ecm_ipa_connect is called)
+ * - register the network device
+ * - set the out parameters
+ *
+ * Returns negative errno, or zero on success
+ */
+int ecm_ipa_init(struct ecm_ipa_params *params)
+{
+ int result = 0;
+ struct net_device *net;
+ struct ecm_ipa_dev *dev;
+
+ ECM_IPA_LOG_ENTRY();
+ pr_debug("%s initializing\n", DRIVER_NAME);
+ NULL_CHECK(params);
+
+ pr_debug("host_ethaddr=%pM, device_ethaddr=%pM\n",
+ params->host_ethaddr,
+ params->device_ethaddr);
+
+ net = alloc_etherdev(sizeof(struct ecm_ipa_dev));
+ if (!net) {
+ result = -ENOMEM;
+ ECM_IPA_ERROR("fail to allocate etherdev\n");
+ goto fail_alloc_etherdev;
+ }
+ pr_debug("network device was successfully allocated\n");
+
+ dev = netdev_priv(net);
+ memset(dev, 0, sizeof(*dev));
+ dev->net = net;
+ ecm_ipa_ctx = dev;
+ dev->tx_enable = true;
+ dev->rx_enable = true;
+ dev->rm_enable = true;
+ dev->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
+ dev->outstanding_low = DEFAULT_OUTSTANDING_LOW;
+ atomic_set(&dev->outstanding_pkts, 0);
+ snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
+ net->netdev_ops = &ecm_ipa_netdev_ops;
+ pr_debug("internal data structures were intialized and defaults set\n");
+
+ result = ecm_ipa_debugfs_init(dev);
+ if (result)
+ goto fail_debugfs;
+ pr_debug("debugfs entries were created\n");
+
+ result = ecm_ipa_create_rm_resource(dev);
+ if (result) {
+ ECM_IPA_ERROR("fail on RM create\n");
+ goto fail_create_rm;
+ }
+ pr_debug("RM resource was created\n");
+
+ result = ecm_ipa_set_device_ethernet_addr(net->dev_addr,
+ params->device_ethaddr);
+ if (result) {
+ ECM_IPA_ERROR("set device MAC failed\n");
+ goto fail_set_device_ethernet;
+ }
+ pr_debug("Device Ethernet address set %pM\n", net->dev_addr);
+
+ result = ecm_ipa_rules_cfg(dev, params->host_ethaddr,
+ params->device_ethaddr);
+ if (result) {
+ ECM_IPA_ERROR("fail on ipa rules set\n");
+ goto fail_rules_cfg;
+ }
+ pr_debug("Ethernet header insertion set\n");
+
+ result = ecm_ipa_register_properties();
+ if (result) {
+ ECM_IPA_ERROR("fail on properties set\n");
+ goto fail_register_tx;
+ }
+ pr_debug("ecm_ipa 2 Tx and 2 Rx properties were registered\n");
+
+ netif_carrier_off(net);
+ pr_debug("set carrier off\n");
+
+ result = register_netdev(net);
+ if (result) {
+ ECM_IPA_ERROR("register_netdev failed: %d\n", result);
+ goto fail_register_netdev;
+ }
+ pr_debug("register_netdev succeeded\n");
+
+ params->ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
+ params->ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
+ params->private = (void *)dev;
+ ECM_IPA_LOG_EXIT();
+
+ return 0;
+
+fail_register_netdev:
+ ecm_ipa_deregister_properties();
+fail_register_tx:
+ ecm_ipa_rules_destroy(dev);
+fail_set_device_ethernet:
+fail_rules_cfg:
+ ecm_ipa_destory_rm_resource(dev);
+fail_create_rm:
+ ecm_ipa_debugfs_destroy(dev);
+fail_debugfs:
+ free_netdev(net);
+fail_alloc_etherdev:
+ return result;
+}
+EXPORT_SYMBOL(ecm_ipa_init);
+
+
+int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
+ void *priv)
+{
+ struct ecm_ipa_dev *dev = priv;
+
+ ECM_IPA_LOG_ENTRY();
+ NULL_CHECK(priv);
+ pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d, priv=0x%p\n",
+ usb_to_ipa_hdl, ipa_to_usb_hdl, priv);
+
+ if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
+ ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
+ usb_to_ipa_hdl);
+ return -EINVAL;
+ }
+ if (!ipa_to_usb_hdl || ipa_to_usb_hdl >= IPA_CLIENT_MAX) {
+ ECM_IPA_ERROR("ipa_to_usb_hdl(%d) is not a valid ipa handle\n",
+ ipa_to_usb_hdl);
+ return -EINVAL;
+ }
+ dev->ipa_to_usb_hdl = ipa_to_usb_hdl;
+ dev->usb_to_ipa_hdl = usb_to_ipa_hdl;
+ ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
+ pr_debug("end-point configured\n");
+
+ netif_carrier_on(dev->net);
+ if (!netif_carrier_ok(dev->net)) {
+ ECM_IPA_ERROR("netif_carrier_ok error\n");
+ return -EBUSY;
+ }
+ pr_debug("carrier_on notified, ecm_ipa is operational\n");
+
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+EXPORT_SYMBOL(ecm_ipa_connect);
+
+static int ecm_ipa_open(struct net_device *net)
+{
+ struct ecm_ipa_dev *dev;
+ ECM_IPA_LOG_ENTRY();
+
+ dev = netdev_priv(net);
+
+ if (!netif_carrier_ok(net))
+ pr_debug("carrier is not ON yet - continuing\n");
+
+ netif_start_queue(net);
+ pr_debug("queue started\n");
+
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+
+/**
+ * ecm_ipa_start_xmit() - send data from APPs to USB core via IPA core
+ * @skb: packet received from Linux stack
+ * @net: the network device being used to send this packet
+ *
+ * Several conditions needed in order to send the packet to IPA:
+ * - we are in a valid state were the queue is not stopped
+ * - Filter Tx switch is turned off
+ * - The resources required for actual Tx are all up
+ *
+ */
+static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
+ struct net_device *net)
+{
+ int ret;
+ netdev_tx_t status = NETDEV_TX_BUSY;
+ struct ecm_ipa_dev *dev = netdev_priv(net);
+
+ if (unlikely(netif_queue_stopped(net))) {
+ ECM_IPA_ERROR("interface queue is stopped\n");
+ goto out;
+ }
+
+ if (unlikely(tx_filter(skb))) {
+ dev_kfree_skb_any(skb);
+ pr_debug("packet got filtered out on Tx path\n");
+ status = NETDEV_TX_OK;
+ goto out;
+ }
+ ret = resource_request(dev);
+ if (ret) {
+ pr_debug("Waiting to resource\n");
+ netif_stop_queue(net);
+ goto resource_busy;
+ }
+
+ if (atomic_read(&dev->outstanding_pkts) >= dev->outstanding_high) {
+ pr_debug("Outstanding high boundary reached (%d)- stopping queue\n",
+ dev->outstanding_high);
+ netif_stop_queue(net);
+ status = -NETDEV_TX_BUSY;
+ goto out;
+ }
+
+ ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
+ if (ret) {
+ ECM_IPA_ERROR("ipa transmit failed (%d)\n", ret);
+ goto fail_tx_packet;
+ }
+
+ atomic_inc(&dev->outstanding_pkts);
+ net->stats.tx_packets++;
+ net->stats.tx_bytes += skb->len;
+ status = NETDEV_TX_OK;
+ goto out;
+
+fail_tx_packet:
+out:
+ resource_release(dev);
+resource_busy:
+ return status;
+}
+
+/**
+ * ecm_ipa_packet_receive_notify() - Rx notify
+ *
+ * @priv: ecm driver context
+ * @evt: event type
+ * @data: data provided with event
+ *
+ * IPA will pass a packet with skb->data pointing to Ethernet packet frame
+ */
+static void ecm_ipa_packet_receive_notify(void *priv,
+ enum ipa_dp_evt_type evt,
+ unsigned long data)
+{
+ struct sk_buff *skb = (struct sk_buff *)data;
+ struct ecm_ipa_dev *dev = priv;
+ int result;
+
+ if (evt != IPA_RECEIVE) {
+ ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
+ return;
+ }
+
+ skb->dev = dev->net;
+ skb->protocol = eth_type_trans(skb, dev->net);
+ if (rx_filter(skb)) {
+ pr_debug("packet got filtered out on Rx path\n");
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
+ result = netif_rx(skb);
+ if (result)
+ ECM_IPA_ERROR("fail on netif_rx\n");
+ dev->net->stats.rx_packets++;
+ dev->net->stats.rx_bytes += skb->len;
+
+ return;
+}
+
+static int ecm_ipa_stop(struct net_device *net)
+{
+ ECM_IPA_LOG_ENTRY();
+ pr_debug("stopping net device\n");
+ netif_stop_queue(net);
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+
+int ecm_ipa_disconnect(void *priv)
+{
+ struct ecm_ipa_dev *dev = priv;
+ ECM_IPA_LOG_ENTRY();
+ NULL_CHECK(dev);
+ pr_debug("priv=0x%p\n", priv);
+ netif_carrier_off(dev->net);
+ ECM_IPA_LOG_EXIT();
+ return 0;
+}
+EXPORT_SYMBOL(ecm_ipa_disconnect);
+
+
+/**
+ * ecm_ipa_cleanup() - destroys all
+ * ecm information
+ * @priv: main driver context parameters
+ *
+ */
+void ecm_ipa_cleanup(void *priv)
+{
+ struct ecm_ipa_dev *dev = priv;
+ ECM_IPA_LOG_ENTRY();
+ pr_debug("priv=0x%p\n", priv);
+ if (!dev) {
+ ECM_IPA_ERROR("dev NULL pointer\n");
+ return;
+ }
+
+ ecm_ipa_destory_rm_resource(dev);
+ ecm_ipa_debugfs_destroy(dev);
+
+ unregister_netdev(dev->net);
+ free_netdev(dev->net);
+
+ pr_debug("cleanup done\n");
+ ecm_ipa_ctx = NULL;
+ ECM_IPA_LOG_EXIT();
+ return ;
+}
+EXPORT_SYMBOL(ecm_ipa_cleanup);
+
+/**
* @ecm_ipa_rx_dp_notify: supplied callback to be called by the IPA
* driver upon data packets received from USB pipe into IPA core.
* @ecm_ipa_rt_dp_notify: supplied callback to be called by the IPA
@@ -183,54 +495,7 @@
*
* Returns negative errno, or zero on success
*/
-int ecm_ipa_init(ecm_ipa_callback *ecm_ipa_rx_dp_notify,
- ecm_ipa_callback *ecm_ipa_tx_dp_notify,
- void **priv)
-{
- int ret = 0;
- struct net_device *net;
- struct ecm_ipa_dev *dev;
- ECM_IPA_LOG_ENTRY();
- pr_debug("%s initializing\n", DRIVER_NAME);
- NULL_CHECK(ecm_ipa_rx_dp_notify);
- NULL_CHECK(ecm_ipa_tx_dp_notify);
- NULL_CHECK(priv);
- pr_debug("rx_cb=0x%p, tx_cb=0x%p priv=0x%p\n",
- ecm_ipa_rx_dp_notify, ecm_ipa_tx_dp_notify, *priv);
- net = alloc_etherdev(sizeof(struct ecm_ipa_dev));
- if (!net) {
- ret = -ENOMEM;
- ECM_IPA_ERROR("fail to allocate etherdev\n");
- goto fail_alloc_etherdev;
- }
- pr_debug("etherdev was successfully allocated\n");
- dev = netdev_priv(net);
- memset(dev, 0, sizeof(*dev));
- dev->tx_enable = true;
- dev->rx_enable = true;
- atomic_set(&dev->outstanding_pkts, 0);
- dev->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
- dev->outstanding_low = DEFAULT_OUTSTANDING_LOW;
- dev->net = net;
- ecm_ipa_ctx = dev;
- *priv = (void *)dev;
- snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
- net->netdev_ops = &ecm_ipa_netdev_ops;
- pr_debug("internal data structures were intialized\n");
- ret = ecm_ipa_debugfs_init(dev);
- if (ret)
- goto fail_debugfs;
- pr_debug("debugfs entries were created\n");
- *ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
- *ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
- ECM_IPA_LOG_EXIT();
- return 0;
-fail_debugfs:
- free_netdev(net);
-fail_alloc_etherdev:
- return ret;
-}
-EXPORT_SYMBOL(ecm_ipa_init);
+
/**
* ecm_ipa_rules_cfg() - set header insertion and register Tx/Rx properties
@@ -406,106 +671,6 @@
*
* Returns negative errno, or zero on success
*/
-int ecm_ipa_configure(u8 host_ethaddr[], u8 device_ethaddr[],
- void *priv)
-{
- struct ecm_ipa_dev *dev = priv;
- struct net_device *net;
- int result;
- ECM_IPA_LOG_ENTRY();
- NULL_CHECK(host_ethaddr);
- NULL_CHECK(host_ethaddr);
- NULL_CHECK(dev);
- net = dev->net;
- NULL_CHECK(net);
- pr_debug("priv=0x%p, host_ethaddr=%pM device_ethaddr=%pM\n",
- priv, host_ethaddr, device_ethaddr);
- result = ecm_ipa_create_rm_resource(dev);
- if (result) {
- ECM_IPA_ERROR("fail on RM create\n");
- return -EINVAL;
- }
- pr_debug("RM resource was created\n");
- netif_carrier_off(dev->net);
- result = ecm_ipa_set_device_ethernet_addr(net->dev_addr,
- device_ethaddr);
- if (result) {
- ECM_IPA_ERROR("set device MAC failed\n");
- goto fail_set_device_ethernet;
- }
- result = ecm_ipa_rules_cfg(dev, host_ethaddr, device_ethaddr);
- if (result) {
- ECM_IPA_ERROR("fail on ipa rules set\n");
- goto fail_set_device_ethernet;
- }
- pr_debug("Ethernet header insertion was set\n");
- result = ecm_ipa_register_properties();
- if (result) {
- ECM_IPA_ERROR("fail on properties set\n");
- goto fail_register_tx;
- }
- pr_debug("ECM 2 Tx and 2 Rx properties were registered\n");
- result = register_netdev(net);
- if (result) {
- ECM_IPA_ERROR("register_netdev failed: %d\n", result);
- goto fail_register_netdev;
- }
- pr_debug("register_netdev succeeded\n");
- ECM_IPA_LOG_EXIT();
- return 0;
-fail_register_netdev:
- ecm_ipa_deregister_properties();
-fail_register_tx:
-fail_set_device_ethernet:
- ecm_ipa_rules_destroy(dev);
- ecm_ipa_destory_rm_resource(dev);
- free_netdev(net);
- return result;
-}
-EXPORT_SYMBOL(ecm_ipa_configure);
-
-int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
- void *priv)
-{
- struct ecm_ipa_dev *dev = priv;
- ECM_IPA_LOG_ENTRY();
- NULL_CHECK(priv);
- pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d, priv=0x%p\n",
- usb_to_ipa_hdl, ipa_to_usb_hdl, priv);
- if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
- ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
- usb_to_ipa_hdl);
- return -EINVAL;
- }
- if (!ipa_to_usb_hdl || ipa_to_usb_hdl >= IPA_CLIENT_MAX) {
- ECM_IPA_ERROR("ipa_to_usb_hdl(%d) is not a valid ipa handle\n",
- ipa_to_usb_hdl);
- return -EINVAL;
- }
- dev->ipa_to_usb_hdl = ipa_to_usb_hdl;
- dev->usb_to_ipa_hdl = usb_to_ipa_hdl;
- ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
- netif_carrier_on(dev->net);
- if (!netif_carrier_ok(dev->net)) {
- ECM_IPA_ERROR("netif_carrier_ok error\n");
- return -EBUSY;
- }
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-EXPORT_SYMBOL(ecm_ipa_connect);
-
-int ecm_ipa_disconnect(void *priv)
-{
- struct ecm_ipa_dev *dev = priv;
- ECM_IPA_LOG_ENTRY();
- NULL_CHECK(dev);
- pr_debug("priv=0x%p\n", priv);
- netif_carrier_off(dev->net);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-EXPORT_SYMBOL(ecm_ipa_disconnect);
static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
@@ -567,12 +732,18 @@
static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *dev)
{
+ int result;
+
ECM_IPA_LOG_ENTRY();
+
if (!dev->rm_enable)
return;
ipa_rm_delete_dependency(IPA_RM_RESOURCE_STD_ECM_PROD,
IPA_RM_RESOURCE_USB_CONS);
ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_STD_ECM_PROD);
+ result = ipa_rm_delete_resource(IPA_RM_RESOURCE_STD_ECM_PROD);
+ if (result)
+ ECM_IPA_ERROR("resource deletion failed\n");
ECM_IPA_LOG_EXIT();
}
@@ -594,52 +765,6 @@
return dev->rm_enable;
}
-static int ecm_ipa_open(struct net_device *net)
-{
- ECM_IPA_LOG_ENTRY();
- netif_start_queue(net);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-
-static int ecm_ipa_stop(struct net_device *net)
-{
- ECM_IPA_LOG_ENTRY();
- pr_debug("stopping net device\n");
- netif_stop_queue(net);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-
-/**
- * ecm_ipa_cleanup() - destroys all
- * ecm information
- * @priv: main driver context parameters
- *
- */
-void ecm_ipa_cleanup(void *priv)
-{
- struct ecm_ipa_dev *dev = priv;
- ECM_IPA_LOG_ENTRY();
- pr_debug("priv=0x%p\n", priv);
- if (!dev) {
- ECM_IPA_ERROR("dev NULL pointer\n");
- return;
- }
-
- ecm_ipa_destory_rm_resource(dev);
- ecm_ipa_debugfs_destroy(dev);
-
- unregister_netdev(dev->net);
- free_netdev(dev->net);
-
- pr_debug("cleanup done\n");
- ecm_ipa_ctx = NULL;
- ECM_IPA_LOG_EXIT();
- return ;
-}
-EXPORT_SYMBOL(ecm_ipa_cleanup);
-
static int resource_request(struct ecm_ipa_dev *dev)
{
int result = 0;
@@ -662,108 +787,6 @@
}
/**
- * ecm_ipa_start_xmit() - send data from APPs to USB core via IPA core
- * @skb: packet received from Linux stack
- * @net: the network device being used to send this packet
- *
- * Several conditions needed in order to send the packet to IPA:
- * - we are in a valid state were the queue is not stopped
- * - Filter Tx switch is turned off
- * - The resources required for actual Tx are all up
- *
- */
-static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
- struct net_device *net)
-{
- int ret;
- netdev_tx_t status = NETDEV_TX_BUSY;
- struct ecm_ipa_dev *dev = netdev_priv(net);
-
- if (unlikely(netif_queue_stopped(net))) {
- ECM_IPA_ERROR("interface queue is stopped\n");
- goto out;
- }
-
- if (unlikely(tx_filter(skb))) {
- dev_kfree_skb_any(skb);
- pr_debug("packet got filtered out on Tx path\n");
- status = NETDEV_TX_OK;
- goto out;
- }
- ret = resource_request(dev);
- if (ret) {
- pr_debug("Waiting to resource\n");
- netif_stop_queue(net);
- goto resource_busy;
- }
-
- if (atomic_read(&dev->outstanding_pkts) >= dev->outstanding_high) {
- pr_debug("Outstanding high boundary reached (%d)- stopping queue\n",
- dev->outstanding_high);
- netif_stop_queue(net);
- status = -NETDEV_TX_BUSY;
- goto out;
- }
-
- ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
- if (ret) {
- ECM_IPA_ERROR("ipa transmit failed (%d)\n", ret);
- goto fail_tx_packet;
- }
-
- atomic_inc(&dev->outstanding_pkts);
- net->stats.tx_packets++;
- net->stats.tx_bytes += skb->len;
- status = NETDEV_TX_OK;
- goto out;
-
-fail_tx_packet:
-out:
- resource_release(dev);
-resource_busy:
- return status;
-}
-
-/**
- * ecm_ipa_packet_receive_notify() - Rx notify
- *
- * @priv: ecm driver context
- * @evt: event type
- * @data: data provided with event
- *
- * IPA will pass a packet with skb->data pointing to Ethernet packet frame
- */
-void ecm_ipa_packet_receive_notify(void *priv,
- enum ipa_dp_evt_type evt,
- unsigned long data)
-{
- struct sk_buff *skb = (struct sk_buff *)data;
- struct ecm_ipa_dev *dev = priv;
- int result;
-
- if (evt != IPA_RECEIVE) {
- ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
- return;
- }
-
- skb->dev = dev->net;
- skb->protocol = eth_type_trans(skb, dev->net);
- if (rx_filter(skb)) {
- pr_debug("packet got filtered out on Rx path\n");
- dev_kfree_skb_any(skb);
- return;
- }
-
- result = netif_rx(skb);
- if (result)
- ECM_IPA_ERROR("fail on netif_rx\n");
- dev->net->stats.rx_packets++;
- dev->net->stats.rx_bytes += skb->len;
-
- return;
-}
-
-/**
* ecm_ipa_tx_complete_notify() - Rx notify
*
* @priv: ecm driver context
@@ -773,7 +796,7 @@
* Check that the packet is the one we sent and release it
* This function will be called in defered context in IPA wq.
*/
-void ecm_ipa_tx_complete_notify(void *priv,
+static void ecm_ipa_tx_complete_notify(void *priv,
enum ipa_dp_evt_type evt,
unsigned long data)
{
@@ -800,33 +823,6 @@
return;
}
-static int ecm_ipa_debugfs_tx_open(struct inode *inode, struct file *file)
-{
- struct ecm_ipa_dev *dev = inode->i_private;
- ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->tx_enable);
- ECM_IPA_LOG_ENTRY();
- return 0;
-}
-
-static int ecm_ipa_debugfs_rx_open(struct inode *inode, struct file *file)
-{
- struct ecm_ipa_dev *dev = inode->i_private;
- ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->rx_enable);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-
-static int ecm_ipa_debugfs_rm_open(struct inode *inode, struct file *file)
-{
- struct ecm_ipa_dev *dev = inode->i_private;
- ECM_IPA_LOG_ENTRY();
- file->private_data = &(dev->rm_enable);
- ECM_IPA_LOG_EXIT();
- return 0;
-}
-
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
{
struct ecm_ipa_dev *dev = inode->i_private;
@@ -921,7 +917,7 @@
static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev)
{
- const mode_t flags = S_IRUGO | S_IWUGO;
+ const mode_t flags_read_write = S_IRUGO | S_IWUGO;
const mode_t flags_read_only = S_IRUGO;
struct dentry *file;
@@ -935,46 +931,44 @@
ECM_IPA_ERROR("could not create debugfs directory entry\n");
goto fail_directory;
}
- file = debugfs_create_file("tx_enable", flags, dev->directory, dev,
- &ecm_ipa_debugfs_tx_ops);
+ file = debugfs_create_bool("tx_enable", flags_read_write,
+ dev->directory, &dev->tx_enable);
if (!file) {
ECM_IPA_ERROR("could not create debugfs tx file\n");
goto fail_file;
}
- file = debugfs_create_file("rx_enable", flags, dev->directory, dev,
- &ecm_ipa_debugfs_rx_ops);
+ file = debugfs_create_bool("rx_enable", flags_read_write,
+ dev->directory, &dev->rx_enable);
if (!file) {
ECM_IPA_ERROR("could not create debugfs rx file\n");
goto fail_file;
}
- file = debugfs_create_file("rm_enable", flags, dev->directory, dev,
- &ecm_ipa_debugfs_rm_ops);
+ file = debugfs_create_bool("rm_enable", flags_read_write,
+ dev->directory, &dev->rm_enable);
if (!file) {
ECM_IPA_ERROR("could not create debugfs rm file\n");
goto fail_file;
}
- file = debugfs_create_file("dma_enable", flags, dev->directory,
- dev, &ecm_ipa_debugfs_dma_ops);
- if (!file) {
- ECM_IPA_ERROR("could not create debugfs dma file\n");
- goto fail_file;
- }
-
- file = debugfs_create_u8("outstanding_high",
- flags, dev->directory, &dev->outstanding_high);
+ file = debugfs_create_u8("outstanding_high", flags_read_write,
+ dev->directory, &dev->outstanding_high);
if (!file) {
ECM_IPA_ERROR("could not create outstanding_high file\n");
goto fail_file;
}
- file = debugfs_create_u8("outstanding_low",
- flags, dev->directory, &dev->outstanding_low);
+ file = debugfs_create_u8("outstanding_low", flags_read_write,
+ dev->directory, &dev->outstanding_low);
if (!file) {
ECM_IPA_ERROR("could not create outstanding_low file\n");
goto fail_file;
}
- file = debugfs_create_file("outstanding",
- flags_read_only, dev->directory, dev,
- &ecm_ipa_debugfs_atomic_ops);
+ file = debugfs_create_file("dma_enable", flags_read_write,
+ dev->directory, dev, &ecm_ipa_debugfs_dma_ops);
+ if (!file) {
+ ECM_IPA_ERROR("could not create debugfs dma file\n");
+ goto fail_file;
+ }
+ file = debugfs_create_file("outstanding", flags_read_only,
+ dev->directory, dev, &ecm_ipa_debugfs_atomic_ops);
if (!file) {
ECM_IPA_ERROR("could not create outstanding file\n");
goto fail_file;
@@ -993,15 +987,6 @@
debugfs_remove_recursive(dev->directory);
}
-static void eth_get_drvinfo(struct net_device *net,
- struct ethtool_drvinfo *drv_info)
-{
- ECM_IPA_LOG_ENTRY();
- strlcpy(drv_info->driver, DRIVER_NAME, sizeof(drv_info->driver));
- ECM_IPA_LOG_EXIT();
-}
-
-
/**
* ecm_ipa_ep_cfg() - configure the USB endpoints for ECM
*
@@ -1017,7 +1002,7 @@
* - No aggregation
* - Add Ethernet header
*/
-int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl)
+static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl)
{
int result = 0;
struct ipa_ep_cfg usb_to_ipa_ep_cfg;
@@ -1059,7 +1044,7 @@
* which is needed for cores that does not support blocks logic
* Note that client handles are the actual pipe index
*/
-int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl)
+static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl)
{
int result = 0;
struct ipa_ep_cfg_mode cfg_mode;
@@ -1095,7 +1080,8 @@
*
* Returns 0 for success, negative otherwise
*/
-int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr, u8 device_ethaddr[])
+static int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
+ u8 device_ethaddr[])
{
if (!is_valid_ether_addr(device_ethaddr))
return -EINVAL;
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 466e694..35b2561 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -778,66 +778,6 @@
return ret;
}
-static int ipa_handle_tx_poll_for_pipe(struct ipa_sys_context *sys,
- bool process_all)
-{
- struct ipa_tx_pkt_wrapper *tx_pkt, *t;
- struct sps_iovec iov;
- unsigned long irq_flags;
- int ret;
- int cnt = 0;
-
- do {
- iov.addr = 0;
- ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
- if (ret) {
- pr_err("%s: sps_get_iovec failed %d\n", __func__, ret);
- break;
- }
- if (!iov.addr)
- break;
- spin_lock_irqsave(&sys->spinlock, irq_flags);
- tx_pkt = list_first_entry(&sys->head_desc_list,
- struct ipa_tx_pkt_wrapper, link);
- spin_unlock_irqrestore(&sys->spinlock, irq_flags);
-
- switch (tx_pkt->cnt) {
- case 1:
- ipa_wq_write_done(&tx_pkt->work);
- ++cnt;
- break;
- case 0xFFFF:
- /* reached end of set */
- spin_lock_irqsave(&sys->spinlock, irq_flags);
- list_for_each_entry_safe(tx_pkt, t,
- &sys->wait_desc_list, link) {
- list_del(&tx_pkt->link);
- list_add(&tx_pkt->link, &sys->head_desc_list);
- }
- tx_pkt =
- list_first_entry(&sys->head_desc_list,
- struct ipa_tx_pkt_wrapper, link);
- spin_unlock_irqrestore(&sys->spinlock, irq_flags);
- ipa_wq_write_done(&tx_pkt->work);
- ++cnt;
- break;
- default:
- /* keep looping till reach the end of the set */
- spin_lock_irqsave(&sys->spinlock,
- irq_flags);
- list_del(&tx_pkt->link);
- list_add_tail(&tx_pkt->link,
- &sys->wait_desc_list);
- spin_unlock_irqrestore(&sys->spinlock,
- irq_flags);
- ++cnt;
- break;
- }
- } while (process_all);
-
- return cnt;
-}
-
static void ipa_poll_function(struct work_struct *work)
{
int ret;
@@ -857,13 +797,15 @@
/* check all the system pipes for tx comp and rx avail */
if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
- cnt |= ipa_handle_rx_core(false, true);
+ cnt |= ipa_handle_rx_core(
+ &ipa_ctx->sys[IPA_A5_LAN_WAN_IN],
+ false, true);
for (i = 0; i < num_tx_pipes; i++)
if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
- cnt |= ipa_handle_tx_poll_for_pipe(
+ cnt |= ipa_handle_tx_core(
&ipa_ctx->sys[tx_pipes[i]],
- false);
+ false, true);
} while (cnt);
/* re-post the poll work */
@@ -1666,10 +1608,6 @@
IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
ipa_ctx->polling_mode = polling_mode;
- if (ipa_ctx->polling_mode)
- atomic_set(&ipa_ctx->curr_polling_state, 1);
- else
- atomic_set(&ipa_ctx->curr_polling_state, 0);
IPADBG("hdr_lcl=%u ip4_rt=%u ip6_rt=%u ip4_flt=%u ip6_flt=%u\n",
hdr_tbl_lcl, ip4_rt_tbl_lcl, ip6_rt_tbl_lcl, ip4_flt_tbl_lcl,
ip6_flt_tbl_lcl);
@@ -1891,7 +1829,10 @@
ipa_ctx->sys[i].ep = &ipa_ctx->ep[i];
else
ipa_ctx->sys[i].ep = &ipa_ctx->ep[WLAN_AMPDU_TX_EP];
- INIT_LIST_HEAD(&ipa_ctx->sys[i].wait_desc_list);
+ if (ipa_ctx->polling_mode)
+ atomic_set(&ipa_ctx->sys[i].curr_polling_state, 1);
+ else
+ atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
}
ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
@@ -1901,7 +1842,8 @@
goto fail_rx_wq;
}
- ipa_ctx->tx_wq = create_singlethread_workqueue("ipa tx wq");
+ ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
+ WQ_CPU_INTENSIVE, 2);
if (!ipa_ctx->tx_wq) {
IPAERR(":fail to create tx wq\n");
result = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index a78879d..a95eafe 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -15,18 +15,14 @@
static void ipa_enable_data_path(u32 clnt_hdl)
{
- struct ipa_ep_context *ep = &ipa_ctx->ep[clnt_hdl];
-
if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_VIRTUAL) {
/* IPA_HW_MODE_VIRTUAL lacks support for TAG IC & EP suspend */
return;
}
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && ep->suspended) {
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1)
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 0);
- ep->suspended = false;
- }
}
static int ipa_disable_data_path(u32 clnt_hdl)
@@ -50,7 +46,7 @@
goto fail_alloc;
}
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1 && !ep->suspended) {
+ if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1) {
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_CTRL_n_OFST(clnt_hdl), 1);
@@ -85,7 +81,6 @@
ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
ep->cfg.aggr.aggr_time_limit)
msleep(ep->cfg.aggr.aggr_time_limit);
- ep->suspended = true;
}
return 0;
@@ -298,7 +293,9 @@
if (in->client == IPA_CLIENT_HSIC1_CONS ||
in->client == IPA_CLIENT_HSIC2_CONS ||
in->client == IPA_CLIENT_HSIC3_CONS ||
- in->client == IPA_CLIENT_HSIC4_CONS) {
+ in->client == IPA_CLIENT_HSIC4_CONS ||
+ in->client == IPA_CLIENT_A2_TETHERED_CONS ||
+ in->client == IPA_CLIENT_A2_EMBEDDED_CONS) {
IPADBG("disable holb for ep=%d tmr=%d\n", ipa_ep_idx,
ipa_ctx->hol_timer);
ipa_write_reg(ipa_ctx->mmio,
@@ -367,6 +364,11 @@
ep = &ipa_ctx->ep[clnt_hdl];
+ if (ep->suspended) {
+ ipa_inc_client_enable_clks();
+ ep->suspended = false;
+ }
+
result = ipa_disable_data_path(clnt_hdl);
if (result) {
IPAERR("disable data path failed res=%d clnt=%d.\n", result,
@@ -422,55 +424,79 @@
EXPORT_SYMBOL(ipa_disconnect);
/**
- * ipa_connection_suspend() - suspend B2B connection to/from IPA
+ * ipa_resume() - low-level IPA client resume
* @clnt_hdl: [in] opaque client handle assigned by IPA to client
*
- * Should be called by the driver of the peripheral that wants to suspend
- * its BAM-BAM connection to/from IPA in BAM-BAM mode. The pipe is not
- * disconnected and must later be resumed before data transfer can begin
+ * Should be called by the driver of the peripheral that wants to resume IPA
+ * connection. Resume IPA connection results in turning on IPA clocks in
+ * case they were off as a result of suspend.
+ * this api can be called only if a call to ipa_suspend() was
+ * made.
*
* Returns: 0 on success, negative on failure
*
* Note: Should not be called from atomic context
*/
-int ipa_connection_suspend(u32 clnt_hdl)
+int ipa_resume(u32 clnt_hdl)
{
- int result;
+ struct ipa_ep_context *ep;
if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
- IPAERR("bad parm.\n");
- return -EINVAL;
- }
- result = ipa_disable_data_path(clnt_hdl);
- if (result)
- IPAERR("disable data path failed res=%d clnt=%d.\n", result,
- clnt_hdl);
-
- return result;
-}
-EXPORT_SYMBOL(ipa_connection_suspend);
-
-/**
- * ipa_connection_resume() - resume B2B connection to/from IPA
- * @clnt_hdl: [in] opaque client handle assigned by IPA to client
- *
- * Should be called by the driver of the peripheral that wants to resume
- * its previously suspended BAM-BAM connection to/from IPA in BAM-BAM mode.
- *
- * Returns: 0 on success, negative on failure
- *
- * Note: Should not be called from atomic context
- */
-int ipa_connection_resume(u32 clnt_hdl)
-{
- if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
- IPAERR("bad parm.\n");
+ IPAERR("bad parm. clnt_hdl %d\n", clnt_hdl);
return -EINVAL;
}
- ipa_enable_data_path(clnt_hdl);
+ ep = &ipa_ctx->ep[clnt_hdl];
+
+ if (!ep->suspended) {
+ IPAERR("EP not suspended. clnt_hdl %d\n", clnt_hdl);
+ return -EPERM;
+ }
+
+ ipa_inc_client_enable_clks();
+ ep->suspended = false;
return 0;
}
-EXPORT_SYMBOL(ipa_connection_resume);
+EXPORT_SYMBOL(ipa_resume);
+/**
+* ipa_suspend() - low-level IPA client suspend
+* @clnt_hdl: [in] opaque client handle assigned by IPA to client
+*
+* Should be called by the driver of the peripheral that wants to suspend IPA
+* connection. Suspend IPA connection results in turning off IPA clocks in
+* case that there is no active clients using IPA. Pipes remains connected in
+* case of suspend.
+*
+* Returns: 0 on success, negative on failure
+*
+* Note: Should not be called from atomic context
+*/
+int ipa_suspend(u32 clnt_hdl)
+{
+ struct ipa_ep_context *ep;
+
+ if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) {
+ IPAERR("bad parm. clnt_hdl %d\n", clnt_hdl);
+ return -EINVAL;
+ }
+
+ ep = &ipa_ctx->ep[clnt_hdl];
+
+ if (ep->suspended) {
+ IPAERR("EP already suspended. clnt_hdl %d\n", clnt_hdl);
+ return -EPERM;
+ }
+
+ if (IPA_CLIENT_IS_CONS(ep->client) &&
+ ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR &&
+ ep->cfg.aggr.aggr_time_limit)
+ msleep(ep->cfg.aggr.aggr_time_limit);
+
+ ipa_dec_client_disable_clks();
+ ep->suspended = true;
+
+ return 0;
+}
+EXPORT_SYMBOL(ipa_suspend);
diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c
index fb69817..b11c7da 100644
--- a/drivers/platform/msm/ipa/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_debugfs.c
@@ -104,6 +104,7 @@
static struct dentry *dfile_stats;
static struct dentry *dfile_dbg_cnt;
static struct dentry *dfile_msg;
+static struct dentry *dfile_ip4_nat;
static char dbg_buff[IPA_MAX_MSG_LEN];
static s8 ep_reg_idx;
@@ -608,6 +609,7 @@
"rx=%u\n"
"rx_repl_repost=%u\n"
"x_intr_repost=%u\n"
+ "x_intr_repost_tx=%u\n"
"rx_q_len=%u\n"
"act_clnt=%u\n"
"con_clnt_bmap=0x%x\n"
@@ -622,6 +624,7 @@
ipa_ctx->stats.rx_pkts,
ipa_ctx->stats.rx_repl_repost,
ipa_ctx->stats.x_intr_repost,
+ ipa_ctx->stats.x_intr_repost_tx,
ipa_ctx->stats.rx_q_len,
ipa_ctx->ipa_active_clients,
connect,
@@ -720,6 +723,238 @@
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
+static ssize_t ipa_read_nat4(struct file *file,
+ char __user *ubuf, size_t count,
+ loff_t *ppos) {
+
+#define ENTRY_U32_FIELDS 8
+#define NAT_ENTRY_ENABLE 0x8000
+#define NAT_ENTRY_RST_FIN_BIT 0x4000
+#define BASE_TABLE 0
+#define EXPANSION_TABLE 1
+
+ u32 *base_tbl, *indx_tbl;
+ u32 tbl_size, *tmp;
+ u32 value, i, j, rule_id;
+ u16 enable, tbl_entry, flag;
+ int nbytes, cnt;
+
+ cnt = 0;
+ value = ipa_ctx->nat_mem.public_ip_addr;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Table IP Address:%d.%d.%d.%d\n",
+ ((value & 0xFF000000) >> 24),
+ ((value & 0x00FF0000) >> 16),
+ ((value & 0x0000FF00) >> 8),
+ ((value & 0x000000FF)));
+ cnt += nbytes;
+
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Table Size:%d\n",
+ ipa_ctx->nat_mem.size_base_tables);
+ cnt += nbytes;
+
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Expansion Table Size:%d\n",
+ ipa_ctx->nat_mem.size_expansion_tables);
+ cnt += nbytes;
+
+ if (!ipa_ctx->nat_mem.is_sys_mem) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Not supported for local(shared) memory\n");
+ cnt += nbytes;
+
+ return simple_read_from_buffer(ubuf, count,
+ ppos, dbg_buff, cnt);
+ }
+
+
+ /* Print Base tables */
+ rule_id = 0;
+ for (j = 0; j < 2; j++) {
+ if (j == BASE_TABLE) {
+ tbl_size = ipa_ctx->nat_mem.size_base_tables;
+ base_tbl = (u32 *)ipa_ctx->nat_mem.ipv4_rules_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nBase Table:\n");
+ cnt += nbytes;
+ } else {
+ tbl_size = ipa_ctx->nat_mem.size_expansion_tables;
+ base_tbl =
+ (u32 *)ipa_ctx->nat_mem.ipv4_expansion_rules_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nExpansion Base Table:\n");
+ cnt += nbytes;
+ }
+
+ if (base_tbl != NULL) {
+ for (i = 0; i <= tbl_size; i++, rule_id++) {
+ tmp = base_tbl;
+ value = tmp[4];
+ enable = ((value & 0xFFFF0000) >> 16);
+
+ if (enable & NAT_ENTRY_ENABLE) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Rule:%d ",
+ rule_id);
+ cnt += nbytes;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Private_IP:%d.%d.%d.%d ",
+ ((value & 0xFF000000) >> 24),
+ ((value & 0x00FF0000) >> 16),
+ ((value & 0x0000FF00) >> 8),
+ ((value & 0x000000FF)));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Target_IP:%d.%d.%d.%d ",
+ ((value & 0xFF000000) >> 24),
+ ((value & 0x00FF0000) >> 16),
+ ((value & 0x0000FF00) >> 8),
+ ((value & 0x000000FF)));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Next_Index:%d Public_Port:%d ",
+ (value & 0x0000FFFF),
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Private_Port:%d Target_Port:%d ",
+ (value & 0x0000FFFF),
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "IP-CKSM-delta:0x%x ",
+ (value & 0x0000FFFF));
+ cnt += nbytes;
+
+ flag = ((value & 0xFFFF0000) >> 16);
+ if (flag & NAT_ENTRY_RST_FIN_BIT) {
+ nbytes =
+ scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "IP_CKSM_delta:0x%x Flags:%s ",
+ (value & 0x0000FFFF),
+ "Direct_To_A5");
+ cnt += nbytes;
+ } else {
+ nbytes =
+ scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "IP_CKSM_delta:0x%x Flags:%s ",
+ (value & 0x0000FFFF),
+ "Fwd_to_route");
+ cnt += nbytes;
+ }
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Time_stamp:0x%x Proto:%d ",
+ (value & 0x00FFFFFF),
+ ((value & 0xFF000000) >> 27));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Prev_Index:%d Indx_tbl_entry:%d ",
+ (value & 0x0000FFFF),
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ tmp++;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "TCP_UDP_cksum_delta:0x%x\n",
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ }
+
+ base_tbl += ENTRY_U32_FIELDS;
+
+ }
+ }
+ }
+
+ /* Print Index tables */
+ rule_id = 0;
+ for (j = 0; j < 2; j++) {
+ if (j == BASE_TABLE) {
+ tbl_size = ipa_ctx->nat_mem.size_base_tables;
+ indx_tbl = (u32 *)ipa_ctx->nat_mem.index_table_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nIndex Table:\n");
+ cnt += nbytes;
+ } else {
+ tbl_size = ipa_ctx->nat_mem.size_expansion_tables;
+ indx_tbl =
+ (u32 *)ipa_ctx->nat_mem.index_table_expansion_addr;
+
+ nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN,
+ "\nExpansion Index Table:\n");
+ cnt += nbytes;
+ }
+
+ if (indx_tbl != NULL) {
+ for (i = 0; i <= tbl_size; i++, rule_id++) {
+ tmp = indx_tbl;
+ value = *tmp;
+ tbl_entry = (value & 0x0000FFFF);
+
+ if (tbl_entry) {
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Rule:%d ",
+ rule_id);
+ cnt += nbytes;
+
+ value = *tmp;
+ nbytes = scnprintf(dbg_buff + cnt,
+ IPA_MAX_MSG_LEN,
+ "Table_Entry:%d Next_Index:%d\n",
+ tbl_entry,
+ ((value & 0xFFFF0000) >> 16));
+ cnt += nbytes;
+ }
+
+ indx_tbl++;
+ }
+ }
+ }
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
const struct file_operations ipa_gen_reg_ops = {
.read = ipa_read_gen_reg,
};
@@ -763,6 +998,10 @@
.write = ipa_write_dbg_cnt,
};
+const struct file_operations ipa_nat4_ops = {
+ .read = ipa_read_nat4,
+};
+
void ipa_debugfs_init(void)
{
const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
@@ -860,6 +1099,13 @@
goto fail;
}
+ dfile_ip4_nat = debugfs_create_file("ip4_nat", read_only_mode, dent,
+ 0, &ipa_nat4_ops);
+ if (!dfile_ip4_nat || IS_ERR(dfile_ip4_nat)) {
+ IPAERR("fail to create file for debug_fs ip4 nat\n");
+ goto fail;
+ }
+
return;
fail:
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index 228c77fe..67728c2 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -20,14 +20,15 @@
#define list_next_entry(pos, member) \
list_entry(pos->member.next, typeof(*pos), member)
#define IPA_LAST_DESC_CNT 0xFFFF
-#define POLLING_INACTIVITY 40
-#define POLLING_MIN_SLEEP 950
-#define POLLING_MAX_SLEEP 1050
+#define POLLING_INACTIVITY_RX 40
+#define POLLING_MIN_SLEEP_RX 950
+#define POLLING_MAX_SLEEP_RX 1050
+#define POLLING_INACTIVITY_TX 40
+#define POLLING_MIN_SLEEP_TX 400
+#define POLLING_MAX_SLEEP_TX 500
static void replenish_rx_work_func(struct work_struct *work);
static struct delayed_work replenish_rx_work;
-static void switch_to_intr_work_func(struct work_struct *work);
-static struct delayed_work switch_to_intr_work;
static void ipa_wq_handle_rx(struct work_struct *work);
static DECLARE_WORK(rx_work, ipa_wq_handle_rx);
@@ -47,57 +48,164 @@
void ipa_wq_write_done(struct work_struct *work)
{
struct ipa_tx_pkt_wrapper *tx_pkt;
- struct ipa_tx_pkt_wrapper *next_pkt;
struct ipa_tx_pkt_wrapper *tx_pkt_expected;
unsigned long irq_flags;
- struct ipa_mem_buffer mult = { 0 };
- int i;
- u32 cnt;
tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
- cnt = tx_pkt->cnt;
- IPADBG("cnt=%d\n", cnt);
- if (unlikely(cnt == 0))
+ if (unlikely(tx_pkt == NULL))
WARN_ON(1);
+ WARN_ON(tx_pkt->cnt != 1);
- if (cnt > 1 && cnt != IPA_LAST_DESC_CNT)
- mult = tx_pkt->mult;
+ spin_lock_irqsave(&tx_pkt->sys->spinlock, irq_flags);
+ tx_pkt_expected = list_first_entry(&tx_pkt->sys->head_desc_list,
+ struct ipa_tx_pkt_wrapper,
+ link);
+ if (unlikely(tx_pkt != tx_pkt_expected)) {
+ spin_unlock_irqrestore(&tx_pkt->sys->spinlock,
+ irq_flags);
+ WARN_ON(1);
+ }
+ list_del(&tx_pkt->link);
+ spin_unlock_irqrestore(&tx_pkt->sys->spinlock, irq_flags);
+ if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+ dma_pool_free(ipa_ctx->dma_pool,
+ tx_pkt->bounce,
+ tx_pkt->mem.phys_base);
+ } else {
+ dma_unmap_single(NULL, tx_pkt->mem.phys_base,
+ tx_pkt->mem.size,
+ DMA_TO_DEVICE);
+ }
- for (i = 0; i < cnt; i++) {
- if (unlikely(tx_pkt == NULL))
- WARN_ON(1);
- spin_lock_irqsave(&tx_pkt->sys->spinlock, irq_flags);
- tx_pkt_expected = list_first_entry(&tx_pkt->sys->head_desc_list,
- struct ipa_tx_pkt_wrapper,
- link);
- if (unlikely(tx_pkt != tx_pkt_expected)) {
- spin_unlock_irqrestore(&tx_pkt->sys->spinlock,
- irq_flags);
- WARN_ON(1);
+ if (tx_pkt->callback)
+ tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+
+ kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+}
+
+int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state)
+{
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ struct sps_iovec iov;
+ int ret;
+ int cnt = 0;
+ unsigned long irq_flags;
+
+ while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
+ !atomic_read(&sys->curr_polling_state))) {
+ if (cnt && !process_all)
+ break;
+ ret = sps_get_iovec(sys->ep->ep_hdl, &iov);
+ if (ret) {
+ IPAERR("sps_get_iovec failed %d\n", ret);
+ break;
}
- next_pkt = list_next_entry(tx_pkt, link);
+
+ if (iov.addr == 0)
+ break;
+
+ if (unlikely(list_empty(&sys->head_desc_list)))
+ continue;
+
+ spin_lock_irqsave(&sys->spinlock, irq_flags);
+ tx_pkt = list_first_entry(&sys->head_desc_list,
+ struct ipa_tx_pkt_wrapper, link);
+
+ sys->len--;
list_del(&tx_pkt->link);
- spin_unlock_irqrestore(&tx_pkt->sys->spinlock, irq_flags);
- if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+ spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+
+ IPADBG("--curr_cnt=%d\n", sys->len);
+
+ if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
dma_pool_free(ipa_ctx->dma_pool,
tx_pkt->bounce,
tx_pkt->mem.phys_base);
- } else {
+ else
dma_unmap_single(NULL, tx_pkt->mem.phys_base,
tx_pkt->mem.size,
DMA_TO_DEVICE);
- }
if (tx_pkt->callback)
tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+ if (tx_pkt->cnt > 1 && tx_pkt->cnt != IPA_LAST_DESC_CNT)
+ dma_pool_free(ipa_ctx->dma_pool, tx_pkt->mult.base,
+ tx_pkt->mult.phys_base);
+
kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
- tx_pkt = next_pkt;
+ cnt++;
+ };
+
+ return cnt;
+}
+
+/**
+ * ipa_tx_switch_to_intr_mode() - Operate the Tx data path in interrupt mode
+ */
+static void ipa_tx_switch_to_intr_mode(struct ipa_sys_context *sys)
+{
+ int ret;
+
+ if (!atomic_read(&sys->curr_polling_state)) {
+ IPAERR("already in intr mode\n");
+ goto fail;
}
- if (mult.phys_base)
- dma_pool_free(ipa_ctx->dma_pool, mult.base, mult.phys_base);
+ ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_get_config() failed %d\n", ret);
+ goto fail;
+ }
+ sys->event.options = SPS_O_EOT;
+ ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
+ if (ret) {
+ IPAERR("sps_register_event() failed %d\n", ret);
+ goto fail;
+ }
+ sys->ep->connect.options =
+ SPS_O_AUTO_ENABLE | SPS_O_ACK_TRANSFERS | SPS_O_EOT;
+ ret = sps_set_config(sys->ep->ep_hdl, &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_set_config() failed %d\n", ret);
+ goto fail;
+ }
+ atomic_set(&sys->curr_polling_state, 0);
+ ipa_handle_tx_core(sys, true, false);
+ return;
+
+fail:
+ IPA_STATS_INC_CNT(ipa_ctx->stats.x_intr_repost_tx);
+ schedule_delayed_work(&sys->switch_to_intr_work, msecs_to_jiffies(1));
+ return;
+}
+
+static void ipa_handle_tx(struct ipa_sys_context *sys)
+{
+ int inactive_cycles = 0;
+ int cnt;
+
+ do {
+ cnt = ipa_handle_tx_core(sys, true, true);
+ if (cnt == 0) {
+ inactive_cycles++;
+ usleep_range(POLLING_MIN_SLEEP_TX,
+ POLLING_MAX_SLEEP_TX);
+ } else {
+ inactive_cycles = 0;
+ }
+ } while (inactive_cycles <= POLLING_INACTIVITY_TX);
+
+ ipa_tx_switch_to_intr_mode(sys);
+}
+
+static void ipa_wq_handle_tx(struct work_struct *work)
+{
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
+ ipa_handle_tx(tx_pkt->sys);
}
/**
@@ -165,7 +273,6 @@
}
INIT_LIST_HEAD(&tx_pkt->link);
- INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
tx_pkt->type = desc->type;
tx_pkt->cnt = 1; /* only 1 desc in this "set" */
@@ -187,10 +294,15 @@
IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
desc->opcode, desc->len, sps_flags);
IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
+ INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
} else {
len = desc->len;
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
}
+ if (unlikely(ipa_ctx->polling_mode))
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
+
spin_lock_irqsave(&sys->spinlock, irq_flags);
list_add_tail(&tx_pkt->link, &sys->head_desc_list);
result = sps_transfer_one(sys->ep->ep_hdl, dma_address, len, tx_pkt,
@@ -286,7 +398,7 @@
tx_pkt->mult.base = transfer.iovec;
tx_pkt->mult.size = size;
tx_pkt->cnt = num_desc;
- INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
}
iovec = &transfer.iovec[i];
@@ -475,6 +587,49 @@
/**
* ipa_sps_irq_tx_notify() - Callback function which will be called by
+ * the SPS driver to start a Tx poll operation.
+ * Called in an interrupt context.
+ * @notify: SPS driver supplied notification struct
+ *
+ * This function defer the work for this event to the tx workqueue.
+ */
+static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
+{
+ struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT];
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ int ret;
+
+ IPADBG("event %d notified\n", notify->event_id);
+
+ switch (notify->event_id) {
+ case SPS_EVENT_EOT:
+ tx_pkt = notify->data.transfer.user;
+ if (!atomic_read(&sys->curr_polling_state)) {
+ ret = sps_get_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_get_config() failed %d\n", ret);
+ break;
+ }
+ sys->ep->connect.options = SPS_O_AUTO_ENABLE |
+ SPS_O_ACK_TRANSFERS | SPS_O_POLL;
+ ret = sps_set_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_set_config() failed %d\n", ret);
+ break;
+ }
+ atomic_set(&sys->curr_polling_state, 1);
+ queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
+ }
+ break;
+ default:
+ IPAERR("recieved unexpected event id %d\n", notify->event_id);
+ }
+}
+
+/**
+ * ipa_sps_irq_tx_no_aggr_notify() - Callback function which will be called by
* the SPS driver after a Tx operation is complete.
* Called in an interrupt context.
* @notify: SPS driver supplied notification struct
@@ -482,7 +637,7 @@
* This function defer the work for this event to the tx workqueue.
* This event will be later handled by ipa_write_done.
*/
-static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
+static void ipa_sps_irq_tx_no_aggr_notify(struct sps_event_notify *notify)
{
struct ipa_tx_pkt_wrapper *tx_pkt;
@@ -512,7 +667,8 @@
* - Call the endpoints notify function, passing the skb in the parameters
* - Replenish the rx cache
*/
-int ipa_handle_rx_core(bool process_all, bool in_poll_state)
+int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state)
{
struct ipa_a5_mux_hdr *mux_hdr;
struct ipa_rx_pkt_wrapper *rx_pkt;
@@ -521,15 +677,14 @@
unsigned int pull_len;
unsigned int padding;
int ret;
- struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
struct ipa_ep_context *ep;
int cnt = 0;
struct completion *compl;
struct ipa_tree_node *node;
unsigned int src_pipe;
- while ((in_poll_state ? atomic_read(&ipa_ctx->curr_polling_state) :
- !atomic_read(&ipa_ctx->curr_polling_state))) {
+ while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
+ !atomic_read(&sys->curr_polling_state))) {
if (cnt && !process_all)
break;
@@ -654,19 +809,15 @@
/**
* ipa_rx_switch_to_intr_mode() - Operate the Rx data path in interrupt mode
*/
-static void ipa_rx_switch_to_intr_mode(void)
+static void ipa_rx_switch_to_intr_mode(struct ipa_sys_context *sys)
{
int ret;
- struct ipa_sys_context *sys;
- IPADBG("Enter");
- if (!atomic_read(&ipa_ctx->curr_polling_state)) {
+ if (!atomic_read(&sys->curr_polling_state)) {
IPAERR("already in intr mode\n");
goto fail;
}
- sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
-
ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
if (ret) {
IPAERR("sps_get_config() failed %d\n", ret);
@@ -685,15 +836,16 @@
IPAERR("sps_set_config() failed %d\n", ret);
goto fail;
}
- atomic_set(&ipa_ctx->curr_polling_state, 0);
- ipa_handle_rx_core(true, false);
+ atomic_set(&sys->curr_polling_state, 0);
+ ipa_handle_rx_core(sys, true, false);
return;
fail:
IPA_STATS_INC_CNT(ipa_ctx->stats.x_intr_repost);
- schedule_delayed_work(&switch_to_intr_work, msecs_to_jiffies(1));
+ schedule_delayed_work(&sys->switch_to_intr_work, msecs_to_jiffies(1));
}
+
/**
* ipa_rx_notify() - Callback function which is called by the SPS driver when a
* a packet is received
@@ -709,29 +861,29 @@
*/
static void ipa_sps_irq_rx_notify(struct sps_event_notify *notify)
{
- struct ipa_ep_context *ep;
+ struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_IN];
int ret;
IPADBG("event %d notified\n", notify->event_id);
switch (notify->event_id) {
case SPS_EVENT_EOT:
- if (!atomic_read(&ipa_ctx->curr_polling_state)) {
- ep = ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep;
-
- ret = sps_get_config(ep->ep_hdl, &ep->connect);
+ if (!atomic_read(&sys->curr_polling_state)) {
+ ret = sps_get_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
if (ret) {
IPAERR("sps_get_config() failed %d\n", ret);
break;
}
- ep->connect.options = SPS_O_AUTO_ENABLE |
+ sys->ep->connect.options = SPS_O_AUTO_ENABLE |
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
- ret = sps_set_config(ep->ep_hdl, &ep->connect);
+ ret = sps_set_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
if (ret) {
IPAERR("sps_set_config() failed %d\n", ret);
break;
}
- atomic_set(&ipa_ctx->curr_polling_state, 1);
+ atomic_set(&sys->curr_polling_state, 1);
queue_work(ipa_ctx->rx_wq, &rx_work);
}
break;
@@ -740,6 +892,51 @@
}
}
+static void switch_to_intr_tx_work_func(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct ipa_sys_context *sys;
+ dwork = container_of(work, struct delayed_work, work);
+ sys = container_of(dwork, struct ipa_sys_context, switch_to_intr_work);
+ ipa_handle_tx(sys);
+}
+
+/**
+ * ipa_handle_rx() - handle packet reception. This function is executed in the
+ * context of a work queue.
+ * @work: work struct needed by the work queue
+ *
+ * ipa_handle_rx_core() is run in polling mode. After all packets has been
+ * received, the driver switches back to interrupt mode.
+ */
+static void ipa_handle_rx(struct ipa_sys_context *sys)
+{
+ int inactive_cycles = 0;
+ int cnt;
+
+ do {
+ cnt = ipa_handle_rx_core(sys, true, true);
+ if (cnt == 0) {
+ inactive_cycles++;
+ usleep_range(POLLING_MIN_SLEEP_RX,
+ POLLING_MAX_SLEEP_RX);
+ } else {
+ inactive_cycles = 0;
+ }
+ } while (inactive_cycles <= POLLING_INACTIVITY_RX);
+
+ ipa_rx_switch_to_intr_mode(sys);
+}
+
+static void switch_to_intr_rx_work_func(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct ipa_sys_context *sys;
+ dwork = container_of(work, struct delayed_work, work);
+ sys = container_of(dwork, struct ipa_sys_context, switch_to_intr_work);
+ ipa_handle_rx(sys);
+}
+
/**
* ipa_setup_sys_pipe() - Setup an IPA end-point in system-BAM mode and perform
* IPA EP configuration
@@ -858,14 +1055,18 @@
switch (ipa_ep_idx) {
case 1:
- /* fall through */
+ sys_idx = ipa_ep_idx;
+ break;
case 2:
- /* fall through */
+ sys_idx = ipa_ep_idx;
+ INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
+ switch_to_intr_tx_work_func);
+ break;
case 3:
sys_idx = ipa_ep_idx;
INIT_DELAYED_WORK(&replenish_rx_work, replenish_rx_work_func);
- INIT_DELAYED_WORK(&switch_to_intr_work,
- switch_to_intr_work_func);
+ INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
+ switch_to_intr_rx_work_func);
break;
case WLAN_AMPDU_TX_EP:
sys_idx = IPA_A5_WLAN_AMPDU_OUT;
@@ -886,7 +1087,10 @@
ipa_ctx->sys[sys_idx].event.callback =
IPA_CLIENT_IS_CONS(sys_in->client) ?
ipa_sps_irq_rx_notify :
- ipa_sps_irq_tx_notify;
+ (sys_in->client ==
+ IPA_CLIENT_A5_LAN_WAN_PROD ?
+ ipa_sps_irq_tx_notify :
+ ipa_sps_irq_tx_no_aggr_notify);
result = sps_register_event(ipa_ctx->ep[ipa_ep_idx].ep_hdl,
&ipa_ctx->sys[sys_idx].event);
if (result < 0) {
@@ -1078,37 +1282,9 @@
}
EXPORT_SYMBOL(ipa_tx_dp);
-static void ipa_handle_rx(void)
-{
- int inactive_cycles = 0;
- int cnt;
-
- ipa_inc_client_enable_clks();
- do {
- cnt = ipa_handle_rx_core(true, true);
- if (cnt == 0) {
- inactive_cycles++;
- usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
- } else {
- inactive_cycles = 0;
- }
- } while (inactive_cycles <= POLLING_INACTIVITY);
-
- ipa_rx_switch_to_intr_mode();
- ipa_dec_client_disable_clks();
-}
-
-/**
- * ipa_handle_rx() - handle packet reception. This function is executed in the
- * context of a work queue.
- * @work: work struct needed by the work queue
- *
- * ipa_handle_rx_core() is run in polling mode. After all packets has been
- * received, the driver switches back to interrupt mode.
- */
static void ipa_wq_handle_rx(struct work_struct *work)
{
- ipa_handle_rx();
+ ipa_handle_rx(&ipa_ctx->sys[IPA_A5_LAN_WAN_IN]);
}
/**
@@ -1202,11 +1378,6 @@
ipa_replenish_rx_cache();
}
-static void switch_to_intr_work_func(struct work_struct *work)
-{
- ipa_handle_rx();
-}
-
/**
* ipa_cleanup_rx() - release RX queue resources
*
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index cc3e630..b57194e 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -372,7 +372,6 @@
* @spinlock: protects the list and its size
* @event: used to request CALLBACK mode from SPS driver
* @ep: IPA EP context
- * @wait_desc_list: used to hold completed Tx packets
*
* IPA context specific to the system-bam pipes a.k.a LAN IN/OUT and WAN
*/
@@ -382,7 +381,8 @@
spinlock_t spinlock;
struct sps_register_event event;
struct ipa_ep_context *ep;
- struct list_head wait_desc_list;
+ atomic_t curr_polling_state;
+ struct delayed_work switch_to_intr_work;
};
/**
@@ -479,6 +479,14 @@
* @is_sys_mem: flag indicating if NAT memory is sys memory
* @is_dev_init: flag indicating if NAT device is initialized
* @lock: NAT memory mutex
+ * @nat_base_address: nat table virutal address
+ * @ipv4_rules_addr: base nat table address
+ * @ipv4_expansion_rules_addr: expansion table address
+ * @index_table_addr: index table address
+ * @index_table_expansion_addr: index expansion table address
+ * @size_base_tables: base table size
+ * @size_expansion_tables: expansion table size
+ * @public_ip_addr: ip address of nat table
*/
struct ipa_nat_mem {
struct class *class;
@@ -492,6 +500,14 @@
bool is_sys_mem;
bool is_dev_init;
struct mutex lock;
+ void *nat_base_address;
+ char *ipv4_rules_addr;
+ char *ipv4_expansion_rules_addr;
+ char *index_table_addr;
+ char *index_table_expansion_addr;
+ u32 size_base_tables;
+ u32 size_expansion_tables;
+ u32 public_ip_addr;
};
/**
@@ -530,6 +546,7 @@
u32 bridged_pkts[IPA_BRIDGE_TYPE_MAX][IPA_BRIDGE_DIR_MAX];
u32 rx_repl_repost;
u32 x_intr_repost;
+ u32 x_intr_repost_tx;
u32 rx_q_len;
u32 msg_w[IPA_EVENT_MAX];
u32 msg_r[IPA_EVENT_MAX];
@@ -641,7 +658,6 @@
uint aggregation_type;
uint aggregation_byte_limit;
uint aggregation_time_limit;
- atomic_t curr_polling_state;
struct delayed_work poll_work;
bool hdr_tbl_lcl;
struct ipa_mem_buffer hdr_mem;
@@ -800,7 +816,10 @@
void ipa_cleanup_rx(void);
int ipa_cfg_filter(u32 disable);
void ipa_wq_write_done(struct work_struct *work);
-int ipa_handle_rx_core(bool process_all, bool in_poll_state);
+int ipa_handle_rx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state);
+int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
+ bool in_poll_state);
int ipa_pipe_mem_init(u32 start_ofst, u32 size);
int ipa_pipe_mem_alloc(u32 *ofst, u32 size);
int ipa_pipe_mem_free(u32 ofst, u32 size);
diff --git a/drivers/platform/msm/ipa/ipa_nat.c b/drivers/platform/msm/ipa/ipa_nat.c
index befa2cf..e2c344f 100644
--- a/drivers/platform/msm/ipa/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_nat.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
@@ -75,6 +75,7 @@
IPAERR("unable to map memory. Err:%d\n", result);
goto bail;
}
+ ipa_ctx->nat_mem.nat_base_address = nat_ctx->vaddr;
} else {
IPADBG("Mapping shared(local) memory\n");
IPADBG("map sz=0x%lx\n", vsize);
@@ -88,7 +89,7 @@
result = -EAGAIN;
goto bail;
}
-
+ ipa_ctx->nat_mem.nat_base_address = (void *)vma->vm_start;
}
nat_ctx->is_mapped = true;
vma->vm_ops = &ipa_nat_remap_vm_ops;
@@ -299,6 +300,35 @@
goto free_cmd;
}
+ ipa_ctx->nat_mem.public_ip_addr = init->ip_addr;
+ IPADBG("Table ip address:0x%x", ipa_ctx->nat_mem.public_ip_addr);
+
+ ipa_ctx->nat_mem.ipv4_rules_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->ipv4_rules_offset;
+ IPADBG("ipv4_rules_addr: 0x%p\n",
+ ipa_ctx->nat_mem.ipv4_rules_addr);
+
+ ipa_ctx->nat_mem.ipv4_expansion_rules_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->expn_rules_offset;
+ IPADBG("ipv4_expansion_rules_addr: 0x%p\n",
+ ipa_ctx->nat_mem.ipv4_expansion_rules_addr);
+
+ ipa_ctx->nat_mem.index_table_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->index_offset;
+ IPADBG("index_table_addr: 0x%p\n",
+ ipa_ctx->nat_mem.index_table_addr);
+
+ ipa_ctx->nat_mem.index_table_expansion_addr =
+ (char *)ipa_ctx->nat_mem.nat_base_address + init->index_expn_offset;
+ IPADBG("index_table_expansion_addr: 0x%p\n",
+ ipa_ctx->nat_mem.index_table_expansion_addr);
+
+ IPADBG("size_base_tables: %d\n", init->table_entries);
+ ipa_ctx->nat_mem.size_base_tables = init->table_entries;
+
+ IPADBG("size_expansion_tables: %d\n", init->expn_table_entries);
+ ipa_ctx->nat_mem.size_expansion_tables = init->expn_table_entries;
+
IPADBG("return\n");
result = 0;
free_cmd:
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index c28a5ee..9062ab8 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -1410,19 +1410,38 @@
goto bail;
}
- /* Request the BRIDGE_PROD resource */
+ /*
+ * Delete part of IPA resource manager dependency graph. Only the
+ * BRIDGE_PROD <-> A2 dependency remains intact
+ */
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
+ if ((res != 0) && (res != -EINPROGRESS))
+ TETH_ERR(
+ "Failed deleting ipa_rm dependency BRIDGE_PROD <-> USB_CONS\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+ IPA_RM_RESOURCE_A2_CONS);
+ if ((res != 0) && (res != -EINPROGRESS))
+ TETH_ERR(
+ "Failed deleting ipa_rm dependency USB_PROD <-> A2_CONS\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
+ if ((res != 0) && (res != -EINPROGRESS))
+ TETH_ERR(
+ "Failed deleting ipa_rm dependency A2_PROD <-> USB_CONS\n");
+
+ /* Request the BRIDGE_PROD resource, A2 and IPA should power up */
res = teth_request_resource();
if (res) {
TETH_ERR("request_resource() failed.\n");
goto bail;
}
- teth_ctx->is_connected = false;
-
/* Close the channel to A2 */
if (a2_mux_close_channel(A2_MUX_TETHERED_0))
TETH_ERR("a2_mux_close_channel() failed\n");
+ /* Teardown the IPA HW bridge */
if (teth_ctx->is_hw_bridge_complete) {
/* Delete header entries */
if (ipa_del_hdr(teth_ctx->hdr_del))
@@ -1452,27 +1471,14 @@
ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
- /* Delete IPA Resource manager dependency graph */
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
- IPA_RM_RESOURCE_USB_CONS);
- if ((res != 0) && (res != -EINPROGRESS))
- TETH_ERR(
- "Failed deleting ipa_rm dependency BRIDGE_PROD <-> USB_CONS\n");
+ /* Delete the last ipa_rm dependency - BRIDGE_PROD <-> A2 */
res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_BRIDGE_PROD,
IPA_RM_RESOURCE_A2_CONS);
if ((res != 0) && (res != -EINPROGRESS))
TETH_ERR(
"Failed deleting ipa_rm dependency BRIDGE_PROD <-> A2_CONS\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
- IPA_RM_RESOURCE_A2_CONS);
- if ((res != 0) && (res != -EINPROGRESS))
- TETH_ERR(
- "Failed deleting ipa_rm dependency USB_PROD <-> A2_CONS\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_A2_PROD,
- IPA_RM_RESOURCE_USB_CONS);
- if ((res != 0) && (res != -EINPROGRESS))
- TETH_ERR(
- "Failed deleting ipa_rm dependency A2_PROD <-> USB_CONS\n");
+
+ teth_ctx->is_connected = false;
bail:
TETH_DBG_FUNC_EXIT();
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index fd42c47..419499d 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -127,7 +127,7 @@
int adjust_soc_low_threshold;
int chg_term_ua;
enum battery_type batt_type;
- unsigned int fcc;
+ unsigned int fcc_mah;
struct single_row_lut *fcc_temp_lut;
struct single_row_lut *fcc_sf_lut;
struct pc_temp_ocv_lut *pc_temp_ocv_lut;
@@ -375,7 +375,7 @@
#define CC_READING_RESOLUTION_N 542535
#define CC_READING_RESOLUTION_D 100000
-static int cc_reading_to_uv(int16_t reading)
+static s64 cc_reading_to_uv(s64 reading)
{
return div_s64(reading * CC_READING_RESOLUTION_N,
CC_READING_RESOLUTION_D);
@@ -582,7 +582,7 @@
return false;
}
-static bool is_batfet_open(struct qpnp_bms_chip *chip)
+static bool is_battery_full(struct qpnp_bms_chip *chip)
{
union power_supply_propval ret = {0,};
@@ -610,18 +610,32 @@
iadc_channel = chip->use_external_rsense ?
EXTERNAL_RSENSE : INTERNAL_RSENSE;
- rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
- VBAT_SNS, &v_result);
- if (rc) {
- pr_err("vadc read failed with rc: %d\n", rc);
- return rc;
+ if (is_battery_full(chip)) {
+ rc = get_battery_current(chip, ibat_ua);
+ if (rc) {
+ pr_err("bms current read failed with rc: %d\n", rc);
+ return rc;
+ }
+ rc = qpnp_vadc_read(VBAT_SNS, &v_result);
+ if (rc) {
+ pr_err("vadc read failed with rc: %d\n", rc);
+ return rc;
+ }
+ *vbat_uv = (int)v_result.physical;
+ } else {
+ rc = qpnp_iadc_vadc_sync_read(iadc_channel, &i_result,
+ VBAT_SNS, &v_result);
+ if (rc) {
+ pr_err("adc sync read failed with rc: %d\n", rc);
+ return rc;
+ }
+ /*
+ * reverse the current read by the iadc, since the bms uses
+ * flipped battery current polarity.
+ */
+ *ibat_ua = -1 * (int)i_result.result_ua;
+ *vbat_uv = (int)v_result.physical;
}
- /*
- * reverse the current read by the iadc, since the bms uses
- * flipped battery current polarity.
- */
- *ibat_ua = -1 * (int)i_result.result_ua;
- *vbat_uv = (int)v_result.physical;
return 0;
}
@@ -774,14 +788,6 @@
return (fcc_uah * pc) / 100;
}
-#define CC_RESOLUTION_N 542535
-#define CC_RESOLUTION_D 100000
-
-static s64 cc_to_uv(s64 cc)
-{
- return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
-}
-
#define CC_READING_TICKS 56
#define SLEEP_CLK_HZ 32764
#define SECONDS_PER_HOUR 3600
@@ -817,7 +823,7 @@
qpnp_iadc_get_gain_and_offset(&calibration);
pr_debug("cc = %lld\n", cc);
- cc_voltage_uv = cc_to_uv(cc);
+ cc_voltage_uv = cc_reading_to_uv(cc);
cc_voltage_uv = cc_adjust_for_gain(cc_voltage_uv,
calibration.gain_raw
- calibration.offset_raw);
@@ -836,7 +842,6 @@
int rbatt_mohm, scalefactor;
rbatt_mohm = chip->default_rbatt_mohm;
- pr_debug("rbatt before scaling = %d\n", rbatt_mohm);
if (chip->rbatt_sf_lut == NULL) {
pr_debug("RBATT = %d\n", rbatt_mohm);
return rbatt_mohm;
@@ -845,18 +850,10 @@
batt_temp = batt_temp / 10;
scalefactor = interpolate_scalingfactor(chip->rbatt_sf_lut,
batt_temp, soc_rbatt_mohm);
- pr_debug("rbatt sf = %d for batt_temp = %d, soc_rbatt = %d\n",
- scalefactor, batt_temp, soc_rbatt_mohm);
rbatt_mohm = (rbatt_mohm * scalefactor) / 100;
rbatt_mohm += chip->r_conn_mohm;
- pr_debug("adding r_conn_mohm = %d rbatt = %d\n",
- chip->r_conn_mohm, rbatt_mohm);
rbatt_mohm += chip->rbatt_capacitive_mohm;
- pr_debug("adding rbatt_capacitive_mohm = %d rbatt = %d\n",
- chip->rbatt_capacitive_mohm, rbatt_mohm);
-
- pr_debug("RBATT = %d\n", rbatt_mohm);
return rbatt_mohm;
}
@@ -909,9 +906,6 @@
+ (chip->v_cutoff_uv);
delta_uv = ocv_mv * 1000 - unusable_uv;
- pr_debug("soc = %d ocv = %d rbat = %d u_uv = %d delta_v = %d\n",
- i, ocv_mv, rbatt_mohm, unusable_uv, delta_uv);
-
if (delta_uv > 0)
break;
@@ -927,10 +921,10 @@
pc_unusable = calculate_pc(chip, unusable_uv, batt_temp);
uuc_uah = (params->fcc_uah * pc_unusable) / 100;
- pr_debug("For uuc_iavg_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d uuc = %d\n",
+ pr_debug("For uuc_iavg_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d rbatt_pc = %d uuc = %d\n",
uuc_iavg_ma,
uuc_rbatt_mohm, unusable_uv,
- pc_unusable, uuc_uah);
+ pc_unusable, i, uuc_uah);
*ret_pc_unusable = pc_unusable;
return uuc_uah;
}
@@ -1174,6 +1168,7 @@
if (soc_rbatt < 0)
soc_rbatt = 0;
params->rbatt_mohm = get_rbatt(chip, soc_rbatt, batt_temp);
+ pr_debug("rbatt_mohm = %d\n", params->rbatt_mohm);
calculate_iavg(chip, params->cc_uah, ¶ms->iavg_ua,
params->delta_time_s);
@@ -1409,7 +1404,7 @@
goto out;
}
- if (ibat_ua < 0 && !is_batfet_open(chip)) {
+ if (ibat_ua < 0 && !is_battery_full(chip)) {
soc = charging_adjustments(chip, params, soc, vbat_uv, ibat_ua,
batt_temp);
goto out;
@@ -1957,7 +1952,7 @@
/* Returns full charge design in uAh */
static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
{
- return chip->fcc;
+ return chip->fcc_mah * 1000;
}
static int get_prop_bms_present(struct qpnp_bms_chip *chip)
@@ -2169,7 +2164,7 @@
}
}
- chip->fcc = batt_data->fcc;
+ chip->fcc_mah = batt_data->fcc;
chip->fcc_temp_lut = batt_data->fcc_temp_lut;
chip->fcc_sf_lut = batt_data->fcc_sf_lut;
chip->pc_temp_ocv_lut = batt_data->pc_temp_ocv_lut;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 8207cd6..de2e5c1 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -546,6 +546,9 @@
/* Don't run on battery for batteryless hardware */
if (chip->use_default_batt_values)
return 0;
+ /* Don't force on battery if battery is not present */
+ if (!qpnp_chg_is_batt_present(chip))
+ return 0;
/* This bit forces the charger to run off of the battery rather
* than a connected charger */
@@ -1811,11 +1814,15 @@
case SMBBP_BOOST_SUBTYPE:
break;
case SMBB_MISC_SUBTYPE:
- chip->type = SMBB;
case SMBBP_MISC_SUBTYPE:
- chip->type = SMBBP;
case SMBCL_MISC_SUBTYPE:
- chip->type = SMBCL;
+ if (subtype == SMBB_MISC_SUBTYPE)
+ chip->type = SMBB;
+ else if (subtype == SMBBP_MISC_SUBTYPE)
+ chip->type = SMBBP;
+ else if (subtype == SMBCL_MISC_SUBTYPE)
+ chip->type = SMBCL;
+
pr_debug("Setting BOOT_DONE\n");
rc = qpnp_chg_masked_write(chip,
chip->misc_base + CHGR_MISC_BOOT_DONE,
@@ -2120,9 +2127,10 @@
}
INIT_WORK(&chip->adc_measure_work,
qpnp_bat_if_adc_measure_work);
- INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
}
+ INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
+
if (chip->dc_chgpth_base) {
chip->dc_psy.name = "qpnp-dc";
chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
@@ -2245,7 +2253,7 @@
return rc;
}
-static const struct dev_pm_ops qpnp_bms_pm_ops = {
+static const struct dev_pm_ops qpnp_chg_pm_ops = {
.resume = qpnp_chg_resume,
.suspend = qpnp_chg_suspend,
};
@@ -2254,9 +2262,10 @@
.probe = qpnp_charger_probe,
.remove = __devexit_p(qpnp_charger_remove),
.driver = {
- .name = QPNP_CHARGER_DEV_NAME,
- .owner = THIS_MODULE,
- .of_match_table = qpnp_charger_match_table,
+ .name = QPNP_CHARGER_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qpnp_charger_match_table,
+ .pm = &qpnp_chg_pm_ops,
},
};
diff --git a/drivers/power/smb350_charger.c b/drivers/power/smb350_charger.c
index 21d7aea..11fff43 100644
--- a/drivers/power/smb350_charger.c
+++ b/drivers/power/smb350_charger.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
@@ -263,6 +263,9 @@
if (!chg_enabled) {
pr_warn("Charging not enabled.\n");
+ /* release the wake-lock when DC power removed */
+ if (wake_lock_active(&dev->chg_wake_lock))
+ wake_unlock(&dev->chg_wake_lock);
return POWER_SUPPLY_CHARGE_TYPE_NONE;
}
diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c
index 6d8985e..e0bffb9 100644
--- a/drivers/rtc/qpnp-rtc.c
+++ b/drivers/rtc/qpnp-rtc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-13, 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
@@ -503,12 +503,17 @@
}
}
- rtc_dd->rtc_ctrl_reg = BIT_RTC_ENABLE;
- rc = qpnp_write_wrapper(rtc_dd, &rtc_dd->rtc_ctrl_reg,
+ rc = qpnp_read_wrapper(rtc_dd, &rtc_dd->rtc_ctrl_reg,
rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1);
if (rc) {
dev_err(&spmi->dev,
- "Write to RTC control reg failed\n");
+ "Read from RTC control reg failed\n");
+ goto fail_rtc_enable;
+ }
+
+ if (!(rtc_dd->rtc_ctrl_reg & BIT_RTC_ENABLE)) {
+ dev_err(&spmi->dev,
+ "RTC h/w disabled, rtc not registered\n");
goto fail_rtc_enable;
}
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index a0179cb..86ae8db 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -471,6 +471,8 @@
DECLARE_COMPLETION_ONSTACK(done);
u8 wbuf[SLIM_RX_MSGQ_BUF_LEN];
+ *clkgear = ctrl->clkgear;
+ *subfrmc = 0;
txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
txn.dt = SLIM_MSG_DEST_LOGICALADDR;
txn.la = SLIM_LA_MGR;
@@ -479,6 +481,34 @@
txn.wbuf = wbuf;
txn.rbuf = NULL;
+ if (ctrl->sched.msgsl != ctrl->sched.pending_msgsl) {
+ pr_debug("slim reserve BW for messaging: req: %d",
+ ctrl->sched.pending_msgsl);
+ txn.mc = SLIM_USR_MC_REQ_BW;
+ wbuf[txn.len++] = ((sb->laddr & 0x1f) |
+ ((u8)(ctrl->sched.pending_msgsl & 0x7) << 5));
+ wbuf[txn.len++] = (u8)(ctrl->sched.pending_msgsl >> 3);
+ ret = ngd_get_tid(ctrl, &txn, &wbuf[txn.len++], &done);
+ if (ret)
+ return ret;
+ txn.rl = txn.len + 4;
+ ret = ngd_xferandwait_ack(ctrl, &txn);
+ if (ret)
+ return ret;
+
+ txn.mc = SLIM_USR_MC_RECONFIG_NOW;
+ txn.len = 2;
+ wbuf[1] = sb->laddr;
+ txn.rl = txn.len + 4;
+ ret = ngd_get_tid(ctrl, &txn, &wbuf[0], &done);
+ if (ret)
+ return ret;
+ ret = ngd_xferandwait_ack(ctrl, &txn);
+ if (ret)
+ return ret;
+
+ txn.len = 0;
+ }
list_for_each_entry(pch, &sb->mark_define, pending) {
struct slim_ich *slc;
slc = &ctrl->chans[pch->chan];
@@ -1039,8 +1069,6 @@
dev->ctrl.config_port = msm_config_port;
dev->ctrl.port_xfer = msm_slim_port_xfer;
dev->ctrl.port_xfer_status = msm_slim_port_xfer_status;
- /* Reserve some messaging BW for satellite-apps driver communication */
- dev->ctrl.sched.pending_msgsl = 30;
dev->bam_mem = bam_mem;
init_completion(&dev->reconf);
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index dc756bb..814817b 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -72,7 +72,7 @@
uint32_t freq_req;
uint32_t min_level;
uint32_t num_levels;
- uint32_t curr_level;
+ int32_t curr_level;
uint32_t levels[3];
struct kobj_attribute value_attr;
struct kobj_attribute level_attr;
@@ -159,6 +159,7 @@
{
int cpu = 0;
int ret = 0;
+ struct cpufreq_policy *policy = NULL;
if (!freq_table_get) {
ret = check_freq_table();
@@ -174,16 +175,20 @@
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;
}
- if (cpufreq_update_policy(cpu))
- pr_debug("%s: Cannot update policy for cpu%d\n",
- __func__, cpu);
+ 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);
+ }
}
return ret;
@@ -193,6 +198,9 @@
{
int ret = 0;
+ if (level == r->curr_level)
+ return ret;
+
/* level = -1: disable, level = 0,1,2..n: enable */
if (level == -1) {
ret = update_cpu_min_freq_all(r->min_level);
@@ -223,6 +231,9 @@
r->name);
return -EFAULT;
}
+ if (level == r->curr_level)
+ return ret;
+
/* level = -1: disable, level = 0,1,2..n: enable */
if (level == -1) {
ret = regulator_set_voltage(r->reg, r->min_level,
@@ -241,32 +252,6 @@
return ret;
}
-/* 1:enable, 0:disable */
-static int vdd_restriction_apply_all(int en)
-{
- int i = 0;
- int fail_cnt = 0;
- int ret = 0;
-
- for (i = 0; i < rails_cnt; i++) {
- if (rails[i].freq_req == 1 && freq_table_get)
- ret = vdd_restriction_apply_freq(&rails[i],
- en ? 0 : -1);
- else
- ret = vdd_restriction_apply_voltage(&rails[i],
- en ? 0 : -1);
- if (ret) {
- pr_err("Cannot set voltage for %s", rails[i].name);
- fail_cnt++;
- }
- }
- /* Check fail_cnt again to make sure all of the rails are applied
- * restriction successfully or not */
- if (fail_cnt)
- return -EFAULT;
-
- return ret;
-}
/* Setting all rails the same mode */
static int psm_set_mode_all(int mode)
@@ -328,8 +313,10 @@
ret = vdd_restriction_apply_voltage(&rails[i],
(val) ? 0 : -1);
- /* Even if fail to set one rail, still try to set the
- * others. Continue the loop */
+ /*
+ * Even if fail to set one rail, still try to set the
+ * others. Continue the loop
+ */
if (ret)
pr_err("Set vdd restriction for %s failed\n",
rails[i].name);
@@ -379,7 +366,7 @@
else
val = reg->levels[reg->curr_level];
- return snprintf(buf, PAGE_SIZE, "%d\n", reg->levels[reg->curr_level]);
+ return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static int vdd_rstr_reg_level_show(
@@ -474,7 +461,6 @@
return count;
}
-
static int check_sensor_id(int sensor_id)
{
int i = 0;
@@ -530,6 +516,48 @@
return ret;
}
+/* 1:enable, 0:disable */
+static int vdd_restriction_apply_all(int en)
+{
+ int i = 0;
+ int en_cnt = 0;
+ int dis_cnt = 0;
+ int fail_cnt = 0;
+ int ret = 0;
+
+ for (i = 0; i < rails_cnt; i++) {
+ if (rails[i].freq_req == 1 && freq_table_get)
+ ret = vdd_restriction_apply_freq(&rails[i],
+ en ? 0 : -1);
+ else
+ ret = vdd_restriction_apply_voltage(&rails[i],
+ en ? 0 : -1);
+ if (ret) {
+ pr_err("Cannot set voltage for %s", rails[i].name);
+ fail_cnt++;
+ } else {
+ if (en)
+ en_cnt++;
+ else
+ dis_cnt++;
+ }
+ }
+
+ /* As long as one rail is enabled, vdd rstr is enabled */
+ if (en && en_cnt)
+ vdd_rstr_en.enabled = 1;
+ else if (!en && (dis_cnt == rails_cnt))
+ vdd_rstr_en.enabled = 0;
+
+ /*
+ * Check fail_cnt again to make sure all of the rails are applied
+ * restriction successfully or not
+ */
+ if (fail_cnt)
+ return -EFAULT;
+ return ret;
+}
+
static int msm_thermal_get_freq_table(void)
{
int ret = 0;
@@ -607,7 +635,8 @@
cpus_offlined &= ~BIT(i);
pr_info("%s: Allow Online CPU%d Temp: %ld\n",
KBUILD_MODNAME, i, temp);
- /* If this core is already online, then bring up the
+ /*
+ * If this core is already online, then bring up the
* next offlined core.
*/
if (cpu_online(i))
@@ -648,18 +677,15 @@
dis_cnt++;
continue;
}
- if (temp <= msm_thermal_info.vdd_rstr_temp_hyst_degC &&
- vdd_rstr_en.enabled == 0) {
+ if (temp <= msm_thermal_info.vdd_rstr_temp_degC) {
ret = vdd_restriction_apply_all(1);
if (ret) {
pr_err( \
"Enable vdd rstr votlage for all failed\n");
goto exit;
}
- vdd_rstr_en.enabled = 1;
goto exit;
- } else if (temp > msm_thermal_info.vdd_rstr_temp_degC &&
- vdd_rstr_en.enabled == 1)
+ } else if (temp > msm_thermal_info.vdd_rstr_temp_hyst_degC)
dis_cnt++;
}
if (dis_cnt == max_tsens_num) {
@@ -668,7 +694,6 @@
pr_err("Disable vdd rstr votlage for all failed\n");
goto exit;
}
- vdd_rstr_en.enabled = 0;
}
exit:
mutex_unlock(&vdd_rstr_mutex);
@@ -694,9 +719,11 @@
continue;
}
- /* As long as one sensor is above the threshold, set PWM mode
+ /*
+ * As long as one sensor is above the threshold, set PWM mode
* on all rails, and loop stops. Set auto mode when all rails
- * are below thershold */
+ * are below thershold
+ */
if (temp > msm_thermal_info.psm_temp_degC) {
ret = psm_set_mode_all(PMIC_PWM_MODE);
if (ret) {
@@ -844,7 +871,7 @@
ts.tv_sec, ts.tv_usec);
}
-/**
+/*
* We will reset the cpu frequencies limits here. The core online/offline
* status will be carried over to the process stopping the msm_thermal, as
* we dont want to online a core and bring in the thermal issues.
@@ -1149,8 +1176,10 @@
if (rails[i].freq_req == 1) {
usefreq |= BIT(i);
check_freq_table();
- /* Restrict frequency by default until we have made
- * our first temp reading */
+ /*
+ * Restrict frequency by default until we have made
+ * our first temp reading
+ */
if (freq_table_get)
ret = vdd_restriction_apply_freq(&rails[i], 0);
else
@@ -1171,8 +1200,10 @@
}
return ret;
}
- /* Restrict votlage by default until we have made
- * our first temp reading */
+ /*
+ * Restrict votlage by default until we have made
+ * our first temp reading
+ */
ret = vdd_restriction_apply_voltage(&rails[i], 0);
}
}
@@ -1435,17 +1466,18 @@
if (ret)
goto read_node_fail;
- key = "qcom,min-level";
- ret = of_property_read_u32(child_node, key,
- &rails[i].min_level);
- if (ret)
- goto read_node_fail;
-
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;
+ else {
+ key = "qcom,min-level";
+ ret = of_property_read_u32(child_node, key,
+ &rails[i].min_level);
+ if (ret)
+ goto read_node_fail;
+ }
- if (ret)
- goto read_node_fail;
rails[i].curr_level = 0;
rails[i].reg = NULL;
i++;
@@ -1576,9 +1608,11 @@
key = "qcom,core-control-mask";
ret = of_property_read_u32(node, key, &data.core_control_mask);
- /* Probe optional properties below. Call probe_psm before
+ /*
+ * Probe optional properties below. Call probe_psm before
* probe_vdd_rstr because rpm_regulator_get has to be called
- * before devm_regulator_get*/
+ * before devm_regulator_get
+ */
ret = probe_psm(node, &data, pdev);
if (ret == -EPROBE_DEFER)
goto fail;
@@ -1586,8 +1620,10 @@
if (ret == -EPROBE_DEFER)
goto fail;
- /* In case sysfs add nodes get called before probe function.
- * Need to make sure sysfs node is created again */
+ /*
+ * In case sysfs add nodes get called before probe function.
+ * Need to make sure sysfs node is created again
+ */
if (psm_nodes_called) {
msm_thermal_add_psm_nodes();
psm_nodes_called = false;
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ede2ef1..1d02e32 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -110,6 +110,34 @@
wake_up_interruptible(&vt_event_waitqueue);
}
+static void __vt_event_queue(struct vt_event_wait *vw)
+{
+ unsigned long flags;
+ /* Prepare the event */
+ INIT_LIST_HEAD(&vw->list);
+ vw->done = 0;
+ /* Queue our event */
+ spin_lock_irqsave(&vt_event_lock, flags);
+ list_add(&vw->list, &vt_events);
+ spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
+static void __vt_event_wait(struct vt_event_wait *vw)
+{
+ /* Wait for it to pass */
+ wait_event_interruptible(vt_event_waitqueue, vw->done);
+}
+
+static void __vt_event_dequeue(struct vt_event_wait *vw)
+{
+ unsigned long flags;
+
+ /* Dequeue it */
+ spin_lock_irqsave(&vt_event_lock, flags);
+ list_del(&vw->list);
+ spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
/**
* vt_event_wait - wait for an event
* @vw: our event
@@ -121,20 +149,9 @@
static void vt_event_wait(struct vt_event_wait *vw)
{
- unsigned long flags;
- /* Prepare the event */
- INIT_LIST_HEAD(&vw->list);
- vw->done = 0;
- /* Queue our event */
- spin_lock_irqsave(&vt_event_lock, flags);
- list_add(&vw->list, &vt_events);
- spin_unlock_irqrestore(&vt_event_lock, flags);
- /* Wait for it to pass */
- wait_event_interruptible(vt_event_waitqueue, vw->done);
- /* Dequeue it */
- spin_lock_irqsave(&vt_event_lock, flags);
- list_del(&vw->list);
- spin_unlock_irqrestore(&vt_event_lock, flags);
+ __vt_event_queue(vw);
+ __vt_event_wait(vw);
+ __vt_event_dequeue(vw);
}
/**
@@ -177,10 +194,14 @@
{
struct vt_event_wait vw;
do {
- if (n == fg_console + 1)
- break;
vw.event.event = VT_EVENT_SWITCH;
- vt_event_wait(&vw);
+ __vt_event_queue(&vw);
+ if (n == fg_console + 1) {
+ __vt_event_dequeue(&vw);
+ break;
+ }
+ __vt_event_wait(&vw);
+ __vt_event_dequeue(&vw);
if (vw.done == 0)
return -EINTR;
} while (vw.event.newev != n);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 147e3db..bc1fa07 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -426,6 +426,7 @@
struct adb_data {
bool opened;
bool enabled;
+ struct android_dev *dev;
};
static int
@@ -459,6 +460,7 @@
data->enabled = true;
+
/* Disable the gadget until adbd is ready */
if (!data->opened)
android_disable(dev);
@@ -490,27 +492,45 @@
struct android_dev *dev = adb_function.android_dev;
struct adb_data *data = adb_function.config;
+ /* dev is null in case ADB is not in the composition */
+ if (dev)
+ mutex_lock(&dev->mutex);
+
+ /* Save dev in case the adb function will get disabled */
+ data->dev = dev;
data->opened = true;
- if (data->enabled && dev) {
- mutex_lock(&dev->mutex);
+ if (data->enabled && dev)
android_enable(dev);
+
+ if (dev)
mutex_unlock(&dev->mutex);
- }
}
static void adb_closed_callback(void)
{
- struct android_dev *dev = adb_function.android_dev;
struct adb_data *data = adb_function.config;
+ struct android_dev *dev = adb_function.android_dev;
+
+ /* In case new composition is without ADB, use saved one */
+ if (!dev)
+ dev = data->dev;
+
+ if (!dev)
+ pr_err("adb_closed_callback: data->dev is NULL");
+
+ if (dev)
+ mutex_lock(&dev->mutex);
data->opened = false;
- if (data->enabled) {
- mutex_lock(&dev->mutex);
+ if (data->enabled)
android_disable(dev);
+
+ data->dev = NULL;
+
+ if (dev)
mutex_unlock(&dev->mutex);
- }
}
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 8e7cbb2..a395d15 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -77,15 +77,7 @@
bool is_open;
};
-struct f_ecm_qc_ipa_params {
- u8 dev_mac[ETH_ALEN];
- u8 host_mac[ETH_ALEN];
- ecm_ipa_callback ipa_rx_cb;
- ecm_ipa_callback ipa_tx_cb;
- void *ipa_priv;
-};
-
-static struct f_ecm_qc_ipa_params ipa_params;
+static struct ecm_ipa_params ipa_params;
static inline struct f_ecm_qc *func_to_ecm_qc(struct usb_function *f)
{
@@ -435,17 +427,17 @@
void *ecm_qc_get_ipa_rx_cb(void)
{
- return ipa_params.ipa_rx_cb;
+ return ipa_params.ecm_ipa_rx_dp_notify;
}
void *ecm_qc_get_ipa_tx_cb(void)
{
- return ipa_params.ipa_tx_cb;
+ return ipa_params.ecm_ipa_tx_dp_notify;
}
void *ecm_qc_get_ipa_priv(void)
{
- return ipa_params.ipa_priv;
+ return ipa_params.private;
}
/*-------------------------------------------------------------------------*/
@@ -849,7 +841,7 @@
ecm_qc_string_defs[1].s = NULL;
if (ecm->xport == USB_GADGET_XPORT_BAM2BAM_IPA)
- ecm_ipa_cleanup(ipa_params.ipa_priv);
+ ecm_ipa_cleanup(ipa_params.private);
kfree(ecm);
}
@@ -920,12 +912,13 @@
/* export host's Ethernet address in CDC format */
if (ecm->xport == USB_GADGET_XPORT_BAM2BAM_IPA) {
- gether_qc_get_macs(ipa_params.dev_mac, ipa_params.host_mac);
+ gether_qc_get_macs(ipa_params.device_ethaddr,
+ ipa_params.host_ethaddr);
snprintf(ecm->ethaddr, sizeof ecm->ethaddr,
"%02X%02X%02X%02X%02X%02X",
- ipa_params.host_mac[0], ipa_params.host_mac[1],
- ipa_params.host_mac[2], ipa_params.host_mac[3],
- ipa_params.host_mac[4], ipa_params.host_mac[5]);
+ ipa_params.host_ethaddr[0], ipa_params.host_ethaddr[1],
+ ipa_params.host_ethaddr[2], ipa_params.host_ethaddr[3],
+ ipa_params.host_ethaddr[4], ipa_params.host_ethaddr[5]);
} else
snprintf(ecm->ethaddr, sizeof ecm->ethaddr,
"%02X%02X%02X%02X%02X%02X",
@@ -957,21 +950,15 @@
if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA)
return status;
- status = ecm_ipa_init(&ipa_params.ipa_rx_cb, &ipa_params.ipa_tx_cb,
- &ipa_params.ipa_priv);
+ pr_debug("setting ecm_ipa, host_ethaddr=%pM, device_ethaddr=%pM",
+ ipa_params.host_ethaddr, ipa_params.device_ethaddr);
+ status = ecm_ipa_init(&ipa_params);
if (status) {
- pr_err("failed to initialize ECM IPA Driver");
+ pr_err("failed to initialize ecm_ipa");
ecm_qc_string_defs[1].s = NULL;
kfree(ecm);
- return status;
- }
-
- status = ecm_ipa_configure(ipa_params.host_mac, ipa_params.dev_mac,
- ipa_params.ipa_priv);
- if (status) {
- pr_err("failed to configure ECM IPA Driver");
- ecm_qc_string_defs[1].s = NULL;
- kfree(ecm);
+ } else {
+ pr_debug("ecm_ipa successful created");
}
return status;
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index f68527c..54b772b 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -181,7 +181,7 @@
struct dsi_panel_cmds_list {
struct dsi_cmd_desc *buf;
- char size;
+ int size;
char ctrl_state;
};
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 52243eb..f672bd4 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -708,45 +708,6 @@
return xres * bpp;
}
-/*
- * physical contiguous memory should be allocated in mdss_fb, and SMMU
- * virtual address mapping can be done in the MDP h/w specific code. It
- * should have a reference count, if none is current mapped, the SMMU context
- * can bedetached, thus allowing power saving in SMMU.
- */
-static int mdp3_fbmem_alloc(struct msm_fb_data_type *mfd)
-{
- int dom;
- void *virt = NULL;
- unsigned long phys = 0;
- size_t size;
- u32 yres = mfd->fbi->var.yres_virtual;
-
- size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
-
- if (mfd->index == 0) {
- virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
- if (!virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
- return -ENOMEM;
- }
- phys = memory_pool_node_paddr(virt);
- dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN)->domain_idx;
- msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
- &mfd->iova);
-
- pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
- size, virt, phys, mfd->index);
- } else {
- size = 0;
- }
-
- mfd->fbi->screen_base = virt;
- mfd->fbi->fix.smem_start = phys;
- mfd->fbi->fix.smem_len = size;
- return 0;
-}
-
struct mdp3_dma *mdp3_get_dma_pipe(int capability)
{
int i;
@@ -775,12 +736,19 @@
return NULL;
}
+static int mdp3_fb_mem_get_iommu_domain(void)
+{
+ if (!mdp3_res)
+ return -ENODEV;
+ return mdp3_res->domains[MDP3_IOMMU_DOMAIN].domain_idx;
+}
+
static int mdp3_probe(struct platform_device *pdev)
{
int rc;
static struct msm_mdp_interface mdp3_interface = {
.init_fnc = mdp3_init,
- .fb_mem_alloc_fnc = mdp3_fbmem_alloc,
+ .fb_mem_get_iommu_domain = mdp3_fb_mem_get_iommu_domain,
.fb_stride = mdp3_fb_stride,
};
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 97a07ed..28f61f9 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -42,9 +42,13 @@
#include <linux/sync.h>
#include <linux/sw_sync.h>
#include <linux/file.h>
+#include <linux/memory_alloc.h>
#include <mach/board.h>
#include <mach/memory.h>
+#include <mach/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/msm_memtypes.h>
#include "mdss_fb.h"
@@ -627,12 +631,7 @@
static int mdss_fb_blank(int blank_mode, struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- if (blank_mode == FB_BLANK_POWERDOWN) {
- struct fb_event event;
- event.info = info;
- event.data = &blank_mode;
- fb_notifier_call_chain(FB_EVENT_BLANK, &event);
- }
+
mdss_fb_pan_idle(mfd);
if (mfd->op_enable == 0) {
if (blank_mode == FB_BLANK_UNBLANK)
@@ -657,6 +656,11 @@
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ if (!start) {
+ pr_warn("No framebuffer memory is allocated.\n");
+ return -ENOMEM;
+ }
+
mdss_fb_pan_idle(mfd);
if (off >= len) {
/* memory mapped io */
@@ -714,13 +718,68 @@
.fb_mmap = mdss_fb_mmap,
};
+static int mdss_fb_alloc_fbmem_iommu(struct msm_fb_data_type *mfd, int dom)
+{
+ void *virt = NULL;
+ unsigned long phys = 0;
+ size_t size = 0;
+ struct platform_device *pdev = mfd->pdev;
+
+ if (!pdev || !pdev->dev.of_node) {
+ pr_err("Invalid device node\n");
+ return -ENODEV;
+ }
+
+ if (of_property_read_u32(pdev->dev.of_node,
+ "qcom,memory-reservation-size",
+ &size) || !size) {
+ mfd->fbi->screen_base = NULL;
+ mfd->fbi->fix.smem_start = 0;
+ mfd->fbi->fix.smem_len = 0;
+ return 0;
+ }
+
+ pr_info("%s frame buffer reserve_size=0x%x\n", __func__, size);
+
+ if (size < PAGE_ALIGN(mfd->fbi->fix.line_length *
+ mfd->fbi->var.yres_virtual))
+ pr_warn("reserve size is smaller than framebuffer size\n");
+
+ virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
+ if (!virt) {
+ pr_err("unable to alloc fbmem size=%u\n", size);
+ return -ENOMEM;
+ }
+
+ phys = memory_pool_node_paddr(virt);
+
+ msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
+ &mfd->iova);
+ pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
+ size, virt, phys, mfd->index);
+
+ mfd->fbi->screen_base = virt;
+ mfd->fbi->fix.smem_start = phys;
+ mfd->fbi->fix.smem_len = size;
+
+ return 0;
+}
+
static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
{
- if (!mfd->mdp.fb_mem_alloc_fnc) {
+
+ if (mfd->mdp.fb_mem_alloc_fnc)
+ return mfd->mdp.fb_mem_alloc_fnc(mfd);
+ else if (mfd->mdp.fb_mem_get_iommu_domain) {
+ int dom = mfd->mdp.fb_mem_get_iommu_domain();
+ if (dom >= 0)
+ return mdss_fb_alloc_fbmem_iommu(mfd, dom);
+ else
+ return -ENOMEM;
+ } else {
pr_err("no fb memory allocator function defined\n");
return -ENOMEM;
}
- return mfd->mdp.fb_mem_alloc_fnc(mfd);
}
static int mdss_fb_register(struct msm_fb_data_type *mfd)
@@ -957,6 +1016,7 @@
result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
mfd->op_enable);
if (result) {
+ pm_runtime_put(info->dev);
pr_err("mdss_fb_open: can't turn on display!\n");
return result;
}
@@ -1538,12 +1598,15 @@
static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
- struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct msm_fb_data_type *mfd;
void __user *argp = (void __user *)arg;
struct mdp_page_protection fb_page_protection;
int ret = -ENOSYS;
struct mdp_buf_sync buf_sync;
+ if (!info || !info->par)
+ return -EINVAL;
+ mfd = (struct msm_fb_data_type *)info->par;
mdss_fb_power_setting_idle(mfd);
mdss_fb_pan_idle(mfd);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 6f6f490..5682f0b 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -56,6 +56,7 @@
struct msm_mdp_interface {
int (*fb_mem_alloc_fnc)(struct msm_fb_data_type *mfd);
+ int (*fb_mem_get_iommu_domain)(void);
int (*init_fnc)(struct msm_fb_data_type *mfd);
int (*on_fnc)(struct msm_fb_data_type *mfd);
int (*off_fnc)(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_mhl.h b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
index 8fef63e..8a9d4fc 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_mhl.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_mhl.h
@@ -19,9 +19,9 @@
struct msm_hdmi_mhl_ops {
u8 (*tmds_enabled)(struct platform_device *pdev);
int (*set_mhl_max_pclk)(struct platform_device *pdev, u32 max_val);
+ int (*set_upstream_hpd)(struct platform_device *pdev, uint8_t on);
};
int msm_hdmi_register_mhl(struct platform_device *pdev,
- struct msm_hdmi_mhl_ops *ops);
-
+ struct msm_hdmi_mhl_ops *ops, void *data);
#endif /* __MDSS_HDMI_MHL_H__ */
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index dc51b1b..42cc356 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -81,6 +81,7 @@
struct hdmi_tx_audio_acr lut[AUDIO_SAMPLE_RATE_MAX];
};
+static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on);
static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on);
static irqreturn_t hdmi_tx_isr(int irq, void *data);
static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
@@ -1950,7 +1951,7 @@
}
int msm_hdmi_register_mhl(struct platform_device *pdev,
- struct msm_hdmi_mhl_ops *ops)
+ struct msm_hdmi_mhl_ops *ops, void *data)
{
struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
@@ -1966,6 +1967,8 @@
ops->tmds_enabled = hdmi_tx_tmds_enabled;
ops->set_mhl_max_pclk = hdmi_tx_set_mhl_max_pclk;
+ ops->set_upstream_hpd = hdmi_tx_set_mhl_hpd;
+
return 0;
}
@@ -2331,6 +2334,9 @@
return;
}
+ /* finish the ongoing hpd work if any */
+ flush_work_sync(&hdmi_ctrl->hpd_int_work);
+
/* Turn off HPD interrupts */
DSS_REG_W(io, HDMI_HPD_INT_CTRL, 0);
@@ -2438,6 +2444,41 @@
return rc;
} /* hdmi_tx_sysfs_enable_hpd */
+static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on)
+{
+ int rc = 0;
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ hdmi_ctrl = platform_get_drvdata(pdev);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!on && hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+ } else if (on && !hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+ } else {
+ DEV_DBG("%s: hpd is already '%s'. return\n", __func__,
+ hdmi_ctrl->hpd_feature_on ? "enabled" : "disabled");
+ return rc;
+ }
+
+ if (!rc) {
+ hdmi_ctrl->hpd_feature_on =
+ (~hdmi_ctrl->hpd_feature_on) & BIT(0);
+ DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_feature_on);
+ } else {
+ DEV_ERR("%s: failed to '%s' hpd. rc = %d\n", __func__,
+ on ? "enable" : "disable", rc);
+ }
+
+ return rc;
+
+}
+
static irqreturn_t hdmi_tx_isr(int irq, void *data)
{
struct dss_io_data *io = NULL;
@@ -2868,7 +2909,7 @@
switch (module_type) {
case HDMI_TX_HPD_PM:
- mp->num_clk = 2;
+ mp->num_clk = 3;
mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) *
mp->num_clk, GFP_KERNEL);
if (!mp->clk_config) {
@@ -2884,6 +2925,16 @@
snprintf(mp->clk_config[1].clk_name, 32, "%s", "core_clk");
mp->clk_config[1].type = DSS_CLK_OTHER;
mp->clk_config[1].rate = 19200000;
+
+ /*
+ * This clock is required to clock MDSS interrupt registers
+ * when HDMI is the only block turned on within MDSS. Since
+ * rate for this clock is controlled by MDP driver, treat this
+ * similar to AHB clock and do not set rate for it.
+ */
+ snprintf(mp->clk_config[2].clk_name, 32, "%s", "mdp_core_clk");
+ mp->clk_config[2].type = DSS_CLK_AHB;
+ mp->clk_config[2].rate = 0;
break;
case HDMI_TX_CORE_PM:
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 22de7e4..772545f 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -55,9 +55,15 @@
#include "mdss_debug.h"
struct mdss_data_type *mdss_res;
+
+static int mdss_fb_mem_get_iommu_domain(void)
+{
+ return mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
+}
+
struct msm_mdp_interface mdp5 = {
.init_fnc = mdss_mdp_overlay_init,
- .fb_mem_alloc_fnc = mdss_mdp_alloc_fb_mem,
+ .fb_mem_get_iommu_domain = mdss_fb_mem_get_iommu_domain,
.panel_register_done = mdss_panel_register_done,
.fb_stride = mdss_mdp_fb_stride,
};
@@ -136,39 +142,6 @@
static int mdss_mdp_parse_dt_misc(struct platform_device *pdev);
static int mdss_mdp_parse_dt_ad_cfg(struct platform_device *pdev);
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd)
-{
- int dom;
- void *virt = NULL;
- unsigned long phys = 0;
- size_t size;
- u32 yres = mfd->fbi->var.yres_virtual;
-
- size = PAGE_ALIGN(mfd->fbi->fix.line_length * yres);
-
- if (mfd->index == 0) {
- virt = allocate_contiguous_memory(size, MEMTYPE_EBI1, SZ_1M, 0);
- if (!virt) {
- pr_err("unable to alloc fbmem size=%u\n", size);
- return -ENOMEM;
- }
- phys = memory_pool_node_paddr(virt);
- dom = mdss_get_iommu_domain(MDSS_IOMMU_DOMAIN_UNSECURE);
- msm_iommu_map_contig_buffer(phys, dom, 0, size, SZ_4K, 0,
- &mfd->iova);
-
- pr_debug("allocating %u bytes at %p (%lx phys) for fb %d\n",
- size, virt, phys, mfd->index);
- } else
- size = 0;
-
- mfd->fbi->screen_base = virt;
- mfd->fbi->fix.smem_start = phys;
- mfd->fbi->fix.smem_len = size;
-
- return 0;
-}
-
u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp)
{
/* The adreno GPU hardware requires that the pitch be aligned to
@@ -388,12 +361,11 @@
bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
- /* aligning to avoid performing updates for small changes */
- ab_quota = ALIGN(ab_quota, SZ_64M);
- ib_quota = ALIGN(ib_quota, SZ_64M);
-
vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
- if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
+
+ /* avoid performing updates for small changes */
+ if ((ALIGN(ab_quota, SZ_64M) == ALIGN(vect->ab, SZ_64M)) &&
+ (ALIGN(ib_quota, SZ_64M) == ALIGN(vect->ib, SZ_64M))) {
pr_debug("skip bus scaling, no change in vectors\n");
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 6be2b73..122dcb9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -110,8 +110,8 @@
typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
struct mdss_mdp_vsync_handler {
+ bool enabled;
mdp_vsync_handler_t vsync_handler;
- u32 ref_cnt;
struct list_head list;
};
@@ -385,7 +385,7 @@
irqreturn_t mdss_mdp_isr(int irq, void *ptr);
int mdss_iommu_attach(struct mdss_data_type *mdata);
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata);
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
u32 intr_type, u32 intf_num);
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
@@ -415,6 +415,10 @@
struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
struct msm_fb_data_type *mfd);
+int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
+void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata);
+int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
struct mdss_panel_data *pdata);
@@ -461,7 +465,7 @@
u32 *copyback);
int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
struct mdp_igc_lut_data *config,
- u32 *copyback);
+ u32 *copyback, u32 copy_from_kernel);
int mdss_mdp_argc_config(struct mdss_mdp_ctl *ctl,
struct mdp_pgc_lut_data *config,
u32 *copyback);
@@ -529,10 +533,10 @@
int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
int mdss_mdp_get_ctl_mixers(u32 fb_num, u32 *mixer_id);
-int mdss_mdp_alloc_fb_mem(struct msm_fb_data_type *mfd);
u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp);
int mdss_panel_register_done(struct mdss_panel_data *pdata);
+int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 568fc37..e346082 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -248,13 +248,14 @@
return ret;
}
-static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata)
+static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata,
+ u32 off)
{
struct mdss_mdp_ctl *ctl = NULL;
- int cnum;
+ u32 cnum;
mutex_lock(&mdss_mdp_ctl_lock);
- for (cnum = 0; cnum < mdata->nctl; cnum++) {
+ for (cnum = off; cnum < mdata->nctl; cnum++) {
ctl = mdata->ctl_off + cnum;
if (ctl->ref_cnt == 0) {
ctl->ref_cnt++;
@@ -391,7 +392,7 @@
struct mdss_mdp_ctl *ctl = NULL;
struct mdss_mdp_mixer *mixer = NULL;
- ctl = mdss_mdp_ctl_alloc(mdss_res);
+ ctl = mdss_mdp_ctl_alloc(mdss_res, mdss_res->nmixers_intf);
if (!ctl)
return NULL;
@@ -451,6 +452,29 @@
return 0;
}
+void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata)
+{
+ switch (pdata->panel_info.type) {
+ case MIPI_VIDEO_PANEL:
+ mdss_mdp_video_copy_splash_screen(pdata);
+ break;
+ case MIPI_CMD_PANEL:
+ default:
+ break;
+ }
+}
+
+int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl)
+{
+ switch (ctl->panel_data->panel_info.type) {
+ case MIPI_VIDEO_PANEL:
+ return mdss_mdp_video_reconfigure_splash_done(ctl);
+ case MIPI_CMD_PANEL:
+ default:
+ return 0;
+ }
+}
+
static inline int mdss_mdp_set_split_ctl(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_ctl *split_ctl)
{
@@ -646,7 +670,7 @@
int ret = 0;
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
- ctl = mdss_mdp_ctl_alloc(mdata);
+ ctl = mdss_mdp_ctl_alloc(mdata, MDSS_MDP_CTL0);
if (!ctl) {
pr_err("unable to allocate ctl\n");
return ERR_PTR(-ENOMEM);
@@ -688,6 +712,9 @@
ctl->intf_type = MDSS_INTF_HDMI;
ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
ctl->start_fnc = mdss_mdp_video_start;
+ ret = mdss_mdp_limited_lut_igc_config(ctl);
+ if (ret)
+ pr_err("Unable to config IGC LUT data");
break;
case WRITEBACK_PANEL:
ctl->intf_num = MDSS_MDP_NO_INTF;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index d68a3d4..72cbed9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -14,6 +14,8 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include "mdss_fb.h"
#include "mdss_mdp.h"
@@ -201,13 +203,13 @@
}
-static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl)
+static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl, bool clear)
{
struct mdss_mdp_video_ctx *ctx = ctl->priv_data;
if (atomic_inc_return(&ctx->vsync_ref) == 1)
mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
- else
+ else if (clear)
mdss_mdp_irq_clear(ctl->mdata, MDSS_MDP_IRQ_INTF_VSYNC,
ctl->intf_num);
}
@@ -225,9 +227,8 @@
{
struct mdss_mdp_video_ctx *ctx;
unsigned long flags;
- struct mdss_mdp_vsync_handler *tmp;
- bool exist = false;
int ret = 0;
+ bool irq_en = false;
if (!handle || !(handle->vsync_handler)) {
ret = -EINVAL;
@@ -242,32 +243,24 @@
}
spin_lock_irqsave(&ctx->vsync_lock, flags);
- list_for_each_entry(tmp, &(ctx->vsync_handlers), list) {
- if (tmp->vsync_handler == handle->vsync_handler) {
- exist = true;
- tmp->ref_cnt++;
- }
- }
- if (!exist) {
- handle->ref_cnt = 1;
+ if (!handle->enabled) {
+ handle->enabled = true;
list_add(&handle->list, &ctx->vsync_handlers);
+ irq_en = true;
}
-
- video_vsync_irq_enable(ctl);
spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+ if (irq_en)
+ video_vsync_irq_enable(ctl, false);
exit:
return ret;
}
-/* passing NULL as handle or vsync_handler will clear all handlers */
static int mdss_mdp_video_remove_vsync_handler(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_vsync_handler *handle)
{
struct mdss_mdp_video_ctx *ctx;
unsigned long flags;
- struct mdss_mdp_vsync_handler *tmp, *q;
- bool exist = true;
- bool used = false;
+ bool irq_dis = false;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
if (!ctx) {
@@ -276,26 +269,21 @@
}
spin_lock_irqsave(&ctx->vsync_lock, flags);
- list_for_each_entry_safe(tmp, q, &ctx->vsync_handlers, list) {
- if (handle && handle->vsync_handler)
- exist = (tmp->vsync_handler == handle->vsync_handler);
- if (exist) {
- tmp->ref_cnt--;
- if (handle && handle->vsync_handler)
- used = (tmp->ref_cnt != 0);
- if (!used) {
- video_vsync_irq_disable(ctl);
- list_del_init(&tmp->list);
- }
- }
+ if (handle->enabled) {
+ handle->enabled = false;
+ list_del_init(&handle->list);
+ irq_dis = true;
}
spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+ if (irq_dis)
+ video_vsync_irq_disable(ctl);
return 0;
}
static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)
{
struct mdss_mdp_video_ctx *ctx;
+ struct mdss_mdp_vsync_handler *tmp, *handle;
int rc;
pr_debug("stop ctl=%d\n", ctl->num);
@@ -326,7 +314,8 @@
ctl->intf_num);
}
- mdss_mdp_video_remove_vsync_handler(ctl, NULL);
+ list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list)
+ mdss_mdp_video_remove_vsync_handler(ctl, handle);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num,
NULL, NULL);
@@ -429,6 +418,8 @@
ctl->num);
ctx->polling_en++;
rc = mdss_mdp_video_pollwait(ctl);
+ } else {
+ rc = 0;
}
}
@@ -466,7 +457,7 @@
if (!ctx->wait_pending) {
ctx->wait_pending++;
- video_vsync_irq_enable(ctl);
+ video_vsync_irq_enable(ctl, true);
INIT_COMPLETION(ctx->vsync_comp);
} else {
WARN(1, "commit without wait! ctl=%d", ctl->num);
@@ -474,7 +465,13 @@
if (!ctx->timegen_en) {
rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
- WARN(rc, "intf %d unblank error (%d)\n", ctl->intf_num, rc);
+ if (rc) {
+ pr_warn("intf #%d unblank error (%d)\n",
+ ctl->intf_num, rc);
+ video_vsync_irq_disable(ctl);
+ ctx->wait_pending = 0;
+ return rc;
+ }
pr_debug("enabling timing gen for intf=%d\n", ctl->intf_num);
@@ -497,6 +494,92 @@
return 0;
}
+int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata)
+{
+ void *virt = NULL;
+ unsigned long bl_fb_addr = 0;
+ unsigned long *bl_fb_addr_va;
+ unsigned long pipe_addr, pipe_src_size;
+ u32 height, width, rgb_size, bpp;
+ size_t size;
+ static struct ion_handle *ihdl;
+ struct ion_client *iclient = mdss_get_ionclient();
+ static ion_phys_addr_t phys;
+
+ pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
+ MDSS_MDP_REG_SSPP_SRC0_ADDR;
+ pipe_src_size =
+ MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
+
+ bpp = 3;
+ rgb_size = MDSS_MDP_REG_READ(pipe_src_size);
+ bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
+
+ height = (rgb_size >> 16) & 0xffff;
+ width = rgb_size & 0xffff;
+ size = PAGE_ALIGN(height * width * bpp);
+ pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
+ __func__, __LINE__, height, width, size);
+
+ ihdl = ion_alloc(iclient, size, SZ_1M,
+ ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+ if (IS_ERR_OR_NULL(ihdl)) {
+ pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
+ return -ENOMEM;
+ }
+
+ pdata->panel_info.splash_ihdl = ihdl;
+
+ virt = ion_map_kernel(iclient, ihdl);
+ ion_phys(iclient, ihdl, &phys, &size);
+
+ pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
+ __func__, __LINE__, size,
+ (unsigned long int)virt, &phys);
+
+ bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
+
+ memcpy(virt, bl_fb_addr_va, size);
+
+ MDSS_MDP_REG_WRITE(pipe_addr, phys);
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
+ 0x48);
+
+ return 0;
+}
+
+int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
+{
+ struct ion_client *iclient = mdss_get_ionclient();
+ struct mdss_panel_data *pdata;
+ int ret = 0, off;
+ int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+ int mdss_v2_intf_off = 0;
+
+ off = 0;
+
+ pdata = ctl->panel_data;
+
+ pdata->panel_info.cont_splash_enabled = 0;
+
+
+ mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
+ off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+
+ if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
+ mdss_v2_intf_off = 0xEC00;
+
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
+ mdss_v2_intf_off, 0);
+ /* wait for 1 VSYNC for the pipe to be unstaged */
+ msleep(20);
+ ion_free(iclient, pdata->panel_info.splash_ihdl);
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
+ NULL);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
+}
+
int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
{
struct mdss_data_type *mdata;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 7363325..26c6934 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -39,6 +39,7 @@
static atomic_t ov_active_panels = ATOMIC_INIT(0);
static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
+static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
struct mdp_overlay *req)
@@ -603,7 +604,7 @@
return 0;
}
-static int mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
+static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_pipe *pipe, *tmp;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
@@ -628,96 +629,6 @@
mutex_unlock(&mfd->lock);
list_for_each_entry_safe(pipe, tmp, &destroy_pipes, cleanup_list)
mdss_mdp_pipe_destroy(pipe);
-
- return 0;
-}
-
-int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata)
-{
- void *virt = NULL;
- unsigned long bl_fb_addr = 0;
- unsigned long *bl_fb_addr_va;
- unsigned long pipe_addr, pipe_src_size;
- u32 height, width, rgb_size, bpp;
- size_t size;
- static struct ion_handle *ihdl;
- struct ion_client *iclient = mdss_get_ionclient();
- static ion_phys_addr_t phys;
-
- pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
- MDSS_MDP_REG_SSPP_SRC0_ADDR;
- pipe_src_size =
- MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
-
- bpp = 3;
- rgb_size = MDSS_MDP_REG_READ(pipe_src_size);
- bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
-
- height = (rgb_size >> 16) & 0xffff;
- width = rgb_size & 0xffff;
- size = PAGE_ALIGN(height * width * bpp);
- pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
- __func__, __LINE__, height, width, size);
-
- ihdl = ion_alloc(iclient, size, SZ_1M,
- ION_HEAP(ION_QSECOM_HEAP_ID), 0);
- if (IS_ERR_OR_NULL(ihdl)) {
- pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
- return -ENOMEM;
- }
-
- pdata->panel_info.splash_ihdl = ihdl;
-
- virt = ion_map_kernel(iclient, ihdl);
- ion_phys(iclient, ihdl, &phys, &size);
-
- pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
- __func__, __LINE__, size,
- (unsigned long int)virt, &phys);
-
- bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
-
- memcpy(virt, bl_fb_addr_va, size);
-
- MDSS_MDP_REG_WRITE(pipe_addr, phys);
- MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
- 0x48);
-
- return 0;
-
-}
-
-int mdss_mdp_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
-{
- struct ion_client *iclient = mdss_get_ionclient();
- struct mdss_panel_data *pdata;
- int ret = 0, off;
- int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
- int mdss_v2_intf_off = 0;
-
- off = 0;
-
- pdata = ctl->panel_data;
-
- pdata->panel_info.cont_splash_enabled = 0;
-
- ion_free(iclient, pdata->panel_info.splash_ihdl);
-
- mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
- off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
-
- if (mdss_mdp_rev == MDSS_MDP_HW_REV_102)
- mdss_v2_intf_off = 0xEC00;
-
- /* wait for 1 VSYNC for the pipe to be unstaged */
- msleep(20);
- MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN -
- mdss_v2_intf_off, 0);
- ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
- NULL);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
- mdss_mdp_footswitch_ctrl_splash(0);
- return ret;
}
static int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
@@ -736,8 +647,10 @@
return rc;
}
- if (mfd->panel_info->cont_splash_enabled)
- mdss_mdp_reconfigure_splash_done(mdp5_data->ctl);
+ if (mfd->panel_info->cont_splash_enabled) {
+ mdss_mdp_ctl_splash_finish(mdp5_data->ctl);
+ mdss_mdp_footswitch_ctrl_splash(0);
+ }
if (!is_mdss_iommu_attached()) {
mdss_iommu_attach(mdss_res);
@@ -826,7 +739,7 @@
mutex_unlock(&mfd->no_update.lock);
commit_fail:
- ret = mdss_mdp_overlay_cleanup(mfd);
+ mdss_mdp_overlay_cleanup(mfd);
mutex_unlock(&mdp5_data->ov_lock);
@@ -1021,7 +934,7 @@
return ret;
}
-static int mdss_mdp_overlay_force_cleanup(struct msm_fb_data_type *mfd)
+static void mdss_mdp_overlay_force_cleanup(struct msm_fb_data_type *mfd)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
@@ -1039,9 +952,7 @@
mdss_mdp_display_wait4comp(ctl);
}
- ret = mdss_mdp_overlay_cleanup(mfd);
-
- return ret;
+ mdss_mdp_overlay_cleanup(mfd);
}
static void mdss_mdp_overlay_force_dma_cleanup(struct mdss_data_type *mdata)
@@ -1200,7 +1111,8 @@
fbi = mfd->fbi;
- if (fbi->fix.smem_len == 0 || mdp5_data->borderfill_enable) {
+ if (!fbi->fix.smem_start || fbi->fix.smem_len == 0 ||
+ mdp5_data->borderfill_enable) {
mfd->mdp.kickoff_fnc(mfd);
return;
}
@@ -1231,9 +1143,13 @@
goto pan_display_error;
}
- if (is_mdss_iommu_attached())
+ if (is_mdss_iommu_attached()) {
+ if (!mfd->iova) {
+ pr_err("mfd iova is zero\n");
+ goto pan_display_error;
+ }
data.p[0].addr = mfd->iova;
- else
+ } else
data.p[0].addr = fbi->fix.smem_start;
data.p[0].addr += offset;
@@ -1551,6 +1467,7 @@
int ret;
struct msmfb_mdp_pp mdp_pp;
u32 copyback = 0;
+ u32 copy_from_kernel = 0;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp));
@@ -1577,7 +1494,7 @@
mdp5_data->ctl,
(struct mdp_igc_lut_data *)
&mdp_pp.data.lut_cfg_data.data,
- ©back);
+ ©back, copy_from_kernel);
break;
case mdp_lut_pgc:
@@ -1914,7 +1831,10 @@
return rc;
}
- if (!IS_ERR_VALUE(rc) && mdp5_data->vsync_pending) {
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("Failed to turn on fb%d\n", mfd->index);
+ mdss_mdp_overlay_off(mfd);
+ } else if (mdp5_data->vsync_pending) {
mdp5_data->vsync_pending = 0;
mdss_mdp_overlay_vsync_ctrl(mfd, mdp5_data->vsync_pending);
}
@@ -1971,7 +1891,7 @@
if (pdata->panel_info.cont_splash_enabled) {
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
mdss_mdp_footswitch_ctrl_splash(1);
- mdss_mdp_copy_splash_screen(pdata);
+ mdss_mdp_ctl_splash_start(pdata);
}
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 12ff943..65b5fc4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -93,6 +93,72 @@
static u32 dither_depth_map[9] = {
0, 0, 0, 0, 0, 1, 2, 3, 3};
+static u32 igc_limited[IGC_LUT_ENTRIES] = {
+ 16777472, 17826064, 18874656, 19923248,
+ 19923248, 20971840, 22020432, 23069024,
+ 24117616, 25166208, 26214800, 26214800,
+ 27263392, 28311984, 29360576, 30409168,
+ 31457760, 32506352, 32506352, 33554944,
+ 34603536, 35652128, 36700720, 37749312,
+ 38797904, 38797904, 39846496, 40895088,
+ 41943680, 42992272, 44040864, 45089456,
+ 45089456, 46138048, 47186640, 48235232,
+ 49283824, 50332416, 51381008, 51381008,
+ 52429600, 53478192, 54526784, 55575376,
+ 56623968, 57672560, 58721152, 58721152,
+ 59769744, 60818336, 61866928, 62915520,
+ 63964112, 65012704, 65012704, 66061296,
+ 67109888, 68158480, 69207072, 70255664,
+ 71304256, 71304256, 72352848, 73401440,
+ 74450032, 75498624, 76547216, 77595808,
+ 77595808, 78644400, 79692992, 80741584,
+ 81790176, 82838768, 83887360, 83887360,
+ 84935952, 85984544, 87033136, 88081728,
+ 89130320, 90178912, 90178912, 91227504,
+ 92276096, 93324688, 94373280, 95421872,
+ 96470464, 96470464, 97519056, 98567648,
+ 99616240, 100664832, 101713424, 102762016,
+ 102762016, 103810608, 104859200, 105907792,
+ 106956384, 108004976, 109053568, 109053568,
+ 110102160, 111150752, 112199344, 113247936,
+ 114296528, 115345120, 115345120, 116393712,
+ 117442304, 118490896, 119539488, 120588080,
+ 121636672, 121636672, 122685264, 123733856,
+ 124782448, 125831040, 126879632, 127928224,
+ 127928224, 128976816, 130025408, 131074000,
+ 132122592, 133171184, 134219776, 135268368,
+ 135268368, 136316960, 137365552, 138414144,
+ 139462736, 140511328, 141559920, 141559920,
+ 142608512, 143657104, 144705696, 145754288,
+ 146802880, 147851472, 147851472, 148900064,
+ 149948656, 150997248, 152045840, 153094432,
+ 154143024, 154143024, 155191616, 156240208,
+ 157288800, 158337392, 159385984, 160434576,
+ 160434576, 161483168, 162531760, 163580352,
+ 164628944, 165677536, 166726128, 166726128,
+ 167774720, 168823312, 169871904, 170920496,
+ 171969088, 173017680, 173017680, 174066272,
+ 175114864, 176163456, 177212048, 178260640,
+ 179309232, 179309232, 180357824, 181406416,
+ 182455008, 183503600, 184552192, 185600784,
+ 185600784, 186649376, 187697968, 188746560,
+ 189795152, 190843744, 191892336, 191892336,
+ 192940928, 193989520, 195038112, 196086704,
+ 197135296, 198183888, 198183888, 199232480,
+ 200281072, 201329664, 202378256, 203426848,
+ 204475440, 204475440, 205524032, 206572624,
+ 207621216, 208669808, 209718400, 210766992,
+ 211815584, 211815584, 212864176, 213912768,
+ 214961360, 216009952, 217058544, 218107136,
+ 218107136, 219155728, 220204320, 221252912,
+ 222301504, 223350096, 224398688, 224398688,
+ 225447280, 226495872, 227544464, 228593056,
+ 229641648, 230690240, 230690240, 231738832,
+ 232787424, 233836016, 234884608, 235933200,
+ 236981792, 236981792, 238030384, 239078976,
+ 240127568, 241176160, 242224752, 243273344,
+ 243273344, 244321936, 245370528, 246419120};
+
#define GAMUT_T0_SIZE 125
#define GAMUT_T1_SIZE 100
#define GAMUT_T2_SIZE 80
@@ -178,11 +244,9 @@
struct mdp_dither_cfg_data dither_disp_cfg[MDSS_BLOCK_DISP_NUM];
struct mdp_gamut_cfg_data gamut_disp_cfg[MDSS_BLOCK_DISP_NUM];
uint16_t gamut_tbl[MDSS_BLOCK_DISP_NUM][GAMUT_TOTAL_TABLE_SIZE];
- struct pp_hist_col_info
- *hist_col[MDSS_BLOCK_DISP_NUM][MDSS_MDP_MAX_DSPP];
u32 hist_data[MDSS_BLOCK_DISP_NUM][HIST_V_SIZE];
/* physical info */
- struct pp_sts_type pp_dspp_sts[MDSS_MDP_MAX_DSPP];
+ struct pp_sts_type pp_disp_sts[MDSS_BLOCK_DISP_NUM];
struct pp_hist_col_info dspp_hist[MDSS_MDP_MAX_DSPP];
};
@@ -671,7 +735,7 @@
else
scale_config |= /* RGB, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
- (MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+ (MDSS_MDP_SCALE_FILTER_PCMN << 18);
}
phasey_step = mdss_mdp_scale_phase_step(
@@ -728,7 +792,7 @@
else
scale_config |= /* RGB, A */
(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
- (MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+ (MDSS_MDP_SCALE_FILTER_PCMN << 16);
}
phasex_step = mdss_mdp_scale_phase_step(
@@ -838,7 +902,7 @@
else
flags = 0;
- pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
+ pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
/* GC_LUT is in layer mixer */
if (flags & PP_FLAGS_DIRTY_ARGC) {
pgc_config = &mdss_pp_res->argc_disp_cfg[disp_num];
@@ -982,7 +1046,7 @@
goto dspp_exit;
ret = 0;
- pp_sts = &mdss_pp_res->pp_dspp_sts[dspp_num];
+ pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
pp_pa_config(flags, base + MDSS_MDP_REG_DSPP_PA_BASE, pp_sts,
&mdss_pp_res->pa_disp_cfg[disp_num]);
@@ -1126,19 +1190,20 @@
* Set dirty and write bits on features that were enabled so they will be
* reconfigured
*/
-int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 mixer_num)
+int mdss_mdp_pp_resume(struct mdss_mdp_ctl *ctl, u32 dspp_num)
{
- u32 flags = 0;
+ u32 flags = 0, disp_num;
struct pp_sts_type pp_sts;
struct mdss_ad_info *ad;
struct mdss_data_type *mdata = ctl->mdata;
- if (mixer_num >= MDSS_MDP_MAX_DSPP) {
- pr_warn("invalid mixer_num");
+ if (dspp_num >= MDSS_MDP_MAX_DSPP) {
+ pr_warn("invalid dspp_num");
return -EINVAL;
}
+ disp_num = ctl->mfd->index;
- if (mixer_num < mdata->nad_cfgs) {
- ad = &mdata->ad_cfgs[mixer_num];
+ if (dspp_num < mdata->nad_cfgs) {
+ ad = &mdata->ad_cfgs[dspp_num];
if (PP_AD_STATE_CFG & ad->state)
pp_ad_cfg_write(ad);
@@ -1150,66 +1215,66 @@
ctl->add_vsync_handler(ctl, &ad->handle);
}
- pp_sts = mdss_pp_res->pp_dspp_sts[mixer_num];
+ pp_sts = mdss_pp_res->pp_disp_sts[disp_num];
if (pp_sts.pa_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_PA;
- if (!(mdss_pp_res->pa_disp_cfg[mixer_num].flags
+ if (!(mdss_pp_res->pa_disp_cfg[disp_num].flags
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->pa_disp_cfg[mixer_num].flags |=
+ mdss_pp_res->pa_disp_cfg[disp_num].flags |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.pcc_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_PCC;
- if (!(mdss_pp_res->pcc_disp_cfg[mixer_num].ops
+ if (!(mdss_pp_res->pcc_disp_cfg[disp_num].ops
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->pcc_disp_cfg[mixer_num].ops |=
+ mdss_pp_res->pcc_disp_cfg[disp_num].ops |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.igc_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_IGC;
- if (!(mdss_pp_res->igc_disp_cfg[mixer_num].ops
+ if (!(mdss_pp_res->igc_disp_cfg[disp_num].ops
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->igc_disp_cfg[mixer_num].ops |=
+ mdss_pp_res->igc_disp_cfg[disp_num].ops |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.argc_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_ARGC;
- if (!(mdss_pp_res->argc_disp_cfg[mixer_num].flags
+ if (!(mdss_pp_res->argc_disp_cfg[disp_num].flags
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->argc_disp_cfg[mixer_num].flags |=
+ mdss_pp_res->argc_disp_cfg[disp_num].flags |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.enhist_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_ENHIST;
- if (!(mdss_pp_res->enhist_disp_cfg[mixer_num].ops
+ if (!(mdss_pp_res->enhist_disp_cfg[disp_num].ops
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->enhist_disp_cfg[mixer_num].ops |=
+ mdss_pp_res->enhist_disp_cfg[disp_num].ops |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.dither_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_DITHER;
- if (!(mdss_pp_res->dither_disp_cfg[mixer_num].flags
+ if (!(mdss_pp_res->dither_disp_cfg[disp_num].flags
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->dither_disp_cfg[mixer_num].flags |=
+ mdss_pp_res->dither_disp_cfg[disp_num].flags |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.gamut_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_GAMUT;
- if (!(mdss_pp_res->gamut_disp_cfg[mixer_num].flags
+ if (!(mdss_pp_res->gamut_disp_cfg[disp_num].flags
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->gamut_disp_cfg[mixer_num].flags |=
+ mdss_pp_res->gamut_disp_cfg[disp_num].flags |=
MDP_PP_OPS_WRITE;
}
if (pp_sts.pgc_sts & PP_STS_ENABLE) {
flags |= PP_FLAGS_DIRTY_PGC;
- if (!(mdss_pp_res->pgc_disp_cfg[mixer_num].flags
+ if (!(mdss_pp_res->pgc_disp_cfg[disp_num].flags
& MDP_PP_OPS_DISABLE))
- mdss_pp_res->pgc_disp_cfg[mixer_num].flags |=
+ mdss_pp_res->pgc_disp_cfg[disp_num].flags |=
MDP_PP_OPS_WRITE;
}
- mdss_pp_res->pp_disp_flags[mixer_num] = flags;
+ mdss_pp_res->pp_disp_flags[disp_num] |= flags;
return 0;
}
@@ -1544,9 +1609,30 @@
MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
}
+int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl)
+{
+ int ret = 0;
+ u32 copyback = 0;
+ u32 copy_from_kernel = 1;
+ struct mdp_igc_lut_data config;
+
+ if (!ctl)
+ return -EINVAL;
+
+ config.len = IGC_LUT_ENTRIES;
+ config.ops = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
+ config.block = (ctl->mfd->index) + MDP_LOGICAL_BLOCK_DISP_0;
+ config.c0_c1_data = igc_limited;
+ config.c2_data = igc_limited;
+
+ ret = mdss_mdp_igc_lut_config(ctl, &config, ©back,
+ copy_from_kernel);
+ return ret;
+}
+
int mdss_mdp_igc_lut_config(struct mdss_mdp_ctl *ctl,
struct mdp_igc_lut_data *config,
- u32 *copyback)
+ u32 *copyback, u32 copy_from_kernel)
{
int ret = 0;
u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
@@ -1598,15 +1684,25 @@
*copyback = 1;
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
} else {
- if (copy_from_user(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
- config->c0_c1_data, config->len * sizeof(u32))) {
- ret = -EFAULT;
- goto igc_config_exit;
- }
- if (copy_from_user(&mdss_pp_res->igc_lut_c2[disp_num][0],
- config->c2_data, config->len * sizeof(u32))) {
- ret = -EFAULT;
- goto igc_config_exit;
+ if (copy_from_kernel) {
+ memcpy(&mdss_pp_res->igc_lut_c0c1[disp_num][0],
+ config->c0_c1_data, config->len * sizeof(u32));
+ memcpy(&mdss_pp_res->igc_lut_c2[disp_num][0],
+ config->c2_data, config->len * sizeof(u32));
+ } else {
+ if (copy_from_user(
+ &mdss_pp_res->igc_lut_c0c1[disp_num][0],
+ config->c0_c1_data,
+ config->len * sizeof(u32))) {
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
+ if (copy_from_user(
+ &mdss_pp_res->igc_lut_c2[disp_num][0],
+ config->c2_data, config->len * sizeof(u32))) {
+ ret = -EFAULT;
+ goto igc_config_exit;
+ }
}
mdss_pp_res->igc_disp_cfg[disp_num] = *config;
mdss_pp_res->igc_disp_cfg[disp_num].c0_c1_data =
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 60f05ca..d1f0c8d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -520,6 +520,11 @@
}
}
+ if (!*start) {
+ pr_err("start address is zero!\n");
+ return -ENOMEM;
+ }
+
if (!ret && (img->offset < data->len)) {
data->addr += img->offset;
data->len -= img->offset;
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index d230100..9e8cfa7 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -55,8 +55,35 @@
MAX_PHYS_TARGET_NUM,
};
+/**
+ * enum mdss_intf_events - Different events generated by MDP core
+ *
+ * @MDSS_EVENT_RESET: MDP control path is being (re)initialized.
+ * @MDSS_EVENT_UNBLANK: Sent before first frame update from MDP is
+ * sent to panel.
+ * @MDSS_EVENT_PANEL_ON: After first frame update from MDP.
+ * @MDSS_EVENT_BLANK: MDP has no contents to display only blank screen
+ * is shown in panel. Sent before panel off.
+ * @MDSS_EVENT_PANEL_OFF: MDP has suspended frame updates, panel should be
+ * completely shutdown after this call.
+ * @MDSS_EVENT_CLOSE: MDP has tore down entire session.
+ * @MDSS_EVENT_SUSPEND: Propagation of power suspend event.
+ * @MDSS_EVENT_RESUME: Propagation of power resume event.
+ * @MDSS_EVENT_CHECK_PARAMS: Event generated when a panel reconfiguration is
+ * requested including when resolution changes.
+ * The event handler receives pointer to
+ * struct mdss_panel_info and should return one of:
+ * - negative if the configuration is invalid
+ * - 0 if there is no panel reconfig needed
+ * - 1 if reconfig is needed to take effect
+ * @MDSS_EVENT_CONT_SPLASH_FINISH: Special event used to handle transition of
+ * display state from boot loader to panel driver.
+ * @MDSS_EVENT_FB_REGISTERED: Called after fb dev driver has been registered,
+ * panel driver gets ptr to struct fb_info which
+ * holds fb dev information.
+ */
enum mdss_intf_events {
- MDSS_EVENT_RESET,
+ MDSS_EVENT_RESET = 1,
MDSS_EVENT_UNBLANK,
MDSS_EVENT_PANEL_ON,
MDSS_EVENT_BLANK,
@@ -214,7 +241,18 @@
void (*set_backlight) (struct mdss_panel_data *pdata, u32 bl_level);
unsigned char *mmss_cc_base;
- /* function entry chain */
+ /**
+ * event_handler() - callback handler for MDP core events
+ * @pdata: Pointer refering to the panel struct associated to this
+ * event. Can be used to retrieve panel info.
+ * @e: Event being generated, see enum mdss_intf_events
+ * @arg: Optional argument to pass some info from some events.
+ *
+ * Used to register handler to be used to propagate different events
+ * happening in MDP core driver. Panel driver can listen for any of
+ * these events to perform appropriate actions for panel initialization
+ * and teardown.
+ */
int (*event_handler) (struct mdss_panel_data *pdata, int e, void *arg);
struct mdss_panel_data *next;
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index a3a1a4e..3c11317 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -190,7 +190,7 @@
static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl,
- enum mhl_st_type to_mode);
+ enum mhl_st_type to_mode, bool hpd_off);
static void mhl_init_reg_settings(struct mhl_tx_ctrl *mhl_ctrl,
bool mhl_disc_en);
@@ -703,9 +703,18 @@
}
-static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl, enum mhl_st_type to_mode)
+static void switch_mode(struct mhl_tx_ctrl *mhl_ctrl, enum mhl_st_type to_mode,
+ bool hpd_off)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
+ int rc;
+ struct msm_hdmi_mhl_ops *hdmi_mhl_ops = mhl_ctrl->hdmi_mhl_ops;
+
+ pr_debug("%s: tx pwr on\n", __func__);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
switch (to_mode) {
case POWER_STATE_D0_NO_MHL:
@@ -722,8 +731,11 @@
mhl_ctrl->cur_state = to_mode;
break;
case POWER_STATE_D3:
- if (mhl_ctrl->cur_state == POWER_STATE_D3)
+ if (mhl_ctrl->cur_state == POWER_STATE_D3) {
+ pr_debug("%s: mhl tx already in low power mode\n",
+ __func__);
break;
+ }
/* Force HPD to 0 when not in MHL mode. */
mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
@@ -736,7 +748,12 @@
msleep(50);
if (!mhl_ctrl->disc_enabled)
MHL_SII_REG_NAME_MOD(REG_DISC_CTRL1, BIT1 | BIT0, 0x00);
- MHL_SII_PAGE3_MOD(0x003D, BIT0, 0x00);
+ if (hdmi_mhl_ops && hpd_off) {
+ rc = hdmi_mhl_ops->set_upstream_hpd(
+ mhl_ctrl->pdata->hdmi_pdev, 0);
+ pr_debug("%s: hdmi unset hpd %s\n", __func__,
+ rc ? "failed" : "passed");
+ }
mhl_ctrl->cur_state = POWER_STATE_D3;
break;
default:
@@ -744,6 +761,22 @@
}
}
+static bool is_mhl_powered(void *mhl_ctx)
+{
+ struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)mhl_ctx;
+ unsigned long flags;
+ bool r = false;
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ if (mhl_ctrl->tx_powered_off)
+ r = false;
+ else
+ r = true;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+ pr_debug("%s: ret pwr state as %x\n", __func__, r);
+ return r;
+}
void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
{
@@ -759,6 +792,7 @@
void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
pr_debug("%s: To state=[0x%x]\n", __func__, to_state);
if (to_state == HPD_UP) {
@@ -769,10 +803,13 @@
* propogate to src let HPD float by clearing
* HPD OUT OVRRD EN
*/
- MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0x00);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, 0);
} else {
/* Drive HPD to DOWN state */
- MHL_SII_REG_NAME_MOD(REG_INT_CTRL, BIT4, BIT4);
+ MHL_SII_REG_NAME_MOD(REG_INT_CTRL, (BIT4 | BIT5), BIT4);
}
}
@@ -789,9 +826,7 @@
pr_err("%s: cur st not D0\n", __func__);
return;
}
- /* spin_lock_irqsave(&mhl_state_lock, flags); */
- switch_mode(mhl_ctrl, POWER_STATE_D0_MHL);
- /* spin_unlock_irqrestore(&mhl_state_lock, flags); */
+ switch_mode(mhl_ctrl, POWER_STATE_D0_MHL, true);
MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0x10);
MHL_SII_CBUS_WR(0x07, 0xF2);
@@ -823,19 +858,29 @@
static void mhl_msm_disconnection(struct mhl_tx_ctrl *mhl_ctrl)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
- /*
- * MHL TX CTL1
- * Disabling Tx termination
- */
- MHL_SII_PAGE3_WR(0x30, 0xD0);
+ unsigned long flags;
- switch_mode(mhl_ctrl, POWER_STATE_D3);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd &= ~BIT6;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+ /* disabling Tx termination */
+ MHL_SII_REG_NAME_WR(REG_MHLTX_CTL1, 0xD0);
+ switch_mode(mhl_ctrl, POWER_STATE_D3, true);
}
static int mhl_msm_read_rgnd_int(struct mhl_tx_ctrl *mhl_ctrl)
{
uint8_t rgnd_imp;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ struct msm_hdmi_mhl_ops *hdmi_mhl_ops = mhl_ctrl->hdmi_mhl_ops;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
/* DISC STATUS REG 2 */
rgnd_imp = (mhl_i2c_reg_read(client, TX_PAGE_3, 0x001C) &
(BIT1 | BIT0));
@@ -843,6 +888,12 @@
if (0x02 == rgnd_imp) {
pr_debug("%s: mhl sink\n", __func__);
+ if (hdmi_mhl_ops) {
+ rc = hdmi_mhl_ops->set_upstream_hpd(
+ mhl_ctrl->pdata->hdmi_pdev, 1);
+ pr_debug("%s: hdmi set hpd %s\n", __func__,
+ rc ? "failed" : "passed");
+ }
mhl_ctrl->mhl_mode = 1;
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
@@ -850,7 +901,7 @@
} else {
pr_debug("%s: non-mhl sink\n", __func__);
mhl_ctrl->mhl_mode = 0;
- switch_mode(mhl_ctrl, POWER_STATE_D3);
+ switch_mode(mhl_ctrl, POWER_STATE_D3, true);
}
complete(&mhl_ctrl->rgnd_done);
return mhl_ctrl->mhl_mode ?
@@ -904,9 +955,9 @@
}
-static void dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl)
+static int dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl)
{
- uint8_t status, reg ;
+ uint8_t status, reg;
struct i2c_client *client = mhl_ctrl->i2c_handle;
/* INTR_STATUS4 */
@@ -916,13 +967,13 @@
if ((0x00 == status) &&\
(mhl_ctrl->cur_state == POWER_STATE_D3)) {
pr_err("%s: invalid intr\n", __func__);
- return;
+ return 0;
}
if (0xFF == status) {
pr_debug("%s: invalid intr 0xff\n", __func__);
MHL_SII_REG_NAME_WR(REG_INTR4, status);
- return;
+ return 0;
}
if ((status & BIT0) && (mhl_ctrl->chip_rev_id < 1)) {
@@ -940,31 +991,35 @@
mhl_msm_connection(mhl_ctrl);
} else if (status & BIT3) {
pr_debug("%s: uUSB-a type dev detct\n", __func__);
+
/* Short RGND */
MHL_SII_REG_NAME_MOD(REG_DISC_STAT2, BIT0 | BIT1, 0x00);
mhl_msm_disconnection(mhl_ctrl);
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(0);
+ return -EACCES;
}
if (status & BIT5) {
/* clr intr - reg int4 */
pr_debug("%s: mhl discon: int4 st=%02X\n", __func__,
(int)status);
+
reg = MHL_SII_REG_NAME_RD(REG_INTR4);
MHL_SII_REG_NAME_WR(REG_INTR4, reg);
mhl_msm_disconnection(mhl_ctrl);
power_supply_changed(&mhl_ctrl->mhl_psy);
if (mhl_ctrl->notify_usb_online)
mhl_ctrl->notify_usb_online(0);
+ return -EACCES;
}
if ((mhl_ctrl->cur_state != POWER_STATE_D0_NO_MHL) &&\
(status & BIT6)) {
/* rgnd rdy Intr */
pr_debug("%s: rgnd ready intr\n", __func__);
- switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL);
+ switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL, true);
mhl_msm_read_rgnd_int(mhl_ctrl);
}
@@ -981,6 +1036,7 @@
release_usb_switch_open(mhl_ctrl);
}
MHL_SII_REG_NAME_WR(REG_INTR4, status);
+ return 0;
}
static void mhl_misc_isr(struct mhl_tx_ctrl *mhl_ctrl)
@@ -1000,10 +1056,13 @@
static void mhl_hpd_stat_isr(struct mhl_tx_ctrl *mhl_ctrl)
{
- uint8_t intr_1_stat;
- uint8_t cbus_stat;
+ uint8_t intr_1_stat, cbus_stat, t;
+ unsigned long flags;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ if (!is_mhl_powered(mhl_ctrl))
+ return;
+
/* INTR STATUS 1 */
intr_1_stat = MHL_SII_PAGE0_RD(0x0071);
@@ -1012,6 +1071,7 @@
/* Clear interrupts */
MHL_SII_PAGE0_WR(0x0071, intr_1_stat);
+
if (BIT6 & intr_1_stat) {
/*
* HPD status change event is pending
@@ -1019,11 +1079,26 @@
* MSC REQ ABRT REASON
*/
cbus_stat = MHL_SII_CBUS_RD(0x0D);
- if (BIT6 & cbus_stat)
- mhl_drive_hpd(mhl_ctrl, HPD_UP);
- else
- mhl_drive_hpd(mhl_ctrl, HPD_DOWN);
+ pr_debug("%s: cbus_stat=[0x%02x] cur_pwr=[%u]\n",
+ __func__, cbus_stat, mhl_ctrl->cur_state);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ t = mhl_ctrl->dwnstream_hpd;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+
+ if (BIT6 & (cbus_stat ^ t)) {
+ u8 status = cbus_stat & BIT6;
+ mhl_drive_hpd(mhl_ctrl, status ? HPD_UP : HPD_DOWN);
+ if (!status) {
+ MHL_SII_PAGE1_MOD(0x003D, BIT0, 0x00);
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->tx_powered_off = true;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ }
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd = cbus_stat;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
+ }
}
}
@@ -1257,122 +1332,9 @@
}
-static void clear_all_intrs(struct i2c_client *client)
-{
- uint8_t regval = 0x00;
-
- pr_debug_intr("********* exiting isr mask check ?? *************\n");
- pr_debug_intr("int1 mask = %02X\n",
- (int) MHL_SII_REG_NAME_RD(REG_INTR1));
- pr_debug_intr("int3 mask = %02X\n",
- (int) MHL_SII_PAGE0_RD(0x0077));
- pr_debug_intr("int4 mask = %02X\n",
- (int) MHL_SII_REG_NAME_RD(REG_INTR4));
- pr_debug_intr("int5 mask = %02X\n",
- (int) MHL_SII_REG_NAME_RD(REG_INTR5));
- pr_debug_intr("cbus1 mask = %02X\n",
- (int) MHL_SII_CBUS_RD(0x0009));
- pr_debug_intr("cbus2 mask = %02X\n",
- (int) MHL_SII_CBUS_RD(0x001F));
- pr_debug_intr("********* end of isr mask check *************\n");
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR1);
- pr_debug_intr("int1 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR1, regval);
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR2);
- pr_debug_intr("int2 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR2, regval);
-
- regval = MHL_SII_PAGE0_RD(0x0073);
- pr_debug_intr("int3 st = %02X\n", (int)regval);
- MHL_SII_PAGE0_WR(0x0073, regval);
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR4);
- pr_debug_intr("int4 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR4, regval);
-
- regval = MHL_SII_REG_NAME_RD(REG_INTR5);
- pr_debug_intr("int5 st = %02X\n", (int)regval);
- MHL_SII_REG_NAME_WR(REG_INTR5, regval);
-
- regval = MHL_SII_CBUS_RD(0x0008);
- pr_debug_intr("cbusInt st = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x0008, regval);
-
- regval = MHL_SII_CBUS_RD(0x001E);
- pr_debug_intr("CBUS intR_2: %d\n", (int)regval);
- MHL_SII_CBUS_WR(0x001E, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A0);
- pr_debug_intr("A0 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A1);
- pr_debug_intr("A1 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A2);
- pr_debug_intr("A2 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00A3);
- pr_debug_intr("A3 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00A3, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B0);
- pr_debug_intr("B0 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B1);
- pr_debug_intr("B1 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B2);
- pr_debug_intr("B2 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00B3);
- pr_debug_intr("B3 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00B3, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E0);
- pr_debug_intr("E0 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E1);
- pr_debug_intr("E1 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E2);
- pr_debug_intr("E2 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00E3);
- pr_debug_intr("E3 st set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00E3, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F0);
- pr_debug_intr("F0 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F0, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F1);
- pr_debug_intr("F1 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F1, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F2);
- pr_debug_intr("F2 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F2, regval);
-
- regval = MHL_SII_CBUS_RD(0x00F3);
- pr_debug_intr("F3 int set = %02X\n", (int)regval);
- MHL_SII_CBUS_WR(0x00F3, regval);
- pr_debug_intr("********* end of exiting in isr *************\n");
-}
-
-
static irqreturn_t mhl_tx_isr(int irq, void *data)
{
+ int rc;
struct mhl_tx_ctrl *mhl_ctrl = (struct mhl_tx_ctrl *)data;
pr_debug("%s: Getting Interrupts\n", __func__);
@@ -1380,28 +1342,27 @@
* Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT
* interrupts. In D3, we get only RGND
*/
- dev_detect_isr(mhl_ctrl);
+ rc = dev_detect_isr(mhl_ctrl);
+ if (rc)
+ pr_debug("%s: dev_detect_isr rc=[%d]\n", __func__, rc);
pr_debug("%s: cur pwr state is [0x%x]\n",
__func__, mhl_ctrl->cur_state);
- if (mhl_ctrl->cur_state == POWER_STATE_D0_MHL) {
- /*
- * If dev_detect_isr() didn't move the tx to D3
- * on disconnect, continue to check other
- * interrupt sources.
- */
- mhl_misc_isr(mhl_ctrl);
- /*
- * Check for any peer messages for DCAP_CHG, MSC etc
- * Dispatch to have the CBUS module working only
- * once connected.
- */
- mhl_cbus_isr(mhl_ctrl);
- mhl_hpd_stat_isr(mhl_ctrl);
- }
+ /*
+ * If dev_detect_isr() didn't move the tx to D3
+ * on disconnect, continue to check other
+ * interrupt sources.
+ */
+ mhl_misc_isr(mhl_ctrl);
- clear_all_intrs(mhl_ctrl->i2c_handle);
+ /*
+ * Check for any peer messages for DCAP_CHG, MSC etc
+ * Dispatch to have the CBUS module working only
+ * once connected.
+ */
+ mhl_cbus_isr(mhl_ctrl);
+ mhl_hpd_stat_isr(mhl_ctrl);
return IRQ_HANDLED;
}
@@ -1410,6 +1371,13 @@
{
uint8_t chip_rev_id = 0x00;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&mhl_ctrl->lock, flags);
+ mhl_ctrl->dwnstream_hpd = 0;
+ mhl_ctrl->tx_powered_off = false;
+ spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
/* Reset the TX chip */
mhl_sii_reset_pin(mhl_ctrl, 0);
@@ -1428,7 +1396,7 @@
* MHL-USB handshake is implemented
*/
mhl_init_reg_settings(mhl_ctrl, true);
- switch_mode(mhl_ctrl, POWER_STATE_D3);
+ switch_mode(mhl_ctrl, POWER_STATE_D3, true);
return 0;
}
@@ -1710,6 +1678,7 @@
mhl_ctrl->cur_state = POWER_STATE_D0_MHL;
INIT_LIST_HEAD(&mhl_ctrl->list_cmd);
init_completion(&mhl_ctrl->msc_cmd_done);
+ spin_lock_init(&mhl_ctrl->lock);
mhl_ctrl->msc_send_workqueue = create_singlethread_workqueue
("mhl_msc_cmd_queue");
@@ -1813,7 +1782,7 @@
pr_debug("%s: i2c client addr is [%x]\n", __func__, client->addr);
if (mhl_ctrl->pdata->hdmi_pdev) {
rc = msm_hdmi_register_mhl(mhl_ctrl->pdata->hdmi_pdev,
- hdmi_mhl_ops);
+ hdmi_mhl_ops, mhl_ctrl);
if (rc) {
pr_err("%s: register with hdmi failed\n", __func__);
rc = -EPROBE_DEFER;
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 2f77d29..73b94af 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -286,7 +286,7 @@
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW,
- MSG_LVL_HIGH,
+ MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
@@ -725,7 +725,7 @@
/* LOG CODES */
#define LOG_0 0x0
-#define LOG_1 0x17F4
+#define LOG_1 0x17FA
#define LOG_2 0x0
#define LOG_3 0x0
#define LOG_4 0x4910
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index c219725..aa1eba5 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -229,7 +229,15 @@
DMX_EVENT_MARKER = 0x00000100,
/* New indexing entry is ready */
- DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200
+ DMX_EVENT_NEW_INDEX_ENTRY = 0x00000200,
+
+ /*
+ * Section filter timer expired. This is notified
+ * when timeout is configured to section filter
+ * (dmx_sct_filter_params) and no sections were
+ * received for the given time.
+ */
+ DMX_EVENT_SECTION_TIMEOUT = 0x00000400
};
enum dmx_oob_cmd {
@@ -706,6 +714,46 @@
__u64 types;
};
+struct dmx_set_ts_insertion {
+ /*
+ * Unique identifier managed by the caller.
+ * This identifier can be used later to remove the
+ * insertion using DMX_ABORT_TS_INSERTION ioctl.
+ */
+ __u32 identifier;
+
+ /*
+ * Repetition time in msec, minimum allowed value is 25msec.
+ * 0 repetition time means one-shot insertion is done.
+ * Insertion done based on wall-clock.
+ */
+ __u32 repetition_time;
+
+ /*
+ * TS packets buffer to be inserted.
+ * The buffer is inserted as-is to the recording buffer
+ * without any modification.
+ * It is advised to set discontinuity flag in the very
+ * first TS packet in the buffer.
+ */
+ const __u8 *ts_packets;
+
+ /*
+ * Size in bytes of the TS packets buffer to be inserted.
+ * Should be in multiples of 188 or 192 bytes
+ * depending on recording filter output format.
+ */
+ size_t size;
+};
+
+struct dmx_abort_ts_insertion {
+ /*
+ * Identifier of the insertion buffer previously set
+ * using DMX_SET_TS_INSERTION.
+ */
+ __u32 identifier;
+};
+
#define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@@ -734,5 +782,7 @@
#define DMX_GET_EVENTS_MASK _IOR('o', 67, struct dmx_events_mask)
#define DMX_PUSH_OOB_COMMAND _IOW('o', 68, struct dmx_oob_command)
#define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params)
+#define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion)
+#define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/input/gen_vkeys.h b/include/linux/input/gen_vkeys.h
index ce29351..a58158d 100644
--- a/include/linux/input/gen_vkeys.h
+++ b/include/linux/input/gen_vkeys.h
@@ -19,5 +19,6 @@
int panel_maxy;
int *keycodes;
int num_keys;
+ int y_offset;
};
#endif
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index c6e4ab3..b7ba6fb 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -126,6 +126,7 @@
u8 bias2_cap_mode;
u8 bias3_cap_mode;
u8 bias4_cap_mode;
+ bool bias2_is_headset_only;
};
struct wcd9xxx_ocp_setting {
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index d8eb494..a66a411 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -158,6 +158,9 @@
int scrpd_busy;
int wr_burst_pending;
struct completion req_write_done;
+ spinlock_t lock;
+ bool tx_powered_off;
+ uint8_t dwnstream_hpd;
};
int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9eef3a0..48be19a 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -82,6 +82,12 @@
#define MMC_SET_DRIVER_TYPE_D 3
};
+/* states to represent load on the host */
+enum mmc_load {
+ MMC_LOAD_HIGH,
+ MMC_LOAD_LOW,
+};
+
struct mmc_host_ops {
/*
* 'enable' is called when the host is claimed and 'disable' is called
@@ -140,6 +146,7 @@
void (*hw_reset)(struct mmc_host *host);
unsigned long (*get_max_frequency)(struct mmc_host *host);
unsigned long (*get_min_frequency)(struct mmc_host *host);
+ int (*notify_load)(struct mmc_host *, enum mmc_load);
int (*stop_request)(struct mmc_host *host);
unsigned int (*get_xfer_remain)(struct mmc_host *host);
};
@@ -401,6 +408,7 @@
bool initialized;
bool in_progress;
struct delayed_work work;
+ enum mmc_load state;
} clk_scaling;
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 15e5dc9..13d0b80 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -197,15 +197,18 @@
/**
* enum qpnp_adc_scale_fn_type - Scaling function for pm8941 pre calibrated
* digital data relative to ADC reference.
- * %ADC_SCALE_DEFAULT: Default scaling to convert raw adc code to voltage.
- * %ADC_SCALE_BATT_THERM: Conversion to temperature based on btm parameters.
- * %ADC_SCALE_THERM_100K_PULLUP: Returns temperature in degC.
+ * %SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
+ * %SCALE_BATT_THERM: Conversion to temperature(decidegC) based on btm
+ * parameters.
+ * %SCALE_THERM_100K_PULLUP: Returns temperature in degC.
* Uses a mapping table with 100K pullup.
- * %ADC_SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
- * %ADC_SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
- * %ADC_SCALE_THERM_150K_PULLUP: Returns temperature in degC.
+ * %SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
+ * %SCALE_XOTHERM: Returns XO thermistor voltage in degree's Centigrade.
+ * %SCALE_THERM_150K_PULLUP: Returns temperature in degC.
* Uses a mapping table with 150K pullup.
- * %ADC_SCALE_NONE: Do not use this scaling type.
+ * %SCALE_QRD_BATT_THERM: Conversion to temperature(decidegC) based on
+ * btm parameters.
+ * %SCALE_NONE: Do not use this scaling type.
*/
enum qpnp_adc_scale_fn_type {
SCALE_DEFAULT = 0,
@@ -214,6 +217,7 @@
SCALE_PMIC_THERM,
SCALE_XOTHERM,
SCALE_THERM_150K_PULLUP,
+ SCALE_QRD_BATT_THERM,
SCALE_NONE,
};
@@ -1039,7 +1043,7 @@
/**
* qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
- * gain and offset. Returns the temperature in degC.
+ * gain and offset. Returns the temperature in decidegC.
* @adc_code: pre-calibrated digital ouput of the ADC.
* @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
* reference voltage.
@@ -1052,6 +1056,21 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_adc_scale_qrd_batt_therm() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Returns the temperature in decidegC.
+ * @adc_code: pre-calibrated digital ouput of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
@@ -1257,6 +1276,11 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 74b09cb..ef8323e 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -700,6 +700,8 @@
#define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x4000
#define V4L2_QCOM_BUF_FLAG_EOSEQ 0x8000
#define V4L2_QCOM_BUF_TIMESTAMP_INVALID 0x10000
+#define V4L2_QCOM_BUF_FLAG_IDRFRAME 0x20000 /* Image is a IDR-frame */
+#define V4L2_QCOM_BUF_FLAG_DECODEONLY 0x40000
/*
* O V E R L A Y P R E V I E W
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 992649f..47cf184 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -289,8 +289,8 @@
enum eeprom_cfg_type_t {
CFG_EEPROM_GET_INFO,
- CFG_EEPROM_GET_DATA,
- CFG_EEPROM_READ_DATA,
+ CFG_EEPROM_GET_CAL_DATA,
+ CFG_EEPROM_READ_CAL_DATA,
CFG_EEPROM_WRITE_DATA,
};
struct eeprom_get_t {
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index bf6b23b..3775ddd 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -64,6 +64,7 @@
EVERY_8FRAME,
EVERY_16FRAME,
EVERY_32FRAME,
+ SKIP_ALL,
MAX_SKIP,
};
diff --git a/include/media/radio-iris-commands.h b/include/media/radio-iris-commands.h
index d41baa9..0b3331a 100644
--- a/include/media/radio-iris-commands.h
+++ b/include/media/radio-iris-commands.h
@@ -71,6 +71,7 @@
V4L2_CID_PRIVATE_CF0TH12,
V4L2_CID_PRIVATE_SINRFIRSTSTAGE,
V4L2_CID_PRIVATE_RMSSIFIRSTSTAGE,
+ V4L2_CID_PRIVATE_RXREPEATCOUNT,
/*using private CIDs under userclass*/
V4L2_CID_PRIVATE_IRIS_READ_DEFAULT = 0x00980928,
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 53602c5..d6151c0 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -73,6 +73,9 @@
#define CF0TH12_BYTE4_OFFSET 11
#define MAX_SINR_FIRSTSTAGE 127
#define MAX_RMSSI_FIRSTSTAGE 127
+#define RDS_PS0_XFR_MODE 0x01
+#define RDS_PS0_LEN 6
+#define RX_REPEATE_BYTE_OFFSET 5
/* HCI timeouts */
#define RADIO_HCI_TIMEOUT (10000) /* 10 seconds */
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index f064837..0d3b5a0 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -2237,7 +2237,7 @@
*/
#define ADSP_MEMORY_MAP_PHYSICAL_MEMORY 0
-
+#define NULL_COPP_TOPOLOGY 0x00010312
#define DEFAULT_COPP_TOPOLOGY 0x00010be3
#define DEFAULT_POPP_TOPOLOGY 0x00010be4
#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
@@ -6928,4 +6928,10 @@
struct afe_port_param_data_v2 pdata;
struct afe_param_id_clip_bank_sel bank_sel;
} __packed;
+
+/* Ultrasound supported formats */
+#define US_POINT_EPOS_FORMAT 0x00012310
+#define US_RAW_FORMAT 0x0001127C
+#define US_PROX_FORMAT 0x0001272B
+
#endif /*_APR_AUDIO_V2_H_ */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 81636a3..a7933a4 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1262,7 +1262,7 @@
#define MPEG4_MULTI_AAC 0x00010D86
#define US_POINT_EPOS_FORMAT 0x00012310
#define US_RAW_FORMAT 0x0001127C
-#define US_PROX_FORMAT 0x00012721
+#define US_PROX_FORMAT 0x0001272B
#define MULTI_CHANNEL_PCM 0x00010C66
#define ASM_ENCDEC_SBCRATE 0x00010C13
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 4bea1e1..449694e 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -47,10 +47,10 @@
int adm_memory_unmap_regions(int port_id, uint32_t *buf_add, uint32_t *bufsz,
uint32_t bufcnt);
-int adm_close(int port);
+int adm_close(int port, bool perf_mode);
int adm_matrix_map(int session_id, int path, int num_copps,
- unsigned int *port_id, int copp_id);
+ unsigned int *port_id, int copp_id, bool perf_mode);
int adm_connect_afe_port(int mode, int session_id, int port_id);
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index e6a2e35..edd656c 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -224,13 +224,10 @@
raw_spin_unlock(&base->cpu_base->lock);
raw_spin_lock(&new_base->cpu_base->lock);
- this_cpu = smp_processor_id();
-
- if (cpu != this_cpu && (hrtimer_check_target(timer, new_base)
- || !cpu_online(cpu))) {
+ if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) {
+ cpu = this_cpu;
raw_spin_unlock(&new_base->cpu_base->lock);
raw_spin_lock(&base->cpu_base->lock);
- cpu = smp_processor_id();
timer->base = base;
goto again;
}
diff --git a/kernel/timer.c b/kernel/timer.c
index 24c5d20..cf7217a 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1679,12 +1679,12 @@
boot_done = 1;
base = &boot_tvec_bases;
}
+ spin_lock_init(&base->lock);
tvec_base_done[cpu] = 1;
} else {
base = per_cpu(tvec_bases, cpu);
}
- spin_lock_init(&base->lock);
for (j = 0; j < TVN_SIZE; j++) {
INIT_LIST_HEAD(base->tv5.vec + j);
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index c8647fb1..e1a904f 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -34,6 +34,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
+#include <mach/qdsp6v2/apr.h>
#include "msm8x10-wcd.h"
#include "wcd9xxx-resmgr.h"
#include "msm8x10_wcd_registers.h"
@@ -52,7 +53,7 @@
#define MAX_MSM8X10_WCD_DEVICE 4
#define CODEC_DT_MAX_PROP_SIZE 40
-#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "1-000d"
+#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "5-000d"
enum {
MSM8X10_WCD_I2C_TOP_LEVEL = 0,
@@ -82,6 +83,12 @@
static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[];
static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
+#define MSM8X10_WCD_ACQUIRE_LOCK(x) do { \
+ mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
+} while (0)
+#define MSM8X10_WCD_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
+
+
/* Codec supports 2 IIR filters */
enum {
IIR1 = 0,
@@ -99,6 +106,12 @@
BAND_MAX,
};
+enum msm8x10_wcd_bandgap_type {
+ MSM8X10_WCD_BANDGAP_OFF = 0,
+ MSM8X10_WCD_BANDGAP_AUDIO_MODE,
+ MSM8X10_WCD_BANDGAP_MBHC_MODE,
+};
+
struct hpf_work {
struct msm8x10_wcd_priv *msm8x10_wcd;
u32 decimator;
@@ -113,11 +126,14 @@
u32 adc_count;
u32 rx_bias_count;
s32 dmic_1_2_clk_cnt;
-
+ enum msm8x10_wcd_bandgap_type bandgap_type;
+ bool mclk_enabled;
+ bool clock_active;
+ bool config_mode_active;
+ bool mbhc_polling_active;
+ struct mutex codec_resource_lock;
/* resmgr module */
struct wcd9xxx_resmgr resmgr;
- /* mbhc module */
- struct wcd9xxx_mbhc mbhc;
};
static unsigned short rx_digital_gain_reg[] = {
@@ -139,8 +155,8 @@
};
static char *msm8x10_wcd_supplies[] = {
- "cdc-vdd-mic-bias", "cdc-vdda-h", "cdc-vdd-1p2", "cdc-vdd-px",
- "cdc-vdda-cp",
+ "cdc-vdda-cp", "cdc-vdda-h", "cdc-vdd-px", "cdc-vdd-1p2v",
+ "cdc-vdd-mic-bias",
};
static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
@@ -158,7 +174,6 @@
{
int rtn = 0;
int value = ((reg & 0x0f00) >> 8) & 0x000f;
- pr_debug("%s: reg(0x%x) value(%d)\n", __func__, reg, value);
switch (value) {
case 0:
case 1:
@@ -171,7 +186,7 @@
return rtn;
}
-static int msm8x10_wcd_abh_write_device(u16 reg, unsigned int *value, u32 bytes)
+static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
{
u32 temp = ((u32)(*value)) & 0x000000FF;
u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
@@ -179,11 +194,13 @@
return 0;
}
-static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, unsigned int *value)
+static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
{
+ u32 temp;
u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
- *value = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
+ temp = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
offset, 4));
+ *value = (u8)temp;
return 0;
}
@@ -274,7 +291,7 @@
}
}
}
- pr_debug("%s: Reg 0x%x = 0x%x\n", __func__, reg, *dest);
+ pr_debug("%s: reg 0x%x = 0x%x\n", __func__, reg, *dest);
return 0;
}
@@ -292,20 +309,22 @@
u16 reg, unsigned int *val)
{
int ret = -EINVAL;
+ u8 temp;
/* check if use I2C interface for Helicon or AHB for Dino */
mutex_lock(&msm8x10_wcd->io_lock);
if (MSM8X10_WCD_IS_HELICON_REG(reg))
- ret = msm8x10_wcd_i2c_read(reg, 1, val);
+ ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
else if (MSM8X10_WCD_IS_DINO_REG(reg))
- ret = msm8x10_wcd_abh_read_device(reg, 1, val);
+ ret = msm8x10_wcd_abh_read_device(reg, 1, &temp);
mutex_unlock(&msm8x10_wcd->io_lock);
+ *val = temp;
return ret;
}
static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16 reg,
- unsigned int val)
+ u8 val)
{
int ret = -EINVAL;
@@ -393,7 +412,7 @@
reg, ret);
}
- return msm8x10_wcd_reg_write(codec->control_data, reg, value);
+ return msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
}
static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
@@ -438,10 +457,14 @@
regnode = of_parse_phandle(dev->of_node, prop_name, 0);
if (!regnode) {
- dev_err(dev, "Looking up %s property in node %s failed",
+ dev_err(dev, "Looking up %s property in node %s failed\n",
prop_name, dev->of_node->full_name);
return -ENODEV;
}
+
+ dev_dbg(dev, "Looking up %s property in node %s\n",
+ prop_name, dev->of_node->full_name);
+
vreg->name = vreg_name;
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
@@ -481,17 +504,7 @@
u32 prop_val;
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias-ldoh-v");
- ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
- if (ret) {
- dev_err(dev, "Looking up %s property in node %s failed",
- prop_name, dev->of_node->full_name);
- return -ENODEV;
- }
- micbias->ldoh_v = (u8)prop_val;
-
- snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias-cfilt1-mv");
+ "qcom,cdc-micbias-cfilt-mv");
ret = of_property_read_u32(dev->of_node, prop_name,
&micbias->cfilt1_mv);
if (ret) {
@@ -501,7 +514,7 @@
}
snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,cdc-micbias1-cfilt-sel");
+ "qcom,cdc-micbias-cfilt-sel");
ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
if (ret) {
dev_err(dev, "Looking up %s property in node %s failed",
@@ -559,23 +572,14 @@
if (ret)
goto err;
}
-
ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
if (ret)
goto err;
-
- pdata->reset_gpio = of_get_named_gpio(dev->of_node,
- "qcom,cdc-reset-gpio", 0);
- if (pdata->reset_gpio < 0) {
- dev_err(dev, "Looking up %s property in node %s failed %d\n",
- "qcom, cdc-reset-gpio", dev->of_node->full_name,
- pdata->reset_gpio);
- goto err;
- }
- dev_dbg(dev, "%s: reset gpio %d", __func__, pdata->reset_gpio);
return pdata;
err:
devm_kfree(dev, pdata);
+ dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
+ __func__, ret);
return NULL;
}
@@ -611,6 +615,9 @@
MSM8X10_WCD_A_CDC_CLK_OTHR_CTL, 0x01,
0x00);
snd_soc_update_bits(codec,
+ MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec,
MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
break;
}
@@ -846,7 +853,7 @@
SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
- SOC_SINGLE_TLV("LINEOUT1 Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
+ SOC_SINGLE_TLV("LINEOUT Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
0, 12, 1, line_gain),
SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
@@ -1102,9 +1109,6 @@
switch (decimator) {
case 1:
case 2:
- if (dec_mux == 1)
- adc_dmic_sel = 0x1;
- else
adc_dmic_sel = 0x0;
break;
default:
@@ -1148,68 +1152,6 @@
SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
};
-/* virtual port entries */
-static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
- ucontrol->value.integer.value[0] = widget->value;
- return 0;
-}
-
-static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return 0;
-}
-
-static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
- ucontrol->value.enumerated.item[0] = widget->value;
- return 0;
-}
-
-static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return 0;
-}
-
-
-static const char *const slim_rx_mux_text[] = {
- "ZERO", "AIF1_PB"
-};
-
-static const struct soc_enum slim_rx_mux_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
-
-static const struct snd_kcontrol_new slim_rx_mux[MSM8X10_WCD_RX_MAX] = {
- SOC_DAPM_ENUM_EXT("I2S RX1 Mux", slim_rx_mux_enum,
- slim_rx_mux_get, slim_rx_mux_put),
- SOC_DAPM_ENUM_EXT("I2S RX2 Mux", slim_rx_mux_enum,
- slim_rx_mux_get, slim_rx_mux_put),
- SOC_DAPM_ENUM_EXT("I2S RX3 Mux", slim_rx_mux_enum,
- slim_rx_mux_get, slim_rx_mux_put),
-};
-
-static const struct snd_kcontrol_new aif_cap_mixer[] = {
- SOC_SINGLE_EXT("I2S TX1", SND_SOC_NOPM, MSM8X10_WCD_TX1, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
- SOC_SINGLE_EXT("I2S TX2", SND_SOC_NOPM, MSM8X10_WCD_TX2, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
- SOC_SINGLE_EXT("I2S TX3", SND_SOC_NOPM, MSM8X10_WCD_TX3, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
- SOC_SINGLE_EXT("I2S TX4", SND_SOC_NOPM, MSM8X10_WCD_TX4, 1, 0,
- slim_tx_mixer_get, slim_tx_mixer_put),
-};
-
-
static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
{
@@ -1243,7 +1185,7 @@
if (w->reg == MSM8X10_WCD_A_TX_1_EN)
init_bit_shift = 7;
- else if (adc_reg == MSM8X10_WCD_A_TX_2_EN)
+ else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
init_bit_shift = 6;
else {
dev_err(codec->dev, "%s: Error, invalid adc register\n",
@@ -1365,54 +1307,36 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
u16 micb_int_reg;
- u8 cfilt_sel_val = 0;
char *internal1_text = "Internal1";
char *internal2_text = "Internal2";
char *internal3_text = "Internal3";
- enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
dev_dbg(codec->dev, "%s %d\n", __func__, event);
switch (w->reg) {
case MSM8X10_WCD_A_MICB_1_CTL:
micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
- cfilt_sel_val =
- msm8x10_wcd->resmgr.pdata->micbias.bias1_cfilt_sel;
- e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
- e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
- e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
break;
default:
dev_err(codec->dev,
- "%s: Error, invalid micbias register\n", __func__);
+ "%s: Error, invalid micbias register 0x%x\n",
+ __func__, w->reg);
return -EINVAL;
}
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- /* Let MBHC module know so micbias switch to be off */
- wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
-
- /* Get cfilt */
- wcd9xxx_resmgr_cfilt_get(&msm8x10_wcd->resmgr, cfilt_sel_val);
-
if (strnstr(w->name, internal1_text, 30))
- snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
+ snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
else if (strnstr(w->name, internal2_text, 30))
- snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
+ snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
else if (strnstr(w->name, internal3_text, 30))
- snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
+ snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20100);
- /* Let MBHC module know so micbias is on */
- wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
- /* Let MBHC module know so micbias switch to be off */
- wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
-
if (strnstr(w->name, internal1_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
else if (strnstr(w->name, internal2_text, 30))
@@ -1420,14 +1344,36 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
- /* Put cfilt */
- wcd9xxx_resmgr_cfilt_put(&msm8x10_wcd->resmgr, cfilt_sel_val);
break;
}
-
return 0;
}
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+ struct delayed_work *hpf_delayed_work;
+ struct hpf_work *hpf_work;
+ struct msm8x10_wcd_priv *msm8x10_wcd;
+ struct snd_soc_codec *codec;
+ u16 tx_mux_ctl_reg;
+ u8 hpf_cut_of_freq;
+
+ hpf_delayed_work = to_delayed_work(work);
+ hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+ msm8x10_wcd = hpf_work->msm8x10_wcd;
+ codec = hpf_work->msm8x10_wcd->codec;
+ hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+ tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
+ (hpf_work->decimator - 1) * 32;
+
+ dev_info(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
+ __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
+}
+
+
#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
#define CF_MIN_3DB_4HZ 0x0
#define CF_MIN_3DB_75HZ 0x1
@@ -1582,6 +1528,7 @@
{
struct snd_soc_codec *codec = w->codec;
struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+ msm8x10_wcd->resmgr.codec = codec;
dev_dbg(codec->dev, "%s %d\n", __func__, event);
@@ -1697,21 +1644,12 @@
{"I2S TX1", NULL, "TX_I2S_CLK"},
{"I2S TX2", NULL, "TX_I2S_CLK"},
- {"I2S TX3", NULL, "TX_I2S_CLK"},
- {"I2S TX4", NULL, "TX_I2S_CLK"},
- {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+ {"DEC1 MUX", NULL, "TX CLK"},
+ {"DEC2 MUX", NULL, "TX CLK"},
- {"AIF1_CAP Mixer", "I2S TX1", "I2S TX1 MUX"},
- {"AIF1_CAP Mixer", "I2S TX2", "I2S TX2 MUX"},
- {"AIF1_CAP Mixer", "I2S TX3", "I2S TX3 MUX"},
- {"AIF1_CAP Mixer", "I2S TX4", "I2S TX4 MUX"},
-
- {"I2S TX1 MUX", NULL, "DEC1 MUX"},
- {"I2S TX2 MUX", NULL, "DEC2 MUX"},
- {"I2S TX3 MUX", NULL, "RX1 MIX1"},
- {"I2S TX4 MUX", "RMIX2", "RX1 MIX2"},
- {"I2S TX4 MUX", "RMIX3", "RX1 MIX3"},
+ {"I2S TX1", NULL, "DEC1 MUX"},
+ {"I2S TX2", NULL, "DEC2 MUX"},
/* Earpiece (RX MIX1) */
{"EAR", NULL, "EAR PA"},
@@ -1725,33 +1663,32 @@
{"HPHL", NULL, "HPHL DAC"},
{"HPHR", NULL, "HPHR DAC"},
- {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
{"HPHL DAC", NULL, "CP"},
{"HPHR DAC", NULL, "CP"},
+ {"SPK DAC", NULL, "CP"},
{"DAC1", "Switch", "RX1 CHAIN"},
{"HPHL DAC", "Switch", "RX1 CHAIN"},
{"HPHR DAC", NULL, "RX2 CHAIN"},
- {"LINEOUT1", NULL, "LINEOUT1 PA"},
+ {"LINEOUT", NULL, "LINEOUT PA"},
{"SPK_OUT", NULL, "SPK PA"},
- {"LINEOUT1 PA", NULL, "CP"},
- {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
+ {"LINEOUT PA", NULL, "CP"},
+ {"LINEOUT PA", NULL, "LINEOUT DAC"},
- {"LINEOUT1 DAC", "RX2 INPUT", "RX2 MIX1"},
- {"LINEOUT1 DAC", "RX3 INPUT", "RX3 MIX1"},
-
+ {"CP", NULL, "RX_BIAS"},
{"SPK PA", NULL, "SPK DAC"},
- {"SPK DAC", NULL, "RX7 MIX2"},
+ {"SPK DAC", NULL, "RX3 CHAIN"},
+ {"RX1 CHAIN", NULL, "RX1 CLK"},
+ {"RX2 CHAIN", NULL, "RX2 CLK"},
+ {"RX3 CHAIN", NULL, "RX3 CLK"},
{"RX1 CHAIN", NULL, "RX1 MIX2"},
{"RX2 CHAIN", NULL, "RX2 MIX2"},
-
- {"LINEOUT1 DAC", NULL, "RX_BIAS"},
- {"SPK DAC", NULL, "RX_BIAS"},
+ {"RX3 CHAIN", NULL, "RX3 MIX1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
@@ -1761,19 +1698,7 @@
{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
{"RX1 MIX2", NULL, "RX1 MIX1"},
- {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
- {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
{"RX2 MIX2", NULL, "RX2 MIX1"},
- {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
- {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
-
- {"I2S RX1 MUX", "AIF1_PB", "AIF1 PB"},
- {"I2S RX2 MUX", "AIF1_PB", "AIF1 PB"},
- {"I2S RX3 MUX", "AIF1_PB", "AIF1 PB"},
-
- {"I2S RX1", NULL, "I2S RX1 MUX"},
- {"I2S RX2", NULL, "I2S RX2 MUX"},
- {"I2S RX3", NULL, "I2S RX3 MUX"},
{"RX1 MIX1 INP1", "RX1", "I2S RX1"},
{"RX1 MIX1 INP1", "RX2", "I2S RX2"},
@@ -1825,41 +1750,109 @@
{"IIR1", NULL, "IIR1 INP1 MUX"},
{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
-
- /* There is no LDO_H in Helicon */
- {"MIC BIAS1 Internal1", NULL, "LDO_H"},
- {"MIC BIAS1 Internal2", NULL, "LDO_H"},
- {"MIC BIAS1 External", NULL, "LDO_H"},
+ {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
+ {"MIC BIAS External", NULL, "INT_LDO_H"},
};
static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct msm8x10_wcd *msm8x10_wcd_core =
- dev_get_drvdata(dai->codec->dev);
dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
__func__,
substream->name, substream->stream);
- if ((msm8x10_wcd_core != NULL) &&
- (msm8x10_wcd_core->dev != NULL))
- pm_runtime_get_sync(msm8x10_wcd_core->dev);
-
return 0;
}
static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct msm8x10_wcd *msm8x10_wcd_core =
- dev_get_drvdata(dai->codec->dev);
dev_dbg(dai->codec->dev,
"%s(): substream = %s stream = %d\n" , __func__,
substream->name, substream->stream);
- if ((msm8x10_wcd_core != NULL) &&
- (msm8x10_wcd_core->dev != NULL)) {
- pm_runtime_mark_last_busy(msm8x10_wcd_core->dev);
- pm_runtime_put(msm8x10_wcd_core->dev);
+}
+
+static int msm8x10_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
+ int enable)
+{
+ if (enable) {
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
+ 0x03, 0x03);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+ 0x0f, 0x0d);
+ } else {
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+ 0x0f, 0x00);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ 0x03, 0x00);
}
+ return 0;
+}
+
+static void msm8x10_wcd_codec_enable_audio_mode_bandgap(struct snd_soc_codec
+ *codec)
+{
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x80);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x04,
+ 0x04);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x01,
+ 0x01);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x00);
+}
+
+static void msm8x10_wcd_codec_enable_bandgap(struct snd_soc_codec *codec,
+ enum msm8x10_wcd_bandgap_type choice)
+{
+ struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
+
+ /* TODO lock resources accessed by audio streams and threaded
+ * interrupt handlers
+ */
+
+ dev_dbg(codec->dev, "%s, choice is %d, current is %d\n",
+ __func__, choice,
+ msm8x10_wcd->bandgap_type);
+
+ if (msm8x10_wcd->bandgap_type == choice)
+ return;
+
+ if ((msm8x10_wcd->bandgap_type == MSM8X10_WCD_BANDGAP_OFF) &&
+ (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
+ msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
+ } else if (choice == MSM8X10_WCD_BANDGAP_MBHC_MODE) {
+ /* bandgap mode becomes fast,
+ * mclk should be off or clk buff source souldn't be VBG
+ * Let's turn off mclk always */
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x2, 0x2);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x80, 0x80);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x4, 0x4);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x01, 0x01);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
+ 0x80, 0x00);
+ } else if ((msm8x10_wcd->bandgap_type ==
+ MSM8X10_WCD_BANDGAP_MBHC_MODE) &&
+ (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
+ snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
+ usleep_range(100, 100);
+ msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
+ } else if (choice == MSM8X10_WCD_BANDGAP_OFF) {
+ snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
+ } else {
+ dev_err(codec->dev,
+ "%s: Error, Invalid bandgap settings\n", __func__);
+ }
+ msm8x10_wcd->bandgap_type = choice;
}
int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
@@ -1867,24 +1860,30 @@
{
struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
- dev_dbg(codec->dev,
- "%s: mclk_enable = %u, dapm = %d\n", __func__,
- mclk_enable, dapm);
- WCD9XXX_BCL_LOCK(&msm8x10_wcd->resmgr);
+ dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
+ __func__, mclk_enable, dapm);
+ if (dapm)
+ MSM8X10_WCD_ACQUIRE_LOCK(msm8x10_wcd->codec_resource_lock);
if (mclk_enable) {
- wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
- WCD9XXX_BANDGAP_AUDIO_MODE);
- wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
- WCD9XXX_CLK_MCLK);
+ msm8x10_wcd->mclk_enabled = true;
+ msm8x10_wcd_codec_enable_bandgap(codec,
+ MSM8X10_WCD_BANDGAP_AUDIO_MODE);
+ msm8x10_wcd_codec_enable_clock_block(codec, 1);
} else {
- /* Put clock and BG */
- wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
- WCD9XXX_CLK_MCLK);
- wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
- WCD9XXX_BANDGAP_AUDIO_MODE);
+ if (!msm8x10_wcd->mclk_enabled) {
+ if (dapm)
+ MSM8X10_WCD_RELEASE_LOCK(
+ msm8x10_wcd->codec_resource_lock);
+ dev_err(codec->dev, "Error, MCLK already diabled\n");
+ return -EINVAL;
+ }
+ msm8x10_wcd->mclk_enabled = false;
+ msm8x10_wcd_codec_enable_clock_block(codec, 0);
+ msm8x10_wcd_codec_enable_bandgap(codec,
+ MSM8X10_WCD_BANDGAP_OFF);
}
- WCD9XXX_BCL_UNLOCK(&msm8x10_wcd->resmgr);
-
+ if (dapm)
+ MSM8X10_WCD_RELEASE_LOCK(msm8x10_wcd->codec_resource_lock);
return 0;
}
@@ -2027,7 +2026,7 @@
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 3,
},
.ops = &msm8x10_wcd_dai_ops,
},
@@ -2077,23 +2076,16 @@
SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
ARRAY_SIZE(dac1_switch)),
- SND_SOC_DAPM_AIF_IN("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
- AIF1_PB, 0),
+ SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_MUX("I2S RX1 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX1, 0,
- &slim_rx_mux[MSM8X10_WCD_RX1]),
- SND_SOC_DAPM_MUX("I2S RX2 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX2, 0,
- &slim_rx_mux[MSM8X10_WCD_RX2]),
- SND_SOC_DAPM_MUX("I2S RX3 MUX", SND_SOC_NOPM, MSM8X10_WCD_RX3, 0,
- &slim_rx_mux[MSM8X10_WCD_RX3]),
+ SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_MIXER("I2S RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("I2S RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
- /* Headphone */
+ SND_SOC_DAPM_SUPPLY("TX CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
+
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
5, 0, NULL, 0,
@@ -2114,10 +2106,10 @@
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* Speaker */
- SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT"),
SND_SOC_DAPM_OUTPUT("SPK_OUT"),
- SND_SOC_DAPM_PGA_E("LINEOUT1 PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
+ SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -2127,7 +2119,7 @@
SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL,
+ SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
msm8x10_wcd_lineout_dac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -2152,10 +2144,18 @@
0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
+ 2, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
5, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
+ 5, 0, NULL, 0),
SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
&rx_mix1_inp1_mux),
@@ -2191,26 +2191,28 @@
SND_SOC_DAPM_INPUT("AMIC1"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External",
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1",
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2",
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
- SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
+ 7, 0),
+
SND_SOC_DAPM_INPUT("AMIC3"),
SND_SOC_DAPM_MUX_E("DEC1 MUX",
@@ -2226,11 +2228,13 @@
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_INPUT("AMIC2"),
- SND_SOC_DAPM_AIF_OUT("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
- AIF1_CAP, 0),
- SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
- aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
+ SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
+ 0, 0),
+ SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
+ 0, 0),
/* Digital Mic Inputs */
SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
@@ -2254,7 +2258,7 @@
static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
/* set MCLk to 9.6 */
- MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x0A),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x00),
/* EAR PA deafults */
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
@@ -2280,7 +2284,12 @@
/* Disable TX7 internal biasing path which can cause leakage */
- MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
};
static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
@@ -2338,12 +2347,36 @@
static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
{
+ struct msm8x10_wcd_priv *msm8x10_wcd;
+ int i;
dev_dbg(codec->dev, "%s()\n", __func__);
+ msm8x10_wcd = kzalloc(sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
+ if (!msm8x10_wcd) {
+ dev_err(codec->dev, "Failed to allocate private data\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0 ; i < NUM_DECIMATORS; i++) {
+ tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd;
+ tx_hpf_work[i].decimator = i + 1;
+ INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+ tx_hpf_corner_freq_callback);
+ }
+
codec->control_data = dev_get_drvdata(codec->dev);
+ snd_soc_codec_set_drvdata(codec, msm8x10_wcd);
+ msm8x10_wcd->codec = codec;
msm8x10_wcd_codec_init_reg(codec);
msm8x10_wcd_update_reg_defaults(codec);
+ msm8x10_wcd->mclk_enabled = false;
+ msm8x10_wcd->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
+ msm8x10_wcd->clock_active = false;
+ msm8x10_wcd->config_mode_active = false;
+ msm8x10_wcd->mbhc_polling_active = false;
+ mutex_init(&msm8x10_wcd->codec_resource_lock);
+ msm8x10_wcd->codec = codec;
return 0;
}
@@ -2353,18 +2386,6 @@
return 0;
}
-static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
-{
-
- mutex_init(&msm8x10->io_lock);
- mutex_init(&msm8x10->xfer_lock);
- mutex_init(&msm8x10->pm_lock);
- msm8x10->wlock_holders = 0;
-
- return 0;
-}
-
-
static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
.probe = msm8x10_wcd_codec_probe,
.remove = msm8x10_wcd_codec_remove,
@@ -2387,6 +2408,124 @@
.num_dapm_routes = ARRAY_SIZE(audio_map),
};
+static int msm8x10_wcd_enable_supplies(struct msm8x10_wcd *msm8x10,
+ struct msm8x10_wcd_pdata *pdata)
+{
+ int ret;
+ int i;
+ msm8x10->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
+ ARRAY_SIZE(pdata->regulator),
+ GFP_KERNEL);
+ if (!msm8x10->supplies) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ msm8x10->num_of_supplies = 0;
+
+ if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
+ dev_err(msm8x10->dev, "%s: Array Size out of bound\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ if (pdata->regulator[i].name) {
+ msm8x10->supplies[i].supply = pdata->regulator[i].name;
+ msm8x10->num_of_supplies++;
+ }
+ }
+
+ ret = regulator_bulk_get(msm8x10->dev, msm8x10->num_of_supplies,
+ msm8x10->supplies);
+ if (ret != 0) {
+ dev_err(msm8x10->dev, "Failed to get supplies: err = %d\n",
+ ret);
+ goto err_supplies;
+ }
+
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
+ pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
+ if (ret) {
+ dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
+ __func__, msm8x10->supplies[i].supply, ret);
+ goto err_get;
+ }
+
+ ret = regulator_set_optimum_mode(msm8x10->supplies[i].consumer,
+ pdata->regulator[i].optimum_uA);
+ if (ret < 0) {
+ dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
+ __func__, msm8x10->supplies[i].supply, ret);
+ goto err_get;
+ }
+ }
+
+ ret = regulator_bulk_enable(msm8x10->num_of_supplies,
+ msm8x10->supplies);
+ if (ret != 0) {
+ dev_err(msm8x10->dev, "Failed to enable supplies: err = %d\n",
+ ret);
+ goto err_configure;
+ }
+ return ret;
+
+err_configure:
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
+ pdata->regulator[i].max_uV);
+ regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
+ }
+err_get:
+ regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
+err_supplies:
+ kfree(msm8x10->supplies);
+err:
+ return ret;
+}
+
+static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
+ struct msm8x10_wcd_pdata *pdata)
+{
+ int i;
+
+ regulator_bulk_disable(msm8x10->num_of_supplies,
+ msm8x10->supplies);
+ for (i = 0; i < msm8x10->num_of_supplies; i++) {
+ regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
+ pdata->regulator[i].max_uV);
+ regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
+ }
+ regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
+ kfree(msm8x10->supplies);
+}
+
+static int msm8x10_wcd_bringup(struct msm8x10_wcd *msm8x10)
+{
+ msm8x10->read_dev = msm8x10_wcd_reg_read;
+ msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x02);
+ msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CHIP_CTL, 0x00);
+ usleep_range(5000, 5000);
+ msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x03);
+ return 0;
+}
+
+static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
+{
+ mutex_init(&msm8x10->io_lock);
+ mutex_init(&msm8x10->xfer_lock);
+ mutex_init(&msm8x10->pm_lock);
+ msm8x10->wlock_holders = 0;
+
+ iowrite32(0x03C00000, ioremap(0xFD512050, 4));
+ usleep_range(5000, 5000);
+
+ msm8x10_wcd_bringup(msm8x10);
+ return 0;
+}
+
static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -2401,7 +2540,7 @@
if (device_id > 0) {
msm8x10_wcd_modules[device_id++].client = client;
- return ret;
+ goto rtn;
}
dev = &client->dev;
@@ -2421,19 +2560,25 @@
dev_err(&client->dev,
"%s: error, allocation failed\n", __func__);
ret = -ENOMEM;
- goto fail;
+ goto rtn;
}
msm8x10->dev = &client->dev;
msm8x10_wcd_modules[device_id++].client = client;
msm8x10->read_dev = msm8x10_wcd_reg_read;
msm8x10->write_dev = msm8x10_wcd_reg_write;
+ ret = msm8x10_wcd_enable_supplies(msm8x10, pdata);
+ if (ret) {
+ dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
+ __func__);
+ goto err_codec;
+ }
ret = msm8x10_wcd_device_init(msm8x10);
if (ret) {
dev_err(&client->dev,
"%s:msm8x10_wcd_device_init failed with error %d\n",
__func__, ret);
- goto fail;
+ goto err_supplies;
}
dev_set_drvdata(&client->dev, msm8x10);
ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
@@ -2443,7 +2588,14 @@
dev_err(&client->dev,
"%s:snd_soc_register_codec failed with error %d\n",
__func__, ret);
-fail:
+ else
+ goto rtn;
+
+err_supplies:
+ msm8x10_wcd_disable_supplies(msm8x10, pdata);
+err_codec:
+ kfree(msm8x10);
+rtn:
return ret;
}
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 44e8a6d..d250e0a 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -199,7 +199,7 @@
int (*read_dev)(struct msm8x10_wcd *msm8x10,
unsigned short reg, unsigned int *val);
int (*write_dev)(struct msm8x10_wcd *msm8x10,
- unsigned short reg, unsigned int val);
+ unsigned short reg, u8 val);
u32 num_of_supplies;
struct regulator_bulk_data *supplies;
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 67674f3..b71dd65 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -461,8 +461,8 @@
kcontrol->private_value)->shift;
ucontrol->value.integer.value[0] =
- snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
- (1 << band_idx);
+ (snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+ (1 << band_idx)) != 0;
dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
iir_idx, band_idx,
@@ -485,23 +485,54 @@
snd_soc_update_bits(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx),
(1 << band_idx), (value << band_idx));
- dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
- iir_idx, band_idx, value);
+ pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx,
+ ((snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+ (1 << band_idx)) != 0));
return 0;
}
static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
int iir_idx, int band_idx,
int coeff_idx)
{
+ uint32_t value = 0;
+
/* Address does not automatically update if reading */
snd_soc_write(codec,
(TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
- (band_idx * BAND_MAX + coeff_idx) & 0x1F);
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t)) & 0x7F);
+
+ value |= snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx));
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 1) & 0x7F);
+
+ value |= (snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 8);
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 2) & 0x7F);
+
+ value |= (snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 16);
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ ((band_idx * BAND_MAX + coeff_idx)
+ * sizeof(uint32_t) + 3) & 0x7F);
/* Mask bits top 2 bits since they are reserved */
- return ((snd_soc_read(codec,
- (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24)) &
- 0x3FFFFFFF;
+ value |= ((snd_soc_read(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) & 0x3F) << 24);
+
+ return value;
+
}
static int tapan_get_iir_band_audio_mixer(
@@ -545,13 +576,19 @@
static void set_iir_band_coeff(struct snd_soc_codec *codec,
int iir_idx, int band_idx,
- int coeff_idx, uint32_t value)
+ uint32_t value)
{
- /* Mask top 3 bits, 6-8 are reserved */
- /* Update address manually each time */
snd_soc_write(codec,
- (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
- (band_idx * BAND_MAX + coeff_idx) & 0x1F);
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ (value & 0xFF));
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ (value >> 8) & 0xFF);
+
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ (value >> 16) & 0xFF);
/* Mask top 2 bits, 7-8 are reserved */
snd_soc_write(codec,
@@ -570,15 +607,21 @@
int band_idx = ((struct soc_multi_mixer_control *)
kcontrol->private_value)->shift;
- set_iir_band_coeff(codec, iir_idx, band_idx, 0,
+ /* Mask top bit it is reserved */
+ /* Updates addr automatically for each B2 write */
+ snd_soc_write(codec,
+ (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[0]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 1,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[1]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 2,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[2]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 3,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[3]);
- set_iir_band_coeff(codec, iir_idx, band_idx, 4,
+ set_iir_band_coeff(codec, iir_idx, band_idx,
ucontrol->value.integer.value[4]);
dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index f9578af..5d4f9e6 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -217,47 +217,47 @@
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_B1_CTL),
- SPKR_CLIP_PIPE_BANK_SEL, 0x1, 8, 0
+ SPKR_CLIP_PIPE_BANK_SEL, 0x3, 8, 0
},
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL0),
- SPKR_CLIPDET_VAL0, 0x1, 8, 0
+ SPKR_CLIPDET_VAL0, 0xff, 8, 0
},
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL1),
- SPKR_CLIPDET_VAL1, 0x1, 8, 0
+ SPKR_CLIPDET_VAL1, 0xff, 8, 0
},
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL2),
- SPKR_CLIPDET_VAL2, 0x1, 8, 0
+ SPKR_CLIPDET_VAL2, 0xff, 8, 0
},
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL3),
- SPKR_CLIPDET_VAL3, 0x1, 8, 0
+ SPKR_CLIPDET_VAL3, 0xff, 8, 0
},
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL4),
- SPKR_CLIPDET_VAL4, 0x1, 8, 0
+ SPKR_CLIPDET_VAL4, 0xff, 8, 0
},
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL5),
- SPKR_CLIPDET_VAL5, 0x1, 8, 0
+ SPKR_CLIPDET_VAL5, 0xff, 8, 0
},
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL6),
- SPKR_CLIPDET_VAL6, 0x1, 8, 0
+ SPKR_CLIPDET_VAL6, 0xff, 8, 0
},
{
1,
(TAIKO_REGISTER_START_OFFSET + TAIKO_A_CDC_SPKR_CLIPDET_VAL7),
- SPKR_CLIPDET_VAL7, 0x1, 8, 0
+ SPKR_CLIPDET_VAL7, 0xff, 8, 0
},
};
@@ -488,6 +488,8 @@
bool spkr_pa_widget_on;
struct regulator *spkdrv_reg;
+ bool mbhc_started;
+
struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
/* resmgr module */
@@ -2648,7 +2650,9 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
- if (micb_ctl_reg == TAIKO_A_MICB_2_CTL)
+ if (taiko->mbhc_started &&
+ taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
+ micb_ctl_reg == TAIKO_A_MICB_2_CTL)
wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
WCD9XXX_COND_HPH_MIC,
micb_ctl_reg, w->shift,
@@ -2663,7 +2667,9 @@
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
- if (micb_ctl_reg == TAIKO_A_MICB_2_CTL)
+ if (taiko->mbhc_started &&
+ taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
+ micb_ctl_reg == TAIKO_A_MICB_2_CTL)
wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
WCD9XXX_COND_HPH_MIC,
micb_ctl_reg, 7, false);
@@ -4708,9 +4714,6 @@
dai = &taiko_p->dai[w->shift];
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- /*Enable Clip Detection*/
- snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
- 0x8, 0x8);
/*Enable V&I sensing*/
snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
0x88, 0x88);
@@ -4723,6 +4726,7 @@
/*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,
&dai->grph);
@@ -4745,9 +4749,6 @@
/*Disable V&I sensing*/
snd_soc_update_bits(codec, TAIKO_A_SPKR_PROT_EN,
0x88, 0x00);
- /*Disable clip detection*/
- snd_soc_update_bits(codec, TAIKO_A_SPKR_DRV_CLIP_DET,
- 0x8, 0x0);
break;
}
out_vi:
@@ -5965,8 +5966,12 @@
int taiko_hs_detect(struct snd_soc_codec *codec,
struct wcd9xxx_mbhc_config *mbhc_cfg)
{
+ int rc;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
- return wcd9xxx_mbhc_start(&taiko->mbhc, mbhc_cfg);
+ rc = wcd9xxx_mbhc_start(&taiko->mbhc, mbhc_cfg);
+ if (!rc)
+ taiko->mbhc_started = true;
+ return rc;
}
EXPORT_SYMBOL_GPL(taiko_hs_detect);
@@ -6022,13 +6027,20 @@
taiko_init_slim_slave_cfg(codec);
taiko_slim_interface_init_reg(codec);
- wcd9xxx_mbhc_deinit(&taiko->mbhc);
- ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
- WCD9XXX_MBHC_VERSION_TAIKO);
- if (ret)
- pr_err("%s: mbhc init failed %d\n", __func__, ret);
- else
- wcd9xxx_mbhc_start(&taiko->mbhc, taiko->mbhc.mbhc_cfg);
+ if (taiko->mbhc_started) {
+ wcd9xxx_mbhc_deinit(&taiko->mbhc);
+ taiko->mbhc_started = false;
+ ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
+ WCD9XXX_MBHC_VERSION_TAIKO);
+ if (ret) {
+ pr_err("%s: mbhc init failed %d\n", __func__, ret);
+ } else {
+ ret = wcd9xxx_mbhc_start(&taiko->mbhc,
+ taiko->mbhc.mbhc_cfg);
+ if (!ret)
+ taiko->mbhc_started = true;
+ }
+ }
mutex_unlock(&codec->mutex);
return ret;
}
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index daba6d5..a37b4eb 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -2786,6 +2786,7 @@
wcd9xxx_turn_onoff_rel_detection(codec, true);
pr_debug("%s: leave\n", __func__);
+ return;
gen_err:
pr_err("%s: Error returned, ret: %d\n", __func__, ret);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index a458713..51334f2 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1424,7 +1424,26 @@
__func__, err);
goto out;
}
-
+ config_data = taiko_get_afe_config(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, err);
+ return err;
+ }
+ }
+ config_data = taiko_get_afe_config(codec, AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, err);
+ return err;
+ }
+ }
/* start mbhc */
mbhc_cfg.calibration = def_taiko_mbhc_cal();
if (mbhc_cfg.calibration) {
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 464e8af..4db3ea5 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/qpnp/clkdiv.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -26,7 +27,9 @@
#include <asm/mach-types.h>
#include <mach/socinfo.h>
#include <qdsp6v2/msm-pcm-routing-v2.h>
+#include <sound/q6afe-v2.h>
#include <linux/module.h>
+#include "../codecs/msm8x10-wcd.h"
#define DRV_NAME "msm8x10-asoc-wcd"
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
@@ -36,6 +39,185 @@
static int msm_proxy_rx_ch = 2;
+#define MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL 0xFE03B004
+#define MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR 0xFE02C000
+#define MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR 0xFE02C004
+#define MSM8X10_DINO_LPASS_DIGCODEC_M 0xFE02C008
+#define MSM8X10_DINO_LPASS_DIGCODEC_N 0xFE02C00C
+#define MSM8X10_DINO_LPASS_DIGCODEC_D 0xFE02C010
+#define MSM8X10_DINO_LPASS_DIGCODEC_CBCR 0xFE02C014
+#define MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR 0xFE02C018
+
+/*
+ * There is limitation for the clock root selection from
+ * either MI2S or DIG_CODEC.
+ * If DIG_CODEC root can only provide 9.6MHz clock
+ * to codec while MI2S only can provide
+ * 12.288MHz.
+ */
+enum {
+ DIG_CDC_CLK_SEL_DIG_CODEC,
+ DIG_CDC_CLK_SEL_PRI_MI2S,
+ DIG_CDC_CLK_SEL_SEC_MI2S,
+};
+
+static struct afe_clk_cfg mi2s_rx_clk = {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
+ Q6AFE_LPASS_CLK_SRC_INTERNAL,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ Q6AFE_LPASS_MODE_BOTH_VALID,
+ 0,
+};
+
+static struct afe_clk_cfg mi2s_tx_clk = {
+ AFE_API_VERSION_I2S_CONFIG,
+ Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
+ Q6AFE_LPASS_OSR_CLK_12_P288_MHZ,
+ Q6AFE_LPASS_CLK_SRC_INTERNAL,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ Q6AFE_LPASS_MODE_BOTH_VALID,
+ 0,
+};
+
+static struct afe_digital_clk_cfg digital_cdc_clk = {
+ AFE_API_VERSION_I2S_CONFIG,
+ 9600000,
+ 5, /* Digital Codec root */
+ 0,
+};
+
+static atomic_t aud_init_rsc_ref;
+
+static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
+
+static const struct snd_soc_dapm_route msm8x10_common_audio_map[] = {
+ {"RX_BIAS", NULL, "MCLK"},
+ {"INT_LDO_H", NULL, "MCLK"},
+ {"MIC BIAS External", NULL, "Handset Mic"},
+ {"MIC BIAS Internal2", NULL, "Headset Mic"},
+ {"AMIC1", NULL, "MIC BIAS External"},
+ {"AMIC2", NULL, "MIC BIAS Internal2"},
+
+};
+
+static const struct snd_soc_dapm_widget msm8x10_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ msm8x10_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+};
+
+/*
+ * This function will be replaced by
+ * afe_set_lpass_internal_digital_codec_clock(port_id, cfg)
+ * in the future after LPASS API fix
+ */
+static int msm_enable_lpass_mclk(void)
+{
+ /* Select the codec root */
+ iowrite32(DIG_CDC_CLK_SEL_DIG_CODEC,
+ ioremap(MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL,
+ 4));
+ /* Div-2 */
+ iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
+ /* Digital codec clock enable */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ /* AHB clock enable */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR, 4));
+ /* Set the update bit to make the settings go through */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
+
+ return 0;
+}
+
+static int msm_enable_mclk_root(u16 port_id, struct afe_digital_clk_cfg *cfg)
+{
+ int ret = 0;
+ /*
+ * msm_enable_lpass_mclk() function call will be replaced by
+ * ret = afe_set_lpass_internal_digital_codec_clock(port_id, cfg)
+ * in the future. Currentlt there is a bug in LPASS plan which
+ * doesn't consider the digital codec clock. It will be fixed soon
+ * in new Q6 image
+ */
+ msm_enable_lpass_mclk();
+ pr_debug("%s(): return = %d\n", __func__, ret);
+ return ret;
+}
+
+static int msm_config_mclk(u16 port_id, struct afe_digital_clk_cfg *cfg)
+{
+ /* Select the codec root */
+ iowrite32(DIG_CDC_CLK_SEL_DIG_CODEC,
+ ioremap(MSM8X10_DINO_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL,
+ 4));
+ /* Div-2 */
+ iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
+ /* Digital codec clock enable */
+ if (cfg->clk_val == 0) {
+ iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ pr_debug("%s(line %d)\n", __func__, __LINE__);
+ } else {
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ pr_debug("%s(line %d)\n", __func__, __LINE__);
+ }
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
+ /* AHB clock enable */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_AHB_CBCR, 4));
+ /* Set the update bit to make the settings go through */
+ iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
+
+ return 0;
+
+}
+
+static int msm_config_mi2s_clk(int enable)
+{
+ int ret = 0;
+ pr_debug("%s(line %d):enable = %x\n", __func__, __LINE__, enable);
+ if (enable) {
+ digital_cdc_clk.clk_val = 9600000;
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ } else {
+ digital_cdc_clk.clk_val = 0;
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ }
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX, &digital_cdc_clk);
+ return ret;
+}
+
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -63,13 +245,7 @@
return 0;
}
-static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
-{
- pr_debug("%s(), dev_name%s\n", __func__, dev_name(rtd->cpu_dai->dev));
- return 0;
-}
-
-static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+static int msm_mi2s_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -77,20 +253,142 @@
return 0;
}
-static int msm_snd_startup(struct snd_pcm_substream *substream)
+static int mi2s_clk_ctl(struct snd_pcm_substream *substream, bool enable)
{
+ int ret = 0;
+ if (enable) {
+ digital_cdc_clk.clk_val = 9600000;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_12_P288_MHZ;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ } else
+ pr_err("%s:Not valid substream.\n", __func__);
+
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ } else {
+ digital_cdc_clk.clk_val = 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mi2s_rx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_rx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &mi2s_rx_clk);
+ } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ mi2s_tx_clk.clk_val2 = Q6AFE_LPASS_OSR_CLK_DISABLE;
+ mi2s_tx_clk.clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE;
+ ret = afe_set_lpass_clock(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &mi2s_tx_clk);
+ } else
+ pr_err("%s:Not valid substream.\n", __func__);
+
+ if (ret < 0)
+ pr_err("%s:afe_set_lpass_clock failed\n", __func__);
+
+ }
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX, &digital_cdc_clk);
+ return ret;
+}
+
+static int msm8x10_enable_codec_ext_clk(struct snd_soc_codec *codec,
+ int enable, bool dapm)
+{
+ int ret = 0;
+
+ pr_debug("%s: enable = %d codec name %s enable %x\n",
+ __func__, enable, codec->name, enable);
+ if (enable) {
+ digital_cdc_clk.clk_val = 9600000;
+ msm_config_mi2s_clk(1);
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &digital_cdc_clk);
+ msm8x10_wcd_mclk_enable(codec, 1, dapm);
+ } else {
+ msm8x10_wcd_mclk_enable(codec, 0, dapm);
+ ret = msm_config_mclk(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &digital_cdc_clk);
+ msm_config_mi2s_clk(0);
+ }
+ return ret;
+}
+
+static int msm8x10_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s: event = %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm8x10_enable_codec_ext_clk(w->codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm8x10_enable_codec_ext_clk(w->codec, 0, true);
+ default:
+ return -EINVAL;
+ }
+}
+
+static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret;
+
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
- return 0;
+ ret = mi2s_clk_ctl(substream, false);
+ if (ret < 0)
+ pr_err("%s:clock disable failed\n", __func__);
}
-
-static void msm_snd_shutdown(struct snd_pcm_substream *substream)
+static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
+
+ ret = mi2s_clk_ctl(substream, true);
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ pr_err("set fmt cpu dai failed\n");
+
+ return ret;
}
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+
+ pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ pr_debug("%s(): aud_init_rsc_ref counter = %d\n",
+ __func__, atomic_read(&aud_init_rsc_ref));
+ if (atomic_inc_return(&aud_init_rsc_ref) != 1)
+ goto exit;
+
+ snd_soc_dapm_new_controls(dapm, msm8x10_dapm_widgets,
+ ARRAY_SIZE(msm8x10_dapm_widgets));
+
+ snd_soc_dapm_add_routes(dapm, msm8x10_common_audio_map,
+ ARRAY_SIZE(msm8x10_common_audio_map));
+
+ snd_soc_dapm_sync(dapm);
+ ret = msm_enable_mclk_root(AFE_PORT_ID_SECONDARY_MI2S_RX,
+ &digital_cdc_clk);
+exit:
+ return ret;
+}
static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
@@ -119,10 +417,10 @@
rate->min = rate->max = 48000;
return 0;
}
-static struct snd_soc_ops msm8x10_be_ops = {
- .startup = msm_snd_startup,
- .hw_params = msm_snd_hw_params,
- .shutdown = msm_snd_shutdown,
+static struct snd_soc_ops msm8x10_mi2s_be_ops = {
+ .startup = msm_mi2s_snd_startup,
+ .hw_params = msm_mi2s_snd_hw_params,
+ .shutdown = msm_mi2s_snd_shutdown,
};
/* Digital audio interface glue - connects codec <---> CPU */
@@ -327,7 +625,7 @@
.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
.init = &msm_audrx_init,
.be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm8x10_be_ops,
+ .ops = &msm8x10_mi2s_be_ops,
.ignore_suspend = 1,
},
{
@@ -341,7 +639,7 @@
.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
.init = &msm_audrx_init,
.be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm8x10_be_ops,
+ .ops = &msm8x10_mi2s_be_ops,
.ignore_suspend = 1,
},
{
@@ -492,6 +790,8 @@
goto err;
}
+ atomic_set(&aud_init_rsc_ref, 0);
+
return 0;
err:
return ret;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 7d9cc16..04a0a84 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1358,16 +1358,25 @@
SOC_ENUM_EXT("PRI MI2S RX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
- SOC_ENUM_EXT("SEC RX Format", mi2s_config_enum[0],
+ SOC_ENUM_EXT("SEC MI2S RX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("TERT MI2S RX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("QUAT MI2S RX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
SOC_ENUM_EXT("PRI MI2S TX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
- SOC_ENUM_EXT("SEC MI2S RX Format", mi2s_config_enum[0],
+ SOC_ENUM_EXT("SEC MI2S TX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
- SOC_ENUM_EXT("SEC MI2S TX Format", mi2s_config_enum[0],
+ SOC_ENUM_EXT("TERT MI2S TX Format", mi2s_config_enum[0],
+ msm_dai_q6_mi2s_format_get,
+ msm_dai_q6_mi2s_format_put),
+ SOC_ENUM_EXT("QUAT MI2S TX Format", mi2s_config_enum[0],
msm_dai_q6_mi2s_format_get,
msm_dai_q6_mi2s_format_put),
};
@@ -1384,6 +1393,10 @@
if (!strncmp(dai->name, "msm-dai-q6-mi2s.0", 17))
ctrl = &mi2s_config_controls[0];
if (!strncmp(dai->name, "msm-dai-q6-mi2s.1", 17))
+ ctrl = &mi2s_config_controls[1];
+ if (!strncmp(dai->name, "msm-dai-q6-mi2s.2", 17))
+ ctrl = &mi2s_config_controls[2];
+ if (!strncmp(dai->name, "msm-dai-q6-mi2s.3", 17))
ctrl = &mi2s_config_controls[3];
}
@@ -1402,9 +1415,13 @@
ctrl = NULL;
if (mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.i2s.channel_mode) {
if (!strncmp(dai->name, "msm-dai-q6-mi2s.0", 17))
- ctrl = &mi2s_config_controls[2];
- if (!strncmp(dai->name, "msm-dai-q6-mi2s.1", 17))
ctrl = &mi2s_config_controls[4];
+ if (!strncmp(dai->name, "msm-dai-q6-mi2s.1", 17))
+ ctrl = &mi2s_config_controls[5];
+ if (!strncmp(dai->name, "msm-dai-q6-mi2s.2", 17))
+ ctrl = &mi2s_config_controls[6];
+ if (!strncmp(dai->name, "msm-dai-q6-mi2s.3", 17))
+ ctrl = &mi2s_config_controls[7];
}
if (ctrl) {
@@ -1482,7 +1499,7 @@
case SNDRV_PCM_STREAM_PLAYBACK:
switch (mi2s_id) {
case MSM_PRIM_MI2S:
- *port_id = MI2S_RX;
+ *port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
break;
case MSM_SEC_MI2S:
*port_id = AFE_PORT_ID_SECONDARY_MI2S_RX;
@@ -1502,7 +1519,7 @@
case SNDRV_PCM_STREAM_CAPTURE:
switch (mi2s_id) {
case MSM_PRIM_MI2S:
- *port_id = MI2S_TX;
+ *port_id = AFE_PORT_ID_PRIMARY_MI2S_TX;
break;
case MSM_SEC_MI2S:
*port_id = AFE_PORT_ID_SECONDARY_MI2S_TX;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 85dc219..643f280 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -44,7 +44,7 @@
unsigned int sample_rate;
unsigned int channel;
unsigned int format;
- bool perf_mode;
+ unsigned long perf_mode;
};
#define INVALID_SESSION -1
@@ -270,7 +270,7 @@
}
static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
- int path_type)
+ int path_type, bool perf_mode)
{
int i, port_type;
struct route_payload payload;
@@ -290,7 +290,7 @@
if (payload.num_copps)
adm_matrix_map(dspst_id, path_type,
- payload.num_copps, payload.copp_ids, 0);
+ payload.num_copps, payload.copp_ids, 0, perf_mode);
}
void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
@@ -365,8 +365,8 @@
msm_send_eq_values(fedai_id);
topology = get_topology(path_type);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
- msm_bedais[i].perf_mode = perf_mode;
+ if (test_bit(fedai_id, &msm_bedais[i].fe_sessions) && perf_mode)
+ set_bit(fedai_id, &msm_bedais[i].perf_mode);
if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
@@ -385,7 +385,8 @@
path_type,
msm_bedais[i].sample_rate,
msm_bedais[i].channel,
- topology, msm_bedais[i].perf_mode,
+ topology,
+ test_bit(fedai_id, &msm_bedais[i].perf_mode),
bits_per_sample);
else
adm_open(msm_bedais[i].port_id,
@@ -408,7 +409,7 @@
}
if (payload.num_copps)
adm_matrix_map(dspst_id, path_type,
- payload.num_copps, payload.copp_ids, 0);
+ payload.num_copps, payload.copp_ids, 0, perf_mode);
mutex_unlock(&routing_lock);
}
@@ -440,7 +441,8 @@
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
- adm_close(msm_bedais[i].port_id);
+ adm_close(msm_bedais[i].port_id,
+ test_bit(fedai_id, &msm_bedais[i].perf_mode));
if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
dolby_dap_deinit(msm_bedais[i].port_id);
}
@@ -473,6 +475,7 @@
int session_type, path_type, port_id, topology;
u32 channels;
uint16_t bits_per_sample = 16;
+ bool perf_mode = false;
pr_debug("%s: reg %x val %x set %x\n", __func__, reg, val, set);
@@ -507,12 +510,14 @@
if ((session_type == SESSION_TYPE_RX) &&
(channels > 0)) {
+ perf_mode = test_bit(val,
+ &msm_bedais[reg].perf_mode);
adm_multi_ch_copp_open(msm_bedais[reg].port_id,
path_type,
msm_bedais[reg].sample_rate,
channels,
topology,
- msm_bedais[reg].perf_mode,
+ perf_mode,
bits_per_sample);
} else
adm_open(msm_bedais[reg].port_id,
@@ -521,7 +526,8 @@
topology, false, bits_per_sample);
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type);
+ fe_dai_map[val][session_type], path_type,
+ perf_mode);
port_id = srs_port_id = msm_bedais[reg].port_id;
srs_send_params(srs_port_id, 1, 0);
if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
@@ -536,11 +542,13 @@
clear_bit(val, &msm_bedais[reg].fe_sessions);
if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
INVALID_SESSION) {
- adm_close(msm_bedais[reg].port_id);
+ perf_mode = test_bit(val, &msm_bedais[reg].perf_mode);
+ adm_close(msm_bedais[reg].port_id, perf_mode);
if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
dolby_dap_deinit(msm_bedais[reg].port_id);
msm_pcm_routing_build_matrix(val,
- fe_dai_map[val][session_type], path_type);
+ fe_dai_map[val][session_type], path_type,
+ perf_mode);
}
}
if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
@@ -1406,6 +1414,24 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX ,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = {
@@ -1421,6 +1447,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_hl_mixer_controls[] = {
@@ -1445,6 +1474,9 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
@@ -1580,9 +1612,15 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -1655,6 +1693,9 @@
SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
@@ -1693,6 +1734,24 @@
msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new sec_mi2s_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1874,6 +1933,9 @@
SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_Voice", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voice2_mixer_controls[] = {
@@ -1943,6 +2005,9 @@
SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX_Voip", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
@@ -2557,6 +2622,8 @@
SND_SOC_DAPM_AIF_OUT("MI2S_RX", "MI2S Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("TERT_MI2S_RX", "Tertiary MI2S Playback",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX", "Secondary MI2S Playback",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("PRI_MI2S_RX", "Primary MI2S Playback",
@@ -2567,6 +2634,8 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("PRI_MI2S_TX", "Primary MI2S Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("TERT_MI2S_TX", "Tertiary MI2S Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
@@ -2642,6 +2711,9 @@
SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
quaternary_mi2s_rx_mixer_controls,
ARRAY_SIZE(quaternary_mi2s_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("TERT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ tertiary_mi2s_rx_mixer_controls,
+ ARRAY_SIZE(tertiary_mi2s_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
secondary_mi2s_rx_mixer_controls,
ARRAY_SIZE(secondary_mi2s_rx_mixer_controls)),
@@ -2678,6 +2750,10 @@
SND_SOC_NOPM, 0, 0,
sec_i2s_rx_voice_mixer_controls,
ARRAY_SIZE(sec_i2s_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_MI2S_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ sec_mi2s_rx_voice_mixer_controls,
+ ARRAY_SIZE(sec_mi2s_rx_voice_mixer_controls)),
SND_SOC_DAPM_MIXER("SLIM_0_RX_Voice Mixer",
SND_SOC_NOPM, 0, 0,
slimbus_rx_voice_mixer_controls,
@@ -2826,13 +2902,20 @@
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"QUAT_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"TERT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Audio Mixer"},
{"SEC_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"SEC_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SEC_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SEC_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Audio Mixer"},
{"SEC_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
@@ -2842,12 +2925,15 @@
{"PRI_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"PRI_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"PRI_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
{"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"},
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
+ {"MultiMedia5 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"MultiMedia1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia5 Mixer", "AUX_PCM_TX", "AUX_PCM_TX"},
@@ -2855,6 +2941,7 @@
{"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"},
{"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2925,6 +3012,13 @@
{"SEC_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
+ {"SEC_MI2S_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SEC_MI2S_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_MI2S_RX_Voice Mixer", "DTMF", "DTMF_DL_HL"},
+ {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX_Voice Mixer"},
+
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SLIM_0_RX_Voice Mixer", "Voice2", "VOICE2_DL"},
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
@@ -2975,6 +3069,7 @@
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
+ {"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
{"Voice_Tx Mixer", "MI2S_TX_Voice", "MI2S_TX"},
{"Voice_Tx Mixer", "SLIM_0_TX_Voice", "SLIMBUS_0_TX"},
{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
@@ -3006,6 +3101,7 @@
{"Voip_Tx Mixer", "AFE_PCM_TX_Voip", "PCM_TX"},
{"Voip_Tx Mixer", "AUX_PCM_TX_Voip", "AUX_PCM_TX"},
{"Voip_Tx Mixer", "SEC_AUX_PCM_TX_Voip", "SEC_AUX_PCM_TX"},
+ {"Voip_Tx Mixer", "PRI_MI2S_TX_Voip", "PRI_MI2S_TX"},
{"VOIP_UL", NULL, "Voip_Tx Mixer"},
{"SLIMBUS_DL_HL", "Switch", "SLIM0_DL_HL"},
@@ -3036,7 +3132,7 @@
{"MI2S_UL_HL", NULL, "MI2S_TX"},
{"PCM_RX_DL_HL", "Switch", "SLIM0_DL_HL"},
{"PCM_RX", NULL, "PCM_RX_DL_HL"},
- {"MI2S_UL_HL", NULL, "MI2S_TX"},
+ {"MI2S_UL_HL", NULL, "TERT_MI2S_TX"},
{"SEC_I2S_RX", NULL, "SEC_I2S_DL_HL"},
{"PRI_MI2S_UL_HL", NULL, "PRI_MI2S_TX"},
{"SEC_MI2S_RX", NULL, "SEC_MI2S_DL_HL"},
@@ -3106,6 +3202,7 @@
{"BE_OUT", NULL, "HDMI"},
{"BE_OUT", NULL, "MI2S_RX"},
{"BE_OUT", NULL, "QUAT_MI2S_RX"},
+ {"BE_OUT", NULL, "TERT_MI2S_RX"},
{"BE_OUT", NULL, "SEC_MI2S_RX"},
{"BE_OUT", NULL, "PRI_MI2S_RX"},
{"BE_OUT", NULL, "INT_BT_SCO_RX"},
@@ -3125,6 +3222,8 @@
{"PRI_I2S_TX", NULL, "BE_IN"},
{"MI2S_TX", NULL, "BE_IN"},
{"QUAT_MI2S_TX", NULL, "BE_IN"},
+ {"PRI_MI2S_TX", NULL, "BE_IN"},
+ {"TERT_MI2S_TX", NULL, "BE_IN"},
{"SEC_MI2S_TX", NULL, "BE_IN"},
{"SLIMBUS_0_TX", NULL, "BE_IN" },
{"SLIMBUS_1_TX", NULL, "BE_IN" },
@@ -3185,8 +3284,10 @@
topology = get_topology(path_type);
for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
if (fe_dai_map[i][session_type] != INVALID_SESSION) {
- adm_close(bedai->port_id);
+ adm_close(bedai->port_id,
+ test_bit(i, &(bedai->perf_mode)));
srs_port_id = -1;
+ clear_bit(i, &(bedai->perf_mode));
if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
dolby_dap_deinit(bedai->port_id);
}
@@ -3195,7 +3296,6 @@
bedai->active = 0;
bedai->sample_rate = 0;
bedai->channel = 0;
- bedai->perf_mode = false;
mutex_unlock(&routing_lock);
return 0;
@@ -3210,6 +3310,7 @@
u32 channels;
bool playback, capture;
uint16_t bits_per_sample = 16;
+ bool perf_mode = false;
if (be_id >= MSM_BACKEND_DAI_MAX) {
pr_err("%s: unexpected be_id %d\n", __func__, be_id);
@@ -3248,11 +3349,13 @@
bits_per_sample = 24;
if ((playback) && (channels > 0)) {
+ perf_mode = test_bit(i, &(bedai->perf_mode));
adm_multi_ch_copp_open(bedai->port_id,
path_type,
bedai->sample_rate,
channels,
- topology, bedai->perf_mode,
+ topology,
+ perf_mode,
bits_per_sample);
} else if (capture) {
adm_open(bedai->port_id,
@@ -3264,7 +3367,8 @@
}
msm_pcm_routing_build_matrix(i,
- fe_dai_map[i][session_type], path_type);
+ fe_dai_map[i][session_type], path_type,
+ perf_mode);
port_id = srs_port_id = bedai->port_id;
srs_send_params(srs_port_id, 1, 0);
if (DOLBY_ADM_COPP_TOPOLOGY_ID == topology)
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 1bd3eac..29c06cb 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -39,6 +39,9 @@
void *apr;
atomic_t copp_id[AFE_MAX_PORTS];
atomic_t copp_cnt[AFE_MAX_PORTS];
+ atomic_t copp_low_latency_id[AFE_MAX_PORTS];
+ atomic_t copp_low_latency_cnt[AFE_MAX_PORTS];
+ atomic_t copp_perf_mode[AFE_MAX_PORTS];
atomic_t copp_stat[AFE_MAX_PORTS];
wait_queue_head_t wait[AFE_MAX_PORTS];
@@ -445,7 +448,12 @@
for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i],
RESET_COPP_ID);
+ atomic_set(&this_adm.copp_low_latency_id[i],
+ RESET_COPP_ID);
atomic_set(&this_adm.copp_cnt[i], 0);
+ atomic_set(&this_adm.copp_low_latency_cnt[i],
+ 0);
+ atomic_set(&this_adm.copp_perf_mode[i], 0);
atomic_set(&this_adm.copp_stat[i], 0);
}
this_adm.apr = NULL;
@@ -545,7 +553,13 @@
wake_up(&this_adm.wait[index]);
break;
}
- atomic_set(&this_adm.copp_id[index], open->copp_id);
+ if (atomic_read(&this_adm.copp_perf_mode[index])) {
+ atomic_set(&this_adm.copp_low_latency_id[index],
+ open->copp_id);
+ } else {
+ atomic_set(&this_adm.copp_id[index],
+ open->copp_id);
+ }
atomic_set(&this_adm.copp_stat[index], 1);
pr_debug("%s: coppid rxed=%d\n", __func__,
open->copp_id);
@@ -892,8 +906,8 @@
int index;
int tmp_port = q6audio_get_port_id(port_id);
- pr_debug("%s: port %#x path:%d rate:%d mode:%d\n", __func__,
- port_id, path, rate, channel_mode);
+ pr_debug("%s: port %#x path:%d rate:%d mode:%d perf_mode:%d\n",
+ __func__, port_id, path, rate, channel_mode, perf_mode);
port_id = q6audio_convert_virtual_to_portid(port_id);
@@ -916,11 +930,19 @@
rtac_set_adm_handle(this_adm.apr);
}
- send_adm_custom_topology(port_id);
+ if (!perf_mode) {
+ atomic_set(&this_adm.copp_perf_mode[index], 0);
+ send_adm_custom_topology(port_id);
+ } else {
+ atomic_set(&this_adm.copp_perf_mode[index], 1);
+ }
/* Create a COPP if port id are not enabled */
- if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
-
+ if ((!perf_mode && (atomic_read(&this_adm.copp_cnt[index]) == 0)) ||
+ (perf_mode &&
+ (atomic_read(&this_adm.copp_low_latency_cnt[index]) == 0))) {
+ pr_debug("%s:opening ADM: perf_mode: %d\n", __func__,
+ perf_mode);
open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
open.hdr.pkt_size = sizeof(open);
@@ -950,6 +972,9 @@
(open.topology_id == VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
rate = 16000;
+ if (perf_mode)
+ open.topology_id = NULL_COPP_TOPOLOGY;
+
open.dev_num_channel = channel_mode & 0x00FF;
open.bit_width = bits_per_sample;
open.sample_rate = rate;
@@ -1026,7 +1051,15 @@
goto fail_cmd;
}
}
- atomic_inc(&this_adm.copp_cnt[index]);
+ if (perf_mode) {
+ atomic_inc(&this_adm.copp_low_latency_cnt[index]);
+ pr_debug("%s: index: %d coppid: %d", __func__, index,
+ atomic_read(&this_adm.copp_low_latency_id[index]));
+ } else {
+ atomic_inc(&this_adm.copp_cnt[index]);
+ pr_debug("%s: index: %d coppid: %d", __func__, index,
+ atomic_read(&this_adm.copp_id[index]));
+ }
return 0;
fail_cmd:
@@ -1046,7 +1079,7 @@
}
int adm_matrix_map(int session_id, int path, int num_copps,
- unsigned int *port_id, int copp_id)
+ unsigned int *port_id, int copp_id, bool perf_mode)
{
struct adm_cmd_matrix_map_routings_v5 *route;
struct adm_session_map_node_v5 *node;
@@ -1085,7 +1118,12 @@
route->hdr.src_port = copp_id;
route->hdr.dest_svc = APR_SVC_ADM;
route->hdr.dest_domain = APR_DOMAIN_ADSP;
- route->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ if (perf_mode) {
+ route->hdr.dest_port =
+ atomic_read(&this_adm.copp_low_latency_id[index]);
+ } else {
+ route->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ }
route->hdr.token = copp_id;
route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5;
route->num_sessions = 1;
@@ -1117,9 +1155,14 @@
tmp = q6audio_get_port_index(port_id[i]);
- if (tmp >= 0 && tmp < AFE_MAX_PORTS)
- copps_list[i] =
+ if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+ if (perf_mode)
+ copps_list[i] =
+ atomic_read(&this_adm.copp_low_latency_id[tmp]);
+ else
+ copps_list[i] =
atomic_read(&this_adm.copp_id[tmp]);
+ }
else
continue;
pr_debug("%s: port_id[%#x]: %d, index: %d act coppid[0x%x]\n",
@@ -1144,21 +1187,42 @@
ret = -EINVAL;
goto fail_cmd;
}
- for (i = 0; i < num_copps; i++)
- send_adm_cal(port_id[i], path);
+ if (perf_mode) {
+ for (i = 0; i < num_copps; i++) {
+ int tmp;
- for (i = 0; i < num_copps; i++) {
- int tmp;
- tmp = afe_get_port_index(port_id[i]);
- if (tmp >= 0 && tmp < AFE_MAX_PORTS)
- rtac_add_adm_device(port_id[i],
- atomic_read(&this_adm.copp_id[tmp]),
- path, session_id);
- else
- pr_debug("%s: Invalid port index %d",
- __func__, tmp);
+ tmp = afe_get_port_index(port_id[i]);
+ if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+ rtac_add_adm_device(port_id[i], atomic_read(
+ &this_adm.copp_low_latency_id[tmp]),
+ path, session_id);
+ pr_debug("%s, copp_id: %d\n", __func__,
+ atomic_read(
+ &this_adm.copp_low_latency_id[tmp]));
+ } else {
+ pr_debug("%s: Invalid port index %d",
+ __func__, tmp);
+ }
+ }
+ } else {
+ for (i = 0; i < num_copps; i++)
+ send_adm_cal(port_id[i], path);
+
+ for (i = 0; i < num_copps; i++) {
+ int tmp;
+ tmp = afe_get_port_index(port_id[i]);
+ if (tmp >= 0 && tmp < AFE_MAX_PORTS) {
+ rtac_add_adm_device(port_id[i],
+ atomic_read(&this_adm.copp_id[tmp]),
+ path, session_id);
+ pr_debug("%s, copp_id: %d\n", __func__,
+ atomic_read(&this_adm.copp_id[tmp]));
+ } else {
+ pr_debug("%s: Invalid port index %d",
+ __func__, tmp);
+ }
+ }
}
-
fail_cmd:
kfree(matrix_map);
return ret;
@@ -1319,7 +1383,7 @@
return atomic_read(&this_adm.copp_id[port_index]);
}
-int adm_close(int port_id)
+int adm_close(int port_id, bool perf_mode)
{
struct apr_hdr close;
@@ -1332,16 +1396,30 @@
if (q6audio_validate_port(port_id) < 0)
return -EINVAL;
- pr_debug("%s port_id=%#x index %d\n", __func__, port_id, index);
+ pr_debug("%s port_id=%#x index %d perf_mode: %d\n", __func__, port_id,
+ index, perf_mode);
- if (!(atomic_read(&this_adm.copp_cnt[index]))) {
- pr_err("%s: copp count for port[%#x]is 0\n", __func__, port_id);
-
- goto fail_cmd;
+ if (perf_mode) {
+ if (!(atomic_read(&this_adm.copp_low_latency_cnt[index]))) {
+ pr_err("%s: copp count for port[%#x]is 0\n", __func__,
+ port_id);
+ goto fail_cmd;
+ }
+ atomic_dec(&this_adm.copp_low_latency_cnt[index]);
+ } else {
+ if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+ pr_err("%s: copp count for port[%#x]is 0\n", __func__,
+ port_id);
+ goto fail_cmd;
+ }
+ atomic_dec(&this_adm.copp_cnt[index]);
}
- atomic_dec(&this_adm.copp_cnt[index]);
- if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+ if ((!perf_mode && !(atomic_read(&this_adm.copp_cnt[index]))) ||
+ (perf_mode &&
+ !(atomic_read(&this_adm.copp_low_latency_cnt[index])))) {
+ pr_debug("%s:Closing ADM: perf_mode: %d\n", __func__,
+ perf_mode);
close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
close.pkt_size = sizeof(close);
@@ -1350,19 +1428,33 @@
close.src_port = port_id;
close.dest_svc = APR_SVC_ADM;
close.dest_domain = APR_DOMAIN_ADSP;
- close.dest_port = atomic_read(&this_adm.copp_id[index]);
+ if (perf_mode)
+ close.dest_port =
+ atomic_read(&this_adm.copp_low_latency_id[index]);
+ else
+ close.dest_port = atomic_read(&this_adm.copp_id[index]);
close.token = port_id;
close.opcode = ADM_CMD_DEVICE_CLOSE_V5;
- atomic_set(&this_adm.copp_id[index], RESET_COPP_ID);
atomic_set(&this_adm.copp_stat[index], 0);
-
- pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
+ if (perf_mode) {
+ pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
+ __func__,
+ atomic_read(&this_adm.copp_low_latency_id[index]),
+ port_id, index,
+ atomic_read(&this_adm.copp_low_latency_cnt[index]));
+ atomic_set(&this_adm.copp_low_latency_id[index],
+ RESET_COPP_ID);
+ } else {
+ pr_debug("%s:coppid %d portid=%#x index=%d coppcnt=%d\n",
__func__,
atomic_read(&this_adm.copp_id[index]),
port_id, index,
atomic_read(&this_adm.copp_cnt[index]));
+ atomic_set(&this_adm.copp_id[index],
+ RESET_COPP_ID);
+ }
ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
if (ret < 0) {
@@ -1380,7 +1472,10 @@
ret = -EINVAL;
goto fail_cmd;
}
-
+ }
+ if (!atomic_read(&this_adm.copp_cnt[index]) &&
+ !atomic_read(&this_adm.copp_low_latency_cnt[index])) {
+ pr_debug("%s: remove adm device from rtac\n", __func__);
rtac_remove_adm_device(port_id);
}
@@ -1396,8 +1491,11 @@
for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
+ atomic_set(&this_adm.copp_low_latency_id[i], RESET_COPP_ID);
atomic_set(&this_adm.copp_cnt[i], 0);
+ atomic_set(&this_adm.copp_low_latency_cnt[i], 0);
atomic_set(&this_adm.copp_stat[i], 0);
+ atomic_set(&this_adm.copp_perf_mode[i], 0);
init_waitqueue_head(&this_adm.wait[i]);
}
return 0;
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 3598977..ce5e816 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -899,6 +899,44 @@
return ret;
}
+static int afe_send_bank_selection_clip(
+ struct afe_param_id_clip_bank_sel *param)
+{
+ int ret;
+ struct afe_svc_cmd_set_clip_bank_selection config;
+ if (!param) {
+ pr_err("%s: Invalid params", __func__);
+ return -EINVAL;
+ }
+ config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ config.hdr.pkt_size = sizeof(config);
+ config.hdr.src_port = 0;
+ config.hdr.dest_port = 0;
+ config.hdr.token = IDX_GLOBAL_CFG;
+ config.hdr.opcode = AFE_SVC_CMD_SET_PARAM;
+
+ config.param.payload_size = sizeof(struct afe_port_param_data_v2) +
+ sizeof(struct afe_param_id_clip_bank_sel);
+ config.param.payload_address_lsw = 0x00;
+ config.param.payload_address_msw = 0x00;
+ config.param.mem_map_handle = 0x00;
+
+ config.pdata.module_id = AFE_MODULE_CDC_DEV_CFG;
+ config.pdata.param_id = AFE_PARAM_ID_CLIP_BANK_SEL_CFG;
+ config.pdata.param_size =
+ sizeof(struct afe_param_id_clip_bank_sel);
+ config.bank_sel = *param;
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[IDX_GLOBAL_CFG]);
+ if (ret) {
+ pr_err("%s: AFE_PARAM_ID_CLIP_BANK_SEL_CFG failed %d\n",
+ __func__, ret);
+ } else if (atomic_read(&this_afe.status) != 0) {
+ pr_err("%s: config cmd failed\n", __func__);
+ ret = -EAGAIN;
+ }
+ return ret;
+}
int afe_send_aanc_version(
struct afe_param_id_cdc_aanc_version *version_cfg)
{
@@ -991,6 +1029,12 @@
case AFE_AANC_VERSION:
ret = afe_send_aanc_version(config_data);
break;
+ case AFE_CLIP_BANK_SEL:
+ ret = afe_send_bank_selection_clip(config_data);
+ break;
+ case AFE_CDC_CLIP_REGISTERS_CONFIG:
+ ret = afe_send_codec_reg_config(config_data);
+ break;
default:
pr_err("%s: unknown configuration type", __func__);
ret = -EINVAL;
@@ -1149,21 +1193,20 @@
config.hdr.token = index;
switch (port_id) {
- case PRIMARY_I2S_RX:
- case PRIMARY_I2S_TX:
- cfg_type = AFE_PARAM_ID_PCM_CONFIG;
- break;
case AFE_PORT_ID_PRIMARY_PCM_RX:
case AFE_PORT_ID_PRIMARY_PCM_TX:
case AFE_PORT_ID_SECONDARY_PCM_RX:
case AFE_PORT_ID_SECONDARY_PCM_TX:
cfg_type = AFE_PARAM_ID_PCM_CONFIG;
break;
+ case PRIMARY_I2S_RX:
+ case PRIMARY_I2S_TX:
case SECONDARY_I2S_RX:
case SECONDARY_I2S_TX:
case MI2S_RX:
case MI2S_TX:
case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
case AFE_PORT_ID_SECONDARY_MI2S_RX:
case AFE_PORT_ID_SECONDARY_MI2S_TX:
case AFE_PORT_ID_TERTIARY_MI2S_RX:
@@ -1288,6 +1331,8 @@
case SLIMBUS_5_TX: return IDX_SLIMBUS_5_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_MI2S_TX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
@@ -1296,6 +1341,10 @@
return IDX_AFE_PORT_ID_SECONDARY_MI2S_RX;
case AFE_PORT_ID_SECONDARY_MI2S_TX:
return IDX_AFE_PORT_ID_SECONDARY_MI2S_TX;
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_RX;
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_TX;
default: return -EINVAL;
}
diff --git a/sound/soc/msm/qdsp6v2/q6audio-v2.c b/sound/soc/msm/qdsp6v2/q6audio-v2.c
index 3cb7a1f..bc7ad4d 100644
--- a/sound/soc/msm/qdsp6v2/q6audio-v2.c
+++ b/sound/soc/msm/qdsp6v2/q6audio-v2.c
@@ -60,6 +60,8 @@
case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return IDX_AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_PRIMARY_MI2S_TX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
return IDX_AFE_PORT_ID_QUATERNARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
@@ -68,6 +70,10 @@
return IDX_AFE_PORT_ID_SECONDARY_MI2S_RX;
case AFE_PORT_ID_SECONDARY_MI2S_TX:
return IDX_AFE_PORT_ID_SECONDARY_MI2S_TX;
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_RX;
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ return IDX_AFE_PORT_ID_TERTIARY_MI2S_TX;
default: return -EINVAL;
}
@@ -76,8 +82,8 @@
int q6audio_get_port_id(u16 port_id)
{
switch (port_id) {
- case PRIMARY_I2S_RX: return AFE_PORT_ID_PRIMARY_MI2S_RX;
- case PRIMARY_I2S_TX: return AFE_PORT_ID_PRIMARY_MI2S_TX;
+ case PRIMARY_I2S_RX: return PRIMARY_I2S_RX;
+ case PRIMARY_I2S_TX: return PRIMARY_I2S_TX;
case AFE_PORT_ID_PRIMARY_PCM_RX:
return AFE_PORT_ID_PRIMARY_PCM_RX;
case AFE_PORT_ID_PRIMARY_PCM_TX:
@@ -114,6 +120,8 @@
case RT_PROXY_PORT_001_TX: return AFE_PORT_ID_RT_PROXY_PORT_001_TX;
case AFE_PORT_ID_PRIMARY_MI2S_RX:
return AFE_PORT_ID_PRIMARY_MI2S_RX;
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ return AFE_PORT_ID_PRIMARY_MI2S_TX;
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
return AFE_PORT_ID_QUATERNARY_MI2S_RX;
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
@@ -122,7 +130,10 @@
return AFE_PORT_ID_SECONDARY_MI2S_RX;
case AFE_PORT_ID_SECONDARY_MI2S_TX:
return AFE_PORT_ID_SECONDARY_MI2S_TX;
-
+ case AFE_PORT_ID_TERTIARY_MI2S_RX:
+ return AFE_PORT_ID_TERTIARY_MI2S_RX;
+ case AFE_PORT_ID_TERTIARY_MI2S_TX:
+ return AFE_PORT_ID_TERTIARY_MI2S_TX;
default:
pr_warn("%s: Invalid port_id %d\n", __func__, port_id);
return -EINVAL;
@@ -168,6 +179,10 @@
case AFE_PORT_ID_TERTIARY_MI2S_RX:
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
+ case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
+ case AFE_PORT_ID_SECONDARY_MI2S_RX:
+ case AFE_PORT_ID_SECONDARY_MI2S_TX:
break;
default:
ret = -EINVAL;
@@ -214,6 +229,7 @@
case RT_PROXY_PORT_001_RX:
case RT_PROXY_PORT_001_TX:
case AFE_PORT_ID_PRIMARY_MI2S_RX:
+ case AFE_PORT_ID_PRIMARY_MI2S_TX:
case AFE_PORT_ID_QUATERNARY_MI2S_RX:
case AFE_PORT_ID_QUATERNARY_MI2S_TX:
case AFE_PORT_ID_SECONDARY_MI2S_RX: