summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/msm/qcom,osm.txt10
-rw-r--r--Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt8
-rw-r--r--Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt19
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi11
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt.dtsi62
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon.dtsi53
-rw-r--r--arch/arm/mm/dma-mapping.c1
-rw-r--r--arch/arm64/configs/msm-perf_defconfig3
-rw-r--r--arch/arm64/configs/msm_defconfig3
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig3
-rw-r--r--arch/arm64/configs/msmcortex_defconfig3
-rw-r--r--drivers/clk/msm/Makefile8
-rw-r--r--drivers/clk/msm/clock-osm.c333
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clk-dummy.c110
-rw-r--r--drivers/clk/qcom/common.h4
-rw-r--r--drivers/gpu/msm/Makefile2
-rw-r--r--drivers/gpu/msm/a5xx_reg.h2
-rw-r--r--drivers/gpu/msm/adreno.c126
-rw-r--r--drivers/gpu/msm/adreno.h155
-rw-r--r--drivers/gpu/msm/adreno_a3xx.c4
-rw-r--r--drivers/gpu/msm/adreno_a4xx.c563
-rw-r--r--drivers/gpu/msm/adreno_a4xx.h9
-rw-r--r--drivers/gpu/msm/adreno_a4xx_preempt.c571
-rw-r--r--drivers/gpu/msm/adreno_a4xx_snapshot.c5
-rw-r--r--drivers/gpu/msm/adreno_a5xx.c687
-rw-r--r--drivers/gpu/msm/adreno_a5xx.h20
-rw-r--r--drivers/gpu/msm/adreno_a5xx_preempt.c574
-rw-r--r--drivers/gpu/msm/adreno_debugfs.c3
-rw-r--r--drivers/gpu/msm/adreno_dispatch.c617
-rw-r--r--drivers/gpu/msm/adreno_dispatch.h40
-rw-r--r--drivers/gpu/msm/adreno_drawctxt.c49
-rw-r--r--drivers/gpu/msm/adreno_drawctxt.h3
-rw-r--r--drivers/gpu/msm/adreno_ioctl.c2
-rw-r--r--drivers/gpu/msm/adreno_iommu.c102
-rw-r--r--drivers/gpu/msm/adreno_iommu.h6
-rw-r--r--drivers/gpu/msm/adreno_ringbuffer.c387
-rw-r--r--drivers/gpu/msm/adreno_ringbuffer.h26
-rw-r--r--drivers/gpu/msm/adreno_snapshot.c5
-rw-r--r--drivers/gpu/msm/adreno_trace.h101
-rw-r--r--drivers/gpu/msm/kgsl.c32
-rw-r--r--drivers/gpu/msm/kgsl.h41
-rw-r--r--drivers/gpu/msm/kgsl_cmdbatch.h4
-rw-r--r--drivers/gpu/msm/kgsl_device.h1
-rw-r--r--drivers/gpu/msm/kgsl_events.c25
-rw-r--r--drivers/gpu/msm/kgsl_iommu.c50
-rw-r--r--drivers/gpu/msm/kgsl_mmu.h6
-rw-r--r--drivers/gpu/msm/kgsl_pwrctrl.c7
-rw-r--r--drivers/input/touchscreen/it7258_ts_i2c.c851
-rw-r--r--drivers/iommu/arm-smmu.c34
-rw-r--r--drivers/media/platform/msm/camera_v2/camera/camera.c4
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp40.c96
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp44.c92
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp46.c95
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.c167
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c30
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c15
-rw-r--r--drivers/mfd/wcd9xxx-utils.c4
-rw-r--r--drivers/misc/qcom/qdsp6v2/q6audio_v2.c7
-rw-r--r--drivers/of/of_batterydata.c23
-rw-r--r--drivers/power/qcom-charger/qpnp-fg.c17
-rw-r--r--drivers/power/qcom-charger/qpnp-smb2.c141
-rw-r--r--drivers/power/qcom-charger/qpnp-smbcharger.c18
-rw-r--r--drivers/power/qcom-charger/smb-lib.h6
-rw-r--r--drivers/power/qcom-charger/smb-reg.h9
-rw-r--r--drivers/regulator/cpr3-regulator.c24
-rw-r--r--drivers/regulator/cpr3-regulator.h9
-rw-r--r--drivers/regulator/cprh-kbss-regulator.c73
-rw-r--r--drivers/soc/qcom/Makefile2
-rw-r--r--drivers/soc/qcom/glink_private.h1
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c2
-rw-r--r--drivers/usb/dwc3/gadget.c11
-rw-r--r--drivers/usb/host/xhci-pci.c1
-rw-r--r--drivers/usb/host/xhci-plat.c1
-rw-r--r--drivers/usb/host/xhci-ring.c3
-rw-r--r--drivers/usb/host/xhci.c8
-rw-r--r--drivers/usb/host/xhci.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c13
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c3
-rw-r--r--include/linux/of_batterydata.h11
-rw-r--r--include/soc/qcom/smem.h1
-rw-r--r--include/uapi/linux/msm_kgsl.h2
-rw-r--r--kernel/Documentation/firmware_updater/request_firmware.txt22
-rw-r--r--kernel/Documentation/firmware_updater/synaptics_fw_updaterbin0 -> 666266 bytes
-rw-r--r--kernel/Documentation/firmware_updater/synaptics_fw_updater.c753
-rw-r--r--kernel/Documentation/firmware_updater/synaptics_fw_updater_readme.txt41
-rw-r--r--kernel/arch/arm/configs/omap3_beagle_android_defconfig2419
-rw-r--r--kernel/arch/arm/configs/panda_defconfig331
-rw-r--r--kernel/arch/arm/mach-omap2/board-omap3beagle.c1038
-rw-r--r--kernel/arch/arm/mach-omap2/board-omap4panda.c1053
-rw-r--r--kernel/drivers/input/touchscreen/Kconfig721
-rw-r--r--kernel/drivers/input/touchscreen/Makefile68
-rw-r--r--kernel/drivers/input/touchscreen/msg21xx/msg21xx_ts.c1757
-rw-r--r--kernel/drivers/input/touchscreen/synaptics_fw_update.c1587
-rw-r--r--kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.c2110
-rw-r--r--kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.h282
-rw-r--r--kernel/drivers/input/touchscreen/synaptics_rmi_dev.c710
-rw-r--r--kernel/include/linux/input/synaptics_dsx.h59
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c78
-rw-r--r--sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c5
-rw-r--r--sound/usb/usb_audio_qmi_svc.c36
-rw-r--r--sound/usb/usb_audio_qmi_v01.c368
-rw-r--r--sound/usb/usb_audio_qmi_v01.h75
104 files changed, 17347 insertions, 2800 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
index 2bd7653af5a3..cee9b942a9e3 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
@@ -182,6 +182,14 @@ Properties:
command register for each of the two clusters managed
by the OSM controller.
+- qcom,apm-threshold-voltage
+ Usage: required
+ Value type: <u32>
+ Definition: Specifies the APM threshold voltage in microvolts. If the
+ VDD_APCC supply voltage is above or at this level, then the
+ APM is switched to use VDD_APCC. If VDD_APCC is below
+ this level, then the APM is switched to use VDD_MX.
+
- qcom,apm-mode-ctl
Usage: required
Value type: <prop-encoded-array>
@@ -392,6 +400,8 @@ Example:
qcom,apm-ctrl-status =
<0x179d000c 0x179d0018>;
+ qcom,apm-threshold-voltage = <832000>;
+
qcom,pwrcl-apcs-mem-acc-cfg =
<0x179d1360 0x179d1364 0x179d1364>;
qcom,perfcl-apcs-mem-acc-cfg =
diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
index 58db2c2350e4..368f0b8c9525 100644
--- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
@@ -50,6 +50,12 @@ Charger specific properties:
Value type: <u32>
Definition: Specifies the DC input current limit in micro-amps.
+- qcom,wipower-max-uw
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the DC input power limit in micro-watts.
+ If the value is not present, 8W is used as default.
+
=============================================
Second Level Nodes - SMB2 Charger Peripherals
=============================================
@@ -80,9 +86,7 @@ pmicobalt_charger: qcom,qpnp-smb2 {
#address-cells = <1>;
#size-cells = <1>;
- qcom,pmic-revid = <&pmicobalt_revid>;
qcom,suspend-input;
- qcom,disable-charging;
dpdm-supply = <&qusb_phy0>;
qcom,chgr@1000 {
diff --git a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt
index b9143cfc2587..833fb645b92a 100644
--- a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt
@@ -42,10 +42,21 @@ KBSS specific properties:
- qcom,apm-threshold-voltage
Usage: optional
Value type: <u32>
- Definition: Specifies the APM threshold voltage in microvolts. If the
- VDD_APCC supply voltage is above this level, then the APM is
- switched to use VDD_APCC. If VDD_APCC is below this level,
- then the APM is switched to use VDD_MX.
+ Definition: Specifies the APM threshold voltage in microvolts. The
+ floor to ceiling range for every corner is adjusted to ensure
+ it does not intersect this voltage. The value of this property
+ must match with the APM threshold voltage defined in the OSM
+ device to ensure that if the VDD_APCC supply voltage is above
+ this level, then the APM is switched to use VDD_APCC and if
+ VDD_APCC is below this level, then the APM is switched to use
+ VDD_MX.
+
+- qcom,apm-crossover-voltage
+ Usage: required if qcom,apm-threshold-voltage is specified
+ Value type: <u32>
+ Definition: Specifies the APM crossover voltage in microvolts which
+ corresponds to the voltage the VDD supply must be set at
+ during an APM switch transition.
- qcom,apm-hysteresis-voltage
Usage: optional
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi
index 3c39a61c4328..86decf438430 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi
@@ -131,6 +131,16 @@
clock-names = "bus_clk", "bus_a_clk";
clocks = <&clock_gcc clk_mmssnoc_axi_clk>,
<&clock_gcc clk_mmssnoc_axi_a_clk>;
+ clk-mdss-axi-no-rate-supply =
+ <&gdsc_mdss>;
+ clk-mdss-ahb-no-rate-supply =
+ <&gdsc_mdss>;
+ clk-camss-ahb-no-rate-supply =
+ <&gdsc_camss_top>;
+ clk-video-ahb-no-rate-supply =
+ <&gdsc_venus>;
+ clk-video-axi-no-rate-supply =
+ <&gdsc_venus>;
qcom,node-qos-clks {
clock-names =
"clk-noc-cfg-ahb-no-rate",
@@ -141,6 +151,7 @@
"clk-video-ahb-no-rate",
"clk-video-axi-no-rate";
clocks =
+ <&clock_gcc clk_mmssnoc_axi_clk>,
<&clock_gcc clk_gcc_mmss_noc_cfg_ahb_clk>,
<&clock_mmss clk_mmss_mnoc_ahb_clk>,
<&clock_mmss clk_mmss_mdss_ahb_clk>,
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
index 12ee61b34d8c..5833b30d1fd1 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
@@ -576,6 +576,7 @@
qcom,cpr-voltage-settling-time = <1760>;
qcom,apm-threshold-voltage = <832000>;
+ qcom,apm-crossover-voltage = <880000>;
qcom,apm-hysteresis-voltage = <32000>;
qcom,voltage-step = <4000>;
qcom,voltage-base = <352000>;
@@ -737,6 +738,7 @@
qcom,cpr-voltage-settling-time = <1760>;
qcom,apm-threshold-voltage = <832000>;
+ qcom,apm-crossover-voltage = <880000>;
qcom,apm-hysteresis-voltage = <32000>;
qcom,voltage-step = <4000>;
qcom,voltage-base = <352000>;
diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi
index e748783b0c7d..5dc530ea8494 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi
@@ -804,21 +804,21 @@
< 576000000 0x0504001e 0x03200020 0x1 >,
< 633600000 0x05040021 0x03200020 0x1 >,
< 710400000 0x05040025 0x03200020 0x1 >,
- < 806400000 0x0504002a 0x04200020 0x2 >,
- < 883200000 0x0404002e 0x04250025 0x2 >,
- < 960000000 0x04040032 0x05280028 0x2 >,
- < 1036800000 0x04040036 0x052b002b 0x3 >,
- < 1113600000 0x0404003a 0x052e002e 0x3 >,
- < 1190400000 0x0404003e 0x06320032 0x3 >,
- < 1248000000 0x04040041 0x06340034 0x3 >,
- < 1324800000 0x04040045 0x06370037 0x3 >,
- < 1401600000 0x04040049 0x073a003a 0x3 >,
- < 1478400000 0x0404004d 0x073e003e 0x3 >,
- < 1574400000 0x04040052 0x08420042 0x4 >,
- < 1651200000 0x04040056 0x08450045 0x4 >,
- < 1728000000 0x0404005a 0x08480048 0x4 >,
- < 1804800000 0x0404005e 0x094b004b 0x4 >,
- < 1881600000 0x04040062 0x094e004e 0x4 >;
+ < 806400000 0x0504002a 0x04200020 0x1 >,
+ < 883200000 0x0404002e 0x04250025 0x1 >,
+ < 960000000 0x04040032 0x05280028 0x1 >,
+ < 1036800000 0x04040036 0x052b002b 0x2 >,
+ < 1113600000 0x0404003a 0x052e002e 0x2 >,
+ < 1190400000 0x0404003e 0x06320032 0x2 >,
+ < 1248000000 0x04040041 0x06340034 0x2 >,
+ < 1324800000 0x04040045 0x06370037 0x2 >,
+ < 1401600000 0x04040049 0x073a003a 0x2 >,
+ < 1478400000 0x0404004d 0x073e003e 0x2 >,
+ < 1574400000 0x04040052 0x08420042 0x3 >,
+ < 1651200000 0x04040056 0x08450045 0x3 >,
+ < 1728000000 0x0404005a 0x08480048 0x3 >,
+ < 1804800000 0x0404005e 0x094b004b 0x3 >,
+ < 1881600000 0x04040062 0x094e004e 0x3 >;
qcom,perfcl-speedbin0-v0 =
< 300000000 0x0004000f 0x01200020 0x1 >,
@@ -888,6 +888,7 @@
<0x8fff0036 0x8fff003a 0x0fff0036>,
<0x8fff003d 0x8fff0041 0x0fff003d>;
+ qcom,apm-threshold-voltage = <832000>;
qcom,boost-fsm-en;
qcom,safe-fsm-en;
qcom,ps-fsm-en;
@@ -900,13 +901,11 @@
qcom,perfcl-apcs-mem-acc-cfg =
<0x179d1368 0x179d136C 0x179d1370>;
qcom,pwrcl-apcs-mem-acc-val =
- <0x00000000 0x10000000 0x10000000>,
- <0x00000000 0x10000000 0x10000000>,
+ <0x00000000 0x80000000 0x80000000>,
<0x00000000 0x00000000 0x00000000>,
<0x00000000 0x00000001 0x00000001>;
qcom,perfcl-apcs-mem-acc-val =
- <0x00000000 0x00000000 0x10000000>,
- <0x00000000 0x00000000 0x10000000>,
+ <0x00000000 0x00000000 0x80000000>,
<0x00000000 0x00000000 0x00000000>,
<0x00000000 0x00000000 0x00000001>;
@@ -966,8 +965,12 @@
qcom,do-not-use-ch-gsi-20;
qcom,ipa-wdi2;
qcom,use-64-bit-dma-mask;
- clock-names = "core_clk";
- clocks = <&clock_gcc clk_ipa_clk>;
+ clocks = <&clock_gcc clk_ipa_clk>,
+ <&clock_gcc clk_aggre2_noc_clk>;
+ clock-names = "core_clk", "smmu_clk";
+ qcom,arm-smmu;
+ qcom,smmu-disable-htw;
+ qcom,smmu-s1-bypass;
qcom,msm-bus,name = "ipa";
qcom,msm-bus,num-cases = <4>;
qcom,msm-bus,num-paths = <3>;
@@ -1074,6 +1077,23 @@
compatible = "qcom,smp2pgpio-map-ipa-1-in";
gpios = <&smp2pgpio_ipa_1_in 0 0>;
};
+
+ ipa_smmu_ap: ipa_smmu_ap {
+ compatible = "qcom,ipa-smmu-ap-cb";
+ iommus = <&anoc2_smmu 0x18e0>;
+ qcom,iova-mapping = <0x10000000 0x40000000>;
+ };
+
+ ipa_smmu_wlan: ipa_smmu_wlan {
+ compatible = "qcom,ipa-smmu-wlan-cb";
+ iommus = <&anoc2_smmu 0x18e1>;
+ };
+
+ ipa_smmu_uc: ipa_smmu_uc {
+ compatible = "qcom,ipa-smmu-uc-cb";
+ iommus = <&anoc2_smmu 0x18e2>;
+ qcom,iova-mapping = <0x40000000 0x20000000>;
+ };
};
qcom,ipa_fws@1e08000 {
diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
index 2b19c74bd3cb..ea60ed90cf4f 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
@@ -313,6 +313,59 @@
compatible = "qcom,dummycc";
#clock-cells = <1>;
};
+
+ qcom,ipc-spinlock@1f40000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0x1f40000 0x8000>;
+ qcom,num-locks = <8>;
+ };
+
+ qcom,smem@86000000 {
+ compatible = "qcom,smem";
+ reg = <0x86000000 0x200000>,
+ <0x17911008 0x4>,
+ <0x778000 0x7000>,
+ <0x1fd4000 0x8>;
+ reg-names = "smem", "irq-reg-base", "aux-mem1",
+ "smem_targ_info_reg";
+ qcom,mpu-enabled;
+ };
+
+ glink_mpss: qcom,glink-ssr-modem {
+ compatible = "qcom,glink_ssr";
+ label = "modem";
+ qcom,edge = "mpss";
+ qcom,notify-edges = <&glink_lpass>, <&glink_rpm>,
+ <&glink_cdsp>;
+ qcom,xprt = "smem";
+ };
+
+ glink_lpass: qcom,glink-ssr-adsp {
+ compatible = "qcom,glink_ssr";
+ label = "adsp";
+ qcom,edge = "lpass";
+ qcom,notify-edges = <&glink_mpss>, <&glink_rpm>,
+ <&glink_cdsp>;
+ qcom,xprt = "smem";
+ };
+
+ glink_rpm: qcom,glink-ssr-rpm {
+ compatible = "qcom,glink_ssr";
+ label = "rpm";
+ qcom,edge = "rpm";
+ qcom,notify-edges = <&glink_lpass>, <&glink_mpss>,
+ <&glink_cdsp>;
+ qcom,xprt = "smem";
+ };
+
+ glink_cdsp: qcom,glink-ssr-cdsp {
+ compatible = "qcom,glink_ssr";
+ label = "cdsp";
+ qcom,edge = "cdsp";
+ qcom,notify-edges = <&glink_lpass>, <&glink_mpss>,
+ <&glink_rpm>;
+ qcom,xprt = "smem";
+ };
};
#include "msmfalcon-ion.dtsi"
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index bf6a92504175..d41957eae6ef 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -2284,6 +2284,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
set_dma_ops(dev, dma_ops);
}
+EXPORT_SYMBOL(arch_setup_dma_ops);
void arch_teardown_dma_ops(struct device *dev)
{
diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig
index fc2cce36bff9..f396b0b7f4cc 100644
--- a/arch/arm64/configs/msm-perf_defconfig
+++ b/arch/arm64/configs/msm-perf_defconfig
@@ -408,7 +408,10 @@ CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8996=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_XHCI_HCD=y
diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig
index 38e489936895..c2902be72848 100644
--- a/arch/arm64/configs/msm_defconfig
+++ b/arch/arm64/configs/msm_defconfig
@@ -397,7 +397,10 @@ CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8996=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig
index 72584917f930..be3e4ce1492a 100644
--- a/arch/arm64/configs/msmcortex-perf_defconfig
+++ b/arch/arm64/configs/msmcortex-perf_defconfig
@@ -390,7 +390,10 @@ CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSMCOBALT=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_XHCI_HCD=y
diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
index e708960cf28b..2e9a7908307b 100644
--- a/arch/arm64/configs/msmcortex_defconfig
+++ b/arch/arm64/configs/msmcortex_defconfig
@@ -395,7 +395,10 @@ CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSMCOBALT=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile
index 107af19abff2..ecf0b09bb49a 100644
--- a/drivers/clk/msm/Makefile
+++ b/drivers/clk/msm/Makefile
@@ -13,9 +13,9 @@ obj-$(CONFIG_COMMON_CLK_MSM) += clock-debug.o
# MSM 8996
ifeq ($(CONFIG_COMMON_CLK_MSM), y)
- obj-$(CONFIG_ARCH_QCOM) += clock-gcc-8996.o
- obj-$(CONFIG_ARCH_QCOM) += clock-mmss-8996.o
- obj-$(CONFIG_ARCH_QCOM) += clock-cpu-8996.o
+ obj-$(CONFIG_ARCH_MSM8996) += clock-gcc-8996.o
+ obj-$(CONFIG_ARCH_MSM8996) += clock-mmss-8996.o
+ obj-$(CONFIG_ARCH_MSM8996) += clock-cpu-8996.o
endif
# MSM COBALT
@@ -27,4 +27,4 @@ ifeq ($(CONFIG_COMMON_CLK_MSM), y)
endif
obj-$(CONFIG_COMMON_CLK_MSM) += gdsc.o
-obj-$(CONFIG_COMMON_CLK_MSM)-y += mdss/
+obj-$(CONFIG_COMMON_CLK_MSM) += mdss/
diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c
index 598e52b54c99..9d605503520f 100644
--- a/drivers/clk/msm/clock-osm.c
+++ b/drivers/clk/msm/clock-osm.c
@@ -75,8 +75,7 @@ enum clk_osm_trace_packet_id {
#define MEM_ACC_SEQ_REG_CFG_START(n) (SEQ_REG(12 + (n)))
#define MEM_ACC_SEQ_CONST(n) (n)
#define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40))
-#define MEM_ACC_SEQ_REG_VAL_START(n) \
- ((n) < 8 ? SEQ_REG(4 + (n)) : SEQ_REG(60 + (n) - 8))
+#define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n)))
#define OSM_TABLE_SIZE 40
#define MAX_CLUSTER_CNT 2
@@ -125,6 +124,7 @@ enum clk_osm_trace_packet_id {
#define SPM_CC_CTRL 0x1028
#define SPM_CC_HYSTERESIS 0x101C
#define SPM_CORE_RET_MAPPING 0x1024
+#define CFG_DELAY_VAL_3 0x12C
#define LLM_FREQ_VOTE_HYSTERESIS 0x102C
#define LLM_VOLT_VOTE_HYSTERESIS 0x1030
@@ -184,11 +184,11 @@ enum clk_osm_trace_packet_id {
#define MAX_INSTRUCTIONS 256
#define MAX_BR_INSTRUCTIONS 49
-#define MAX_MEM_ACC_LEVELS 4
+#define MAX_MEM_ACC_LEVELS 3
#define MAX_MEM_ACC_VAL_PER_LEVEL 3
#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \
MAX_MEM_ACC_VAL_PER_LEVEL)
-#define MEM_ACC_READ_MASK 0x7
+#define MEM_ACC_APM_READ_MASK 0xff
#define TRACE_CTRL 0x1F38
#define TRACE_CTRL_EN_MASK BIT(0)
@@ -203,6 +203,11 @@ enum clk_osm_trace_packet_id {
#define PERIODIC_TRACE_MAX_NS 21474836475
#define PERIODIC_TRACE_DEFAULT_NS 1000000
+#define PLL_DD_USER_CTL_LO_ENABLE 0x0f04c408
+#define PLL_DD_USER_CTL_LO_DISABLE 0x1f04c41f
+#define PLL_DD_D0_USER_CTL_LO 0x17916208
+#define PLL_DD_D1_USER_CTL_LO 0x17816208
+
static void __iomem *virt_base;
#define lmh_lite_clk_src_source_val 1
@@ -222,50 +227,48 @@ static void __iomem *virt_base;
static u32 seq_instr[] = {
0xc2005000, 0x2c9e3b21, 0xc0ab2cdc, 0xc2882525, 0x359dc491,
- 0x700a500b, 0x70005001, 0x390938c8, 0xcb44c833, 0xce56cd54,
- 0x341336e0, 0xadba0000, 0x10004000, 0x70005001, 0x1000500c,
- 0xc792c5a1, 0x501625e1, 0x3da335a2, 0x50170006, 0x50150006,
- 0xafb9c633, 0xacb31000, 0xacb41000, 0x1000c422, 0x500baefc,
- 0x5001700a, 0xaefd7000, 0x700b5010, 0x700c5012, 0xadb9ad41,
- 0x181b0000, 0x500f500c, 0x34135011, 0x84b9181b, 0xbd808539,
- 0x2ba40003, 0x0006a001, 0x10007105, 0x1000500e, 0x1c0a500c,
- 0x3b181c01, 0x3b431c06, 0x10001c07, 0x39831c06, 0x500c1c07,
- 0x1c0a1c02, 0x10000000, 0x70015002, 0x10000000, 0x50038103,
- 0x50047002, 0x10007003, 0x39853b44, 0x50038104, 0x40037002,
- 0x70095005, 0xb1c0a146, 0x238b0003, 0x10004005, 0x848b8308,
- 0x1000850c, 0x848e830d, 0x1000850c, 0x3a4c5006, 0x3a8f39cd,
- 0x40063ad0, 0x50071000, 0x2c127006, 0x4007a00f, 0x71050006,
- 0x1000700d, 0x1c1aa964, 0x700d4007, 0x50071000, 0x1c167006,
- 0x50125010, 0x40072411, 0x4007700d, 0xa00f1000, 0x0006a821,
- 0x40077105, 0x500c700d, 0x1c1591ad, 0x5011500f, 0x10000000,
- 0x500c2bd4, 0x0006a00f, 0x10007105, 0xa821a00f, 0x70050006,
- 0x91ad500c, 0x500f1c15, 0x10005011, 0x1c162bce, 0x50125010,
- 0xa82aa022, 0x71050006, 0x1c1591a6, 0x5011500f, 0x5014500c,
- 0x0006a00f, 0x00007105, 0x91a41000, 0x22175013, 0x1c1aa963,
- 0x22171000, 0x1c1aa963, 0x50081000, 0x40087007, 0x1c1aa963,
- 0x70085009, 0x10004009, 0x850c848e, 0x0003b1c0, 0x400d2b99,
- 0x500d1000, 0xabaf1000, 0x853184b0, 0x0003bb80, 0xa0371000,
- 0x71050006, 0x85481000, 0xbf8084c3, 0x2ba80003, 0xbf8084c2,
- 0x2ba70003, 0xbf8084c1, 0x2ba60003, 0x8ec71000, 0xc6dd8dc3,
- 0x8c1625ec, 0x8d498c97, 0x8ec61c00, 0xc6dd8dc2, 0x8c1325ec,
- 0x8d158c94, 0x8ec51c00, 0xc6dd8dc1, 0x8c1025ec, 0x8d128c91,
- 0x8dc01c00, 0x182cc633, 0x84c08548, 0x0003bf80, 0x84c12ba9,
- 0x0003bf80, 0x84c22baa, 0x0003bf80, 0x10002bab, 0x8dc08ec4,
- 0x25ecc6dd, 0x8c948c13, 0x1c008d15, 0x8dc18ec5, 0x25ecc6dd,
- 0x8c978c16, 0x1c008d49, 0x8dc28ec6, 0x25ecc6dd, 0x8ccb8c4a,
- 0x1c008d4c, 0xc6338dc3, 0x1000af9b, 0xa759a79a, 0x1000a718,
+ 0x700a500b, 0x5001aefc, 0xaefd7000, 0x390938c8, 0xcb44c833,
+ 0xce56cd54, 0x341336e0, 0xa4baadba, 0xb480a493, 0x10004000,
+ 0x70005001, 0x1000500c, 0xc792c5a1, 0x501625e1, 0x3da335a2,
+ 0x50170006, 0x50150006, 0x1000c633, 0x1000acb3, 0xc422acb4,
+ 0xaefc1000, 0x700a500b, 0x70005001, 0x5010aefd, 0x5012700b,
+ 0xad41700c, 0x84e5adb9, 0xb3808566, 0x239b0003, 0x856484e3,
+ 0xb9800007, 0x2bad0003, 0xac3aa20b, 0x0003181b, 0x0003bb40,
+ 0xa30d239b, 0x500c181b, 0x5011500f, 0x181b3413, 0x853984b9,
+ 0x0003bd80, 0xa0012ba4, 0x72050803, 0x500e1000, 0x500c1000,
+ 0x1c011c0a, 0x3b181c06, 0x1c073b43, 0x1c061000, 0x1c073983,
+ 0x1c02500c, 0x10001c0a, 0x70015002, 0x81031000, 0x70025003,
+ 0x70035004, 0x3b441000, 0x81553985, 0x70025003, 0x50054003,
+ 0xa1467009, 0x0003b1c0, 0x4005238b, 0x835a1000, 0x855c84db,
+ 0x1000a51f, 0x84de835d, 0xa52c855c, 0x50061000, 0x39cd3a4c,
+ 0x3ad03a8f, 0x10004006, 0x70065007, 0xa00f2c12, 0x08034007,
+ 0xaefc7205, 0xaefd700d, 0xa9641000, 0x40071c1a, 0x700daefc,
+ 0x1000aefd, 0x70065007, 0x50101c16, 0x40075012, 0x700daefc,
+ 0x2411aefd, 0xa8211000, 0x0803a00f, 0x500c7005, 0x1c1591e0,
+ 0x500f5014, 0x10005011, 0x500c2bd4, 0x0803a00f, 0x10007205,
+ 0xa00fa9d1, 0x0803a821, 0xa9d07005, 0x91e0500c, 0x500f1c15,
+ 0x10005011, 0x1c162bce, 0x50125010, 0xa022a82a, 0x70050803,
+ 0x1c1591df, 0x5011500f, 0x5014500c, 0x0803a00f, 0x10007205,
+ 0x501391a4, 0x22172217, 0x70075008, 0xa9634008, 0x1c1a0006,
+ 0x70085009, 0x10004009, 0x00008ed9, 0x3e05c8dd, 0x1c033604,
+ 0xabaf1000, 0x856284e1, 0x0003bb80, 0x1000239f, 0x0803a037,
+ 0x10007205, 0x8dc61000, 0x38a71c2a, 0x1c2a8dc4, 0x100038a6,
+ 0x1c2a8dc5, 0x8dc73867, 0x38681c2a, 0x8c491000, 0x8d4b8cca,
+ 0x10001c00, 0x8ccd8c4c, 0x1c008d4e, 0x8c4f1000, 0x8d518cd0,
+ 0x10001c00, 0xa759a79a, 0x1000a718, 0xbf80af9b, 0x00001000,
};
static u32 seq_br_instr[] = {
- 0x28c, 0x1e6, 0x238, 0xd0, 0xec,
- 0xf4, 0xbc, 0xc4, 0x9c, 0xac,
- 0xfc, 0xe2, 0x154, 0x174, 0x17c,
- 0x10a, 0x126, 0x13a, 0x11c, 0x98,
- 0x160, 0x1a6, 0x19a, 0x1ae, 0x1c0,
- 0x1ce, 0x1d2, 0x30, 0x60, 0x86,
- 0x7c, 0x1d8, 0x34, 0x3c, 0x56,
- 0x5a, 0x1de, 0x2e, 0x222, 0x212,
- 0x202, 0x254, 0x264, 0x274, 0x288,
+ 0x248, 0x20e, 0x21c, 0xf6, 0x112,
+ 0x11c, 0xe4, 0xea, 0xc6, 0xd6,
+ 0x126, 0x108, 0x184, 0x1a8, 0x1b0,
+ 0x134, 0x158, 0x16e, 0x14a, 0xc2,
+ 0x190, 0x1d2, 0x1cc, 0x1d4, 0x1e8,
+ 0x0, 0x1f6, 0x32, 0x66, 0xb0,
+ 0xa6, 0x1fc, 0x3c, 0x44, 0x5c,
+ 0x60, 0x204, 0x30, 0x22a, 0x234,
+ 0x23e, 0x0, 0x250, 0x0, 0x0, 0x9a,
+ 0x20c,
};
DEFINE_EXT_CLK(xo_ao, NULL);
@@ -298,6 +301,7 @@ struct clk_osm {
u32 cluster_num;
u32 irq;
u32 apm_crossover_vc;
+ u32 apm_threshold_vc;
u32 cycle_counter_reads;
u32 cycle_counter_delay;
u32 cycle_counter_factor;
@@ -551,8 +555,8 @@ static void clk_osm_print_osm_table(struct clk_osm *c)
lval,
table[i].spare_data);
}
- pr_debug("APM crossover corner: %d\n",
- c->apm_crossover_vc);
+ pr_debug("APM threshold corner=%d, crossover corner=%d\n",
+ c->apm_threshold_vc, c->apm_crossover_vc);
}
static int clk_osm_get_lut(struct platform_device *pdev,
@@ -1116,10 +1120,21 @@ exit:
static int clk_osm_resolve_crossover_corners(struct clk_osm *c,
struct platform_device *pdev)
{
+ struct regulator *regulator = c->vdd_reg;
struct dev_pm_opp *opp;
unsigned long freq = 0;
- int vc, rc = 0;
+ int vc, i, threshold, rc = 0;
+ u32 corner_volt, data;
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,apm-threshold-voltage",
+ &threshold);
+ if (rc) {
+ pr_info("qcom,apm-threshold-voltage property not specified\n");
+ return rc;
+ }
+
+ /* Determine crossover virtual corner */
rcu_read_lock();
opp = dev_pm_opp_find_freq_exact(&c->vdd_dev->dev, freq, true);
if (IS_ERR(opp)) {
@@ -1138,6 +1153,48 @@ static int clk_osm_resolve_crossover_corners(struct clk_osm *c,
vc--;
c->apm_crossover_vc = vc;
+ /* Determine threshold virtual corner */
+ for (i = 0; i < OSM_TABLE_SIZE; i++) {
+ freq = c->osm_table[i].frequency;
+ /*
+ * Only frequencies that are supported across all configurations
+ * are present in the OPP table associated with the regulator
+ * device.
+ */
+ data = (c->osm_table[i].freq_data & GENMASK(18, 16)) >> 16;
+ if (data != MAX_CONFIG)
+ continue;
+
+ rcu_read_lock();
+ opp = dev_pm_opp_find_freq_exact(&c->vdd_dev->dev, freq, true);
+ if (IS_ERR(opp)) {
+ rc = PTR_ERR(opp);
+ if (rc == -ERANGE)
+ pr_err("Frequency %lu not found\n", freq);
+ goto exit;
+ }
+
+ vc = dev_pm_opp_get_voltage(opp);
+ if (!vc) {
+ pr_err("No virtual corner found for frequency %lu\n",
+ freq);
+ rc = -ERANGE;
+ goto exit;
+ }
+
+ rcu_read_unlock();
+
+ corner_volt = regulator_list_corner_voltage(regulator, vc);
+
+ /* CPR virtual corners are zero-based numbered */
+ vc--;
+
+ if (corner_volt >= threshold) {
+ c->apm_threshold_vc = vc;
+ break;
+ }
+ }
+
return 0;
exit:
rcu_read_unlock();
@@ -1413,55 +1470,77 @@ static void clk_osm_program_apm_regs(struct clk_osm *c)
*/
clk_osm_write_reg(c, c->apm_mode_ctl, SEQ_REG(2));
- /* Program mode value to switch APM from VDD_APCC to VDD_MX */
- clk_osm_write_reg(c, APM_MX_MODE, SEQ_REG(22));
-
- /* Program mode value to switch APM from VDD_MX to VDD_APCC */
- clk_osm_write_reg(c, APM_APC_MODE, SEQ_REG(25));
-
/* Program address of controller status register */
clk_osm_write_reg(c, c->apm_ctrl_status, SEQ_REG(3));
- /* Program mask used to determine status of APM power supply switch */
- clk_osm_write_reg(c, APM_MODE_SWITCH_MASK, SEQ_REG(24));
+ /* Program mode value to switch APM from VDD_APCC to VDD_MX */
+ clk_osm_write_reg(c, APM_MX_MODE, SEQ_REG(77));
/* Program value used to determine current APM power supply is VDD_MX */
- clk_osm_write_reg(c, APM_MX_MODE_VAL, SEQ_REG(23));
+ clk_osm_write_reg(c, APM_MX_MODE_VAL, SEQ_REG(78));
+
+ /* Program mask used to determine status of APM power supply switch */
+ clk_osm_write_reg(c, APM_MODE_SWITCH_MASK, SEQ_REG(79));
+
+ /* Program mode value to switch APM from VDD_MX to VDD_APCC */
+ clk_osm_write_reg(c, APM_APC_MODE, SEQ_REG(80));
/*
* Program value used to determine current APM power supply
* is VDD_APCC
*/
- clk_osm_write_reg(c, APM_APC_MODE_VAL, SEQ_REG(26));
+ clk_osm_write_reg(c, APM_APC_MODE_VAL, SEQ_REG(81));
}
static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
{
- int i;
+ int i, curr_level, j = 0;
+ int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {0, 0, 0};
- if (!c->secure_init)
- return;
+ curr_level = c->osm_table[0].spare_data;
+ for (i = 0; i < c->num_entries; i++) {
+ if (curr_level == MAX_MEM_ACC_LEVELS)
+ break;
- clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(50),
- SEQ_REG(49));
- clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(50));
- clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(51));
- clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(2), SEQ_REG(52));
- clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(3), SEQ_REG(53));
- clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(4), SEQ_REG(54));
- clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(0), SEQ_REG(55));
- clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(1), SEQ_REG(56));
- clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(2), SEQ_REG(57));
- clk_osm_write_reg(c, MEM_ACC_INSTR_COMP(3), SEQ_REG(58));
- clk_osm_write_reg(c, MEM_ACC_READ_MASK, SEQ_REG(59));
-
- for (i = 0; i < MAX_MEM_ACC_VALUES; i++)
- clk_osm_write_reg(c, c->apcs_mem_acc_val[i],
- MEM_ACC_SEQ_REG_VAL_START(i));
-
- for (i = 0; i < MAX_MEM_ACC_VAL_PER_LEVEL; i++)
- clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i],
- MEM_ACC_SEQ_REG_CFG_START(i));
+ if (c->osm_table[i].spare_data != curr_level) {
+ mem_acc_level_map[j++] = i - 1;
+ curr_level = c->osm_table[i].spare_data;
+ }
+ }
+
+ if (c->secure_init) {
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(51));
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(2), SEQ_REG(52));
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(3), SEQ_REG(53));
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(4), SEQ_REG(54));
+ clk_osm_write_reg(c, MEM_ACC_APM_READ_MASK, SEQ_REG(59));
+ clk_osm_write_reg(c, mem_acc_level_map[0], SEQ_REG(55));
+ clk_osm_write_reg(c, mem_acc_level_map[0] + 1, SEQ_REG(56));
+ clk_osm_write_reg(c, mem_acc_level_map[1], SEQ_REG(57));
+ clk_osm_write_reg(c, mem_acc_level_map[1] + 1, SEQ_REG(58));
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(28),
+ SEQ_REG(49));
+
+ for (i = 0; i < MAX_MEM_ACC_VALUES; i++)
+ clk_osm_write_reg(c, c->apcs_mem_acc_val[i],
+ MEM_ACC_SEQ_REG_VAL_START(i));
+
+ for (i = 0; i < MAX_MEM_ACC_VAL_PER_LEVEL; i++)
+ clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i],
+ MEM_ACC_SEQ_REG_CFG_START(i));
+ } else {
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(55),
+ mem_acc_level_map[0]);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(56),
+ mem_acc_level_map[0] + 1);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(57),
+ mem_acc_level_map[1]);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(58),
+ mem_acc_level_map[1] + 1);
+ /* SEQ_REG(49) = SEQ_REG(28) init by TZ */
+ }
+
+ return;
}
void clk_osm_setup_sequencer(struct clk_osm *c)
@@ -1500,10 +1579,12 @@ static void clk_osm_setup_cycle_counters(struct clk_osm *c)
static void clk_osm_setup_osm_was(struct clk_osm *c)
{
+ u32 cc_hyst;
u32 val;
val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
val |= IGNORE_PLL_LOCK_MASK;
+ cc_hyst = clk_osm_read_reg(c, SPM_CC_HYSTERESIS);
if (c->secure_init) {
clk_osm_write_reg(c, val, SEQ_REG(47));
@@ -1518,10 +1599,51 @@ static void clk_osm_setup_osm_was(struct clk_osm *c)
clk_osm_write_reg(c, 0x0, SEQ_REG(45));
clk_osm_write_reg(c, c->pbases[OSM_BASE] + PDN_FSM_CTRL_REG,
SEQ_REG(46));
+
+ /* C2D/C3 + D2D workaround */
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SPM_CC_HYSTERESIS,
+ SEQ_REG(6));
+ clk_osm_write_reg(c, cc_hyst, SEQ_REG(7));
+
+ /* Droop detector PLL lock detect workaround */
+ clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_ENABLE, SEQ_REG(4));
+ clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_DISABLE, SEQ_REG(5));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? PLL_DD_D0_USER_CTL_LO
+ : PLL_DD_D1_USER_CTL_LO, SEQ_REG(21));
+
+ /* PLL lock detect and HMSS AHB clock workaround */
+ clk_osm_write_reg(c, 0x640, CFG_DELAY_VAL_3);
+
+ /* DxFSM workaround */
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911200 :
+ 0x17811200, SEQ_REG(22));
+ clk_osm_write_reg(c, 0x80800, SEQ_REG(23));
+ clk_osm_write_reg(c, 0x179D1100, SEQ_REG(24));
+ clk_osm_write_reg(c, 0x11f, SEQ_REG(25));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17912000 :
+ 0x17811290, SEQ_REG(26));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911290 :
+ 0x17811290, SEQ_REG(20));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17811290 :
+ 0x17911290, SEQ_REG(32));
+ clk_osm_write_reg(c, 0x179D4020, SEQ_REG(35));
+ clk_osm_write_reg(c, 0x11f, SEQ_REG(25));
+ clk_osm_write_reg(c, 0xa, SEQ_REG(86));
+ clk_osm_write_reg(c, 0xe, SEQ_REG(87));
+ clk_osm_write_reg(c, 0x00400000, SEQ_REG(88));
+ clk_osm_write_reg(c, 0x00700000, SEQ_REG(89));
} else {
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(47), val);
val &= ~IGNORE_PLL_LOCK_MASK;
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(48), val);
+
+ /* C2D/C3 + D2D workaround */
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(7),
+ cc_hyst);
+
+ /* Droop detector PLL lock detect workaround */
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(4),
+ PLL_DD_USER_CTL_LO_ENABLE);
}
if (c->cluster_num == 0) {
@@ -1671,18 +1793,15 @@ static void clk_osm_do_additional_setup(struct clk_osm *c,
/* APM Programming */
clk_osm_program_apm_regs(c);
- /* MEM-ACC Programming */
- clk_osm_program_mem_acc_regs(c);
-
/* GFMUX Programming */
clk_osm_write_reg(c, c->apcs_cfg_rcgr, SEQ_REG(16));
- clk_osm_write_reg(c, GPLL_SEL, SEQ_REG(17));
- clk_osm_write_reg(c, PLL_EARLY_SEL, SEQ_REG(20));
- clk_osm_write_reg(c, PLL_MAIN_SEL, SEQ_REG(32));
clk_osm_write_reg(c, c->apcs_cmd_rcgr, SEQ_REG(33));
clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(34));
- clk_osm_write_reg(c, RCG_UPDATE_SUCCESS, SEQ_REG(35));
- clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(36));
+ clk_osm_write_reg(c, GPLL_SEL, SEQ_REG(17));
+ clk_osm_write_reg(c, PLL_EARLY_SEL, SEQ_REG(82));
+ clk_osm_write_reg(c, PLL_MAIN_SEL, SEQ_REG(83));
+ clk_osm_write_reg(c, RCG_UPDATE_SUCCESS, SEQ_REG(84));
+ clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(85));
pr_debug("seq_size: %lu, seqbr_size: %lu\n", ARRAY_SIZE(seq_instr),
ARRAY_SIZE(seq_br_instr));
@@ -1693,17 +1812,43 @@ static void clk_osm_do_additional_setup(struct clk_osm *c,
static void clk_osm_apm_vc_setup(struct clk_osm *c)
{
/*
- * APM crossover virtual corner at which the switch
- * from APC to MX and vice-versa should take place.
+ * APM crossover virtual corner corresponds to switching
+ * voltage during APM transition. APM threshold virtual
+ * corner is the first corner which requires switch
+ * sequence of APM from MX to APC.
*/
if (c->secure_init) {
- clk_osm_write_reg(c, c->apm_crossover_vc, SEQ_REG(1));
+ clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(1));
+ clk_osm_write_reg(c, c->apm_crossover_vc, SEQ_REG(72));
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(1),
+ SEQ_REG(8));
+ clk_osm_write_reg(c, c->apm_threshold_vc,
+ SEQ_REG(15));
+ clk_osm_write_reg(c, c->apm_threshold_vc != 0 ?
+ c->apm_threshold_vc - 1 : 0xff,
+ SEQ_REG(31));
+ clk_osm_write_reg(c, 0x3b | c->apm_threshold_vc << 6,
+ SEQ_REG(73));
+ clk_osm_write_reg(c, 0x39 | c->apm_threshold_vc << 6,
+ SEQ_REG(76));
/* Ensure writes complete before returning */
mb();
} else {
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(1),
+ c->apm_threshold_vc);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(72),
c->apm_crossover_vc);
+ /* SEQ_REG(8) = address of SEQ_REG(1) init by TZ */
+ clk_osm_write_reg(c, c->apm_threshold_vc,
+ SEQ_REG(15));
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(31),
+ c->apm_threshold_vc != 0 ?
+ c->apm_threshold_vc - 1 : 0xff);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(73),
+ 0x3b | c->apm_threshold_vc << 6);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(76),
+ 0x39 | c->apm_threshold_vc << 6);
}
}
@@ -2412,6 +2557,10 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
clk_osm_do_additional_setup(&pwrcl_clk, pdev);
clk_osm_do_additional_setup(&perfcl_clk, pdev);
+ /* MEM-ACC Programming */
+ clk_osm_program_mem_acc_regs(&pwrcl_clk);
+ clk_osm_program_mem_acc_regs(&perfcl_clk);
+
/* Program APM crossover corners */
clk_osm_apm_vc_setup(&pwrcl_clk);
clk_osm_apm_vc_setup(&perfcl_clk);
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 94419695cd2e..dc1b66f84af2 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -12,6 +12,7 @@ clk-qcom-y += clk-regmap-mux.o
clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
clk-qcom-y += clk-hfpll.o
clk-qcom-y += reset.o
+clk-qcom-y += clk-dummy.o
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
diff --git a/drivers/clk/qcom/clk-dummy.c b/drivers/clk/qcom/clk-dummy.c
new file mode 100644
index 000000000000..3205fbc6b8ba
--- /dev/null
+++ b/drivers/clk/qcom/clk-dummy.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016, 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/clk-provider.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+struct clk_dummy {
+ struct clk_hw hw;
+ unsigned long rrate;
+};
+
+#define to_clk_dummy(_hw) container_of(_hw, struct clk_dummy, hw)
+
+static int dummy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_dummy *dummy = to_clk_dummy(hw);
+
+ dummy->rrate = rate;
+
+ pr_debug("set rate: %lu\n", rate);
+
+ return 0;
+}
+
+static long dummy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ return rate;
+}
+
+static unsigned long dummy_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_dummy *dummy = to_clk_dummy(hw);
+
+ pr_debug("clock rate: %lu\n", dummy->rrate);
+
+ return dummy->rrate;
+}
+
+struct clk_ops clk_dummy_ops = {
+ .set_rate = dummy_clk_set_rate,
+ .round_rate = dummy_clk_round_rate,
+ .recalc_rate = dummy_clk_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_dummy_ops);
+
+/**
+ * clk_register_dummy - register dummy clock with the
+ * clock framework
+ * @dev: device that is registering this clock
+ * @name: name of this clock
+ * @flags: framework-specific flags
+ */
+static struct clk *clk_register_dummy(struct device *dev, const char *name,
+ unsigned long flags)
+{
+ struct clk_dummy *dummy;
+ struct clk *clk;
+ struct clk_init_data init = {};
+
+ /* allocate dummy clock */
+ dummy = kzalloc(sizeof(*dummy), GFP_KERNEL);
+ if (!dummy)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_dummy_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.num_parents = 0;
+ dummy->hw.init = &init;
+
+ /* register the clock */
+ clk = clk_register(dev, &dummy->hw);
+ if (IS_ERR(clk))
+ kfree(dummy);
+
+ return clk;
+}
+
+/**
+ * of_dummy_clk_setup() - Setup function for simple fixed rate clock
+ */
+static void of_dummy_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ const char *clk_name = "dummy_clk";
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ clk = clk_register_dummy(NULL, clk_name, 0);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+ pr_info("%s: Dummy clock registered\n", clk_name);
+}
+CLK_OF_DECLARE(dummy_clk, "qcom,dummycc", of_dummy_clk_setup);
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index ae9bdeb21f29..10cabca921be 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2016, 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
@@ -48,5 +48,5 @@ extern int qcom_cc_really_probe(struct platform_device *pdev,
struct regmap *regmap);
extern int qcom_cc_probe(struct platform_device *pdev,
const struct qcom_cc_desc *desc);
-
+extern struct clk_ops clk_dummy_ops;
#endif
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index db5a9ca28408..90aee3cad5ad 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -33,6 +33,8 @@ msm_adreno-y += \
adreno_a3xx_snapshot.o \
adreno_a4xx_snapshot.o \
adreno_a5xx_snapshot.o \
+ adreno_a4xx_preempt.o \
+ adreno_a5xx_preempt.o \
adreno_sysfs.o \
adreno.o \
adreno_cp_parser.o \
diff --git a/drivers/gpu/msm/a5xx_reg.h b/drivers/gpu/msm/a5xx_reg.h
index 913cedb885ad..207588844931 100644
--- a/drivers/gpu/msm/a5xx_reg.h
+++ b/drivers/gpu/msm/a5xx_reg.h
@@ -60,6 +60,8 @@
#define A5XX_CP_RB_BASE 0x800
#define A5XX_CP_RB_BASE_HI 0x801
#define A5XX_CP_RB_CNTL 0x802
+#define A5XX_CP_RB_RPTR_ADDR_LO 0x804
+#define A5XX_CP_RB_RPTR_ADDR_HI 0x805
#define A5XX_CP_RB_RPTR 0x806
#define A5XX_CP_RB_WPTR 0x807
#define A5XX_CP_PFP_STAT_ADDR 0x808
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 26e341a876e8..918231b73215 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -171,6 +171,30 @@ void adreno_writereg64(struct adreno_device *adreno_dev,
}
/**
+ * adreno_get_rptr() - Get the current ringbuffer read pointer
+ * @rb: Pointer the ringbuffer to query
+ *
+ * Get the latest rptr
+ */
+unsigned int adreno_get_rptr(struct adreno_ringbuffer *rb)
+{
+ struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
+ unsigned int rptr = 0;
+
+ if (adreno_is_a3xx(adreno_dev))
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR,
+ &rptr);
+ else {
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ kgsl_sharedmem_readl(&device->scratch, &rptr,
+ SCRATCH_RPTR_OFFSET(rb->id));
+ }
+
+ return rptr;
+}
+
+/**
* adreno_of_read_property() - Adreno read property
* @node: Device node
*
@@ -1290,6 +1314,28 @@ static void _update_threshold_count(struct adreno_device *adreno_dev,
adreno_dev->lm_threshold_cross = adj;
}
+static void _set_secvid(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ /* Program GPU contect protection init values */
+ if (device->mmu.secured) {
+ if (adreno_is_a4xx(adreno_dev))
+ adreno_writereg(adreno_dev,
+ ADRENO_REG_RBBM_SECVID_TRUST_CONFIG, 0x2);
+ adreno_writereg(adreno_dev,
+ ADRENO_REG_RBBM_SECVID_TSB_CONTROL, 0x0);
+
+ adreno_writereg64(adreno_dev,
+ ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
+ ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI,
+ KGSL_IOMMU_SECURE_BASE);
+ adreno_writereg(adreno_dev,
+ ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE,
+ KGSL_IOMMU_SECURE_SIZE);
+ }
+}
+
/**
* _adreno_start - Power up the GPU and prepare to accept commands
* @adreno_dev: Pointer to an adreno_device structure
@@ -1332,26 +1378,13 @@ static int _adreno_start(struct adreno_device *adreno_dev)
if (regulator_left_on)
_soft_reset(adreno_dev);
+ adreno_ringbuffer_set_global(adreno_dev, 0);
+
status = kgsl_mmu_start(device);
if (status)
goto error_pwr_off;
- /* Program GPU contect protection init values */
- if (device->mmu.secured) {
- if (adreno_is_a4xx(adreno_dev))
- adreno_writereg(adreno_dev,
- ADRENO_REG_RBBM_SECVID_TRUST_CONFIG, 0x2);
- adreno_writereg(adreno_dev,
- ADRENO_REG_RBBM_SECVID_TSB_CONTROL, 0x0);
-
- adreno_writereg64(adreno_dev,
- ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
- ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI,
- KGSL_IOMMU_SECURE_BASE);
- adreno_writereg(adreno_dev,
- ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE,
- KGSL_IOMMU_SECURE_SIZE);
- }
+ _set_secvid(device);
status = adreno_ocmem_malloc(adreno_dev);
if (status) {
@@ -1533,6 +1566,22 @@ static int adreno_vbif_clear_pending_transactions(struct kgsl_device *device)
return ret;
}
+static void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev)
+{
+ int i;
+ struct adreno_ringbuffer *rb;
+
+ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
+ if (rb->drawctxt_active)
+ kgsl_context_put(&(rb->drawctxt_active->base));
+ rb->drawctxt_active = NULL;
+
+ kgsl_sharedmem_writel(KGSL_DEVICE(adreno_dev),
+ &rb->pagetable_desc, PT_INFO_OFFSET(current_rb_ptname),
+ 0);
+ }
+}
+
static int adreno_stop(struct kgsl_device *device)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
@@ -1645,13 +1694,6 @@ int adreno_reset(struct kgsl_device *device, int fault)
else
kgsl_pwrctrl_change_state(device, KGSL_STATE_NAP);
- /* Set the page table back to the default page table */
- kgsl_mmu_set_pt(&device->mmu, device->mmu.defaultpagetable);
- kgsl_sharedmem_writel(device,
- &adreno_dev->ringbuffers[0].pagetable_desc,
- offsetof(struct adreno_ringbuffer_pagetable_info,
- current_global_ptname), 0);
-
return ret;
}
@@ -2094,9 +2136,15 @@ static int adreno_soft_reset(struct kgsl_device *device)
/* Reset the GPU */
_soft_reset(adreno_dev);
+ /* Set the page table back to the default page table */
+ adreno_ringbuffer_set_global(adreno_dev, 0);
+ kgsl_mmu_set_pt(&device->mmu, device->mmu.defaultpagetable);
+
/* start of new CFF after reset */
kgsl_cffdump_open(device);
+ _set_secvid(device);
+
/* Enable 64 bit gpu addr if feature is set */
if (gpudev->enable_64bit &&
adreno_support_64bit(adreno_dev))
@@ -2149,8 +2197,6 @@ bool adreno_isidle(struct kgsl_device *device)
if (!kgsl_state_is_awake(device))
return true;
- adreno_get_rptr(ADRENO_CURRENT_RINGBUFFER(adreno_dev));
-
/*
* wptr is updated when we add commands to ringbuffer, add a barrier
* to make sure updated wptr is compared to rptr
@@ -2161,15 +2207,13 @@ bool adreno_isidle(struct kgsl_device *device)
* ringbuffer is truly idle when all ringbuffers read and write
* pointers are equal
*/
+
FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
- if (rb->rptr != rb->wptr)
- break;
+ if (!adreno_rb_empty(rb))
+ return false;
}
- if (i == adreno_dev->num_ringbuffers)
- return adreno_hw_isidle(adreno_dev);
-
- return false;
+ return adreno_hw_isidle(adreno_dev);
}
/**
@@ -2267,25 +2311,11 @@ static int adreno_drain(struct kgsl_device *device)
/* Caller must hold the device mutex. */
static int adreno_suspend_context(struct kgsl_device *device)
{
- int status = 0;
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
-
/* process any profiling results that are available */
- adreno_profile_process_results(adreno_dev);
+ adreno_profile_process_results(ADRENO_DEVICE(device));
- status = adreno_idle(device);
- if (status)
- return status;
- /* set the device to default pagetable */
- kgsl_mmu_set_pt(&device->mmu, device->mmu.defaultpagetable);
- kgsl_sharedmem_writel(device,
- &adreno_dev->ringbuffers[0].pagetable_desc,
- offsetof(struct adreno_ringbuffer_pagetable_info,
- current_global_ptname), 0);
- /* set ringbuffers to NULL ctxt */
- adreno_set_active_ctxs_null(adreno_dev);
-
- return status;
+ /* Wait for the device to go idle */
+ return adreno_idle(device);
}
/**
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 7ac91f203a70..9f462bca26ce 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -193,6 +193,47 @@ enum adreno_gpurev {
struct adreno_gpudev;
+/* Time to allow preemption to complete (in ms) */
+#define ADRENO_PREEMPT_TIMEOUT 10000
+
+/**
+ * enum adreno_preempt_states
+ * ADRENO_PREEMPT_NONE: No preemption is scheduled
+ * ADRENO_PREEMPT_START: The S/W has started
+ * ADRENO_PREEMPT_TRIGGERED: A preeempt has been triggered in the HW
+ * ADRENO_PREEMPT_FAULTED: The preempt timer has fired
+ * ADRENO_PREEMPT_PENDING: The H/W has signaled preemption complete
+ * ADRENO_PREEMPT_COMPLETE: Preemption could not be finished in the IRQ handler,
+ * worker has been scheduled
+ */
+enum adreno_preempt_states {
+ ADRENO_PREEMPT_NONE = 0,
+ ADRENO_PREEMPT_START,
+ ADRENO_PREEMPT_TRIGGERED,
+ ADRENO_PREEMPT_FAULTED,
+ ADRENO_PREEMPT_PENDING,
+ ADRENO_PREEMPT_COMPLETE,
+};
+
+/**
+ * struct adreno_preemption
+ * @state: The current state of preemption
+ * @counters: Memory descriptor for the memory where the GPU writes the
+ * preemption counters on switch
+ * @timer: A timer to make sure preemption doesn't stall
+ * @work: A work struct for the preemption worker (for 5XX)
+ * @token_submit: Indicates if a preempt token has been submitted in
+ * current ringbuffer (for 4XX)
+ */
+struct adreno_preemption {
+ atomic_t state;
+ struct kgsl_memdesc counters;
+ struct timer_list timer;
+ struct work_struct work;
+ bool token_submit;
+};
+
+
struct adreno_busy_data {
unsigned int gpu_busy;
unsigned int vbif_ram_cycles;
@@ -368,7 +409,7 @@ struct adreno_device {
const struct firmware *lm_fw;
uint32_t *lm_sequence;
uint32_t lm_size;
- struct kgsl_memdesc preemption_counters;
+ struct adreno_preemption preempt;
struct work_struct gpmu_work;
uint32_t lm_leakage;
uint32_t lm_limit;
@@ -458,6 +499,8 @@ enum adreno_regs {
ADRENO_REG_CP_WFI_PEND_CTR,
ADRENO_REG_CP_RB_BASE,
ADRENO_REG_CP_RB_BASE_HI,
+ ADRENO_REG_CP_RB_RPTR_ADDR_LO,
+ ADRENO_REG_CP_RB_RPTR_ADDR_HI,
ADRENO_REG_CP_RB_RPTR,
ADRENO_REG_CP_RB_WPTR,
ADRENO_REG_CP_CNTL,
@@ -709,17 +752,12 @@ struct adreno_gpudev {
void (*pwrlevel_change_settings)(struct adreno_device *,
unsigned int prelevel, unsigned int postlevel,
bool post);
- int (*preemption_pre_ibsubmit)(struct adreno_device *,
- struct adreno_ringbuffer *, unsigned int *,
- struct kgsl_context *, uint64_t cond_addr,
- struct kgsl_memobj_node *);
+ unsigned int (*preemption_pre_ibsubmit)(struct adreno_device *,
+ struct adreno_ringbuffer *rb,
+ unsigned int *, struct kgsl_context *);
int (*preemption_yield_enable)(unsigned int *);
- int (*preemption_post_ibsubmit)(struct adreno_device *,
- struct adreno_ringbuffer *, unsigned int *,
- struct kgsl_context *);
- int (*preemption_token)(struct adreno_device *,
- struct adreno_ringbuffer *, unsigned int *,
- uint64_t gpuaddr);
+ unsigned int (*preemption_post_ibsubmit)(struct adreno_device *,
+ unsigned int *);
int (*preemption_init)(struct adreno_device *);
void (*preemption_schedule)(struct adreno_device *);
void (*enable_64bit)(struct adreno_device *);
@@ -1260,34 +1298,32 @@ static inline int adreno_bootstrap_ucode(struct adreno_device *adreno_dev)
}
/**
- * adreno_preempt_state() - Check if preemption state is equal to given state
+ * adreno_in_preempt_state() - Check if preemption state is equal to given state
* @adreno_dev: Device whose preemption state is checked
* @state: State to compare against
*/
-static inline unsigned int adreno_preempt_state(
- struct adreno_device *adreno_dev,
- enum adreno_dispatcher_preempt_states state)
+static inline bool adreno_in_preempt_state(struct adreno_device *adreno_dev,
+ enum adreno_preempt_states state)
{
- return atomic_read(&adreno_dev->dispatcher.preemption_state) ==
- state;
+ return atomic_read(&adreno_dev->preempt.state) == state;
}
-
/**
- * adreno_get_rptr() - Get the current ringbuffer read pointer
- * @rb: Pointer the ringbuffer to query
- *
- * Get the current read pointer from the GPU register.
+ * adreno_set_preempt_state() - Set the specified preemption state
+ * @adreno_dev: Device to change preemption state
+ * @state: State to set
*/
-static inline unsigned int
-adreno_get_rptr(struct adreno_ringbuffer *rb)
+static inline void adreno_set_preempt_state(struct adreno_device *adreno_dev,
+ enum adreno_preempt_states state)
{
- struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
- if (adreno_dev->cur_rb == rb &&
- adreno_preempt_state(adreno_dev,
- ADRENO_DISPATCHER_PREEMPT_CLEAR))
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, &(rb->rptr));
+ /*
+ * atomic_set doesn't use barriers, so we need to do it ourselves. One
+ * before...
+ */
+ smp_wmb();
+ atomic_set(&adreno_dev->preempt.state, state);
- return rb->rptr;
+ /* ... and one after */
+ smp_wmb();
}
static inline bool adreno_is_preemption_enabled(
@@ -1295,7 +1331,6 @@ static inline bool adreno_is_preemption_enabled(
{
return test_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv);
}
-
/**
* adreno_ctx_get_rb() - Return the ringbuffer that a context should
* use based on priority
@@ -1332,25 +1367,6 @@ static inline struct adreno_ringbuffer *adreno_ctx_get_rb(
return &(adreno_dev->ringbuffers[
adreno_dev->num_ringbuffers - 1]);
}
-/*
- * adreno_set_active_ctxs_null() - Put back reference to any active context
- * and set the active context to NULL
- * @adreno_dev: The adreno device
- */
-static inline void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev)
-{
- int i;
- struct adreno_ringbuffer *rb;
- FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
- if (rb->drawctxt_active)
- kgsl_context_put(&(rb->drawctxt_active->base));
- rb->drawctxt_active = NULL;
- kgsl_sharedmem_writel(KGSL_DEVICE(adreno_dev),
- &rb->pagetable_desc,
- offsetof(struct adreno_ringbuffer_pagetable_info,
- current_rb_ptname), 0);
- }
-}
/*
* adreno_compare_prio_level() - Compares 2 priority levels based on enum values
@@ -1371,6 +1387,13 @@ void adreno_readreg64(struct adreno_device *adreno_dev,
void adreno_writereg64(struct adreno_device *adreno_dev,
enum adreno_regs lo, enum adreno_regs hi, uint64_t val);
+unsigned int adreno_get_rptr(struct adreno_ringbuffer *rb);
+
+static inline bool adreno_rb_empty(struct adreno_ringbuffer *rb)
+{
+ return (adreno_get_rptr(rb) == rb->wptr);
+}
+
static inline bool adreno_soft_fault_detect(struct adreno_device *adreno_dev)
{
return adreno_dev->fast_hang_detect &&
@@ -1400,4 +1423,36 @@ static inline bool adreno_support_64bit(struct adreno_device *adreno_dev)
}
#endif /*BITS_PER_LONG*/
+static inline void adreno_ringbuffer_set_global(
+ struct adreno_device *adreno_dev, int name)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ kgsl_sharedmem_writel(device,
+ &adreno_dev->ringbuffers[0].pagetable_desc,
+ PT_INFO_OFFSET(current_global_ptname), name);
+}
+
+static inline void adreno_ringbuffer_set_pagetable(struct adreno_ringbuffer *rb,
+ struct kgsl_pagetable *pt)
+{
+ struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&rb->preempt_lock, flags);
+
+ kgsl_sharedmem_writel(device, &rb->pagetable_desc,
+ PT_INFO_OFFSET(current_rb_ptname), pt->name);
+
+ kgsl_sharedmem_writeq(device, &rb->pagetable_desc,
+ PT_INFO_OFFSET(ttbr0), kgsl_mmu_pagetable_get_ttbr0(pt));
+
+ kgsl_sharedmem_writel(device, &rb->pagetable_desc,
+ PT_INFO_OFFSET(contextidr),
+ kgsl_mmu_pagetable_get_contextidr(pt));
+
+ spin_unlock_irqrestore(&rb->preempt_lock, flags);
+}
+
#endif /*__ADRENO_H */
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index ea8b75f4c83b..2accbe5c5764 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -1756,9 +1756,9 @@ static int _ringbuffer_bootstrap_ucode(struct adreno_device *adreno_dev,
*cmds++ = cp_type3_packet(CP_INTERRUPT, 1);
*cmds++ = 0;
- rb->wptr = rb->wptr - 2;
+ rb->_wptr = rb->_wptr - 2;
adreno_ringbuffer_submit(rb, NULL);
- rb->wptr = rb->wptr + 2;
+ rb->_wptr = rb->_wptr + 2;
} else {
for (i = pfp_idx; i < adreno_dev->pfp_fw_size; i++)
*cmds++ = adreno_dev->pfp_fw[i];
diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c
index b1196da0cee1..b15d23cfbe0a 100644
--- a/drivers/gpu/msm/adreno_a4xx.c
+++ b/drivers/gpu/msm/adreno_a4xx.c
@@ -178,111 +178,6 @@ static const struct adreno_vbif_platform a4xx_vbif_platforms[] = {
{ adreno_is_a418, a430_vbif },
};
-/* a4xx_preemption_start() - Setup state to start preemption */
-static void a4xx_preemption_start(struct adreno_device *adreno_dev,
- struct adreno_ringbuffer *rb)
-{
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- uint32_t val;
-
- /*
- * Setup scratch registers from which the GPU will program the
- * registers required to start execution of new ringbuffer
- * set ringbuffer address
- */
- kgsl_regwrite(device, A4XX_CP_SCRATCH_REG8,
- rb->buffer_desc.gpuaddr);
- kgsl_regread(device, A4XX_CP_RB_CNTL, &val);
- /* scratch REG9 corresponds to CP_RB_CNTL register */
- kgsl_regwrite(device, A4XX_CP_SCRATCH_REG9, val);
- /* scratch REG10 corresponds to rptr address */
- kgsl_regwrite(device, A4XX_CP_SCRATCH_REG10, 0);
- /* scratch REG11 corresponds to rptr */
- kgsl_regwrite(device, A4XX_CP_SCRATCH_REG11, rb->rptr);
- /* scratch REG12 corresponds to wptr */
- kgsl_regwrite(device, A4XX_CP_SCRATCH_REG12, rb->wptr);
- /*
- * scratch REG13 corresponds to IB1_BASE,
- * 0 since we do not do switches in between IB's
- */
- kgsl_regwrite(device, A4XX_CP_SCRATCH_REG13, 0);
- /* scratch REG14 corresponds to IB1_BUFSZ */
- kgsl_regwrite(device, A4XX_CP_SCRATCH_REG14, 0);
- /* scratch REG15 corresponds to IB2_BASE */
- kgsl_regwrite(device, A4XX_CP_SCRATCH_REG15, 0);
- /* scratch REG16 corresponds to IB2_BUFSZ */
- kgsl_regwrite(device, A4XX_CP_SCRATCH_REG16, 0);
- /* scratch REG17 corresponds to GPR11 */
- kgsl_regwrite(device, A4XX_CP_SCRATCH_REG17, rb->gpr11);
-}
-
-/* a4xx_preemption_save() - Save the state after preemption is done */
-static void a4xx_preemption_save(struct adreno_device *adreno_dev,
- struct adreno_ringbuffer *rb)
-{
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
-
- kgsl_regread(device, A4XX_CP_SCRATCH_REG18, &rb->rptr);
- kgsl_regread(device, A4XX_CP_SCRATCH_REG23, &rb->gpr11);
-}
-
-static int a4xx_preemption_token(struct adreno_device *adreno_dev,
- struct adreno_ringbuffer *rb, unsigned int *cmds,
- uint64_t gpuaddr)
-{
- unsigned int *cmds_orig = cmds;
-
- /* Turn on preemption flag */
- /* preemption token - fill when pt switch command size is known */
- *cmds++ = cp_type3_packet(CP_PREEMPT_TOKEN, 3);
- *cmds++ = (uint)gpuaddr;
- *cmds++ = 1;
- /* generate interrupt on preemption completion */
- *cmds++ = 1 << CP_PREEMPT_ORDINAL_INTERRUPT;
-
- return cmds - cmds_orig;
-
-}
-
-static int a4xx_preemption_pre_ibsubmit(
- struct adreno_device *adreno_dev,
- struct adreno_ringbuffer *rb, unsigned int *cmds,
- struct kgsl_context *context, uint64_t cond_addr,
- struct kgsl_memobj_node *ib)
-{
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- unsigned int *cmds_orig = cmds;
- int exec_ib = 0;
-
- cmds += a4xx_preemption_token(adreno_dev, rb, cmds,
- device->memstore.gpuaddr +
- KGSL_MEMSTORE_OFFSET(context->id, preempted));
-
- if (ib)
- exec_ib = 1;
-
- *cmds++ = cp_type3_packet(CP_COND_EXEC, 4);
- *cmds++ = cond_addr;
- *cmds++ = cond_addr;
- *cmds++ = 1;
- *cmds++ = 7 + exec_ib * 3;
- if (exec_ib) {
- *cmds++ = cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2);
- *cmds++ = ib->gpuaddr;
- *cmds++ = (unsigned int) ib->size >> 2;
- }
- /* clear preemption flag */
- *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
- *cmds++ = cond_addr;
- *cmds++ = 0;
- *cmds++ = cp_type3_packet(CP_WAIT_MEM_WRITES, 1);
- *cmds++ = 0;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
- *cmds++ = 0;
-
- return cmds - cmds_orig;
-}
-
/*
* a4xx_is_sptp_idle() - A430 SP/TP should be off to be considered idle
* @adreno_dev: The adreno device pointer
@@ -723,6 +618,8 @@ static void a4xx_start(struct adreno_device *adreno_dev)
gpudev->vbif_xin_halt_ctrl0_mask =
A405_VBIF_XIN_HALT_CTRL0_MASK;
+ adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE);
+
a4xx_protect_init(adreno_dev);
}
@@ -839,6 +736,7 @@ static unsigned int a4xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
ADRENO_REG_DEFINE(ADRENO_REG_CP_WFI_PEND_CTR, A4XX_CP_WFI_PEND_CTR),
ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_BASE, A4XX_CP_RB_BASE),
ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_BASE_HI, ADRENO_REG_SKIP),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR_ADDR_LO, A4XX_CP_RB_RPTR_ADDR),
ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR, A4XX_CP_RB_RPTR),
ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_WPTR, A4XX_CP_RB_WPTR),
ADRENO_REG_DEFINE(ADRENO_REG_CP_CNTL, A4XX_CP_CNTL),
@@ -1634,8 +1532,15 @@ static int a4xx_rb_start(struct adreno_device *adreno_dev,
unsigned int start_type)
{
struct adreno_ringbuffer *rb = ADRENO_CURRENT_RINGBUFFER(adreno_dev);
+ struct kgsl_device *device = &adreno_dev->dev;
+ uint64_t addr;
int ret;
+ addr = SCRATCH_RPTR_GPU_ADDR(device, rb->id);
+
+ adreno_writereg64(adreno_dev, ADRENO_REG_CP_RB_RPTR_ADDR_LO,
+ ADRENO_REG_CP_RB_RPTR_ADDR_HI, addr);
+
/*
* The size of the ringbuffer in the hardware is the log2
* representation of the size in quadwords (sizedwords / 2).
@@ -1644,8 +1549,8 @@ static int a4xx_rb_start(struct adreno_device *adreno_dev,
*/
adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL,
- (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F) |
- (1 << 27));
+ ((ilog2(4) << 8) & 0x1F00) |
+ (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F));
adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE,
rb->buffer_desc.gpuaddr);
@@ -1755,6 +1660,19 @@ static struct adreno_coresight a4xx_coresight = {
.groups = a4xx_coresight_groups,
};
+static void a4xx_preempt_callback(struct adreno_device *adreno_dev, int bit)
+{
+ if (atomic_read(&adreno_dev->preempt.state) != ADRENO_PREEMPT_TRIGGERED)
+ return;
+
+ trace_adreno_hw_preempt_trig_to_comp_int(adreno_dev->cur_rb,
+ adreno_dev->next_rb,
+ adreno_get_rptr(adreno_dev->cur_rb),
+ adreno_get_rptr(adreno_dev->next_rb));
+
+ adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev));
+}
+
#define A4XX_INT_MASK \
((1 << A4XX_INT_RBBM_AHB_ERROR) | \
(1 << A4XX_INT_RBBM_REG_TIMEOUT) | \
@@ -1792,7 +1710,7 @@ static struct adreno_irq_funcs a4xx_irq_funcs[32] = {
/* 6 - RBBM_ATB_ASYNC_OVERFLOW */
ADRENO_IRQ_CALLBACK(a4xx_err_callback),
ADRENO_IRQ_CALLBACK(NULL), /* 7 - RBBM_GPC_ERR */
- ADRENO_IRQ_CALLBACK(adreno_dispatcher_preempt_callback), /* 8 - CP_SW */
+ ADRENO_IRQ_CALLBACK(a4xx_preempt_callback), /* 8 - CP_SW */
ADRENO_IRQ_CALLBACK(a4xx_err_callback), /* 9 - CP_OPCODE_ERROR */
/* 10 - CP_RESERVED_BIT_ERROR */
ADRENO_IRQ_CALLBACK(a4xx_err_callback),
@@ -1833,433 +1751,6 @@ static struct adreno_snapshot_data a4xx_snapshot_data = {
.sect_sizes = &a4xx_snap_sizes,
};
-#define ADRENO_RB_PREEMPT_TOKEN_DWORDS 125
-
-static int a4xx_submit_preempt_token(struct adreno_ringbuffer *rb,
- struct adreno_ringbuffer *incoming_rb)
-{
- struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- unsigned int *ringcmds, *start;
- struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
- int ptname;
- struct kgsl_pagetable *pt;
- int pt_switch_sizedwords = 0, total_sizedwords = 20;
- unsigned link[ADRENO_RB_PREEMPT_TOKEN_DWORDS];
- uint i;
-
- if (incoming_rb->preempted_midway) {
-
- kgsl_sharedmem_readl(&incoming_rb->pagetable_desc,
- &ptname, offsetof(
- struct adreno_ringbuffer_pagetable_info,
- current_rb_ptname));
- pt = kgsl_mmu_get_pt_from_ptname(&(device->mmu),
- ptname);
- /*
- * always expect a valid pt, else pt refcounting is
- * messed up or current pt tracking has a bug which
- * could lead to eventual disaster
- */
- BUG_ON(!pt);
- /* set the ringbuffer for incoming RB */
- pt_switch_sizedwords =
- adreno_iommu_set_pt_generate_cmds(incoming_rb,
- &link[0], pt);
- total_sizedwords += pt_switch_sizedwords;
- }
-
- /*
- * Allocate total_sizedwords space in RB, this is the max space
- * required.
- */
- ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
-
- if (IS_ERR(ringcmds))
- return PTR_ERR(ringcmds);
-
- start = ringcmds;
-
- *ringcmds++ = cp_packet(adreno_dev, CP_SET_PROTECTED_MODE, 1);
- *ringcmds++ = 0;
-
- if (incoming_rb->preempted_midway) {
- for (i = 0; i < pt_switch_sizedwords; i++)
- *ringcmds++ = link[i];
- }
-
- *ringcmds++ = cp_register(adreno_dev, adreno_getreg(adreno_dev,
- ADRENO_REG_CP_PREEMPT_DISABLE), 1);
- *ringcmds++ = 0;
-
- *ringcmds++ = cp_packet(adreno_dev, CP_SET_PROTECTED_MODE, 1);
- *ringcmds++ = 1;
-
- ringcmds += gpudev->preemption_token(adreno_dev, rb, ringcmds,
- device->memstore.gpuaddr +
- KGSL_MEMSTORE_RB_OFFSET(rb, preempted));
-
- if ((uint)(ringcmds - start) > total_sizedwords) {
- KGSL_DRV_ERR(device, "Insufficient rb size allocated\n");
- BUG();
- }
-
- /*
- * If we have commands less than the space reserved in RB
- * adjust the wptr accordingly
- */
- rb->wptr = rb->wptr - (total_sizedwords - (uint)(ringcmds - start));
-
- /* submit just the preempt token */
- mb();
- kgsl_pwrscale_busy(device);
- adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr);
- return 0;
-}
-
-/**
- * a4xx_preempt_trig_state() - Schedule preemption in TRIGGERRED
- * state
- * @adreno_dev: Device which is in TRIGGERRED state
- */
-static void a4xx_preempt_trig_state(
- struct adreno_device *adreno_dev)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- unsigned int rbbase, val;
-
- /*
- * Hardware not yet idle means that preemption interrupt
- * may still occur, nothing to do here until interrupt signals
- * completion of preemption, just return here
- */
- if (!adreno_hw_isidle(adreno_dev))
- return;
-
- /*
- * We just changed states, reschedule dispatcher to change
- * preemption states
- */
- if (ADRENO_DISPATCHER_PREEMPT_TRIGGERED !=
- atomic_read(&dispatcher->preemption_state)) {
- adreno_dispatcher_schedule(device);
- return;
- }
-
- /*
- * H/W is idle and we did not get a preemption interrupt, may
- * be device went idle w/o encountering any preempt token or
- * we already preempted w/o interrupt
- */
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_BASE, &rbbase);
- /* Did preemption occur, if so then change states and return */
- if (rbbase != adreno_dev->cur_rb->buffer_desc.gpuaddr) {
- adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, &val);
- if (val && rbbase == adreno_dev->next_rb->buffer_desc.gpuaddr) {
- KGSL_DRV_INFO(device,
- "Preemption completed without interrupt\n");
- trace_adreno_hw_preempt_trig_to_comp(adreno_dev->cur_rb,
- adreno_dev->next_rb);
- atomic_set(&dispatcher->preemption_state,
- ADRENO_DISPATCHER_PREEMPT_COMPLETE);
- adreno_dispatcher_schedule(device);
- return;
- }
- adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
- /* reschedule dispatcher to take care of the fault */
- adreno_dispatcher_schedule(device);
- return;
- }
- /*
- * Check if preempt token was submitted after preemption trigger, if so
- * then preemption should have occurred, since device is already idle it
- * means something went wrong - trigger FT
- */
- if (dispatcher->preempt_token_submit) {
- adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
- /* reschedule dispatcher to take care of the fault */
- adreno_dispatcher_schedule(device);
- return;
- }
- /*
- * Preempt token was not submitted after preemption trigger so device
- * may have gone idle before preemption could occur, if there are
- * commands that got submitted to current RB after triggering preemption
- * then submit them as those commands may have a preempt token in them
- */
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR,
- &adreno_dev->cur_rb->rptr);
- if (adreno_dev->cur_rb->rptr != adreno_dev->cur_rb->wptr) {
- /*
- * Memory barrier before informing the
- * hardware of new commands
- */
- mb();
- kgsl_pwrscale_busy(device);
- adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR,
- adreno_dev->cur_rb->wptr);
- return;
- }
-
- /* Submit preempt token to make preemption happen */
- if (adreno_drawctxt_switch(adreno_dev, adreno_dev->cur_rb, NULL, 0))
- BUG();
- if (a4xx_submit_preempt_token(adreno_dev->cur_rb,
- adreno_dev->next_rb))
- BUG();
- dispatcher->preempt_token_submit = 1;
- adreno_dev->cur_rb->wptr_preempt_end = adreno_dev->cur_rb->wptr;
- trace_adreno_hw_preempt_token_submit(adreno_dev->cur_rb,
- adreno_dev->next_rb);
-}
-
-/**
- * a4xx_preempt_clear_state() - Schedule preemption in
- * CLEAR state. Preemption can be issued in this state.
- * @adreno_dev: Device which is in CLEAR state
- */
-static void a4xx_preempt_clear_state(
- struct adreno_device *adreno_dev)
-
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct adreno_dispatcher_cmdqueue *dispatch_tempq;
- struct kgsl_cmdbatch *cmdbatch;
- struct adreno_ringbuffer *highest_busy_rb;
- int switch_low_to_high;
- int ret;
-
- /* Device not awake means there is nothing to do */
- if (!kgsl_state_is_awake(device))
- return;
-
- /* keep updating the current rptr when preemption is clear */
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR,
- &(adreno_dev->cur_rb->rptr));
-
- highest_busy_rb = adreno_dispatcher_get_highest_busy_rb(adreno_dev);
- if (!highest_busy_rb)
- return;
-
- switch_low_to_high = adreno_compare_prio_level(
- highest_busy_rb->id,
- adreno_dev->cur_rb->id);
-
- /* already current then return */
- if (!switch_low_to_high)
- return;
-
- if (switch_low_to_high < 0) {
- /*
- * if switching to lower priority make sure that the rptr and
- * wptr are equal, when the lower rb is not starved
- */
- if (adreno_dev->cur_rb->rptr != adreno_dev->cur_rb->wptr)
- return;
- /*
- * switch to default context because when we switch back
- * to higher context then its not known which pt will
- * be current, so by making it default here the next
- * commands submitted will set the right pt
- */
- ret = adreno_drawctxt_switch(adreno_dev,
- adreno_dev->cur_rb,
- NULL, 0);
- /*
- * lower priority RB has to wait until space opens up in
- * higher RB
- */
- if (ret)
- return;
-
- adreno_writereg(adreno_dev,
- ADRENO_REG_CP_PREEMPT_DISABLE, 1);
- }
-
- /*
- * setup registers to do the switch to highest priority RB
- * which is not empty or may be starving away(poor thing)
- */
- a4xx_preemption_start(adreno_dev, highest_busy_rb);
-
- /* turn on IOMMU as the preemption may trigger pt switch */
- kgsl_mmu_enable_clk(&device->mmu);
-
- atomic_set(&dispatcher->preemption_state,
- ADRENO_DISPATCHER_PREEMPT_TRIGGERED);
-
- adreno_dev->next_rb = highest_busy_rb;
- mod_timer(&dispatcher->preempt_timer, jiffies +
- msecs_to_jiffies(ADRENO_DISPATCH_PREEMPT_TIMEOUT));
-
- trace_adreno_hw_preempt_clear_to_trig(adreno_dev->cur_rb,
- adreno_dev->next_rb);
- /* issue PREEMPT trigger */
- adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT, 1);
- /*
- * IOMMU clock can be safely switched off after the timestamp
- * of the first command in the new rb
- */
- dispatch_tempq = &adreno_dev->next_rb->dispatch_q;
- if (dispatch_tempq->head != dispatch_tempq->tail)
- cmdbatch = dispatch_tempq->cmd_q[dispatch_tempq->head];
- else
- cmdbatch = NULL;
- if (cmdbatch)
- adreno_ringbuffer_mmu_disable_clk_on_ts(device,
- adreno_dev->next_rb,
- cmdbatch->global_ts);
- else
- adreno_ringbuffer_mmu_disable_clk_on_ts(device,
- adreno_dev->next_rb, adreno_dev->next_rb->timestamp);
- /* submit preempt token packet to ensure preemption */
- if (switch_low_to_high < 0) {
- ret = a4xx_submit_preempt_token(
- adreno_dev->cur_rb, adreno_dev->next_rb);
- /*
- * unexpected since we are submitting this when rptr = wptr,
- * this was checked above already
- */
- BUG_ON(ret);
- dispatcher->preempt_token_submit = 1;
- adreno_dev->cur_rb->wptr_preempt_end = adreno_dev->cur_rb->wptr;
- } else {
- dispatcher->preempt_token_submit = 0;
- adreno_dispatcher_schedule(device);
- adreno_dev->cur_rb->wptr_preempt_end = 0xFFFFFFFF;
- }
-}
-
-/**
- * a4xx_preempt_complete_state() - Schedule preemption in
- * COMPLETE state
- * @adreno_dev: Device which is in COMPLETE state
- */
-static void a4xx_preempt_complete_state(
- struct adreno_device *adreno_dev)
-
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct adreno_dispatcher_cmdqueue *dispatch_q;
- unsigned int wptr, rbbase;
- unsigned int val, val1;
-
- del_timer_sync(&dispatcher->preempt_timer);
-
- adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &val);
- adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, &val1);
-
- if (val || !val1) {
- KGSL_DRV_ERR(device,
- "Invalid state after preemption CP_PREEMPT: %08x, CP_PREEMPT_DEBUG: %08x\n",
- val, val1);
- adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
- adreno_dispatcher_schedule(device);
- return;
- }
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_BASE, &rbbase);
- if (rbbase != adreno_dev->next_rb->buffer_desc.gpuaddr) {
- KGSL_DRV_ERR(device,
- "RBBASE incorrect after preemption, expected %x got %016llx\b",
- rbbase,
- adreno_dev->next_rb->buffer_desc.gpuaddr);
- adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
- adreno_dispatcher_schedule(device);
- return;
- }
-
- a4xx_preemption_save(adreno_dev, adreno_dev->cur_rb);
-
- dispatch_q = &(adreno_dev->cur_rb->dispatch_q);
- /* new RB is the current RB */
- trace_adreno_hw_preempt_comp_to_clear(adreno_dev->next_rb,
- adreno_dev->cur_rb);
- adreno_dev->prev_rb = adreno_dev->cur_rb;
- adreno_dev->cur_rb = adreno_dev->next_rb;
- adreno_dev->cur_rb->preempted_midway = 0;
- adreno_dev->cur_rb->wptr_preempt_end = 0xFFFFFFFF;
- adreno_dev->next_rb = NULL;
- if (adreno_disp_preempt_fair_sched) {
- /* starved rb is now scheduled so unhalt dispatcher */
- if (ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED ==
- adreno_dev->cur_rb->starve_timer_state)
- adreno_put_gpu_halt(adreno_dev);
- adreno_dev->cur_rb->starve_timer_state =
- ADRENO_DISPATCHER_RB_STARVE_TIMER_SCHEDULED;
- adreno_dev->cur_rb->sched_timer = jiffies;
- /*
- * If the outgoing RB is has commands then set the
- * busy time for it
- */
- if (adreno_dev->prev_rb->rptr != adreno_dev->prev_rb->wptr) {
- adreno_dev->prev_rb->starve_timer_state =
- ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT;
- adreno_dev->prev_rb->sched_timer = jiffies;
- } else {
- adreno_dev->prev_rb->starve_timer_state =
- ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT;
- }
- }
- atomic_set(&dispatcher->preemption_state,
- ADRENO_DISPATCHER_PREEMPT_CLEAR);
- if (adreno_compare_prio_level(adreno_dev->prev_rb->id,
- adreno_dev->cur_rb->id) < 0) {
- if (adreno_dev->prev_rb->wptr_preempt_end !=
- adreno_dev->prev_rb->rptr)
- adreno_dev->prev_rb->preempted_midway = 1;
- } else if (adreno_dev->prev_rb->wptr_preempt_end !=
- adreno_dev->prev_rb->rptr) {
- BUG();
- }
- /* submit wptr if required for new rb */
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_WPTR, &wptr);
- if (adreno_dev->cur_rb->wptr != wptr) {
- kgsl_pwrscale_busy(device);
- adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR,
- adreno_dev->cur_rb->wptr);
- }
- /* clear preemption register */
- adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, 0);
- adreno_preempt_process_dispatch_queue(adreno_dev, dispatch_q);
-}
-
-static void a4xx_preemption_schedule(
- struct adreno_device *adreno_dev)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
-
- if (!adreno_is_preemption_enabled(adreno_dev))
- return;
-
- mutex_lock(&device->mutex);
-
- switch (atomic_read(&dispatcher->preemption_state)) {
- case ADRENO_DISPATCHER_PREEMPT_CLEAR:
- a4xx_preempt_clear_state(adreno_dev);
- break;
- case ADRENO_DISPATCHER_PREEMPT_TRIGGERED:
- a4xx_preempt_trig_state(adreno_dev);
- /*
- * if we transitioned to next state then fall-through
- * processing to next state
- */
- if (!adreno_preempt_state(adreno_dev,
- ADRENO_DISPATCHER_PREEMPT_COMPLETE))
- break;
- case ADRENO_DISPATCHER_PREEMPT_COMPLETE:
- a4xx_preempt_complete_state(adreno_dev);
- break;
- default:
- BUG();
- }
-
- mutex_unlock(&device->mutex);
-}
-
struct adreno_gpudev adreno_a4xx_gpudev = {
.reg_offsets = &a4xx_reg_offsets,
.ft_perf_counters = a4xx_ft_perf_counters,
@@ -2284,6 +1775,6 @@ struct adreno_gpudev adreno_a4xx_gpudev = {
.regulator_enable = a4xx_regulator_enable,
.regulator_disable = a4xx_regulator_disable,
.preemption_pre_ibsubmit = a4xx_preemption_pre_ibsubmit,
- .preemption_token = a4xx_preemption_token,
.preemption_schedule = a4xx_preemption_schedule,
+ .preemption_init = a4xx_preemption_init,
};
diff --git a/drivers/gpu/msm/adreno_a4xx.h b/drivers/gpu/msm/adreno_a4xx.h
index e425dc8e9f7b..5dabc26fd34f 100644
--- a/drivers/gpu/msm/adreno_a4xx.h
+++ b/drivers/gpu/msm/adreno_a4xx.h
@@ -47,6 +47,15 @@
"RBBM_DPM_THERMAL_YELLOW_ERR" }, \
{ BIT(A4XX_INT_RBBM_DPM_THERMAL_RED_ERR), "RBBM_DPM_THERMAL_RED_ERR" }
+unsigned int a4xx_preemption_pre_ibsubmit(struct adreno_device *adreno_dev,
+ struct adreno_ringbuffer *rb,
+ unsigned int *cmds,
+ struct kgsl_context *context);
+
+void a4xx_preemption_schedule(struct adreno_device *adreno_dev);
+
+int a4xx_preemption_init(struct adreno_device *adreno_dev);
+
void a4xx_snapshot(struct adreno_device *adreno_dev,
struct kgsl_snapshot *snapshot);
diff --git a/drivers/gpu/msm/adreno_a4xx_preempt.c b/drivers/gpu/msm/adreno_a4xx_preempt.c
new file mode 100644
index 000000000000..4087ac60c89e
--- /dev/null
+++ b/drivers/gpu/msm/adreno_a4xx_preempt.c
@@ -0,0 +1,571 @@
+/* Copyright (c) 2013-2016, 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 "adreno.h"
+#include "adreno_a4xx.h"
+#include "adreno_trace.h"
+#include "adreno_pm4types.h"
+
+#define ADRENO_RB_PREEMPT_TOKEN_DWORDS 125
+
+static void a4xx_preemption_timer(unsigned long data)
+{
+ struct adreno_device *adreno_dev = (struct adreno_device *) data;
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ unsigned int cur_rptr = adreno_get_rptr(adreno_dev->cur_rb);
+ unsigned int next_rptr = adreno_get_rptr(adreno_dev->next_rb);
+
+ KGSL_DRV_ERR(device,
+ "Preemption timed out. cur_rb rptr/wptr %x/%x id %d, next_rb rptr/wptr %x/%x id %d, disp_state: %d\n",
+ cur_rptr, adreno_dev->cur_rb->wptr, adreno_dev->cur_rb->id,
+ next_rptr, adreno_dev->next_rb->wptr, adreno_dev->next_rb->id,
+ atomic_read(&adreno_dev->preempt.state));
+
+ adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
+ adreno_dispatcher_schedule(device);
+}
+
+static unsigned int a4xx_preemption_token(struct adreno_device *adreno_dev,
+ unsigned int *cmds, uint64_t gpuaddr)
+{
+ unsigned int *cmds_orig = cmds;
+
+ /* Turn on preemption flag */
+ /* preemption token - fill when pt switch command size is known */
+ *cmds++ = cp_type3_packet(CP_PREEMPT_TOKEN, 3);
+ *cmds++ = (uint)gpuaddr;
+ *cmds++ = 1;
+ /* generate interrupt on preemption completion */
+ *cmds++ = 1 << CP_PREEMPT_ORDINAL_INTERRUPT;
+
+ return (unsigned int) (cmds - cmds_orig);
+}
+
+unsigned int a4xx_preemption_pre_ibsubmit(struct adreno_device *adreno_dev,
+ struct adreno_ringbuffer *rb, unsigned int *cmds,
+ struct kgsl_context *context)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ unsigned int *cmds_orig = cmds;
+ unsigned int cond_addr = device->memstore.gpuaddr +
+ MEMSTORE_ID_GPU_ADDR(device, context->id, preempted);
+
+ cmds += a4xx_preemption_token(adreno_dev, cmds, cond_addr);
+
+ *cmds++ = cp_type3_packet(CP_COND_EXEC, 4);
+ *cmds++ = cond_addr;
+ *cmds++ = cond_addr;
+ *cmds++ = 1;
+ *cmds++ = 7;
+
+ /* clear preemption flag */
+ *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
+ *cmds++ = cond_addr;
+ *cmds++ = 0;
+ *cmds++ = cp_type3_packet(CP_WAIT_MEM_WRITES, 1);
+ *cmds++ = 0;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1);
+ *cmds++ = 0;
+
+ return (unsigned int) (cmds - cmds_orig);
+}
+
+
+static void a4xx_preemption_start(struct adreno_device *adreno_dev,
+ struct adreno_ringbuffer *rb)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ uint32_t val;
+
+ /*
+ * Setup scratch registers from which the GPU will program the
+ * registers required to start execution of new ringbuffer
+ * set ringbuffer address
+ */
+ kgsl_regwrite(device, A4XX_CP_SCRATCH_REG8,
+ rb->buffer_desc.gpuaddr);
+ kgsl_regread(device, A4XX_CP_RB_CNTL, &val);
+ /* scratch REG9 corresponds to CP_RB_CNTL register */
+ kgsl_regwrite(device, A4XX_CP_SCRATCH_REG9, val);
+ /* scratch REG10 corresponds to rptr address */
+ kgsl_regwrite(device, A4XX_CP_SCRATCH_REG10,
+ SCRATCH_RPTR_GPU_ADDR(device, rb->id));
+ /* scratch REG11 corresponds to rptr */
+ kgsl_regwrite(device, A4XX_CP_SCRATCH_REG11, adreno_get_rptr(rb));
+ /* scratch REG12 corresponds to wptr */
+ kgsl_regwrite(device, A4XX_CP_SCRATCH_REG12, rb->wptr);
+ /*
+ * scratch REG13 corresponds to IB1_BASE,
+ * 0 since we do not do switches in between IB's
+ */
+ kgsl_regwrite(device, A4XX_CP_SCRATCH_REG13, 0);
+ /* scratch REG14 corresponds to IB1_BUFSZ */
+ kgsl_regwrite(device, A4XX_CP_SCRATCH_REG14, 0);
+ /* scratch REG15 corresponds to IB2_BASE */
+ kgsl_regwrite(device, A4XX_CP_SCRATCH_REG15, 0);
+ /* scratch REG16 corresponds to IB2_BUFSZ */
+ kgsl_regwrite(device, A4XX_CP_SCRATCH_REG16, 0);
+ /* scratch REG17 corresponds to GPR11 */
+ kgsl_regwrite(device, A4XX_CP_SCRATCH_REG17, rb->gpr11);
+}
+
+static void a4xx_preemption_save(struct adreno_device *adreno_dev,
+ struct adreno_ringbuffer *rb)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ kgsl_regread(device, A4XX_CP_SCRATCH_REG23, &rb->gpr11);
+}
+
+
+static int a4xx_submit_preempt_token(struct adreno_ringbuffer *rb,
+ struct adreno_ringbuffer *incoming_rb)
+{
+ struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ unsigned int *ringcmds, *start;
+ int ptname;
+ struct kgsl_pagetable *pt;
+ int pt_switch_sizedwords = 0, total_sizedwords = 20;
+ unsigned link[ADRENO_RB_PREEMPT_TOKEN_DWORDS];
+ uint i;
+
+ if (incoming_rb->preempted_midway) {
+
+ kgsl_sharedmem_readl(&incoming_rb->pagetable_desc,
+ &ptname, PT_INFO_OFFSET(current_rb_ptname));
+ pt = kgsl_mmu_get_pt_from_ptname(&(device->mmu),
+ ptname);
+ /* set the ringbuffer for incoming RB */
+ pt_switch_sizedwords =
+ adreno_iommu_set_pt_generate_cmds(incoming_rb,
+ &link[0], pt);
+ total_sizedwords += pt_switch_sizedwords;
+ }
+
+ /*
+ * Allocate total_sizedwords space in RB, this is the max space
+ * required.
+ */
+ ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords);
+
+ if (IS_ERR(ringcmds))
+ return PTR_ERR(ringcmds);
+
+ start = ringcmds;
+
+ *ringcmds++ = cp_packet(adreno_dev, CP_SET_PROTECTED_MODE, 1);
+ *ringcmds++ = 0;
+
+ if (incoming_rb->preempted_midway) {
+ for (i = 0; i < pt_switch_sizedwords; i++)
+ *ringcmds++ = link[i];
+ }
+
+ *ringcmds++ = cp_register(adreno_dev, adreno_getreg(adreno_dev,
+ ADRENO_REG_CP_PREEMPT_DISABLE), 1);
+ *ringcmds++ = 0;
+
+ *ringcmds++ = cp_packet(adreno_dev, CP_SET_PROTECTED_MODE, 1);
+ *ringcmds++ = 1;
+
+ ringcmds += a4xx_preemption_token(adreno_dev, ringcmds,
+ device->memstore.gpuaddr +
+ MEMSTORE_RB_OFFSET(rb, preempted));
+
+ if ((uint)(ringcmds - start) > total_sizedwords)
+ KGSL_DRV_ERR(device, "Insufficient rb size allocated\n");
+
+ /*
+ * If we have commands less than the space reserved in RB
+ * adjust the wptr accordingly
+ */
+ rb->wptr = rb->wptr - (total_sizedwords - (uint)(ringcmds - start));
+
+ /* submit just the preempt token */
+ mb();
+ kgsl_pwrscale_busy(device);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr);
+ return 0;
+}
+
+static void a4xx_preempt_trig_state(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ unsigned int rbbase, val;
+ int ret;
+
+ /*
+ * Hardware not yet idle means that preemption interrupt
+ * may still occur, nothing to do here until interrupt signals
+ * completion of preemption, just return here
+ */
+ if (!adreno_hw_isidle(adreno_dev))
+ return;
+
+ /*
+ * We just changed states, reschedule dispatcher to change
+ * preemption states
+ */
+
+ if (atomic_read(&adreno_dev->preempt.state) !=
+ ADRENO_PREEMPT_TRIGGERED) {
+ adreno_dispatcher_schedule(device);
+ return;
+ }
+
+ /*
+ * H/W is idle and we did not get a preemption interrupt, may
+ * be device went idle w/o encountering any preempt token or
+ * we already preempted w/o interrupt
+ */
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_BASE, &rbbase);
+ /* Did preemption occur, if so then change states and return */
+ if (rbbase != adreno_dev->cur_rb->buffer_desc.gpuaddr) {
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, &val);
+ if (val && rbbase == adreno_dev->next_rb->buffer_desc.gpuaddr) {
+ KGSL_DRV_INFO(device,
+ "Preemption completed without interrupt\n");
+ trace_adreno_hw_preempt_trig_to_comp(adreno_dev->cur_rb,
+ adreno_dev->next_rb,
+ adreno_get_rptr(adreno_dev->cur_rb),
+ adreno_get_rptr(adreno_dev->next_rb));
+ adreno_set_preempt_state(adreno_dev,
+ ADRENO_PREEMPT_COMPLETE);
+ adreno_dispatcher_schedule(device);
+ return;
+ }
+ adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
+ /* reschedule dispatcher to take care of the fault */
+ adreno_dispatcher_schedule(device);
+ return;
+ }
+ /*
+ * Check if preempt token was submitted after preemption trigger, if so
+ * then preemption should have occurred, since device is already idle it
+ * means something went wrong - trigger FT
+ */
+ if (adreno_dev->preempt.token_submit) {
+ adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
+ /* reschedule dispatcher to take care of the fault */
+ adreno_dispatcher_schedule(device);
+ return;
+ }
+ /*
+ * Preempt token was not submitted after preemption trigger so device
+ * may have gone idle before preemption could occur, if there are
+ * commands that got submitted to current RB after triggering preemption
+ * then submit them as those commands may have a preempt token in them
+ */
+ if (!adreno_rb_empty(adreno_dev->cur_rb)) {
+ /*
+ * Memory barrier before informing the
+ * hardware of new commands
+ */
+ mb();
+ kgsl_pwrscale_busy(device);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR,
+ adreno_dev->cur_rb->wptr);
+ return;
+ }
+
+ /* Submit preempt token to make preemption happen */
+ ret = adreno_drawctxt_switch(adreno_dev, adreno_dev->cur_rb,
+ NULL, 0);
+ if (ret)
+ KGSL_DRV_ERR(device,
+ "Unable to switch context to NULL: %d\n", ret);
+
+ ret = a4xx_submit_preempt_token(adreno_dev->cur_rb,
+ adreno_dev->next_rb);
+ if (ret)
+ KGSL_DRV_ERR(device,
+ "Unable to submit preempt token: %d\n", ret);
+
+ adreno_dev->preempt.token_submit = true;
+ adreno_dev->cur_rb->wptr_preempt_end = adreno_dev->cur_rb->wptr;
+ trace_adreno_hw_preempt_token_submit(adreno_dev->cur_rb,
+ adreno_dev->next_rb,
+ adreno_get_rptr(adreno_dev->cur_rb),
+ adreno_get_rptr(adreno_dev->next_rb));
+}
+
+static struct adreno_ringbuffer *a4xx_next_ringbuffer(
+ struct adreno_device *adreno_dev)
+{
+ struct adreno_ringbuffer *rb, *next = NULL;
+ int i;
+
+ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
+ if (!adreno_rb_empty(rb) && next == NULL) {
+ next = rb;
+ continue;
+ }
+
+ if (!adreno_disp_preempt_fair_sched)
+ continue;
+
+ switch (rb->starve_timer_state) {
+ case ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT:
+ if (!adreno_rb_empty(rb) &&
+ adreno_dev->cur_rb != rb) {
+ rb->starve_timer_state =
+ ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT;
+ rb->sched_timer = jiffies;
+ }
+ break;
+ case ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT:
+ if (time_after(jiffies, rb->sched_timer +
+ msecs_to_jiffies(
+ adreno_dispatch_starvation_time))) {
+ rb->starve_timer_state =
+ ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED;
+ /* halt dispatcher to remove starvation */
+ adreno_get_gpu_halt(adreno_dev);
+ }
+ break;
+ case ADRENO_DISPATCHER_RB_STARVE_TIMER_SCHEDULED:
+ /*
+ * If the RB has not been running for the minimum
+ * time slice then allow it to run
+ */
+ if (!adreno_rb_empty(rb) && time_before(jiffies,
+ adreno_dev->cur_rb->sched_timer +
+ msecs_to_jiffies(adreno_dispatch_time_slice)))
+ next = rb;
+ else
+ rb->starve_timer_state =
+ ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT;
+ break;
+ case ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED:
+ default:
+ break;
+ }
+ }
+
+ return next;
+}
+
+static void a4xx_preempt_clear_state(struct adreno_device *adreno_dev)
+
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct adreno_ringbuffer *highest_busy_rb;
+ int switch_low_to_high;
+ int ret;
+
+ /* Device not awake means there is nothing to do */
+ if (!kgsl_state_is_awake(device))
+ return;
+
+ highest_busy_rb = a4xx_next_ringbuffer(adreno_dev);
+ if (!highest_busy_rb || highest_busy_rb == adreno_dev->cur_rb)
+ return;
+
+ switch_low_to_high = adreno_compare_prio_level(
+ highest_busy_rb->id,
+ adreno_dev->cur_rb->id);
+
+ if (switch_low_to_high < 0) {
+ /*
+ * if switching to lower priority make sure that the rptr and
+ * wptr are equal, when the lower rb is not starved
+ */
+ if (!adreno_rb_empty(adreno_dev->cur_rb))
+ return;
+ /*
+ * switch to default context because when we switch back
+ * to higher context then its not known which pt will
+ * be current, so by making it default here the next
+ * commands submitted will set the right pt
+ */
+ ret = adreno_drawctxt_switch(adreno_dev,
+ adreno_dev->cur_rb,
+ NULL, 0);
+ /*
+ * lower priority RB has to wait until space opens up in
+ * higher RB
+ */
+ if (ret) {
+ KGSL_DRV_ERR(device,
+ "Unable to switch context to NULL: %d",
+ ret);
+
+ return;
+ }
+
+ adreno_writereg(adreno_dev,
+ ADRENO_REG_CP_PREEMPT_DISABLE, 1);
+ }
+
+ /*
+ * setup registers to do the switch to highest priority RB
+ * which is not empty or may be starving away(poor thing)
+ */
+ a4xx_preemption_start(adreno_dev, highest_busy_rb);
+
+ adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_TRIGGERED);
+
+ adreno_dev->next_rb = highest_busy_rb;
+ mod_timer(&adreno_dev->preempt.timer, jiffies +
+ msecs_to_jiffies(ADRENO_PREEMPT_TIMEOUT));
+
+ trace_adreno_hw_preempt_clear_to_trig(adreno_dev->cur_rb,
+ adreno_dev->next_rb,
+ adreno_get_rptr(adreno_dev->cur_rb),
+ adreno_get_rptr(adreno_dev->next_rb));
+ /* issue PREEMPT trigger */
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT, 1);
+
+ /* submit preempt token packet to ensure preemption */
+ if (switch_low_to_high < 0) {
+ ret = a4xx_submit_preempt_token(
+ adreno_dev->cur_rb, adreno_dev->next_rb);
+ KGSL_DRV_ERR(device,
+ "Unable to submit preempt token: %d\n", ret);
+ adreno_dev->preempt.token_submit = true;
+ adreno_dev->cur_rb->wptr_preempt_end = adreno_dev->cur_rb->wptr;
+ } else {
+ adreno_dev->preempt.token_submit = false;
+ adreno_dispatcher_schedule(device);
+ adreno_dev->cur_rb->wptr_preempt_end = 0xFFFFFFFF;
+ }
+}
+
+static void a4xx_preempt_complete_state(struct adreno_device *adreno_dev)
+
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ unsigned int wptr, rbbase;
+ unsigned int val, val1;
+ unsigned int prevrptr;
+
+ del_timer_sync(&adreno_dev->preempt.timer);
+
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &val);
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, &val1);
+
+ if (val || !val1) {
+ KGSL_DRV_ERR(device,
+ "Invalid state after preemption CP_PREEMPT: %08x, CP_PREEMPT_DEBUG: %08x\n",
+ val, val1);
+ adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
+ adreno_dispatcher_schedule(device);
+ return;
+ }
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_BASE, &rbbase);
+ if (rbbase != adreno_dev->next_rb->buffer_desc.gpuaddr) {
+ KGSL_DRV_ERR(device,
+ "RBBASE incorrect after preemption, expected %x got %016llx\b",
+ rbbase,
+ adreno_dev->next_rb->buffer_desc.gpuaddr);
+ adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
+ adreno_dispatcher_schedule(device);
+ return;
+ }
+
+ a4xx_preemption_save(adreno_dev, adreno_dev->cur_rb);
+
+ /* new RB is the current RB */
+ trace_adreno_hw_preempt_comp_to_clear(adreno_dev->next_rb,
+ adreno_dev->cur_rb,
+ adreno_get_rptr(adreno_dev->next_rb),
+ adreno_get_rptr(adreno_dev->cur_rb));
+
+ adreno_dev->prev_rb = adreno_dev->cur_rb;
+ adreno_dev->cur_rb = adreno_dev->next_rb;
+ adreno_dev->cur_rb->preempted_midway = 0;
+ adreno_dev->cur_rb->wptr_preempt_end = 0xFFFFFFFF;
+ adreno_dev->next_rb = NULL;
+
+ if (adreno_disp_preempt_fair_sched) {
+ /* starved rb is now scheduled so unhalt dispatcher */
+ if (ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED ==
+ adreno_dev->cur_rb->starve_timer_state)
+ adreno_put_gpu_halt(adreno_dev);
+ adreno_dev->cur_rb->starve_timer_state =
+ ADRENO_DISPATCHER_RB_STARVE_TIMER_SCHEDULED;
+ adreno_dev->cur_rb->sched_timer = jiffies;
+ /*
+ * If the outgoing RB is has commands then set the
+ * busy time for it
+ */
+ if (!adreno_rb_empty(adreno_dev->prev_rb)) {
+ adreno_dev->prev_rb->starve_timer_state =
+ ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT;
+ adreno_dev->prev_rb->sched_timer = jiffies;
+ } else {
+ adreno_dev->prev_rb->starve_timer_state =
+ ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT;
+ }
+ }
+ adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE);
+
+ prevrptr = adreno_get_rptr(adreno_dev->prev_rb);
+
+ if (adreno_compare_prio_level(adreno_dev->prev_rb->id,
+ adreno_dev->cur_rb->id) < 0) {
+ if (adreno_dev->prev_rb->wptr_preempt_end != prevrptr)
+ adreno_dev->prev_rb->preempted_midway = 1;
+ }
+
+ /* submit wptr if required for new rb */
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_WPTR, &wptr);
+ if (adreno_dev->cur_rb->wptr != wptr) {
+ kgsl_pwrscale_busy(device);
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR,
+ adreno_dev->cur_rb->wptr);
+ }
+ /* clear preemption register */
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, 0);
+}
+
+void a4xx_preemption_schedule(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ if (!adreno_is_preemption_enabled(adreno_dev))
+ return;
+
+ mutex_lock(&device->mutex);
+
+ switch (atomic_read(&adreno_dev->preempt.state)) {
+ case ADRENO_PREEMPT_NONE:
+ a4xx_preempt_clear_state(adreno_dev);
+ break;
+ case ADRENO_PREEMPT_TRIGGERED:
+ a4xx_preempt_trig_state(adreno_dev);
+ /*
+ * if we transitioned to next state then fall-through
+ * processing to next state
+ */
+ if (!adreno_in_preempt_state(adreno_dev,
+ ADRENO_PREEMPT_COMPLETE))
+ break;
+ case ADRENO_PREEMPT_COMPLETE:
+ a4xx_preempt_complete_state(adreno_dev);
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&device->mutex);
+}
+
+int a4xx_preemption_init(struct adreno_device *adreno_dev)
+{
+ setup_timer(&adreno_dev->preempt.timer, a4xx_preemption_timer,
+ (unsigned long) adreno_dev);
+
+ return 0;
+}
diff --git a/drivers/gpu/msm/adreno_a4xx_snapshot.c b/drivers/gpu/msm/adreno_a4xx_snapshot.c
index b07e970aae32..6921af5c0ab5 100644
--- a/drivers/gpu/msm/adreno_a4xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a4xx_snapshot.c
@@ -534,9 +534,6 @@ void a4xx_snapshot(struct adreno_device *adreno_dev,
kgsl_regwrite(device, A4XX_RBBM_CLOCK_CTL, 0);
kgsl_regwrite(device, A4XX_RBBM_CLOCK_CTL2, 0);
- /* Turn on MMU clocks since we read MMU registers */
- kgsl_mmu_enable_clk(&device->mmu);
-
/* Master set of (non debug) registers */
SNAPSHOT_REGISTERS(device, snapshot, a4xx_registers);
@@ -554,8 +551,6 @@ void a4xx_snapshot(struct adreno_device *adreno_dev,
a4xx_vbif_snapshot_registers,
ARRAY_SIZE(a4xx_vbif_snapshot_registers));
- kgsl_mmu_disable_clk(&device->mmu);
-
kgsl_snapshot_indexed_registers(device, snapshot,
A4XX_CP_STATE_DEBUG_INDEX, A4XX_CP_STATE_DEBUG_DATA,
0, snap_data->sect_sizes->cp_pfp);
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 512dcd483f45..96f72c59e4cd 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -60,19 +60,12 @@ static const struct adreno_vbif_platform a5xx_vbif_platforms[] = {
{ adreno_is_a506, a530_vbif },
};
-#define PREEMPT_RECORD(_field) \
- offsetof(struct a5xx_cp_preemption_record, _field)
-
-#define PREEMPT_SMMU_RECORD(_field) \
- offsetof(struct a5xx_cp_smmu_info, _field)
-
static void a5xx_irq_storm_worker(struct work_struct *work);
static int _read_fw2_block_header(uint32_t *header, uint32_t id,
uint32_t major, uint32_t minor);
static void a5xx_gpmu_reset(struct work_struct *work);
static int a5xx_gpmu_init(struct adreno_device *adreno_dev);
-
/**
* Number of times to check if the regulator enabled before
* giving up and returning failure.
@@ -108,8 +101,9 @@ static void spin_idle_debug(struct kgsl_device *device,
kgsl_regread(device, A5XX_CP_HW_FAULT, &hwfault);
dev_err(device->dev,
- " rb=%X/%X rbbm_status=%8.8X/%8.8X int_0_status=%8.8X\n",
- rptr, wptr, status, status3, intstatus);
+ "rb=%d pos=%X/%X rbbm_status=%8.8X/%8.8X int_0_status=%8.8X\n",
+ adreno_dev->cur_rb->id, rptr, wptr, status, status3, intstatus);
+
dev_err(device->dev, " hwfault=%8.8X\n", hwfault);
kgsl_device_snapshot(device, NULL);
@@ -179,277 +173,6 @@ static void a5xx_check_features(struct adreno_device *adreno_dev)
adreno_efuse_unmap(adreno_dev);
}
-/*
- * a5xx_preemption_start() - Setup state to start preemption
- */
-static void a5xx_preemption_start(struct adreno_device *adreno_dev,
- struct adreno_ringbuffer *rb)
-{
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
- uint64_t ttbr0;
- uint32_t contextidr;
- struct kgsl_pagetable *pt;
- bool switch_default_pt = true;
-
- kgsl_sharedmem_writel(device, &rb->preemption_desc,
- PREEMPT_RECORD(wptr), rb->wptr);
- kgsl_regwrite(device, A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_LO,
- lower_32_bits(rb->preemption_desc.gpuaddr));
- kgsl_regwrite(device, A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_HI,
- upper_32_bits(rb->preemption_desc.gpuaddr));
- kgsl_sharedmem_readq(&rb->pagetable_desc, &ttbr0,
- offsetof(struct adreno_ringbuffer_pagetable_info, ttbr0));
- kgsl_sharedmem_readl(&rb->pagetable_desc, &contextidr,
- offsetof(struct adreno_ringbuffer_pagetable_info, contextidr));
-
- spin_lock(&kgsl_driver.ptlock);
- list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) {
- if (kgsl_mmu_pagetable_get_ttbr0(pt) == ttbr0) {
- switch_default_pt = false;
- break;
- }
- }
- spin_unlock(&kgsl_driver.ptlock);
-
- if (switch_default_pt) {
- ttbr0 = kgsl_mmu_pagetable_get_ttbr0(
- device->mmu.defaultpagetable);
- contextidr = kgsl_mmu_pagetable_get_contextidr(
- device->mmu.defaultpagetable);
- }
-
- kgsl_sharedmem_writeq(device, &iommu->smmu_info,
- offsetof(struct a5xx_cp_smmu_info, ttbr0), ttbr0);
- kgsl_sharedmem_writel(device, &iommu->smmu_info,
- offsetof(struct a5xx_cp_smmu_info, context_idr), contextidr);
-}
-
-/*
- * a5xx_preemption_save() - Save the state after preemption is done
- */
-static void a5xx_preemption_save(struct adreno_device *adreno_dev,
- struct adreno_ringbuffer *rb)
-{
- /* save the rptr from ctxrecord here */
- kgsl_sharedmem_readl(&rb->preemption_desc, &rb->rptr,
- PREEMPT_RECORD(rptr));
-}
-
-#ifdef CONFIG_QCOM_KGSL_IOMMU
-static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev)
-{
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
-
- /* Allocate mem for storing preemption smmu record */
- return kgsl_allocate_global(device, &iommu->smmu_info, PAGE_SIZE,
- KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED);
-}
-#else
-static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev)
-{
- return -ENODEV;
-}
-#endif
-
-static int a5xx_preemption_init(struct adreno_device *adreno_dev)
-{
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct adreno_ringbuffer *rb;
- int ret;
- unsigned int i;
- uint64_t addr;
-
- /* We are dependent on IOMMU to make preemption go on the CP side */
- if (kgsl_mmu_get_mmutype(device) != KGSL_MMU_TYPE_IOMMU)
- return -ENODEV;
-
- /* Allocate mem for storing preemption counters */
- ret = kgsl_allocate_global(device, &adreno_dev->preemption_counters,
- adreno_dev->num_ringbuffers *
- A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0);
- if (ret)
- return ret;
-
- addr = adreno_dev->preemption_counters.gpuaddr;
-
- /* Allocate mem for storing preemption switch record */
- FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
- ret = kgsl_allocate_global(device,
- &rb->preemption_desc, A5XX_CP_CTXRECORD_SIZE_IN_BYTES,
- 0, KGSL_MEMDESC_PRIVILEGED);
- if (ret)
- return ret;
-
- /* Initialize the context switch record here */
- kgsl_sharedmem_writel(device, &rb->preemption_desc,
- PREEMPT_RECORD(magic), A5XX_CP_CTXRECORD_MAGIC_REF);
- kgsl_sharedmem_writel(device, &rb->preemption_desc,
- PREEMPT_RECORD(info), 0);
- kgsl_sharedmem_writel(device, &rb->preemption_desc,
- PREEMPT_RECORD(data), 0);
- kgsl_sharedmem_writel(device, &rb->preemption_desc,
- PREEMPT_RECORD(cntl), 0x0800000C);
- kgsl_sharedmem_writel(device, &rb->preemption_desc,
- PREEMPT_RECORD(rptr), 0);
- kgsl_sharedmem_writel(device, &rb->preemption_desc,
- PREEMPT_RECORD(wptr), 0);
- kgsl_sharedmem_writeq(device, &rb->preemption_desc,
- PREEMPT_RECORD(rbase),
- adreno_dev->ringbuffers[i].buffer_desc.gpuaddr);
- kgsl_sharedmem_writeq(device, &rb->preemption_desc,
- PREEMPT_RECORD(counter), addr);
-
- addr += A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE;
- }
-
- return a5xx_preemption_iommu_init(adreno_dev);
-}
-
-/*
- * a5xx_preemption_token() - Preempt token on a5xx
- * PM4 commands for preempt token on a5xx. These commands are
- * submitted to ringbuffer to trigger preemption.
- */
-static int a5xx_preemption_token(struct adreno_device *adreno_dev,
- struct adreno_ringbuffer *rb, unsigned int *cmds,
- uint64_t gpuaddr)
-{
- unsigned int *cmds_orig = cmds;
-
- *cmds++ = cp_type7_packet(CP_CONTEXT_SWITCH_YIELD, 4);
- cmds += cp_gpuaddr(adreno_dev, cmds, gpuaddr);
- *cmds++ = 1;
- /* generate interrupt on preemption completion */
- *cmds++ = 1;
-
- return cmds - cmds_orig;
-
-}
-
-/*
- * a5xx_preemption_pre_ibsubmit() - Below PM4 commands are
- * added at the beginning of every cmdbatch submission.
- */
-static int a5xx_preemption_pre_ibsubmit(
- struct adreno_device *adreno_dev,
- struct adreno_ringbuffer *rb, unsigned int *cmds,
- struct kgsl_context *context, uint64_t cond_addr,
- struct kgsl_memobj_node *ib)
-{
- unsigned int *cmds_orig = cmds;
- uint64_t gpuaddr = rb->preemption_desc.gpuaddr;
- unsigned int preempt_style = 0;
-
- if (context) {
- /*
- * Preemption from secure to unsecure needs Zap shader to be
- * run to clear all secure content. CP does not know during
- * preemption if it is switching between secure and unsecure
- * contexts so restrict Secure contexts to be preempted at
- * ringbuffer level.
- */
- if (context->flags & KGSL_CONTEXT_SECURE)
- preempt_style = KGSL_CONTEXT_PREEMPT_STYLE_RINGBUFFER;
- else
- preempt_style = ADRENO_PREEMPT_STYLE(context->flags);
- }
-
- /*
- * CP_PREEMPT_ENABLE_GLOBAL(global preemption) can only be set by KMD
- * in ringbuffer.
- * 1) set global preemption to 0x0 to disable global preemption.
- * Only RB level preemption is allowed in this mode
- * 2) Set global preemption to defer(0x2) for finegrain preemption.
- * when global preemption is set to defer(0x2),
- * CP_PREEMPT_ENABLE_LOCAL(local preemption) determines the
- * preemption point. Local preemption
- * can be enabled by both UMD(within IB) and KMD.
- */
- *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_GLOBAL, 1);
- *cmds++ = ((preempt_style == KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN)
- ? 2 : 0);
-
- /* Turn CP protection OFF */
- *cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1);
- *cmds++ = 0;
-
- /*
- * CP during context switch will save context switch info to
- * a5xx_cp_preemption_record pointed by CONTEXT_SWITCH_SAVE_ADDR
- */
- *cmds++ = cp_type4_packet(A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 1);
- *cmds++ = lower_32_bits(gpuaddr);
- *cmds++ = cp_type4_packet(A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_HI, 1);
- *cmds++ = upper_32_bits(gpuaddr);
-
- /* Turn CP protection ON */
- *cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1);
- *cmds++ = 1;
-
- /*
- * Enable local preemption for finegrain preemption in case of
- * a misbehaving IB
- */
- if (preempt_style == KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN) {
- *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_LOCAL, 1);
- *cmds++ = 1;
- } else {
- *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_LOCAL, 1);
- *cmds++ = 0;
- }
-
- /* Enable CP_CONTEXT_SWITCH_YIELD packets in the IB2s */
- *cmds++ = cp_type7_packet(CP_YIELD_ENABLE, 1);
- *cmds++ = 2;
-
- return cmds - cmds_orig;
-}
-
-/*
- * a5xx_preemption_yield_enable() - Below PM4 commands are
- * added after every cmdbatch submission.
- */
-static int a5xx_preemption_yield_enable(unsigned int *cmds)
-{
- /*
- * SRM -- set render mode (ex binning, direct render etc)
- * SRM is set by UMD usually at start of IB to tell CP the type of
- * preemption.
- * KMD needs to set SRM to NULL to indicate CP that rendering is
- * done by IB.
- */
- *cmds++ = cp_type7_packet(CP_SET_RENDER_MODE, 5);
- *cmds++ = 0;
- *cmds++ = 0;
- *cmds++ = 0;
- *cmds++ = 0;
- *cmds++ = 0;
-
- *cmds++ = cp_type7_packet(CP_YIELD_ENABLE, 1);
- *cmds++ = 1;
-
- return 8;
-}
-
-/*
- * a5xx_preemption_post_ibsubmit() - Below PM4 commands are
- * added after every cmdbatch submission.
- */
-static int a5xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev,
- struct adreno_ringbuffer *rb, unsigned int *cmds,
- struct kgsl_context *context)
-{
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- unsigned int ctx_id = context ? context->id : 0;
-
- return a5xx_preemption_token(adreno_dev, rb, cmds,
- device->memstore.gpuaddr +
- KGSL_MEMSTORE_OFFSET(ctx_id, preempted));
-
-}
-
static void a5xx_platform_setup(struct adreno_device *adreno_dev)
{
uint64_t addr;
@@ -1972,12 +1695,8 @@ out:
static void a5xx_start(struct adreno_device *adreno_dev)
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
- unsigned int i, bit;
- struct adreno_ringbuffer *rb;
- uint64_t def_ttbr0;
- uint32_t contextidr;
+ unsigned int bit;
adreno_vbif_start(adreno_dev, a5xx_vbif_platforms,
ARRAY_SIZE(a5xx_vbif_platforms));
@@ -2178,58 +1897,21 @@ static void a5xx_start(struct adreno_device *adreno_dev)
}
- if (adreno_is_preemption_enabled(adreno_dev)) {
- struct kgsl_pagetable *pt = device->mmu.defaultpagetable;
-
- def_ttbr0 = kgsl_mmu_pagetable_get_ttbr0(pt);
- contextidr = kgsl_mmu_pagetable_get_contextidr(pt);
-
- /* Initialize the context switch record here */
- kgsl_sharedmem_writel(device, &iommu->smmu_info,
- PREEMPT_SMMU_RECORD(magic),
- A5XX_CP_SMMU_INFO_MAGIC_REF);
- kgsl_sharedmem_writeq(device, &iommu->smmu_info,
- PREEMPT_SMMU_RECORD(ttbr0), def_ttbr0);
- /*
- * The CP doesn't actually use the asid field, so
- * put a bad value into it until it is removed from
- * the preemption record.
- */
- kgsl_sharedmem_writeq(device, &iommu->smmu_info,
- PREEMPT_SMMU_RECORD(asid),
- 0xdecafbad);
- kgsl_sharedmem_writeq(device, &iommu->smmu_info,
- PREEMPT_SMMU_RECORD(context_idr),
- contextidr);
- adreno_writereg64(adreno_dev,
- ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_LO,
- ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_HI,
- iommu->smmu_info.gpuaddr);
-
- FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
- kgsl_sharedmem_writel(device, &rb->preemption_desc,
- PREEMPT_RECORD(rptr), 0);
- kgsl_sharedmem_writel(device, &rb->preemption_desc,
- PREEMPT_RECORD(wptr), 0);
- kgsl_sharedmem_writeq(device, &rb->pagetable_desc,
- offsetof(struct adreno_ringbuffer_pagetable_info,
- ttbr0), def_ttbr0);
- }
- }
-
+ a5xx_preemption_start(adreno_dev);
a5xx_protect_init(adreno_dev);
}
+/*
+ * Follow the ME_INIT sequence with a preemption yield to allow the GPU to move
+ * to a different ringbuffer, if desired
+ */
static int _preemption_init(
struct adreno_device *adreno_dev,
struct adreno_ringbuffer *rb, unsigned int *cmds,
struct kgsl_context *context)
{
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
unsigned int *cmds_orig = cmds;
uint64_t gpuaddr = rb->preemption_desc.gpuaddr;
- uint64_t gpuaddr_token = device->memstore.gpuaddr +
- KGSL_MEMSTORE_OFFSET(0, preempted);
/* Turn CP protection OFF */
*cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1);
@@ -2258,8 +1940,8 @@ static int _preemption_init(
*cmds++ = 1;
*cmds++ = cp_type7_packet(CP_CONTEXT_SWITCH_YIELD, 4);
- cmds += cp_gpuaddr(adreno_dev, cmds, gpuaddr_token);
- *cmds++ = 1;
+ cmds += cp_gpuaddr(adreno_dev, cmds, 0x0);
+ *cmds++ = 0;
/* generate interrupt on preemption completion */
*cmds++ = 1;
@@ -2297,7 +1979,7 @@ static int a5xx_post_start(struct adreno_device *adreno_dev)
if (adreno_is_preemption_enabled(adreno_dev))
cmds += _preemption_init(adreno_dev, rb, cmds, NULL);
- rb->wptr = rb->wptr - (42 - (cmds - start));
+ rb->_wptr = rb->_wptr - (42 - (cmds - start));
ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000);
if (ret)
@@ -2595,8 +2277,15 @@ static int a5xx_rb_start(struct adreno_device *adreno_dev,
unsigned int start_type)
{
struct adreno_ringbuffer *rb = ADRENO_CURRENT_RINGBUFFER(adreno_dev);
+ struct kgsl_device *device = &adreno_dev->dev;
+ uint64_t addr;
int ret;
+ addr = SCRATCH_RPTR_GPU_ADDR(device, rb->id);
+
+ adreno_writereg64(adreno_dev, ADRENO_REG_CP_RB_RPTR_ADDR_LO,
+ ADRENO_REG_CP_RB_RPTR_ADDR_HI, addr);
+
/*
* The size of the ringbuffer in the hardware is the log2
* representation of the size in quadwords (sizedwords / 2).
@@ -2605,8 +2294,7 @@ static int a5xx_rb_start(struct adreno_device *adreno_dev,
*/
adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL,
- (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F) |
- (1 << 27));
+ A5XX_CP_RB_CNTL_DEFAULT);
adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE,
rb->buffer_desc.gpuaddr);
@@ -3147,6 +2835,10 @@ static unsigned int a5xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
ADRENO_REG_DEFINE(ADRENO_REG_CP_WFI_PEND_CTR, A5XX_CP_WFI_PEND_CTR),
ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_BASE, A5XX_CP_RB_BASE),
ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_BASE_HI, A5XX_CP_RB_BASE_HI),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR_ADDR_LO,
+ A5XX_CP_RB_RPTR_ADDR_LO),
+ ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR_ADDR_HI,
+ A5XX_CP_RB_RPTR_ADDR_HI),
ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR, A5XX_CP_RB_RPTR),
ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_WPTR, A5XX_CP_RB_WPTR),
ADRENO_REG_DEFINE(ADRENO_REG_CP_CNTL, A5XX_CP_CNTL),
@@ -3416,6 +3108,8 @@ static void a5xx_cp_callback(struct adreno_device *adreno_dev, int bit)
prev = cur;
}
+ a5xx_preemption_trigger(adreno_dev);
+
kgsl_schedule_work(&device->event_work);
adreno_dispatcher_schedule(device);
}
@@ -3500,9 +3194,6 @@ void a5x_gpc_err_int_callback(struct adreno_device *adreno_dev, int bit)
(1 << A5XX_INT_RBBM_ATB_ASYNC_OVERFLOW) | \
(1 << A5XX_INT_RBBM_GPC_ERROR) | \
(1 << A5XX_INT_CP_HW_ERROR) | \
- (1 << A5XX_INT_CP_IB1) | \
- (1 << A5XX_INT_CP_IB2) | \
- (1 << A5XX_INT_CP_RB) | \
(1 << A5XX_INT_CP_CACHE_FLUSH_TS) | \
(1 << A5XX_INT_RBBM_ATB_BUS_OVERFLOW) | \
(1 << A5XX_INT_UCHE_OOB_ACCESS) | \
@@ -3525,7 +3216,7 @@ static struct adreno_irq_funcs a5xx_irq_funcs[32] = {
/* 6 - RBBM_ATB_ASYNC_OVERFLOW */
ADRENO_IRQ_CALLBACK(a5xx_err_callback),
ADRENO_IRQ_CALLBACK(a5x_gpc_err_int_callback), /* 7 - GPC_ERR */
- ADRENO_IRQ_CALLBACK(adreno_dispatcher_preempt_callback),/* 8 - CP_SW */
+ ADRENO_IRQ_CALLBACK(a5xx_preempt_callback),/* 8 - CP_SW */
ADRENO_IRQ_CALLBACK(a5xx_cp_hw_err_callback), /* 9 - CP_HW_ERROR */
/* 10 - CP_CCU_FLUSH_DEPTH_TS */
ADRENO_IRQ_CALLBACK(NULL),
@@ -3533,9 +3224,9 @@ static struct adreno_irq_funcs a5xx_irq_funcs[32] = {
ADRENO_IRQ_CALLBACK(NULL),
/* 12 - CP_CCU_RESOLVE_TS */
ADRENO_IRQ_CALLBACK(NULL),
- ADRENO_IRQ_CALLBACK(adreno_cp_callback), /* 13 - CP_IB2_INT */
- ADRENO_IRQ_CALLBACK(adreno_cp_callback), /* 14 - CP_IB1_INT */
- ADRENO_IRQ_CALLBACK(adreno_cp_callback), /* 15 - CP_RB_INT */
+ ADRENO_IRQ_CALLBACK(NULL), /* 13 - CP_IB2_INT */
+ ADRENO_IRQ_CALLBACK(NULL), /* 14 - CP_IB1_INT */
+ ADRENO_IRQ_CALLBACK(NULL), /* 15 - CP_RB_INT */
/* 16 - CCP_UNUSED_1 */
ADRENO_IRQ_CALLBACK(NULL),
ADRENO_IRQ_CALLBACK(NULL), /* 17 - CP_RB_DONE_TS */
@@ -3772,323 +3463,6 @@ static struct adreno_coresight a5xx_coresight = {
.groups = a5xx_coresight_groups,
};
-/**
- * a5xx_preempt_trig_state() - Schedule preemption in TRIGGERRED
- * state
- * @adreno_dev: Device which is in TRIGGERRED state
- */
-static void a5xx_preempt_trig_state(
- struct adreno_device *adreno_dev)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- unsigned int preempt_busy;
- uint64_t rbbase;
-
- /*
- * triggered preemption, check for busy bits, if not set go to complete
- * bit 0: When high indicates CP is not done with preemption.
- * bit 4: When high indicates that the CP is actively switching between
- * application contexts.
- * Check both the bits to make sure CP is done with preemption.
- */
- adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &preempt_busy);
- if (!(preempt_busy & 0x11)) {
-
- adreno_readreg64(adreno_dev, ADRENO_REG_CP_RB_BASE,
- ADRENO_REG_CP_RB_BASE_HI, &rbbase);
- /* Did preemption occur, if so then change states and return */
- if (rbbase != adreno_dev->cur_rb->buffer_desc.gpuaddr) {
- if (rbbase ==
- adreno_dev->next_rb->buffer_desc.gpuaddr) {
- KGSL_DRV_INFO(device,
- "Preemption completed without interrupt\n");
- trace_adreno_hw_preempt_trig_to_comp(
- adreno_dev->cur_rb,
- adreno_dev->next_rb);
- atomic_set(&dispatcher->preemption_state,
- ADRENO_DISPATCHER_PREEMPT_COMPLETE);
- } else {
- /*
- * Something wrong with preemption.
- * Set fault and reschedule dispatcher to take
- * care of fault.
- */
- adreno_set_gpu_fault(adreno_dev,
- ADRENO_PREEMPT_FAULT);
- }
- adreno_dispatcher_schedule(device);
- return;
- }
- }
-
- /*
- * Preemption is still happening.
- * Hardware not yet idle means that preemption interrupt
- * may still occur, nothing to do here until interrupt signals
- * completion of preemption, just return here
- */
- if (!adreno_hw_isidle(adreno_dev))
- return;
-
- /*
- * We just changed states, reschedule dispatcher to change
- * preemption states
- */
- if (ADRENO_DISPATCHER_PREEMPT_TRIGGERED !=
- atomic_read(&dispatcher->preemption_state)) {
- adreno_dispatcher_schedule(device);
- return;
- }
-
-
- adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
-
- /* reschedule dispatcher to take care of the fault */
- adreno_dispatcher_schedule(device);
-}
-
-/**
- * a5xx_preempt_clear_state() - Schedule preemption in CLEAR
- * state. Preemption can be issued in this state.
- * @adreno_dev: Device which is in CLEAR state
- */
-static void a5xx_preempt_clear_state(
- struct adreno_device *adreno_dev)
-
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct adreno_ringbuffer *highest_busy_rb;
- int switch_low_to_high;
- int ret;
-
- /* Device not awake means there is nothing to do */
- if (!kgsl_state_is_awake(device))
- return;
-
- /* keep updating the current rptr when preemption is clear */
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR,
- &(adreno_dev->cur_rb->rptr));
-
- highest_busy_rb = adreno_dispatcher_get_highest_busy_rb(adreno_dev);
- if (!highest_busy_rb)
- return;
-
- switch_low_to_high = adreno_compare_prio_level(
- highest_busy_rb->id, adreno_dev->cur_rb->id);
-
- /* already current then return */
- if (!switch_low_to_high)
- return;
-
- if (switch_low_to_high < 0) {
-
- if (!adreno_hw_isidle(adreno_dev)) {
- adreno_dispatcher_schedule(device);
- return;
- }
-
- /*
- * if switching to lower priority make sure that the rptr and
- * wptr are equal, when the lower rb is not starved
- */
- if (adreno_dev->cur_rb->rptr != adreno_dev->cur_rb->wptr)
- return;
- /*
- * switch to default context because when we switch back
- * to higher context then its not known which pt will
- * be current, so by making it default here the next
- * commands submitted will set the right pt
- */
- ret = adreno_drawctxt_switch(adreno_dev,
- adreno_dev->cur_rb,
- NULL, 0);
- /*
- * lower priority RB has to wait until space opens up in
- * higher RB
- */
- if (ret)
- return;
- }
-
- /* rptr could be updated in drawctxt switch above, update it here */
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR,
- &(adreno_dev->cur_rb->rptr));
-
- /* turn on IOMMU as the preemption may trigger pt switch */
- kgsl_mmu_enable_clk(&device->mmu);
-
- /*
- * setup memory to do the switch to highest priority RB
- * which is not empty or may be starving away(poor thing)
- */
- a5xx_preemption_start(adreno_dev, highest_busy_rb);
-
- atomic_set(&dispatcher->preemption_state,
- ADRENO_DISPATCHER_PREEMPT_TRIGGERED);
-
- adreno_dev->next_rb = highest_busy_rb;
- mod_timer(&dispatcher->preempt_timer, jiffies +
- msecs_to_jiffies(ADRENO_DISPATCH_PREEMPT_TIMEOUT));
-
- trace_adreno_hw_preempt_clear_to_trig(adreno_dev->cur_rb,
- adreno_dev->next_rb);
- /* issue PREEMPT trigger */
- adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT, 1);
-
- adreno_dispatcher_schedule(device);
-}
-
-/**
- * a5xx_preempt_complete_state() - Schedule preemption in
- * COMPLETE state
- * @adreno_dev: Device which is in COMPLETE state
- */
-static void a5xx_preempt_complete_state(
- struct adreno_device *adreno_dev)
-
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct adreno_dispatcher_cmdqueue *dispatch_q;
- uint64_t rbbase;
- unsigned int wptr;
- unsigned int val;
- static unsigned long wait_for_preemption_complete;
-
- del_timer_sync(&dispatcher->preempt_timer);
-
- adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &val);
-
- if (val) {
- /*
- * Wait for 50ms for preemption state to be updated by CP
- * before triggering hang
- */
- if (wait_for_preemption_complete == 0)
- wait_for_preemption_complete = jiffies +
- msecs_to_jiffies(50);
- if (time_after(jiffies, wait_for_preemption_complete)) {
- wait_for_preemption_complete = 0;
- KGSL_DRV_ERR(device,
- "Invalid state after preemption CP_PREEMPT:%08x STOP:%1x BUSY:%1x\n",
- val, (val & 0x1), (val & 0x10)>>4);
- adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
- }
- adreno_dispatcher_schedule(device);
- return;
- }
-
- wait_for_preemption_complete = 0;
- adreno_readreg64(adreno_dev, ADRENO_REG_CP_RB_BASE,
- ADRENO_REG_CP_RB_BASE_HI, &rbbase);
- if (rbbase != adreno_dev->next_rb->buffer_desc.gpuaddr) {
- KGSL_DRV_ERR(device,
- "RBBASE incorrect after preemption, expected %016llx got %016llx\b",
- rbbase,
- adreno_dev->next_rb->buffer_desc.gpuaddr);
- adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
- adreno_dispatcher_schedule(device);
- return;
- }
-
- a5xx_preemption_save(adreno_dev, adreno_dev->cur_rb);
-
- dispatch_q = &(adreno_dev->cur_rb->dispatch_q);
- /* new RB is the current RB */
- trace_adreno_hw_preempt_comp_to_clear(adreno_dev->next_rb,
- adreno_dev->cur_rb);
- adreno_dev->prev_rb = adreno_dev->cur_rb;
- adreno_dev->cur_rb = adreno_dev->next_rb;
- adreno_dev->cur_rb->preempted_midway = 0;
- adreno_dev->cur_rb->wptr_preempt_end = 0xFFFFFFFF;
- adreno_dev->next_rb = NULL;
-
- if (adreno_disp_preempt_fair_sched) {
- /* starved rb is now scheduled so unhalt dispatcher */
- if (ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED ==
- adreno_dev->cur_rb->starve_timer_state)
- adreno_put_gpu_halt(adreno_dev);
- adreno_dev->cur_rb->starve_timer_state =
- ADRENO_DISPATCHER_RB_STARVE_TIMER_SCHEDULED;
- adreno_dev->cur_rb->sched_timer = jiffies;
- /*
- * If the outgoing RB is has commands then set the
- * busy time for it
- */
- if (adreno_dev->prev_rb->rptr != adreno_dev->prev_rb->wptr) {
- adreno_dev->prev_rb->starve_timer_state =
- ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT;
- adreno_dev->prev_rb->sched_timer = jiffies;
- } else {
- adreno_dev->prev_rb->starve_timer_state =
- ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT;
- }
- }
- adreno_ringbuffer_mmu_disable_clk_on_ts(device, adreno_dev->cur_rb,
- adreno_dev->cur_rb->timestamp);
-
- atomic_set(&dispatcher->preemption_state,
- ADRENO_DISPATCHER_PREEMPT_CLEAR);
-
- /* submit wptr if required for new rb */
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_WPTR, &wptr);
- if (adreno_dev->cur_rb->wptr != wptr) {
- kgsl_pwrscale_busy(device);
- adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR,
- adreno_dev->cur_rb->wptr);
- }
-
- adreno_preempt_process_dispatch_queue(adreno_dev, dispatch_q);
-}
-
-static void a5xx_preemption_schedule(
- struct adreno_device *adreno_dev)
-{
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct adreno_ringbuffer *rb;
- int i = 0;
-
- if (!adreno_is_preemption_enabled(adreno_dev))
- return;
-
- mutex_lock(&device->mutex);
-
- /*
- * This barrier is needed for most updated preemption_state
- * to be read.
- */
- smp_mb();
-
- if (KGSL_STATE_ACTIVE == device->state)
- FOR_EACH_RINGBUFFER(adreno_dev, rb, i)
- rb->rptr = adreno_get_rptr(rb);
-
- switch (atomic_read(&dispatcher->preemption_state)) {
- case ADRENO_DISPATCHER_PREEMPT_CLEAR:
- a5xx_preempt_clear_state(adreno_dev);
- break;
- case ADRENO_DISPATCHER_PREEMPT_TRIGGERED:
- a5xx_preempt_trig_state(adreno_dev);
- /*
- * if we transitioned to next state then fall-through
- * processing to next state
- */
- if (!adreno_preempt_state(adreno_dev,
- ADRENO_DISPATCHER_PREEMPT_COMPLETE))
- break;
- case ADRENO_DISPATCHER_PREEMPT_COMPLETE:
- a5xx_preempt_complete_state(adreno_dev);
- break;
- default:
- BUG();
- }
-
- mutex_unlock(&device->mutex);
-}
-
struct adreno_gpudev adreno_a5xx_gpudev = {
.reg_offsets = &a5xx_reg_offsets,
.ft_perf_counters = a5xx_ft_perf_counters,
@@ -4116,7 +3490,6 @@ struct adreno_gpudev adreno_a5xx_gpudev = {
a5xx_preemption_yield_enable,
.preemption_post_ibsubmit =
a5xx_preemption_post_ibsubmit,
- .preemption_token = a5xx_preemption_token,
.preemption_init = a5xx_preemption_init,
.preemption_schedule = a5xx_preemption_schedule,
.enable_64bit = a5xx_enable_64bit,
diff --git a/drivers/gpu/msm/adreno_a5xx.h b/drivers/gpu/msm/adreno_a5xx.h
index 6ce95ff7bdbf..7965bb7b5440 100644
--- a/drivers/gpu/msm/adreno_a5xx.h
+++ b/drivers/gpu/msm/adreno_a5xx.h
@@ -112,6 +112,8 @@ void a5xx_crashdump_init(struct adreno_device *adreno_dev);
void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on);
+#define A5XX_CP_RB_CNTL_DEFAULT (((ilog2(4) << 8) & 0x1F00) | \
+ (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F))
/* GPMU interrupt multiplexor */
#define FW_INTR_INFO (0)
#define LLM_ACK_ERR_INTR (1)
@@ -232,4 +234,22 @@ static inline bool lm_on(struct adreno_device *adreno_dev)
return ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag);
}
+
+/* Preemption functions */
+void a5xx_preemption_trigger(struct adreno_device *adreno_dev);
+void a5xx_preemption_schedule(struct adreno_device *adreno_dev);
+void a5xx_preemption_start(struct adreno_device *adreno_dev);
+int a5xx_preemption_init(struct adreno_device *adreno_dev);
+int a5xx_preemption_yield_enable(unsigned int *cmds);
+
+unsigned int a5xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev,
+ unsigned int *cmds);
+unsigned int a5xx_preemption_pre_ibsubmit(
+ struct adreno_device *adreno_dev,
+ struct adreno_ringbuffer *rb,
+ unsigned int *cmds, struct kgsl_context *context);
+
+
+void a5xx_preempt_callback(struct adreno_device *adreno_dev, int bit);
+
#endif
diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c
new file mode 100644
index 000000000000..c1463b824c67
--- /dev/null
+++ b/drivers/gpu/msm/adreno_a5xx_preempt.c
@@ -0,0 +1,574 @@
+/* Copyright (c) 2014-2016, 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 "adreno.h"
+#include "adreno_a5xx.h"
+#include "a5xx_reg.h"
+#include "adreno_trace.h"
+#include "adreno_pm4types.h"
+
+#define PREEMPT_RECORD(_field) \
+ offsetof(struct a5xx_cp_preemption_record, _field)
+
+#define PREEMPT_SMMU_RECORD(_field) \
+ offsetof(struct a5xx_cp_smmu_info, _field)
+
+static void _update_wptr(struct adreno_device *adreno_dev)
+{
+ struct adreno_ringbuffer *rb = adreno_dev->cur_rb;
+ unsigned int wptr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rb->preempt_lock, flags);
+
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_WPTR, &wptr);
+
+ if (wptr != rb->wptr) {
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR,
+ rb->wptr);
+
+ rb->dispatch_q.expires = jiffies +
+ msecs_to_jiffies(adreno_cmdbatch_timeout);
+ }
+
+ spin_unlock_irqrestore(&rb->preempt_lock, flags);
+}
+
+static inline bool adreno_move_preempt_state(struct adreno_device *adreno_dev,
+ enum adreno_preempt_states old, enum adreno_preempt_states new)
+{
+ return (atomic_cmpxchg(&adreno_dev->preempt.state, old, new) == old);
+}
+
+static void _a5xx_preemption_done(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ unsigned int status;
+
+ /*
+ * In the very unlikely case that the power is off, do nothing - the
+ * state will be reset on power up and everybody will be happy
+ */
+
+ if (!kgsl_state_is_awake(device))
+ return;
+
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &status);
+
+ if (status != 0) {
+ KGSL_DRV_ERR(device,
+ "Preemption not complete: status=%X cur=%d R/W=%X/%X next=%d R/W=%X/%X\n",
+ status, adreno_dev->cur_rb->id,
+ adreno_get_rptr(adreno_dev->cur_rb),
+ adreno_dev->cur_rb->wptr, adreno_dev->next_rb->id,
+ adreno_get_rptr(adreno_dev->next_rb),
+ adreno_dev->next_rb->wptr);
+
+ /* Set a fault and restart */
+ adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
+ adreno_dispatcher_schedule(device);
+
+ return;
+ }
+
+ del_timer_sync(&adreno_dev->preempt.timer);
+
+ trace_adreno_preempt_done(adreno_dev->cur_rb, adreno_dev->next_rb);
+
+ /* Clean up all the bits */
+ adreno_dev->prev_rb = adreno_dev->cur_rb;
+ adreno_dev->cur_rb = adreno_dev->next_rb;
+ adreno_dev->next_rb = NULL;
+
+ /* Update the wptr for the new command queue */
+ _update_wptr(adreno_dev);
+
+ /* Update the dispatcher timer for the new command queue */
+ mod_timer(&adreno_dev->dispatcher.timer,
+ adreno_dev->cur_rb->dispatch_q.expires);
+
+ /* Clear the preempt state */
+ adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE);
+}
+
+static void _a5xx_preemption_fault(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ unsigned int status;
+
+ /*
+ * If the power is on check the preemption status one more time - if it
+ * was successful then just transition to the complete state
+ */
+ if (kgsl_state_is_awake(device)) {
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &status);
+
+ if (status == 0) {
+ adreno_set_preempt_state(adreno_dev,
+ ADRENO_PREEMPT_COMPLETE);
+
+ adreno_dispatcher_schedule(device);
+ return;
+ }
+ }
+
+ KGSL_DRV_ERR(device,
+ "Preemption timed out: cur=%d R/W=%X/%X, next=%d R/W=%X/%X\n",
+ adreno_dev->cur_rb->id,
+ adreno_get_rptr(adreno_dev->cur_rb), adreno_dev->cur_rb->wptr,
+ adreno_dev->next_rb->id,
+ adreno_get_rptr(adreno_dev->next_rb),
+ adreno_dev->next_rb->wptr);
+
+ adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
+ adreno_dispatcher_schedule(device);
+}
+
+static void _a5xx_preemption_worker(struct work_struct *work)
+{
+ struct adreno_preemption *preempt = container_of(work,
+ struct adreno_preemption, work);
+ struct adreno_device *adreno_dev = container_of(preempt,
+ struct adreno_device, preempt);
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ /* Need to take the mutex to make sure that the power stays on */
+ mutex_lock(&device->mutex);
+
+ if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_FAULTED))
+ _a5xx_preemption_fault(adreno_dev);
+
+ mutex_unlock(&device->mutex);
+}
+
+static void _a5xx_preemption_timer(unsigned long data)
+{
+ struct adreno_device *adreno_dev = (struct adreno_device *) data;
+
+ /* We should only be here from a triggered state */
+ if (!adreno_move_preempt_state(adreno_dev,
+ ADRENO_PREEMPT_TRIGGERED, ADRENO_PREEMPT_FAULTED))
+ return;
+
+ /* Schedule the worker to take care of the details */
+ queue_work(system_unbound_wq, &adreno_dev->preempt.work);
+}
+
+/* Find the highest priority active ringbuffer */
+static struct adreno_ringbuffer *a5xx_next_ringbuffer(
+ struct adreno_device *adreno_dev)
+{
+ struct adreno_ringbuffer *rb;
+ unsigned long flags;
+ unsigned int i;
+
+ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
+ bool empty;
+
+ spin_lock_irqsave(&rb->preempt_lock, flags);
+ empty = adreno_rb_empty(rb);
+ spin_unlock_irqrestore(&rb->preempt_lock, flags);
+
+ if (empty == false)
+ return rb;
+ }
+
+ return NULL;
+}
+
+void a5xx_preemption_trigger(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
+ struct adreno_ringbuffer *next;
+ uint64_t ttbr0;
+ unsigned int contextidr;
+ unsigned long flags;
+
+ /* Put ourselves into a possible trigger state */
+ if (!adreno_move_preempt_state(adreno_dev,
+ ADRENO_PREEMPT_NONE, ADRENO_PREEMPT_START))
+ return;
+
+ /* Get the next ringbuffer to preempt in */
+ next = a5xx_next_ringbuffer(adreno_dev);
+
+ /*
+ * Nothing to do if every ringbuffer is empty or if the current
+ * ringbuffer is the only active one
+ */
+ if (next == NULL || next == adreno_dev->cur_rb) {
+ /*
+ * Update any critical things that might have been skipped while
+ * we were looking for a new ringbuffer
+ */
+
+ if (next != NULL) {
+ _update_wptr(adreno_dev);
+
+ mod_timer(&adreno_dev->dispatcher.timer,
+ adreno_dev->cur_rb->dispatch_q.expires);
+ }
+
+ adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE);
+ return;
+ }
+
+ /* Turn off the dispatcher timer */
+ del_timer(&adreno_dev->dispatcher.timer);
+
+ /*
+ * This is the most critical section - we need to take care not to race
+ * until we have programmed the CP for the switch
+ */
+
+ spin_lock_irqsave(&next->preempt_lock, flags);
+
+ /* Get the pagetable from the pagetable info */
+ kgsl_sharedmem_readq(&next->pagetable_desc, &ttbr0,
+ PT_INFO_OFFSET(ttbr0));
+ kgsl_sharedmem_readl(&next->pagetable_desc, &contextidr,
+ PT_INFO_OFFSET(contextidr));
+
+ kgsl_sharedmem_writel(device, &next->preemption_desc,
+ PREEMPT_RECORD(wptr), next->wptr);
+
+ spin_unlock_irqrestore(&next->preempt_lock, flags);
+
+ /* And write it to the smmu info */
+ kgsl_sharedmem_writeq(device, &iommu->smmu_info,
+ PREEMPT_SMMU_RECORD(ttbr0), ttbr0);
+ kgsl_sharedmem_writel(device, &iommu->smmu_info,
+ PREEMPT_SMMU_RECORD(context_idr), contextidr);
+
+ kgsl_regwrite(device, A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_LO,
+ lower_32_bits(next->preemption_desc.gpuaddr));
+ kgsl_regwrite(device, A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_HI,
+ upper_32_bits(next->preemption_desc.gpuaddr));
+
+ adreno_dev->next_rb = next;
+
+ /* Start the timer to detect a stuck preemption */
+ mod_timer(&adreno_dev->preempt.timer,
+ jiffies + msecs_to_jiffies(ADRENO_PREEMPT_TIMEOUT));
+
+ trace_adreno_preempt_trigger(adreno_dev->cur_rb, adreno_dev->next_rb);
+
+ adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_TRIGGERED);
+
+ /* Trigger the preemption */
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT, 1);
+}
+
+void a5xx_preempt_callback(struct adreno_device *adreno_dev, int bit)
+{
+ unsigned int status;
+
+ if (!adreno_move_preempt_state(adreno_dev,
+ ADRENO_PREEMPT_TRIGGERED, ADRENO_PREEMPT_PENDING))
+ return;
+
+ adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &status);
+
+ if (status != 0) {
+ KGSL_DRV_ERR(KGSL_DEVICE(adreno_dev),
+ "preempt interrupt with non-zero status: %X\n", status);
+
+ /*
+ * Under the assumption that this is a race between the
+ * interrupt and the register, schedule the worker to clean up.
+ * If the status still hasn't resolved itself by the time we get
+ * there then we have to assume something bad happened
+ */
+ adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_COMPLETE);
+ adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev));
+ return;
+ }
+
+ del_timer(&adreno_dev->preempt.timer);
+
+ trace_adreno_preempt_done(adreno_dev->cur_rb,
+ adreno_dev->next_rb);
+
+ adreno_dev->prev_rb = adreno_dev->cur_rb;
+ adreno_dev->cur_rb = adreno_dev->next_rb;
+ adreno_dev->next_rb = NULL;
+
+ /* Update the wptr if it changed while preemption was ongoing */
+ _update_wptr(adreno_dev);
+
+ /* Update the dispatcher timer for the new command queue */
+ mod_timer(&adreno_dev->dispatcher.timer,
+ adreno_dev->cur_rb->dispatch_q.expires);
+
+ adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE);
+}
+
+void a5xx_preemption_schedule(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+ if (!adreno_is_preemption_enabled(adreno_dev))
+ return;
+
+ mutex_lock(&device->mutex);
+
+ if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_COMPLETE))
+ _a5xx_preemption_done(adreno_dev);
+
+ a5xx_preemption_trigger(adreno_dev);
+
+ mutex_unlock(&device->mutex);
+}
+
+unsigned int a5xx_preemption_pre_ibsubmit(
+ struct adreno_device *adreno_dev,
+ struct adreno_ringbuffer *rb,
+ unsigned int *cmds, struct kgsl_context *context)
+{
+ unsigned int *cmds_orig = cmds;
+ uint64_t gpuaddr = rb->preemption_desc.gpuaddr;
+ unsigned int preempt_style = 0;
+
+ if (context) {
+ /*
+ * Preemption from secure to unsecure needs Zap shader to be
+ * run to clear all secure content. CP does not know during
+ * preemption if it is switching between secure and unsecure
+ * contexts so restrict Secure contexts to be preempted at
+ * ringbuffer level.
+ */
+ if (context->flags & KGSL_CONTEXT_SECURE)
+ preempt_style = KGSL_CONTEXT_PREEMPT_STYLE_RINGBUFFER;
+ else
+ preempt_style = ADRENO_PREEMPT_STYLE(context->flags);
+ }
+
+ /*
+ * CP_PREEMPT_ENABLE_GLOBAL(global preemption) can only be set by KMD
+ * in ringbuffer.
+ * 1) set global preemption to 0x0 to disable global preemption.
+ * Only RB level preemption is allowed in this mode
+ * 2) Set global preemption to defer(0x2) for finegrain preemption.
+ * when global preemption is set to defer(0x2),
+ * CP_PREEMPT_ENABLE_LOCAL(local preemption) determines the
+ * preemption point. Local preemption
+ * can be enabled by both UMD(within IB) and KMD.
+ */
+ *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_GLOBAL, 1);
+ *cmds++ = ((preempt_style == KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN)
+ ? 2 : 0);
+
+ /* Turn CP protection OFF */
+ *cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
+ /*
+ * CP during context switch will save context switch info to
+ * a5xx_cp_preemption_record pointed by CONTEXT_SWITCH_SAVE_ADDR
+ */
+ *cmds++ = cp_type4_packet(A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 1);
+ *cmds++ = lower_32_bits(gpuaddr);
+ *cmds++ = cp_type4_packet(A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_HI, 1);
+ *cmds++ = upper_32_bits(gpuaddr);
+
+ /* Turn CP protection ON */
+ *cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 1;
+
+ /*
+ * Enable local preemption for finegrain preemption in case of
+ * a misbehaving IB
+ */
+ if (preempt_style == KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN) {
+ *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_LOCAL, 1);
+ *cmds++ = 1;
+ } else {
+ *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_LOCAL, 1);
+ *cmds++ = 0;
+ }
+
+ /* Enable CP_CONTEXT_SWITCH_YIELD packets in the IB2s */
+ *cmds++ = cp_type7_packet(CP_YIELD_ENABLE, 1);
+ *cmds++ = 2;
+
+ return (unsigned int) (cmds - cmds_orig);
+}
+
+int a5xx_preemption_yield_enable(unsigned int *cmds)
+{
+ /*
+ * SRM -- set render mode (ex binning, direct render etc)
+ * SRM is set by UMD usually at start of IB to tell CP the type of
+ * preemption.
+ * KMD needs to set SRM to NULL to indicate CP that rendering is
+ * done by IB.
+ */
+ *cmds++ = cp_type7_packet(CP_SET_RENDER_MODE, 5);
+ *cmds++ = 0;
+ *cmds++ = 0;
+ *cmds++ = 0;
+ *cmds++ = 0;
+ *cmds++ = 0;
+
+ *cmds++ = cp_type7_packet(CP_YIELD_ENABLE, 1);
+ *cmds++ = 1;
+
+ return 8;
+}
+
+unsigned int a5xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev,
+ unsigned int *cmds)
+{
+ int dwords = 0;
+
+ cmds[dwords++] = cp_type7_packet(CP_CONTEXT_SWITCH_YIELD, 4);
+ /* Write NULL to the address to skip the data write */
+ dwords += cp_gpuaddr(adreno_dev, &cmds[dwords], 0x0);
+ cmds[dwords++] = 1;
+ /* generate interrupt on preemption completion */
+ cmds[dwords++] = 1;
+
+ return dwords;
+}
+
+void a5xx_preemption_start(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
+ struct adreno_ringbuffer *rb;
+ unsigned int i;
+
+ if (!adreno_is_preemption_enabled(adreno_dev))
+ return;
+
+ /* Force the state to be clear */
+ adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE);
+
+ kgsl_sharedmem_writel(device, &iommu->smmu_info,
+ PREEMPT_SMMU_RECORD(magic), A5XX_CP_SMMU_INFO_MAGIC_REF);
+ kgsl_sharedmem_writeq(device, &iommu->smmu_info,
+ PREEMPT_SMMU_RECORD(ttbr0), MMU_DEFAULT_TTBR0(device));
+
+ /* The CP doesn't use the asid record, so poison it */
+ kgsl_sharedmem_writel(device, &iommu->smmu_info,
+ PREEMPT_SMMU_RECORD(asid), 0xDECAFBAD);
+ kgsl_sharedmem_writel(device, &iommu->smmu_info,
+ PREEMPT_SMMU_RECORD(context_idr),
+ MMU_DEFAULT_CONTEXTIDR(device));
+
+ adreno_writereg64(adreno_dev,
+ ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_LO,
+ ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_HI,
+ iommu->smmu_info.gpuaddr);
+
+ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
+ kgsl_sharedmem_writel(device, &rb->preemption_desc,
+ PREEMPT_RECORD(rptr), 0);
+ kgsl_sharedmem_writel(device, &rb->preemption_desc,
+ PREEMPT_RECORD(wptr), 0);
+
+ adreno_ringbuffer_set_pagetable(rb,
+ device->mmu.defaultpagetable);
+ }
+
+}
+
+static int a5xx_preemption_ringbuffer_init(struct adreno_device *adreno_dev,
+ struct adreno_ringbuffer *rb, uint64_t counteraddr)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ int ret;
+
+ ret = kgsl_allocate_global(device, &rb->preemption_desc,
+ A5XX_CP_CTXRECORD_SIZE_IN_BYTES, 0, KGSL_MEMDESC_PRIVILEGED);
+ if (ret)
+ return ret;
+
+ kgsl_sharedmem_writel(device, &rb->preemption_desc,
+ PREEMPT_RECORD(magic), A5XX_CP_CTXRECORD_MAGIC_REF);
+ kgsl_sharedmem_writel(device, &rb->preemption_desc,
+ PREEMPT_RECORD(info), 0);
+ kgsl_sharedmem_writel(device, &rb->preemption_desc,
+ PREEMPT_RECORD(data), 0);
+ kgsl_sharedmem_writel(device, &rb->preemption_desc,
+ PREEMPT_RECORD(cntl), A5XX_CP_RB_CNTL_DEFAULT);
+ kgsl_sharedmem_writel(device, &rb->preemption_desc,
+ PREEMPT_RECORD(rptr), 0);
+ kgsl_sharedmem_writel(device, &rb->preemption_desc,
+ PREEMPT_RECORD(wptr), 0);
+ kgsl_sharedmem_writeq(device, &rb->preemption_desc,
+ PREEMPT_RECORD(rptr_addr), SCRATCH_RPTR_GPU_ADDR(device,
+ rb->id));
+ kgsl_sharedmem_writeq(device, &rb->preemption_desc,
+ PREEMPT_RECORD(rbase), rb->buffer_desc.gpuaddr);
+ kgsl_sharedmem_writeq(device, &rb->preemption_desc,
+ PREEMPT_RECORD(counter), counteraddr);
+
+ return 0;
+}
+
+#ifdef CONFIG_QCOM_KGSL_IOMMU
+static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device);
+
+ /* Allocate mem for storing preemption smmu record */
+ return kgsl_allocate_global(device, &iommu->smmu_info, PAGE_SIZE,
+ KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED);
+}
+#else
+static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev)
+{
+ return -ENODEV;
+}
+#endif
+
+int a5xx_preemption_init(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct adreno_preemption *preempt = &adreno_dev->preempt;
+ struct adreno_ringbuffer *rb;
+ int ret;
+ unsigned int i;
+ uint64_t addr;
+
+ /* We are dependent on IOMMU to make preemption go on the CP side */
+ if (kgsl_mmu_get_mmutype(device) != KGSL_MMU_TYPE_IOMMU)
+ return -ENODEV;
+
+ INIT_WORK(&preempt->work, _a5xx_preemption_worker);
+
+ setup_timer(&preempt->timer, _a5xx_preemption_timer,
+ (unsigned long) adreno_dev);
+
+ /* Allocate mem for storing preemption counters */
+ ret = kgsl_allocate_global(device, &preempt->counters,
+ adreno_dev->num_ringbuffers *
+ A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0);
+ if (ret)
+ return ret;
+
+ addr = preempt->counters.gpuaddr;
+
+ /* Allocate mem for storing preemption switch record */
+ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
+ ret = a5xx_preemption_ringbuffer_init(adreno_dev, rb, addr);
+ if (ret)
+ return ret;
+
+ addr += A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE;
+ }
+
+ return a5xx_preemption_iommu_init(adreno_dev);
+}
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index 1a1db3ab3dc9..9cbcd06d7658 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -226,8 +226,7 @@ static void cmdbatch_print(struct seq_file *s, struct kgsl_cmdbatch *cmdbatch)
if (cmdbatch->flags & KGSL_CONTEXT_SYNC)
return;
- seq_printf(s, "\t%d: ib: expires: %lu",
- cmdbatch->timestamp, cmdbatch->expires);
+ seq_printf(s, "\t%d: ", cmdbatch->timestamp);
seq_puts(s, " flags: ");
print_flags(s, cmdbatch_flags, ARRAY_SIZE(cmdbatch_flags),
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 3f36a93ea110..ac3805800691 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -28,10 +28,10 @@
#define CMDQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s))
/* Time in ms after which the dispatcher tries to schedule an unscheduled RB */
-static unsigned int _dispatch_starvation_time = 2000;
+unsigned int adreno_dispatch_starvation_time = 2000;
/* Amount of time in ms that a starved RB is permitted to execute for */
-static unsigned int _dispatch_time_slice = 25;
+unsigned int adreno_dispatch_time_slice = 25;
/*
* If set then dispatcher tries to schedule lower priority RB's after if they
@@ -78,6 +78,24 @@ unsigned int adreno_cmdbatch_timeout = 2000;
/* Interval for reading and comparing fault detection registers */
static unsigned int _fault_timer_interval = 200;
+#define CMDQUEUE_RB(_cmdqueue) \
+ ((struct adreno_ringbuffer *) \
+ container_of((_cmdqueue), struct adreno_ringbuffer, dispatch_q))
+
+#define CMDQUEUE(_ringbuffer) (&(_ringbuffer)->dispatch_q)
+
+static int adreno_dispatch_retire_cmdqueue(struct adreno_device *adreno_dev,
+ struct adreno_dispatcher_cmdqueue *cmdqueue);
+
+static inline bool cmdqueue_is_current(
+ struct adreno_dispatcher_cmdqueue *cmdqueue)
+{
+ struct adreno_ringbuffer *rb = CMDQUEUE_RB(cmdqueue);
+ struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
+
+ return (adreno_dev->cur_rb == rb);
+}
+
static void _add_context(struct adreno_device *adreno_dev,
struct adreno_context *drawctxt)
{
@@ -283,7 +301,8 @@ static void _retire_marker(struct kgsl_cmdbatch *cmdbatch)
/* Retire pending GPU events for the object */
kgsl_process_event_group(device, &context->events);
- trace_adreno_cmdbatch_retired(cmdbatch, -1, 0, 0, drawctxt->rb);
+ trace_adreno_cmdbatch_retired(cmdbatch, -1, 0, 0, drawctxt->rb,
+ adreno_get_rptr(drawctxt->rb));
kgsl_cmdbatch_destroy(cmdbatch);
}
@@ -576,8 +595,15 @@ static int sendcmd(struct adreno_device *adreno_dev,
if (dispatcher->inflight == 1) {
if (ret == 0) {
+
+ /* Stop fault timer before reading fault registers */
+ del_timer_sync(&dispatcher->fault_timer);
+
fault_detect_read(adreno_dev);
+ /* Start the fault timer on first submission */
+ start_fault_timer(adreno_dev);
+
if (!test_and_set_bit(ADRENO_DISPATCHER_ACTIVE,
&dispatcher->priv))
reinit_completion(&dispatcher->idle_gate);
@@ -594,11 +620,15 @@ static int sendcmd(struct adreno_device *adreno_dev,
dispatch_q->inflight--;
/*
+ * Don't log a message in case of:
* -ENOENT means that the context was detached before the
- * command was submitted - don't log a message in that case
+ * command was submitted
+ * -ENOSPC means that there temporarily isn't any room in the
+ * ringbuffer
+ * -PROTO means that a fault is currently being worked
*/
- if (ret != -ENOENT)
+ if (ret != -ENOENT && ret != -ENOSPC && ret != -EPROTO)
KGSL_DRV_ERR(device,
"Unable to submit command to the ringbuffer %d\n",
ret);
@@ -609,7 +639,8 @@ static int sendcmd(struct adreno_device *adreno_dev,
nsecs = do_div(secs, 1000000000);
trace_adreno_cmdbatch_submitted(cmdbatch, (int) dispatcher->inflight,
- time.ticks, (unsigned long) secs, nsecs / 1000, drawctxt->rb);
+ time.ticks, (unsigned long) secs, nsecs / 1000, drawctxt->rb,
+ adreno_get_rptr(drawctxt->rb));
cmdbatch->submit_ticks = time.ticks;
@@ -618,28 +649,26 @@ static int sendcmd(struct adreno_device *adreno_dev,
ADRENO_DISPATCH_CMDQUEUE_SIZE;
/*
- * If this is the first command in the pipe then the GPU will
- * immediately start executing it so we can start the expiry timeout on
- * the command batch here. Subsequent command batches will have their
- * timer started when the previous command batch is retired.
- * Set the timer if the cmdbatch was submitted to current
- * active RB else this timer will need to be set when the
- * RB becomes active, also if dispatcher is not is CLEAR
- * state then the cmdbatch it is currently executing is
- * unclear so do not set timer in that case either.
+ * For the first submission in any given command queue update the
+ * expected expire time - this won't actually be used / updated until
+ * the command queue in question goes current, but universally setting
+ * it here avoids the possibilty of some race conditions with preempt
*/
- if (1 == dispatch_q->inflight &&
- (&(adreno_dev->cur_rb->dispatch_q)) == dispatch_q &&
- adreno_preempt_state(adreno_dev,
- ADRENO_DISPATCHER_PREEMPT_CLEAR)) {
- cmdbatch->expires = jiffies +
+
+ if (dispatch_q->inflight == 1)
+ dispatch_q->expires = jiffies +
msecs_to_jiffies(adreno_cmdbatch_timeout);
- mod_timer(&dispatcher->timer, cmdbatch->expires);
+
+ /*
+ * If we believe ourselves to be current and preemption isn't a thing,
+ * then set up the timer. If this misses, then preemption is indeed a
+ * thing and the timer will be set up in due time
+ */
+ if (!adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) {
+ if (cmdqueue_is_current(dispatch_q))
+ mod_timer(&dispatcher->timer, dispatch_q->expires);
}
- /* Start the fault detection timer on the first submission */
- if (dispatcher->inflight == 1)
- start_fault_timer(adreno_dev);
/*
* we just submitted something, readjust ringbuffer
@@ -924,87 +953,6 @@ static int get_timestamp(struct adreno_context *drawctxt,
}
/**
- * adreno_dispatcher_preempt_timer() - Timer that triggers when preemption has
- * not completed
- * @data: Pointer to adreno device that did not preempt in timely manner
- */
-static void adreno_dispatcher_preempt_timer(unsigned long data)
-{
- struct adreno_device *adreno_dev = (struct adreno_device *) data;
- struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-
- KGSL_DRV_ERR(KGSL_DEVICE(adreno_dev),
- "Preemption timed out. cur_rb rptr/wptr %x/%x id %d, next_rb rptr/wptr %x/%x id %d, disp_state: %d\n",
- adreno_dev->cur_rb->rptr, adreno_dev->cur_rb->wptr,
- adreno_dev->cur_rb->id, adreno_dev->next_rb->rptr,
- adreno_dev->next_rb->wptr, adreno_dev->next_rb->id,
- atomic_read(&dispatcher->preemption_state));
- adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT);
- adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev));
-}
-
-/**
- * adreno_dispatcher_get_highest_busy_rb() - Returns the highest priority RB
- * which is busy
- * @adreno_dev: Device whose RB is returned
- */
-struct adreno_ringbuffer *adreno_dispatcher_get_highest_busy_rb(
- struct adreno_device *adreno_dev)
-{
- struct adreno_ringbuffer *rb, *highest_busy_rb = NULL;
- int i;
-
- FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
- if (rb->rptr != rb->wptr && !highest_busy_rb) {
- highest_busy_rb = rb;
- goto done;
- }
-
- if (!adreno_disp_preempt_fair_sched)
- continue;
-
- switch (rb->starve_timer_state) {
- case ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT:
- if (rb->rptr != rb->wptr &&
- adreno_dev->cur_rb != rb) {
- rb->starve_timer_state =
- ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT;
- rb->sched_timer = jiffies;
- }
- break;
- case ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT:
- if (time_after(jiffies, rb->sched_timer +
- msecs_to_jiffies(_dispatch_starvation_time))) {
- rb->starve_timer_state =
- ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED;
- /* halt dispatcher to remove starvation */
- adreno_get_gpu_halt(adreno_dev);
- }
- break;
- case ADRENO_DISPATCHER_RB_STARVE_TIMER_SCHEDULED:
- BUG_ON(adreno_dev->cur_rb != rb);
- /*
- * If the RB has not been running for the minimum
- * time slice then allow it to run
- */
- if ((rb->rptr != rb->wptr) && time_before(jiffies,
- adreno_dev->cur_rb->sched_timer +
- msecs_to_jiffies(_dispatch_time_slice)))
- highest_busy_rb = rb;
- else
- rb->starve_timer_state =
- ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT;
- break;
- case ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED:
- default:
- break;
- }
- }
-done:
- return highest_busy_rb;
-}
-
-/**
* adreno_dispactcher_queue_cmd() - Queue a new command in the context
* @adreno_dev: Pointer to the adreno device struct
* @drawctxt: Pointer to the adreno draw context
@@ -1433,7 +1381,7 @@ static void adreno_fault_header(struct kgsl_device *device,
if (rb != NULL)
pr_fault(device, cmdbatch,
"gpu fault rb %d rb sw r/w %4.4x/%4.4x\n",
- rb->id, rb->rptr, rb->wptr);
+ rb->id, rptr, rb->wptr);
} else {
int id = (rb != NULL) ? rb->id : -1;
@@ -1444,7 +1392,7 @@ static void adreno_fault_header(struct kgsl_device *device,
if (rb != NULL)
dev_err(device->dev,
"RB[%d] gpu fault rb sw r/w %4.4x/%4.4x\n",
- rb->id, rb->rptr, rb->wptr);
+ rb->id, rptr, rb->wptr);
}
}
@@ -1751,6 +1699,27 @@ replay:
kfree(replay);
}
+static void do_header_and_snapshot(struct kgsl_device *device,
+ struct adreno_ringbuffer *rb, struct kgsl_cmdbatch *cmdbatch)
+{
+ /* Always dump the snapshot on a non-cmdbatch failure */
+ if (cmdbatch == NULL) {
+ adreno_fault_header(device, rb, NULL);
+ kgsl_device_snapshot(device, NULL);
+ return;
+ }
+
+ /* Skip everything if the PMDUMP flag is set */
+ if (test_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy))
+ return;
+
+ /* Print the fault header */
+ adreno_fault_header(device, rb, cmdbatch);
+
+ if (!(cmdbatch->context->flags & KGSL_CONTEXT_NO_SNAPSHOT))
+ kgsl_device_snapshot(device, cmdbatch->context);
+}
+
static int dispatcher_do_fault(struct adreno_device *adreno_dev)
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
@@ -1787,7 +1756,7 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev)
/* Turn off all the timers */
del_timer_sync(&dispatcher->timer);
del_timer_sync(&dispatcher->fault_timer);
- del_timer_sync(&dispatcher->preempt_timer);
+ del_timer_sync(&adreno_dev->preempt.timer);
mutex_lock(&device->mutex);
@@ -1813,14 +1782,12 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev)
* retire cmdbatches from all the dispatch_q's before starting recovery
*/
FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
- adreno_dispatch_process_cmdqueue(adreno_dev,
- &(rb->dispatch_q), 0);
+ adreno_dispatch_retire_cmdqueue(adreno_dev,
+ &(rb->dispatch_q));
/* Select the active dispatch_q */
if (base == rb->buffer_desc.gpuaddr) {
dispatch_q = &(rb->dispatch_q);
hung_rb = rb;
- adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR,
- &hung_rb->rptr);
if (adreno_dev->cur_rb != hung_rb) {
adreno_dev->prev_rb = adreno_dev->cur_rb;
adreno_dev->cur_rb = hung_rb;
@@ -1834,7 +1801,7 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev)
}
}
- if (dispatch_q && (dispatch_q->tail != dispatch_q->head)) {
+ if (!adreno_cmdqueue_is_empty(dispatch_q)) {
cmdbatch = dispatch_q->cmd_q[dispatch_q->head];
trace_adreno_cmdbatch_fault(cmdbatch, fault);
}
@@ -1842,17 +1809,7 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev)
adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE,
ADRENO_REG_CP_IB1_BASE_HI, &base);
- /*
- * Dump the snapshot information if this is the first
- * detected fault for the oldest active command batch
- */
-
- if (cmdbatch == NULL ||
- !test_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy)) {
- adreno_fault_header(device, hung_rb, cmdbatch);
- kgsl_device_snapshot(device,
- cmdbatch ? cmdbatch->context : NULL);
- }
+ do_header_and_snapshot(device, hung_rb, cmdbatch);
/* Terminate the stalled transaction and resume the IOMMU */
if (fault & ADRENO_IOMMU_PAGE_FAULT)
@@ -1860,8 +1817,6 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev)
/* Reset the dispatcher queue */
dispatcher->inflight = 0;
- atomic_set(&dispatcher->preemption_state,
- ADRENO_DISPATCHER_PREEMPT_CLEAR);
/* Reset the GPU and make sure halt is not set during recovery */
halt = adreno_gpu_halt(adreno_dev);
@@ -1875,12 +1830,12 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev)
if (hung_rb != NULL) {
kgsl_sharedmem_writel(device, &device->memstore,
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_MAX + hung_rb->id,
- soptimestamp), hung_rb->timestamp);
+ MEMSTORE_RB_OFFSET(hung_rb, soptimestamp),
+ hung_rb->timestamp);
kgsl_sharedmem_writel(device, &device->memstore,
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_MAX + hung_rb->id,
- eoptimestamp), hung_rb->timestamp);
+ MEMSTORE_RB_OFFSET(hung_rb, eoptimestamp),
+ hung_rb->timestamp);
/* Schedule any pending events to be run */
kgsl_process_event_group(device, &hung_rb->events);
@@ -1953,139 +1908,170 @@ static void cmdbatch_profile_ticks(struct adreno_device *adreno_dev,
*retire = entry->retired;
}
-int adreno_dispatch_process_cmdqueue(struct adreno_device *adreno_dev,
- struct adreno_dispatcher_cmdqueue *dispatch_q,
- int long_ib_detect)
+static void retire_cmdbatch(struct adreno_device *adreno_dev,
+ struct kgsl_cmdbatch *cmdbatch)
{
- struct adreno_dispatcher *dispatcher = &(adreno_dev->dispatcher);
- uint64_t start_ticks = 0, retire_ticks = 0;
+ struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
+ struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context);
+ uint64_t start = 0, end = 0;
- struct adreno_dispatcher_cmdqueue *active_q =
- &(adreno_dev->cur_rb->dispatch_q);
+ if (cmdbatch->fault_recovery != 0) {
+ set_bit(ADRENO_CONTEXT_FAULT, &cmdbatch->context->priv);
+ _print_recovery(KGSL_DEVICE(adreno_dev), cmdbatch);
+ }
+
+ if (test_bit(CMDBATCH_FLAG_PROFILE, &cmdbatch->priv))
+ cmdbatch_profile_ticks(adreno_dev, cmdbatch, &start, &end);
+
+ trace_adreno_cmdbatch_retired(cmdbatch, (int) dispatcher->inflight,
+ start, end, ADRENO_CMDBATCH_RB(cmdbatch),
+ adreno_get_rptr(drawctxt->rb));
+
+ drawctxt->submit_retire_ticks[drawctxt->ticks_index] =
+ end - cmdbatch->submit_ticks;
+
+ drawctxt->ticks_index = (drawctxt->ticks_index + 1) %
+ SUBMIT_RETIRE_TICKS_SIZE;
+
+ kgsl_cmdbatch_destroy(cmdbatch);
+}
+
+static int adreno_dispatch_retire_cmdqueue(struct adreno_device *adreno_dev,
+ struct adreno_dispatcher_cmdqueue *cmdqueue)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
int count = 0;
- while (dispatch_q->head != dispatch_q->tail) {
+ while (!adreno_cmdqueue_is_empty(cmdqueue)) {
struct kgsl_cmdbatch *cmdbatch =
- dispatch_q->cmd_q[dispatch_q->head];
- struct adreno_context *drawctxt;
- BUG_ON(cmdbatch == NULL);
+ cmdqueue->cmd_q[cmdqueue->head];
- drawctxt = ADRENO_CONTEXT(cmdbatch->context);
+ if (!kgsl_check_timestamp(device, cmdbatch->context,
+ cmdbatch->timestamp))
+ break;
- /*
- * First try to expire the timestamp. This happens if the
- * context is valid and the timestamp expired normally or if the
- * context was destroyed before the command batch was finished
- * in the GPU. Either way retire the command batch advance the
- * pointers and continue processing the queue
- */
+ retire_cmdbatch(adreno_dev, cmdbatch);
- if (kgsl_check_timestamp(KGSL_DEVICE(adreno_dev),
- cmdbatch->context, cmdbatch->timestamp)) {
+ dispatcher->inflight--;
+ cmdqueue->inflight--;
- /*
- * If the cmdbatch in question had faulted announce its
- * successful completion to the world
- */
+ cmdqueue->cmd_q[cmdqueue->head] = NULL;
- if (cmdbatch->fault_recovery != 0) {
- /* Mark the context as faulted and recovered */
- set_bit(ADRENO_CONTEXT_FAULT,
- &cmdbatch->context->priv);
+ cmdqueue->head = CMDQUEUE_NEXT(cmdqueue->head,
+ ADRENO_DISPATCH_CMDQUEUE_SIZE);
- _print_recovery(KGSL_DEVICE(adreno_dev),
- cmdbatch);
- }
+ count++;
+ }
- /* Reduce the number of inflight command batches */
- dispatcher->inflight--;
- dispatch_q->inflight--;
+ return count;
+}
- /*
- * If kernel profiling is enabled get the submit and
- * retired ticks from the buffer
- */
+static void _adreno_dispatch_check_timeout(struct adreno_device *adreno_dev,
+ struct adreno_dispatcher_cmdqueue *cmdqueue)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct kgsl_cmdbatch *cmdbatch = cmdqueue->cmd_q[cmdqueue->head];
- if (test_bit(CMDBATCH_FLAG_PROFILE, &cmdbatch->priv))
- cmdbatch_profile_ticks(adreno_dev, cmdbatch,
- &start_ticks, &retire_ticks);
+ /* Don't timeout if the timer hasn't expired yet (duh) */
+ if (time_is_after_jiffies(cmdqueue->expires))
+ return;
- trace_adreno_cmdbatch_retired(cmdbatch,
- (int) dispatcher->inflight, start_ticks,
- retire_ticks, ADRENO_CMDBATCH_RB(cmdbatch));
+ /* Don't timeout if the IB timeout is disabled globally */
+ if (!adreno_long_ib_detect(adreno_dev))
+ return;
- /* Record the delta between submit and retire ticks */
- drawctxt->submit_retire_ticks[drawctxt->ticks_index] =
- retire_ticks - cmdbatch->submit_ticks;
+ /* Don't time out if the context has disabled it */
+ if (cmdbatch->context->flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
+ return;
- drawctxt->ticks_index = (drawctxt->ticks_index + 1)
- % SUBMIT_RETIRE_TICKS_SIZE;
+ pr_context(device, cmdbatch->context, "gpu timeout ctx %d ts %d\n",
+ cmdbatch->context->id, cmdbatch->timestamp);
- /* Zero the old entry*/
- dispatch_q->cmd_q[dispatch_q->head] = NULL;
+ adreno_set_gpu_fault(adreno_dev, ADRENO_TIMEOUT_FAULT);
+}
- /* Advance the buffer head */
- dispatch_q->head = CMDQUEUE_NEXT(dispatch_q->head,
- ADRENO_DISPATCH_CMDQUEUE_SIZE);
+static int adreno_dispatch_process_cmdqueue(struct adreno_device *adreno_dev,
+ struct adreno_dispatcher_cmdqueue *cmdqueue)
+{
+ int count = adreno_dispatch_retire_cmdqueue(adreno_dev, cmdqueue);
- /* Destroy the retired command batch */
- kgsl_cmdbatch_destroy(cmdbatch);
+ /* Nothing to do if there are no pending commands */
+ if (adreno_cmdqueue_is_empty(cmdqueue))
+ return count;
- /* Update the expire time for the next command batch */
+ /* Don't update the cmdqueue timeout if we are about to preempt out */
+ if (!adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE))
+ return count;
- if (dispatch_q->inflight > 0 &&
- dispatch_q == active_q) {
- cmdbatch =
- dispatch_q->cmd_q[dispatch_q->head];
- cmdbatch->expires = jiffies +
- msecs_to_jiffies(
- adreno_cmdbatch_timeout);
- }
+ /* Don't update the cmdqueue timeout if it isn't active */
+ if (!cmdqueue_is_current(cmdqueue))
+ return count;
- count++;
- continue;
- }
- /*
- * Break here if fault detection is disabled for the context or
- * if the long running IB detection is disaled device wide or
- * if the dispatch q is not active
- * Long running command buffers will be allowed to run to
- * completion - but badly behaving command buffers (infinite
- * shaders etc) can end up running forever.
- */
+ /*
+ * If the current ringbuffer retired any commands then universally
+ * reset the timeout
+ */
- if (!long_ib_detect ||
- drawctxt->base.flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE
- || dispatch_q != active_q)
- break;
+ if (count) {
+ cmdqueue->expires = jiffies +
+ msecs_to_jiffies(adreno_cmdbatch_timeout);
+ return count;
+ }
- /*
- * The last line of defense is to check if the command batch has
- * timed out. If we get this far but the timeout hasn't expired
- * yet then the GPU is still ticking away
- */
+ /*
+ * If we get here then 1) the ringbuffer is current and 2) we haven't
+ * retired anything. Check to see if the timeout if valid for the
+ * current cmdbatch and fault if it has expired
+ */
+ _adreno_dispatch_check_timeout(adreno_dev, cmdqueue);
+ return 0;
+}
- if (time_is_after_jiffies(cmdbatch->expires))
- break;
+/* Update the dispatcher timers */
+static void _dispatcher_update_timers(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
- /* Boom goes the dynamite */
+ /* Kick the idle timer */
+ mutex_lock(&device->mutex);
+ kgsl_pwrscale_update(device);
+ mod_timer(&device->idle_timer,
+ jiffies + device->pwrctrl.interval_timeout);
+ mutex_unlock(&device->mutex);
- pr_context(KGSL_DEVICE(adreno_dev), cmdbatch->context,
- "gpu timeout ctx %d ts %d\n",
- cmdbatch->context->id, cmdbatch->timestamp);
+ /* Check to see if we need to update the command timer */
+ if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) {
+ struct adreno_dispatcher_cmdqueue *cmdqueue =
+ CMDQUEUE(adreno_dev->cur_rb);
- adreno_set_gpu_fault(adreno_dev, ADRENO_TIMEOUT_FAULT);
- break;
+ if (!adreno_cmdqueue_is_empty(cmdqueue))
+ mod_timer(&dispatcher->timer, cmdqueue->expires);
}
- return count;
}
-/**
- * adreno_dispatcher_work() - Master work handler for the dispatcher
- * @work: Pointer to the work struct for the current work queue
- *
- * Process expired commands and send new ones.
- */
+/* Take down the dispatcher and release any power states */
+static void _dispatcher_power_down(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+ struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
+
+ mutex_lock(&device->mutex);
+
+ if (test_and_clear_bit(ADRENO_DISPATCHER_ACTIVE, &dispatcher->priv))
+ complete_all(&dispatcher->idle_gate);
+
+ del_timer_sync(&dispatcher->fault_timer);
+
+ if (test_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv)) {
+ kgsl_active_count_put(device);
+ clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv);
+ }
+
+ mutex_unlock(&device->mutex);
+}
+
static void adreno_dispatcher_work(struct work_struct *work)
{
struct adreno_dispatcher *dispatcher =
@@ -2095,95 +2081,50 @@ static void adreno_dispatcher_work(struct work_struct *work)
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
int count = 0;
- int cur_rb_id = adreno_dev->cur_rb->id;
+ unsigned int i = 0;
mutex_lock(&dispatcher->mutex);
- if (ADRENO_DISPATCHER_PREEMPT_CLEAR ==
- atomic_read(&dispatcher->preemption_state))
- /* process the active q*/
- count = adreno_dispatch_process_cmdqueue(adreno_dev,
- &(adreno_dev->cur_rb->dispatch_q),
- adreno_long_ib_detect(adreno_dev));
-
- else if (ADRENO_DISPATCHER_PREEMPT_TRIGGERED ==
- atomic_read(&dispatcher->preemption_state))
- count = adreno_dispatch_process_cmdqueue(adreno_dev,
- &(adreno_dev->cur_rb->dispatch_q), 0);
-
- /* Check if gpu fault occurred */
- if (dispatcher_do_fault(adreno_dev))
- goto done;
-
- if (gpudev->preemption_schedule)
- gpudev->preemption_schedule(adreno_dev);
-
- if (cur_rb_id != adreno_dev->cur_rb->id) {
- struct adreno_dispatcher_cmdqueue *dispatch_q =
- &(adreno_dev->cur_rb->dispatch_q);
- /* active level switched, clear new level cmdbatches */
- count = adreno_dispatch_process_cmdqueue(adreno_dev,
- dispatch_q,
- adreno_long_ib_detect(adreno_dev));
- /*
- * If GPU has already completed all the commands in new incoming
- * RB then we may not get another interrupt due to which
- * dispatcher may not run again. Schedule dispatcher here so
- * we can come back and process the other RB's if required
- */
- if (dispatch_q->head == dispatch_q->tail)
- adreno_dispatcher_schedule(device);
- }
/*
- * If inflight went to 0, queue back up the event processor to catch
- * stragglers
+ * As long as there are inflight commands, process retired comamnds from
+ * all cmdqueues
*/
- if (dispatcher->inflight == 0 && count)
- kgsl_schedule_work(&device->event_work);
-
- /* Try to dispatch new commands */
- _adreno_dispatcher_issuecmds(adreno_dev);
-
-done:
- /* Either update the timer for the next command batch or disable it */
- if (dispatcher->inflight) {
- struct kgsl_cmdbatch *cmdbatch =
- adreno_dev->cur_rb->dispatch_q.cmd_q[
- adreno_dev->cur_rb->dispatch_q.head];
- if (cmdbatch && adreno_preempt_state(adreno_dev,
- ADRENO_DISPATCHER_PREEMPT_CLEAR))
- /* Update the timeout timer for the next cmdbatch */
- mod_timer(&dispatcher->timer, cmdbatch->expires);
-
- /* There are still things in flight - update the idle counts */
- mutex_lock(&device->mutex);
- kgsl_pwrscale_update(device);
- mod_timer(&device->idle_timer, jiffies +
- device->pwrctrl.interval_timeout);
- mutex_unlock(&device->mutex);
- } else {
- /* There is nothing left in the pipeline. Shut 'er down boys */
- mutex_lock(&device->mutex);
+ for (i = 0; i < adreno_dev->num_ringbuffers; i++) {
+ struct adreno_dispatcher_cmdqueue *cmdqueue =
+ CMDQUEUE(&adreno_dev->ringbuffers[i]);
- if (test_and_clear_bit(ADRENO_DISPATCHER_ACTIVE,
- &dispatcher->priv))
- complete_all(&dispatcher->idle_gate);
+ count += adreno_dispatch_process_cmdqueue(adreno_dev,
+ cmdqueue);
+ if (dispatcher->inflight == 0)
+ break;
+ }
- /*
- * Stop the fault timer before decrementing the active count to
- * avoid reading the hardware registers while we are trying to
- * turn clocks off
- */
- del_timer_sync(&dispatcher->fault_timer);
+ /*
+ * dispatcher_do_fault() returns 0 if no faults occurred. If that is the
+ * case, then clean up preemption and try to schedule more work
+ */
+ if (dispatcher_do_fault(adreno_dev) == 0) {
+ /* Clean up after preemption */
+ if (gpudev->preemption_schedule)
+ gpudev->preemption_schedule(adreno_dev);
- if (test_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv)) {
- kgsl_active_count_put(device);
- clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv);
- }
+ /* Re-kick the event engine to catch stragglers */
+ if (dispatcher->inflight == 0 && count != 0)
+ kgsl_schedule_work(&device->event_work);
- mutex_unlock(&device->mutex);
+ /* Run the scheduler for to dispatch new commands */
+ _adreno_dispatcher_issuecmds(adreno_dev);
}
+ /*
+ * If there are commands pending, update the timers, otherwise release
+ * the power state to prepare for power down
+ */
+ if (dispatcher->inflight > 0)
+ _dispatcher_update_timers(adreno_dev);
+ else
+ _dispatcher_power_down(adreno_dev);
+
mutex_unlock(&dispatcher->mutex);
}
@@ -2305,7 +2246,7 @@ void adreno_dispatcher_close(struct adreno_device *adreno_dev)
FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
struct adreno_dispatcher_cmdqueue *dispatch_q =
&(rb->dispatch_q);
- while (dispatch_q->head != dispatch_q->tail) {
+ while (!adreno_cmdqueue_is_empty(dispatch_q)) {
kgsl_cmdbatch_destroy(
dispatch_q->cmd_q[dispatch_q->head]);
dispatch_q->head = (dispatch_q->head + 1)
@@ -2395,9 +2336,9 @@ static DISPATCHER_UINT_ATTR(fault_throttle_burst, 0644, 0,
static DISPATCHER_UINT_ATTR(disp_preempt_fair_sched, 0644, 0,
adreno_disp_preempt_fair_sched);
static DISPATCHER_UINT_ATTR(dispatch_time_slice, 0644, 0,
- _dispatch_time_slice);
+ adreno_dispatch_time_slice);
static DISPATCHER_UINT_ATTR(dispatch_starvation_time, 0644, 0,
- _dispatch_starvation_time);
+ adreno_dispatch_starvation_time);
static struct attribute *dispatcher_attrs[] = {
&dispatcher_attr_inflight.attr,
@@ -2474,9 +2415,6 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev)
setup_timer(&dispatcher->fault_timer, adreno_dispatcher_fault_timer,
(unsigned long) adreno_dev);
- setup_timer(&dispatcher->preempt_timer, adreno_dispatcher_preempt_timer,
- (unsigned long) adreno_dev);
-
INIT_WORK(&dispatcher->work, adreno_dispatcher_work);
init_completion(&dispatcher->idle_gate);
@@ -2485,9 +2423,6 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev)
plist_head_init(&dispatcher->pending);
spin_lock_init(&dispatcher->plist_lock);
- atomic_set(&dispatcher->preemption_state,
- ADRENO_DISPATCHER_PREEMPT_CLEAR);
-
ret = kobject_init_and_add(&dispatcher->kobj, &ktype_dispatcher,
&device->dev->kobj, "dispatch");
@@ -2544,49 +2479,3 @@ int adreno_dispatcher_idle(struct adreno_device *adreno_dev)
adreno_dispatcher_schedule(device);
return ret;
}
-
-void adreno_preempt_process_dispatch_queue(struct adreno_device *adreno_dev,
- struct adreno_dispatcher_cmdqueue *dispatch_q)
-{
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct kgsl_cmdbatch *cmdbatch;
-
- if (dispatch_q->head != dispatch_q->tail) {
- /*
- * retire cmdbacthes from previous q, and don't check for
- * timeout since the cmdbatch may have been preempted
- */
- adreno_dispatch_process_cmdqueue(adreno_dev,
- dispatch_q, 0);
- }
-
- /* set the timer for the first cmdbatch of active dispatch_q */
- dispatch_q = &(adreno_dev->cur_rb->dispatch_q);
- if (dispatch_q->head != dispatch_q->tail) {
- cmdbatch = dispatch_q->cmd_q[dispatch_q->head];
- cmdbatch->expires = jiffies +
- msecs_to_jiffies(adreno_cmdbatch_timeout);
- }
- kgsl_schedule_work(&device->event_work);
-}
-
-/**
- * adreno_dispatcher_preempt_callback() - Callback funcion for CP_SW interrupt
- * @adreno_dev: The device on which the interrupt occurred
- * @bit: Interrupt bit in the interrupt status register
- */
-void adreno_dispatcher_preempt_callback(struct adreno_device *adreno_dev,
- int bit)
-{
- struct adreno_dispatcher *dispatcher = &(adreno_dev->dispatcher);
-
- if (ADRENO_DISPATCHER_PREEMPT_TRIGGERED !=
- atomic_read(&dispatcher->preemption_state))
- return;
-
- trace_adreno_hw_preempt_trig_to_comp_int(adreno_dev->cur_rb,
- adreno_dev->next_rb);
- atomic_set(&dispatcher->preemption_state,
- ADRENO_DISPATCHER_PREEMPT_COMPLETE);
- adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev));
-}
diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h
index 308d5b936819..699c3e4adb27 100644
--- a/drivers/gpu/msm/adreno_dispatch.h
+++ b/drivers/gpu/msm/adreno_dispatch.h
@@ -11,29 +11,13 @@
*
*/
-
#ifndef ____ADRENO_DISPATCHER_H
#define ____ADRENO_DISPATCHER_H
-/* Time to allow preemption to complete (in ms) */
-#define ADRENO_DISPATCH_PREEMPT_TIMEOUT 10000
-
extern unsigned int adreno_disp_preempt_fair_sched;
extern unsigned int adreno_cmdbatch_timeout;
-
-/**
- * enum adreno_dispatcher_preempt_states - States of dispatcher for ringbuffer
- * preemption
- * @ADRENO_DISPATCHER_PREEMPT_CLEAR: No preemption is underway,
- * only 1 preemption can be underway at any point
- * @ADRENO_DISPATCHER_PREEMPT_TRIGGERED: A preemption is underway
- * @ADRENO_DISPATCHER_PREEMPT_COMPLETE: A preemption has just completed
- */
-enum adreno_dispatcher_preempt_states {
- ADRENO_DISPATCHER_PREEMPT_CLEAR = 0,
- ADRENO_DISPATCHER_PREEMPT_TRIGGERED,
- ADRENO_DISPATCHER_PREEMPT_COMPLETE,
-};
+extern unsigned int adreno_dispatch_starvation_time;
+extern unsigned int adreno_dispatch_time_slice;
/**
* enum adreno_dispatcher_starve_timer_states - Starvation control states of
@@ -71,6 +55,7 @@ enum adreno_dispatcher_starve_timer_states {
* @head: Head pointer to the q
* @tail: Queues tail pointer
* @active_context_count: Number of active contexts seen in this rb cmdqueue
+ * @expires: The jiffies value at which this cmdqueue has run too long
*/
struct adreno_dispatcher_cmdqueue {
struct kgsl_cmdbatch *cmd_q[ADRENO_DISPATCH_CMDQUEUE_SIZE];
@@ -78,6 +63,7 @@ struct adreno_dispatcher_cmdqueue {
unsigned int head;
unsigned int tail;
int active_context_count;
+ unsigned long expires;
};
/**
@@ -92,11 +78,6 @@ struct adreno_dispatcher_cmdqueue {
* @work: work_struct to put the dispatcher in a work queue
* @kobj: kobject for the dispatcher directory in the device sysfs node
* @idle_gate: Gate to wait on for dispatcher to idle
- * @preemption_state: Indicated what state the dispatcher is in, states are
- * defined by enum adreno_dispatcher_preempt_states
- * @preempt_token_submit: Indicates if a preempt token has been subnitted in
- * current ringbuffer.
- * @preempt_timer: Timer to track if preemption occured within specified time
* @disp_preempt_fair_sched: If set then dispatcher will try to be fair to
* starving RB's by scheduling them in and enforcing a minimum time slice
* for every RB that is scheduled to run on the device
@@ -113,9 +94,6 @@ struct adreno_dispatcher {
struct work_struct work;
struct kobject kobj;
struct completion idle_gate;
- atomic_t preemption_state;
- int preempt_token_submit;
- struct timer_list preempt_timer;
unsigned int disp_preempt_fair_sched;
};
@@ -141,12 +119,12 @@ void adreno_dispatcher_queue_context(struct kgsl_device *device,
struct adreno_context *drawctxt);
void adreno_dispatcher_preempt_callback(struct adreno_device *adreno_dev,
int bit);
-struct adreno_ringbuffer *adreno_dispatcher_get_highest_busy_rb(
- struct adreno_device *adreno_dev);
-int adreno_dispatch_process_cmdqueue(struct adreno_device *adreno_dev,
- struct adreno_dispatcher_cmdqueue *dispatch_q,
- int long_ib_detect);
void adreno_preempt_process_dispatch_queue(struct adreno_device *adreno_dev,
struct adreno_dispatcher_cmdqueue *dispatch_q);
+static inline bool adreno_cmdqueue_is_empty(
+ struct adreno_dispatcher_cmdqueue *cmdqueue)
+{
+ return (cmdqueue != NULL && cmdqueue->head == cmdqueue->tail);
+}
#endif /* __ADRENO_DISPATCHER_H */
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index d8498d938b6a..fb95f6108fb8 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -346,7 +346,8 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
KGSL_CONTEXT_PWR_CONSTRAINT |
KGSL_CONTEXT_IFH_NOP |
KGSL_CONTEXT_SECURE |
- KGSL_CONTEXT_PREEMPT_STYLE_MASK);
+ KGSL_CONTEXT_PREEMPT_STYLE_MASK |
+ KGSL_CONTEXT_NO_SNAPSHOT);
/* Check for errors before trying to initialize */
@@ -466,20 +467,6 @@ void adreno_drawctxt_detach(struct kgsl_context *context)
list_del_init(&drawctxt->active_node);
spin_unlock(&adreno_dev->active_list_lock);
- /* deactivate context */
- mutex_lock(&device->mutex);
- if (rb->drawctxt_active == drawctxt) {
- if (adreno_dev->cur_rb == rb) {
- if (!kgsl_active_count_get(device)) {
- adreno_drawctxt_switch(adreno_dev, rb, NULL, 0);
- kgsl_active_count_put(device);
- } else
- BUG();
- } else
- adreno_drawctxt_switch(adreno_dev, rb, NULL, 0);
- }
- mutex_unlock(&device->mutex);
-
spin_lock(&drawctxt->lock);
count = drawctxt_detach_cmdbatches(drawctxt, list);
spin_unlock(&drawctxt->lock);
@@ -548,12 +535,21 @@ void adreno_drawctxt_destroy(struct kgsl_context *context)
kfree(drawctxt);
}
+static void _drawctxt_switch_wait_callback(struct kgsl_device *device,
+ struct kgsl_event_group *group,
+ void *priv, int result)
+{
+ struct adreno_context *drawctxt = (struct adreno_context *) priv;
+
+ kgsl_context_put(&drawctxt->base);
+}
+
/**
* adreno_drawctxt_switch - switch the current draw context in a given RB
* @adreno_dev - The 3D device that owns the context
* @rb: The ringubffer pointer on which the current context is being changed
* @drawctxt - the 3D context to switch to
- * @flags - Flags to accompany the switch (from user space)
+ * @flags: Control flags for the switch
*
* Switch the current draw context in given RB
*/
@@ -583,8 +579,7 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
if (drawctxt != NULL && kgsl_context_detached(&drawctxt->base))
return -ENOENT;
- trace_adreno_drawctxt_switch(rb,
- drawctxt, flags);
+ trace_adreno_drawctxt_switch(rb, drawctxt);
/* Get a refcount to the new instance */
if (drawctxt) {
@@ -596,16 +591,18 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev,
/* No context - set the default pagetable and thats it. */
new_pt = device->mmu.defaultpagetable;
}
- ret = adreno_ringbuffer_set_pt_ctx(rb, new_pt, drawctxt);
- if (ret) {
- KGSL_DRV_ERR(device,
- "Failed to set pagetable on rb %d\n", rb->id);
+ ret = adreno_ringbuffer_set_pt_ctx(rb, new_pt, drawctxt, flags);
+ if (ret)
return ret;
- }
- /* Put the old instance of the active drawctxt */
- if (rb->drawctxt_active)
- kgsl_context_put(&rb->drawctxt_active->base);
+ if (rb->drawctxt_active) {
+ /* Wait for the timestamp to expire */
+ if (kgsl_add_event(device, &rb->events, rb->timestamp,
+ _drawctxt_switch_wait_callback,
+ rb->drawctxt_active)) {
+ kgsl_context_put(&rb->drawctxt_active->base);
+ }
+ }
rb->drawctxt_active = drawctxt;
return 0;
diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h
index 7e80247e9322..5ea911954991 100644
--- a/drivers/gpu/msm/adreno_drawctxt.h
+++ b/drivers/gpu/msm/adreno_drawctxt.h
@@ -104,6 +104,9 @@ enum adreno_context_priv {
ADRENO_CONTEXT_SKIP_CMD,
};
+/* Flags for adreno_drawctxt_switch() */
+#define ADRENO_CONTEXT_SWITCH_FORCE_GPU BIT(0)
+
struct kgsl_context *adreno_drawctxt_create(struct kgsl_device_private *,
uint32_t *flags);
diff --git a/drivers/gpu/msm/adreno_ioctl.c b/drivers/gpu/msm/adreno_ioctl.c
index 519087a77b83..0d5e3e094c36 100644
--- a/drivers/gpu/msm/adreno_ioctl.c
+++ b/drivers/gpu/msm/adreno_ioctl.c
@@ -103,7 +103,7 @@ static long adreno_ioctl_preemption_counters_query(
levels_to_copy = gpudev->num_prio_levels;
if (copy_to_user((void __user *) (uintptr_t) read->counters,
- adreno_dev->preemption_counters.hostptr,
+ adreno_dev->preempt.counters.hostptr,
levels_to_copy * size_level))
return -EFAULT;
diff --git a/drivers/gpu/msm/adreno_iommu.c b/drivers/gpu/msm/adreno_iommu.c
index 2eeda01b3c4d..aa00dcb84185 100644
--- a/drivers/gpu/msm/adreno_iommu.c
+++ b/drivers/gpu/msm/adreno_iommu.c
@@ -275,6 +275,7 @@ static bool _ctx_switch_use_cpu_path(
struct adreno_ringbuffer *rb)
{
struct kgsl_mmu *mmu = KGSL_MMU(adreno_dev);
+
/*
* If rb is current, we can use cpu path when GPU is
* idle and we are switching to default pt.
@@ -284,7 +285,7 @@ static bool _ctx_switch_use_cpu_path(
if (adreno_dev->cur_rb == rb)
return adreno_isidle(KGSL_DEVICE(adreno_dev)) &&
(new_pt == mmu->defaultpagetable);
- else if ((rb->wptr == rb->rptr) &&
+ else if (adreno_rb_empty(rb) &&
(new_pt == mmu->defaultpagetable))
return true;
@@ -360,8 +361,7 @@ static unsigned int _adreno_mmu_set_pt_update_condition(
*/
*cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr +
- offsetof(struct adreno_ringbuffer_pagetable_info,
- switch_pt_enable)));
+ PT_INFO_OFFSET(switch_pt_enable)));
*cmds++ = 1;
*cmds++ = cp_packet(adreno_dev, CP_WAIT_MEM_WRITES, 1);
*cmds++ = 0;
@@ -375,14 +375,11 @@ static unsigned int _adreno_mmu_set_pt_update_condition(
*cmds++ = (1 << 8) | (1 << 4) | 3;
cmds += cp_gpuaddr(adreno_dev, cmds,
(adreno_dev->ringbuffers[0].pagetable_desc.gpuaddr +
- offsetof(struct adreno_ringbuffer_pagetable_info,
- current_global_ptname)));
+ PT_INFO_OFFSET(current_global_ptname)));
*cmds++ = ptname;
*cmds++ = 0xFFFFFFFF;
- cmds += cp_gpuaddr(adreno_dev, cmds,
- (rb->pagetable_desc.gpuaddr +
- offsetof(struct adreno_ringbuffer_pagetable_info,
- switch_pt_enable)));
+ cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr +
+ PT_INFO_OFFSET(switch_pt_enable)));
*cmds++ = 0;
*cmds++ = cp_packet(adreno_dev, CP_WAIT_MEM_WRITES, 1);
*cmds++ = 0;
@@ -406,23 +403,18 @@ static unsigned int _adreno_iommu_pt_update_pid_to_mem(
unsigned int *cmds_orig = cmds;
*cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
- cmds += cp_gpuaddr(adreno_dev, cmds,
- (rb->pagetable_desc.gpuaddr +
- offsetof(struct adreno_ringbuffer_pagetable_info,
- current_rb_ptname)));
+ cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr +
+ PT_INFO_OFFSET(current_rb_ptname)));
*cmds++ = ptname;
*cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
cmds += cp_gpuaddr(adreno_dev, cmds,
- (adreno_dev->ringbuffers[0].pagetable_desc.gpuaddr +
- offsetof(struct adreno_ringbuffer_pagetable_info,
- current_global_ptname)));
+ (adreno_dev->ringbuffers[0].pagetable_desc.gpuaddr +
+ PT_INFO_OFFSET(current_global_ptname)));
*cmds++ = ptname;
/* pagetable switch done, Housekeeping: set the switch_pt_enable to 0 */
*cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
- cmds += cp_gpuaddr(adreno_dev, cmds,
- (rb->pagetable_desc.gpuaddr +
- offsetof(struct adreno_ringbuffer_pagetable_info,
- switch_pt_enable)));
+ cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr +
+ PT_INFO_OFFSET(switch_pt_enable)));
*cmds++ = 0;
*cmds++ = cp_packet(adreno_dev, CP_WAIT_MEM_WRITES, 1);
*cmds++ = 0;
@@ -444,14 +436,10 @@ static unsigned int _adreno_iommu_set_pt_v1(struct adreno_ringbuffer *rb,
/* set flag that indicates whether pt switch is required*/
cmds += _adreno_mmu_set_pt_update_condition(rb, cmds, ptname);
*cmds++ = cp_mem_packet(adreno_dev, CP_COND_EXEC, 4, 2);
- cmds += cp_gpuaddr(adreno_dev, cmds,
- (rb->pagetable_desc.gpuaddr +
- offsetof(struct adreno_ringbuffer_pagetable_info,
- switch_pt_enable)));
- cmds += cp_gpuaddr(adreno_dev, cmds,
- (rb->pagetable_desc.gpuaddr +
- offsetof(struct adreno_ringbuffer_pagetable_info,
- switch_pt_enable)));
+ cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr +
+ PT_INFO_OFFSET(switch_pt_enable)));
+ cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr +
+ PT_INFO_OFFSET(switch_pt_enable)));
*cmds++ = 1;
/* Exec count to be filled later */
cond_exec_ptr = cmds;
@@ -566,7 +554,7 @@ static unsigned int _adreno_iommu_set_pt_v2_a5xx(struct kgsl_device *device,
*cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 4, 1);
cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr +
- offsetof(struct adreno_ringbuffer_pagetable_info, ttbr0)));
+ PT_INFO_OFFSET(ttbr0)));
*cmds++ = lower_32_bits(ttbr0);
*cmds++ = upper_32_bits(ttbr0);
*cmds++ = contextidr;
@@ -651,14 +639,14 @@ static unsigned int __add_curr_ctxt_cmds(struct adreno_ringbuffer *rb,
*cmds++ = KGSL_CONTEXT_TO_MEM_IDENTIFIER;
*cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
- cmds += cp_gpuaddr(adreno_dev, cmds, device->memstore.gpuaddr +
- KGSL_MEMSTORE_RB_OFFSET(rb, current_context));
+ cmds += cp_gpuaddr(adreno_dev, cmds,
+ MEMSTORE_RB_GPU_ADDR(device, rb, current_context));
*cmds++ = (drawctxt ? drawctxt->base.id : 0);
*cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
- cmds += cp_gpuaddr(adreno_dev, cmds, device->memstore.gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- current_context));
+ cmds += cp_gpuaddr(adreno_dev, cmds,
+ MEMSTORE_ID_GPU_ADDR(device,
+ KGSL_MEMSTORE_GLOBAL, current_context));
*cmds++ = (drawctxt ? drawctxt->base.id : 0);
/* Invalidate UCHE for new context */
@@ -706,7 +694,7 @@ static void _set_ctxt_cpu(struct adreno_ringbuffer *rb,
}
/* Update rb memstore with current context */
kgsl_sharedmem_writel(device, &device->memstore,
- KGSL_MEMSTORE_RB_OFFSET(rb, current_context),
+ MEMSTORE_RB_OFFSET(rb, current_context),
drawctxt ? drawctxt->base.id : 0);
}
@@ -746,26 +734,11 @@ static int _set_pagetable_cpu(struct adreno_ringbuffer *rb,
if (result)
return result;
/* write the new pt set to memory var */
- kgsl_sharedmem_writel(device,
- &adreno_dev->ringbuffers[0].pagetable_desc,
- offsetof(
- struct adreno_ringbuffer_pagetable_info,
- current_global_ptname), new_pt->name);
+ adreno_ringbuffer_set_global(adreno_dev, new_pt->name);
}
/* Update the RB pagetable info here */
- kgsl_sharedmem_writel(device, &rb->pagetable_desc,
- offsetof(
- struct adreno_ringbuffer_pagetable_info,
- current_rb_ptname), new_pt->name);
- kgsl_sharedmem_writeq(device, &rb->pagetable_desc,
- offsetof(
- struct adreno_ringbuffer_pagetable_info,
- ttbr0), kgsl_mmu_pagetable_get_ttbr0(new_pt));
- kgsl_sharedmem_writel(device, &rb->pagetable_desc,
- offsetof(
- struct adreno_ringbuffer_pagetable_info,
- contextidr), kgsl_mmu_pagetable_get_contextidr(new_pt));
+ adreno_ringbuffer_set_pagetable(rb, new_pt);
return 0;
}
@@ -795,8 +768,6 @@ static int _set_pagetable_gpu(struct adreno_ringbuffer *rb,
return 0;
}
- kgsl_mmu_enable_clk(KGSL_MMU(adreno_dev));
-
cmds += adreno_iommu_set_pt_generate_cmds(rb, cmds, new_pt);
if ((unsigned int) (cmds - link) > (PAGE_SIZE / sizeof(unsigned int))) {
@@ -812,16 +783,6 @@ static int _set_pagetable_gpu(struct adreno_ringbuffer *rb,
KGSL_CMD_FLAGS_PMODE, link,
(unsigned int)(cmds - link));
- /*
- * On error disable the IOMMU clock right away otherwise turn it off
- * after the command has been retired
- */
- if (result)
- kgsl_mmu_disable_clk(KGSL_MMU(adreno_dev));
- else
- adreno_ringbuffer_mmu_disable_clk_on_ts(KGSL_DEVICE(adreno_dev),
- rb, rb->timestamp);
-
kfree(link);
return result;
}
@@ -886,7 +847,8 @@ int adreno_iommu_init(struct adreno_device *adreno_dev)
*/
int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb,
struct kgsl_pagetable *new_pt,
- struct adreno_context *drawctxt)
+ struct adreno_context *drawctxt,
+ unsigned long flags)
{
struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
@@ -897,7 +859,8 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb,
if (rb->drawctxt_active)
cur_pt = rb->drawctxt_active->base.proc_priv->pagetable;
- cpu_path = _ctx_switch_use_cpu_path(adreno_dev, new_pt, rb);
+ cpu_path = !(flags & ADRENO_CONTEXT_SWITCH_FORCE_GPU) &&
+ _ctx_switch_use_cpu_path(adreno_dev, new_pt, rb);
/* Pagetable switch */
if (new_pt != cur_pt) {
@@ -907,10 +870,8 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb,
result = _set_pagetable_gpu(rb, new_pt);
}
- if (result) {
- KGSL_DRV_ERR(device, "Error switching pagetable %d\n", result);
+ if (result)
return result;
- }
/* Context switch */
if (cpu_path)
@@ -918,8 +879,5 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb,
else
result = _set_ctxt_gpu(rb, drawctxt);
- if (result)
- KGSL_DRV_ERR(device, "Error switching context %d\n", result);
-
return result;
}
diff --git a/drivers/gpu/msm/adreno_iommu.h b/drivers/gpu/msm/adreno_iommu.h
index c557c65bb4c9..5a6c2c549370 100644
--- a/drivers/gpu/msm/adreno_iommu.h
+++ b/drivers/gpu/msm/adreno_iommu.h
@@ -17,7 +17,8 @@
#ifdef CONFIG_QCOM_KGSL_IOMMU
int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb,
struct kgsl_pagetable *new_pt,
- struct adreno_context *drawctxt);
+ struct adreno_context *drawctxt,
+ unsigned long flags);
int adreno_iommu_init(struct adreno_device *adreno_dev);
@@ -33,7 +34,8 @@ static inline int adreno_iommu_init(struct adreno_device *adreno_dev)
static inline int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb,
struct kgsl_pagetable *new_pt,
- struct adreno_context *drawctxt)
+ struct adreno_context *drawctxt,
+ unsigned long flags)
{
return 0;
}
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index dceb8fb93461..0160939e97f9 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -30,8 +30,6 @@
#include "a3xx_reg.h"
#include "adreno_a5xx.h"
-#define GSL_RB_NOP_SIZEDWORDS 2
-
#define RB_HOSTPTR(_rb, _pos) \
((unsigned int *) ((_rb)->buffer_desc.hostptr + \
((_pos) * sizeof(unsigned int))))
@@ -50,86 +48,89 @@ static void _cff_write_ringbuffer(struct adreno_ringbuffer *rb)
if (device->cff_dump_enable == 0)
return;
- /*
- * This code is predicated on the fact that we write a full block of
- * stuff without wrapping
- */
- BUG_ON(rb->wptr < rb->last_wptr);
-
- size = (rb->wptr - rb->last_wptr) * sizeof(unsigned int);
+ size = (rb->_wptr - rb->last_wptr) * sizeof(unsigned int);
hostptr = RB_HOSTPTR(rb, rb->last_wptr);
gpuaddr = RB_GPUADDR(rb, rb->last_wptr);
kgsl_cffdump_memcpy(device, gpuaddr, hostptr, size);
+ rb->last_wptr = rb->_wptr;
}
-void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb,
+static void adreno_get_submit_time(struct adreno_device *adreno_dev,
struct adreno_submit_time *time)
{
- struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
- BUG_ON(rb->wptr == 0);
-
- /* Write the changes to CFF if so enabled */
- _cff_write_ringbuffer(rb);
-
+ unsigned long flags;
/*
- * Read the current GPU ticks and wallclock for most accurate
- * profiling
+ * Here we are attempting to create a mapping between the
+ * GPU time domain (alwayson counter) and the CPU time domain
+ * (local_clock) by sampling both values as close together as
+ * possible. This is useful for many types of debugging and
+ * profiling. In order to make this mapping as accurate as
+ * possible, we must turn off interrupts to avoid running
+ * interrupt handlers between the two samples.
*/
- if (time != NULL) {
- /*
- * Here we are attempting to create a mapping between the
- * GPU time domain (alwayson counter) and the CPU time domain
- * (local_clock) by sampling both values as close together as
- * possible. This is useful for many types of debugging and
- * profiling. In order to make this mapping as accurate as
- * possible, we must turn off interrupts to avoid running
- * interrupt handlers between the two samples.
- */
- unsigned long flags;
- local_irq_save(flags);
+ local_irq_save(flags);
- /* Read always on registers */
- if (!adreno_is_a3xx(adreno_dev)) {
- adreno_readreg64(adreno_dev,
- ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO,
- ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI,
- &time->ticks);
+ /* Read always on registers */
+ if (!adreno_is_a3xx(adreno_dev)) {
+ adreno_readreg64(adreno_dev,
+ ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO,
+ ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI,
+ &time->ticks);
- /*
- * Mask hi bits as they may be incorrect on
- * a4x and some a5x
- */
- if (ADRENO_GPUREV(adreno_dev) >= 400 &&
+ /* Mask hi bits as they may be incorrect on some targets */
+ if (ADRENO_GPUREV(adreno_dev) >= 400 &&
ADRENO_GPUREV(adreno_dev) <= ADRENO_REV_A530)
- time->ticks &= 0xFFFFFFFF;
- }
- else
- time->ticks = 0;
+ time->ticks &= 0xFFFFFFFF;
+ } else
+ time->ticks = 0;
- /* Get the kernel clock for time since boot */
- time->ktime = local_clock();
+ /* Get the kernel clock for time since boot */
+ time->ktime = local_clock();
- /* Get the timeofday for the wall time (for the user) */
- getnstimeofday(&time->utime);
+ /* Get the timeofday for the wall time (for the user) */
+ getnstimeofday(&time->utime);
- local_irq_restore(flags);
- }
+ local_irq_restore(flags);
+}
+
+void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev,
+ struct adreno_ringbuffer *rb)
+{
+ unsigned long flags;
- /* Memory barrier before informing the hardware of new commands */
- mb();
+ spin_lock_irqsave(&rb->preempt_lock, flags);
+ if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) {
- if (adreno_preempt_state(adreno_dev, ADRENO_DISPATCHER_PREEMPT_CLEAR) &&
- (adreno_dev->cur_rb == rb)) {
- /*
- * Let the pwrscale policy know that new commands have
- * been submitted.
- */
- kgsl_pwrscale_busy(KGSL_DEVICE(adreno_dev));
- adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr);
+ if (adreno_dev->cur_rb == rb) {
+ /*
+ * Let the pwrscale policy know that new commands have
+ * been submitted.
+ */
+ kgsl_pwrscale_busy(KGSL_DEVICE(adreno_dev));
+ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR,
+ rb->_wptr);
+ }
}
+
+ rb->wptr = rb->_wptr;
+ spin_unlock_irqrestore(&rb->preempt_lock, flags);
+}
+
+void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb,
+ struct adreno_submit_time *time)
+{
+ struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
+
+ /* Write the changes to CFF if so enabled */
+ _cff_write_ringbuffer(rb);
+
+ if (time != NULL)
+ adreno_get_submit_time(adreno_dev, time);
+
+ adreno_ringbuffer_wptr(adreno_dev, rb);
}
int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb,
@@ -141,125 +142,36 @@ int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb,
return adreno_spin_idle(adreno_dev, timeout);
}
-static int
-adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb,
- unsigned int numcmds, int wptr_ahead)
+unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
+ unsigned int dwords)
{
- int nopcount = 0;
- unsigned int freecmds;
- unsigned int wptr = rb->wptr;
- unsigned int *cmds = NULL;
- uint64_t gpuaddr;
- unsigned long wait_time;
- unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
- unsigned int rptr;
struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
+ unsigned int rptr = adreno_get_rptr(rb);
+ unsigned int ret;
- /* if wptr ahead, fill the remaining with NOPs */
- if (wptr_ahead) {
- /* -1 for header */
- nopcount = KGSL_RB_DWORDS - rb->wptr - 1;
-
- cmds = RB_HOSTPTR(rb, rb->wptr);
- gpuaddr = RB_GPUADDR(rb, rb->wptr);
-
- rptr = adreno_get_rptr(rb);
- /* For non current rb we don't expect the rptr to move */
- if ((adreno_dev->cur_rb != rb ||
- !adreno_preempt_state(adreno_dev,
- ADRENO_DISPATCHER_PREEMPT_CLEAR)) &&
- !rptr)
- return -ENOSPC;
-
- /* Make sure that rptr is not 0 before submitting
- * commands at the end of ringbuffer. We do not
- * want the rptr and wptr to become equal when
- * the ringbuffer is not empty */
- wait_time = jiffies + wait_timeout;
- while (!rptr) {
- rptr = adreno_get_rptr(rb);
- if (time_after(jiffies, wait_time))
- return -ETIMEDOUT;
- }
-
- rb->wptr = 0;
- }
-
- rptr = adreno_get_rptr(rb);
- freecmds = rptr - rb->wptr;
- if (freecmds == 0 || freecmds > numcmds)
- goto done;
+ if (rptr <= rb->_wptr) {
+ unsigned int *cmds;
- /* non current rptr will not advance anyway or if preemption underway */
- if (adreno_dev->cur_rb != rb ||
- !adreno_preempt_state(adreno_dev,
- ADRENO_DISPATCHER_PREEMPT_CLEAR)) {
- rb->wptr = wptr;
- return -ENOSPC;
- }
-
- wait_time = jiffies + wait_timeout;
- /* wait for space in ringbuffer */
- while (1) {
- rptr = adreno_get_rptr(rb);
-
- freecmds = rptr - rb->wptr;
-
- if (freecmds == 0 || freecmds > numcmds)
- break;
-
- if (time_after(jiffies, wait_time)) {
- KGSL_DRV_ERR(KGSL_DEVICE(adreno_dev),
- "Timed out waiting for freespace in RB rptr: 0x%x, wptr: 0x%x, rb id %d\n",
- rptr, wptr, rb->id);
- return -ETIMEDOUT;
+ if (rb->_wptr + dwords <= (KGSL_RB_DWORDS - 2)) {
+ ret = rb->_wptr;
+ rb->_wptr = (rb->_wptr + dwords) % KGSL_RB_DWORDS;
+ return RB_HOSTPTR(rb, ret);
}
- }
-done:
- if (wptr_ahead) {
- *cmds = cp_packet(adreno_dev, CP_NOP, nopcount);
- kgsl_cffdump_write(KGSL_DEVICE(adreno_dev), gpuaddr, *cmds);
- }
- return 0;
-}
+ cmds = RB_HOSTPTR(rb, rb->_wptr);
+ *cmds = cp_packet(adreno_dev, CP_NOP,
+ KGSL_RB_DWORDS - rb->_wptr - 1);
-unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
- unsigned int numcmds)
-{
- unsigned int *ptr = NULL;
- int ret = 0;
- unsigned int rptr;
- BUG_ON(numcmds >= KGSL_RB_DWORDS);
-
- rptr = adreno_get_rptr(rb);
- /* check for available space */
- if (rb->wptr >= rptr) {
- /* wptr ahead or equal to rptr */
- /* reserve dwords for nop packet */
- if ((rb->wptr + numcmds) > (KGSL_RB_DWORDS -
- GSL_RB_NOP_SIZEDWORDS))
- ret = adreno_ringbuffer_waitspace(rb, numcmds, 1);
- } else {
- /* wptr behind rptr */
- if ((rb->wptr + numcmds) >= rptr)
- ret = adreno_ringbuffer_waitspace(rb, numcmds, 0);
- /* check for remaining space */
- /* reserve dwords for nop packet */
- if (!ret && (rb->wptr + numcmds) > (KGSL_RB_DWORDS -
- GSL_RB_NOP_SIZEDWORDS))
- ret = adreno_ringbuffer_waitspace(rb, numcmds, 1);
+ rb->_wptr = 0;
}
- if (!ret) {
- rb->last_wptr = rb->wptr;
-
- ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr;
- rb->wptr += numcmds;
- } else
- ptr = ERR_PTR(ret);
+ if (rb->_wptr + dwords < rptr) {
+ ret = rb->_wptr;
+ rb->_wptr = (rb->_wptr + dwords) % KGSL_RB_DWORDS;
+ return RB_HOSTPTR(rb, ret);
+ }
- return ptr;
+ return ERR_PTR(-ENOSPC);
}
/**
@@ -279,8 +191,10 @@ int adreno_ringbuffer_start(struct adreno_device *adreno_dev,
FOR_EACH_RINGBUFFER(adreno_dev, rb, i) {
kgsl_sharedmem_set(device, &(rb->buffer_desc),
0, 0xAA, KGSL_RB_SIZE);
+ kgsl_sharedmem_writel(device, &device->scratch,
+ SCRATCH_RPTR_OFFSET(rb->id), 0);
rb->wptr = 0;
- rb->rptr = 0;
+ rb->_wptr = 0;
rb->wptr_preempt_end = 0xFFFFFFFF;
rb->starve_timer_state =
ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT;
@@ -322,6 +236,8 @@ static int _adreno_ringbuffer_probe(struct adreno_device *adreno_dev,
rb->timestamp = 0;
init_waitqueue_head(&rb->ts_expire_waitq);
+ spin_lock_init(&rb->preempt_lock);
+
/*
* Allocate mem for storing RB pagetables and commands to
* switch pagetable
@@ -433,6 +349,18 @@ int cp_secure_mode(struct adreno_device *adreno_dev, uint *cmds,
return cmds - start;
}
+static inline int cp_mem_write(struct adreno_device *adreno_dev,
+ unsigned int *cmds, uint64_t gpuaddr, unsigned int value)
+{
+ int dwords = 0;
+
+ cmds[dwords++] = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
+ dwords += cp_gpuaddr(adreno_dev, &cmds[dwords], gpuaddr);
+ cmds[dwords++] = value;
+
+ return dwords;
+}
+
static int
adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
unsigned int flags, unsigned int *cmds,
@@ -446,18 +374,20 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
unsigned int total_sizedwords = sizedwords;
unsigned int i;
unsigned int context_id = 0;
- uint64_t gpuaddr = device->memstore.gpuaddr;
bool profile_ready;
struct adreno_context *drawctxt = rb->drawctxt_active;
struct kgsl_context *context = NULL;
bool secured_ctxt = false;
- uint64_t cond_addr;
static unsigned int _seq_cnt;
if (drawctxt != NULL && kgsl_context_detached(&drawctxt->base) &&
!(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))
return -ENOENT;
+ /* On fault return error so that we don't keep submitting */
+ if (adreno_gpu_fault(adreno_dev) != 0)
+ return -EPROTO;
+
rb->timestamp++;
/* If this is a internal IB, use the global timestamp for it */
@@ -529,7 +459,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
* required in ringbuffer and adjust the write pointer depending on
* gpucore at the end of this function.
*/
- total_sizedwords += 4; /* sop timestamp */
+ total_sizedwords += 8; /* sop timestamp */
total_sizedwords += 5; /* eop timestamp */
if (drawctxt && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
@@ -564,14 +494,9 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
*ringcmds++ = KGSL_CMD_IDENTIFIER;
if (adreno_is_preemption_enabled(adreno_dev) &&
- gpudev->preemption_pre_ibsubmit) {
- cond_addr = device->memstore.gpuaddr +
- KGSL_MEMSTORE_OFFSET(context_id,
- preempted);
+ gpudev->preemption_pre_ibsubmit)
ringcmds += gpudev->preemption_pre_ibsubmit(
- adreno_dev, rb, ringcmds, context,
- cond_addr, NULL);
- }
+ adreno_dev, rb, ringcmds, context);
if (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) {
*ringcmds++ = cp_packet(adreno_dev, CP_NOP, 1);
@@ -601,16 +526,15 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
adreno_profile_preib_processing(adreno_dev, drawctxt,
&flags, &ringcmds);
- /* start-of-pipeline timestamp */
- *ringcmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
+ /* start-of-pipeline timestamp for the context */
if (drawctxt && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE))
- ringcmds += cp_gpuaddr(adreno_dev, ringcmds,
- gpuaddr + KGSL_MEMSTORE_OFFSET(context_id,
- soptimestamp));
- else
- ringcmds += cp_gpuaddr(adreno_dev, ringcmds,
- gpuaddr + KGSL_MEMSTORE_RB_OFFSET(rb, soptimestamp));
- *ringcmds++ = timestamp;
+ ringcmds += cp_mem_write(adreno_dev, ringcmds,
+ MEMSTORE_ID_GPU_ADDR(device, context_id, soptimestamp),
+ timestamp);
+
+ /* start-of-pipeline timestamp for the ringbuffer */
+ ringcmds += cp_mem_write(adreno_dev, ringcmds,
+ MEMSTORE_RB_GPU_ADDR(device, rb, soptimestamp), rb->timestamp);
if (secured_ctxt)
ringcmds += cp_secure_mode(adreno_dev, ringcmds, 1);
@@ -659,11 +583,9 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
* early detection of timestamp interrupt storms to stave
* off system collapse.
*/
- *ringcmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
- ringcmds += cp_gpuaddr(adreno_dev, ringcmds, gpuaddr +
- KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
- ref_wait_ts));
- *ringcmds++ = ++_seq_cnt;
+ ringcmds += cp_mem_write(adreno_dev, ringcmds,
+ MEMSTORE_ID_GPU_ADDR(device, KGSL_MEMSTORE_GLOBAL,
+ ref_wait_ts), ++_seq_cnt);
/*
* end-of-pipeline timestamp. If per context timestamps is not
@@ -677,16 +599,17 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
*ringcmds++ = CACHE_FLUSH_TS;
if (drawctxt && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) {
- ringcmds += cp_gpuaddr(adreno_dev, ringcmds, gpuaddr +
- KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp));
+ ringcmds += cp_gpuaddr(adreno_dev, ringcmds,
+ MEMSTORE_ID_GPU_ADDR(device, context_id, eoptimestamp));
*ringcmds++ = timestamp;
- *ringcmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
- ringcmds += cp_gpuaddr(adreno_dev, ringcmds, gpuaddr +
- KGSL_MEMSTORE_RB_OFFSET(rb, eoptimestamp));
- *ringcmds++ = rb->timestamp;
+
+ /* Write the end of pipeline timestamp to the ringbuffer too */
+ ringcmds += cp_mem_write(adreno_dev, ringcmds,
+ MEMSTORE_RB_GPU_ADDR(device, rb, eoptimestamp),
+ rb->timestamp);
} else {
- ringcmds += cp_gpuaddr(adreno_dev, ringcmds, gpuaddr +
- KGSL_MEMSTORE_RB_OFFSET(rb, eoptimestamp));
+ ringcmds += cp_gpuaddr(adreno_dev, ringcmds,
+ MEMSTORE_RB_GPU_ADDR(device, rb, eoptimestamp));
*ringcmds++ = timestamp;
}
@@ -707,8 +630,8 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
if (gpudev->preemption_post_ibsubmit &&
adreno_is_preemption_enabled(adreno_dev))
- ringcmds += gpudev->preemption_post_ibsubmit(adreno_dev, rb,
- ringcmds, &drawctxt->base);
+ ringcmds += gpudev->preemption_post_ibsubmit(adreno_dev,
+ ringcmds);
/*
* If we have more ringbuffer commands than space reserved
@@ -722,7 +645,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb,
* required. If we have commands less than the space reserved in RB
* adjust the wptr accordingly.
*/
- rb->wptr = rb->wptr - (total_sizedwords - (ringcmds - start));
+ rb->_wptr = rb->_wptr - (total_sizedwords - (ringcmds - start));
adreno_ringbuffer_submit(rb, time);
@@ -1063,14 +986,24 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
*cmds++ = cp_packet(adreno_dev, CP_NOP, 1);
*cmds++ = KGSL_END_OF_IB_IDENTIFIER;
- ret = adreno_drawctxt_switch(adreno_dev, rb, drawctxt, cmdbatch->flags);
+ /* Context switches commands should *always* be on the GPU */
+ ret = adreno_drawctxt_switch(adreno_dev, rb, drawctxt,
+ ADRENO_CONTEXT_SWITCH_FORCE_GPU);
/*
* In the unlikely event of an error in the drawctxt switch,
* treat it like a hang
*/
- if (ret)
+ if (ret) {
+ /*
+ * It is "normal" to get a -ENOSPC or a -ENOENT. Don't log it,
+ * the upper layers know how to handle it
+ */
+ if (ret != -ENOSPC && ret != -ENOENT)
+ KGSL_DRV_ERR(device,
+ "Unable to switch draw context: %d\n", ret);
goto done;
+ }
if (test_bit(CMDBATCH_FLAG_WFI, &cmdbatch->priv))
flags = KGSL_CMD_FLAGS_WFI;
@@ -1138,44 +1071,6 @@ done:
}
/**
- * adreno_ringbuffer_mmu_clk_disable_event() - Callback function that
- * disables the MMU clocks.
- * @device: Device pointer
- * @context: The ringbuffer context pointer
- * @data: Pointer containing the adreno_mmu_disable_clk_param structure
- * @type: The event call type (RETIRED or CANCELLED)
- */
-static void adreno_ringbuffer_mmu_clk_disable_event(struct kgsl_device *device,
- struct kgsl_event_group *group, void *data, int type)
-{
- kgsl_mmu_disable_clk(&device->mmu);
-}
-
-/*
- * adreno_ringbuffer_mmu_disable_clk_on_ts() - Sets up event to disable MMU
- * clocks
- * @device - The kgsl device pointer
- * @rb: The ringbuffer in whose event list the event is added
- * @timestamp: The timestamp on which the event should trigger
- *
- * Creates an event to disable the MMU clocks on timestamp and if event
- * already exists then updates the timestamp of disabling the MMU clocks
- * with the passed in ts if it is greater than the current value at which
- * the clocks will be disabled
- * Return - void
- */
-void
-adreno_ringbuffer_mmu_disable_clk_on_ts(struct kgsl_device *device,
- struct adreno_ringbuffer *rb, unsigned int timestamp)
-{
- if (kgsl_add_event(device, &(rb->events), timestamp,
- adreno_ringbuffer_mmu_clk_disable_event, NULL)) {
- KGSL_DRV_ERR(device,
- "Failed to add IOMMU disable clk event\n");
- }
-}
-
-/**
* adreno_ringbuffer_wait_callback() - Callback function for event registered
* on a ringbuffer timestamp
* @device: Device for which the the callback is valid
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index f1980fd92961..b126f710b5e6 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -73,13 +73,16 @@ struct adreno_ringbuffer_pagetable_info {
unsigned int contextidr;
};
+#define PT_INFO_OFFSET(_field) \
+ offsetof(struct adreno_ringbuffer_pagetable_info, _field)
+
/**
* struct adreno_ringbuffer - Definition for an adreno ringbuffer object
* @flags: Internal control flags for the ringbuffer
- * @buffer_desc: Pointer to the ringbuffer memory descriptor
- * @wptr: Local copy of the wptr offset
- * @rptr: Read pointer offset in dwords from baseaddr
- * @last_wptr: offset of the last H/W committed wptr
+ * @buffer_desc: Pointer to the ringbuffer memory descripto
+ * @_wptr: The next value of wptr to be written to the hardware on submit
+ * @wptr: Local copy of the wptr offset last written to hardware
+ * @last_wptr: offset of the last wptr that was written to CFF
* @rb_ctx: The context that represents a ringbuffer
* @id: Priority level of the ringbuffer, also used as an ID
* @fault_detect_ts: The last retired global timestamp read during fault detect
@@ -101,12 +104,13 @@ struct adreno_ringbuffer_pagetable_info {
* @sched_timer: Timer that tracks how long RB has been waiting to be scheduled
* or how long it has been scheduled for after preempting in
* @starve_timer_state: Indicates the state of the wait.
+ * @preempt_lock: Lock to protect the wptr pointer while it is being updated
*/
struct adreno_ringbuffer {
uint32_t flags;
struct kgsl_memdesc buffer_desc;
+ unsigned int _wptr;
unsigned int wptr;
- unsigned int rptr;
unsigned int last_wptr;
int id;
unsigned int fault_detect_ts;
@@ -122,14 +126,12 @@ struct adreno_ringbuffer {
int preempted_midway;
unsigned long sched_timer;
enum adreno_dispatcher_starve_timer_states starve_timer_state;
+ spinlock_t preempt_lock;
};
/* Returns the current ringbuffer */
#define ADRENO_CURRENT_RINGBUFFER(a) ((a)->cur_rb)
-#define KGSL_MEMSTORE_RB_OFFSET(rb, field) \
- KGSL_MEMSTORE_OFFSET((rb->id + KGSL_MEMSTORE_MAX), field)
-
int cp_secure_mode(struct adreno_device *adreno_dev, uint *cmds, int set);
int adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
@@ -170,9 +172,6 @@ void adreno_ringbuffer_read_pfp_ucode(struct kgsl_device *device);
void adreno_ringbuffer_read_pm4_ucode(struct kgsl_device *device);
-void adreno_ringbuffer_mmu_disable_clk_on_ts(struct kgsl_device *device,
- struct adreno_ringbuffer *rb, unsigned int ts);
-
int adreno_ringbuffer_waittimestamp(struct adreno_ringbuffer *rb,
unsigned int timestamp,
unsigned int msecs);
@@ -204,9 +203,10 @@ static inline unsigned int adreno_ringbuffer_dec_wrapped(unsigned int val,
}
static inline int adreno_ringbuffer_set_pt_ctx(struct adreno_ringbuffer *rb,
- struct kgsl_pagetable *pt, struct adreno_context *context)
+ struct kgsl_pagetable *pt, struct adreno_context *context,
+ unsigned long flags)
{
- return adreno_iommu_set_pt_ctx(rb, pt, context);
+ return adreno_iommu_set_pt_ctx(rb, pt, context, flags);
}
#endif /* __ADRENO_RINGBUFFER_H */
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index ca61d36a1384..b069b16c75ef 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -467,7 +467,7 @@ static size_t snapshot_rb(struct kgsl_device *device, u8 *buf,
header->start = 0;
header->end = KGSL_RB_DWORDS;
header->wptr = rb->wptr;
- header->rptr = rb->rptr;
+ header->rptr = adreno_get_rptr(rb);
header->rbsize = KGSL_RB_DWORDS;
header->count = KGSL_RB_DWORDS;
adreno_rb_readtimestamp(adreno_dev, rb, KGSL_TIMESTAMP_QUEUED,
@@ -741,8 +741,7 @@ static size_t snapshot_global(struct kgsl_device *device, u8 *buf,
header->size = memdesc->size >> 2;
header->gpuaddr = memdesc->gpuaddr;
- header->ptbase =
- kgsl_mmu_pagetable_get_ttbr0(device->mmu.defaultpagetable);
+ header->ptbase = MMU_DEFAULT_TTBR0(device);
header->type = SNAPSHOT_GPU_OBJECT_GLOBAL;
memcpy(ptr, memdesc->hostptr, memdesc->size);
diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h
index 5f1bbb9a83b3..f52ddfa894d5 100644
--- a/drivers/gpu/msm/adreno_trace.h
+++ b/drivers/gpu/msm/adreno_trace.h
@@ -55,8 +55,8 @@ TRACE_EVENT(adreno_cmdbatch_queued,
TRACE_EVENT(adreno_cmdbatch_submitted,
TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight, uint64_t ticks,
unsigned long secs, unsigned long usecs,
- struct adreno_ringbuffer *rb),
- TP_ARGS(cmdbatch, inflight, ticks, secs, usecs, rb),
+ struct adreno_ringbuffer *rb, unsigned int rptr),
+ TP_ARGS(cmdbatch, inflight, ticks, secs, usecs, rb, rptr),
TP_STRUCT__entry(
__field(unsigned int, id)
__field(unsigned int, timestamp)
@@ -81,7 +81,7 @@ TRACE_EVENT(adreno_cmdbatch_submitted,
__entry->usecs = usecs;
__entry->prio = cmdbatch->context->priority;
__entry->rb_id = rb->id;
- __entry->rptr = rb->rptr;
+ __entry->rptr = rptr;
__entry->wptr = rb->wptr;
__entry->q_inflight = rb->dispatch_q.inflight;
),
@@ -100,8 +100,8 @@ TRACE_EVENT(adreno_cmdbatch_submitted,
TRACE_EVENT(adreno_cmdbatch_retired,
TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight,
uint64_t start, uint64_t retire,
- struct adreno_ringbuffer *rb),
- TP_ARGS(cmdbatch, inflight, start, retire, rb),
+ struct adreno_ringbuffer *rb, unsigned int rptr),
+ TP_ARGS(cmdbatch, inflight, start, retire, rb, rptr),
TP_STRUCT__entry(
__field(unsigned int, id)
__field(unsigned int, timestamp)
@@ -126,7 +126,7 @@ TRACE_EVENT(adreno_cmdbatch_retired,
__entry->retire = retire;
__entry->prio = cmdbatch->context->priority;
__entry->rb_id = rb->id;
- __entry->rptr = rb->rptr;
+ __entry->rptr = rptr;
__entry->wptr = rb->wptr;
__entry->q_inflight = rb->dispatch_q.inflight;
),
@@ -267,9 +267,8 @@ TRACE_EVENT(adreno_drawctxt_wait_done,
TRACE_EVENT(adreno_drawctxt_switch,
TP_PROTO(struct adreno_ringbuffer *rb,
- struct adreno_context *newctx,
- unsigned int flags),
- TP_ARGS(rb, newctx, flags),
+ struct adreno_context *newctx),
+ TP_ARGS(rb, newctx),
TP_STRUCT__entry(
__field(int, rb_level)
__field(unsigned int, oldctx)
@@ -283,8 +282,8 @@ TRACE_EVENT(adreno_drawctxt_switch,
__entry->newctx = newctx ? newctx->base.id : 0;
),
TP_printk(
- "rb level=%d oldctx=%u newctx=%u flags=%X",
- __entry->rb_level, __entry->oldctx, __entry->newctx, flags
+ "rb level=%d oldctx=%u newctx=%u",
+ __entry->rb_level, __entry->oldctx, __entry->newctx
)
);
@@ -427,8 +426,9 @@ TRACE_EVENT(kgsl_a5xx_irq_status,
DECLARE_EVENT_CLASS(adreno_hw_preempt_template,
TP_PROTO(struct adreno_ringbuffer *cur_rb,
- struct adreno_ringbuffer *new_rb),
- TP_ARGS(cur_rb, new_rb),
+ struct adreno_ringbuffer *new_rb,
+ unsigned int cur_rptr, unsigned int new_rptr),
+ TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr),
TP_STRUCT__entry(__field(int, cur_level)
__field(int, new_level)
__field(unsigned int, cur_rptr)
@@ -440,8 +440,8 @@ DECLARE_EVENT_CLASS(adreno_hw_preempt_template,
),
TP_fast_assign(__entry->cur_level = cur_rb->id;
__entry->new_level = new_rb->id;
- __entry->cur_rptr = cur_rb->rptr;
- __entry->new_rptr = new_rb->rptr;
+ __entry->cur_rptr = cur_rptr;
+ __entry->new_rptr = new_rptr;
__entry->cur_wptr = cur_rb->wptr;
__entry->new_wptr = new_rb->wptr;
__entry->cur_rbbase = cur_rb->buffer_desc.gpuaddr;
@@ -458,26 +458,30 @@ DECLARE_EVENT_CLASS(adreno_hw_preempt_template,
DEFINE_EVENT(adreno_hw_preempt_template, adreno_hw_preempt_clear_to_trig,
TP_PROTO(struct adreno_ringbuffer *cur_rb,
- struct adreno_ringbuffer *new_rb),
- TP_ARGS(cur_rb, new_rb)
+ struct adreno_ringbuffer *new_rb,
+ unsigned int cur_rptr, unsigned int new_rptr),
+ TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr)
);
DEFINE_EVENT(adreno_hw_preempt_template, adreno_hw_preempt_trig_to_comp,
TP_PROTO(struct adreno_ringbuffer *cur_rb,
- struct adreno_ringbuffer *new_rb),
- TP_ARGS(cur_rb, new_rb)
+ struct adreno_ringbuffer *new_rb,
+ unsigned int cur_rptr, unsigned int new_rptr),
+ TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr)
);
DEFINE_EVENT(adreno_hw_preempt_template, adreno_hw_preempt_trig_to_comp_int,
TP_PROTO(struct adreno_ringbuffer *cur_rb,
- struct adreno_ringbuffer *new_rb),
- TP_ARGS(cur_rb, new_rb)
+ struct adreno_ringbuffer *new_rb,
+ unsigned int cur_rptr, unsigned int new_rptr),
+ TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr)
);
TRACE_EVENT(adreno_hw_preempt_comp_to_clear,
TP_PROTO(struct adreno_ringbuffer *cur_rb,
- struct adreno_ringbuffer *new_rb),
- TP_ARGS(cur_rb, new_rb),
+ struct adreno_ringbuffer *new_rb,
+ unsigned int cur_rptr, unsigned int new_rptr),
+ TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr),
TP_STRUCT__entry(__field(int, cur_level)
__field(int, new_level)
__field(unsigned int, cur_rptr)
@@ -490,8 +494,8 @@ TRACE_EVENT(adreno_hw_preempt_comp_to_clear,
),
TP_fast_assign(__entry->cur_level = cur_rb->id;
__entry->new_level = new_rb->id;
- __entry->cur_rptr = cur_rb->rptr;
- __entry->new_rptr = new_rb->rptr;
+ __entry->cur_rptr = cur_rptr;
+ __entry->new_rptr = new_rptr;
__entry->cur_wptr = cur_rb->wptr;
__entry->new_wptr_end = new_rb->wptr_preempt_end;
__entry->new_wptr = new_rb->wptr;
@@ -509,8 +513,9 @@ TRACE_EVENT(adreno_hw_preempt_comp_to_clear,
TRACE_EVENT(adreno_hw_preempt_token_submit,
TP_PROTO(struct adreno_ringbuffer *cur_rb,
- struct adreno_ringbuffer *new_rb),
- TP_ARGS(cur_rb, new_rb),
+ struct adreno_ringbuffer *new_rb,
+ unsigned int cur_rptr, unsigned int new_rptr),
+ TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr),
TP_STRUCT__entry(__field(int, cur_level)
__field(int, new_level)
__field(unsigned int, cur_rptr)
@@ -523,8 +528,8 @@ TRACE_EVENT(adreno_hw_preempt_token_submit,
),
TP_fast_assign(__entry->cur_level = cur_rb->id;
__entry->new_level = new_rb->id;
- __entry->cur_rptr = cur_rb->rptr;
- __entry->new_rptr = new_rb->rptr;
+ __entry->cur_rptr = cur_rptr;
+ __entry->new_rptr = new_rptr;
__entry->cur_wptr = cur_rb->wptr;
__entry->cur_wptr_end = cur_rb->wptr_preempt_end;
__entry->new_wptr = new_rb->wptr;
@@ -541,23 +546,37 @@ TRACE_EVENT(adreno_hw_preempt_token_submit,
)
);
-TRACE_EVENT(adreno_rb_starve,
- TP_PROTO(struct adreno_ringbuffer *rb),
- TP_ARGS(rb),
- TP_STRUCT__entry(__field(int, id)
- __field(unsigned int, rptr)
- __field(unsigned int, wptr)
+TRACE_EVENT(adreno_preempt_trigger,
+ TP_PROTO(struct adreno_ringbuffer *cur, struct adreno_ringbuffer *next),
+ TP_ARGS(cur, next),
+ TP_STRUCT__entry(
+ __field(struct adreno_ringbuffer *, cur)
+ __field(struct adreno_ringbuffer *, next)
),
- TP_fast_assign(__entry->id = rb->id;
- __entry->rptr = rb->rptr;
- __entry->wptr = rb->wptr;
+ TP_fast_assign(
+ __entry->cur = cur;
+ __entry->next = next;
),
- TP_printk(
- "rb %d r/w %x/%x starved", __entry->id, __entry->rptr,
- __entry->wptr
+ TP_printk("trigger from id=%d to id=%d",
+ __entry->cur->id, __entry->next->id
)
);
+TRACE_EVENT(adreno_preempt_done,
+ TP_PROTO(struct adreno_ringbuffer *cur, struct adreno_ringbuffer *next),
+ TP_ARGS(cur, next),
+ TP_STRUCT__entry(
+ __field(struct adreno_ringbuffer *, cur)
+ __field(struct adreno_ringbuffer *, next)
+ ),
+ TP_fast_assign(
+ __entry->cur = cur;
+ __entry->next = next;
+ ),
+ TP_printk("done switch to id=%d from id=%d",
+ __entry->next->id, __entry->cur->id
+ )
+);
#endif /* _ADRENO_TRACE_H */
/* This part must be outside protection */
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2563591f376e..f77dbb7f20af 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -233,6 +233,8 @@ int kgsl_readtimestamp(struct kgsl_device *device, void *priv,
}
EXPORT_SYMBOL(kgsl_readtimestamp);
+static long gpumem_free_entry(struct kgsl_mem_entry *entry);
+
/* Scheduled by kgsl_mem_entry_put_deferred() */
static void _deferred_put(struct work_struct *work)
{
@@ -247,10 +249,8 @@ kgsl_mem_entry_create(void)
{
struct kgsl_mem_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (entry != NULL) {
+ if (entry != NULL)
kref_init(&entry->refcount);
- INIT_WORK(&entry->work, _deferred_put);
- }
return entry;
}
@@ -1150,6 +1150,8 @@ static int kgsl_open_device(struct kgsl_device *device)
atomic_inc(&device->active_cnt);
kgsl_sharedmem_set(device, &device->memstore, 0, 0,
device->memstore.size);
+ kgsl_sharedmem_set(device, &device->scratch, 0, 0,
+ device->scratch.size);
result = device->ftbl->init(device);
if (result)
@@ -1855,7 +1857,10 @@ static long gpuobj_free_on_timestamp(struct kgsl_device_private *dev_priv,
static void gpuobj_free_fence_func(void *priv)
{
- kgsl_mem_entry_put_deferred((struct kgsl_mem_entry *) priv);
+ struct kgsl_mem_entry *entry = priv;
+
+ INIT_WORK(&entry->work, _deferred_put);
+ queue_work(kgsl_driver.mem_workqueue, &entry->work);
}
static long gpuobj_free_on_fence(struct kgsl_device_private *dev_priv,
@@ -3910,11 +3915,13 @@ int kgsl_device_platform_probe(struct kgsl_device *device)
status = kgsl_allocate_global(device, &device->memstore,
KGSL_MEMSTORE_SIZE, 0, 0);
- if (status != 0) {
- KGSL_DRV_ERR(device, "kgsl_allocate_global failed %d\n",
- status);
+ if (status != 0)
goto error_close_mmu;
- }
+
+ status = kgsl_allocate_global(device, &device->scratch,
+ PAGE_SIZE, 0, 0);
+ if (status != 0)
+ goto error_free_memstore;
/*
* The default request type PM_QOS_REQ_ALL_CORES is
@@ -3964,6 +3971,8 @@ int kgsl_device_platform_probe(struct kgsl_device *device)
return 0;
+error_free_memstore:
+ kgsl_free_global(device, &device->memstore);
error_close_mmu:
kgsl_mmu_close(device);
error_pwrctrl_close:
@@ -3990,6 +3999,8 @@ void kgsl_device_platform_remove(struct kgsl_device *device)
idr_destroy(&device->context_idr);
+ kgsl_free_global(device, &device->scratch);
+
kgsl_free_global(device, &device->memstore);
kgsl_mmu_close(device);
@@ -4091,8 +4102,9 @@ static int __init kgsl_core_init(void)
INIT_LIST_HEAD(&kgsl_driver.pagetable_list);
kgsl_driver.workqueue = create_singlethread_workqueue("kgsl-workqueue");
- kgsl_driver.mem_workqueue =
- create_singlethread_workqueue("kgsl-mementry");
+
+ kgsl_driver.mem_workqueue = alloc_workqueue("kgsl-mementry",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
kgsl_events_init();
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index dfe83be799b3..c172021c8944 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -37,6 +37,32 @@
#define KGSL_MEMSTORE_MAX (KGSL_MEMSTORE_SIZE / \
sizeof(struct kgsl_devmemstore) - 1 - KGSL_PRIORITY_MAX_RB_LEVELS)
+#define MEMSTORE_RB_OFFSET(rb, field) \
+ KGSL_MEMSTORE_OFFSET(((rb)->id + KGSL_MEMSTORE_MAX), field)
+
+#define MEMSTORE_ID_GPU_ADDR(dev, iter, field) \
+ ((dev)->memstore.gpuaddr + KGSL_MEMSTORE_OFFSET(iter, field))
+
+#define MEMSTORE_RB_GPU_ADDR(dev, rb, field) \
+ ((dev)->memstore.gpuaddr + \
+ KGSL_MEMSTORE_OFFSET(((rb)->id + KGSL_MEMSTORE_MAX), field))
+
+/*
+ * SCRATCH MEMORY: The scratch memory is one page worth of data that
+ * is mapped into the GPU. This allows for some 'shared' data between
+ * the GPU and CPU. For example, it will be used by the GPU to write
+ * each updated RPTR for each RB.
+ *
+ * Used Data:
+ * Offset: Length(bytes): What
+ * 0x0: 4 * KGSL_PRIORITY_MAX_RB_LEVELS: RB0 RPTR
+ */
+
+/* Shadow global helpers */
+#define SCRATCH_RPTR_OFFSET(id) ((id) * sizeof(unsigned int))
+#define SCRATCH_RPTR_GPU_ADDR(dev, id) \
+ ((dev)->scratch.gpuaddr + SCRATCH_RPTR_OFFSET(id))
+
/* Timestamp window used to detect rollovers (half of integer range) */
#define KGSL_TIMESTAMP_WINDOW 0x80000000
@@ -447,21 +473,6 @@ kgsl_mem_entry_put(struct kgsl_mem_entry *entry)
kref_put(&entry->refcount, kgsl_mem_entry_destroy);
}
-/**
- * kgsl_mem_entry_put_deferred() - Schedule a task to put the memory entry
- * @entry: Mem entry to put
- *
- * This function is for atomic contexts where a normal kgsl_mem_entry_put()
- * would result in the memory entry getting destroyed and possibly taking
- * mutexes along the way. Schedule the work to happen outside of the atomic
- * context.
- */
-static inline void kgsl_mem_entry_put_deferred(struct kgsl_mem_entry *entry)
-{
- if (entry != NULL)
- queue_work(kgsl_driver.mem_workqueue, &entry->work);
-}
-
/*
* kgsl_addr_range_overlap() - Checks if 2 ranges overlap
* @gpuaddr1: Start of first address range
diff --git a/drivers/gpu/msm/kgsl_cmdbatch.h b/drivers/gpu/msm/kgsl_cmdbatch.h
index 1547ac02fdbf..d5cbf375b5d3 100644
--- a/drivers/gpu/msm/kgsl_cmdbatch.h
+++ b/drivers/gpu/msm/kgsl_cmdbatch.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,7 +31,6 @@
* @fault_policy: Internal policy describing how to handle this command in case
* of a fault
* @fault_recovery: recovery actions actually tried for this batch
- * @expires: Point in time when the cmdbatch is considered to be hung
* @refcount: kref structure to maintain the reference count
* @cmdlist: List of IBs to issue
* @memlist: List of all memory used in this command batch
@@ -61,7 +60,6 @@ struct kgsl_cmdbatch {
unsigned long priv;
unsigned long fault_policy;
unsigned long fault_recovery;
- unsigned long expires;
struct kref refcount;
struct list_head cmdlist;
struct list_head memlist;
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index c3fb2b81fcbd..4159a5fe375f 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -227,6 +227,7 @@ struct kgsl_device {
/* GPU shader memory size */
unsigned int shader_mem_len;
struct kgsl_memdesc memstore;
+ struct kgsl_memdesc scratch;
const char *iomemname;
const char *shadermemname;
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index e1f9ad17d0ff..6f70b9ddd376 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2016, 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
@@ -56,6 +56,23 @@ static void _kgsl_event_worker(struct work_struct *work)
kmem_cache_free(events_cache, event);
}
+/* return true if the group needs to be processed */
+static bool _do_process_group(unsigned int processed, unsigned int cur)
+{
+ if (processed == cur)
+ return false;
+
+ /*
+ * This ensures that the timestamp didn't slip back accidently, maybe
+ * due to a memory barrier issue. This is highly unlikely but we've
+ * been burned here in the past.
+ */
+ if ((cur < processed) && ((processed - cur) < KGSL_TIMESTAMP_WINDOW))
+ return false;
+
+ return true;
+}
+
static void _process_event_group(struct kgsl_device *device,
struct kgsl_event_group *group, bool flush)
{
@@ -80,11 +97,7 @@ static void _process_event_group(struct kgsl_device *device,
group->readtimestamp(device, group->priv, KGSL_TIMESTAMP_RETIRED,
&timestamp);
- /*
- * If no timestamps have been retired since the last time we were here
- * then we can avoid going through this loop
- */
- if (!flush && timestamp_cmp(timestamp, group->processed) <= 0)
+ if (!flush && _do_process_group(group->processed, timestamp) == false)
goto out;
list_for_each_entry_safe(event, tmp, &group->events, node) {
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index a338559ac0bb..103d290eb681 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -220,9 +220,6 @@ static int _attach_pt(struct kgsl_iommu_pt *iommu_pt,
if (ret == 0)
iommu_pt->attached = true;
- else
- KGSL_CORE_ERR("iommu_attach_device(%s) failed: %d\n",
- ctx->name, ret);
return ret;
}
@@ -1452,25 +1449,25 @@ done:
return ret;
}
+static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt);
+
static int kgsl_iommu_start(struct kgsl_mmu *mmu)
{
int status;
struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu);
- struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER];
status = _setup_user_context(mmu);
if (status)
return status;
status = _setup_secure_context(mmu);
- if (status)
+ if (status) {
_detach_context(&iommu->ctx[KGSL_IOMMU_CONTEXT_USER]);
- else {
- kgsl_iommu_enable_clk(mmu);
- KGSL_IOMMU_SET_CTX_REG(ctx, TLBIALL, 1);
- kgsl_iommu_disable_clk(mmu);
+ return status;
}
- return status;
+
+ /* Make sure the hardware is programmed to the default pagetable */
+ return kgsl_iommu_set_pt(mmu, mmu->defaultpagetable);
}
static int
@@ -1707,23 +1704,15 @@ kgsl_iommu_get_current_ttbr0(struct kgsl_mmu *mmu)
*
* Return - void
*/
-static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu,
- struct kgsl_pagetable *pt)
+static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt)
{
- struct kgsl_device *device = KGSL_MMU_DEVICE(mmu);
struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu);
struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER];
- int ret = 0;
uint64_t ttbr0, temp;
unsigned int contextidr;
unsigned long wait_for_flush;
- /*
- * If using a global pagetable, we can skip all this
- * because the pagetable will be set up by the iommu
- * driver and never changed at runtime.
- */
- if (!kgsl_mmu_is_perprocess(mmu))
+ if ((pt != mmu->defaultpagetable) && !kgsl_mmu_is_perprocess(mmu))
return 0;
kgsl_iommu_enable_clk(mmu);
@@ -1731,14 +1720,6 @@ static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu,
ttbr0 = kgsl_mmu_pagetable_get_ttbr0(pt);
contextidr = kgsl_mmu_pagetable_get_contextidr(pt);
- /*
- * Taking the liberty to spin idle since this codepath
- * is invoked when we can spin safely for it to be idle
- */
- ret = adreno_spin_idle(ADRENO_DEVICE(device), ADRENO_IDLE_TIMEOUT);
- if (ret)
- return ret;
-
KGSL_IOMMU_SET_CTX_REG_Q(ctx, TTBR0, ttbr0);
KGSL_IOMMU_SET_CTX_REG(ctx, CONTEXTIDR, contextidr);
@@ -1767,10 +1748,8 @@ static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu,
cpu_relax();
}
- /* Disable smmu clock */
kgsl_iommu_disable_clk(mmu);
-
- return ret;
+ return 0;
}
/*
@@ -1788,8 +1767,6 @@ static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu,
struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER];
struct kgsl_device *device = KGSL_MMU_DEVICE(mmu);
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- int ret = 0;
- unsigned int sctlr_val;
if ((adreno_dev->ft_pf_policy &
BIT(KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)) ==
@@ -1798,10 +1775,7 @@ static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu,
/* If not attached, policy will be updated during the next attach */
if (ctx->default_pt != NULL) {
- /* Need to idle device before changing options */
- ret = device->ftbl->idle(device);
- if (ret)
- return ret;
+ unsigned int sctlr_val;
kgsl_iommu_enable_clk(mmu);
@@ -1820,7 +1794,7 @@ static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu,
kgsl_iommu_disable_clk(mmu);
}
- return ret;
+ return 0;
}
static struct kgsl_protected_registers *
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 3652aa2e6ec4..5339917911b1 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -21,6 +21,12 @@
#define KGSL_MMU_GLOBAL_PT 0
#define KGSL_MMU_SECURE_PT 1
+#define MMU_DEFAULT_TTBR0(_d) \
+ (kgsl_mmu_pagetable_get_ttbr0((_d)->mmu.defaultpagetable))
+
+#define MMU_DEFAULT_CONTEXTIDR(_d) \
+ (kgsl_mmu_pagetable_get_contextidr((_d)->mmu.defaultpagetable))
+
struct kgsl_device;
enum kgsl_mmutype {
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index da8c8585d31e..2b9eef8b6351 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1381,6 +1381,9 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
_isense_clk_set_rate(pwr,
pwr->num_pwrlevels - 1);
}
+
+ /* Turn off the IOMMU clocks */
+ kgsl_mmu_disable_clk(&device->mmu);
} else if (requested_state == KGSL_STATE_SLEEP) {
/* High latency clock maintenance. */
for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
@@ -1428,7 +1431,11 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
pwr->gpu_bimc_interface_enabled = 1;
}
}
+
+ /* Turn on the IOMMU clocks */
+ kgsl_mmu_enable_clk(&device->mmu);
}
+
}
}
diff --git a/drivers/input/touchscreen/it7258_ts_i2c.c b/drivers/input/touchscreen/it7258_ts_i2c.c
new file mode 100644
index 000000000000..048358e2ef9d
--- /dev/null
+++ b/drivers/input/touchscreen/it7258_ts_i2c.c
@@ -0,0 +1,851 @@
+/* drivers/input/touchscreen/it7258_ts_i2c.c
+ *
+ * Copyright (C) 2014 ITE Tech. Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/wakelock.h>
+
+#define MAX_BUFFER_SIZE 144
+#define DEVICE_NAME "IT7260"
+#define SCREEN_X_RESOLUTION 320
+#define SCREEN_Y_RESOLUTION 320
+
+#define BUF_COMMAND 0x20 /* all commands writes go to this idx */
+#define BUF_SYS_COMMAND 0x40
+#define BUF_QUERY 0x80 /* "revice ready?" and "wake up please" and "read touch data" reads go to this idx */
+#define BUF_RESPONSE 0xA0 /* most command responce reads go to this idx */
+#define BUF_SYS_RESPONSE 0xC0
+#define BUF_POINT_INFO 0xE0 /* reads of "point" go through here and produce 14 bytes of data */
+
+/* commands and their subcommands. when no subcommands exist, a zero is send as the second byte */
+#define CMD_IDENT_CHIP 0x00
+#define CMD_READ_VERSIONS 0x01 /* VERSION_LENGTH bytes of data in response */
+# define VER_FIRMWARE 0x00
+# define VER_CONFIG 0x06
+# define VERSION_LENGTH 10
+#define CMD_PWR_CTL 0x04 /* subcommand is zero, next byte is power mode */
+# define PWR_CTL_LOW_POWER_MODE 0x01 /* idle mode */
+# define PWR_CTL_SLEEP_MODE 0x02 /* sleep mode */
+#define CMD_UNKNOWN_7 0x07 /* command is not documented in the datasheet v1.0.0.7 */
+#define CMD_FIRMWARE_REINIT_C 0x0C
+#define CMD_CALIBRATE 0x13 /* needs to be followed by 4 bytes of zeroes */
+#define CMD_FIRMWARE_UPGRADE 0x60
+# define FIRMWARE_MODE_ENTER 0x00
+# define FIRMWARE_MODE_EXIT 0x80
+#define CMD_SET_START_OFFSET 0x61 /* address for FW read/write */
+#define CMD_FW_WRITE 0x62 /* subcommand is number of bytes to write */
+#define CMD_FW_READ 0x63 /* subcommand is number of bytes to read */
+#define CMD_FIRMWARE_REINIT_6F 0x6F
+
+#define FW_WRITE_CHUNK_SIZE 128
+#define FW_WRITE_RETRY_COUNT 4
+#define CHIP_FLASH_SIZE 0x8000
+#define SYSFS_FW_UPLOAD_MODE_MANUAL 2
+#define SYSFS_RESULT_FAIL (-1)
+#define SYSFS_RESULT_NOT_DONE 0
+#define SYSFS_RESULT_SUCCESS 1
+#define DEVICE_READY_MAX_WAIT 500
+
+/* result of reading with BUF_QUERY bits */
+#define CMD_STATUS_BITS 0x07
+#define CMD_STATUS_DONE 0x00
+#define CMD_STATUS_BUSY 0x01
+#define CMD_STATUS_ERROR 0x02
+#define PT_INFO_BITS 0xF8
+#define BT_INFO_NONE 0x00
+#define PT_INFO_YES 0x80
+#define BT_INFO_NONE_BUT_DOWN 0x08 /* no new data but finder(s) still down */
+
+/* use this to include integers in commands */
+#define CMD_UINT16(v) ((uint8_t)(v)) , ((uint8_t)((v) >> 8))
+
+
+struct FingerData {
+ uint8_t xLo;
+ uint8_t hi;
+ uint8_t yLo;
+ uint8_t pressure;
+} __attribute__((packed));
+
+struct PointData {
+ uint8_t flags;
+ uint8_t palm;
+ struct FingerData fd[3];
+} __attribute__((packed));
+
+#define PD_FLAGS_DATA_TYPE_BITS 0xF0
+/* other types (like chip-detected gestures) exist but we do not care */
+#define PD_FLAGS_DATA_TYPE_TOUCH 0x00
+#define PD_FLAGS_NOT_PEN 0x08 /* set if pen touched, clear if finger(s) */
+#define PD_FLAGS_HAVE_FINGERS 0x07 /* a bit for each finger data that is valid (from lsb to msb) */
+#define PD_PALM_FLAG_BIT 0x01
+#define FD_PRESSURE_BITS 0x0F
+#define FD_PRESSURE_NONE 0x00
+#define FD_PRESSURE_HOVER 0x01
+#define FD_PRESSURE_LIGHT 0x02
+#define FD_PRESSURE_NORMAL 0x04
+#define FD_PRESSURE_HIGH 0x08
+#define FD_PRESSURE_HEAVY 0x0F
+
+struct IT7260_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+};
+
+static int8_t fwUploadResult = SYSFS_RESULT_NOT_DONE;
+static int8_t calibrationWasSuccessful = SYSFS_RESULT_NOT_DONE;
+static bool devicePresent = false;
+static DEFINE_MUTEX(sleepModeMutex);
+static bool chipAwake = true;
+static bool hadFingerDown = false;
+static bool isDeviceSleeping = false;
+static bool isDeviceSuspend = false;
+static struct input_dev *input_dev;
+static struct IT7260_ts_data *gl_ts;
+
+#define LOGE(...) pr_err(DEVICE_NAME ": " __VA_ARGS__)
+#define LOGI(...) printk(DEVICE_NAME ": " __VA_ARGS__)
+
+/* internal use func - does not make sure chip is ready before read */
+static bool i2cReadNoReadyCheck(uint8_t bufferIndex, uint8_t *dataBuffer, uint16_t dataLength)
+{
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = gl_ts->client->addr,
+ .flags = I2C_M_NOSTART,
+ .len = 1,
+ .buf = &bufferIndex
+ },
+ {
+ .addr = gl_ts->client->addr,
+ .flags = I2C_M_RD,
+ .len = dataLength,
+ .buf = dataBuffer
+ }
+ };
+
+ memset(dataBuffer, 0xFF, dataLength);
+
+ return i2c_transfer(gl_ts->client->adapter, msgs, 2);
+}
+
+static bool i2cWriteNoReadyCheck(uint8_t bufferIndex, const uint8_t *dataBuffer, uint16_t dataLength)
+{
+ uint8_t txbuf[257];
+ struct i2c_msg msg = {
+ .addr = gl_ts->client->addr,
+ .flags = 0,
+ .len = dataLength + 1,
+ .buf = txbuf
+ };
+
+ /* just to be careful */
+ BUG_ON(dataLength > sizeof(txbuf) - 1);
+
+ txbuf[0] = bufferIndex;
+ memcpy(txbuf + 1, dataBuffer, dataLength);
+
+ return i2c_transfer(gl_ts->client->adapter, &msg, 1);
+}
+
+/*
+ * Device is apparently always ready for i2c but not for actual register reads/writes.
+ * This function ascertains it is ready for that too. the results of this call often
+ * were ignored.
+ */
+static bool waitDeviceReady(bool forever, bool slowly)
+{
+ uint8_t ucQuery;
+ uint32_t count = DEVICE_READY_MAX_WAIT;
+
+ do{
+ if (!i2cReadNoReadyCheck(BUF_QUERY, &ucQuery, sizeof(ucQuery)))
+ ucQuery = CMD_STATUS_BUSY;
+
+ if (slowly)
+ mdelay(1000);
+ if (!forever)
+ count--;
+
+ }while((ucQuery & CMD_STATUS_BUSY) && count);
+
+ return !ucQuery;
+}
+
+static bool i2cRead(uint8_t bufferIndex, uint8_t *dataBuffer, uint16_t dataLength)
+{
+ waitDeviceReady(false, false);
+ return i2cReadNoReadyCheck(bufferIndex, dataBuffer, dataLength);
+}
+
+static bool i2cWrite(uint8_t bufferIndex, const uint8_t *dataBuffer, uint16_t dataLength)
+{
+ waitDeviceReady(false, false);
+ return i2cWriteNoReadyCheck(bufferIndex, dataBuffer, dataLength);
+}
+
+static bool chipFirmwareReinitialize(uint8_t cmdOfChoice)
+{
+ uint8_t cmd[] = {cmdOfChoice};
+ uint8_t rsp[2];
+
+ if (!i2cWrite(BUF_COMMAND, cmd, sizeof(cmd)))
+ return false;
+
+ if (!i2cRead(BUF_RESPONSE, rsp, sizeof(rsp)))
+ return false;
+
+ /* a reply of two zero bytes signifies success */
+ return !rsp[0] && !rsp[1];
+}
+
+static bool chipFirmwareUpgradeModeEnterExit(bool enter)
+{
+ uint8_t cmd[] = {CMD_FIRMWARE_UPGRADE, 0, 'I', 'T', '7', '2', '6', '0', 0x55, 0xAA};
+ uint8_t resp[2];
+
+ cmd[1] = enter ? FIRMWARE_MODE_ENTER : FIRMWARE_MODE_EXIT;
+ if (!i2cWrite(BUF_COMMAND, cmd, sizeof(cmd)))
+ return false;
+
+ if (!i2cRead(BUF_RESPONSE, resp, sizeof(resp)))
+ return false;
+
+ /* a reply of two zero bytes signifies success */
+ return !resp[0] && !resp[1];
+}
+
+static bool chipSetStartOffset(uint16_t offset)
+{
+ uint8_t cmd[] = {CMD_SET_START_OFFSET, 0, CMD_UINT16(offset)};
+ uint8_t resp[2];
+
+ if (!i2cWrite(BUF_COMMAND, cmd, 4))
+ return false;
+
+
+ if (!i2cRead(BUF_RESPONSE, resp, sizeof(resp)))
+ return false;
+
+
+ /* a reply of two zero bytes signifies success */
+ return !resp[0] && !resp[1];
+}
+
+
+/* write fwLength bytes from fwData at chip offset writeStartOffset */
+static bool chipFlashWriteAndVerify(unsigned int fwLength, const uint8_t *fwData, uint16_t writeStartOffset)
+{
+ uint32_t curDataOfst;
+
+ for (curDataOfst = 0; curDataOfst < fwLength; curDataOfst += FW_WRITE_CHUNK_SIZE) {
+
+ uint8_t cmdWrite[2 + FW_WRITE_CHUNK_SIZE] = {CMD_FW_WRITE};
+ uint8_t bufRead[FW_WRITE_CHUNK_SIZE];
+ uint8_t cmdRead[2] = {CMD_FW_READ};
+ unsigned i, nRetries;
+ uint32_t curWriteSz;
+
+ /* figure out how much to write */
+ curWriteSz = fwLength - curDataOfst;
+ if (curWriteSz > FW_WRITE_CHUNK_SIZE)
+ curWriteSz = FW_WRITE_CHUNK_SIZE;
+
+ /* prepare the write command */
+ cmdWrite[1] = curWriteSz;
+ for (i = 0; i < curWriteSz; i++)
+ cmdWrite[i + 2] = fwData[curDataOfst + i];
+
+ /* prepare the read command */
+ cmdRead[1] = curWriteSz;
+
+ for (nRetries = 0; nRetries < FW_WRITE_RETRY_COUNT; nRetries++) {
+
+ /* set write offset and write the data*/
+ chipSetStartOffset(writeStartOffset + curDataOfst);
+ i2cWrite(BUF_COMMAND, cmdWrite, 2 + curWriteSz);
+
+ /* set offset and read the data back */
+ chipSetStartOffset(writeStartOffset + curDataOfst);
+ i2cWrite(BUF_COMMAND, cmdRead, sizeof(cmdRead));
+ i2cRead(BUF_RESPONSE, bufRead, curWriteSz);
+
+ /* verify. If success break out of retry loop */
+ for (i = 0; i < curWriteSz && bufRead[i] == cmdWrite[i + 2]; i++);
+ if (i == curWriteSz)
+ break;
+ LOGE("write of data offset %u failed on try %u at byte %u/%u\n", curDataOfst, nRetries, i, curWriteSz);
+ }
+ /* if we've failed after all the retries, tell the caller */
+ if (nRetries == FW_WRITE_RETRY_COUNT)
+ return false;
+ }
+
+ return true;
+}
+
+static bool chipFirmwareUpload(uint32_t fwLen, const uint8_t *fwData, uint32_t cfgLen, const uint8_t *cfgData)
+{
+ bool success = false;
+
+ /* enter fw upload mode */
+ if (!chipFirmwareUpgradeModeEnterExit(true))
+ return false;
+
+ /* flash the firmware if requested */
+ if (fwLen && fwData && !chipFlashWriteAndVerify(fwLen, fwData, 0)) {
+ LOGE("failed to upload touch firmware\n");
+ goto out;
+ }
+
+ /* flash config data if requested */
+ if (fwLen && fwData && !chipFlashWriteAndVerify(cfgLen, cfgData, CHIP_FLASH_SIZE - cfgLen)) {
+ LOGE("failed to upload touch cfg data\n");
+ goto out;
+ }
+
+ success = true;
+
+out:
+ return chipFirmwareUpgradeModeEnterExit(false) && chipFirmwareReinitialize(CMD_FIRMWARE_REINIT_6F) && success;
+}
+
+/*
+ * both buffers should be VERSION_LENGTH in size,
+ * but only a part of them is significant
+ */
+static bool chipGetVersions(uint8_t *verFw, uint8_t *verCfg, bool logIt)
+{
+ /* this code to get versions is reproduced as was written, but it does not make sense. Something here *PROBABLY IS* wrong */
+ static const uint8_t cmdReadFwVer[] = {CMD_READ_VERSIONS, VER_FIRMWARE};
+ static const uint8_t cmdReadCfgVer[] = {CMD_READ_VERSIONS, VER_CONFIG};
+ bool ret = true;
+
+ /* this structure is so that we definitely do all the calls, but still return a status in case anyone cares */
+ ret = i2cWrite(BUF_COMMAND, cmdReadFwVer, sizeof(cmdReadFwVer)) && ret;
+ ret = i2cRead(BUF_RESPONSE, verFw, VERSION_LENGTH) && ret;
+ ret = i2cWrite(BUF_COMMAND, cmdReadCfgVer, sizeof(cmdReadCfgVer)) && ret;
+ ret = i2cRead(BUF_RESPONSE, verCfg, VERSION_LENGTH) && ret;
+
+ if (logIt)
+ LOGI("current versions: fw@{%X,%X,%X,%X}, cfg@{%X,%X,%X,%X}\n",
+ verFw[5], verFw[6], verFw[7], verFw[8],
+ verCfg[1], verCfg[2], verCfg[3], verCfg[4]);
+
+ return ret;
+}
+
+static ssize_t sysfsUpgradeStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ const struct firmware *fw, *cfg;
+ uint8_t verFw[10], verCfg[10];
+ unsigned fwLen = 0, cfgLen = 0;
+ bool manualUpgrade, success;
+ int mode = 0;
+
+ if (request_firmware(&fw, "it7260.fw", dev))
+ LOGE("failed to get firmware for it7260\n");
+ else
+ fwLen = fw->size;
+
+
+ if (request_firmware(&cfg, "it7260.cfg", dev))
+ LOGE("failed to get config data for it7260\n");
+ else
+ cfgLen = cfg->size;
+
+ sscanf(buf, "%d", &mode);
+ manualUpgrade = mode == SYSFS_FW_UPLOAD_MODE_MANUAL;
+ LOGI("firmware found %ub of fw and %ub of config in %s mode\n",
+ fwLen, cfgLen, manualUpgrade ? "manual" : "normal");
+
+ chipGetVersions(verFw, verCfg, true);
+
+ fwUploadResult = SYSFS_RESULT_NOT_DONE;
+ if (fwLen && cfgLen) {
+ if (manualUpgrade || (verFw[5] < fw->data[8] || verFw[6] <
+ fw->data[9] || verFw[7] < fw->data[10] || verFw[8] <
+ fw->data[11]) || (verCfg[1] < cfg->data[cfgLen - 8]
+ || verCfg[2] < cfg->data[cfgLen - 7] || verCfg[3] <
+ cfg->data[cfgLen - 6] ||
+ verCfg[4] < cfg->data[cfgLen - 5])){
+ LOGI("firmware/config will be upgraded\n");
+ disable_irq(gl_ts->client->irq);
+ success = chipFirmwareUpload(fwLen, fw->data, cfgLen, cfg->data);
+ enable_irq(gl_ts->client->irq);
+
+ fwUploadResult = success ? SYSFS_RESULT_SUCCESS : SYSFS_RESULT_FAIL;
+ LOGI("upload %s\n", success ? "success" : "failed");
+ }
+ else {
+ LOGI("firmware/config upgrade not needed\n");
+ }
+ }
+
+ if (fwLen)
+ release_firmware(fw);
+
+ if (cfgLen)
+ release_firmware(cfg);
+
+ return count;
+}
+
+static ssize_t sysfsUpgradeShow(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d", fwUploadResult);
+}
+
+static ssize_t sysfsCalibrationShow(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d", calibrationWasSuccessful);
+}
+
+static bool chipSendCalibrationCmd(bool autoTuneOn)
+{
+ uint8_t cmdCalibrate[] = {CMD_CALIBRATE, 0, autoTuneOn ? 1 : 0, 0, 0};
+ return i2cWrite(BUF_COMMAND, cmdCalibrate, sizeof(cmdCalibrate));
+}
+
+static ssize_t sysfsCalibrationStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ uint8_t resp;
+
+ if (!chipSendCalibrationCmd(false))
+ LOGE("failed to send calibration command\n");
+ else {
+ calibrationWasSuccessful = i2cRead(BUF_RESPONSE, &resp, sizeof(resp)) ? SYSFS_RESULT_SUCCESS : SYSFS_RESULT_FAIL;
+
+ /* previous logic that was here never called chipFirmwareReinitialize() due to checking a guaranteed-not-null value against null. We now call it. Hopefully this is OK */
+ if (!resp)
+ LOGI("chipFirmwareReinitialize -> %s\n", chipFirmwareReinitialize(CMD_FIRMWARE_REINIT_6F) ? "success" : "fail");
+ }
+
+ return count;
+}
+
+static ssize_t sysfsPointShow(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ uint8_t pointData[sizeof(struct PointData)];
+ bool readSuccess;
+ ssize_t ret;
+
+ readSuccess = i2cReadNoReadyCheck(BUF_POINT_INFO, pointData, sizeof(pointData));
+ ret = sprintf(buf, "point_show read ret[%d]--point[%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x]=\n",
+ readSuccess, pointData[0],pointData[1],pointData[2],pointData[3],
+ pointData[4],pointData[5],pointData[6],pointData[7],pointData[8],
+ pointData[9],pointData[10],pointData[11],pointData[12],pointData[13]);
+
+
+ LOGI("%s", buf);
+
+ return ret;
+}
+
+static ssize_t sysfsPointStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ return count;
+}
+
+static ssize_t sysfsStatusShow(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", devicePresent ? 1 : 0);
+}
+
+static ssize_t sysfsStatusStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ uint8_t verFw[10], verCfg[10];
+
+ chipGetVersions(verFw, verCfg, true);
+
+ return count;
+}
+
+static ssize_t sysfsVersionShow(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ uint8_t verFw[10], verCfg[10];
+
+ chipGetVersions(verFw, verCfg, false);
+ return sprintf(buf, "%x,%x,%x,%x # %x,%x,%x,%x\n",verFw[5], verFw[6], verFw[7], verFw[8], verCfg[1], verCfg[2], verCfg[3], verCfg[4]);
+}
+
+static ssize_t sysfsVersionStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ return count;
+}
+
+static ssize_t sysfsSleepShow(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ /*
+ * The usefulness of this was questionable at best - we were at least leaking a byte of
+ * kernel data (by claiming to return a byte but not writing to buf. To fix this now
+ * we actually return the sleep status
+ */
+ if (!mutex_lock_interruptible(&sleepModeMutex)) {
+ *buf = chipAwake ? '1' : '0';
+ mutex_unlock(&sleepModeMutex);
+ return 1;
+ }
+ else
+ return -EINTR;
+}
+
+static ssize_t sysfsSleepStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ static const uint8_t cmdGoSleep[] = {CMD_PWR_CTL, 0x00, PWR_CTL_SLEEP_MODE};
+ int goToSleepVal;
+ bool goToWake;
+ uint8_t dummy;
+
+ sscanf(buf, "%d", &goToSleepVal);
+ goToWake = !goToSleepVal; /* convert to bool of proper polarity */
+
+ if (!mutex_lock_interruptible(&sleepModeMutex)) {
+ if ((chipAwake && goToWake) || (!chipAwake && !goToWake))
+ LOGE("duplicate request to %s chip\n", goToWake ? "wake" : "sleep");
+ else if (goToWake) {
+ i2cReadNoReadyCheck(BUF_QUERY, &dummy, sizeof(dummy));
+ enable_irq(gl_ts->client->irq);
+ LOGI("touch is going to wake!\n\n");
+ } else {
+ disable_irq(gl_ts->client->irq);
+ i2cWriteNoReadyCheck(BUF_COMMAND, cmdGoSleep, sizeof(cmdGoSleep));
+ LOGI("touch is going to sleep...\n\n");
+ }
+ chipAwake = goToWake;
+ mutex_unlock(&sleepModeMutex);
+ return count;
+ } else
+ return -EINTR;
+}
+
+
+static DEVICE_ATTR(status, S_IRUGO|S_IWUSR|S_IWGRP, sysfsStatusShow, sysfsStatusStore);
+static DEVICE_ATTR(version, S_IRUGO|S_IWUSR|S_IWGRP, sysfsVersionShow, sysfsVersionStore);
+static DEVICE_ATTR(sleep, S_IRUGO|S_IWUSR|S_IWGRP, sysfsSleepShow, sysfsSleepStore);
+
+static struct attribute *it7260_attrstatus[] = {
+ &dev_attr_status.attr,
+ &dev_attr_version.attr,
+ &dev_attr_sleep.attr,
+ NULL
+};
+
+static const struct attribute_group it7260_attrstatus_group = {
+ .attrs = it7260_attrstatus,
+};
+
+static DEVICE_ATTR(calibration, S_IRUGO|S_IWUSR|S_IWGRP, sysfsCalibrationShow, sysfsCalibrationStore);
+static DEVICE_ATTR(upgrade, S_IRUGO|S_IWUSR|S_IWGRP, sysfsUpgradeShow, sysfsUpgradeStore);
+static DEVICE_ATTR(point, S_IRUGO|S_IWUSR|S_IWGRP, sysfsPointShow, sysfsPointStore);
+
+
+static struct attribute *it7260_attributes[] = {
+ &dev_attr_calibration.attr,
+ &dev_attr_upgrade.attr,
+ &dev_attr_point.attr,
+ NULL
+};
+
+static const struct attribute_group it7260_attr_group = {
+ .attrs = it7260_attributes,
+};
+
+static void chipExternalCalibration(bool autoTuneEnabled)
+{
+ uint8_t resp[2];
+
+ LOGI("sent calibration command -> %d\n", chipSendCalibrationCmd(autoTuneEnabled));
+ waitDeviceReady(true, true);
+ i2cReadNoReadyCheck(BUF_RESPONSE, resp, sizeof(resp));
+ chipFirmwareReinitialize(CMD_FIRMWARE_REINIT_C);
+}
+
+void sendCalibrationCmd(void)
+{
+ chipExternalCalibration(false);
+}
+EXPORT_SYMBOL(sendCalibrationCmd);
+
+static void readFingerData(uint16_t *xP, uint16_t *yP, uint8_t *pressureP, const struct FingerData *fd)
+{
+ uint16_t x = fd->xLo;
+ uint16_t y = fd->yLo;
+
+ x += ((uint16_t)(fd->hi & 0x0F)) << 8;
+ y += ((uint16_t)(fd->hi & 0xF0)) << 4;
+
+ if (xP)
+ *xP = x;
+ if (yP)
+ *yP = y;
+ if (pressureP)
+ *pressureP = fd->pressure & FD_PRESSURE_BITS;
+}
+
+static void readTouchDataPoint(void)
+{
+ struct PointData pointData;
+ uint8_t devStatus;
+ uint8_t pressure = FD_PRESSURE_NONE;
+ uint16_t x, y;
+
+ /* verify there is point data to read & it is readable and valid */
+ i2cReadNoReadyCheck(BUF_QUERY, &devStatus, sizeof(devStatus));
+ if (!((devStatus & PT_INFO_BITS) & PT_INFO_YES)) {
+ LOGE("readTouchDataPoint() called when no data available (0x%02X)\n", devStatus);
+ return;
+ }
+ if (!i2cReadNoReadyCheck(BUF_POINT_INFO, (void*)&pointData, sizeof(pointData))) {
+ LOGE("readTouchDataPoint() failed to read point data buffer\n");
+ return;
+ }
+ if ((pointData.flags & PD_FLAGS_DATA_TYPE_BITS) != PD_FLAGS_DATA_TYPE_TOUCH) {
+ LOGE("readTouchDataPoint() dropping non-point data of type 0x%02X\n", pointData.flags);
+ return;
+ }
+
+ if ((pointData.flags & PD_FLAGS_HAVE_FINGERS) & 1)
+ readFingerData(&x, &y, &pressure, pointData.fd);
+
+ if (pressure >= FD_PRESSURE_LIGHT) {
+
+ if (!hadFingerDown)
+ hadFingerDown = true;
+
+ readFingerData(&x, &y, &pressure, pointData.fd);
+
+ input_report_abs(gl_ts->input_dev, ABS_X, x);
+ input_report_abs(gl_ts->input_dev, ABS_Y, y);
+ input_report_key(gl_ts->input_dev, BTN_TOUCH, 1);
+ input_sync(gl_ts->input_dev);
+
+ } else if (hadFingerDown) {
+ hadFingerDown = false;
+
+ input_report_key(gl_ts->input_dev, BTN_TOUCH, 0);
+ input_sync(gl_ts->input_dev);
+ }
+
+}
+
+static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid)
+{
+ smp_rmb();
+ if (isDeviceSleeping) {
+ smp_wmb();
+ } else {
+ readTouchDataPoint();
+ }
+
+ return IRQ_HANDLED;
+}
+
+static bool chipIdentifyIT7260(void)
+{
+ static const uint8_t cmdIdent[] = {CMD_IDENT_CHIP};
+ static const uint8_t expectedID[] = {0x0A, 'I', 'T', 'E', '7', '2', '6', '0'};
+ uint8_t chipID[10] = {0,};
+
+ waitDeviceReady(true, false);
+
+ if (!i2cWriteNoReadyCheck(BUF_COMMAND, cmdIdent, sizeof(cmdIdent))) {
+ LOGE("i2cWrite() failed\n");
+ return false;
+ }
+
+ waitDeviceReady(true, false);
+
+ if (!i2cReadNoReadyCheck(BUF_RESPONSE, chipID, sizeof(chipID))) {
+ LOGE("i2cRead() failed\n");
+ return false;
+ }
+ pr_info("chipIdentifyIT7260 read id: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ chipID[0], chipID[1], chipID[2], chipID[3], chipID[4],
+ chipID[5], chipID[6], chipID[7], chipID[8], chipID[9]);
+
+ if (memcmp(chipID, expectedID, sizeof(expectedID)))
+ return false;
+
+ if (chipID[8] == '5' && chipID[9] == '6')
+ LOGI("rev BX3 found\n");
+ else if (chipID[8] == '6' && chipID[9] == '6')
+ LOGI("rev BX4 found\n");
+ else
+ LOGI("unknown revision (0x%02X 0x%02X) found\n", chipID[8], chipID[9]);
+
+ return true;
+}
+
+static int IT7260_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ static const uint8_t cmdStart[] = {CMD_UNKNOWN_7};
+ struct IT7260_i2c_platform_data *pdata;
+ uint8_t rsp[2];
+ int ret = -1;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ LOGE("need I2C_FUNC_I2C\n");
+ ret = -ENODEV;
+ goto err_out;
+ }
+
+ if (!client->irq) {
+ LOGE("need IRQ\n");
+ ret = -ENODEV;
+ goto err_out;
+ }
+ gl_ts = kzalloc(sizeof(*gl_ts), GFP_KERNEL);
+ if (!gl_ts) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ gl_ts->client = client;
+ i2c_set_clientdata(client, gl_ts);
+ pdata = client->dev.platform_data;
+
+ if (sysfs_create_group(&(client->dev.kobj), &it7260_attrstatus_group)) {
+ dev_err(&client->dev, "failed to register sysfs #1\n");
+ goto err_sysfs_grp_create_1;
+ }
+
+ if (!chipIdentifyIT7260()) {
+ LOGI ("chipIdentifyIT7260 FAIL");
+ goto err_ident_fail_or_input_alloc;
+ }
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ LOGE("failed to allocate input device\n");
+ ret = -ENOMEM;
+ goto err_ident_fail_or_input_alloc;
+ }
+ gl_ts->input_dev = input_dev;
+
+ input_dev->name = DEVICE_NAME;
+ input_dev->phys = "I2C";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x7260;
+ set_bit(EV_SYN, input_dev->evbit);
+ set_bit(EV_KEY, input_dev->evbit);
+ set_bit(EV_ABS, input_dev->evbit);
+ set_bit(INPUT_PROP_DIRECT,input_dev->propbit);
+ set_bit(BTN_TOUCH, input_dev->keybit);
+ set_bit(KEY_SLEEP,input_dev->keybit);
+ set_bit(KEY_WAKEUP,input_dev->keybit);
+ set_bit(KEY_POWER,input_dev->keybit);
+ input_set_abs_params(input_dev, ABS_X, 0, SCREEN_X_RESOLUTION, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_Y_RESOLUTION, 0, 0);
+
+ if (input_register_device(input_dev)) {
+ LOGE("failed to register input device\n");
+ goto err_input_register;
+ }
+
+ if (request_threaded_irq(client->irq, NULL, IT7260_ts_threaded_handler, IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, gl_ts)) {
+ dev_err(&client->dev, "request_irq failed\n");
+ goto err_irq_reg;
+ }
+
+ if (sysfs_create_group(&(client->dev.kobj), &it7260_attr_group)) {
+ dev_err(&client->dev, "failed to register sysfs #2\n");
+ goto err_sysfs_grp_create_2;
+ }
+
+ devicePresent = true;
+
+ i2cWriteNoReadyCheck(BUF_COMMAND, cmdStart, sizeof(cmdStart));
+ mdelay(10);
+ i2cReadNoReadyCheck(BUF_RESPONSE, rsp, sizeof(rsp));
+ mdelay(10);
+
+ return 0;
+
+err_sysfs_grp_create_2:
+ free_irq(client->irq, gl_ts);
+
+err_irq_reg:
+ input_unregister_device(input_dev);
+ input_dev = NULL;
+
+err_input_register:
+ if (input_dev)
+ input_free_device(input_dev);
+
+err_ident_fail_or_input_alloc:
+ sysfs_remove_group(&(client->dev.kobj), &it7260_attrstatus_group);
+
+err_sysfs_grp_create_1:
+ kfree(gl_ts);
+
+err_out:
+ return ret;
+}
+
+static int IT7260_ts_remove(struct i2c_client *client)
+{
+ devicePresent = false;
+ return 0;
+}
+
+static const struct i2c_device_id IT7260_ts_id[] = {
+ { DEVICE_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, IT7260_ts_id);
+
+static const struct of_device_id IT7260_match_table[] = {
+ { .compatible = "ITE,IT7260_ts",},
+ {},
+};
+
+static int IT7260_ts_resume(struct i2c_client *i2cdev)
+{
+ isDeviceSuspend = false;
+ return 0;
+}
+
+static int IT7260_ts_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
+{
+ isDeviceSuspend = true;
+ return 0;
+}
+
+static struct i2c_driver IT7260_ts_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DEVICE_NAME,
+ .of_match_table = IT7260_match_table,
+ },
+ .probe = IT7260_ts_probe,
+ .remove = IT7260_ts_remove,
+ .id_table = IT7260_ts_id,
+ .resume = IT7260_ts_resume,
+ .suspend = IT7260_ts_suspend,
+};
+
+module_i2c_driver(IT7260_ts_driver);
+
+MODULE_DESCRIPTION("IT7260 Touchscreen Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index ce3f8713df3e..db4b66bb18ed 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -568,6 +568,28 @@ static struct arm_smmu_master *find_smmu_master(struct arm_smmu_device *smmu,
return NULL;
}
+static struct arm_smmu_master *find_smmu_master_by_sid(
+ struct arm_smmu_device *smmu, u32 sid)
+{
+ struct rb_node *next;
+ struct arm_smmu_master *master;
+ struct arm_smmu_master_cfg *cfg;
+ int i;
+
+ next = rb_first(&smmu->masters);
+ for (; next; next = rb_next(next)) {
+ master = container_of(next, struct arm_smmu_master, node);
+ cfg = &master->cfg;
+
+ for (i = 0; i < cfg->num_streamids; i++) {
+ if (cfg->streamids[i] == sid)
+ return master;
+ }
+ }
+
+ return NULL;
+}
+
static struct arm_smmu_master_cfg *
find_smmu_master_cfg(struct device *dev)
{
@@ -1175,8 +1197,9 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
bool fatal_asf;
void __iomem *gr1_base;
phys_addr_t phys_soft;
- u32 frsynra;
+ u32 sid;
bool non_fatal_fault = smmu_domain->non_fatal_faults;
+ struct arm_smmu_master *master;
static DEFINE_RATELIMIT_STATE(_rs,
DEFAULT_RATELIMIT_INTERVAL,
@@ -1231,7 +1254,9 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
iova = far;
phys_soft = arm_smmu_iova_to_phys(domain, iova);
- frsynra = readl_relaxed(gr1_base + ARM_SMMU_GR1_CBFRSYNRA(cfg->cbndx));
+ sid = readl_relaxed(gr1_base + ARM_SMMU_GR1_CBFRSYNRA(cfg->cbndx));
+ sid &= 0xffff;
+ master = find_smmu_master_by_sid(smmu, sid);
tmp = report_iommu_fault(domain, smmu->dev, iova, flags);
if (!tmp || (tmp == -EBUSY)) {
dev_dbg(smmu->dev,
@@ -1246,6 +1271,9 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
fsr);
if (__ratelimit(&_rs)) {
+ dev_err(smmu->dev, "Context Fault for %s\n",
+ master ? master->of_node->name : "Unknown SID");
+
dev_err(smmu->dev,
"Unhandled context fault: iova=0x%08lx, fsr=0x%x, fsynr=0x%x, cb=%d\n",
iova, fsr, fsynr, cfg->cbndx);
@@ -1271,7 +1299,7 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
dev_name(smmu->dev));
dev_err(smmu->dev,
"hard iova-to-phys (ATOS)=%pa\n", &phys_atos);
- dev_err(smmu->dev, "SID=0x%x\n", frsynra & 0xffff);
+ dev_err(smmu->dev, "SID=0x%x\n", sid);
}
ret = IRQ_NONE;
resume = RESUME_TERMINATE;
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index c1aeb8c43e81..3985df780216 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -538,7 +538,7 @@ static int camera_v4l2_fh_open(struct file *filep)
{
struct msm_video_device *pvdev = video_drvdata(filep);
struct camera_v4l2_private *sp;
- unsigned int stream_id;
+ unsigned long stream_id;
sp = kzalloc(sizeof(*sp), GFP_KERNEL);
if (!sp) {
@@ -617,7 +617,7 @@ static int camera_v4l2_open(struct file *filep)
int rc = 0;
struct v4l2_event event;
struct msm_video_device *pvdev = video_drvdata(filep);
- unsigned int opn_idx, idx;
+ unsigned long opn_idx, idx;
BUG_ON(!pvdev);
rc = camera_v4l2_fh_open(filep);
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 a76ccc06c9e1..d42ada769380 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -101,29 +101,21 @@ static void msm_vfe40_config_irq(struct vfe_device *vfe_dev,
uint32_t irq0_mask, uint32_t irq1_mask,
enum msm_isp_irq_operation oper)
{
- uint32_t val;
-
switch (oper) {
case MSM_ISP_IRQ_ENABLE:
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
- val |= irq0_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28);
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
- val |= irq1_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x2C);
+ vfe_dev->irq0_mask |= irq0_mask;
+ vfe_dev->irq1_mask |= irq1_mask;
break;
case MSM_ISP_IRQ_DISABLE:
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
- val &= ~irq0_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28);
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
- val &= ~irq1_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x2C);
+ vfe_dev->irq0_mask &= ~irq0_mask;
+ vfe_dev->irq1_mask &= ~irq1_mask;
break;
case MSM_ISP_IRQ_SET:
- msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x28);
- msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x2C);
+ vfe_dev->irq0_mask = irq0_mask;
+ vfe_dev->irq1_mask = irq1_mask;
}
+ msm_camera_io_w_mb(vfe_dev->irq0_mask, vfe_dev->vfe_base + 0x28);
+ msm_camera_io_w_mb(vfe_dev->irq1_mask, vfe_dev->vfe_base + 0x2C);
}
static int32_t msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev,
@@ -335,10 +327,8 @@ static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev)
msm_vfe40_init_vbif_parms(vfe_dev, &vbif_parms);
/* BUS_CFG */
msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50);
- vfe_dev->irq0_mask = 0xE00000F1;
- vfe_dev->irq1_mask = 0xFEFFFFFF;
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe40_config_irq(vfe_dev, 0x800000E0, 0xFEFFFF7E,
+ MSM_ISP_IRQ_ENABLE);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x34);
msm_camera_io_w(1, vfe_dev->vfe_base + 0x24);
@@ -346,15 +336,13 @@ static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev)
msm_camera_io_w(0, vfe_dev->vfe_base + 0x30);
msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x34);
msm_camera_io_w(1, vfe_dev->vfe_base + 0x24);
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
}
static void msm_vfe40_clear_status_reg(struct vfe_device *vfe_dev)
{
vfe_dev->irq0_mask = (1 << 31);
vfe_dev->irq1_mask = 0;
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
+ msm_vfe40_config_irq(vfe_dev, (1 << 31), 0,
MSM_ISP_IRQ_SET);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34);
@@ -589,7 +577,6 @@ static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev,
if (*irq_status1 & (1 << 0)) {
vfe_dev->error_info.camif_status =
msm_camera_io_r(vfe_dev->vfe_base + 0x31C);
- vfe_dev->irq1_mask &= ~(1 << 0);
msm_vfe40_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE);
}
@@ -812,11 +799,9 @@ static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
comp_mask |= (axi_data->composite_info[comp_mask_index].
stream_composite_mask << (comp_mask_index * 8));
- vfe_dev->irq0_mask |= 1 << (comp_mask_index + 25);
-
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe40_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0,
+ MSM_ISP_IRQ_ENABLE);
}
static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev,
@@ -828,27 +813,24 @@ static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev,
comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
comp_mask &= ~(0x7F << (comp_mask_index * 8));
- vfe_dev->irq0_mask &= ~(1 << (comp_mask_index + 25));
-
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe40_config_irq(vfe_dev, (1 << (comp_mask_index + 25)), 0,
+ MSM_ISP_IRQ_DISABLE);
}
static void msm_vfe40_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
- vfe_dev->irq0_mask |= 1 << (stream_info->wm[0] + 8);
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe40_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0,
+ MSM_ISP_IRQ_ENABLE);
}
static void msm_vfe40_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[0] + 8));
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe40_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0,
+ MSM_ISP_IRQ_DISABLE);
}
static void msm_vfe40_cfg_framedrop(void __iomem *vfe_base,
@@ -1088,10 +1070,8 @@ static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
temp |= (1 << 1);
msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50);
- vfe_dev->irq0_mask &= 0xFEFFFFFF;
- vfe_dev->irq0_mask |= (1 << 24);
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe40_config_irq(vfe_dev, (1 << 24), 0,
+ MSM_ISP_IRQ_ENABLE);
msm_camera_io_w((fe_cfg->fetch_height - 1),
vfe_dev->vfe_base + 0x238);
@@ -1382,13 +1362,11 @@ static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev,
return;
if (update_state == ENABLE_CAMIF) {
- msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
- msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34);
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x30);
+ msm_camera_io_w_mb(0x81, vfe_dev->vfe_base + 0x34);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24);
- vfe_dev->irq0_mask |= 0xF7;
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask,
- vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe40_config_irq(vfe_dev, 0xF7, 0x81,
+ MSM_ISP_IRQ_ENABLE);
msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318);
bus_en =
@@ -1413,8 +1391,8 @@ static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev,
if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
update_state = DISABLE_CAMIF;
- msm_vfe40_config_irq(vfe_dev, 0, 0,
- MSM_ISP_IRQ_SET);
+ msm_vfe40_config_irq(vfe_dev, 0, 0x81,
+ MSM_ISP_IRQ_DISABLE);
val = msm_camera_io_r(vfe_dev->vfe_base + 0x464);
/* disable danger signal */
msm_camera_io_w_mb(val & ~(1 << 8), vfe_dev->vfe_base + 0x464);
@@ -1897,6 +1875,9 @@ static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev,
comp_mask_reg |= mask_bf_scale << (16 + request_comp_index * 8);
atomic_set(stats_comp_mask, stats_mask |
atomic_read(stats_comp_mask));
+ msm_vfe40_config_irq(vfe_dev,
+ 1 << (request_comp_index + 29), 0,
+ MSM_ISP_IRQ_ENABLE);
} else {
if (!(atomic_read(stats_comp_mask) & stats_mask))
return;
@@ -1904,6 +1885,9 @@ static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev,
~stats_mask & atomic_read(stats_comp_mask));
comp_mask_reg &= ~(mask_bf_scale <<
(16 + request_comp_index * 8));
+ msm_vfe40_config_irq(vfe_dev,
+ 1 << (request_comp_index + 29), 0,
+ MSM_ISP_IRQ_DISABLE);
}
msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x44);
@@ -1919,20 +1903,18 @@ static void msm_vfe40_stats_cfg_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
- vfe_dev->irq0_mask |=
- 1 << (STATS_IDX(stream_info->stream_handle) + 16);
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe40_config_irq(vfe_dev,
+ 1 << (STATS_IDX(stream_info->stream_handle) + 16), 0,
+ MSM_ISP_IRQ_ENABLE);
}
static void msm_vfe40_stats_clear_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
- vfe_dev->irq0_mask &=
- ~(1 << (STATS_IDX(stream_info->stream_handle) + 16));
- msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe40_config_irq(vfe_dev,
+ (1 << (STATS_IDX(stream_info->stream_handle) + 16)), 0,
+ MSM_ISP_IRQ_DISABLE);
}
static void msm_vfe40_stats_cfg_wm_reg(
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
index 08b20395813c..388656b9ca30 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
@@ -70,30 +70,22 @@ static void msm_vfe44_config_irq(struct vfe_device *vfe_dev,
uint32_t irq0_mask, uint32_t irq1_mask,
enum msm_isp_irq_operation oper)
{
- uint32_t val;
-
switch (oper) {
case MSM_ISP_IRQ_ENABLE:
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
- val |= irq0_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28);
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
- val |= irq1_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x2C);
+ vfe_dev->irq0_mask |= irq0_mask;
+ vfe_dev->irq1_mask |= irq1_mask;
break;
case MSM_ISP_IRQ_DISABLE:
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
- val &= ~irq0_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28);
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x2C);
- val &= ~irq1_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x2C);
+ vfe_dev->irq0_mask &= ~irq0_mask;
+ vfe_dev->irq1_mask &= ~irq1_mask;
break;
case MSM_ISP_IRQ_SET:
- msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x28);
- msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x2C);
+ vfe_dev->irq0_mask = irq0_mask;
+ vfe_dev->irq1_mask = irq1_mask;
break;
}
+ msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x28);
+ msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x2C);
}
static int32_t msm_vfe44_init_dt_parms(struct vfe_device *vfe_dev,
@@ -181,10 +173,8 @@ static void msm_vfe44_init_hardware_reg(struct vfe_device *vfe_dev)
/* BUS_CFG */
msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50);
- vfe_dev->irq0_mask = 0xE00000F1;
- vfe_dev->irq1_mask = 0xFFFFFFFF;
- msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe44_config_irq(vfe_dev, 0x800000E0, 0xFFFFFF7E,
+ MSM_ISP_IRQ_ENABLE);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24);
@@ -193,9 +183,7 @@ static void msm_vfe44_init_hardware_reg(struct vfe_device *vfe_dev)
static void msm_vfe44_clear_status_reg(struct vfe_device *vfe_dev)
{
- vfe_dev->irq0_mask = 0x80000000;
- vfe_dev->irq1_mask = 0;
- msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
+ msm_vfe44_config_irq(vfe_dev, 0x80000000, 0,
MSM_ISP_IRQ_SET);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34);
@@ -419,7 +407,6 @@ static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev,
if (*irq_status1 & (1 << 0)) {
vfe_dev->error_info.camif_status =
msm_camera_io_r(vfe_dev->vfe_base + 0x31C);
- vfe_dev->irq1_mask &= ~(1 << 0);
msm_vfe44_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE);
}
@@ -650,9 +637,8 @@ static void msm_vfe44_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
stream_composite_mask << (comp_mask_index * 8));
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
- vfe_dev->irq0_mask |= 1 << (comp_mask_index + 25);
- msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe44_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0,
+ MSM_ISP_IRQ_ENABLE);
}
static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev,
@@ -664,25 +650,22 @@ static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev,
comp_mask &= ~(0x7F << (comp_mask_index * 8));
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
- vfe_dev->irq0_mask &= ~(1 << (comp_mask_index + 25));
- msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe44_config_irq(vfe_dev, (1 << (comp_mask_index + 25)), 0,
+ MSM_ISP_IRQ_DISABLE);
}
static void msm_vfe44_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
- vfe_dev->irq0_mask |= 1 << (stream_info->wm[0] + 8);
- msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe44_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0,
+ MSM_ISP_IRQ_ENABLE);
}
static void msm_vfe44_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
- vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[0] + 8));
- msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe44_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0,
+ MSM_ISP_IRQ_DISABLE);
}
static void msm_vfe44_cfg_framedrop(void __iomem *vfe_base,
@@ -918,10 +901,8 @@ static void msm_vfe44_cfg_fetch_engine(struct vfe_device *vfe_dev,
temp |= (1 << 1);
msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50);
- vfe_dev->irq0_mask &= 0xFEFFFFFF;
- vfe_dev->irq0_mask |= (1 << 24);
- msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask,
- vfe_dev->irq1_mask, MSM_ISP_IRQ_SET);
+ msm_vfe44_config_irq(vfe_dev, (1 << 24), 0,
+ MSM_ISP_IRQ_SET);
msm_camera_io_w((fe_cfg->fetch_height - 1) & 0xFFF,
vfe_dev->vfe_base + 0x238);
@@ -1045,13 +1026,12 @@ static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev,
return;
if (update_state == ENABLE_CAMIF) {
- msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30);
- msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34);
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x30);
+ msm_camera_io_w_mb(0x81, vfe_dev->vfe_base + 0x34);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24);
- vfe_dev->irq0_mask |= 0xF7;
- msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask,
- vfe_dev->irq1_mask, MSM_ISP_IRQ_SET);
+ msm_vfe44_config_irq(vfe_dev, 0xF7, 0x81,
+ MSM_ISP_IRQ_ENABLE);
msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318);
bus_en =
@@ -1075,7 +1055,7 @@ static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev,
if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
update_state = DISABLE_CAMIF;
msm_vfe44_config_irq(vfe_dev, 0,
- 0, MSM_ISP_IRQ_SET);
+ 0x81, MSM_ISP_IRQ_DISABLE);
val = msm_camera_io_r(vfe_dev->vfe_base + 0xC18);
/* disable danger signal */
msm_camera_io_w_mb(val & ~(1 << 8), vfe_dev->vfe_base + 0xC18);
@@ -1526,6 +1506,9 @@ static void msm_vfe44_stats_cfg_comp_mask(
comp_mask_reg |= mask_bf_scale << (16 + request_comp_index * 8);
atomic_set(stats_comp_mask, stats_mask |
atomic_read(stats_comp_mask));
+ msm_vfe44_config_irq(vfe_dev,
+ 1 << (request_comp_index + 29), 0,
+ MSM_ISP_IRQ_ENABLE);
} else {
if (!(atomic_read(stats_comp_mask) & stats_mask))
return;
@@ -1540,6 +1523,9 @@ static void msm_vfe44_stats_cfg_comp_mask(
~stats_mask & atomic_read(stats_comp_mask));
comp_mask_reg &= ~(mask_bf_scale <<
(16 + request_comp_index * 8));
+ msm_vfe44_config_irq(vfe_dev,
+ 1 << (request_comp_index + 29), 0,
+ MSM_ISP_IRQ_DISABLE);
}
msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x44);
@@ -1555,20 +1541,18 @@ static void msm_vfe44_stats_cfg_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
- vfe_dev->irq0_mask |=
- 1 << (STATS_IDX(stream_info->stream_handle) + 15);
- msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe44_config_irq(vfe_dev,
+ 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0,
+ MSM_ISP_IRQ_ENABLE);
}
static void msm_vfe44_stats_clear_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
- vfe_dev->irq0_mask &=
- ~(1 << (STATS_IDX(stream_info->stream_handle) + 15));
- msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe44_config_irq(vfe_dev,
+ (1 << (STATS_IDX(stream_info->stream_handle) + 15)), 0,
+ MSM_ISP_IRQ_DISABLE);
}
static void msm_vfe44_stats_cfg_wm_reg(
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
index 9f815e65edc8..40bb044fde47 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
@@ -92,30 +92,24 @@ static void msm_vfe46_config_irq(struct vfe_device *vfe_dev,
uint32_t irq0_mask, uint32_t irq1_mask,
enum msm_isp_irq_operation oper)
{
- uint32_t val;
-
switch (oper) {
case MSM_ISP_IRQ_ENABLE:
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x5C);
- val |= irq0_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x5C);
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x60);
- val |= irq1_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x60);
+ vfe_dev->irq0_mask |= irq0_mask;
+ vfe_dev->irq1_mask |= irq1_mask;
break;
case MSM_ISP_IRQ_DISABLE:
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x5C);
- val &= ~irq0_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x5C);
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x60);
- val &= ~irq1_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x60);
+ vfe_dev->irq0_mask &= ~irq0_mask;
+ vfe_dev->irq1_mask &= ~irq1_mask;
break;
case MSM_ISP_IRQ_SET:
- msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x5C);
- msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x60);
+ vfe_dev->irq0_mask = irq0_mask;
+ vfe_dev->irq1_mask = irq1_mask;
break;
}
+ msm_camera_io_w_mb(vfe_dev->irq0_mask,
+ vfe_dev->vfe_base + 0x5C);
+ msm_camera_io_w_mb(vfe_dev->irq1_mask,
+ vfe_dev->vfe_base + 0x60);
}
static int32_t msm_vfe46_init_dt_parms(struct vfe_device *vfe_dev,
@@ -208,20 +202,16 @@ static void msm_vfe46_init_hardware_reg(struct vfe_device *vfe_dev)
/* BUS_CFG */
msm_camera_io_w(0x00000001, vfe_dev->vfe_base + 0x84);
/* IRQ_MASK/CLEAR */
- vfe_dev->irq0_mask = 0xE00000F1;
- vfe_dev->irq1_mask = 0xE1FFFFFF;
- msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe46_config_irq(vfe_dev, 0x810000E0, 0xFFFFFF7E,
+ MSM_ISP_IRQ_ENABLE);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x64);
msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x68);
+ msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58);
}
static void msm_vfe46_clear_status_reg(struct vfe_device *vfe_dev)
{
- vfe_dev->irq0_mask = 0x80000000;
- vfe_dev->irq1_mask = 0x0;
- msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe46_config_irq(vfe_dev, 0x80000000, 0, MSM_ISP_IRQ_SET);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x64);
msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x68);
msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58);
@@ -355,7 +345,6 @@ static void msm_vfe46_read_irq_status(struct vfe_device *vfe_dev,
if (*irq_status1 & (1 << 0)) {
vfe_dev->error_info.camif_status =
msm_camera_io_r(vfe_dev->vfe_base + 0x3D0);
- vfe_dev->irq1_mask &= ~(1 << 0);
msm_vfe46_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE);
}
@@ -587,9 +576,8 @@ static void msm_vfe46_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
stream_composite_mask << (comp_mask_index * 8));
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74);
- vfe_dev->irq0_mask |= 1 << (comp_mask_index + 25);
- msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe46_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0,
+ MSM_ISP_IRQ_ENABLE);
}
static void msm_vfe46_axi_clear_comp_mask(struct vfe_device *vfe_dev,
@@ -601,25 +589,22 @@ static void msm_vfe46_axi_clear_comp_mask(struct vfe_device *vfe_dev,
comp_mask &= ~(0x7F << (comp_mask_index * 8));
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74);
- vfe_dev->irq0_mask |= 1 << (comp_mask_index + 25);
- msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe46_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0,
+ MSM_ISP_IRQ_DISABLE);
}
static void msm_vfe46_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
- vfe_dev->irq0_mask |= 1 << (stream_info->wm[0] + 8);
- msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe46_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0,
+ MSM_ISP_IRQ_ENABLE);
}
static void msm_vfe46_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
- vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[0] + 8));
- msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe46_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0,
+ MSM_ISP_IRQ_DISABLE);
}
static void msm_vfe46_cfg_framedrop(void __iomem *vfe_base,
@@ -857,10 +842,8 @@ static void msm_vfe46_cfg_fetch_engine(struct vfe_device *vfe_dev,
temp |= (1 << 1);
msm_camera_io_w(temp, vfe_dev->vfe_base + 0x84);
- vfe_dev->irq0_mask &= 0xFEFFFFFF;
- vfe_dev->irq0_mask |= (1 << 24);
- msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask,
- vfe_dev->irq1_mask, MSM_ISP_IRQ_SET);
+ msm_vfe46_config_irq(vfe_dev, 1 << 24, 0,
+ MSM_ISP_IRQ_ENABLE);
temp = fe_cfg->fetch_height - 1;
msm_camera_io_w(temp & 0x3FFF, vfe_dev->vfe_base + 0x278);
@@ -1120,9 +1103,11 @@ static void msm_vfe46_update_camif_state(struct vfe_device *vfe_dev,
return;
if (update_state == ENABLE_CAMIF) {
- vfe_dev->irq0_mask |= 0xF5;
- msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask,
- vfe_dev->irq1_mask, MSM_ISP_IRQ_SET);
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x64);
+ msm_camera_io_w(0x81, vfe_dev->vfe_base + 0x68);
+ msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x58);
+ msm_vfe46_config_irq(vfe_dev, 0x15, 0x81,
+ MSM_ISP_IRQ_ENABLE);
bus_en =
((vfe_dev->axi_data.
@@ -1148,7 +1133,8 @@ static void msm_vfe46_update_camif_state(struct vfe_device *vfe_dev,
if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
update_state = DISABLE_CAMIF;
- msm_vfe46_config_irq(vfe_dev, 0, 0, MSM_ISP_IRQ_SET);
+ msm_vfe46_config_irq(vfe_dev, 0, 0x81,
+ MSM_ISP_IRQ_DISABLE);
/* disable danger signal */
val = msm_camera_io_r(vfe_dev->vfe_base + 0xC18);
val &= ~(1 << 8);
@@ -1611,6 +1597,9 @@ static void msm_vfe46_stats_cfg_comp_mask(
comp_mask_reg |= mask_bf_scale << (16 + request_comp_index * 8);
atomic_set(stats_comp_mask, stats_mask |
atomic_read(stats_comp_mask));
+ msm_vfe46_config_irq(vfe_dev,
+ 1 << (request_comp_index + 29), 0,
+ MSM_ISP_IRQ_ENABLE);
} else {
if (!(atomic_read(stats_comp_mask) & stats_mask))
return;
@@ -1625,6 +1614,9 @@ static void msm_vfe46_stats_cfg_comp_mask(
~stats_mask & atomic_read(stats_comp_mask));
comp_mask_reg &= ~(mask_bf_scale <<
(16 + request_comp_index * 8));
+ msm_vfe46_config_irq(vfe_dev,
+ 1 << (request_comp_index + 29), 0,
+ MSM_ISP_IRQ_DISABLE);
}
msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x78);
@@ -1640,19 +1632,18 @@ static void msm_vfe46_stats_cfg_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
- vfe_dev->irq0_mask |= 1 << (STATS_IDX(stream_info->stream_handle) + 15);
- msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe46_config_irq(vfe_dev,
+ 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0,
+ MSM_ISP_IRQ_ENABLE);
}
static void msm_vfe46_stats_clear_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
- vfe_dev->irq0_mask &=
- ~(1 << (STATS_IDX(stream_info->stream_handle) + 15));
- msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe46_config_irq(vfe_dev,
+ 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0,
+ MSM_ISP_IRQ_DISABLE);
}
static void msm_vfe46_stats_cfg_wm_reg(
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
index 20aa69f322db..290f100ffeba 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
@@ -149,30 +149,24 @@ void msm_vfe47_config_irq(struct vfe_device *vfe_dev,
uint32_t irq0_mask, uint32_t irq1_mask,
enum msm_isp_irq_operation oper)
{
- uint32_t val;
-
switch (oper) {
case MSM_ISP_IRQ_ENABLE:
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x5C);
- val |= irq0_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x5C);
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x60);
- val |= irq1_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x60);
+ vfe_dev->irq0_mask |= irq0_mask;
+ vfe_dev->irq1_mask |= irq1_mask;
break;
case MSM_ISP_IRQ_DISABLE:
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x5C);
- val &= ~irq0_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x5C);
- val = msm_camera_io_r(vfe_dev->vfe_base + 0x60);
- val &= ~irq1_mask;
- msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x60);
+ vfe_dev->irq0_mask &= ~irq0_mask;
+ vfe_dev->irq1_mask &= ~irq1_mask;
break;
case MSM_ISP_IRQ_SET:
- msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x5C);
- msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x60);
+ vfe_dev->irq0_mask = irq0_mask;
+ vfe_dev->irq1_mask = irq1_mask;
break;
}
+ msm_camera_io_w_mb(vfe_dev->irq0_mask,
+ vfe_dev->vfe_base + 0x5C);
+ msm_camera_io_w_mb(vfe_dev->irq1_mask,
+ vfe_dev->vfe_base + 0x60);
}
static int32_t msm_vfe47_init_dt_parms(struct vfe_device *vfe_dev,
@@ -285,13 +279,6 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev)
else
id = CAM_AHB_CLIENT_VFE1;
- rc = cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SVS_VOTE);
- if (rc < 0) {
- pr_err("%s: failed to vote for AHB\n", __func__);
- goto ahb_vote_fail;
- }
- vfe_dev->ahb_vote = CAM_AHB_SVS_VOTE;
-
rc = vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(
vfe_dev, 1);
if (rc)
@@ -302,6 +289,13 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev)
if (rc)
goto clk_enable_failed;
+ rc = cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SVS_VOTE);
+ if (rc < 0) {
+ pr_err("%s: failed to vote for AHB\n", __func__);
+ goto ahb_vote_fail;
+ }
+ vfe_dev->ahb_vote = CAM_AHB_SVS_VOTE;
+
vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] =
vfe_dev->vfe_base;
@@ -312,14 +306,14 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev)
return rc;
irq_enable_fail:
vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL;
- vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(vfe_dev, 0);
-clk_enable_failed:
- vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0);
-enable_regulators_failed:
if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SUSPEND_VOTE) < 0)
pr_err("%s: failed to remove vote for AHB\n", __func__);
vfe_dev->ahb_vote = CAM_AHB_SUSPEND_VOTE;
ahb_vote_fail:
+ vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(vfe_dev, 0);
+clk_enable_failed:
+ vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0);
+enable_regulators_failed:
return rc;
}
@@ -338,9 +332,6 @@ void msm_vfe47_release_hardware(struct vfe_device *vfe_dev)
msm_isp_flush_tasklet(vfe_dev);
vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL;
- vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(
- vfe_dev, 0);
- vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0);
msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, 0, 0);
@@ -351,7 +342,12 @@ void msm_vfe47_release_hardware(struct vfe_device *vfe_dev)
if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SUSPEND_VOTE) < 0)
pr_err("%s: failed to vote for AHB\n", __func__);
- vfe_dev->ahb_vote = CAM_AHB_SUSPEND_VOTE;
+
+ vfe_dev->ahb_vote = CAM_AHB_SUSPEND_VOTE;
+
+ vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(
+ vfe_dev, 0);
+ vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0);
}
void msm_vfe47_init_hardware_reg(struct vfe_device *vfe_dev)
@@ -382,19 +378,16 @@ void msm_vfe47_init_hardware_reg(struct vfe_device *vfe_dev)
/* BUS_CFG */
msm_camera_io_w(0x00000101, vfe_dev->vfe_base + 0x84);
/* IRQ_MASK/CLEAR */
- vfe_dev->irq0_mask = 0xE00000F3;
- vfe_dev->irq1_mask = 0xFFFFFFFF;
- msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe47_config_irq(vfe_dev, 0x810000E0, 0xFFFFFF7E,
+ MSM_ISP_IRQ_ENABLE);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x64);
msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x68);
+ msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58);
}
void msm_vfe47_clear_status_reg(struct vfe_device *vfe_dev)
{
- vfe_dev->irq0_mask = 0x80000000;
- vfe_dev->irq1_mask = 0x0;
- msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
+ msm_vfe47_config_irq(vfe_dev, 0x80000000, 0x0,
MSM_ISP_IRQ_SET);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x64);
msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x68);
@@ -543,7 +536,6 @@ void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev,
vfe_dev->error_info.camif_status =
msm_camera_io_r(vfe_dev->vfe_base + 0x4A4);
/* mask off camif error after first occurrance */
- vfe_dev->irq1_mask &= ~(1 << 0);
msm_vfe47_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE);
}
@@ -785,9 +777,8 @@ void msm_vfe47_axi_cfg_comp_mask(struct vfe_device *vfe_dev,
stream_composite_mask << (comp_mask_index * 8));
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74);
- vfe_dev->irq0_mask |= 1 << (comp_mask_index + 25);
- msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe47_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0,
+ MSM_ISP_IRQ_ENABLE);
}
void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev,
@@ -799,25 +790,22 @@ void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev,
comp_mask &= ~(0x7F << (comp_mask_index * 8));
msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74);
- vfe_dev->irq0_mask &= ~(1 << (comp_mask_index + 25));
- msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe47_config_irq(vfe_dev, (1 << (comp_mask_index + 25)), 0,
+ MSM_ISP_IRQ_DISABLE);
}
void msm_vfe47_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
- vfe_dev->irq0_mask |= 1 << (stream_info->wm[0] + 8);
- msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe47_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0,
+ MSM_ISP_IRQ_ENABLE);
}
void msm_vfe47_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev,
struct msm_vfe_axi_stream *stream_info)
{
- vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[0] + 8));
- msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask,
- MSM_ISP_IRQ_SET);
+ msm_vfe47_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0,
+ MSM_ISP_IRQ_DISABLE);
}
void msm_vfe47_cfg_framedrop(void __iomem *vfe_base,
@@ -1065,10 +1053,8 @@ void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
temp |= (1 << 1);
msm_camera_io_w(temp, vfe_dev->vfe_base + 0x84);
- vfe_dev->irq0_mask &= 0xFEFFFFFF;
- vfe_dev->irq0_mask |= (1 << 24);
- msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask,
- vfe_dev->irq1_mask, MSM_ISP_IRQ_SET);
+ msm_vfe47_config_irq(vfe_dev, (1 << 24), 0,
+ MSM_ISP_IRQ_ENABLE);
temp = fe_cfg->fetch_height - 1;
msm_camera_io_w(temp & 0x3FFF, vfe_dev->vfe_base + 0x308);
@@ -1394,9 +1380,11 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev,
val = msm_camera_io_r(vfe_dev->vfe_base + 0x47C);
if (update_state == ENABLE_CAMIF) {
- vfe_dev->irq0_mask |= 0xF5;
- msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask,
- vfe_dev->irq1_mask, MSM_ISP_IRQ_SET);
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x64);
+ msm_camera_io_w(0x81, vfe_dev->vfe_base + 0x68);
+ msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x58);
+ msm_vfe47_config_irq(vfe_dev, 0x15, 0x81,
+ MSM_ISP_IRQ_ENABLE);
if ((vfe_dev->hvx_cmd > HVX_DISABLE) &&
(vfe_dev->hvx_cmd <= HVX_ROUND_TRIP))
@@ -1427,8 +1415,9 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev,
/* For testgen always halt on camif boundary */
if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN)
update_state = DISABLE_CAMIF;
- /* turn off all irq before camif disable */
- msm_vfe47_config_irq(vfe_dev, 0, 0, MSM_ISP_IRQ_SET);
+ /* turn off camif violation and error irqs */
+ msm_vfe47_config_irq(vfe_dev, 0, 0x81,
+ MSM_ISP_IRQ_DISABLE);
val = msm_camera_io_r(vfe_dev->vfe_base + 0x464);
/* disable danger signal */
msm_camera_io_w_mb(val & ~(1 << 8), vfe_dev->vfe_base + 0x464);
@@ -1896,6 +1885,8 @@ void msm_vfe47_stats_cfg_comp_mask(
comp_mask_reg |= stats_mask << (request_comp_index * 16);
atomic_set(stats_comp_mask, stats_mask |
atomic_read(stats_comp_mask));
+ msm_vfe47_config_irq(vfe_dev, 1 << (29 + request_comp_index),
+ 0, MSM_ISP_IRQ_ENABLE);
} else {
if (!(atomic_read(stats_comp_mask) & stats_mask))
return;
@@ -1903,6 +1894,8 @@ void msm_vfe47_stats_cfg_comp_mask(
atomic_set(stats_comp_mask,
~stats_mask & atomic_read(stats_comp_mask));
comp_mask_reg &= ~(stats_mask << (request_comp_index * 16));
+ msm_vfe47_config_irq(vfe_dev, 1 << (29 + request_comp_index),
+ 0, MSM_ISP_IRQ_DISABLE);
}
msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x78);
@@ -1919,49 +1912,39 @@ void msm_vfe47_stats_cfg_wm_irq_mask(
struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info)
{
- uint32_t irq_mask;
- uint32_t irq_mask_1;
-
- irq_mask = vfe_dev->irq0_mask;
- irq_mask_1 = vfe_dev->irq1_mask;
-
switch (STATS_IDX(stream_info->stream_handle)) {
case STATS_COMP_IDX_AEC_BG:
- irq_mask |= 1 << 15;
+ msm_vfe47_config_irq(vfe_dev, 1 << 15, 0, MSM_ISP_IRQ_ENABLE);
break;
case STATS_COMP_IDX_HDR_BE:
- irq_mask |= 1 << 16;
+ msm_vfe47_config_irq(vfe_dev, 1 << 16, 0, MSM_ISP_IRQ_ENABLE);
break;
case STATS_COMP_IDX_BG:
- irq_mask |= 1 << 17;
+ msm_vfe47_config_irq(vfe_dev, 1 << 17, 0, MSM_ISP_IRQ_ENABLE);
break;
case STATS_COMP_IDX_BF:
- irq_mask |= 1 << 18;
- irq_mask_1 |= 1 << 26;
+ msm_vfe47_config_irq(vfe_dev, 1 << 18, 1 << 26,
+ MSM_ISP_IRQ_ENABLE);
break;
case STATS_COMP_IDX_HDR_BHIST:
- irq_mask |= 1 << 19;
+ msm_vfe47_config_irq(vfe_dev, 1 << 19, 0, MSM_ISP_IRQ_ENABLE);
break;
case STATS_COMP_IDX_RS:
- irq_mask |= 1 << 20;
+ msm_vfe47_config_irq(vfe_dev, 1 << 20, 0, MSM_ISP_IRQ_ENABLE);
break;
case STATS_COMP_IDX_CS:
- irq_mask |= 1 << 21;
+ msm_vfe47_config_irq(vfe_dev, 1 << 21, 0, MSM_ISP_IRQ_ENABLE);
break;
case STATS_COMP_IDX_IHIST:
- irq_mask |= 1 << 22;
+ msm_vfe47_config_irq(vfe_dev, 1 << 22, 0, MSM_ISP_IRQ_ENABLE);
break;
case STATS_COMP_IDX_BHIST:
- irq_mask |= 1 << 23;
+ msm_vfe47_config_irq(vfe_dev, 1 << 23, 0, MSM_ISP_IRQ_ENABLE);
break;
default:
pr_err("%s: Invalid stats idx %d\n", __func__,
STATS_IDX(stream_info->stream_handle));
}
-
- msm_vfe47_config_irq(vfe_dev, irq_mask, irq_mask_1, MSM_ISP_IRQ_SET);
- vfe_dev->irq0_mask = irq_mask;
- vfe_dev->irq1_mask = irq_mask_1;
}
void msm_vfe47_stats_clear_wm_irq_mask(
@@ -1975,41 +1958,37 @@ void msm_vfe47_stats_clear_wm_irq_mask(
switch (STATS_IDX(stream_info->stream_handle)) {
case STATS_COMP_IDX_AEC_BG:
- irq_mask &= ~(1 << 15);
+ msm_vfe47_config_irq(vfe_dev, 1 << 15, 0, MSM_ISP_IRQ_DISABLE);
break;
case STATS_COMP_IDX_HDR_BE:
- irq_mask &= ~(1 << 16);
+ msm_vfe47_config_irq(vfe_dev, 1 << 16, 0, MSM_ISP_IRQ_DISABLE);
break;
case STATS_COMP_IDX_BG:
- irq_mask &= ~(1 << 17);
+ msm_vfe47_config_irq(vfe_dev, 1 << 17, 0, MSM_ISP_IRQ_DISABLE);
break;
case STATS_COMP_IDX_BF:
- irq_mask &= ~(1 << 18);
- irq_mask_1 &= ~(1 << 26);
+ msm_vfe47_config_irq(vfe_dev, 1 << 18, 1 << 26,
+ MSM_ISP_IRQ_DISABLE);
break;
case STATS_COMP_IDX_HDR_BHIST:
- irq_mask &= ~(1 << 19);
+ msm_vfe47_config_irq(vfe_dev, 1 << 19, 0, MSM_ISP_IRQ_DISABLE);
break;
case STATS_COMP_IDX_RS:
- irq_mask &= ~(1 << 20);
+ msm_vfe47_config_irq(vfe_dev, 1 << 20, 0, MSM_ISP_IRQ_DISABLE);
break;
case STATS_COMP_IDX_CS:
- irq_mask &= ~(1 << 21);
+ msm_vfe47_config_irq(vfe_dev, 1 << 21, 0, MSM_ISP_IRQ_DISABLE);
break;
case STATS_COMP_IDX_IHIST:
- irq_mask &= ~(1 << 22);
+ msm_vfe47_config_irq(vfe_dev, 1 << 22, 0, MSM_ISP_IRQ_DISABLE);
break;
case STATS_COMP_IDX_BHIST:
- irq_mask &= ~(1 << 23);
+ msm_vfe47_config_irq(vfe_dev, 1 << 23, 0, MSM_ISP_IRQ_DISABLE);
break;
default:
pr_err("%s: Invalid stats idx %d\n", __func__,
STATS_IDX(stream_info->stream_handle));
}
-
- msm_vfe47_config_irq(vfe_dev, irq_mask, irq_mask_1, MSM_ISP_IRQ_SET);
- vfe_dev->irq0_mask = irq_mask;
- vfe_dev->irq1_mask = irq_mask_1;
}
void msm_vfe47_stats_cfg_wm_reg(
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 3dd55e02826d..8721fc18eaa8 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
@@ -1188,15 +1188,9 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg)
vfe_dev->vt_enable = stream_cfg_cmd->vt_enable;
msm_isp_start_avtimer();
}
- if (stream_info->num_planes > 1) {
+ if (stream_info->num_planes > 1)
msm_isp_axi_reserve_comp_mask(
&vfe_dev->axi_data, stream_info);
- vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_comp_mask(vfe_dev, stream_info);
- } else {
- vfe_dev->hw_info->vfe_ops.axi_ops.
- cfg_wm_irq_mask(vfe_dev, stream_info);
- }
for (i = 0; i < stream_info->num_planes; i++) {
vfe_dev->hw_info->vfe_ops.axi_ops.
@@ -1252,14 +1246,8 @@ int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg)
clear_wm_xbar_reg(vfe_dev, stream_info, i);
}
- if (stream_info->num_planes > 1) {
- vfe_dev->hw_info->vfe_ops.axi_ops.
- clear_comp_mask(vfe_dev, stream_info);
+ if (stream_info->num_planes > 1)
msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info);
- } else {
- vfe_dev->hw_info->vfe_ops.axi_ops.
- clear_wm_irq_mask(vfe_dev, stream_info);
- }
vfe_dev->hw_info->vfe_ops.axi_ops.clear_framedrop(vfe_dev, stream_info);
msm_isp_axi_free_wm(axi_data, stream_info);
@@ -2617,6 +2605,13 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev,
return rc;
}
spin_unlock_irqrestore(&stream_info->lock, flags);
+ if (stream_info->num_planes > 1) {
+ vfe_dev->hw_info->vfe_ops.axi_ops.
+ cfg_comp_mask(vfe_dev, stream_info);
+ } else {
+ vfe_dev->hw_info->vfe_ops.axi_ops.
+ cfg_wm_irq_mask(vfe_dev, stream_info);
+ }
stream_info->state = START_PENDING;
@@ -2733,6 +2728,13 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev,
spin_unlock_irqrestore(&stream_info->lock, flags);
wait_for_complete_for_this_stream = 0;
+ if (stream_info->num_planes > 1)
+ vfe_dev->hw_info->vfe_ops.axi_ops.
+ clear_comp_mask(vfe_dev, stream_info);
+ else
+ vfe_dev->hw_info->vfe_ops.axi_ops.
+ clear_wm_irq_mask(vfe_dev, stream_info);
+
stream_info->state = STOP_PENDING;
if (!halt && !ext_read &&
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 e98c99fcb62d..4aef6b5c7f38 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
@@ -444,10 +444,6 @@ int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
stream_info->framedrop_pattern = 0x1;
stream_info->framedrop_period = framedrop_period - 1;
- if (!stream_info->composite_flag)
- vfe_dev->hw_info->vfe_ops.stats_ops.
- cfg_wm_irq_mask(vfe_dev, stream_info);
-
if (stream_info->init_stats_frame_drop == 0)
vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev,
stream_info);
@@ -485,10 +481,6 @@ int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg)
rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd);
}
- if (!stream_info->composite_flag)
- vfe_dev->hw_info->vfe_ops.stats_ops.
- clear_wm_irq_mask(vfe_dev, stream_info);
-
vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info);
memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream));
return 0;
@@ -711,6 +703,9 @@ static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev,
pr_err("%s: No buffer for stream%d\n", __func__, idx);
return rc;
}
+ if (!stream_info->composite_flag)
+ vfe_dev->hw_info->vfe_ops.stats_ops.
+ cfg_wm_irq_mask(vfe_dev, stream_info);
if (vfe_dev->axi_data.src_info[VFE_PIX_0].active)
stream_info->state = STATS_START_PENDING;
@@ -784,6 +779,10 @@ static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev,
return -EINVAL;
}
+ if (!stream_info->composite_flag)
+ vfe_dev->hw_info->vfe_ops.stats_ops.
+ clear_wm_irq_mask(vfe_dev, stream_info);
+
if (vfe_dev->axi_data.src_info[VFE_PIX_0].active)
stream_info->state = STATS_STOP_PENDING;
else
diff --git a/drivers/mfd/wcd9xxx-utils.c b/drivers/mfd/wcd9xxx-utils.c
index 2160dfd063b1..22d61d96a11d 100644
--- a/drivers/mfd/wcd9xxx-utils.c
+++ b/drivers/mfd/wcd9xxx-utils.c
@@ -39,6 +39,10 @@ static enum wcd9xxx_intf_status wcd9xxx_intf = -1;
static struct mfd_cell tavil_devs[] = {
{
+ .name = "qcom-wcd-pinctrl",
+ .of_compatible = "qcom,wcd-pinctrl",
+ },
+ {
.name = "tavil_codec",
},
};
diff --git a/drivers/misc/qcom/qdsp6v2/q6audio_v2.c b/drivers/misc/qcom/qdsp6v2/q6audio_v2.c
index 7eb6629b1e57..51ba23da1270 100644
--- a/drivers/misc/qcom/qdsp6v2/q6audio_v2.c
+++ b/drivers/misc/qcom/qdsp6v2/q6audio_v2.c
@@ -85,6 +85,13 @@ void audio_in_get_dsp_frames(void *priv,
pr_debug("%s:session id %d: enc_framesotal_size=0x%8x\n", __func__,
audio->ac->session, payload[4]);
+ /* Ensure the index is within max array size: FRAME_NUM */
+ if (index >= FRAME_NUM) {
+ pr_err("%s: Invalid index %d\n",
+ __func__, index);
+ return;
+ }
+
audio->out_frame_info[index][0] = payload[9];
audio->out_frame_info[index][1] = payload[5];
diff --git a/drivers/of/of_batterydata.c b/drivers/of/of_batterydata.c
index 5f140cd0c2a6..4410f270f557 100644
--- a/drivers/of/of_batterydata.c
+++ b/drivers/of/of_batterydata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2016, 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
@@ -312,32 +312,15 @@ static int64_t of_batterydata_convert_battery_id_kohm(int batt_id_uv,
struct device_node *of_batterydata_get_best_profile(
const struct device_node *batterydata_container_node,
- const char *psy_name, const char *batt_type)
+ int batt_id_kohm, const char *batt_type)
{
struct batt_ids batt_ids;
struct device_node *node, *best_node = NULL;
- struct power_supply *psy;
const char *battery_type = NULL;
- union power_supply_propval ret = {0, };
int delta = 0, best_delta = 0, best_id_kohm = 0, id_range_pct,
- batt_id_kohm = 0, i = 0, rc = 0, limit = 0;
+ i = 0, rc = 0, limit = 0;
bool in_range = false;
- psy = power_supply_get_by_name(psy_name);
- if (!psy) {
- pr_err("%s supply not found. defer\n", psy_name);
- return ERR_PTR(-EPROBE_DEFER);
- }
-
- rc = power_supply_get_property(psy, POWER_SUPPLY_PROP_RESISTANCE_ID,
- &ret);
- if (rc) {
- pr_err("failed to retrieve resistance value rc=%d\n", rc);
- return ERR_PTR(-ENOSYS);
- }
-
- batt_id_kohm = ret.intval / 1000;
-
/* read battery id range percentage for best profile */
rc = of_property_read_u32(batterydata_container_node,
"qcom,batt-id-range-pct", &id_range_pct);
diff --git a/drivers/power/qcom-charger/qpnp-fg.c b/drivers/power/qcom-charger/qpnp-fg.c
index 8660c1f8c3f5..0658f0d3b1eb 100644
--- a/drivers/power/qcom-charger/qpnp-fg.c
+++ b/drivers/power/qcom-charger/qpnp-fg.c
@@ -4772,8 +4772,7 @@ fail:
#define BATTERY_PSY_WAIT_MS 2000
static int fg_batt_profile_init(struct fg_chip *chip)
{
- int rc = 0, ret;
- int len;
+ int rc = 0, ret, len, batt_id;
struct device_node *node = chip->pdev->dev.of_node;
struct device_node *batt_node, *profile_node;
const char *data, *batt_type_str;
@@ -4802,14 +4801,16 @@ wait:
goto no_profile;
}
+ batt_id = get_sram_prop_now(chip, FG_DATA_BATT_ID);
+ batt_id /= 1000;
if (fg_debug_mask & FG_STATUS)
- pr_info("battery id = %d\n",
- get_sram_prop_now(chip, FG_DATA_BATT_ID));
- profile_node = of_batterydata_get_best_profile(batt_node, "bms",
+ pr_info("battery id = %dKOhms\n", batt_id);
+
+ profile_node = of_batterydata_get_best_profile(batt_node, batt_id,
fg_batt_type);
- if (!profile_node) {
- pr_err("couldn't find profile handle\n");
- rc = -ENODATA;
+ if (IS_ERR_OR_NULL(profile_node)) {
+ rc = PTR_ERR(profile_node);
+ pr_err("couldn't find profile handle %d\n", rc);
goto no_profile;
}
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index 7810ecb9b15b..ad00a987ae41 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -25,54 +25,98 @@
#include "smb-lib.h"
#include "pmic-voter.h"
-#define SMB2_DEFAULT_FCC_UA 3000000
-#define SMB2_DEFAULT_FV_UV 4350000
-#define SMB2_DEFAULT_ICL_UA 3000000
+#define SMB2_DEFAULT_FCC_UA 3000000
+#define SMB2_DEFAULT_FV_UV 4350000
+#define SMB2_DEFAULT_ICL_UA 3000000
+#define SMB2_DEFAULT_WPWR_UW 8000000
static struct smb_params v1_params = {
- .fcc = {
+ .fcc = {
.name = "fast charge current",
.reg = FAST_CHARGE_CURRENT_CFG_REG,
.min_u = 0,
.max_u = 4500000,
.step_u = 25000,
},
- .fv = {
+ .fv = {
.name = "float voltage",
.reg = FLOAT_VOLTAGE_CFG_REG,
- .min_u = 3487500,
- .max_u = 4920000,
- .step_u = 7500,
+ .min_u = 2500000,
+ .max_u = 5000000,
+ .step_u = 10000,
},
- .usb_icl = {
+ .usb_icl = {
.name = "usb input current limit",
.reg = USBIN_CURRENT_LIMIT_CFG_REG,
.min_u = 0,
- .max_u = 4800000,
+ .max_u = 6000000,
.step_u = 25000,
},
- .icl_stat = {
+ .icl_stat = {
.name = "input current limit status",
.reg = ICL_STATUS_REG,
.min_u = 0,
.max_u = 4800000,
.step_u = 25000,
},
- .dc_icl = {
+ .dc_icl = {
.name = "dc input current limit",
.reg = DCIN_CURRENT_LIMIT_CFG_REG,
.min_u = 0,
+ .max_u = 6000000,
+ .step_u = 25000,
+ },
+ .dc_icl_pt_lv = {
+ .name = "dc icl PT <8V",
+ .reg = ZIN_ICL_PT_REG,
+ .min_u = 0,
+ .max_u = 3000000,
+ .step_u = 25000,
+ },
+ .dc_icl_pt_hv = {
+ .name = "dc icl PT >8V",
+ .reg = ZIN_ICL_PT_HV_REG,
+ .min_u = 0,
+ .max_u = 3000000,
+ .step_u = 25000,
+ },
+ .dc_icl_div2_lv = {
+ .name = "dc icl div2 <5.5V",
+ .reg = ZIN_ICL_LV_REG,
+ .min_u = 0,
+ .max_u = 3000000,
+ .step_u = 25000,
+ },
+ .dc_icl_div2_mid_lv = {
+ .name = "dc icl div2 5.5-6.5V",
+ .reg = ZIN_ICL_MID_LV_REG,
+ .min_u = 0,
+ .max_u = 3000000,
+ .step_u = 25000,
+ },
+ .dc_icl_div2_mid_hv = {
+ .name = "dc icl div2 6.5-8.0V",
+ .reg = ZIN_ICL_MID_HV_REG,
+ .min_u = 0,
+ .max_u = 3000000,
+ .step_u = 25000,
+ },
+ .dc_icl_div2_hv = {
+ .name = "dc icl div2 >8.0V",
+ .reg = ZIN_ICL_HV_REG,
+ .min_u = 0,
.max_u = 3000000,
.step_u = 25000,
},
};
struct smb_dt_props {
- bool suspend_input;
- int fcc_ua;
- int usb_icl_ua;
- int dc_icl_ua;
- int fv_uv;
+ bool suspend_input;
+ int fcc_ua;
+ int usb_icl_ua;
+ int dc_icl_ua;
+ int fv_uv;
+ int wipower_max_uw;
};
struct smb2 {
@@ -125,6 +169,11 @@ static int smb2_parse_dt(struct smb2 *chip)
if (rc < 0)
chip->dt.dc_icl_ua = SMB2_DEFAULT_ICL_UA;
+ rc = of_property_read_u32(node,
+ "qcom,wipower-max-uw", &chip->dt.wipower_max_uw);
+ if (rc < 0)
+ chip->dt.wipower_max_uw = SMB2_DEFAULT_WPWR_UW;
+
return 0;
}
@@ -486,6 +535,57 @@ static int smb2_init_vconn_regulator(struct smb2 *chip)
/***************************
* HARDWARE INITIALIZATION *
***************************/
+static int smb2_config_wipower_input_power(struct smb2 *chip, int uw)
+{
+ int rc;
+ int ua;
+ struct smb_charger *chg = &chip->chg;
+ s64 nw = (s64)uw * 1000;
+
+ ua = div_s64(nw, ZIN_ICL_PT_MAX_MV);
+ rc = smblib_set_charge_param(chg, &chg->param.dc_icl_pt_lv, ua);
+ if (rc < 0) {
+ pr_err("Couldn't configure dc_icl_pt_lv rc = %d\n", rc);
+ return rc;
+ }
+
+ ua = div_s64(nw, ZIN_ICL_PT_HV_MAX_MV);
+ rc = smblib_set_charge_param(chg, &chg->param.dc_icl_pt_hv, ua);
+ if (rc < 0) {
+ pr_err("Couldn't configure dc_icl_pt_hv rc = %d\n", rc);
+ return rc;
+ }
+
+ ua = div_s64(nw, ZIN_ICL_LV_MAX_MV);
+ rc = smblib_set_charge_param(chg, &chg->param.dc_icl_div2_lv, ua);
+ if (rc < 0) {
+ pr_err("Couldn't configure dc_icl_div2_lv rc = %d\n", rc);
+ return rc;
+ }
+
+ ua = div_s64(nw, ZIN_ICL_MID_LV_MAX_MV);
+ rc = smblib_set_charge_param(chg, &chg->param.dc_icl_div2_mid_lv, ua);
+ if (rc < 0) {
+ pr_err("Couldn't configure dc_icl_div2_mid_lv rc = %d\n", rc);
+ return rc;
+ }
+
+ ua = div_s64(nw, ZIN_ICL_MID_HV_MAX_MV);
+ rc = smblib_set_charge_param(chg, &chg->param.dc_icl_div2_mid_hv, ua);
+ if (rc < 0) {
+ pr_err("Couldn't configure dc_icl_div2_mid_hv rc = %d\n", rc);
+ return rc;
+ }
+
+ ua = div_s64(nw, ZIN_ICL_HV_MAX_MV);
+ rc = smblib_set_charge_param(chg, &chg->param.dc_icl_div2_hv, ua);
+ if (rc < 0) {
+ pr_err("Couldn't configure dc_icl_div2_hv rc = %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
static int smb2_init_hw(struct smb2 *chip)
{
@@ -582,6 +682,13 @@ static int smb2_init_hw(struct smb2 *chip)
return rc;
}
+ /* configure wipower watts */
+ rc = smb2_config_wipower_input_power(chip, chip->dt.wipower_max_uw);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure wipower rc=%d\n", rc);
+ return rc;
+ }
+
return rc;
}
diff --git a/drivers/power/qcom-charger/qpnp-smbcharger.c b/drivers/power/qcom-charger/qpnp-smbcharger.c
index 2536f4ec5c15..6c1e58d046e8 100644
--- a/drivers/power/qcom-charger/qpnp-smbcharger.c
+++ b/drivers/power/qcom-charger/qpnp-smbcharger.c
@@ -3507,19 +3507,27 @@ static int smbchg_config_chg_battery_type(struct smbchg_chip *chip)
if (chip->battery_type && !strcmp(prop.strval, chip->battery_type))
return 0;
+ chip->battery_type = prop.strval;
batt_node = of_parse_phandle(node, "qcom,battery-data", 0);
if (!batt_node) {
pr_smb(PR_MISC, "No batterydata available\n");
return 0;
}
+ rc = power_supply_get_property(chip->bms_psy,
+ POWER_SUPPLY_PROP_RESISTANCE_ID, &prop);
+ if (rc < 0) {
+ pr_smb(PR_STATUS, "Unable to read battery-id rc=%d\n", rc);
+ return 0;
+ }
+
profile_node = of_batterydata_get_best_profile(batt_node,
- "bms", NULL);
- if (!profile_node) {
- pr_err("couldn't find profile handle\n");
- return -EINVAL;
+ prop.intval / 1000, NULL);
+ if (IS_ERR_OR_NULL(profile_node)) {
+ rc = PTR_ERR(profile_node);
+ pr_err("couldn't find profile handle %d\n", rc);
+ return rc;
}
- chip->battery_type = prop.strval;
/* change vfloat */
rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h
index 8b3d00b6a5c1..1ee4945b625f 100644
--- a/drivers/power/qcom-charger/smb-lib.h
+++ b/drivers/power/qcom-charger/smb-lib.h
@@ -62,6 +62,12 @@ struct smb_params {
struct smb_chg_param usb_icl;
struct smb_chg_param icl_stat;
struct smb_chg_param dc_icl;
+ struct smb_chg_param dc_icl_pt_lv;
+ struct smb_chg_param dc_icl_pt_hv;
+ struct smb_chg_param dc_icl_div2_lv;
+ struct smb_chg_param dc_icl_div2_mid_lv;
+ struct smb_chg_param dc_icl_div2_mid_hv;
+ struct smb_chg_param dc_icl_div2_hv;
};
struct parallel_params {
diff --git a/drivers/power/qcom-charger/smb-reg.h b/drivers/power/qcom-charger/smb-reg.h
index f63e983c595c..5af01c229f01 100644
--- a/drivers/power/qcom-charger/smb-reg.h
+++ b/drivers/power/qcom-charger/smb-reg.h
@@ -719,6 +719,15 @@ enum {
#define ZIN_ICL_MID_HV_REG (DCIN_BASE + 0x98)
#define ZIN_ICL_MID_HV_MASK GENMASK(7, 0)
+enum {
+ ZIN_ICL_PT_MAX_MV = 8000,
+ ZIN_ICL_PT_HV_MAX_MV = 9000,
+ ZIN_ICL_LV_MAX_MV = 5500,
+ ZIN_ICL_MID_LV_MAX_MV = 6500,
+ ZIN_ICL_MID_HV_MAX_MV = 8000,
+ ZIN_ICL_HV_MAX_MV = 11000,
+};
+
/* MISC Peripheral Registers */
#define REVISION1_REG (MISC_BASE + 0x00)
#define DIG_MINOR_MASK GENMASK(7, 0)
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index c13e811a5d71..78c5c47e4e8b 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -1109,10 +1109,18 @@ static int cpr3_regulator_init_cprh_corners(struct cpr3_regulator *vreg)
}
if (ro_sel == INT_MAX) {
- cpr3_err(vreg, "corner=%d has invalid RO select value\n",
- i);
- rc = -EINVAL;
- goto free_base_quots;
+ if (!corner->proc_freq) {
+ /*
+ * Corner is not used as active DCVS set point
+ * select RO 0 arbitrarily.
+ */
+ ro_sel = 0;
+ } else {
+ cpr3_err(vreg, "corner=%d has invalid RO select value\n",
+ i);
+ rc = -EINVAL;
+ goto free_base_quots;
+ }
}
open_loop_volt_steps = DIV_ROUND_UP(corner->open_loop_volt -
@@ -1121,9 +1129,11 @@ static int cpr3_regulator_init_cprh_corners(struct cpr3_regulator *vreg)
floor_volt_steps = DIV_ROUND_UP(corner->floor_volt -
ctrl->base_volt,
ctrl->step_volt);
- delta_quot_steps = DIV_ROUND_UP(corner->target_quot[ro_sel] -
- base_quots[ro_sel],
- CPRH_DELTA_QUOT_STEP_FACTOR);
+ delta_quot_steps = corner->proc_freq ?
+ DIV_ROUND_UP(corner->target_quot[ro_sel] -
+ base_quots[ro_sel],
+ CPRH_DELTA_QUOT_STEP_FACTOR) :
+ 0;
if (open_loop_volt_steps > CPRH_CORNER_INIT_VOLTAGE_MAX_VALUE ||
floor_volt_steps > CPRH_CORNER_FLOOR_VOLTAGE_MAX_VALUE ||
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index d750b70519d1..3ddc1dc3c982 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -572,7 +572,13 @@ struct cpr3_panic_regs_info {
* when hardware closed-loop attempts to exceed the ceiling
* voltage
* @apm: Handle to the array power mux (APM)
- * @apm_threshold_volt: APM threshold voltage in microvolts
+ * @apm_threshold_volt: Voltage in microvolts which defines the threshold
+ * voltage to determine the APM supply selection for
+ * each corner
+ * @apm_crossover_volt: Voltage in microvolts corresponding to the voltage that
+ * the VDD supply must be set to while an APM switch is in
+ * progress. This element must be initialized for CPRh
+ * controllers when an APM threshold voltage is defined
* @apm_adj_volt: Minimum difference between APM threshold voltage and
* open-loop voltage which allows the APM threshold voltage
* to be used as a ceiling
@@ -736,6 +742,7 @@ struct cpr3_controller {
int ceiling_irq;
struct msm_apm_ctrl_dev *apm;
int apm_threshold_volt;
+ int apm_crossover_volt;
int apm_adj_volt;
enum msm_apm_supply apm_high_supply;
enum msm_apm_supply apm_low_supply;
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index ffd3db1a6dff..dfdd6921fed5 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -697,61 +697,38 @@ free_temp:
}
/**
- * cprh_kbss_apm_threshold_as_corner() - introduce a corner whose floor, open-loop,
- * and ceiling voltages correspond to the APM threshold voltage.
+ * cprh_kbss_apm_crossover_as_corner() - introduce a corner whose floor,
+ * open-loop, and ceiling voltages correspond to the APM
+ * crossover voltage.
* @vreg: Pointer to the CPR3 regulator
*
* The APM corner is utilized as a crossover corner by OSM and CPRh
- * hardware to determine the correct APM supply selection for the
- * rest of the corners. This function must be called after all other
- * functions which load per-corner values.
+ * hardware to set the VDD supply voltage during the APM switch
+ * routine.
*
* Return: 0 on success, errno on failure
*/
-static int cprh_kbss_apm_threshold_as_corner(struct cpr3_regulator *vreg)
+static int cprh_kbss_apm_crossover_as_corner(struct cpr3_regulator *vreg)
{
struct cpr3_controller *ctrl = vreg->thread->ctrl;
struct cpr3_corner *corner;
- struct cprh_corner_band *corner_band;
- int i, threshold, apm_corner = 0;
- if (!ctrl->apm_threshold_volt) {
- /* APM voltage threshold corner not required. */
+ if (!ctrl->apm_crossover_volt) {
+ /* APM voltage crossover corner not required. */
return 0;
}
- threshold = ctrl->apm_threshold_volt;
- vreg->corner_count++;
-
- for (i = vreg->corner_count - 1; i >= 1; i--) {
- corner = &vreg->corner[i];
-
- if (threshold >= vreg->corner[i - 1].open_loop_volt) {
- apm_corner = i;
- break;
- }
-
- memcpy(corner, &vreg->corner[i - 1], sizeof(*corner));
- }
-
- corner = &vreg->corner[apm_corner];
- corner->proc_freq = 0;
- corner->floor_volt = threshold;
- corner->ceiling_volt = threshold;
- corner->open_loop_volt = threshold;
- corner->use_open_loop = true;
- cpr3_info(vreg, "APM threshold corner=%d, open-loop=%d\n",
- apm_corner, threshold);
-
+ corner = &vreg->corner[vreg->corner_count];
/*
- * Update corner band mappings to account for the inserted
- * APM crossover corner.
+ * 0 MHz indicates this corner is not to be
+ * used as active DCVS set point.
*/
- for (i = 0; i < vreg->corner_band_count; i++) {
- corner_band = &vreg->corner_band[i];
- if (corner_band->corner >= apm_corner)
- corner_band->corner++;
- }
+ corner->proc_freq = 0;
+ corner->floor_volt = ctrl->apm_crossover_volt;
+ corner->ceiling_volt = ctrl->apm_crossover_volt;
+ corner->open_loop_volt = ctrl->apm_crossover_volt;
+ corner->use_open_loop = true;
+ vreg->corner_count++;
return 0;
}
@@ -1203,9 +1180,9 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
return -EINVAL;
}
- rc = cprh_kbss_apm_threshold_as_corner(vreg);
+ rc = cprh_kbss_apm_crossover_as_corner(vreg);
if (rc) {
- cpr3_err(vreg, "unable to introduce APM voltage threshold corner\n, rc=%d\n",
+ cpr3_err(vreg, "unable to introduce APM voltage crossover corner, rc=%d\n",
rc);
return rc;
}
@@ -1288,8 +1265,18 @@ static int cprh_kbss_init_controller(struct cpr3_controller *ctrl)
rc = of_property_read_u32(ctrl->dev->of_node,
"qcom,apm-threshold-voltage",
&ctrl->apm_threshold_volt);
- if (rc)
+ if (rc) {
cpr3_debug(ctrl, "qcom,apm-threshold-voltage not specified\n");
+ } else {
+ rc = of_property_read_u32(ctrl->dev->of_node,
+ "qcom,apm-crossover-voltage",
+ &ctrl->apm_crossover_volt);
+ if (rc) {
+ cpr3_err(ctrl, "error reading property qcom,apm-crossover-voltage, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
of_property_read_u32(ctrl->dev->of_node, "qcom,apm-hysteresis-voltage",
&ctrl->apm_adj_volt);
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index bb3f092f6de9..36b9a9435910 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_MSM_GLINK_SMD_XPRT) += glink_smd_xprt.o
obj-$(CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT)+= glink_smem_native_xprt.o
obj-$(CONFIG_MSM_SMEM_LOGGING) += smem_log.o
obj-$(CONFIG_MSM_SYSMON_GLINK_COMM) += sysmon-glink.o sysmon-qmi.o
-obj-$(CONFIG_ARCH_QCOM) += kryo-l2-accessors.o
+obj-$(CONFIG_ARCH_MSM8996) += kryo-l2-accessors.o
obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o smp2p_sleepstate.o
obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_spinlock_test.o
obj-$(CONFIG_MSM_QMI_INTERFACE) += qmi_interface.o
diff --git a/drivers/soc/qcom/glink_private.h b/drivers/soc/qcom/glink_private.h
index 2f064e546f48..cdd6988418f7 100644
--- a/drivers/soc/qcom/glink_private.h
+++ b/drivers/soc/qcom/glink_private.h
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/ratelimit.h>
+#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/types.h>
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index d7d08dc588e5..84f346385f18 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -2191,6 +2191,8 @@ static int subsys_name_to_id(const char *name)
return SMEM_WCNSS;
if (!strcmp(name, "spss"))
return SMEM_SPSS;
+ if (!strcmp(name, "cdsp"))
+ return SMEM_CDSP;
return -ENODEV;
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 7087b5744eef..35994b827549 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1787,6 +1787,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (is_on) {
+ dbg_event(0xFF, "Pullup_enable", is_on);
if (dwc->revision <= DWC3_REVISION_187A) {
reg &= ~DWC3_DCTL_TRGTULST_MASK;
reg |= DWC3_DCTL_TRGTULST_RX_DET;
@@ -1824,6 +1825,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
dwc->pullups_connected = true;
} else {
+ dbg_event(0xFF, "Pullup_disable", is_on);
dwc3_gadget_disable_irq(dwc);
__dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]);
@@ -1849,8 +1851,15 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
break;
}
timeout--;
- if (!timeout)
+ if (!timeout) {
+ dev_err(dwc->dev, "failed to %s controller\n",
+ is_on ? "start" : "stop");
+ if (is_on)
+ dbg_event(0xFF, "STARTTOUT", reg);
+ else
+ dbg_event(0xFF, "STOPTOUT", reg);
return -ETIMEDOUT;
+ }
udelay(1);
} while (1);
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index c2d65206ec6c..6c47c26b5df7 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -299,6 +299,7 @@ static void xhci_pci_remove(struct pci_dev *dev)
struct xhci_hcd *xhci;
xhci = hcd_to_xhci(pci_get_drvdata(dev));
+ xhci->xhc_state |= XHCI_STATE_REMOVING;
if (xhci->shared_hcd) {
usb_remove_hcd(xhci->shared_hcd);
usb_put_hcd(xhci->shared_hcd);
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 8125a8f96311..3e49861a09a2 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -284,6 +284,7 @@ static int xhci_plat_remove(struct platform_device *dev)
pm_runtime_disable(&dev->dev);
device_remove_file(&dev->dev, &dev_attr_config_imod);
+ xhci->xhc_state |= XHCI_STATE_REMOVING;
usb_remove_hcd(xhci->shared_hcd);
usb_phy_shutdown(hcd->usb_phy);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index db0f0831b94f..2b63969c2bbf 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -4008,7 +4008,8 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
int reserved_trbs = xhci->cmd_ring_reserved_trbs;
int ret;
- if (xhci->xhc_state) {
+ if ((xhci->xhc_state & XHCI_STATE_DYING) ||
+ (xhci->xhc_state & XHCI_STATE_HALTED)) {
xhci_dbg(xhci, "xHCI dying or halted, can't queue_command\n");
return -ESHUTDOWN;
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 42f74d55e3bd..dd7669331d00 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -155,7 +155,8 @@ static int xhci_start(struct xhci_hcd *xhci)
"waited %u microseconds.\n",
XHCI_MAX_HALT_USEC);
if (!ret)
- xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING);
+ /* clear state flags. Including dying, halted or removing */
+ xhci->xhc_state = 0;
return ret;
}
@@ -2762,7 +2763,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
if (ret <= 0)
return ret;
xhci = hcd_to_xhci(hcd);
- if (xhci->xhc_state & XHCI_STATE_DYING)
+ if ((xhci->xhc_state & XHCI_STATE_DYING) ||
+ (xhci->xhc_state & XHCI_STATE_REMOVING))
return -ENODEV;
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
@@ -3809,7 +3811,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
mutex_lock(&xhci->mutex);
- if (xhci->xhc_state) /* dying or halted */
+ if (xhci->xhc_state) /* dying, removing or halted */
goto out;
if (!udev->slot_id) {
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index a6e94e029a10..dc03aac4f88a 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1604,6 +1604,7 @@ struct xhci_hcd {
*/
#define XHCI_STATE_DYING (1 << 0)
#define XHCI_STATE_HALTED (1 << 1)
+#define XHCI_STATE_REMOVING (1 << 2)
/* Statistics */
int error_bitmask;
unsigned int quirks;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 164bf0273597..5a355f226179 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -1638,9 +1638,16 @@ static int mdss_mdp_gdsc_notifier_call(struct notifier_block *self,
if (event & REGULATOR_EVENT_ENABLE) {
__mdss_restore_sec_cfg(mdata);
} else if (event & REGULATOR_EVENT_PRE_DISABLE) {
- pr_debug("mdss gdsc is getting disabled\n");
- /* halt the vbif transactions */
- mdss_mdp_vbif_axi_halt(mdata);
+ int active_cnt = atomic_read(&mdata->active_intf_cnt);
+
+ pr_debug("mdss gdsc is getting disabled, active_cnt=%d\n",
+ active_cnt);
+ /*
+ * halt the vbif transactions only if we have any active
+ * overlay session
+ */
+ if (active_cnt)
+ mdss_mdp_vbif_axi_halt(mdata);
}
return NOTIFY_OK;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index f97a9f9a9adc..cd8df78bc8c0 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -561,7 +561,8 @@ static u32 __calc_qseed3_mdp_clk_rate(struct mdss_mdp_pipe *pipe,
u64 active_line;
u64 backfill_line;
- ver_dwnscale = ((u64)src_h << PHASE_STEP_SHIFT) / dst.h;
+ ver_dwnscale = (u64)src_h << PHASE_STEP_SHIFT;
+ do_div(ver_dwnscale, dst.h);
if (ver_dwnscale > (MDSS_MDP_QSEED3_VER_DOWNSCALE_LIM
<< PHASE_STEP_SHIFT)) {
diff --git a/include/linux/of_batterydata.h b/include/linux/of_batterydata.h
index fe2c996de264..5505371488d0 100644
--- a/include/linux/of_batterydata.h
+++ b/include/linux/of_batterydata.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016 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
@@ -39,10 +39,7 @@ int of_batterydata_read_data(struct device_node *container_node,
* of_batterydata_get_best_profile() - Find matching battery data device node
* @batterydata_container_node: pointer to the battery-data container device
* node containing the profile nodes.
- * @psy_name: Name of the power supply which holds the
- * POWER_SUPPLY_RESISTANCE_ID value to be used to match
- * against the id resistances specified in the corresponding
- * battery data profiles.
+ * @batt_id_kohm: Battery ID in KOhms for which we want to find the profile.
* @batt_type: Battery type which we want to force load the profile.
*
* This routine returns a device_node pointer to the closest match battery data
@@ -50,7 +47,7 @@ int of_batterydata_read_data(struct device_node *container_node,
*/
struct device_node *of_batterydata_get_best_profile(
struct device_node *batterydata_container_node,
- const char *psy_name, const char *batt_type);
+ int batt_id_kohm, const char *batt_type);
#else
static inline int of_batterydata_read_data(struct device_node *container_node,
struct bms_battery_data *batt_data,
@@ -60,7 +57,7 @@ static inline int of_batterydata_read_data(struct device_node *container_node,
}
static inline struct device_node *of_batterydata_get_best_profile(
struct device_node *batterydata_container_node,
- struct device_node *best_node, const char *psy_name)
+ int batt_id_kohm, const char *batt_type)
{
return -ENXIO;
}
diff --git a/include/soc/qcom/smem.h b/include/soc/qcom/smem.h
index 9295532dec8a..79bcc1b31cf8 100644
--- a/include/soc/qcom/smem.h
+++ b/include/soc/qcom/smem.h
@@ -26,6 +26,7 @@ enum {
SMEM_TZ,
SMEM_SPSS,
SMEM_HYP,
+ SMEM_CDSP,
NUM_SMEM_SUBSYSTEMS,
};
diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h
index 34503420c882..dbba773cd49d 100644
--- a/include/uapi/linux/msm_kgsl.h
+++ b/include/uapi/linux/msm_kgsl.h
@@ -43,13 +43,13 @@
/* This is a cmdbatch exclusive flag - use the CMDBATCH equivalent instead */
#define KGSL_CONTEXT_SYNC 0x00000400
#define KGSL_CONTEXT_PWR_CONSTRAINT 0x00000800
-
#define KGSL_CONTEXT_PRIORITY_MASK 0x0000F000
#define KGSL_CONTEXT_PRIORITY_SHIFT 12
#define KGSL_CONTEXT_PRIORITY_UNDEF 0
#define KGSL_CONTEXT_IFH_NOP 0x00010000
#define KGSL_CONTEXT_SECURE 0x00020000
+#define KGSL_CONTEXT_NO_SNAPSHOT 0x00040000
#define KGSL_CONTEXT_PREEMPT_STYLE_MASK 0x0E000000
#define KGSL_CONTEXT_PREEMPT_STYLE_SHIFT 25
diff --git a/kernel/Documentation/firmware_updater/request_firmware.txt b/kernel/Documentation/firmware_updater/request_firmware.txt
new file mode 100644
index 000000000000..317f04ac5684
--- /dev/null
+++ b/kernel/Documentation/firmware_updater/request_firmware.txt
@@ -0,0 +1,22 @@
+Firmware Update Function
+========================
+
+Call export function "synaptics_fw_updater" in rmi_fw_update.c to start
+firmware updating process in the driver.
+
+The RMI4 driver uses the kernel's request_firmware() feature to obtain
+firmware for the touch sensor. The firmware is expected to live in
+the file firmware/<firmware_name>.img.ihex.
+
+To prepare Synaptics provided .img file for reflashing, convert it to .ihex
+format using the following command:
+
+ objcopy -I binary -O ihex <firmware_name>.img firmware/<firmware_name>.img.ihex
+
+Then make sure to add the image file name to the
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_FW_UPDATE entry in firmware/Makefile.
+If you don't do this, the image file won't be included, and
+the firmware loader class will delay for 60 seconds waiting for a non-existent
+userspace response to the firmware load request.
+
+Firmware updates for multichip solutions (aka LTS) are not supported.
diff --git a/kernel/Documentation/firmware_updater/synaptics_fw_updater b/kernel/Documentation/firmware_updater/synaptics_fw_updater
new file mode 100644
index 000000000000..b0c1b4d9e770
--- /dev/null
+++ b/kernel/Documentation/firmware_updater/synaptics_fw_updater
Binary files differ
diff --git a/kernel/Documentation/firmware_updater/synaptics_fw_updater.c b/kernel/Documentation/firmware_updater/synaptics_fw_updater.c
new file mode 100644
index 000000000000..7409dd424109
--- /dev/null
+++ b/kernel/Documentation/firmware_updater/synaptics_fw_updater.c
@@ -0,0 +1,753 @@
+/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ *
+ * Copyright © 2011, 2012 Synaptics Incorporated. All rights reserved.
+ *
+ * The information in this file is confidential under the terms
+ * of a non-disclosure agreement with Synaptics and is provided
+ * AS IS without warranties or guarantees of any kind.
+ *
+ * The information in this file shall remain the exclusive property
+ * of Synaptics and may be the subject of Synaptics patents, in
+ * whole or part. Synaptics intellectual property rights in the
+ * information in this file are not expressly or implicitly licensed
+ * or otherwise transferred to you as a result of such information
+ * being made available to you.
+ *
+ * File: synaptics_fw_updater.c
+ *
+ * Description: command line reflash implimentation using command
+ * line args. This file should not be OS dependant and should build and
+ * run under any Linux based OS that utilizes the Synaptice rmi driver
+ * built into the kernel (kernel/drivers/input/rmi4).
+ *
+ * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ */
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#define DEFAULT_SENSOR "/sys/class/input/input1"
+
+#define MAX_STRING_LEN 256
+#define MAX_INT_LEN 33
+
+#define DATA_FILENAME "data"
+#define IMAGESIZE_FILENAME "imagesize"
+#define DOREFLASH_FILENAME "doreflash"
+#define CONFIGAREA_FILENAME "configarea"
+#define READCONFIG_FILENAME "readconfig"
+#define WRITECONFIG_FILENAME "writeconfig"
+#define BLOCKSIZE_FILENAME "blocksize"
+#define IMAGEBLOCKCOUNT_FILENAME "fwblockcount"
+#define CONFIGBLOCKCOUNT_FILENAME "configblockcount"
+#define PMCONFIGBLOCKCOUNT_FILENAME "permconfigblockcount"
+#define BUILDID_FILENAME "buildid"
+#define FLASHPROG_FILENAME "flashprog"
+
+#define UI_CONFIG_AREA 0
+#define PERM_CONFIG_AREA 1
+#define BL_CONFIG_AREA 2
+#define DISP_CONFIG_AREA 3
+
+#define IMAGE_FILE_CHECKSUM_SIZE 4
+
+unsigned char *firmware = NULL;
+int fileSize;
+int firmwareBlockSize;
+int firmwareBlockCount;
+int firmwareImgSize;
+int configBlockSize;
+int configBlockCount;
+int configImgSize;
+int totalBlockCount;
+int readConfig = 0;
+int writeConfig = 0;
+int uiConfig = 0;
+int pmConfig = 0;
+int blConfig = 0;
+int dpConfig = 0;
+int force = 0;
+int verbose = 0;
+
+char mySensor[MAX_STRING_LEN];
+char imageFileName[MAX_STRING_LEN];
+
+static void usage(char *name)
+{
+ printf("Usage: %s [-b {image_file}] [-d {sysfs_entry}] [-r] [-ui] [-pm] [-bl] [-dp] [-f] [-v]\n", name);
+ printf("\t[-b {image_file}] - Name of image file\n");
+ printf("\t[-d {sysfs_entry}] - Path to sysfs entry of sensor\n");
+ printf("\t[-r] - Read config area\n");
+ printf("\t[-ui] - UI config area\n");
+ printf("\t[-pm] - Permanent config area\n");
+ printf("\t[-bl] - BL config area\n");
+ printf("\t[-dp] - Display config area\n");
+ printf("\t[-f] - Force reflash\n");
+ printf("\t[-v] - Verbose output\n");
+
+ return;
+}
+
+static void TimeSubtract(struct timeval *result, struct timeval *x, struct timeval *y)
+{
+ if (x->tv_usec < y->tv_usec) {
+ result->tv_sec = x->tv_sec - y->tv_sec - 1;
+ result->tv_usec = y->tv_usec - x->tv_usec;
+ } else {
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_usec = x->tv_usec - y->tv_usec;
+ }
+
+ return;
+}
+
+static int CheckSysfsEntry(char *sensorName)
+{
+ int retval;
+ struct stat st;
+
+ retval = stat(sensorName, &st);
+ if (retval)
+ printf("ERROR: sensor sysfs entry %s not found\n", sensorName);
+
+ return retval;
+}
+
+static void WriteBinData(char *fname, unsigned char *buf, int len)
+{
+ int numBytesWritten;
+ FILE *fp;
+
+ fp = fopen(fname, "wb");
+ if (!fp) {
+ printf("ERROR: failed to open %s for writing data\n", fname);
+ exit(EIO);
+ }
+
+ numBytesWritten = fwrite(buf, 1, len, fp);
+
+ if (numBytesWritten != len) {
+ printf("ERROR: failed to write all data to bin file\n");
+ fclose(fp);
+ exit(EIO);
+ }
+
+ fclose(fp);
+
+ return;
+}
+
+static void ReadBinData(char *fname, unsigned char *buf, int len)
+{
+ int numBytesRead;
+ FILE *fp;
+
+ fp = fopen(fname, "rb");
+ if (!fp) {
+ printf("ERROR: failed to open %s for reading data\n", fname);
+ exit(EIO);
+ }
+
+ numBytesRead = fread(buf, 1, len, fp);
+
+ if (numBytesRead != len) {
+ printf("ERROR: failed to read all data from bin file\n");
+ fclose(fp);
+ exit(EIO);
+ }
+
+ fclose(fp);
+
+ return;
+}
+
+static void WriteValueToFp(FILE *fp, unsigned int value)
+{
+ int numBytesWritten;
+ char buf[MAX_INT_LEN];
+
+ snprintf(buf, MAX_INT_LEN, "%u", value);
+
+ fseek(fp, 0, 0);
+
+ numBytesWritten = fwrite(buf, 1, strlen(buf) + 1, fp);
+ if (numBytesWritten != ((int)(strlen(buf) + 1))) {
+ printf("ERROR: failed to write value to file pointer\n");
+ fclose(fp);
+ exit(EIO);
+ }
+
+ return;
+}
+
+static void WriteValueToSysfsFile(char *fname, unsigned int value)
+{
+ FILE *fp;
+
+ fp = fopen(fname, "w");
+ if (!fp) {
+ printf("ERROR: failed to open %s for writing value\n", fname);
+ exit(EIO);
+ }
+
+ WriteValueToFp(fp, value);
+
+ fclose(fp);
+
+ return;
+}
+
+static void ReadValueFromFp(FILE *fp, unsigned int *value)
+{
+ int retVal;
+ char buf[MAX_INT_LEN];
+
+ fseek(fp, 0, 0);
+
+ retVal = fread(buf, 1, sizeof(buf), fp);
+ if (retVal == -1) {
+ printf("ERROR: failed to read value from file pointer\n");
+ exit(EIO);
+ }
+
+ *value = strtoul(buf, NULL, 0);
+
+ return;
+}
+
+static void ReadValueFromSysfsFile(char *fname, unsigned int *value)
+{
+ FILE *fp;
+
+ fp = fopen(fname, "r");
+ if (!fp) {
+ printf("ERROR: failed to open %s for reading value\n", fname);
+ exit(EIO);
+ }
+
+ ReadValueFromFp(fp, value);
+
+ fclose(fp);
+
+ return;
+}
+
+static void WriteBlockData(char *buf, int len)
+{
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, DATA_FILENAME);
+
+ WriteBinData(tmpfname, (unsigned char *)buf, len);
+
+ return;
+}
+
+static void ReadBlockData(char *buf, int len)
+{
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, DATA_FILENAME);
+
+ ReadBinData(tmpfname, (unsigned char *)buf, len);
+
+ return;
+}
+
+static void SetImageSize(int value)
+{
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, IMAGESIZE_FILENAME);
+
+ WriteValueToSysfsFile(tmpfname, value);
+
+ return;
+}
+
+static void StartReflash(int value)
+{
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, DOREFLASH_FILENAME);
+
+ WriteValueToSysfsFile(tmpfname, value);
+
+ return;
+}
+
+static void SetConfigArea(int value)
+{
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, CONFIGAREA_FILENAME);
+
+ WriteValueToSysfsFile(tmpfname, value);
+
+ return;
+}
+
+static void StartWriteConfig(int value)
+{
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, WRITECONFIG_FILENAME);
+
+ WriteValueToSysfsFile(tmpfname, value);
+
+ return;
+}
+
+static void StartReadConfig(int value)
+{
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, READCONFIG_FILENAME);
+
+ WriteValueToSysfsFile(tmpfname, value);
+
+ return;
+}
+
+static int ReadBlockSize(void)
+{
+ unsigned int blockSize;
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, BLOCKSIZE_FILENAME);
+
+ ReadValueFromSysfsFile(tmpfname, &blockSize);
+
+ return blockSize;
+}
+
+static int ReadFirmwareBlockCount(void)
+{
+ unsigned int imageBlockCount;
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, IMAGEBLOCKCOUNT_FILENAME);
+
+ ReadValueFromSysfsFile(tmpfname, &imageBlockCount);
+
+ return imageBlockCount;
+}
+
+static int ReadConfigBlockCount(void)
+{
+ unsigned int configBlockCount;
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, CONFIGBLOCKCOUNT_FILENAME);
+
+ ReadValueFromSysfsFile(tmpfname, &configBlockCount);
+
+ return configBlockCount;
+}
+
+static int ReadPmConfigBlockCount(void)
+{
+ unsigned int configBlockCount;
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, PMCONFIGBLOCKCOUNT_FILENAME);
+
+ ReadValueFromSysfsFile(tmpfname, &configBlockCount);
+
+ return configBlockCount;
+}
+
+static int ReadBuildID(void)
+{
+ unsigned int buildID;
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, BUILDID_FILENAME);
+
+ ReadValueFromSysfsFile(tmpfname, &buildID);
+
+ return buildID;
+}
+
+static int ReadFlashProg(void)
+{
+ unsigned int flashProg;
+ char tmpfname[MAX_STRING_LEN];
+
+ snprintf(tmpfname, MAX_STRING_LEN, "%s/%s", mySensor, FLASHPROG_FILENAME);
+
+ ReadValueFromSysfsFile(tmpfname, &flashProg);
+
+ return flashProg;
+}
+
+static void ReadFirmwareInfo(void)
+{
+ firmwareBlockSize = ReadBlockSize();
+ firmwareBlockCount = ReadFirmwareBlockCount();
+ firmwareImgSize = firmwareBlockCount * firmwareBlockSize;
+
+ return;
+}
+
+static void ReadConfigInfo(void)
+{
+ configBlockSize = ReadBlockSize();
+ configBlockCount = ReadConfigBlockCount();
+ configImgSize = configBlockSize * configBlockCount;
+
+ return;
+}
+
+static void CalculateChecksum(unsigned short *data, unsigned short len, unsigned long *result)
+{
+ unsigned long temp;
+ unsigned long sum1 = 0xffff;
+ unsigned long sum2 = 0xffff;
+
+ *result = 0xffffffff;
+
+ while (len--) {
+ temp = *data;
+ sum1 += temp;
+ sum2 += sum1;
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+ data++;
+ }
+
+ *result = sum2 << 16 | sum1;
+
+ return;
+}
+
+static int CompareChecksum(void)
+{
+ unsigned long headerChecksum;
+ unsigned long computedChecksum;
+
+ headerChecksum = (unsigned long)firmware[0] +
+ (unsigned long)firmware[1] * 0x100 +
+ (unsigned long)firmware[2] * 0x10000 +
+ (unsigned long)firmware[3] * 0x1000000;
+
+ CalculateChecksum((unsigned short *)&firmware[IMAGE_FILE_CHECKSUM_SIZE],
+ ((fileSize - IMAGE_FILE_CHECKSUM_SIZE) / 2), &computedChecksum);
+
+ if (verbose) {
+ printf("Checksum in image file header = 0x%08x\n", (unsigned int)headerChecksum);
+ printf("Checksum computed from image file = 0x%08x\n", (unsigned int)computedChecksum);
+ }
+
+ if (headerChecksum == computedChecksum)
+ return 1;
+ else
+ return 0;
+}
+
+static int ProceedWithReflash(void)
+{
+ int index = 0;
+ int deviceBuildID;
+ int imageBuildID;
+ char imagePR[MAX_STRING_LEN];
+ char *strptr;
+
+ if (force) {
+ printf("Force reflash...\n");
+ return 1;
+ }
+
+ if (ReadFlashProg()) {
+ printf("Force reflash (device in flash prog mode)...\n");
+ return 1;
+ }
+
+ strptr = strstr(imageFileName, "PR");
+ if (!strptr) {
+ printf("No valid PR number (PRxxxxxxx) found in image file name...\n");
+ return 0;
+ }
+
+ strptr += 2;
+ while (strptr[index] >= '0' && strptr[index] <= '9') {
+ imagePR[index] = strptr[index];
+ index++;
+ }
+ imagePR[index] = 0;
+
+ imageBuildID = strtoul(imagePR, NULL, 0);
+ deviceBuildID = ReadBuildID();
+ printf("Image file PR = %d\n", imageBuildID);
+ printf("Device PR = %d\n", deviceBuildID);
+
+ if (imageBuildID > deviceBuildID) {
+ printf("Proceed with reflash...\n");
+ return 1;
+ } else {
+ printf("No need to do reflash...\n");
+ return 0;
+ }
+}
+
+static void DoReadConfig(void)
+{
+ int ii;
+ int jj;
+ int index = 0;
+ int configSize;
+ int blockCount;
+ unsigned char *buffer;
+
+ if (uiConfig) {
+ SetConfigArea(UI_CONFIG_AREA);
+ StartReadConfig(1);
+ blockCount = configBlockCount;
+ configSize = configImgSize;
+ buffer = malloc(configSize);
+ if (!buffer)
+ exit(ENOMEM);
+ ReadBlockData((char *)&buffer[0], configSize);
+ } else if (pmConfig) {
+ SetConfigArea(PERM_CONFIG_AREA);
+ StartReadConfig(1);
+ blockCount = ReadPmConfigBlockCount();
+ configSize = configBlockSize * blockCount;
+ buffer = malloc(configSize);
+ if (!buffer)
+ exit(ENOMEM);
+ ReadBlockData((char *)&buffer[0], configSize);
+ } else {
+ return;
+ }
+
+ for (ii = 0; ii < blockCount; ii++) {
+ for (jj = 0; jj < configBlockSize; jj++) {
+ printf("0x%02x ", buffer[index]);
+ index++;
+ }
+ printf("\n");
+ }
+
+ free(buffer);
+
+ return;
+}
+
+static void DoWriteConfig(void)
+{
+ printf("Starting config programming...\n");
+
+ if (uiConfig)
+ SetConfigArea(UI_CONFIG_AREA);
+ else if (pmConfig)
+ SetConfigArea(PERM_CONFIG_AREA);
+ else if (blConfig)
+ SetConfigArea(BL_CONFIG_AREA);
+ else if (dpConfig)
+ SetConfigArea(DISP_CONFIG_AREA);
+ else
+ return;
+
+ SetImageSize(fileSize);
+ WriteBlockData((char *)&firmware[0], fileSize);
+ StartWriteConfig(1);
+
+ printf("Config programming completed...\n");
+
+ return;
+}
+
+static void DoReflash(void)
+{
+ if (verbose)
+ printf("Blocks: %d (firmware: %d, config: %d)\n", totalBlockCount, firmwareBlockCount, configBlockCount);
+
+ if (!ProceedWithReflash())
+ return;
+
+ printf("Starting reflash...\n");
+
+ SetImageSize(fileSize);
+ WriteBlockData((char *)&firmware[0], fileSize);
+ StartReflash(1);
+
+ printf("Reflash completed...\n");
+
+ return;
+}
+
+static int InitFirmwareImage(void)
+{
+ int numBytesRead;
+ FILE *fp;
+
+ if (!readConfig) {
+ fp = fopen(imageFileName, "rb");
+
+ if (!fp) {
+ printf("ERROR: image file %s not found\n", imageFileName);
+ exit(ENODEV);
+ }
+
+ fseek(fp, 0L, SEEK_END);
+ fileSize = ftell(fp);
+ if (fileSize == -1) {
+ printf("ERROR: failed to determine size of %s\n", imageFileName);
+ exit(EIO);
+ }
+
+ fseek(fp, 0L, SEEK_SET);
+
+ firmware = malloc(fileSize + 1);
+ if (!firmware) {
+ exit(ENOMEM);
+ } else {
+ numBytesRead = fread(firmware, 1, fileSize, fp);
+ if (numBytesRead != fileSize) {
+ printf("ERROR: failed to read entire content of image file\n");
+ exit(EIO);
+ }
+ }
+
+ fclose(fp);
+
+ if (!(pmConfig || blConfig || dpConfig)) {
+ if (!CompareChecksum()) {
+ printf("ERROR: failed to validate checksum of image file\n");
+ exit(EINVAL);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char* argv[])
+{
+ int retVal;
+ int this_arg = 1;
+ struct stat st;
+ struct timeval start_time;
+ struct timeval end_time;
+ struct timeval elapsed_time;
+
+ if (argc == 1) {
+ usage(argv[0]);
+ exit(EINVAL);
+ }
+
+ while (this_arg < argc) {
+ if (!strcmp((const char *)argv[this_arg], "-b")) {
+ /* Image file */
+ FILE *file;
+
+ this_arg++;
+ if (this_arg >= argc) {
+ printf("ERROR: image file missing\n");
+ exit(EINVAL);
+ }
+
+ /* check for presence of image file */
+ file = fopen(argv[this_arg], "rb");
+ if (file == 0) {
+ printf("ERROR: image file %s not found\n", argv[this_arg]);
+ exit(EINVAL);
+ }
+ fclose(file);
+
+ strncpy(imageFileName, argv[this_arg], MAX_STRING_LEN);
+ } else if (!strcmp((const char *)argv[this_arg], "-d")) {
+ /* path to sensor sysfs entry */
+ this_arg++;
+
+ if (stat(argv[this_arg], &st) == 0) {
+ strncpy(mySensor, argv[this_arg], MAX_STRING_LEN);
+ } else {
+ printf("ERROR: sensor sysfs entry %s not found\n", argv[this_arg]);
+ exit(EINVAL);
+ }
+ } else if (!strcmp((const char *)argv[this_arg], "-r")) {
+ readConfig = 1;
+ } else if (!strcmp((const char *)argv[this_arg], "-ui")) {
+ uiConfig = 1;
+ } else if (!strcmp((const char *)argv[this_arg], "-pm")) {
+ pmConfig = 1;
+ } else if (!strcmp((const char *)argv[this_arg], "-bl")) {
+ blConfig = 1;
+ } else if (!strcmp((const char *)argv[this_arg], "-dp")) {
+ dpConfig = 1;
+ } else if (!strcmp((const char *)argv[this_arg], "-f")) {
+ force = 1;
+ } else if (!strcmp((const char *)argv[this_arg], "-v")) {
+ verbose = 1;
+ } else {
+ usage(argv[0]);
+ printf("ERROR: invalid parameter %s supplied\n", argv[this_arg]);
+ exit(EINVAL);
+ }
+ this_arg++;
+ }
+
+ if ((uiConfig + pmConfig + blConfig + dpConfig) > 1) {
+ printf("ERROR: too many parameters\n");
+ exit(EINVAL);
+ }
+
+ if (uiConfig || pmConfig || blConfig || dpConfig)
+ writeConfig = 1;
+
+ if (!readConfig && !strlen(imageFileName)) {
+ printf("ERROR: no image file specified\n");
+ exit(EINVAL);
+ }
+
+ if (!strlen(mySensor))
+ strncpy(mySensor, DEFAULT_SENSOR, MAX_STRING_LEN);
+
+ if (CheckSysfsEntry(mySensor))
+ exit(ENODEV);
+
+ InitFirmwareImage();
+
+ ReadFirmwareInfo();
+ ReadConfigInfo();
+ totalBlockCount = configBlockCount + firmwareBlockCount;
+
+ retVal = gettimeofday(&start_time, NULL);
+ if (retVal)
+ printf("WARNING: failed to get start time\n");
+
+ if (verbose) {
+ if (!readConfig)
+ printf("Image file: %s\n", imageFileName);
+ printf("Sensor sysfs entry: %s\n", mySensor);
+ }
+
+ if (readConfig)
+ DoReadConfig();
+ else if (writeConfig)
+ DoWriteConfig();
+ else
+ DoReflash();
+
+ retVal = gettimeofday(&end_time, NULL);
+ if (retVal)
+ printf("WARNING: failed to get end time\n");
+
+ TimeSubtract(&elapsed_time, &end_time, &start_time);
+
+ if (verbose) {
+ printf("Elapsed time = %ld.%06ld seconds\n",
+ (long)elapsed_time.tv_sec,
+ (long)elapsed_time.tv_usec);
+ }
+
+ return 0;
+}
diff --git a/kernel/Documentation/firmware_updater/synaptics_fw_updater_readme.txt b/kernel/Documentation/firmware_updater/synaptics_fw_updater_readme.txt
new file mode 100644
index 000000000000..66f71922995a
--- /dev/null
+++ b/kernel/Documentation/firmware_updater/synaptics_fw_updater_readme.txt
@@ -0,0 +1,41 @@
+Use ADB (Android Debug Bridge) to do command-line reflash
+- Power on device.
+- Connect device to host via USB.
+- Open command prompt on host and go to directory where adb, synaptics_fw_updater, and FW image (e.g. PR1234567.img) reside.
+- Run "adb devices" to ensure connection with device.
+- Run "adb root" to have root privileges.
+- Run "adb push synaptics_fw_updater /data" to copy synaptics_fw_updater to /data directory on device.
+- Run "adb push firmware.img /data" to copy firmware.img to /data directory on device.
+- Run "adb shell chmod 777 /data/synaptics_fw_updater" to make synaptics_fw_updater executable.
+- Run "adb shell /data/synaptics_fw_updater -b /data/PR1234567.img -f -v" to start reflash process.
+
+Parameters
+[-b {image_file}] - Name of image file
+[-d {sysfs_entry}] - Path to sysfs entry of sensor
+[-r] - Read config area
+[-ui] - UI config area
+[-pm] - Permanent config area
+[-bl] - BL config area
+[-dp] - Display config area
+[-f] - Force reflash
+[-v] - Verbose output
+
+Procedures for checking whether to proceed with reflash
+- If [-f] flag is set, proceed with reflash
+- If device is in flash prog (bootloader) mode, proceed with reflash
+- If PR number contained in name of new FW image is greater than PR number of FW on device, proceed with reflash.
+- Otherwise, no reflash is performed
+
+Usage examples
+- Perform reflash using PR1234567.img regardless of PR number of FW on device
+ synaptics_fw_updater -b PR1234567.img -f
+- Perform reflash using PR1234567.img only if 1234567 is greater than PR number of FW on device.
+ synaptics_fw_updater -b PR1234567.img
+- Write UI config area from PR1234567.img (parsing UI config area from firmware image file)
+ synaptics_fw_updater -b PR1234567.img -ui
+- Write permanent config area from pmconfig.img (binary file containing permanent config data)
+ synaptics_fw_updater -b pmconfig.img -pm
+- Read UI config area
+ synaptics_fw_updater -r -ui
+- Read permanent config area
+ synaptics_fw_updater -r -pm \ No newline at end of file
diff --git a/kernel/arch/arm/configs/omap3_beagle_android_defconfig b/kernel/arch/arm/configs/omap3_beagle_android_defconfig
new file mode 100644
index 000000000000..4fc62c4fa440
--- /dev/null
+++ b/kernel/arch/arm/configs/omap3_beagle_android_defconfig
@@ -0,0 +1,2419 @@
+#
+# Automatically generated make config: don't edit
+# Linux/arm 2.6.37 Kernel Configuration
+# Mon Apr 16 13:58:06 2012
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_ARCH_HAS_CPUFREQ=y
+CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_IRQ_WORK=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_HAVE_GENERIC_HARDIRQS is not set
+# CONFIG_SPARSE_IRQ is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TINY_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_CGROUPS is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_PANIC_TIMEOUT=0
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_ASHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_LPC32XX is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_NUC93X is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P64X0 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_S5PV310 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_TCC_926 is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_PLAT_SPEAR is not set
+
+#
+# TI OMAP Common Features
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2PLUS=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_SMARTREFLEX=y
+CONFIG_OMAP_SMARTREFLEX_CLASS3=y
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_IOMMU=y
+# CONFIG_OMAP_IOMMU_DEBUG is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+# CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE is not set
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_PM_NONE is not set
+CONFIG_OMAP_PM_NOOP=y
+
+#
+# TI OMAP2/3/4 Specific Features
+#
+CONFIG_ARCH_OMAP2PLUS_TYPICAL=y
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+# CONFIG_ARCH_OMAP4 is not set
+# CONFIG_ARCH_TI81XX is not set
+CONFIG_ARCH_OMAP3430=y
+CONFIG_OMAP_PACKAGE_CBB=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP3_BEAGLE=y
+# CONFIG_MACH_DEVKIT8000 is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP3530_LV_SOM is not set
+# CONFIG_MACH_OMAP3_TORPEDO is not set
+# CONFIG_MACH_OVERO is not set
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_FLASHBOARD is not set
+# CONFIG_MACH_OMAP3517EVM is not set
+# CONFIG_MACH_CRANEBOARD is not set
+# CONFIG_MACH_OMAP3_PANDORA is not set
+# CONFIG_MACH_OMAP3_TOUCHBOOK is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_NOKIA_RM680 is not set
+# CONFIG_MACH_NOKIA_RX51 is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_MACH_OMAP_ZOOM3 is not set
+# CONFIG_MACH_CM_T35 is not set
+# CONFIG_MACH_CM_T3517 is not set
+# CONFIG_MACH_IGEP0020 is not set
+# CONFIG_MACH_IGEP0030 is not set
+# CONFIG_MACH_SBC3530 is not set
+# CONFIG_MACH_OMAP_3630SDP is not set
+# CONFIG_OMAP3_EMU is not set
+CONFIG_OMAP3_PM_DISABLE_VT_SWITCH=y
+# CONFIG_OMAP3_SDRC_AC_TIMING is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+# CONFIG_ARM_ERRATA_430973 is not set
+# CONFIG_ARM_ERRATA_458693 is not set
+# CONFIG_ARM_ERRATA_460075 is not set
+# CONFIG_ARM_ERRATA_743622 is not set
+CONFIG_COMMON_CLKDEV=y
+# CONFIG_FIQ_DEBUGGER is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_CC_STACKPROTECTOR is not set
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+# CONFIG_AUTO_ZRELADDR is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_INTERACTIVE is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+# CONFIG_PM_ADVANCED_DEBUG is not set
+# CONFIG_PM_VERBOSE is not set
+CONFIG_CAN_PM_TRACE=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+# CONFIG_PM_TEST_SUSPEND is not set
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_HAS_WAKELOCK=y
+CONFIG_HAS_EARLYSUSPEND=y
+CONFIG_WAKELOCK=y
+CONFIG_WAKELOCK_STAT=y
+CONFIG_USER_WAKELOCK=y
+CONFIG_EARLYSUSPEND=y
+# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set
+# CONFIG_CONSOLE_EARLYSUSPEND is not set
+CONFIG_FB_EARLYSUSPEND=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_OPS=y
+CONFIG_ARCH_HAS_OPP=y
+CONFIG_PM_OPP=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETLABEL is not set
+CONFIG_ANDROID_PARANOID_NETWORK=y
+CONFIG_NET_ACTIVITY_STATS=y
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+CONFIG_DNS_RESOLVER=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_NET_DROP_MONITOR is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+
+#
+# Some wireless drivers require a rate control algorithm
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
+CONFIG_MTD_OOPS=y
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_OMAP2=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=y
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_MII=y
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BCM63XX_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+# CONFIG_SMSC911X_ARCH_HOOKS is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_NETDEV_1000=y
+CONFIG_TI_DAVINCI_EMAC=y
+CONFIG_TI_DAVINCI_MDIO=y
+CONFIG_TI_DAVINCI_CPDMA=y
+# CONFIG_STMMAC_ETH is not set
+CONFIG_NETDEV_10000=y
+CONFIG_WLAN=y
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_BCM4329 is not set
+# CONFIG_HOSTAP is not set
+CONFIG_WL12XX_PLATFORM_DATA=y
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+CONFIG_USB_NET_SMSC95XX=y
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_KEYRESET is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_KEYBOARD_GPIO_POLLED is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_MCS is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_TWL4030=y
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_BU21013 is not set
+# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_QT602240 is not set
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_TSC2004 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_AD714X is not set
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYCHORD is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+CONFIG_INPUT_TWL4030_PWRBUTTON=y
+# CONFIG_INPUT_TWL4030_VIBRA is not set
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_GPIO is not set
+# CONFIG_INPUT_PCF8574 is not set
+# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
+# CONFIG_INPUT_ADXL34X is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_SERIO_PS2MULT is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVMEM=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_TI81XX_HDMI is not set
+# CONFIG_DCC_TTY is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_OMAP24XX=y
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_BASIC_MMIO is not set
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_VX855 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_SX150X is not set
+CONFIG_GPIO_TWL4030=y
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_74X164 is not set
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ20Z75 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_CHARGER_ISP1704 is not set
+# CONFIG_CHARGER_TWL4030 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_GPIO_FAN is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_JC42 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LTC4261 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_SMM665 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_EMC2103 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83795 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_TWL4030_WATCHDOG=y
+# CONFIG_MAX63XX_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_POWER=y
+CONFIG_TWL4030_SCRIPT=y
+CONFIG_TWL4030_CODEC=y
+# CONFIG_TWL6030_PWM is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MFD_TPS6586X is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+CONFIG_REGULATOR_DUMMY=y
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_MAX8952 is not set
+CONFIG_REGULATOR_TWL4030=y
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_LP3972 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+# CONFIG_REGULATOR_ISL6271A is not set
+# CONFIG_REGULATOR_AD5398 is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+# CONFIG_IR_CORE is not set
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=y
+CONFIG_MEDIA_TUNER_TDA8290=y
+CONFIG_MEDIA_TUNER_TDA827X=y
+CONFIG_MEDIA_TUNER_TDA18271=y
+CONFIG_MEDIA_TUNER_TDA9887=y
+CONFIG_MEDIA_TUNER_TEA5761=y
+CONFIG_MEDIA_TUNER_TEA5767=y
+CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER_XC2028=y
+CONFIG_MEDIA_TUNER_XC5000=y
+CONFIG_MEDIA_TUNER_MC44S803=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_DMA_CONTIG=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TDA9875 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+
+#
+# RDS decoders
+#
+# CONFIG_VIDEO_SAA6588 is not set
+
+#
+# Video decoders
+#
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_MT9T001 is not set
+CONFIG_VIDEO_MT9V011=y
+# CONFIG_VIDEO_MT9V032 is not set
+CONFIG_VIDEO_MT9V113=y
+# CONFIG_VIDEO_MT9T111 is not set
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+# CONFIG_VIDEO_CX25840 is not set
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_AK881X is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_VPSS_SYSTEM is not set
+# CONFIG_VIDEO_VPFE_CAPTURE is not set
+CONFIG_VIDEO_OMAP2_VOUT=y
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+CONFIG_VIDEO_OMAP3=y
+CONFIG_VIDEO_OMAP3_DEBUG=y
+# CONFIG_SOC_CAMERA is not set
+CONFIG_V4L_USB_DRIVERS=y
+CONFIG_USB_VIDEO_CLASS=y
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+# CONFIG_USB_GSPCA is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_TMIO is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_OMAP2_VRAM=y
+CONFIG_OMAP2_VRFB=y
+CONFIG_OMAP2_DSS=y
+CONFIG_OMAP2_VRAM_SIZE=4
+CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
+# CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS is not set
+CONFIG_OMAP2_DSS_DPI=y
+# CONFIG_OMAP2_DSS_RFBI is not set
+CONFIG_OMAP2_DSS_VENC=y
+CONFIG_OMAP2_VENC_OUT_TYPE_SVIDEO=y
+# CONFIG_OMAP2_VENC_OUT_TYPE_COMPOSITE is not set
+# CONFIG_OMAP2_DSS_SDI is not set
+CONFIG_OMAP2_DSS_DSI=y
+CONFIG_OMAP2_DSS_USE_DSI_PLL=y
+# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=1
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
+CONFIG_FB_OMAP2_NUM_FBS=1
+
+#
+# OMAP2/3 Display Device Drivers
+#
+CONFIG_PANEL_GENERIC=y
+# CONFIG_PANEL_LGPHILIPS_LB035Q02 is not set
+# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set
+CONFIG_PANEL_SHARP_LS037V7DW01=y
+# CONFIG_PANEL_SHARP_LQ043T1DG01 is not set
+# CONFIG_PANEL_SAMSUNG_LMS700KF23 is not set
+# CONFIG_PANEL_TAAL is not set
+# CONFIG_PANEL_TOPPOLY_TDO35S is not set
+# CONFIG_PANEL_TPO_TD043MTEA1 is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_L4F00242T03 is not set
+# CONFIG_LCD_LMS283GF05 is not set
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LCD_PLATFORM=y
+# CONFIG_LCD_S6E63M0 is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=m
+# CONFIG_BACKLIGHT_ADP8860 is not set
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=y
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_TWL4030=y
+# CONFIG_SND_SOC_WL1271BT is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_ROCCAT_PYRA is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+
+#
+# Platform Glue Layer
+#
+# CONFIG_USB_MUSB_TUSB6010_GLUE is not set
+CONFIG_USB_MUSB_OMAP2PLUS_GLUE=y
+# CONFIG_USB_MUSB_AM35X_GLUE is not set
+# CONFIG_USB_MUSB_DAVINCI is not set
+# CONFIG_USB_MUSB_DA8XX is not set
+# CONFIG_USB_MUSB_TUSB6010 is not set
+CONFIG_USB_MUSB_OMAP2PLUS=y
+# CONFIG_USB_MUSB_AM35X is not set
+# CONFIG_USB_MUSB_TI81XX is not set
+# CONFIG_USB_MUSB_BLACKFIN is not set
+# CONFIG_USB_MUSB_UX500 is not set
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA_HW=y
+# CONFIG_USB_TI_CPPI_DMA_HW is not set
+# CONFIG_USB_TI_CPPI41_DMA_HW is not set
+CONFIG_USB_INVENTRA_DMA=y
+CONFIG_MUSB_USE_SYSTEM_DMA_WORKAROUND=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_TI_CPPI41_DMA is not set
+# CONFIG_USB_TUSB_OMAP_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_USB_ANDROID=y
+# CONFIG_USB_ANDROID_ACM is not set
+CONFIG_USB_ANDROID_ADB=y
+CONFIG_USB_ANDROID_MASS_STORAGE=y
+# CONFIG_USB_ANDROID_MTP is not set
+# CONFIG_USB_ANDROID_RNDIS is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_G_WEBCAM is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_USB_ULPI is not set
+CONFIG_TWL4030_USB=y
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_EMBEDDED_SDIO is not set
+# CONFIG_MMC_PARANOID_SD_INIT is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
+CONFIG_SDIO_UART=y
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_OMAP=y
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_SWITCH=y
+# CONFIG_SWITCH_GPIO is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+CONFIG_RTC_INTF_ALARM=y
+CONFIG_RTC_INTF_ALARM_DEV=y
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+CONFIG_RTC_DRV_TWL4030=y
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_USB_IP_COMMON is not set
+# CONFIG_ECHO is not set
+# CONFIG_BRCM80211 is not set
+# CONFIG_RT2870 is not set
+# CONFIG_COMEDI is not set
+# CONFIG_ASUS_OLED is not set
+# CONFIG_R8712U is not set
+# CONFIG_TRANZPORT is not set
+
+#
+# Android
+#
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE=128
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE=16
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE=8
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d
+# CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT is not set
+CONFIG_ANDROID_TIMED_OUTPUT=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+# CONFIG_POHMELFS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_VT6656 is not set
+# CONFIG_FB_UDL is not set
+# CONFIG_IIO is not set
+# CONFIG_ZRAM is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_FB_SM7XX is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_ADIS16255 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_EASYCAP is not set
+# CONFIG_TIDSPBRIDGE is not set
+# CONFIG_WESTBRIDGE is not set
+CONFIG_WESTBRIDGE_HAL_SELECTED=y
+CONFIG_MACH_OMAP3_WESTBRIDGE_AST_PNAND_HAL=y
+# CONFIG_MACH_NO_WESTBRIDGE is not set
+# CONFIG_ATH6K_LEGACY is not set
+# CONFIG_USB_ENESTORAGE is not set
+# CONFIG_BCM_WIMAX is not set
+# CONFIG_FT1000 is not set
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_XATTR=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_YAFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_LOGFS is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFS_USE_LEGACY_DNS=y
+# CONFIG_NFS_USE_NEW_IDMAPPER is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_BKL=y
+# CONFIG_SPARSE_RCU_POINTER is not set
+CONFIG_STACKTRACE=y
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_LKDTM is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
+CONFIG_RING_BUFFER_ALLOW_SWAP=y
+CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_KPROBE_EVENT=y
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_STRICT_DEVMEM is not set
+# CONFIG_ARM_UNWIND is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_TOMOYO is not set
+# CONFIG_SECURITY_APPARMOR is not set
+# CONFIG_IMA is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_TWOFISH_COMMON=y
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_OMAP_SHAM is not set
+# CONFIG_CRYPTO_DEV_OMAP_AES is not set
+CONFIG_BINARY_PRINTF=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_REED_SOLOMON=y
+CONFIG_REED_SOLOMON_ENC8=y
+CONFIG_REED_SOLOMON_DEC8=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/kernel/arch/arm/configs/panda_defconfig b/kernel/arch/arm/configs/panda_defconfig
new file mode 100644
index 000000000000..4c5e56c56cf6
--- /dev/null
+++ b/kernel/arch/arm/configs/panda_defconfig
@@ -0,0 +1,331 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_ASHMEM=y
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARCH_OMAP=y
+CONFIG_OMAP_RESET_CLOCKS=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_MACH_OMAP_4430SDP is not set
+CONFIG_ARM_THUMBEE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_NR_CPUS=2
+CONFIG_PREEMPT=y
+CONFIG_CMDLINE="console=ttyO2,115200n8 mem=1G androidboot.console=ttyO2"
+CONFIG_CMDLINE_EXTEND=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_OMAP_SMARTREFLEX=y
+CONFIG_OMAP_SMARTREFLEX_CLASS1P5=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_WAKELOCK=y
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_TARGET_LOG=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_PHONET=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_BT=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_WILINK=y
+CONFIG_RFKILL=y
+CONFIG_RFKILL_INPUT=y
+CONFIG_MTD=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_ONENAND=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_MISC_DEVICES=y
+# CONFIG_ANDROID_PMEM is not set
+CONFIG_KERNEL_DEBUGGER_CORE=y
+CONFIG_UID_STAT=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_IFB=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_PPP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_HW_RANDOM=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_GPIO=y
+CONFIG_SPI=y
+CONFIG_SPI_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_TWL4030=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_HWMON is not set
+CONFIG_TWL6030_PWM=y
+CONFIG_REGULATOR_TWL4030=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_PVR_SGX=y
+CONFIG_PVR_NEED_PVR_DPF=y
+CONFIG_PVR_NEED_PVR_ASSERT=y
+CONFIG_PVR_USSE_EDM_STATUS_DEBUG=y
+CONFIG_FB=y
+CONFIG_OMAP2_DSS=y
+# CONFIG_OMAP2_DSS_VENC is not set
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_NUM_FBS=2
+CONFIG_OMAP2_VRAM_SIZE=16
+CONFIG_PANEL_GENERIC_DPI=y
+CONFIG_DISPLAY_SUPPORT=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_OMAP2PLUS=y
+CONFIG_USB_MUSB_PERIPHERAL=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_KEYSPAN=y
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_OMAP=y
+CONFIG_MMC_OMAP_HS=y
+CONFIG_SWITCH=y
+CONFIG_SWITCH_GPIO=y
+CONFIG_RTC_CLASS=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT4_FS=y
+# CONFIG_EXT4_FS_XATTR is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+CONFIG_DEBUG_INFO=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_ARM_UNWIND is not set
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRC_CCITT=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_SDP4430=y
+CONFIG_SND_OMAP_SOC_OMAP4_HDMI=y
+CONFIG_OMAP_HSI=y
+CONFIG_OMAP_HSI_DEVICE=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_LIB80211=y
+CONFIG_MAC80211=y
+CONFIG_MAC80211_LEDS=y
+CONFIG_MAC80211_DEBUGFS=y
+CONFIG_USB_ZD1201=y
+CONFIG_WL12XX_MENU=y
+CONFIG_WL12XX=y
+CONFIG_WL12XX_SDIO=y
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_OMAP_TEMP_SENSOR=y
+CONFIG_OMAP_DIE_TEMP_SENSOR=y
+CONFIG_TI_ST=y
+CONFIG_KEYBOARD_GPIO=y
diff --git a/kernel/arch/arm/mach-omap2/board-omap3beagle.c b/kernel/arch/arm/mach-omap2/board-omap3beagle.c
new file mode 100644
index 000000000000..b3d1b81b2a2e
--- /dev/null
+++ b/kernel/arch/arm/mach-omap2/board-omap3beagle.c
@@ -0,0 +1,1038 @@
+/*
+ * linux/arch/arm/mach-omap2/board-omap3beagle.c
+ *
+ * Copyright (C) 2008 Texas Instruments
+ *
+ * Modified from mach-omap2/board-3430sdp.c
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/mmc/host.h>
+
+#include <linux/usb/android_composite.h>
+
+#include <linux/regulator/machine.h>
+#include <linux/i2c/twl.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/display.h>
+#include <plat/gpmc.h>
+#include <plat/nand.h>
+#include <plat/usb.h>
+
+#include "mux.h"
+#include "hsmmc.h"
+#include "timer-gp.h"
+#include "board-flash.h"
+
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+#include <linux/input/synaptics_dsx.h>
+
+#define TM_SAMPLE1 (1) // 2D only
+#define TM_SAMPLE2 (2) // 2D + 0D x 2
+#define TM_SAMPLE3 (3) // 2D + 0D x 4
+#define SYNAPTICS_MODULE TM_SAMPLE1
+#endif
+
+#define NAND_BLOCK_SIZE SZ_128K
+
+#ifdef CONFIG_USB_ANDROID
+#define GOOGLE_VENDOR_ID 0x18d1
+#define GOOGLE_PRODUCT_ID 0x9018
+#define GOOGLE_ADB_PRODUCT_ID 0x9015
+#endif
+
+/* Synaptics Thin Driver */
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+static int synaptics_gpio_setup(unsigned gpio, bool configure)
+{
+ int retval=0;
+ if (configure)
+ {
+ retval = gpio_request(gpio, "rmi4_attn");
+ if (retval) {
+ pr_err("%s: Failed to get attn gpio %d. Code: %d.",
+ __func__, gpio, retval);
+ return retval;
+ }
+ omap_mux_init_signal("sdmmc2_clk.gpio_130", OMAP_PIN_INPUT_PULLUP);
+
+ retval = gpio_direction_input(gpio);
+ if (retval) {
+ pr_err("%s: Failed to setup attn gpio %d. Code: %d.",
+ __func__, gpio, retval);
+ gpio_free(gpio);
+ }
+ } else {
+ pr_warn("%s: No way to deconfigure gpio %d.",
+ __func__, gpio);
+ }
+
+ return retval;
+}
+
+ #if (SYNAPTICS_MODULE == TM_SAMPLE1)
+#define TM_SAMPLE1_ADDR 0x20
+#define TM_SAMPLE1_ATTN 130
+
+static unsigned char TM_SAMPLE1_f1a_button_codes[] = {};
+
+static struct synaptics_rmi4_capacitance_button_map TM_SAMPLE1_capacitance_button_map = {
+ .nbuttons = ARRAY_SIZE(TM_SAMPLE1_f1a_button_codes),
+ .map = TM_SAMPLE1_f1a_button_codes,
+};
+
+static struct synaptics_rmi4_platform_data rmi4_platformdata = {
+ .irq_flags = IRQF_TRIGGER_FALLING,
+ .irq_gpio = TM_SAMPLE1_ATTN,
+ .gpio_config = synaptics_gpio_setup,
+ .capacitance_button_map = &TM_SAMPLE1_capacitance_button_map,
+};
+
+static struct i2c_board_info bus2_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("synaptics_rmi4_i2c", TM_SAMPLE1_ADDR),
+ .platform_data = &rmi4_platformdata,
+ },
+};
+
+#elif (SYNAPTICS_MODULE == TM_SAMPLE2)
+#define TM_SAMPLE2_ADDR 0x20
+#define TM_SAMPLE2_ATTN 130
+
+static unsigned char TM_SAMPLE2_f1a_button_codes[] = {KEY_MENU, KEY_BACK};
+
+static struct synaptics_rmi4_capacitance_button_map TM_SAMPLE2_capacitance_button_map = {
+ .nbuttons = ARRAY_SIZE(TM_SAMPLE2_f1a_button_codes),
+ .map = TM_SAMPLE2_f1a_button_codes,
+};
+
+static struct synaptics_rmi4_platform_data rmi4_platformdata = {
+ .irq_flags = IRQF_TRIGGER_FALLING,
+ .irq_gpio = TM_SAMPLE2_ATTN,
+ .gpio_config = synaptics_gpio_setup,
+ .capacitance_button_map = &TM_SAMPLE2_capacitance_button_map,
+};
+
+static struct i2c_board_info bus2_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("synaptics_rmi4_i2c", TM_SAMPLE2_ADDR),
+ .platform_data = &rmi4_platformdata,
+ },
+};
+
+#elif (SYNAPTICS_MODULE == TM_SAMPLE3)
+#define TM_SAMPLE3_ADDR 0x20
+#define TM_SAMPLE3_ATTN 130
+
+static unsigned char TM_SAMPLE3_f1a_button_codes[] = {KEY_MENU, KEY_HOME,KEY_BACK,KEY_SEARCH};
+
+static struct synaptics_rmi4_capacitance_button_map TM_SAMPLE3_capacitance_button_map = {
+ .nbuttons = ARRAY_SIZE(TM_SAMPLE3_f1a_button_codes),
+ .map = TM_SAMPLE3_f1a_button_codes,
+};
+
+static struct synaptics_rmi4_platform_data rmi4_platformdata = {
+ .irq_flags = IRQF_TRIGGER_FALLING,
+ .irq_gpio = TM_SAMPLE3_ATTN,
+ .gpio_config = synaptics_gpio_setup,
+ .capacitance_button_map = &TM_SAMPLE3_capacitance_button_map,
+};
+
+static struct i2c_board_info bus2_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("synaptics_rmi4_i2c", TM_SAMPLE3_ADDR),
+ .platform_data = &rmi4_platformdata,
+ },
+};
+#endif
+
+void __init i2c_device_setup(void)
+{
+ pr_info(">>>>I2C device setup.");
+ if (ARRAY_SIZE(bus2_i2c_devices)) {
+ i2c_register_board_info(2, bus2_i2c_devices,
+ ARRAY_SIZE(bus2_i2c_devices));
+ }
+}
+
+/* End of Synaptics change for beagle board */
+
+static char *usb_functions_adb[] = {
+ "adb",
+};
+
+static char *usb_functions_mass_storage[] = {
+ "usb_mass_storage",
+};
+static char *usb_functions_ums_adb[] = {
+ "usb_mass_storage",
+ "adb",
+};
+
+static char *usb_functions_all[] = {
+ "adb", "usb_mass_storage",
+};
+
+static struct android_usb_product usb_products[] = {
+ {
+ .product_id = GOOGLE_PRODUCT_ID,
+ .num_functions = ARRAY_SIZE(usb_functions_adb),
+ .functions = usb_functions_adb,
+ },
+ {
+ .product_id = GOOGLE_PRODUCT_ID,
+ .num_functions = ARRAY_SIZE(usb_functions_mass_storage),
+ .functions = usb_functions_mass_storage,
+ },
+ {
+ .product_id = GOOGLE_PRODUCT_ID,
+ .num_functions = ARRAY_SIZE(usb_functions_ums_adb),
+ .functions = usb_functions_ums_adb,
+ },
+};
+
+static struct usb_mass_storage_platform_data mass_storage_pdata = {
+ .nluns = 1,
+ .vendor = "rowboat",
+ .product = "rowboat gadget",
+ .release = 0x100,
+};
+
+static struct platform_device usb_mass_storage_device = {
+ .name = "usb_mass_storage",
+ .id = -1,
+ .dev = {
+ .platform_data = &mass_storage_pdata,
+ },
+};
+
+static struct android_usb_platform_data android_usb_pdata = {
+ .vendor_id = GOOGLE_VENDOR_ID,
+ .product_id = GOOGLE_PRODUCT_ID,
+ .functions = usb_functions_all,
+ .products = usb_products,
+ .num_products = ARRAY_SIZE(usb_products),
+ .version = 0x0100,
+ .product_name = "rowboat gadget",
+ .manufacturer_name = "rowboat",
+ .serial_number = "20100720",
+ .num_functions = ARRAY_SIZE(usb_functions_all),
+};
+
+static struct platform_device androidusb_device = {
+ .name = "android_usb",
+ .id = -1,
+ .dev = {
+ .platform_data = &android_usb_pdata,
+ },
+};
+
+static void omap3beagle_android_gadget_init(void)
+{
+ platform_device_register(&androidusb_device);
+}
+#endif
+/*
+ * OMAP3 Beagle revision
+ * Run time detection of Beagle revision is done by reading GPIO.
+ * GPIO ID -
+ * AXBX = GPIO173, GPIO172, GPIO171: 1 1 1
+ * C1_3 = GPIO173, GPIO172, GPIO171: 1 1 0
+ * C4 = GPIO173, GPIO172, GPIO171: 1 0 1
+ * XM = GPIO173, GPIO172, GPIO171: 0 0 0
+ */
+enum {
+ OMAP3BEAGLE_BOARD_UNKN = 0,
+ OMAP3BEAGLE_BOARD_AXBX,
+ OMAP3BEAGLE_BOARD_C1_3,
+ OMAP3BEAGLE_BOARD_C4,
+ OMAP3BEAGLE_BOARD_XM,
+ OMAP3BEAGLE_BOARD_XMC,
+};
+
+extern void omap_pm_sys_offmode_select(int);
+extern void omap_pm_sys_offmode_pol(int);
+extern void omap_pm_sys_clkreq_pol(int);
+extern void omap_pm_auto_off(int);
+extern void omap_pm_auto_ret(int);
+
+static u8 omap3_beagle_version;
+
+static u8 omap3_beagle_get_rev(void)
+{
+ return omap3_beagle_version;
+}
+
+/**
+ * Board specific initialization of PM components
+ */
+static void __init omap3_beagle_pm_init(void)
+{
+ /* Use sys_offmode signal */
+ omap_pm_sys_offmode_select(1);
+
+ /* sys_clkreq - active high */
+ omap_pm_sys_clkreq_pol(1);
+
+ /* sys_offmode - active low */
+ omap_pm_sys_offmode_pol(0);
+
+ /* Automatically send OFF command */
+ omap_pm_auto_off(1);
+
+ /* Automatically send RET command */
+ omap_pm_auto_ret(1);
+}
+
+static void __init omap3_beagle_init_rev(void)
+{
+ int ret;
+ u16 beagle_rev = 0;
+
+ omap_mux_init_gpio(171, OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_gpio(172, OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_gpio(173, OMAP_PIN_INPUT_PULLUP);
+
+ ret = gpio_request(171, "rev_id_0");
+ if (ret < 0)
+ goto fail0;
+
+ ret = gpio_request(172, "rev_id_1");
+ if (ret < 0)
+ goto fail1;
+
+ ret = gpio_request(173, "rev_id_2");
+ if (ret < 0)
+ goto fail2;
+
+ gpio_direction_input(171);
+ gpio_direction_input(172);
+ gpio_direction_input(173);
+
+ beagle_rev = gpio_get_value(171) | (gpio_get_value(172) << 1)
+ | (gpio_get_value(173) << 2);
+
+ switch (beagle_rev) {
+ case 7:
+ printk(KERN_INFO "OMAP3 Beagle Rev: Ax/Bx\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_AXBX;
+ break;
+ case 6:
+ printk(KERN_INFO "OMAP3 Beagle Rev: C1/C2/C3\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_C1_3;
+ break;
+ case 5:
+ printk(KERN_INFO "OMAP3 Beagle Rev: C4\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_C4;
+ break;
+ case 2:
+ printk(KERN_INFO "OMAP3 Beagle Rev: xM C\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
+ break;
+ case 0:
+ printk(KERN_INFO "OMAP3 Beagle Rev: xM\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
+ break;
+ default:
+ printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+ }
+
+ return;
+
+fail2:
+ gpio_free(172);
+fail1:
+ gpio_free(171);
+fail0:
+ printk(KERN_ERR "Unable to get revision detection GPIO pins\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+
+ return;
+}
+
+static struct mtd_partition omap3beagle_nand_partitions[] = {
+ /* All the partition sizes are listed in terms of NAND block size */
+ {
+ .name = "X-Loader",
+ .offset = 0,
+ .size = 4 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "U-Boot",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
+ .size = 15 * NAND_BLOCK_SIZE,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ {
+ .name = "U-Boot Env",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */
+ .size = 1 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "Kernel",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */
+ .size = 32 * NAND_BLOCK_SIZE,
+ },
+ {
+ .name = "File System",
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+/* DSS */
+
+static int beagle_enable_dvi(struct omap_dss_device *dssdev)
+{
+ if (gpio_is_valid(dssdev->reset_gpio))
+ gpio_set_value(dssdev->reset_gpio, 1);
+
+ return 0;
+}
+
+static void beagle_disable_dvi(struct omap_dss_device *dssdev)
+{
+ if (gpio_is_valid(dssdev->reset_gpio))
+ gpio_set_value(dssdev->reset_gpio, 0);
+}
+
+static struct omap_dss_device beagle_dvi_device = {
+ .type = OMAP_DISPLAY_TYPE_DPI,
+ .name = "dvi",
+ .driver_name = "generic_panel",
+ .phy.dpi.data_lines = 24,
+ .reset_gpio = -EINVAL,
+ .platform_enable = beagle_enable_dvi,
+ .platform_disable = beagle_disable_dvi,
+};
+
+static struct omap_dss_device beagle_tv_device = {
+ .name = "tv",
+ .driver_name = "venc",
+ .type = OMAP_DISPLAY_TYPE_VENC,
+ .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO,
+};
+
+static struct omap_dss_device *beagle_dss_devices[] = {
+ &beagle_dvi_device,
+ &beagle_tv_device,
+};
+
+static struct omap_dss_board_info beagle_dss_data = {
+ .num_devices = ARRAY_SIZE(beagle_dss_devices),
+ .devices = beagle_dss_devices,
+ .default_device = &beagle_dvi_device,
+};
+
+static struct platform_device beagle_dss_device = {
+ .name = "omapdss",
+ .id = -1,
+ .dev = {
+ .platform_data = &beagle_dss_data,
+ },
+};
+
+static struct regulator_consumer_supply beagle_vdac_supply =
+ REGULATOR_SUPPLY("vdda_dac", "omapdss");
+
+static struct regulator_consumer_supply beagle_vdvi_supply =
+ REGULATOR_SUPPLY("vdds_dsi", "omapdss");
+
+static void __init beagle_display_init(void)
+{
+ int r;
+
+ r = gpio_request(beagle_dvi_device.reset_gpio, "DVI reset");
+ if (r < 0) {
+ printk(KERN_ERR "Unable to get DVI reset GPIO\n");
+ return;
+ }
+
+ gpio_direction_output(beagle_dvi_device.reset_gpio, 0);
+}
+
+#include "sdram-micron-mt46h32m32lf-6.h"
+
+static struct omap2_hsmmc_info mmc[] = {
+ {
+ .mmc = 1,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .gpio_wp = 29,
+ },
+ {} /* Terminator */
+};
+
+static struct regulator_consumer_supply beagle_vmmc1_supply = {
+ .supply = "vmmc",
+};
+
+static struct regulator_consumer_supply beagle_vsim_supply = {
+ .supply = "vmmc_aux",
+};
+
+static struct regulator_consumer_supply beagle_vaux3_supply = {
+ .supply = "cam_1v8",
+};
+
+static struct regulator_consumer_supply beagle_vaux4_supply = {
+ .supply = "cam_2v8",
+};
+
+static struct gpio_led gpio_leds[];
+
+static int beagle_twl_gpio_setup(struct device *dev,
+ unsigned gpio, unsigned ngpio)
+{
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+ mmc[0].gpio_wp = -EINVAL;
+ } else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
+ (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C4)) {
+ omap_mux_init_gpio(23, OMAP_PIN_INPUT);
+ mmc[0].gpio_wp = 23;
+ } else {
+ omap_mux_init_gpio(29, OMAP_PIN_INPUT);
+ }
+ /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+ mmc[0].gpio_cd = gpio + 0;
+ omap2_hsmmc_init(mmc);
+
+ /* link regulators to MMC adapters */
+ beagle_vmmc1_supply.dev = mmc[0].dev;
+ beagle_vsim_supply.dev = mmc[0].dev;
+
+ /* REVISIT: need ehci-omap hooks for external VBUS
+ * power switch and overcurrent detect
+ */
+ if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+ gpio_request(gpio + 1, "EHCI_nOC");
+ gpio_direction_input(gpio + 1);
+ }
+
+ /*
+ * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
+ * high / others active low)
+ */
+ gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
+ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
+ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 1);
+ else
+ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+
+ /* DVI reset GPIO is different between beagle revisions */
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC)
+ beagle_dvi_device.reset_gpio = 129;
+ else
+ beagle_dvi_device.reset_gpio = 170;
+
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+ /* Power on camera interface */
+ gpio_request(gpio + 2, "CAM_EN");
+ gpio_direction_output(gpio + 2, 1);
+
+ /* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */
+ gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
+ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 1);
+ } else {
+ gpio_request(gpio + 1, "EHCI_nOC");
+ gpio_direction_input(gpio + 1);
+
+ /* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */
+ gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
+ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+ }
+ /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
+ gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+
+ /*
+ * gpio + 1 on Xm controls the TFP410's enable line (active low)
+ * gpio + 2 control varies depending on the board rev as follows:
+ * P7/P8 revisions(prototype): Camera EN
+ * A2+ revisions (production): LDO (supplies DVI, serial, led blocks)
+ */
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) {
+ gpio_request(gpio + 1, "nDVI_PWR_EN");
+ gpio_direction_output(gpio + 1, 0);
+ gpio_request(gpio + 2, "DVI_LDO_EN");
+ gpio_direction_output(gpio + 2, 1);
+ }
+
+ return 0;
+}
+
+static struct twl4030_gpio_platform_data beagle_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+ .use_leds = true,
+ .pullups = BIT(1),
+ .pulldowns = BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13)
+ | BIT(15) | BIT(16) | BIT(17),
+ .setup = beagle_twl_gpio_setup,
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data beagle_vmmc1 = {
+ .constraints = {
+ .min_uV = 1850000,
+ .max_uV = 3150000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &beagle_vmmc1_supply,
+};
+
+/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */
+static struct regulator_init_data beagle_vsim = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 3000000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &beagle_vsim_supply,
+};
+
+/* VDAC for DSS driving S-Video (8 mA unloaded, max 65 mA) */
+static struct regulator_init_data beagle_vdac = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &beagle_vdac_supply,
+};
+
+/* VPLL2 for digital video outputs */
+static struct regulator_init_data beagle_vpll2 = {
+ .constraints = {
+ .name = "VDVI",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &beagle_vdvi_supply,
+};
+
+/* VAUX3 for CAM_1V8 */
+static struct regulator_init_data beagle_vaux3 = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &beagle_vaux3_supply,
+};
+
+ /* VAUX4 for CAM_2V8 */
+static struct regulator_init_data beagle_vaux4 = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &beagle_vaux4_supply,
+};
+
+static struct twl4030_usb_data beagle_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
+/**
+ * Macro to configure resources
+ */
+#define TWL4030_RESCONFIG(res,grp,typ1,typ2,state) \
+ { \
+ .resource = res, \
+ .devgroup = grp, \
+ .type = typ1, \
+ .type2 = typ2, \
+ .remap_sleep = state \
+ }
+
+static struct twl4030_resconfig __initdata board_twl4030_rconfig[] = {
+ TWL4030_RESCONFIG(RES_VPLL1, DEV_GRP_P1, 3, 1, RES_STATE_OFF), /* ? */
+ TWL4030_RESCONFIG(RES_VINTANA1, DEV_GRP_ALL, 1, 2, RES_STATE_SLEEP),
+ TWL4030_RESCONFIG(RES_VINTANA2, DEV_GRP_ALL, 0, 2, RES_STATE_SLEEP),
+ TWL4030_RESCONFIG(RES_VINTDIG, DEV_GRP_ALL, 1, 2, RES_STATE_SLEEP),
+ TWL4030_RESCONFIG(RES_VIO, DEV_GRP_ALL, 2, 2, RES_STATE_SLEEP),
+ TWL4030_RESCONFIG(RES_VDD1, DEV_GRP_P1, 4, 1, RES_STATE_OFF), /* ? */
+ TWL4030_RESCONFIG(RES_VDD2, DEV_GRP_P1, 3, 1, RES_STATE_OFF), /* ? */
+ TWL4030_RESCONFIG(RES_REGEN, DEV_GRP_ALL, 2, 1, RES_STATE_SLEEP),
+ TWL4030_RESCONFIG(RES_NRES_PWRON, DEV_GRP_ALL, 0, 1, RES_STATE_SLEEP),
+ TWL4030_RESCONFIG(RES_CLKEN, DEV_GRP_ALL, 3, 2, RES_STATE_SLEEP),
+ TWL4030_RESCONFIG(RES_SYSEN, DEV_GRP_ALL, 6, 1, RES_STATE_SLEEP),
+ TWL4030_RESCONFIG(RES_HFCLKOUT, DEV_GRP_P3, 0, 2, RES_STATE_SLEEP), /* ? */
+ TWL4030_RESCONFIG(0, 0, 0, 0, 0),
+};
+
+/**
+ * Optimized 'Active to Sleep' sequence
+ */
+static struct twl4030_ins omap3beagle_sleep_seq[] __initdata = {
+ { MSG_SINGULAR(DEV_GRP_NULL, RES_HFCLKOUT, RES_STATE_SLEEP), 20},
+ { MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1, RES_STATE_SLEEP), 2 },
+ { MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2, RES_STATE_SLEEP), 2 },
+};
+
+static struct twl4030_script omap3beagle_sleep_script __initdata = {
+ .script = omap3beagle_sleep_seq,
+ .size = ARRAY_SIZE(omap3beagle_sleep_seq),
+ .flags = TWL4030_SLEEP_SCRIPT,
+};
+
+/**
+ * Optimized 'Sleep to Active (P12)' sequence
+ */
+static struct twl4030_ins omap3beagle_wake_p12_seq[] __initdata = {
+ { MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1, RES_STATE_ACTIVE), 2 }
+};
+
+static struct twl4030_script omap3beagle_wake_p12_script __initdata = {
+ .script = omap3beagle_wake_p12_seq,
+ .size = ARRAY_SIZE(omap3beagle_wake_p12_seq),
+ .flags = TWL4030_WAKEUP12_SCRIPT,
+};
+
+/**
+ * Optimized 'Sleep to Active' (P3) sequence
+ */
+static struct twl4030_ins omap3beagle_wake_p3_seq[] __initdata = {
+ { MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2, RES_STATE_ACTIVE), 2 }
+};
+
+static struct twl4030_script omap3beagle_wake_p3_script __initdata = {
+ .script = omap3beagle_wake_p3_seq,
+ .size = ARRAY_SIZE(omap3beagle_wake_p3_seq),
+ .flags = TWL4030_WAKEUP3_SCRIPT,
+};
+
+/**
+ * Optimized warm reset sequence (for less power surge)
+ */
+static struct twl4030_ins omap3beagle_wrst_seq[] __initdata = {
+ { MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_OFF), 0x2 },
+ { MSG_SINGULAR(DEV_GRP_NULL, RES_MAIN_REF, RES_STATE_WRST), 2 },
+ { MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2, RES_STATE_WRST), 0x2},
+ { MSG_SINGULAR(DEV_GRP_NULL, RES_VUSB_3V1, RES_STATE_WRST), 0x2 },
+ { MSG_SINGULAR(DEV_GRP_NULL, RES_VPLL1, RES_STATE_WRST), 0x2 },
+ { MSG_SINGULAR(DEV_GRP_NULL, RES_VDD2, RES_STATE_WRST), 0x7 },
+ { MSG_SINGULAR(DEV_GRP_NULL, RES_VDD1, RES_STATE_WRST), 0x25 },
+ { MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0, RES_STATE_WRST), 0x2 },
+ { MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_ACTIVE), 0x2 },
+
+};
+
+static struct twl4030_script omap3beagle_wrst_script __initdata = {
+ .script = omap3beagle_wrst_seq,
+ .size = ARRAY_SIZE(omap3beagle_wrst_seq),
+ .flags = TWL4030_WRST_SCRIPT,
+};
+
+static struct twl4030_script __initdata *board_twl4030_scripts[] = {
+ &omap3beagle_wake_p12_script,
+ &omap3beagle_wake_p3_script,
+ &omap3beagle_sleep_script,
+ &omap3beagle_wrst_script
+};
+
+static struct twl4030_power_data __initdata omap3beagle_script_data = {
+ .scripts = board_twl4030_scripts,
+ .num = ARRAY_SIZE(board_twl4030_scripts),
+ .resource_config = board_twl4030_rconfig,
+};
+
+static struct twl4030_codec_audio_data beagle_audio_data = {
+ .audio_mclk = 26000000,
+ .digimic_delay = 1,
+ .ramp_delay_value = 1,
+ .offset_cncl_path = 1,
+ .check_defaults = false,
+ .reset_registers = false,
+ .reset_registers = false,
+};
+
+static struct twl4030_codec_data beagle_codec_data = {
+ .audio_mclk = 26000000,
+ .audio = &beagle_audio_data,
+};
+
+static struct twl4030_platform_data beagle_twldata = {
+ .irq_base = TWL4030_IRQ_BASE,
+ .irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .usb = &beagle_usb_data,
+ .gpio = &beagle_gpio_data,
+ .codec = &beagle_codec_data,
+ .vmmc1 = &beagle_vmmc1,
+ .vsim = &beagle_vsim,
+ .vdac = &beagle_vdac,
+ .vpll2 = &beagle_vpll2,
+ .vaux3 = &beagle_vaux3,
+ .vaux4 = &beagle_vaux4,
+ .power = &omap3beagle_script_data,
+};
+
+static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("twl4030", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+ .irq = INT_34XX_SYS_NIRQ,
+ .platform_data = &beagle_twldata,
+ },
+};
+
+static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
+ {
+ I2C_BOARD_INFO("eeprom", 0x50),
+ },
+};
+
+static int __init omap3_beagle_i2c_init(void)
+{
+ omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
+ ARRAY_SIZE(beagle_i2c_boardinfo));
+
+ /* Bus 2 is used for Camera/Sensor interface */
+ if (ARRAY_SIZE(bus2_i2c_devices))
+ omap_register_i2c_bus(2, 400, bus2_i2c_devices,
+ ARRAY_SIZE(bus2_i2c_devices));
+ else
+ omap_register_i2c_bus(2, 400, NULL, 0);
+
+ /* Bus 3 is attached to the DVI port where devices like the pico DLP
+ * projector don't work reliably with 400kHz */
+ omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
+
+ return 0;
+}
+
+static struct gpio_led gpio_leds[] = {
+ {
+ .name = "beagleboard::usr0",
+ .default_trigger = "heartbeat",
+ .gpio = 150,
+ },
+ {
+ .name = "beagleboard::usr1",
+ .default_trigger = "mmc0",
+ .gpio = 149,
+ },
+ {
+ .name = "beagleboard::pmu_stat",
+ .gpio = -EINVAL, /* gets replaced */
+ .active_low = true,
+ },
+};
+
+static struct gpio_led_platform_data gpio_led_info = {
+ .leds = gpio_leds,
+ .num_leds = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device leds_gpio = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &gpio_led_info,
+ },
+};
+
+static struct gpio_keys_button gpio_buttons[] = {
+ {
+ .code = KEY_POWER,
+ .gpio = 4,
+ .desc = "user",
+ .wakeup = 1,
+ },
+};
+
+static struct gpio_keys_platform_data gpio_key_info = {
+ .buttons = gpio_buttons,
+ .nbuttons = ARRAY_SIZE(gpio_buttons),
+};
+
+static struct platform_device keys_gpio = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &gpio_key_info,
+ },
+};
+
+static void __init omap3_beagle_init_irq(void)
+{
+ omap2_init_common_infrastructure();
+ omap2_init_common_devices(mt46h32m32lf6_sdrc_params,
+ mt46h32m32lf6_sdrc_params);
+ omap_init_irq();
+ gpmc_init();
+#ifdef CONFIG_OMAP_32K_TIMER
+ if (omap3_beagle_version == OMAP3BEAGLE_BOARD_AXBX)
+ omap2_gp_clockevent_set_gptimer(12);
+ else
+ omap2_gp_clockevent_set_gptimer(1);
+#endif
+}
+
+static struct platform_device *omap3_beagle_devices[] __initdata = {
+ &leds_gpio,
+ &keys_gpio,
+ &beagle_dss_device,
+ &usb_mass_storage_device,
+};
+
+static void __init omap3beagle_flash_init(void)
+{
+ u8 cs = 0;
+ u8 nandcs = GPMC_CS_NUM + 1;
+
+ /* find out the chip-select on which NAND exists */
+ while (cs < GPMC_CS_NUM) {
+ u32 ret = 0;
+ ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+ if ((ret & 0xC00) == 0x800) {
+ printk(KERN_INFO "Found NAND on CS%d\n", cs);
+ if (nandcs > GPMC_CS_NUM)
+ nandcs = cs;
+ }
+ cs++;
+ }
+
+ if (nandcs > GPMC_CS_NUM) {
+ printk(KERN_INFO "NAND: Unable to find configuration "
+ "in GPMC\n ");
+ return;
+ }
+
+ if (nandcs < GPMC_CS_NUM) {
+ printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
+ board_nand_init(omap3beagle_nand_partitions,
+ ARRAY_SIZE(omap3beagle_nand_partitions),
+ nandcs, NAND_BUSWIDTH_16);
+ }
+}
+
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+
+ .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+ .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+ .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+ .phy_reset = true,
+ .reset_gpio_port[0] = -EINVAL,
+ .reset_gpio_port[1] = 147,
+ .reset_gpio_port[2] = -EINVAL
+};
+
+#ifdef CONFIG_OMAP_MUX
+static struct omap_board_mux board_mux[] __initdata = {
+ OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP |
+ OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_OUTPUT_LOW |
+ OMAP_PIN_OFF_WAKEUPENABLE),
+ { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+#endif
+
+static struct omap_musb_board_data musb_board_data = {
+ .interface_type = MUSB_INTERFACE_ULPI,
+ .mode = MUSB_OTG,
+ .power = 100,
+};
+
+static void __init omap3_beagle_init(void)
+{
+ omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+ omap3_beagle_init_rev();
+ omap3_beagle_i2c_init();
+ platform_add_devices(omap3_beagle_devices,
+ ARRAY_SIZE(omap3_beagle_devices));
+ omap_serial_init();
+
+ omap_mux_init_gpio(170, OMAP_PIN_INPUT);
+ gpio_request(170, "DVI_nPD");
+ /* REVISIT leave DVI powered down until it's needed ... */
+ gpio_direction_output(170, true);
+
+ usb_musb_init(&musb_board_data);
+ usb_ehci_init(&ehci_pdata);
+ omap3beagle_flash_init();
+
+ /* Ensure SDRC pins are mux'd for self-refresh */
+ omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
+ omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
+
+ beagle_display_init();
+#ifdef CONFIG_USB_ANDROID
+ omap3beagle_android_gadget_init();
+#endif
+ omap3_beagle_pm_init();
+}
+
+MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
+ /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
+ .boot_params = 0x80000100,
+ .map_io = omap3_map_io,
+ .reserve = omap_reserve,
+ .init_irq = omap3_beagle_init_irq,
+ .init_machine = omap3_beagle_init,
+ .timer = &omap_timer,
+MACHINE_END
diff --git a/kernel/arch/arm/mach-omap2/board-omap4panda.c b/kernel/arch/arm/mach-omap2/board-omap4panda.c
new file mode 100644
index 000000000000..4f8c79ddd650
--- /dev/null
+++ b/kernel/arch/arm/mach-omap2/board-omap4panda.c
@@ -0,0 +1,1053 @@
+/*
+ * Board support file for OMAP4430 based PandaBoard.
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * Author: David Anders <x0132446@ti.com>
+ *
+ * Based on mach-omap2/board-4430sdp.c
+ *
+ * Author: Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Based on mach-omap2/board-3430sdp.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/omapfb.h>
+#include <linux/reboot.h>
+#include <linux/usb/otg.h>
+#include <linux/i2c/twl.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/wl12xx.h>
+#include <linux/memblock.h>
+#include <linux/skbuff.h>
+#include <linux/ti_wilink_st.h>
+#include <linux/platform_data/ram_console.h>
+
+#include <mach/hardware.h>
+#include <mach/omap4-common.h>
+#include <mach/emif.h>
+#include <mach/lpddr2-elpida.h>
+#include <mach/dmm.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <video/omapdss.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/usb.h>
+#include <plat/mmc.h>
+#include <plat/remoteproc.h>
+#include <plat/vram.h>
+#include <video/omap-panel-generic-dpi.h>
+#include "timer-gp.h"
+
+#include "hsmmc.h"
+#include "control.h"
+#include "mux.h"
+#include "common-board-devices.h"
+#include "prm-regbits-44xx.h"
+#include "prm44xx.h"
+#include "pm.h"
+#include "resetreason.h"
+
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+#include <linux/input/synaptics_dsx.h>
+#define TM_SAMPLE1 (1) // 2D only
+#define TM_SAMPLE2 (2) // 2D + 0D x 2
+#define TM_SAMPLE3 (3) // 2D + 0D x 4
+#define SYNAPTICS_MODULE TM_SAMPLE1
+#endif
+
+#define PANDA_RAMCONSOLE_START (PLAT_PHYS_OFFSET + SZ_512M)
+#define PANDA_RAMCONSOLE_SIZE SZ_2M
+
+#define GPIO_HUB_POWER 1
+#define GPIO_HUB_NRESET 62
+#define GPIO_WIFI_PMENA 43
+#define GPIO_WIFI_IRQ 53
+#define HDMI_GPIO_CT_CP_HPD 60
+#define HDMI_GPIO_HPD 63 /* Hot plug pin for HDMI */
+#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
+#define TPS62361_GPIO 7 /* VCORE1 power control */
+#define PANDA_BT_GPIO 46
+
+
+#define PHYS_ADDR_SMC_SIZE (SZ_1M * 3)
+#define PHYS_ADDR_SMC_MEM (0x80000000 + SZ_1G - PHYS_ADDR_SMC_SIZE)
+#define OMAP_ION_HEAP_SECURE_INPUT_SIZE (SZ_1M * 90)
+#define PHYS_ADDR_DUCATI_SIZE (SZ_1M * 105)
+#define PHYS_ADDR_DUCATI_MEM (PHYS_ADDR_SMC_MEM - PHYS_ADDR_DUCATI_SIZE - \
+ OMAP_ION_HEAP_SECURE_INPUT_SIZE)
+
+#define WILINK_UART_DEV_NAME "/dev/ttyO1"
+
+
+/* Synaptics changes for PandaBoard */
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+static int synaptics_gpio_setup(unsigned gpio, bool configure)
+{
+ int retval = 0;
+
+ if (configure) {
+ retval = gpio_request(gpio, "rmi4_attn");
+ if (retval) {
+ pr_err("%s: Failed to get attn gpio %d (code: %d)",
+ __func__, gpio, retval);
+ return retval;
+ }
+ omap_mux_init_signal("gpmc_ad15.gpio_39", OMAP_PIN_INPUT_PULLUP);
+
+ retval = gpio_direction_input(gpio);
+ if (retval) {
+ pr_err("%s: Failed to setup attn gpio %d (code: %d)",
+ __func__, gpio, retval);
+ gpio_free(gpio);
+ }
+ } else {
+ pr_warn("%s: No way to deconfigure gpio %d",
+ __func__, gpio);
+ }
+
+ return retval;
+}
+
+ #if (SYNAPTICS_MODULE == TM_SAMPLE1)
+#define TM_SAMPLE1_ADDR 0x20
+#define TM_SAMPLE1_ATTN 130
+
+static unsigned char TM_SAMPLE1_f1a_button_codes[] = {};
+
+static struct synaptics_rmi4_capacitance_button_map TM_SAMPLE1_capacitance_button_map = {
+ .nbuttons = ARRAY_SIZE(TM_SAMPLE1_f1a_button_codes),
+ .map = TM_SAMPLE1_f1a_button_codes,
+};
+
+static struct synaptics_rmi4_platform_data rmi4_platformdata = {
+ .irq_flags = IRQF_TRIGGER_FALLING,
+ .irq_gpio = TM_SAMPLE1_ATTN,
+ .gpio_config = synaptics_gpio_setup,
+ .capacitance_button_map = &TM_SAMPLE1_capacitance_button_map,
+};
+
+static struct i2c_board_info bus4_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("synaptics_rmi4_i2c", TM_SAMPLE1_ADDR),
+ .platform_data = &rmi4_platformdata,
+ },
+};
+
+#elif (SYNAPTICS_MODULE == TM_SAMPLE2)
+#define TM_SAMPLE2_ADDR 0x20
+#define TM_SAMPLE2_ATTN 130
+
+static unsigned char TM_SAMPLE2_f1a_button_codes[] = {KEY_MENU, KEY_BACK};
+
+static struct synaptics_rmi4_capacitance_button_map TM_SAMPLE2_capacitance_button_map = {
+ .nbuttons = ARRAY_SIZE(TM_SAMPLE2_f1a_button_codes),
+ .map = TM_SAMPLE2_f1a_button_codes,
+};
+
+static struct synaptics_rmi4_platform_data rmi4_platformdata = {
+ .irq_flags = IRQF_TRIGGER_FALLING,
+ .irq_gpio = TM_SAMPLE2_ATTN,
+ .gpio_config = synaptics_gpio_setup,
+ .capacitance_button_map = &TM_SAMPLE2_capacitance_button_map,
+};
+
+static struct i2c_board_info bus4_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("synaptics_rmi4_i2c", TM_SAMPLE2_ADDR),
+ .platform_data = &rmi4_platformdata,
+ },
+};
+};
+
+#elif (SYNAPTICS_MODULE == TM_SAMPLE3)
+#define TM_SAMPLE3_ADDR 0x20
+#define TM_SAMPLE3_ATTN 130
+
+static unsigned char TM_SAMPLE3_f1a_button_codes[] = {KEY_MENU, KEY_HOME,KEY_BACK,KEY_SEARCH};
+
+static struct synaptics_rmi4_capacitance_button_map TM_SAMPLE3_capacitance_button_map = {
+ .nbuttons = ARRAY_SIZE(TM_SAMPLE3_f1a_button_codes),
+ .map = TM_SAMPLE3_f1a_button_codes,
+};
+
+static struct synaptics_rmi4_platform_data rmi4_platformdata = {
+ .irq_flags = IRQF_TRIGGER_FALLING,
+ .irq_gpio = TM_SAMPLE3_ATTN,
+ .gpio_config = synaptics_gpio_setup,
+ .capacitance_button_map = &TM_SAMPLE3_capacitance_button_map,
+};
+
+static struct i2c_board_info bus4_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("synaptics_rmi4_i2c", TM_SAMPLE3_ADDR),
+ .platform_data = &rmi4_platformdata,
+ },
+};
+#endif
+
+void __init i2c_device_setup(void)
+{
+ pr_info(">>>>I2C device setup");
+ if (ARRAY_SIZE(bus4_i2c_devices)) {
+ i2c_register_board_info(4, bus4_i2c_devices,
+ ARRAY_SIZE(bus4_i2c_devices));
+ }
+}
+#endif
+/* End of Synaptics changes for PandaBoard */
+
+static struct gpio_led gpio_leds[] = {
+ {
+ .name = "pandaboard::status1",
+ .default_trigger = "heartbeat",
+ .gpio = 7,
+ },
+ {
+ .name = "pandaboard::status2",
+ .default_trigger = "mmc0",
+ .gpio = 8,
+ },
+};
+
+static struct gpio_led_platform_data gpio_led_info = {
+ .leds = gpio_leds,
+ .num_leds = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device leds_gpio = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &gpio_led_info,
+ },
+};
+
+/* GPIO_KEY for the panda */
+static struct gpio_keys_button panda_gpio_keys_buttons[] = {
+ [0] = {
+ .code = KEY_HOME,
+ .gpio = 113,
+ .desc = "user_button",
+ .active_low = 1,
+ .debounce_interval = 5,
+ },
+};
+
+static struct gpio_keys_platform_data panda_gpio_keys = {
+ .buttons = panda_gpio_keys_buttons,
+ .nbuttons = ARRAY_SIZE(panda_gpio_keys_buttons),
+ .rep = 0,
+};
+
+static struct platform_device panda_gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &panda_gpio_keys,
+ },
+};
+
+/* TODO: handle suspend/resume here.
+ * Upon every suspend, make sure the wilink chip is
+ * capable enough to wake-up the OMAP host.
+ */
+static int plat_wlink_kim_suspend(struct platform_device *pdev, pm_message_t
+ state)
+{
+ return 0;
+}
+
+static int plat_wlink_kim_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+/* wl128x BT, FM, GPS connectivity chip */
+static struct ti_st_plat_data wilink_pdata = {
+ .nshutdown_gpio = PANDA_BT_GPIO,
+ .dev_name = WILINK_UART_DEV_NAME,
+ .flow_cntrl = 1,
+ .baud_rate = 3686400,
+ .suspend = plat_wlink_kim_suspend,
+ .resume = plat_wlink_kim_resume,
+};
+
+static struct platform_device btwilink_device = {
+ .name = "btwilink",
+ .id = -1,
+};
+
+/* wl127x BT, FM, GPS connectivity chip */
+static struct platform_device wl1271_device = {
+ .name = "kim",
+ .id = -1,
+ .dev.platform_data = &wilink_pdata,
+};
+
+
+static struct platform_device *panda_devices[] __initdata = {
+ &leds_gpio,
+ &wl1271_device,
+ &btwilink_device,
+ &panda_gpio_keys_device,
+};
+
+static void __init omap4_panda_init_early(void)
+{
+ omap2_init_common_infrastructure();
+ omap2_init_common_devices(NULL, NULL);
+}
+
+static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+ .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
+ .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
+ .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
+ .phy_reset = false,
+ .reset_gpio_port[0] = -EINVAL,
+ .reset_gpio_port[1] = -EINVAL,
+ .reset_gpio_port[2] = -EINVAL
+};
+
+static struct gpio panda_ehci_gpios[] __initdata = {
+ { GPIO_HUB_POWER, GPIOF_OUT_INIT_LOW, "hub_power" },
+ { GPIO_HUB_NRESET, GPIOF_OUT_INIT_LOW, "hub_nreset" },
+};
+
+static void __init omap4_ehci_init(void)
+{
+ int ret;
+ struct clk *phy_ref_clk;
+
+ /* FREF_CLK3 provides the 19.2 MHz reference clock to the PHY */
+ phy_ref_clk = clk_get(NULL, "auxclk3_ck");
+ if (IS_ERR(phy_ref_clk)) {
+ pr_err("Cannot request auxclk3\n");
+ return;
+ }
+ clk_set_rate(phy_ref_clk, 19200000);
+ clk_enable(phy_ref_clk);
+
+ /* disable the power to the usb hub prior to init and reset phy+hub */
+ ret = gpio_request_array(panda_ehci_gpios,
+ ARRAY_SIZE(panda_ehci_gpios));
+ if (ret) {
+ pr_err("Unable to initialize EHCI power/reset\n");
+ return;
+ }
+
+ gpio_export(GPIO_HUB_POWER, 0);
+ gpio_export(GPIO_HUB_NRESET, 0);
+ gpio_set_value(GPIO_HUB_NRESET, 1);
+
+ usbhs_init(&usbhs_bdata);
+
+ /* enable power to hub */
+ gpio_set_value(GPIO_HUB_POWER, 1);
+}
+
+static struct omap_musb_board_data musb_board_data = {
+ .interface_type = MUSB_INTERFACE_UTMI,
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ .mode = MUSB_PERIPHERAL,
+#else
+ .mode = MUSB_OTG,
+#endif
+ .power = 100,
+};
+
+static struct twl4030_usb_data omap4_usbphy_data = {
+ .phy_init = omap4430_phy_init,
+ .phy_exit = omap4430_phy_exit,
+ .phy_power = omap4430_phy_power,
+ .phy_set_clock = omap4430_phy_set_clk,
+ .phy_suspend = omap4430_phy_suspend,
+};
+
+static struct omap2_hsmmc_info mmc[] = {
+ {
+ .mmc = 1,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .gpio_wp = -EINVAL,
+ .gpio_cd = -EINVAL,
+ },
+ {
+ .name = "wl1271",
+ .mmc = 5,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
+ .gpio_wp = -EINVAL,
+ .gpio_cd = -EINVAL,
+ .ocr_mask = MMC_VDD_165_195,
+ .nonremovable = true,
+ },
+ {} /* Terminator */
+};
+
+static struct regulator_consumer_supply omap4_panda_vmmc_supply[] = {
+ {
+ .supply = "vmmc",
+ .dev_name = "omap_hsmmc.0",
+ },
+};
+
+static struct regulator_consumer_supply omap4_panda_vmmc5_supply = {
+ .supply = "vmmc",
+ .dev_name = "omap_hsmmc.4",
+};
+
+static struct regulator_init_data panda_vmmc5 = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &omap4_panda_vmmc5_supply,
+};
+
+static struct fixed_voltage_config panda_vwlan = {
+ .supply_name = "vwl1271",
+ .microvolts = 1800000, /* 1.8V */
+ .gpio = GPIO_WIFI_PMENA,
+ .startup_delay = 70000, /* 70msec */
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &panda_vmmc5,
+};
+
+static struct platform_device omap_vwlan_device = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+ .dev = {
+ .platform_data = &panda_vwlan,
+ },
+};
+
+struct wl12xx_platform_data omap_panda_wlan_data __initdata = {
+ .irq = OMAP_GPIO_IRQ(GPIO_WIFI_IRQ),
+ /* PANDA ref clock is 38.4 MHz */
+ .board_ref_clock = 2,
+};
+
+static int omap4_twl6030_hsmmc_late_init(struct device *dev)
+{
+ int ret = 0;
+ struct platform_device *pdev = container_of(dev,
+ struct platform_device, dev);
+ struct omap_mmc_platform_data *pdata = dev->platform_data;
+
+ if (!pdata) {
+ dev_err(dev, "%s: NULL platform data\n", __func__);
+ return -EINVAL;
+ }
+ /* Setting MMC1 Card detect Irq */
+ if (pdev->id == 0) {
+ ret = twl6030_mmc_card_detect_config();
+ if (ret)
+ dev_err(dev, "%s: Error card detect config(%d)\n",
+ __func__, ret);
+ else
+ pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+ }
+ return ret;
+}
+
+static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
+{
+ struct omap_mmc_platform_data *pdata;
+
+ /* dev can be null if CONFIG_MMC_OMAP_HS is not set */
+ if (!dev) {
+ pr_err("Failed omap4_twl6030_hsmmc_set_late_init\n");
+ return;
+ }
+ pdata = dev->platform_data;
+
+ pdata->init = omap4_twl6030_hsmmc_late_init;
+}
+
+static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
+{
+ struct omap2_hsmmc_info *c;
+
+ omap2_hsmmc_init(controllers);
+ for (c = controllers; c->mmc; c++)
+ omap4_twl6030_hsmmc_set_late_init(c->dev);
+
+ return 0;
+}
+
+static struct regulator_init_data omap4_panda_vaux2 = {
+ .constraints = {
+ .min_uV = 1200000,
+ .max_uV = 2800000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+};
+
+static struct regulator_init_data omap4_panda_vaux3 = {
+ .constraints = {
+ .min_uV = 1000000,
+ .max_uV = 3000000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+};
+
+/* VMMC1 for MMC1 card */
+static struct regulator_init_data omap4_panda_vmmc = {
+ .constraints = {
+ .min_uV = 1200000,
+ .max_uV = 3000000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = omap4_panda_vmmc_supply,
+};
+
+static struct regulator_init_data omap4_panda_vpp = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 2500000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+};
+
+static struct regulator_init_data omap4_panda_vana = {
+ .constraints = {
+ .min_uV = 2100000,
+ .max_uV = 2100000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+};
+
+static struct regulator_init_data omap4_panda_vcxio = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+};
+
+static struct regulator_consumer_supply panda_vdac_supply[] = {
+ {
+ .supply = "hdmi_vref",
+ },
+};
+
+static struct regulator_init_data omap4_panda_vdac = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(panda_vdac_supply),
+ .consumer_supplies = panda_vdac_supply,
+};
+
+static struct regulator_init_data omap4_panda_vusb = {
+ .constraints = {
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+};
+
+static struct regulator_init_data omap4_panda_clk32kg = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .always_on = true,
+ },
+};
+
+static void omap4_audio_conf(void)
+{
+ /* twl6040 naudint */
+ omap_mux_init_signal("sys_nirq2.sys_nirq2", \
+ OMAP_PIN_INPUT_PULLUP);
+}
+
+static struct twl4030_codec_audio_data twl6040_audio = {
+ /* single-step ramp for headset and handsfree */
+ .hs_left_step = 0x0f,
+ .hs_right_step = 0x0f,
+ .hf_left_step = 0x1d,
+ .hf_right_step = 0x1d,
+ .hs_switch_dev = 0x1,
+ .hs_forced_hs_state = 0x1
+};
+
+static struct twl4030_codec_data twl6040_codec = {
+ .audio = &twl6040_audio,
+ .audpwron_gpio = 127,
+ .naudint_irq = OMAP44XX_IRQ_SYS_2N,
+ .irq_base = TWL6040_CODEC_IRQ_BASE,
+};
+
+static struct twl4030_platform_data omap4_panda_twldata = {
+ .irq_base = TWL6030_IRQ_BASE,
+ .irq_end = TWL6030_IRQ_END,
+
+ /* Regulators */
+ .vmmc = &omap4_panda_vmmc,
+ .vpp = &omap4_panda_vpp,
+ .vana = &omap4_panda_vana,
+ .vcxio = &omap4_panda_vcxio,
+ .vdac = &omap4_panda_vdac,
+ .vusb = &omap4_panda_vusb,
+ .vaux2 = &omap4_panda_vaux2,
+ .vaux3 = &omap4_panda_vaux3,
+ .clk32kg = &omap4_panda_clk32kg,
+ .usb = &omap4_usbphy_data,
+
+ /* children */
+ .codec = &twl6040_codec,
+};
+
+/*
+ * Display monitor features are burnt in their EEPROM as EDID data. The EEPROM
+ * is connected as I2C slave device, and can be accessed at address 0x50
+ */
+static struct i2c_board_info __initdata panda_i2c_eeprom[] = {
+ {
+ I2C_BOARD_INFO("eeprom", 0x50),
+ },
+};
+
+static int __init omap4_panda_i2c_init(void)
+{
+ omap4_pmic_init("twl6030", &omap4_panda_twldata);
+ omap_register_i2c_bus(2, 400, NULL, 0);
+ /*
+ * Bus 3 is attached to the DVI port where devices like the pico DLP
+ * projector don't work reliably with 400kHz
+ */
+ omap_register_i2c_bus(3, 100, panda_i2c_eeprom,
+ ARRAY_SIZE(panda_i2c_eeprom));
+ if(ARRAY_SIZE(bus4_i2c_devices))
+ omap_register_i2c_bus(4, 400, bus4_i2c_devices, ARRAY_SIZE(bus4_i2c_devices));
+ else
+ omap_register_i2c_bus(4, 400, NULL, 0);
+ return 0;
+}
+
+#ifdef CONFIG_OMAP_MUX
+static struct omap_board_mux board_mux[] __initdata = {
+ /* WLAN IRQ - GPIO 53 */
+ OMAP4_MUX(GPMC_NCS3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT),
+ /* WLAN POWER ENABLE - GPIO 43 */
+ OMAP4_MUX(GPMC_A19, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT),
+ /* WLAN SDIO: MMC5 CMD */
+ OMAP4_MUX(SDMMC5_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ /* WLAN SDIO: MMC5 CLK */
+ OMAP4_MUX(SDMMC5_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ /* WLAN SDIO: MMC5 DAT[0-3] */
+ OMAP4_MUX(SDMMC5_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ OMAP4_MUX(SDMMC5_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP),
+ /* gpio 0 - TFP410 PD */
+ OMAP4_MUX(KPD_COL1, OMAP_PIN_OUTPUT | OMAP_MUX_MODE3),
+ /* dispc2_data23 */
+ OMAP4_MUX(USBB2_ULPITLL_STP, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data22 */
+ OMAP4_MUX(USBB2_ULPITLL_DIR, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data21 */
+ OMAP4_MUX(USBB2_ULPITLL_NXT, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data20 */
+ OMAP4_MUX(USBB2_ULPITLL_DAT0, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data19 */
+ OMAP4_MUX(USBB2_ULPITLL_DAT1, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data18 */
+ OMAP4_MUX(USBB2_ULPITLL_DAT2, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data15 */
+ OMAP4_MUX(USBB2_ULPITLL_DAT3, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data14 */
+ OMAP4_MUX(USBB2_ULPITLL_DAT4, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data13 */
+ OMAP4_MUX(USBB2_ULPITLL_DAT5, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data12 */
+ OMAP4_MUX(USBB2_ULPITLL_DAT6, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data11 */
+ OMAP4_MUX(USBB2_ULPITLL_DAT7, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data10 */
+ OMAP4_MUX(DPM_EMU3, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data9 */
+ OMAP4_MUX(DPM_EMU4, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data16 */
+ OMAP4_MUX(DPM_EMU5, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data17 */
+ OMAP4_MUX(DPM_EMU6, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_hsync */
+ OMAP4_MUX(DPM_EMU7, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_pclk */
+ OMAP4_MUX(DPM_EMU8, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_vsync */
+ OMAP4_MUX(DPM_EMU9, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_de */
+ OMAP4_MUX(DPM_EMU10, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data8 */
+ OMAP4_MUX(DPM_EMU11, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data7 */
+ OMAP4_MUX(DPM_EMU12, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data6 */
+ OMAP4_MUX(DPM_EMU13, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data5 */
+ OMAP4_MUX(DPM_EMU14, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data4 */
+ OMAP4_MUX(DPM_EMU15, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data3 */
+ OMAP4_MUX(DPM_EMU16, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data2 */
+ OMAP4_MUX(DPM_EMU17, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data1 */
+ OMAP4_MUX(DPM_EMU18, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ /* dispc2_data0 */
+ OMAP4_MUX(DPM_EMU19, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5),
+ { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+
+static inline void __init board_serial_init(void)
+{
+ omap_serial_init();
+}
+#else
+#define board_mux NULL
+
+static inline void __init board_serial_init(void)
+{
+ omap_serial_init();
+}
+#endif
+
+/* Display DVI */
+#define PANDA_DVI_TFP410_POWER_DOWN_GPIO 0
+
+static int omap4_panda_enable_dvi(struct omap_dss_device *dssdev)
+{
+ gpio_set_value(dssdev->reset_gpio, 1);
+ return 0;
+}
+
+static void omap4_panda_disable_dvi(struct omap_dss_device *dssdev)
+{
+ gpio_set_value(dssdev->reset_gpio, 0);
+}
+
+/* Using generic display panel */
+static struct panel_generic_dpi_data omap4_dvi_panel = {
+ .name = "generic_720p",
+ .platform_enable = omap4_panda_enable_dvi,
+ .platform_disable = omap4_panda_disable_dvi,
+};
+
+struct omap_dss_device omap4_panda_dvi_device = {
+ .type = OMAP_DISPLAY_TYPE_DPI,
+ .name = "dvi",
+ .driver_name = "generic_dpi_panel",
+ .data = &omap4_dvi_panel,
+ .phy.dpi.data_lines = 24,
+ .reset_gpio = PANDA_DVI_TFP410_POWER_DOWN_GPIO,
+ .channel = OMAP_DSS_CHANNEL_LCD2,
+};
+
+int __init omap4_panda_dvi_init(void)
+{
+ int r;
+
+ /* Requesting TFP410 DVI GPIO and disabling it, at bootup */
+ r = gpio_request_one(omap4_panda_dvi_device.reset_gpio,
+ GPIOF_OUT_INIT_LOW, "DVI PD");
+ if (r)
+ pr_err("Failed to get DVI powerdown GPIO\n");
+
+ return r;
+}
+
+static struct gpio panda_hdmi_gpios[] = {
+ { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" },
+ { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
+};
+
+static void omap4_panda_hdmi_mux_init(void)
+{
+ u32 r;
+ int status;
+ /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
+ omap_mux_init_signal("hdmi_hpd.hdmi_hpd",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("gpmc_wait2.gpio_100",
+ OMAP_PIN_INPUT_PULLDOWN);
+ omap_mux_init_signal("hdmi_cec.hdmi_cec",
+ OMAP_PIN_INPUT_PULLUP);
+ /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
+ omap_mux_init_signal("hdmi_ddc_scl.hdmi_ddc_scl",
+ OMAP_PIN_INPUT_PULLUP);
+ omap_mux_init_signal("hdmi_ddc_sda.hdmi_ddc_sda",
+ OMAP_PIN_INPUT_PULLUP);
+
+ /* strong pullup on DDC lines using unpublished register */
+ r = ((1 << 24) | (1 << 28)) ;
+ omap4_ctrl_pad_writel(r, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_1);
+
+ gpio_request(HDMI_GPIO_HPD, NULL);
+ omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT | OMAP_PULL_ENA);
+ gpio_direction_input(HDMI_GPIO_HPD);
+
+ status = gpio_request_array(panda_hdmi_gpios,
+ ARRAY_SIZE(panda_hdmi_gpios));
+ if (status)
+ pr_err("%s: Cannot request HDMI GPIOs %x \n", __func__, status);
+}
+
+static struct omap_dss_device omap4_panda_hdmi_device = {
+ .name = "hdmi",
+ .driver_name = "hdmi_panel",
+ .type = OMAP_DISPLAY_TYPE_HDMI,
+ .clocks = {
+ .dispc = {
+ .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK,
+ },
+ .hdmi = {
+ .regn = 15,
+ .regm2 = 1,
+ },
+ },
+ .hpd_gpio = HDMI_GPIO_HPD,
+ .channel = OMAP_DSS_CHANNEL_DIGIT,
+};
+
+static struct omap_dss_device *omap4_panda_dss_devices[] = {
+ &omap4_panda_dvi_device,
+ &omap4_panda_hdmi_device,
+};
+
+static struct omap_dss_board_info omap4_panda_dss_data = {
+ .num_devices = ARRAY_SIZE(omap4_panda_dss_devices),
+ .devices = omap4_panda_dss_devices,
+ .default_device = &omap4_panda_dvi_device,
+};
+
+/*
+ * LPDDR2 Configeration Data:
+ * The memory organisation is as below :
+ * EMIF1 - CS0 - 2 Gb
+ * CS1 - 2 Gb
+ * EMIF2 - CS0 - 2 Gb
+ * CS1 - 2 Gb
+ * --------------------
+ * TOTAL - 8 Gb
+ *
+ * Same devices installed on EMIF1 and EMIF2
+ */
+static __initdata struct emif_device_details emif_devices = {
+ .cs0_device = &lpddr2_elpida_2G_S4_dev,
+ .cs1_device = &lpddr2_elpida_2G_S4_dev
+};
+
+void omap4_panda_display_init(void)
+{
+ int r;
+
+ r = omap4_panda_dvi_init();
+ if (r)
+ pr_err("error initializing panda DVI\n");
+
+ omap4_panda_hdmi_mux_init();
+ omap_display_init(&omap4_panda_dss_data);
+}
+
+static int panda_notifier_call(struct notifier_block *this,
+ unsigned long code, void *cmd)
+{
+ void __iomem *sar_base;
+ u32 v = OMAP4430_RST_GLOBAL_COLD_SW_MASK;
+
+ sar_base = omap4_get_sar_ram_base();
+
+ if (!sar_base)
+ return notifier_from_errno(-ENOMEM);
+
+ if ((code == SYS_RESTART) && (cmd != NULL)) {
+ /* cmd != null; case: warm boot */
+ if (!strcmp(cmd, "bootloader")) {
+ /* Save reboot mode in scratch memory */
+ strcpy(sar_base + 0xA0C, cmd);
+ v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
+ } else if (!strcmp(cmd, "recovery")) {
+ /* Save reboot mode in scratch memory */
+ strcpy(sar_base + 0xA0C, cmd);
+ v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
+ } else {
+ v |= OMAP4430_RST_GLOBAL_COLD_SW_MASK;
+ }
+ }
+
+ omap4_prm_write_inst_reg(0xfff, OMAP4430_PRM_DEVICE_INST,
+ OMAP4_RM_RSTST);
+ omap4_prm_write_inst_reg(v, OMAP4430_PRM_DEVICE_INST, OMAP4_RM_RSTCTRL);
+ v = omap4_prm_read_inst_reg(WKUP_MOD, OMAP4_RM_RSTCTRL);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block panda_reboot_notifier = {
+ .notifier_call = panda_notifier_call,
+};
+
+#define PANDA_FB_RAM_SIZE SZ_16M /* 1920?1080*4 * 2 */
+static struct omapfb_platform_data panda_fb_pdata = {
+ .mem_desc = {
+ .region_cnt = 1,
+ .region = {
+ [0] = {
+ .size = PANDA_FB_RAM_SIZE,
+ },
+ },
+ },
+};
+
+static struct resource ramconsole_resources[] = {
+ {
+ .flags = IORESOURCE_MEM,
+ .start = PANDA_RAMCONSOLE_START,
+ .end = PANDA_RAMCONSOLE_START + PANDA_RAMCONSOLE_SIZE - 1,
+ },
+};
+
+static struct ram_console_platform_data ramconsole_pdata;
+
+static struct platform_device ramconsole_device = {
+ .name = "ram_console",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(ramconsole_resources),
+ .resource = ramconsole_resources,
+ .dev = {
+ .platform_data = &ramconsole_pdata,
+ },
+};
+
+extern void __init omap4_panda_android_init(void);
+
+static void __init omap4_panda_init(void)
+{
+ int package = OMAP_PACKAGE_CBS;
+ int status;
+
+ omap_emif_setup_device_details(&emif_devices, &emif_devices);
+
+ if (omap_rev() == OMAP4430_REV_ES1_0)
+ package = OMAP_PACKAGE_CBL;
+ omap4_mux_init(board_mux, NULL, package);
+
+ if (wl12xx_set_platform_data(&omap_panda_wlan_data))
+ pr_err("error setting wl12xx data\n");
+
+ register_reboot_notifier(&panda_reboot_notifier);
+ ramconsole_pdata.bootinfo = omap4_get_resetreason();
+ platform_device_register(&ramconsole_device);
+ omap4_panda_i2c_init();
+ omap4_audio_conf();
+
+ if (cpu_is_omap4430())
+ panda_gpio_keys_buttons[0].gpio = 121;
+
+ platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
+ platform_device_register(&omap_vwlan_device);
+ board_serial_init();
+ omap4_twl6030_hsmmc_init(mmc);
+ omap4_ehci_init();
+ usb_musb_init(&musb_board_data);
+
+ omap_dmm_init();
+ omap_vram_set_sdram_vram(PANDA_FB_RAM_SIZE, 0);
+ omapfb_set_platform_data(&panda_fb_pdata);
+ omap4_panda_display_init();
+
+ if (cpu_is_omap446x()) {
+ /* Vsel0 = gpio, vsel1 = gnd */
+ status = omap_tps6236x_board_setup(true, TPS62361_GPIO, -1,
+ OMAP_PIN_OFF_OUTPUT_HIGH, -1);
+ if (status)
+ pr_err("TPS62361 initialization failed: %d\n", status);
+ }
+ omap_enable_smartreflex_on_init();
+}
+
+static void __init omap4_panda_map_io(void)
+{
+ omap2_set_globals_443x();
+ omap44xx_map_common_io();
+}
+
+static void __init omap4_panda_reserve(void)
+{
+ /* do the static reservations first */
+ memblock_remove(PANDA_RAMCONSOLE_START, PANDA_RAMCONSOLE_SIZE);
+ memblock_remove(PHYS_ADDR_SMC_MEM, PHYS_ADDR_SMC_SIZE);
+ memblock_remove(PHYS_ADDR_DUCATI_MEM, PHYS_ADDR_DUCATI_SIZE);
+ /* ipu needs to recognize secure input buffer area as well */
+ omap_ipu_set_static_mempool(PHYS_ADDR_DUCATI_MEM, PHYS_ADDR_DUCATI_SIZE +
+ OMAP_ION_HEAP_SECURE_INPUT_SIZE);
+
+ omap_reserve();
+}
+
+MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board")
+ /* Maintainer: David Anders - Texas Instruments Inc */
+ .boot_params = 0x80000100,
+ .reserve = omap4_panda_reserve,
+ .map_io = omap4_panda_map_io,
+ .init_early = omap4_panda_init_early,
+ .init_irq = gic_init_irq,
+ .init_machine = omap4_panda_init,
+ .timer = &omap_timer,
+MACHINE_END
diff --git a/kernel/drivers/input/touchscreen/Kconfig b/kernel/drivers/input/touchscreen/Kconfig
new file mode 100644
index 000000000000..18655c0b3997
--- /dev/null
+++ b/kernel/drivers/input/touchscreen/Kconfig
@@ -0,0 +1,721 @@
+#
+# Touchscreen driver configuration
+#
+menuconfig INPUT_TOUCHSCREEN
+ bool "Touchscreens"
+ help
+ Say Y here, and a list of supported touchscreens will be displayed.
+ This option doesn't affect the kernel.
+
+ If unsure, say Y.
+
+if INPUT_TOUCHSCREEN
+
+config TOUCHSCREEN_88PM860X
+ tristate "Marvell 88PM860x touchscreen"
+ depends on MFD_88PM860X
+ help
+ Say Y here if you have a 88PM860x PMIC and want to enable
+ support for the built-in touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called 88pm860x-ts.
+
+config TOUCHSCREEN_ADS7846
+ tristate "ADS7846/TSC2046/AD7873 and AD(S)7843 based touchscreens"
+ depends on SPI_MASTER
+ depends on HWMON = n || HWMON
+ help
+ Say Y here if you have a touchscreen interface using the
+ ADS7846/TSC2046/AD7873 or ADS7843/AD7843 controller,
+ and your board-specific setup code includes that in its
+ table of SPI devices.
+
+ If HWMON is selected, and the driver is told the reference voltage
+ on your board, you will also get hwmon interfaces for the voltage
+ (and on ads7846/tsc2046/ad7873, temperature) sensors of this chip.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called ads7846.
+
+config TOUCHSCREEN_AD7877
+ tristate "AD7877 based touchscreens"
+ depends on SPI_MASTER
+ help
+ Say Y here if you have a touchscreen interface using the
+ AD7877 controller, and your board-specific initialization
+ code includes that in its table of SPI devices.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7877.
+
+config TOUCHSCREEN_AD7879
+ tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface"
+ help
+ Say Y here if you want to support a touchscreen interface using
+ the AD7879-1/AD7889-1 controller.
+
+ You should select a bus connection too.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7879.
+
+config TOUCHSCREEN_AD7879_I2C
+ tristate "support I2C bus connection"
+ depends on TOUCHSCREEN_AD7879 && I2C
+ help
+ Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7879-i2c.
+
+config TOUCHSCREEN_AD7879_SPI
+ tristate "support SPI bus connection"
+ depends on TOUCHSCREEN_AD7879 && SPI_MASTER
+ help
+ Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7879-spi.
+
+config TOUCHSCREEN_BITSY
+ tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
+ depends on SA1100_BITSY
+ select SERIO
+ help
+ Say Y here if you have the h3600 (Bitsy) touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called h3600_ts_input.
+
+config TOUCHSCREEN_BU21013
+ tristate "BU21013 based touch panel controllers"
+ depends on I2C
+ help
+ Say Y here if you have a bu21013 touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bu21013_ts.
+
+config TOUCHSCREEN_CY8CTMG110
+ tristate "cy8ctmg110 touchscreen"
+ depends on I2C
+ depends on GPIOLIB
+
+ help
+ Say Y here if you have a cy8ctmg110 capacitive touchscreen on
+ an AAVA device.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cy8ctmg110_ts.
+
+config TOUCHSCREEN_DA9034
+ tristate "Touchscreen support for Dialog Semiconductor DA9034"
+ depends on PMIC_DA903X
+ default y
+ help
+ Say Y here to enable the support for the touchscreen found
+ on Dialog Semiconductor DA9034 PMIC.
+
+config TOUCHSCREEN_DYNAPRO
+ tristate "Dynapro serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Dynapro serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called dynapro.
+
+config TOUCHSCREEN_HAMPSHIRE
+ tristate "Hampshire serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Hampshire serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hampshire.
+
+config TOUCHSCREEN_EETI
+ tristate "EETI touchscreen panel support"
+ depends on I2C
+ help
+ Say Y here to enable support for I2C connected EETI touch panels.
+
+ To compile this driver as a module, choose M here: the
+ module will be called eeti_ts.
+
+config TOUCHSCREEN_FUJITSU
+ tristate "Fujitsu serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have the Fujitsu touchscreen (such as one
+ installed in Lifebook P series laptop) connected to your
+ system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fujitsu-ts.
+
+config TOUCHSCREEN_S3C2410
+ tristate "Samsung S3C2410/generic touchscreen input driver"
+ depends on ARCH_S3C2410 || SAMSUNG_DEV_TS
+ select S3C_ADC
+ help
+ Say Y here if you have the s3c2410 touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called s3c2410_ts.
+
+config TOUCHSCREEN_GUNZE
+ tristate "Gunze AHL-51S touchscreen"
+ select SERIO
+ help
+ Say Y here if you have the Gunze AHL-51 touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gunze.
+
+config TOUCHSCREEN_ELO
+ tristate "Elo serial touchscreens"
+ select SERIO
+ help
+ Say Y here if you have an Elo serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called elo.
+
+config TOUCHSCREEN_WACOM_W8001
+ tristate "Wacom W8001 penabled serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have an Wacom W8001 penabled serial touchscreen
+ connected to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wacom_w8001.
+
+config TOUCHSCREEN_LPC32XX
+ tristate "LPC32XX touchscreen controller"
+ depends on ARCH_LPC32XX
+ help
+ Say Y here if you have a LPC32XX device and want
+ to support the built-in touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called lpc32xx_ts.
+
+config TOUCHSCREEN_MCS5000
+ tristate "MELFAS MCS-5000 touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have the MELFAS MCS-5000 touchscreen controller
+ chip in your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mcs5000_ts.
+
+config TOUCHSCREEN_MTOUCH
+ tristate "MicroTouch serial touchscreens"
+ select SERIO
+ help
+ Say Y here if you have a MicroTouch (3M) serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mtouch.
+
+config TOUCHSCREEN_INEXIO
+ tristate "iNexio serial touchscreens"
+ select SERIO
+ help
+ Say Y here if you have an iNexio serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called inexio.
+
+config TOUCHSCREEN_INTEL_MID
+ tristate "Intel MID platform resistive touchscreen"
+ depends on INTEL_SCU_IPC
+ help
+ Say Y here if you have a Intel MID based touchscreen in
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called intel_mid_touch.
+
+config TOUCHSCREEN_MK712
+ tristate "ICS MicroClock MK712 touchscreen"
+ help
+ Say Y here if you have the ICS MicroClock MK712 touchscreen
+ controller chip in your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mk712.
+
+config TOUCHSCREEN_HP600
+ tristate "HP Jornada 6xx touchscreen"
+ depends on SH_HP6XX && SH_ADC
+ help
+ Say Y here if you have a HP Jornada 620/660/680/690 and want to
+ support the built-in touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hp680_ts_input.
+
+config TOUCHSCREEN_HP7XX
+ tristate "HP Jornada 7xx touchscreen"
+ depends on SA1100_JORNADA720_SSP
+ help
+ Say Y here if you have a HP Jornada 710/720/728 and want
+ to support the built-in touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jornada720_ts.
+
+config TOUCHSCREEN_HTCPEN
+ tristate "HTC Shift X9500 touchscreen"
+ depends on ISA
+ help
+ Say Y here if you have an HTC Shift UMPC also known as HTC X9500
+ Clio / Shangrila and want to support the built-in touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called htcpen.
+
+config TOUCHSCREEN_PENMOUNT
+ tristate "Penmount serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Penmount serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called penmount.
+
+config TOUCHSCREEN_QT602240
+ tristate "QT602240 I2C Touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have the AT42QT602240/ATMXT224 I2C touchscreen
+ connected to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called qt602240_ts.
+
+config TOUCHSCREEN_MIGOR
+ tristate "Renesas MIGO-R touchscreen"
+ depends on SH_MIGOR && I2C
+ help
+ Say Y here to enable MIGO-R touchscreen support.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called migor_ts.
+
+config TOUCHSCREEN_TNETV107X
+ tristate "TI TNETV107X touchscreen support"
+ depends on ARCH_DAVINCI_TNETV107X
+ help
+ Say Y here if you want to use the TNETV107X touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tnetv107x-ts.
+
+config TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+ tristate "Synaptics DSX I2C touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have a Synaptics DSX I2C touchscreen
+ connected to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called synaptics_i2c_rmi4.
+
+config TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV
+ tristate "Synaptics I2C touchscreen rmi device"
+ depends on TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+ help
+ This enables support for character device channel for Synaptics RMI
+ touchscreens.
+
+config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE
+ tristate "Synaptics I2C touchscreen firmware update"
+ depends on TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+ help
+ This enables support for firmware update for Synaptics RMI
+ touchscreens.
+
+config TOUCHSCREEN_TOUCHRIGHT
+ tristate "Touchright serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Touchright serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called touchright.
+
+config TOUCHSCREEN_TOUCHWIN
+ tristate "Touchwin serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Touchwin serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called touchwin.
+
+config TOUCHSCREEN_ATMEL_TSADCC
+ tristate "Atmel Touchscreen Interface"
+ depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+ help
+ Say Y here if you have a 4-wire touchscreen connected to the
+ ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atmel_tsadcc.
+
+config TOUCHSCREEN_UCB1400
+ tristate "Philips UCB1400 touchscreen"
+ depends on AC97_BUS
+ depends on UCB1400_CORE
+ help
+ This enables support for the Philips UCB1400 touchscreen interface.
+ The UCB1400 is an AC97 audio codec. The touchscreen interface
+ will be initialized only after the ALSA subsystem has been
+ brought up and the UCB1400 detected. You therefore have to
+ configure ALSA support as well (either built-in or modular,
+ independently of whether this driver is itself built-in or
+ modular) for this driver to work.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ucb1400_ts.
+
+config TOUCHSCREEN_WM97XX
+ tristate "Support for WM97xx AC97 touchscreen controllers"
+ depends on AC97_BUS
+ help
+ Say Y here if you have a Wolfson Microelectronics WM97xx
+ touchscreen connected to your system. Note that this option
+ only enables core driver, you will also need to select
+ support for appropriate chip below.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wm97xx-ts.
+
+config TOUCHSCREEN_WM9705
+ bool "WM9705 Touchscreen interface support"
+ depends on TOUCHSCREEN_WM97XX
+ default y
+ help
+ Say Y here to enable support for the Wolfson Microelectronics
+ WM9705 touchscreen controller.
+
+config TOUCHSCREEN_WM9712
+ bool "WM9712 Touchscreen interface support"
+ depends on TOUCHSCREEN_WM97XX
+ default y
+ help
+ Say Y here to enable support for the Wolfson Microelectronics
+ WM9712 touchscreen controller.
+
+config TOUCHSCREEN_WM9713
+ bool "WM9713 Touchscreen interface support"
+ depends on TOUCHSCREEN_WM97XX
+ default y
+ help
+ Say Y here to enable support for the Wolfson Microelectronics
+ WM9713 touchscreen controller.
+
+config TOUCHSCREEN_WM97XX_ATMEL
+ tristate "WM97xx Atmel accelerated touch"
+ depends on TOUCHSCREEN_WM97XX && (AVR32 || ARCH_AT91)
+ help
+ Say Y here for support for streaming mode with WM97xx touchscreens
+ on Atmel AT91 or AVR32 systems with an AC97C module.
+
+ Be aware that this will use channel B in the controller for
+ streaming data, this must not conflict with other AC97C drivers.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module will
+ be called atmel-wm97xx.
+
+config TOUCHSCREEN_WM97XX_MAINSTONE
+ tristate "WM97xx Mainstone/Palm accelerated touch"
+ depends on TOUCHSCREEN_WM97XX && ARCH_PXA
+ help
+ Say Y here for support for streaming mode with WM97xx touchscreens
+ on Mainstone, Palm Tungsten T5, TX and LifeDrive systems.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mainstone-wm97xx.
+
+config TOUCHSCREEN_WM97XX_ZYLONITE
+ tristate "Zylonite accelerated touch"
+ depends on TOUCHSCREEN_WM97XX && MACH_ZYLONITE
+ select TOUCHSCREEN_WM9713
+ help
+ Say Y here for support for streaming mode with the touchscreen
+ on Zylonite systems.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called zylonite-wm97xx.
+
+config TOUCHSCREEN_USB_COMPOSITE
+ tristate "USB Touchscreen Driver"
+ depends on USB_ARCH_HAS_HCD
+ select USB
+ help
+ USB Touchscreen driver for:
+ - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
+ - PanJit TouchSet USB
+ - 3M MicroTouch USB (EX II series)
+ - ITM
+ - some other eTurboTouch
+ - Gunze AHL61
+ - DMC TSC-10/25
+ - IRTOUCHSYSTEMS/UNITOP
+ - IdealTEK URTC1000
+ - GoTop Super_Q2/GogoPen/PenPower tablets
+ - JASTEC USB Touch Controller/DigiTech DTR-02U
+ - Zytronic controllers
+
+ Have a look at <http://linux.chapter7.ch/touchkit/> for
+ a usage description and the required user-space stuff.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbtouchscreen.
+
+config TOUCHSCREEN_MC13783
+ tristate "Freescale MC13783 touchscreen input driver"
+ depends on MFD_MC13783
+ help
+ Say Y here if you have an Freescale MC13783 PMIC on your
+ board and want to use its touchscreen
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mc13783_ts.
+
+config TOUCHSCREEN_USB_EGALAX
+ default y
+ bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_PANJIT
+ default y
+ bool "PanJit device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_3M
+ default y
+ bool "3M/Microtouch EX II series device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ITM
+ default y
+ bool "ITM device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ETURBO
+ default y
+ bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GUNZE
+ default y
+ bool "Gunze AHL61 device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_DMC_TSC10
+ default y
+ bool "DMC TSC-10/25 device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_IRTOUCH
+ default y
+ bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_IDEALTEK
+ default y
+ bool "IdealTEK URTC1000 device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GENERAL_TOUCH
+ default y
+ bool "GeneralTouch Touchscreen device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GOTOP
+ default y
+ bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_JASTEC
+ default y
+ bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_E2I
+ default y
+ bool "e2i Touchscreen controller (e.g. from Mimo 740)"
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ZYTRONIC
+ default y
+ bool "Zytronic controller" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ETT_TC45USB
+ default y
+ bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_NEXIO
+ default y
+ bool "NEXIO/iNexio device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_TOUCHIT213
+ tristate "Sahara TouchIT-213 touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Sahara TouchIT-213 Tablet PC.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called touchit213.
+
+config TOUCHSCREEN_TSC2007
+ tristate "TSC2007 based touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a TSC2007 based touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tsc2007.
+
+config TOUCHSCREEN_TSC2004
+ tristate "TSC2004 based touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a TSC2004 based touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tsc2004.
+
+config TOUCHSCREEN_W90X900
+ tristate "W90P910 touchscreen driver"
+ depends on HAVE_CLK
+ help
+ Say Y here if you have a W90P910 based touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called w90p910_ts.
+
+config TOUCHSCREEN_PCAP
+ tristate "Motorola PCAP touchscreen"
+ depends on EZX_PCAP
+ help
+ Say Y here if you have a Motorola EZX telephone and
+ want to enable support for the built-in touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pcap_ts.
+
+config TOUCHSCREEN_TPS6507X
+ tristate "TPS6507x based touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a TPS6507x based touchscreen
+ controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tps6507x_ts.
+
+config TOUCHSCREEN_STMPE
+ tristate "STMicroelectronics STMPE touchscreens"
+ depends on MFD_STMPE
+ help
+ Say Y here if you want support for STMicroelectronics
+ STMPE touchscreen controllers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called stmpe-ts.
+
+endif
diff --git a/kernel/drivers/input/touchscreen/Makefile b/kernel/drivers/input/touchscreen/Makefile
new file mode 100644
index 000000000000..a6c7d9f388a6
--- /dev/null
+++ b/kernel/drivers/input/touchscreen/Makefile
@@ -0,0 +1,68 @@
+#
+# Makefile for the touchscreen drivers.
+#
+
+# Each configuration option enables a list of files.
+
+wm97xx-ts-y := wm97xx-core.o
+
+obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
+obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
+obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
+obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
+obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
+obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
+obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
+obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
+obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
+obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
+obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
+obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
+obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
+obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
+obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
+obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
+obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
+obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
+obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o
+obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
+obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV) += synaptics_rmi_dev.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_fw_update.o
+obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
+obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
+obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o
+obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
+obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
+obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
+wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
+wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
+wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
+obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
+obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
+obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
+obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
+
+all:
+make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
+
+clean:
+make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
diff --git a/kernel/drivers/input/touchscreen/msg21xx/msg21xx_ts.c b/kernel/drivers/input/touchscreen/msg21xx/msg21xx_ts.c
new file mode 100644
index 000000000000..4eb7fd4b1cc9
--- /dev/null
+++ b/kernel/drivers/input/touchscreen/msg21xx/msg21xx_ts.c
@@ -0,0 +1,1757 @@
+/*
+ * MStar MSG21XX touchscreen driver
+ *
+ * Copyright (c) 2006-2012 MStar Semiconductor, Inc.
+ *
+ * Copyright (C) 2012 Bruce Ding <bruce.ding@mstarsemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/gpio.h>
+
+#include <linux/sysfs.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <mach/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <linux/syscalls.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <asm/unistd.h>
+#include <linux/cdev.h>
+#include <asm/uaccess.h>
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/input.h>
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#endif
+#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR
+#include <linux/input/vir_ps.h>
+#endif
+
+/*=============================================================*/
+// Macro Definition
+/*=============================================================*/
+
+#define TOUCH_DRIVER_DEBUG 0
+#if (TOUCH_DRIVER_DEBUG == 1)
+#define DBG(fmt, arg...) pr_err(fmt, ##arg) //pr_info(fmt, ##arg)
+#else
+#define DBG(fmt, arg...)
+#endif
+
+/*=============================================================*/
+// Constant Value & Variable Definition
+/*=============================================================*/
+
+#define U8 unsigned char
+#define U16 unsigned short
+#define U32 unsigned int
+#define S8 signed char
+#define S16 signed short
+#define S32 signed int
+
+#define TOUCH_SCREEN_X_MIN (0)
+#define TOUCH_SCREEN_Y_MIN (0)
+/*
+ * Note.
+ * Please change the below touch screen resolution according to the touch panel that you are using.
+ */
+#define TOUCH_SCREEN_X_MAX (480)
+#define TOUCH_SCREEN_Y_MAX (800)
+/*
+ * Note.
+ * Please do not change the below setting.
+ */
+#define TPD_WIDTH (2048)
+#define TPD_HEIGHT (2048)
+
+/*
+ * Note.
+ * Please change the below GPIO pin setting to follow the platform that you are using
+ */
+static int int_gpio = 1;
+static int reset_gpio = 0;
+#define MS_TS_MSG21XX_GPIO_RST reset_gpio
+#define MS_TS_MSG21XX_GPIO_INT int_gpio
+//---------------------------------------------------------------------//
+
+//#define SYSFS_AUTHORITY_CHANGE_FOR_CTS_TEST
+
+#ifdef SYSFS_AUTHORITY_CHANGE_FOR_CTS_TEST
+#define SYSFS_AUTHORITY (0644)
+#else
+#define SYSFS_AUTHORITY (0777)
+#endif
+
+#define FIRMWARE_AUTOUPDATE
+#ifdef FIRMWARE_AUTOUPDATE
+typedef enum {
+ SWID_START = 1,
+ SWID_TRULY = SWID_START,
+ SWID_NULL,
+} SWID_ENUM;
+
+unsigned char MSG_FIRMWARE[1][33*1024] =
+{
+ {
+ #include "msg21xx_truly_update_bin.h"
+ }
+};
+#endif
+
+#define CONFIG_TP_HAVE_KEY
+
+/*
+ * Note.
+ * If the below virtual key value definition are not consistent with those that defined in key layout file of platform,
+ * please change the below virtual key value to follow the platform that you are using.
+ */
+#ifdef CONFIG_TP_HAVE_KEY
+#define TOUCH_KEY_MENU (139) //229
+#define TOUCH_KEY_HOME (172) //102
+#define TOUCH_KEY_BACK (158)
+#define TOUCH_KEY_SEARCH (217)
+
+const U16 tp_key_array[] = {TOUCH_KEY_MENU, TOUCH_KEY_HOME, TOUCH_KEY_BACK, TOUCH_KEY_SEARCH};
+#define MAX_KEY_NUM (sizeof(tp_key_array)/sizeof(tp_key_array[0]))
+#endif
+
+#define SLAVE_I2C_ID_DBBUS (0xC4>>1)
+#define SLAVE_I2C_ID_DWI2C (0x4C>>1)
+
+#define DEMO_MODE_PACKET_LENGTH (8)
+#define MAX_TOUCH_NUM (2) //5
+
+#define TP_PRINT
+#ifdef TP_PRINT
+static int tp_print_proc_read(void);
+static void tp_print_create_entry(void);
+#endif
+
+static char *fw_version = NULL; // customer firmware version
+static U16 fw_version_major = 0;
+static U16 fw_version_minor = 0;
+static U8 temp[94][1024];
+static U32 crc32_table[256];
+static int FwDataCnt = 0;
+static U8 bFwUpdating = 0;
+static struct class *firmware_class = NULL;
+static struct device *firmware_cmd_dev = NULL;
+
+static struct i2c_client *i2c_client = NULL;
+
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data);
+static struct notifier_block msg21xx_fb_notif;
+#elif defined (CONFIG_HAS_EARLYSUSPEND)
+static struct early_suspend mstar_ts_early_suspend;
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR
+static U8 bEnableTpProximity = 0;
+static U8 bFaceClosingTp = 0;
+#endif
+static U8 bTpInSuspend = 0;
+
+static int irq_msg21xx = -1;
+static struct work_struct msg21xx_wk;
+static struct mutex msg21xx_mutex;
+static struct input_dev *input_dev = NULL;
+
+/*=============================================================*/
+// Data Type Definition
+/*=============================================================*/
+
+typedef struct
+{
+ U16 x;
+ U16 y;
+} touchPoint_t;
+
+/// max 80+1+1 = 82 bytes
+typedef struct
+{
+ touchPoint_t point[MAX_TOUCH_NUM];
+ U8 count;
+ U8 keycode;
+} touchInfo_t;
+
+enum i2c_speed
+{
+ I2C_SLOW = 0,
+ I2C_NORMAL = 1, /* Enable erasing/writing for 10 msec. */
+ I2C_FAST = 2, /* Disable EWENB before 10 msec timeout. */
+};
+
+typedef enum
+{
+ EMEM_ALL = 0,
+ EMEM_MAIN,
+ EMEM_INFO,
+} EMEM_TYPE_t;
+
+/*=============================================================*/
+// Function Definition
+/*=============================================================*/
+
+/// CRC
+static U32 _CRC_doReflect(U32 ref, S8 ch)
+{
+ U32 value = 0;
+ U32 i = 0;
+
+ for (i = 1; i < (ch + 1); i ++)
+ {
+ if (ref & 1)
+ {
+ value |= 1 << (ch - i);
+ }
+ ref >>= 1;
+ }
+
+ return value;
+}
+
+U32 _CRC_getValue(U32 text, U32 prevCRC)
+{
+ U32 ulCRC = prevCRC;
+
+ ulCRC = (ulCRC >> 8) ^ crc32_table[(ulCRC & 0xFF) ^ text];
+
+ return ulCRC;
+}
+
+static void _CRC_initTable(void)
+{
+ U32 magic_number = 0x04c11db7;
+ U32 i, j;
+
+ for (i = 0; i <= 0xFF; i ++)
+ {
+ crc32_table[i] = _CRC_doReflect (i, 8) << 24;
+ for (j = 0; j < 8; j ++)
+ {
+ crc32_table[i] = (crc32_table[i] << 1) ^ (crc32_table[i] & (0x80000000L) ? magic_number : 0);
+ }
+ crc32_table[i] = _CRC_doReflect(crc32_table[i], 32);
+ }
+}
+
+static void reset_hw(void)
+{
+ DBG("reset_hw()\n");
+
+ gpio_direction_output(MS_TS_MSG21XX_GPIO_RST, 1);
+ gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0);
+ mdelay(100); /* Note that the RST must be in LOW 10ms at least */
+ gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 1);
+ mdelay(100); /* Enable the interrupt service thread/routine for INT after 50ms */
+}
+
+static int read_i2c_seq(U8 addr, U8* buf, U16 size)
+{
+ int rc = 0;
+ struct i2c_msg msgs[] =
+ {
+ {
+ .addr = addr,
+ .flags = I2C_M_RD, // read flag
+ .len = size,
+ .buf = buf,
+ },
+ };
+
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ if (i2c_client != NULL)
+ {
+ rc = i2c_transfer(i2c_client->adapter, msgs, 1);
+ if (rc < 0)
+ {
+ DBG("read_i2c_seq() error %d\n", rc);
+ }
+ }
+ else
+ {
+ DBG("i2c_client is NULL\n");
+ }
+
+ return rc;
+}
+
+static int write_i2c_seq(U8 addr, U8* buf, U16 size)
+{
+ int rc = 0;
+ struct i2c_msg msgs[] =
+ {
+ {
+ .addr = addr,
+ .flags = 0, // if read flag is undefined, then it means write flag.
+ .len = size,
+ .buf = buf,
+ },
+ };
+
+ /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+ transmitted, else error code. */
+ if (i2c_client != NULL)
+ {
+ rc = i2c_transfer(i2c_client->adapter, msgs, 1);
+ if ( rc < 0 )
+ {
+ DBG("write_i2c_seq() error %d\n", rc);
+ }
+ }
+ else
+ {
+ DBG("i2c_client is NULL\n");
+ }
+
+ return rc;
+}
+
+static U16 read_reg(U8 bank, U8 addr)
+{
+ U8 tx_data[3] = {0x10, bank, addr};
+ U8 rx_data[2] = {0};
+
+ write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 3);
+ read_i2c_seq(SLAVE_I2C_ID_DBBUS, &rx_data[0], 2);
+
+ return (rx_data[1] << 8 | rx_data[0]);
+}
+
+static void write_reg(U8 bank, U8 addr, U16 data)
+{
+ U8 tx_data[5] = {0x10, bank, addr, data & 0xFF, data >> 8};
+ write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 5);
+}
+
+static void write_reg_8bit(U8 bank, U8 addr, U8 data)
+{
+ U8 tx_data[4] = {0x10, bank, addr, data};
+ write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 4);
+}
+
+void dbbusDWIICEnterSerialDebugMode(void)
+{
+ U8 data[5];
+
+ // Enter the Serial Debug Mode
+ data[0] = 0x53;
+ data[1] = 0x45;
+ data[2] = 0x52;
+ data[3] = 0x44;
+ data[4] = 0x42;
+
+ write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 5);
+}
+
+void dbbusDWIICStopMCU(void)
+{
+ U8 data[1];
+
+ // Stop the MCU
+ data[0] = 0x37;
+
+ write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1);
+}
+
+void dbbusDWIICIICUseBus(void)
+{
+ U8 data[1];
+
+ // IIC Use Bus
+ data[0] = 0x35;
+
+ write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1);
+}
+
+void dbbusDWIICIICReshape(void)
+{
+ U8 data[1];
+
+ // IIC Re-shape
+ data[0] = 0x71;
+
+ write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1);
+}
+
+void dbbusDWIICIICNotUseBus(void)
+{
+ U8 data[1];
+
+ // IIC Not Use Bus
+ data[0] = 0x34;
+
+ write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1);
+}
+
+void dbbusDWIICNotStopMCU(void)
+{
+ U8 data[1];
+
+ // Not Stop the MCU
+ data[0] = 0x36;
+
+ write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1);
+}
+
+void dbbusDWIICExitSerialDebugMode(void)
+{
+ U8 data[1];
+
+ // Exit the Serial Debug Mode
+ data[0] = 0x45;
+
+ write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1);
+
+ // Delay some interval to guard the next transaction
+ //udelay ( 200 ); // delay about 0.2ms
+}
+
+//---------------------------------------------------------------------//
+
+static U8 get_ic_type(void)
+{
+ U8 ic_type = 0;
+
+ reset_hw();
+ dbbusDWIICEnterSerialDebugMode();
+ dbbusDWIICStopMCU();
+ dbbusDWIICIICUseBus();
+ dbbusDWIICIICReshape();
+ mdelay ( 300 );
+
+ // stop mcu
+ write_reg_8bit ( 0x0F, 0xE6, 0x01 );
+ // disable watch dog
+ write_reg ( 0x3C, 0x60, 0xAA55 );
+ // get ic type
+ ic_type = (0xff)&(read_reg(0x1E, 0xCC));
+
+ if (ic_type != 1 //msg2133
+ && ic_type != 2 //msg21xxA
+ && ic_type != 3) //msg26xxM
+ {
+ ic_type = 0;
+ }
+
+ reset_hw();
+
+ return ic_type;
+}
+
+static int get_customer_firmware_version(void)
+{
+ U8 dbbus_tx_data[3] = {0};
+ U8 dbbus_rx_data[4] = {0};
+ int ret = 0;
+
+ DBG("get_customer_firmware_version()\n");
+
+ dbbus_tx_data[0] = 0x53;
+ dbbus_tx_data[1] = 0x00;
+ dbbus_tx_data[2] = 0x2A;
+ mutex_lock(&msg21xx_mutex);
+ write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 3);
+ read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 4);
+ mutex_unlock(&msg21xx_mutex);
+ fw_version_major = (dbbus_rx_data[1]<<8) + dbbus_rx_data[0];
+ fw_version_minor = (dbbus_rx_data[3]<<8) + dbbus_rx_data[2];
+
+ DBG("*** major = %d ***\n", fw_version_major);
+ DBG("*** minor = %d ***\n", fw_version_minor);
+
+ if (fw_version == NULL)
+ {
+ fw_version = kzalloc(sizeof(char), GFP_KERNEL);
+ }
+
+ sprintf(fw_version, "%03d%03d", fw_version_major, fw_version_minor);
+
+ return ret;
+}
+
+static int firmware_erase_c33 ( EMEM_TYPE_t emem_type )
+{
+ // stop mcu
+ write_reg ( 0x0F, 0xE6, 0x0001 );
+
+ //disable watch dog
+ write_reg_8bit ( 0x3C, 0x60, 0x55 );
+ write_reg_8bit ( 0x3C, 0x61, 0xAA );
+
+ // set PROGRAM password
+ write_reg_8bit ( 0x16, 0x1A, 0xBA );
+ write_reg_8bit ( 0x16, 0x1B, 0xAB );
+
+ write_reg_8bit ( 0x16, 0x18, 0x80 );
+
+ if ( emem_type == EMEM_ALL )
+ {
+ write_reg_8bit ( 0x16, 0x08, 0x10 ); //mark
+ }
+
+ write_reg_8bit ( 0x16, 0x18, 0x40 );
+ mdelay ( 10 );
+
+ // clear pce
+ write_reg_8bit ( 0x16, 0x18, 0x80 );
+
+ // erase trigger
+ if ( emem_type == EMEM_MAIN )
+ {
+ write_reg_8bit ( 0x16, 0x0E, 0x04 ); //erase main
+ }
+ else
+ {
+ write_reg_8bit ( 0x16, 0x0E, 0x08 ); //erase all block
+ }
+
+ return ( 1 );
+}
+
+static ssize_t firmware_update_c33 ( struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size, EMEM_TYPE_t emem_type )
+{
+ U32 i, j;
+ U32 crc_main, crc_main_tp;
+ U32 crc_info, crc_info_tp;
+ U16 reg_data = 0;
+ int update_pass = 1;
+
+ crc_main = 0xffffffff;
+ crc_info = 0xffffffff;
+
+ reset_hw();
+ dbbusDWIICEnterSerialDebugMode();
+ dbbusDWIICStopMCU();
+ dbbusDWIICIICUseBus();
+ dbbusDWIICIICReshape();
+ mdelay ( 300 );
+
+ //erase main
+ firmware_erase_c33 ( EMEM_MAIN );
+ mdelay ( 1000 );
+
+ reset_hw();
+ dbbusDWIICEnterSerialDebugMode();
+ dbbusDWIICStopMCU();
+ dbbusDWIICIICUseBus();
+ dbbusDWIICIICReshape();
+ mdelay ( 300 );
+
+ /////////////////////////
+ // Program
+ /////////////////////////
+
+ //polling 0x3CE4 is 0x1C70
+ if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) )
+ {
+ do
+ {
+ reg_data = read_reg ( 0x3C, 0xE4 );
+ }
+ while ( reg_data != 0x1C70 );
+ }
+
+ switch ( emem_type )
+ {
+ case EMEM_ALL:
+ write_reg ( 0x3C, 0xE4, 0xE38F ); // for all-blocks
+ break;
+ case EMEM_MAIN:
+ write_reg ( 0x3C, 0xE4, 0x7731 ); // for main block
+ break;
+ case EMEM_INFO:
+ write_reg ( 0x3C, 0xE4, 0x7731 ); // for info block
+
+ write_reg_8bit ( 0x0F, 0xE6, 0x01 );
+
+ write_reg_8bit ( 0x3C, 0xE4, 0xC5 );
+ write_reg_8bit ( 0x3C, 0xE5, 0x78 );
+
+ write_reg_8bit ( 0x1E, 0x04, 0x9F );
+ write_reg_8bit ( 0x1E, 0x05, 0x82 );
+
+ write_reg_8bit ( 0x0F, 0xE6, 0x00 );
+ mdelay ( 100 );
+ break;
+ }
+
+ // polling 0x3CE4 is 0x2F43
+ do
+ {
+ reg_data = read_reg ( 0x3C, 0xE4 );
+ }
+ while ( reg_data != 0x2F43 );
+
+ // calculate CRC 32
+ _CRC_initTable ();
+
+ for ( i = 0; i < 32; i++ ) // total 32 KB : 2 byte per R/W
+ {
+ if ( i == 31 )
+ {
+ temp[i][1014] = 0x5A;
+ temp[i][1015] = 0xA5;
+
+ for ( j = 0; j < 1016; j++ )
+ {
+ crc_main = _CRC_getValue ( temp[i][j], crc_main);
+ }
+ }
+ else
+ {
+ for ( j = 0; j < 1024; j++ )
+ {
+ crc_main = _CRC_getValue ( temp[i][j], crc_main);
+ }
+ }
+
+ //write_i2c_seq(SLAVE_I2C_ID_DWI2C, temp[i], 1024);
+ for (j = 0; j < 8; j++)
+ {
+ write_i2c_seq(SLAVE_I2C_ID_DWI2C, &temp[i][j*128], 128 );
+ }
+ msleep (100);
+
+ // polling 0x3CE4 is 0xD0BC
+ do
+ {
+ reg_data = read_reg ( 0x3C, 0xE4 );
+ }
+ while ( reg_data != 0xD0BC );
+
+ write_reg ( 0x3C, 0xE4, 0x2F43 );
+ }
+
+ if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) )
+ {
+ // write file done and check crc
+ write_reg ( 0x3C, 0xE4, 0x1380 );
+ }
+ mdelay ( 10 );
+
+ if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) )
+ {
+ // polling 0x3CE4 is 0x9432
+ do
+ {
+ reg_data = read_reg ( 0x3C, 0xE4 );
+ }while ( reg_data != 0x9432 );
+ }
+
+ crc_main = crc_main ^ 0xffffffff;
+ crc_info = crc_info ^ 0xffffffff;
+
+ if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) )
+ {
+ // CRC Main from TP
+ crc_main_tp = read_reg ( 0x3C, 0x80 );
+ crc_main_tp = ( crc_main_tp << 16 ) | read_reg ( 0x3C, 0x82 );
+
+ // CRC Info from TP
+ crc_info_tp = read_reg ( 0x3C, 0xA0 );
+ crc_info_tp = ( crc_info_tp << 16 ) | read_reg ( 0x3C, 0xA2 );
+ }
+
+ update_pass = 1;
+ if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) )
+ {
+ if ( crc_main_tp != crc_main )
+ update_pass = 0;
+
+ /*
+ if ( crc_info_tp != crc_info )
+ update_pass = 0;
+ */
+ }
+
+ if ( !update_pass )
+ {
+ DBG( "update_C33 failed\n" );
+ reset_hw();
+ FwDataCnt = 0;
+ return 0;
+ }
+
+ DBG( "update_C33 OK\n" );
+ reset_hw();
+ FwDataCnt = 0;
+ return size;
+}
+
+#ifdef FIRMWARE_AUTOUPDATE
+unsigned short main_sw_id = 0x7FF, info_sw_id = 0x7FF;
+U32 bin_conf_crc32 = 0;
+
+static U32 _CalMainCRC32(void)
+{
+ U32 ret=0;
+ U16 reg_data=0;
+
+ reset_hw();
+
+ dbbusDWIICEnterSerialDebugMode();
+ dbbusDWIICStopMCU();
+ dbbusDWIICIICUseBus();
+ dbbusDWIICIICReshape();
+ msleep ( 100 );
+
+ //Stop MCU
+ write_reg ( 0x0F, 0xE6, 0x0001 );
+
+ // Stop Watchdog
+ write_reg_8bit ( 0x3C, 0x60, 0x55 );
+ write_reg_8bit ( 0x3C, 0x61, 0xAA );
+
+ //cmd
+ write_reg ( 0x3C, 0xE4, 0xDF4C );
+ write_reg ( 0x1E, 0x04, 0x7d60 );
+ // TP SW reset
+ write_reg ( 0x1E, 0x04, 0x829F );
+
+ //MCU run
+ write_reg ( 0x0F, 0xE6, 0x0000 );
+
+ //polling 0x3CE4
+ do
+ {
+ reg_data = read_reg ( 0x3C, 0xE4 );
+ }while ( reg_data != 0x9432 );
+
+ // Cal CRC Main from TP
+ ret = read_reg ( 0x3C, 0x80 );
+ ret = ( ret << 16 ) | read_reg ( 0x3C, 0x82 );
+
+ DBG("[21xxA]:Current main crc32=0x%x\n",ret);
+ return (ret);
+}
+
+static void _ReadBinConfig ( void )
+{
+ U8 dbbus_tx_data[5]={0};
+ U8 dbbus_rx_data[4]={0};
+ U16 reg_data=0;
+
+ reset_hw();
+
+ dbbusDWIICEnterSerialDebugMode();
+ dbbusDWIICStopMCU();
+ dbbusDWIICIICUseBus();
+ dbbusDWIICIICReshape();
+ msleep ( 100 );
+
+ //Stop MCU
+ write_reg ( 0x0F, 0xE6, 0x0001 );
+
+ // Stop Watchdog
+ write_reg_8bit ( 0x3C, 0x60, 0x55 );
+ write_reg_8bit ( 0x3C, 0x61, 0xAA );
+
+ //cmd
+ write_reg ( 0x3C, 0xE4, 0xA4AB );
+ write_reg ( 0x1E, 0x04, 0x7d60 );
+
+ // TP SW reset
+ write_reg ( 0x1E, 0x04, 0x829F );
+
+ //MCU run
+ write_reg ( 0x0F, 0xE6, 0x0000 );
+
+ //polling 0x3CE4
+ do
+ {
+ reg_data = read_reg ( 0x3C, 0xE4 );
+ }
+ while ( reg_data != 0x5B58 );
+
+ dbbus_tx_data[0] = 0x72;
+ dbbus_tx_data[1] = 0x7F;
+ dbbus_tx_data[2] = 0x55;
+ dbbus_tx_data[3] = 0x00;
+ dbbus_tx_data[4] = 0x04;
+ write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 5 );
+ read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 4 );
+ if ((dbbus_rx_data[0]>=0x30 && dbbus_rx_data[0]<=0x39)
+ &&(dbbus_rx_data[1]>=0x30 && dbbus_rx_data[1]<=0x39)
+ &&(dbbus_rx_data[2]>=0x31 && dbbus_rx_data[2]<=0x39))
+ {
+ main_sw_id = (dbbus_rx_data[0]-0x30)*100+(dbbus_rx_data[1]-0x30)*10+(dbbus_rx_data[2]-0x30);
+ }
+
+ dbbus_tx_data[0] = 0x72;
+ dbbus_tx_data[1] = 0x7F;
+ dbbus_tx_data[2] = 0xFC;
+ dbbus_tx_data[3] = 0x00;
+ dbbus_tx_data[4] = 0x04;
+ write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 5 );
+ read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 4 );
+ bin_conf_crc32 = dbbus_rx_data[0];
+ bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[1];
+ bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[2];
+ bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[3];
+
+ dbbus_tx_data[0] = 0x72;
+ dbbus_tx_data[1] = 0x83;
+ dbbus_tx_data[2] = 0x00;
+ dbbus_tx_data[3] = 0x00;
+ dbbus_tx_data[4] = 0x04;
+ write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 5 );
+ read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 4 );
+ if ((dbbus_rx_data[0]>=0x30 && dbbus_rx_data[0]<=0x39)
+ &&(dbbus_rx_data[1]>=0x30 && dbbus_rx_data[1]<=0x39)
+ &&(dbbus_rx_data[2]>=0x31 && dbbus_rx_data[2]<=0x39))
+ {
+ info_sw_id = (dbbus_rx_data[0]-0x30)*100+(dbbus_rx_data[1]-0x30)*10+(dbbus_rx_data[2]-0x30);
+ }
+
+ DBG("[21xxA]:main_sw_id = %d, info_sw_id = %d, bin_conf_crc32=0x%x\n", main_sw_id, info_sw_id, bin_conf_crc32);
+}
+
+static int fwAutoUpdate(void *unused)
+{
+ int time = 0;
+ ssize_t ret = 0;
+
+ for (time = 0; time < 5; time++)
+ {
+ DBG("fwAutoUpdate time = %d\n",time);
+ ret = firmware_update_c33(NULL, NULL, NULL, 1, EMEM_MAIN);
+ if (ret == 1)
+ {
+ DBG("AUTO_UPDATE OK!!!");
+ break;
+ }
+ }
+ if (time == 5)
+ {
+ DBG("AUTO_UPDATE failed!!!");
+ }
+ enable_irq(irq_msg21xx);
+ return 0;
+}
+#endif
+
+//------------------------------------------------------------------------------//
+static ssize_t firmware_update_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ DBG("*** firmware_update_show() fw_version = %s ***\n", fw_version);
+
+ return sprintf(buf, "%s\n", fw_version);
+}
+
+static ssize_t firmware_update_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ bFwUpdating = 1;
+ disable_irq(irq_msg21xx);
+
+ DBG("*** update fw size = %d ***\n", FwDataCnt);
+ size = firmware_update_c33 (dev, attr, buf, size, EMEM_MAIN);
+
+ enable_irq(irq_msg21xx);
+ bFwUpdating = 0;
+
+ return size;
+}
+
+static DEVICE_ATTR(update, SYSFS_AUTHORITY, firmware_update_show, firmware_update_store);
+
+static ssize_t firmware_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ DBG("*** firmware_version_show() fw_version = %s ***\n", fw_version);
+
+ return sprintf(buf, "%s\n", fw_version);
+}
+
+static ssize_t firmware_version_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ get_customer_firmware_version();
+
+ DBG("*** firmware_version_store() fw_version = %s ***\n", fw_version);
+
+ return size;
+}
+
+static DEVICE_ATTR(version, SYSFS_AUTHORITY, firmware_version_show, firmware_version_store);
+
+static ssize_t firmware_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ DBG("*** firmware_data_show() FwDataCnt = %d ***\n", FwDataCnt);
+
+ return FwDataCnt;
+}
+
+static ssize_t firmware_data_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ int count = size / 1024;
+ int i;
+
+ for (i = 0; i < count; i ++)
+ {
+ memcpy(temp[FwDataCnt], buf+(i*1024), 1024);
+
+ FwDataCnt ++;
+ }
+
+ DBG("***FwDataCnt = %d ***\n", FwDataCnt);
+
+ if (buf != NULL)
+ {
+ DBG("*** buf[0] = %c ***\n", buf[0]);
+ }
+
+ return size;
+}
+
+static DEVICE_ATTR(data, SYSFS_AUTHORITY, firmware_data_show, firmware_data_store);
+
+#ifdef TP_PRINT
+static ssize_t tp_print_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ tp_print_proc_read();
+
+ return sprintf(buf, "%d\n", bTpInSuspend);
+}
+
+static ssize_t tp_print_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ DBG("*** tp_print_store() ***\n");
+
+ return size;
+}
+
+static DEVICE_ATTR(tpp, SYSFS_AUTHORITY, tp_print_show, tp_print_store);
+#endif
+
+//------------------------------------------------------------------------------//
+#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR
+static void _msg_enable_proximity(void)
+{
+ U8 tx_data[4] = {0};
+
+ DBG("_msg_enable_proximity!");
+ tx_data[0] = 0x52;
+ tx_data[1] = 0x00;
+ tx_data[2] = 0x47;
+ tx_data[3] = 0xa0;
+ mutex_lock(&msg21xx_mutex);
+ write_i2c_seq(SLAVE_I2C_ID_DWI2C, &tx_data[0], 4);
+ mutex_unlock(&msg21xx_mutex);
+
+ bEnableTpProximity = 1;
+}
+
+static void _msg_disable_proximity(void)
+{
+ U8 tx_data[4] = {0};
+
+ DBG("_msg_disable_proximity!");
+ tx_data[0] = 0x52;
+ tx_data[1] = 0x00;
+ tx_data[2] = 0x47;
+ tx_data[3] = 0xa1;
+ mutex_lock(&msg21xx_mutex);
+ write_i2c_seq(SLAVE_I2C_ID_DWI2C, &tx_data[0], 4);
+ mutex_unlock(&msg21xx_mutex);
+
+ bEnableTpProximity = 0;
+ bFaceClosingTp = 0;
+}
+
+void tsps_msg21xx_enable(int en)
+{
+ if (en)
+ {
+ _msg_enable_proximity();
+ }
+ else
+ {
+ _msg_disable_proximity();
+ }
+}
+
+int tsps_msg21xx_data(void)
+{
+ return bFaceClosingTp;
+}
+#endif
+
+static U8 calculate_checksum(U8 *msg, S32 length)
+{
+ S32 Checksum = 0;
+ S32 i;
+
+ for (i = 0; i < length; i ++)
+ {
+ Checksum += msg[i];
+ }
+
+ return (U8)((-Checksum) & 0xFF);
+}
+
+static S32 parse_info(touchInfo_t *info)
+{
+ U8 data[DEMO_MODE_PACKET_LENGTH] = {0};
+ U8 checksum = 0;
+ U32 x = 0, y = 0;
+ U32 x2 = 0, y2 = 0;
+ U32 delta_x = 0, delta_y = 0;
+
+ mutex_lock(&msg21xx_mutex);
+ read_i2c_seq(SLAVE_I2C_ID_DWI2C, &data[0], DEMO_MODE_PACKET_LENGTH);
+ mutex_unlock(&msg21xx_mutex);
+ checksum = calculate_checksum(&data[0], (DEMO_MODE_PACKET_LENGTH-1));
+ DBG("check sum: [%x] == [%x]? \n", data[DEMO_MODE_PACKET_LENGTH-1], checksum);
+
+ if(data[DEMO_MODE_PACKET_LENGTH-1] != checksum)
+ {
+ DBG("WRONG CHECKSUM\n");
+ return -1;
+ }
+
+ if(data[0] != 0x52)
+ {
+ DBG("WRONG HEADER\n");
+ return -1;
+ }
+
+ info->keycode = 0xFF;
+ if ((data[1] == 0xFF) && (data[2] == 0xFF) && (data[3] == 0xFF) && (data[4] == 0xFF) && (data[6] == 0xFF))
+ {
+ if ((data[5] == 0xFF) || (data[5] == 0))
+ {
+ info->keycode = 0xFF;
+ }
+ else if ((data[5] == 1) || (data[5] == 2) || (data[5] == 4) || (data[5] == 8))
+ {
+ if (data[5] == 1)
+ {
+ info->keycode = 0;
+ }
+ else if (data[5] == 2)
+ {
+ info->keycode = 1;
+ }
+ else if (data[5] == 4)
+ {
+ info->keycode = 2;
+ }
+ else if (data[5] == 8)
+ {
+ info->keycode = 3;
+ }
+ }
+ #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR
+ else if (bEnableTpProximity &&((data[5] == 0x80) || (data[5] == 0x40)))
+ {
+ if (data[5] == 0x80)
+ {
+ bFaceClosingTp = 1;
+ }
+ else if (data[5] == 0x40)
+ {
+ bFaceClosingTp = 0;
+ }
+ DBG("bEnableTpProximity=%d; bFaceClosingTp=%d; data[5]=%x;\n", bEnableTpProximity, bFaceClosingTp, data[5]);
+ return -1;
+ }
+ #endif
+ else
+ {
+ DBG("WRONG KEY\n");
+ return -1;
+ }
+ }
+ else
+ {
+ x = (((data[1] & 0xF0 ) << 4) | data[2]);
+ y = ((( data[1] & 0x0F) << 8) | data[3]);
+ delta_x = (((data[4] & 0xF0) << 4 ) | data[5]);
+ delta_y = (((data[4] & 0x0F) << 8 ) | data[6]);
+
+ if ((delta_x == 0) && (delta_y == 0))
+ {
+ info->point[0].x = x * TOUCH_SCREEN_X_MAX / TPD_WIDTH;
+ info->point[0].y = y * TOUCH_SCREEN_Y_MAX/ TPD_HEIGHT;
+ info->count = 1;
+ }
+ else
+ {
+ if (delta_x > 2048)
+ {
+ delta_x -= 4096;
+ }
+ if (delta_y > 2048)
+ {
+ delta_y -= 4096;
+ }
+ x2 = (U32)((S16)x + (S16)delta_x);
+ y2 = (U32)((S16)y + (S16)delta_y);
+ info->point[0].x = x * TOUCH_SCREEN_X_MAX / TPD_WIDTH;
+ info->point[0].y = y * TOUCH_SCREEN_Y_MAX/ TPD_HEIGHT;
+ info->point[1].x = x2 * TOUCH_SCREEN_X_MAX / TPD_WIDTH;
+ info->point[1].y = y2 * TOUCH_SCREEN_Y_MAX/ TPD_HEIGHT;
+ info->count = 2;
+ }
+ }
+
+ return 0;
+}
+
+static void touch_driver_touch_pressed(int x, int y)
+{
+ DBG("point touch pressed");
+
+ input_report_key(input_dev, BTN_TOUCH, 1);
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, 1);
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ input_mt_sync(input_dev);
+}
+
+static void touch_driver_touch_released(void)
+{
+ DBG("point touch released");
+
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_mt_sync(input_dev);
+}
+
+/* read data through I2C then report data to input sub-system when interrupt occurred */
+void touch_driver_do_work(struct work_struct *work)
+{
+ touchInfo_t info;
+ int i = 0;
+ static int last_keycode = 0xFF;
+ static int last_count = 0;
+
+ DBG("touch_driver_do_work()\n");
+
+ memset(&info, 0x0, sizeof(info));
+ if (0 == parse_info(&info))
+ {
+ #ifdef CONFIG_TP_HAVE_KEY
+ if (info.keycode != 0xFF) //key touch pressed
+ {
+ DBG("touch_driver_do_work() info.keycode=%x, last_keycode=%x, tp_key_array[%d]=%d\n", info.keycode, last_keycode, info.keycode, tp_key_array[info.keycode]);
+ if (info.keycode < MAX_KEY_NUM)
+ {
+ if (info.keycode != last_keycode)
+ {
+ DBG("key touch pressed");
+
+ input_report_key(input_dev, BTN_TOUCH, 1);
+ input_report_key(input_dev, tp_key_array[info.keycode], 1);
+
+ last_keycode = info.keycode;
+ }
+ else
+ {
+ /// pass duplicate key-pressing
+ DBG("REPEATED KEY\n");
+ }
+ }
+ else
+ {
+ DBG("WRONG KEY\n");
+ }
+ }
+ else //key touch released
+ {
+ if (last_keycode != 0xFF)
+ {
+ DBG("key touch released");
+
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_report_key(input_dev, tp_key_array[last_keycode], 0);
+
+ last_keycode = 0xFF;
+ }
+ }
+ #endif //CONFIG_TP_HAVE_KEY
+
+ if (info.count > 0) //point touch pressed
+ {
+ for (i = 0; i < info.count; i ++)
+ {
+ touch_driver_touch_pressed(info.point[i].x, info.point[i].y);
+ }
+ last_count = info.count;
+ }
+ else if (last_count > 0) //point touch released
+ {
+ touch_driver_touch_released();
+ last_count = 0;
+ }
+
+ input_sync(input_dev);
+ }
+
+ enable_irq(irq_msg21xx);
+}
+
+/* The interrupt service routine will be triggered when interrupt occurred */
+irqreturn_t touch_driver_isr(int irq, void *dev_id)
+{
+ DBG("touch_driver_isr()\n");
+
+ disable_irq_nosync(irq_msg21xx);
+ schedule_work(&msg21xx_wk);
+
+ return IRQ_HANDLED;
+}
+
+#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;
+
+ if (evdata && evdata->data && event == FB_EVENT_BLANK )
+ {
+ blank = evdata->data;
+ if (*blank == FB_BLANK_UNBLANK)
+ {
+ if (bTpInSuspend)
+ {
+ gpio_direction_output(MS_TS_MSG21XX_GPIO_RST, 1);
+ mdelay(10);
+ gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0);
+ mdelay(10);
+ gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 1);
+ mdelay(200);
+
+ touch_driver_touch_released();
+ input_sync(input_dev);
+
+ enable_irq(irq_msg21xx);
+ }
+ bTpInSuspend = 0;
+ }
+ else if (*blank == FB_BLANK_POWERDOWN)
+ {
+ if (bFwUpdating)
+ {
+ DBG("suspend bFwUpdating=%d\n", bFwUpdating);
+ return 0;
+ }
+
+ #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR
+ if (bEnableTpProximity)
+ {
+ DBG("suspend bEnableTpProximity=%d\n", bEnableTpProximity);
+ return 0;
+ }
+ #endif
+
+ if (bTpInSuspend == 0)
+ {
+ disable_irq(irq_msg21xx);
+ gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0);
+ }
+ bTpInSuspend = 1;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void touch_driver_early_suspend(struct early_suspend *p)
+{
+ DBG("touch_driver_early_suspend()\n");
+
+ if (bFwUpdating)
+ {
+ DBG("suspend bFwUpdating=%d\n", bFwUpdating);
+ return;
+ }
+
+#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR
+ if (bEnableTpProximity)
+ {
+ DBG("suspend bEnableTpProximity=%d\n", bEnableTpProximity);
+ return;
+ }
+#endif
+
+ if (bTpInSuspend == 0)
+ {
+ disable_irq(irq_msg21xx);
+ gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0);
+ }
+ bTpInSuspend = 1;
+}
+
+void touch_driver_early_resume(struct early_suspend *p)
+{
+ DBG("touch_driver_early_resume() bTpInSuspend=%d\n", bTpInSuspend);
+
+ if (bTpInSuspend)
+ {
+ gpio_direction_output(MS_TS_MSG21XX_GPIO_RST, 1);
+ mdelay(10);
+ gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0);
+ mdelay(10);
+ gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 1);
+ mdelay(200);
+
+ touch_driver_touch_released();
+ input_sync(input_dev);
+
+ enable_irq(irq_msg21xx);
+ }
+ bTpInSuspend = 0;
+}
+#endif
+
+/* probe function is used for matching and initializing input device */
+static int touch_driver_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+#ifdef FIRMWARE_AUTOUPDATE
+ unsigned short update_bin_major = 0, update_bin_minor = 0;
+ int i, update_flag = 0;
+#endif
+ int ret = 0;
+
+ if (input_dev != NULL)
+ {
+ DBG("input device has found\n");
+ return -1;
+ }
+
+ DBG("*** %s ***\n", __FUNCTION__);
+
+ i2c_client = client;
+
+ ret = gpio_request(MS_TS_MSG21XX_GPIO_RST, "reset");
+ if (ret < 0)
+ {
+ pr_err("*** Failed to request GPIO %d, error %d ***\n", MS_TS_MSG21XX_GPIO_RST, ret);
+ goto err0;
+ }
+
+ // power on TP
+ gpio_direction_output(MS_TS_MSG21XX_GPIO_RST, 1);
+ mdelay(100);
+ gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0);
+ mdelay(10);
+ gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 1);
+ mdelay(200);
+ if (0 == get_ic_type())
+ {
+ pr_err("the currnet ic is not Mstar\n");
+ ret = -1;
+ goto err0;
+ }
+
+ mutex_init(&msg21xx_mutex);
+
+ /* allocate an input device */
+ input_dev = input_allocate_device();
+ if (!input_dev)
+ {
+ ret = -ENOMEM;
+ pr_err("*** input device allocation failed ***\n");
+ goto err1;
+ }
+
+ input_dev->name = client->name;
+ input_dev->phys = "I2C";
+ input_dev->dev.parent = &client->dev;
+ input_dev->id.bustype = BUS_I2C;
+
+ /* set the supported event type for input device */
+ set_bit(EV_ABS, input_dev->evbit);
+ set_bit(EV_SYN, input_dev->evbit);
+ set_bit(EV_KEY, input_dev->evbit);
+ set_bit(BTN_TOUCH, input_dev->keybit);
+ set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
+#ifdef CONFIG_TP_HAVE_KEY
+ {
+ int i;
+ for (i = 0; i < MAX_KEY_NUM; i ++)
+ {
+ input_set_capability(input_dev, EV_KEY, tp_key_array[i]);
+ }
+ }
+#endif
+
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 2, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, TOUCH_SCREEN_X_MIN, TOUCH_SCREEN_X_MAX, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, TOUCH_SCREEN_Y_MIN, TOUCH_SCREEN_Y_MAX, 0, 0);
+
+ /* register the input device to input sub-system */
+ ret = input_register_device(input_dev);
+ if (ret < 0)
+ {
+ pr_err("*** Unable to register ms-touchscreen input device ***\n");
+ goto err1;
+ }
+
+ /* set sysfs for firmware */
+ firmware_class = class_create(THIS_MODULE, "ms-touchscreen-msg20xx"); //client->name
+ if (IS_ERR(firmware_class))
+ pr_err("Failed to create class(firmware)!\n");
+
+ firmware_cmd_dev = device_create(firmware_class, NULL, 0, NULL, "device");
+ if (IS_ERR(firmware_cmd_dev))
+ pr_err("Failed to create device(firmware_cmd_dev)!\n");
+
+ // version
+ if (device_create_file(firmware_cmd_dev, &dev_attr_version) < 0)
+ pr_err("Failed to create device file(%s)!\n", dev_attr_version.attr.name);
+ // update
+ if (device_create_file(firmware_cmd_dev, &dev_attr_update) < 0)
+ pr_err("Failed to create device file(%s)!\n", dev_attr_update.attr.name);
+ // data
+ if (device_create_file(firmware_cmd_dev, &dev_attr_data) < 0)
+ pr_err("Failed to create device file(%s)!\n", dev_attr_data.attr.name);
+
+#ifdef TP_PRINT
+ tp_print_create_entry();
+#endif
+
+ dev_set_drvdata(firmware_cmd_dev, NULL);
+
+ /* initialize the work queue */
+ INIT_WORK(&msg21xx_wk, touch_driver_do_work);
+
+ ret = gpio_request(MS_TS_MSG21XX_GPIO_INT, "interrupt");
+ if (ret < 0)
+ {
+ pr_err("*** Failed to request GPIO %d, error %d ***\n", MS_TS_MSG21XX_GPIO_INT, ret);
+ goto err2;
+ }
+ gpio_direction_input(MS_TS_MSG21XX_GPIO_INT);
+ gpio_set_value(MS_TS_MSG21XX_GPIO_INT, 1);
+
+ irq_msg21xx = gpio_to_irq(MS_TS_MSG21XX_GPIO_INT);
+
+ /* request an irq and register the isr */
+ ret = request_irq(irq_msg21xx, touch_driver_isr, IRQF_TRIGGER_RISING, "msg21xx", NULL);
+ if (ret != 0)
+ {
+ pr_err("*** Unable to claim irq %d; error %d ***\n", MS_TS_MSG21XX_GPIO_INT, ret);
+ goto err3;
+ }
+
+ disable_irq(irq_msg21xx);
+
+#if defined(CONFIG_FB)
+ msg21xx_fb_notif.notifier_call = fb_notifier_callback;
+ ret = fb_register_client(&msg21xx_fb_notif);
+#elif defined (CONFIG_HAS_EARLYSUSPEND)
+ mstar_ts_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
+ mstar_ts_early_suspend.suspend = touch_driver_early_suspend;
+ mstar_ts_early_suspend.resume = touch_driver_early_resume;
+ register_early_suspend(&mstar_ts_early_suspend);
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR
+ tsps_assist_register_callback("msg21xx", &tsps_msg21xx_enable, &tsps_msg21xx_data);
+#endif
+
+#ifdef FIRMWARE_AUTOUPDATE
+ get_customer_firmware_version();
+ _ReadBinConfig();
+
+ if (main_sw_id == info_sw_id)
+ {
+ if (_CalMainCRC32() == bin_conf_crc32)
+ {
+ if ((main_sw_id >= SWID_START) && (main_sw_id < SWID_NULL))
+ {
+ update_bin_major= (MSG_FIRMWARE[main_sw_id-SWID_START][0x7f4f] << 8) + MSG_FIRMWARE[main_sw_id-SWID_START][0x7f4e];
+ update_bin_minor= (MSG_FIRMWARE[main_sw_id-SWID_START][0x7f51] << 8) + MSG_FIRMWARE[main_sw_id-SWID_START][0x7f50];
+
+ //check upgrading
+ if ((update_bin_major == fw_version_major) && (update_bin_minor > fw_version_minor))
+ {
+ update_flag = 1;
+ }
+ }
+ DBG("MAIN sw_id=%d,update_flag=%d,update_bin_major=%d,update_bin_minor=%d\n",main_sw_id,update_flag,update_bin_major,update_bin_minor);
+ }
+ else
+ {
+ if ((info_sw_id >= SWID_START) && (info_sw_id < SWID_NULL))
+ {
+ update_bin_major= (MSG_FIRMWARE[info_sw_id-SWID_START][0x7f4f] << 8) + MSG_FIRMWARE[info_sw_id-SWID_START][0x7f4e];
+ update_bin_minor= (MSG_FIRMWARE[info_sw_id-SWID_START][0x7f51] << 8) + MSG_FIRMWARE[info_sw_id-SWID_START][0x7f50];
+ update_flag = 1;
+ }
+ DBG("INFO1 sw_id=%d,update_flag=%d,update_bin_major=%d,update_bin_minor=%d\n",info_sw_id,update_flag,update_bin_major,update_bin_minor);
+ }
+ }
+ else
+ {
+ if ((info_sw_id >= SWID_START) && (info_sw_id < SWID_NULL))
+ {
+ update_bin_major= (MSG_FIRMWARE[info_sw_id-SWID_START][0x7f4f] << 8) + MSG_FIRMWARE[info_sw_id-SWID_START][0x7f4e];
+ update_bin_minor= (MSG_FIRMWARE[info_sw_id-SWID_START][0x7f51] << 8) + MSG_FIRMWARE[info_sw_id-SWID_START][0x7f50];
+ update_flag = 1;
+ }
+ DBG("INFO2 sw_id=%d,update_flag=%d,update_bin_major=%d,update_bin_minor=%d\n",info_sw_id,update_flag,update_bin_major,update_bin_minor);
+ }
+
+ if (update_flag == 1)
+ {
+ DBG("MSG21XX_fw_auto_update begin....\n");
+ //transfer data
+ for (i = 0; i < 33; i++)
+ {
+ firmware_data_store(NULL, NULL, &(MSG_FIRMWARE[info_sw_id-SWID_START][i*1024]), 1024);
+ }
+
+ kthread_run(fwAutoUpdate, 0, "MSG21XX_fw_auto_update");
+ DBG("*** mstar touch screen registered ***\n");
+ return 0;
+ }
+
+ reset_hw();
+#endif
+
+ DBG("*** mstar touch screen registered ***\n");
+ enable_irq(irq_msg21xx);
+ return 0;
+
+err3:
+ free_irq(irq_msg21xx, input_dev);
+
+err2:
+ gpio_free(MS_TS_MSG21XX_GPIO_INT);
+
+err1:
+ mutex_destroy(&msg21xx_mutex);
+ input_unregister_device(input_dev);
+ input_free_device(input_dev);
+ input_dev = NULL;
+
+err0:
+ gpio_free(MS_TS_MSG21XX_GPIO_RST);
+
+ return ret;
+}
+
+/* remove function is triggered when the input device is removed from input sub-system */
+static int touch_driver_remove(struct i2c_client *client)
+{
+ DBG("touch_driver_remove()\n");
+
+ free_irq(irq_msg21xx, input_dev);
+ gpio_free(MS_TS_MSG21XX_GPIO_INT);
+ gpio_free(MS_TS_MSG21XX_GPIO_RST);
+ input_unregister_device(input_dev);
+ mutex_destroy(&msg21xx_mutex);
+
+ return 0;
+}
+
+/* The I2C device list is used for matching I2C device and I2C device driver. */
+static const struct i2c_device_id touch_device_id[] =
+{
+ {"msg21xx", 0},
+ {}, /* should not omitted */
+};
+
+MODULE_DEVICE_TABLE(i2c, touch_device_id);
+
+static struct i2c_driver touch_device_driver =
+{
+ .driver = {
+ .name = "msg21xx",
+ .owner = THIS_MODULE,
+ },
+ .probe = touch_driver_probe,
+ .remove = touch_driver_remove,
+ .id_table = touch_device_id,
+};
+
+static int __init touch_driver_init(void)
+{
+ int ret;
+
+ /* register driver */
+ ret = i2c_add_driver(&touch_device_driver);
+ if (ret < 0)
+ {
+ DBG("add touch_device_driver i2c driver failed.\n");
+ return -ENODEV;
+ }
+ DBG("add touch_device_driver i2c driver.\n");
+
+ return ret;
+}
+
+static void __exit touch_driver_exit(void)
+{
+ DBG("remove touch_device_driver i2c driver.\n");
+
+ i2c_del_driver(&touch_device_driver);
+}
+
+#ifdef TP_PRINT
+#include <linux/proc_fs.h>
+
+static U16 InfoAddr = 0x0F, PoolAddr = 0x10, TransLen = 256;
+static U8 row, units, cnt;
+
+static int tp_print_proc_read(void)
+{
+ U16 i, j;
+ U16 left, offset = 0;
+ U8 dbbus_tx_data[3] = {0};
+ U8 u8Data;
+ S16 s16Data;
+ S32 s32Data;
+ char *buf = NULL;
+
+ left = cnt*row*units;
+ if ((bTpInSuspend == 0) && (InfoAddr != 0x0F) && (PoolAddr != 0x10) && (left > 0))
+ {
+ buf = kmalloc(left, GFP_KERNEL);
+ if (buf != NULL)
+ {
+ printk("tpp: \n");
+
+ while (left > 0)
+ {
+ dbbus_tx_data[0] = 0x53;
+ dbbus_tx_data[1] = ((PoolAddr + offset) >> 8) & 0xFF;
+ dbbus_tx_data[2] = (PoolAddr + offset) & 0xFF;
+ mutex_lock(&msg21xx_mutex);
+ write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 3);
+ read_i2c_seq(SLAVE_I2C_ID_DWI2C, &buf[offset], left > TransLen ? TransLen : left);
+ mutex_unlock(&msg21xx_mutex);
+
+ if (left > TransLen)
+ {
+ left -= TransLen;
+ offset += TransLen;
+ }
+ else
+ {
+ left = 0;
+ }
+ }
+
+ for (i = 0; i < cnt; i++)
+ {
+ printk("tpp: ");
+ for (j = 0; j < row; j++)
+ {
+ if (units == 1)
+ {
+ u8Data = buf[i*row*units + j*units];
+ printk("%d\t", u8Data);
+ }
+ else if (units == 2)
+ {
+ s16Data = buf[i*row*units + j*units] + (buf[i*row*units + j*units + 1] << 8);
+ printk("%d\t", s16Data);
+ }
+ else if (units == 4)
+ {
+ s32Data = buf[i*row*units + j*units] + (buf[i*row*units + j*units + 1] << 8) + (buf[i*row*units + j*units + 2] << 16) + (buf[i*row*units + j*units + 3] << 24);
+ printk("%d\t", s32Data);
+ }
+ }
+ printk("\n");
+ }
+
+ kfree(buf);
+ }
+ }
+
+ return 0;
+}
+
+static void tp_print_create_entry(void)
+{
+ U8 dbbus_tx_data[3] = {0};
+ U8 dbbus_rx_data[8] = {0};
+
+ dbbus_tx_data[0] = 0x53;
+ dbbus_tx_data[1] = 0x00;
+ dbbus_tx_data[2] = 0x58;
+ mutex_lock(&msg21xx_mutex);
+ write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 3);
+ read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 4);
+ mutex_unlock(&msg21xx_mutex);
+ InfoAddr = (dbbus_rx_data[1]<<8) + dbbus_rx_data[0];
+ PoolAddr = (dbbus_rx_data[3]<<8) + dbbus_rx_data[2];
+ printk("InfoAddr=0x%X\n", InfoAddr);
+ printk("PoolAddr=0x%X\n", PoolAddr);
+
+ if ((InfoAddr != 0x0F) && (PoolAddr != 0x10))
+ {
+ msleep(10);
+ dbbus_tx_data[0] = 0x53;
+ dbbus_tx_data[1] = (InfoAddr >> 8) & 0xFF;
+ dbbus_tx_data[2] = InfoAddr & 0xFF;
+ mutex_lock(&msg21xx_mutex);
+ write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 3);
+ read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 8);
+ mutex_unlock(&msg21xx_mutex);
+
+ units = dbbus_rx_data[0];
+ row = dbbus_rx_data[1];
+ cnt = dbbus_rx_data[2];
+ TransLen = (dbbus_rx_data[7]<<8) + dbbus_rx_data[6];
+ printk("tpp: row=%d, units=%d\n", row, units);
+ printk("tpp: cnt=%d, TransLen=%d\n", cnt, TransLen);
+
+ // tpp
+ if (device_create_file(firmware_cmd_dev, &dev_attr_tpp) < 0)
+ {
+ pr_err("Failed to create device file(%s)!\n", dev_attr_tpp.attr.name);
+ }
+ }
+}
+#endif
+
+module_init(touch_driver_init);
+module_exit(touch_driver_exit);
+MODULE_AUTHOR("MStar Semiconductor, Inc.");
+MODULE_LICENSE("GPL v2");
+
diff --git a/kernel/drivers/input/touchscreen/synaptics_fw_update.c b/kernel/drivers/input/touchscreen/synaptics_fw_update.c
new file mode 100644
index 000000000000..4867d1f73c4d
--- /dev/null
+++ b/kernel/drivers/input/touchscreen/synaptics_fw_update.c
@@ -0,0 +1,1587 @@
+/*
+ * Synaptics RMI4 touchscreen driver
+ *
+ * Copyright (C) 2012 Synaptics Incorporated
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/firmware.h>
+#include <linux/input/synaptics_dsx.h>
+#include "synaptics_i2c_rmi4.h"
+
+#define DEBUG_FW_UPDATE
+#define SHOW_PROGRESS
+#define FW_IMAGE_NAME "PR12345678.img"
+
+#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
+#define BLOCK_SIZE_OFFSET 3
+#define FW_BLOCK_COUNT_OFFSET 5
+
+#define REG_MAP (1 << 0)
+#define UNLOCKED (1 << 1)
+#define HAS_CONFIG_ID (1 << 2)
+#define HAS_PERM_CONFIG (1 << 3)
+#define HAS_BL_CONFIG (1 << 4)
+#define HAS_DISP_CONFIG (1 << 5)
+#define HAS_CTRL1 (1 << 6)
+
+#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
+
+enum flash_command {
+ CMD_WRITE_FW_BLOCK = 0x2,
+ CMD_ERASE_ALL = 0x3,
+ CMD_READ_CONFIG_BLOCK = 0x5,
+ CMD_WRITE_CONFIG_BLOCK = 0x6,
+ CMD_ERASE_CONFIG = 0x7,
+ CMD_ERASE_BL_CONFIG = 0x9,
+ CMD_ERASE_DISP_CONFIG = 0xA,
+ CMD_ENABLE_FLASH_PROG = 0xF,
+};
+
+#define SLEEP_MODE_NORMAL (0x00)
+#define SLEEP_MODE_SENSOR_SLEEP (0x01)
+#define SLEEP_MODE_RESERVED0 (0x02)
+#define SLEEP_MODE_RESERVED1 (0x03)
+
+#define ENABLE_WAIT_MS (1 * 1000)
+#define WRITE_WAIT_MS (3 * 1000)
+#define ERASE_WAIT_MS (5 * 1000)
+
+#define MIN_SLEEP_TIME_US 50
+#define MAX_SLEEP_TIME_US 100
+
+static ssize_t fwu_sysfs_show_image(struct file *data_file,
+ struct kobject *kobj, struct bin_attribute *attributes,
+ char *buf, loff_t pos, size_t count);
+
+static ssize_t fwu_sysfs_store_image(struct file *data_file,
+ struct kobject *kobj, struct bin_attribute *attributes,
+ char *buf, loff_t pos, size_t count);
+
+static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t fwu_sysfs_write_config_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t fwu_sysfs_read_config_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t fwu_sysfs_config_area_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t fwu_sysfs_image_size_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t fwu_sysfs_block_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static int fwu_wait_for_idle(int timeout_ms);
+
+struct image_header {
+ unsigned int checksum;
+ unsigned int image_size;
+ unsigned int config_size;
+ unsigned char options;
+ unsigned char bootloader_version;
+ unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
+ unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
+};
+
+struct pdt_properties {
+ union {
+ struct {
+ unsigned char reserved_1:6;
+ unsigned char has_bsr:1;
+ unsigned char reserved_2:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f01_device_status {
+ union {
+ struct {
+ unsigned char status_code:4;
+ unsigned char reserved:2;
+ unsigned char flash_prog:1;
+ unsigned char unconfigured:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f01_device_control {
+ union {
+ struct {
+ unsigned char sleep_mode:2;
+ unsigned char nosleep:1;
+ unsigned char reserved:2;
+ unsigned char charger_connected:1;
+ unsigned char report_rate:1;
+ unsigned char configured:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f34_flash_control {
+ union {
+ struct {
+ unsigned char command:4;
+ unsigned char status:3;
+ unsigned char program_enabled:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f34_flash_properties {
+ union {
+ struct {
+ unsigned char regmap:1;
+ unsigned char unlocked:1;
+ unsigned char has_configid:1;
+ unsigned char has_perm_config:1;
+ unsigned char has_bl_config:1;
+ unsigned char has_display_config:1;
+ unsigned char has_blob_config:1;
+ unsigned char reserved:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct synaptics_rmi4_fwu_handle {
+ bool initialized;
+ char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
+ unsigned int image_size;
+ unsigned int data_pos;
+ unsigned char intr_mask;
+ unsigned char bootloader_id[2];
+ unsigned char productinfo1;
+ unsigned char productinfo2;
+ unsigned char *ext_data_source;
+ unsigned char *read_config_buf;
+ const unsigned char *firmware_data;
+ const unsigned char *config_data;
+ unsigned short block_size;
+ unsigned short fw_block_count;
+ unsigned short config_block_count;
+ unsigned short perm_config_block_count;
+ unsigned short bl_config_block_count;
+ unsigned short disp_config_block_count;
+ unsigned short config_size;
+ unsigned short config_area;
+ unsigned short addr_f34_flash_control;
+ unsigned short addr_f01_interrupt_register;
+ struct synaptics_rmi4_fn_desc f01_fd;
+ struct synaptics_rmi4_fn_desc f34_fd;
+ struct synaptics_rmi4_exp_fn_ptr *fn_ptr;
+ struct synaptics_rmi4_data *rmi4_data;
+ struct f34_flash_control flash_control;
+ struct f34_flash_properties flash_properties;
+};
+
+static struct bin_attribute dev_attr_data = {
+ .attr = {
+ .name = "data",
+ .mode = (S_IRUGO | S_IWUGO),
+ },
+ .size = 0,
+ .read = fwu_sysfs_show_image,
+ .write = fwu_sysfs_store_image,
+};
+
+static struct device_attribute attrs[] = {
+ __ATTR(doreflash, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_do_reflash_store),
+ __ATTR(writeconfig, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_write_config_store),
+ __ATTR(readconfig, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_read_config_store),
+ __ATTR(configarea, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_config_area_store),
+ __ATTR(imagesize, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_image_size_store),
+ __ATTR(blocksize, S_IRUGO,
+ fwu_sysfs_block_size_show,
+ synaptics_rmi4_store_error),
+ __ATTR(fwblockcount, S_IRUGO,
+ fwu_sysfs_firmware_block_count_show,
+ synaptics_rmi4_store_error),
+ __ATTR(configblockcount, S_IRUGO,
+ fwu_sysfs_configuration_block_count_show,
+ synaptics_rmi4_store_error),
+ __ATTR(permconfigblockcount, S_IRUGO,
+ fwu_sysfs_perm_config_block_count_show,
+ synaptics_rmi4_store_error),
+ __ATTR(blconfigblockcount, S_IRUGO,
+ fwu_sysfs_bl_config_block_count_show,
+ synaptics_rmi4_store_error),
+ __ATTR(dispconfigblockcount, S_IRUGO,
+ fwu_sysfs_disp_config_block_count_show,
+ synaptics_rmi4_store_error),
+};
+
+static struct synaptics_rmi4_fwu_handle *fwu;
+
+static struct completion remove_complete;
+
+static unsigned int extract_uint(const unsigned char *ptr)
+{
+ return (unsigned int)ptr[0] +
+ (unsigned int)ptr[1] * 0x100 +
+ (unsigned int)ptr[2] * 0x10000 +
+ (unsigned int)ptr[3] * 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);
+
+#ifdef DEBUG_FW_UPDATE
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "Firwmare size %d, config size %d\n",
+ header->image_size,
+ header->config_size);
+#endif
+ return;
+}
+
+static int fwu_check_version(void)
+{
+ int retval;
+ unsigned char firmware_id[4];
+ unsigned char config_id[4];
+ struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
+
+ /* device firmware id */
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f01_fd.query_base_addr + 18,
+ firmware_id,
+ sizeof(firmware_id));
+ if (retval < 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to read firmware ID (code %d).\n", retval);
+ return retval;
+ }
+ firmware_id[3] = 0;
+
+ dev_info(&i2c_client->dev, "Device firmware ID%d\n",
+ extract_uint(firmware_id));
+
+ /* device config id */
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f34_fd.ctrl_base_addr,
+ config_id,
+ sizeof(config_id));
+ if (retval < 0) {
+ dev_err(&i2c_client->dev,
+ "Failed to read config ID (code %d).\n", retval);
+ return retval;
+ }
+
+ dev_info(&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,
+ ".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]);
+ return 0;
+}
+
+static int fwu_read_f01_device_status(struct f01_device_status *status)
+{
+ int retval;
+
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f01_fd.data_base_addr,
+ status->data,
+ sizeof(status->data));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to read F01 device status\n",
+ __func__);
+ return retval;
+ }
+
+ return 0;
+}
+
+static int fwu_read_f34_queries(void)
+{
+ int retval;
+ unsigned char count = 4;
+ unsigned char buf[10];
+ struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
+
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f34_fd.query_base_addr + BOOTLOADER_ID_OFFSET,
+ fwu->bootloader_id,
+ sizeof(fwu->bootloader_id));
+ if (retval < 0) {
+ dev_err(&i2c_client->dev,
+ "%s: Failed to read bootloader ID\n",
+ __func__);
+ return retval;
+ }
+
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f34_fd.query_base_addr + FLASH_PROPERTIES_OFFSET,
+ fwu->flash_properties.data,
+ sizeof(fwu->flash_properties.data));
+ if (retval < 0) {
+ dev_err(&i2c_client->dev,
+ "%s: Failed to read flash properties\n",
+ __func__);
+ return retval;
+ }
+
+ dev_info(&i2c_client->dev, "%s perm:%d, bl%d, display:%d\n",
+ __func__,
+ fwu->flash_properties.has_perm_config,
+ fwu->flash_properties.has_bl_config,
+ fwu->flash_properties.has_display_config);
+
+ if (fwu->flash_properties.has_perm_config)
+ count += 2;
+
+ if (fwu->flash_properties.has_bl_config)
+ count += 2;
+
+ if (fwu->flash_properties.has_display_config)
+ count += 2;
+
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f34_fd.query_base_addr + BLOCK_SIZE_OFFSET,
+ buf,
+ 2);
+ if (retval < 0) {
+ dev_err(&i2c_client->dev,
+ "%s: Failed to read block size info\n",
+ __func__);
+ return retval;
+ }
+
+ batohs(&fwu->block_size, &(buf[0]));
+
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f34_fd.query_base_addr + FW_BLOCK_COUNT_OFFSET,
+ buf,
+ count);
+ if (retval < 0) {
+ dev_err(&i2c_client->dev,
+ "%s: Failed to read block count info\n",
+ __func__);
+ return retval;
+ }
+
+ batohs(&fwu->fw_block_count, &(buf[0]));
+ batohs(&fwu->config_block_count, &(buf[2]));
+
+ count = 4;
+
+ if (fwu->flash_properties.has_perm_config) {
+ batohs(&fwu->perm_config_block_count, &(buf[count]));
+ count += 2;
+ }
+
+ if (fwu->flash_properties.has_bl_config) {
+ batohs(&fwu->bl_config_block_count, &(buf[count]));
+ count += 2;
+ }
+
+ if (fwu->flash_properties.has_display_config)
+ batohs(&fwu->disp_config_block_count, &(buf[count]));
+
+ fwu->addr_f34_flash_control = fwu->f34_fd.data_base_addr +
+ BLOCK_DATA_OFFSET +
+ fwu->block_size;
+ return 0;
+}
+
+static int fwu_read_interrupt_status(void)
+{
+ int retval;
+ unsigned char interrupt_status;
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->addr_f01_interrupt_register,
+ &interrupt_status,
+ sizeof(interrupt_status));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to read flash status\n",
+ __func__);
+ return retval;
+ }
+ return interrupt_status;
+}
+
+static int fwu_read_f34_flash_status(void)
+{
+ int retval;
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->addr_f34_flash_control,
+ fwu->flash_control.data,
+ sizeof(fwu->flash_control.data));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to read flash status\n",
+ __func__);
+ return retval;
+ }
+ return 0;
+}
+
+static int fwu_reset_device(void)
+{
+ int retval;
+ unsigned char reset = 0x01;
+
+#ifdef DEBUG_FW_UPDATE
+ dev_info(&fwu->rmi4_data->i2c_client->dev, "Reset device\n");
+#endif
+
+ retval = fwu->fn_ptr->write(fwu->rmi4_data,
+ fwu->f01_fd.cmd_base_addr,
+ &reset,
+ sizeof(reset));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to reset device (addr : 0x%02x)\n",
+ __func__, fwu->f01_fd.cmd_base_addr);
+ return retval;
+ }
+
+ fwu_wait_for_idle(WRITE_WAIT_MS);
+
+ retval = fwu->rmi4_data->reset_device(fwu->rmi4_data);
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to reset core driver after reflash\n",
+ __func__);
+ return retval;
+ }
+ return 0;
+}
+
+static int fwu_write_f34_command(unsigned char cmd)
+{
+ int retval;
+
+ retval = fwu->fn_ptr->write(fwu->rmi4_data,
+ fwu->addr_f34_flash_control,
+ &cmd,
+ sizeof(cmd));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to write command 0x%02x\n",
+ __func__, cmd);
+ return retval;
+ }
+ return 0;
+}
+
+static unsigned char fwu_check_flash_status(void)
+{
+ fwu_read_f34_flash_status();
+ return fwu->flash_control.status;
+}
+
+static int fwu_wait_for_idle(int timeout_ms)
+{
+ int count = 0;
+ int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1;
+
+ do {
+ if (fwu_read_interrupt_status() > 0)
+ return 0;
+
+ usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US);
+ count++;
+ } while (count < timeout_count);
+
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Timed out waiting for idle status\n",
+ __func__);
+
+ return -ETIMEDOUT;
+}
+
+static int fwu_scan_pdt(void)
+{
+ int retval;
+ unsigned char ii;
+ unsigned char intr_count = 0;
+ unsigned char intr_off;
+ unsigned char intr_src;
+ unsigned short addr;
+ bool f01found = false;
+ bool f34found = false;
+ struct synaptics_rmi4_fn_desc rmi_fd;
+
+#ifdef DEBUG_FW_UPDATE
+ dev_info(&fwu->rmi4_data->i2c_client->dev, "Scan PDT\n");
+#endif
+
+ for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ addr,
+ (unsigned char *)&rmi_fd,
+ sizeof(rmi_fd));
+ if (retval < 0)
+ return retval;
+
+ if (rmi_fd.fn_number) {
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Found F%02x\n",
+ __func__, rmi_fd.fn_number);
+ switch (rmi_fd.fn_number) {
+ case SYNAPTICS_RMI4_F01:
+ f01found = true;
+ fwu->f01_fd = rmi_fd;
+ fwu->addr_f01_interrupt_register =
+ fwu->f01_fd.data_base_addr + 1;
+ break;
+ case SYNAPTICS_RMI4_F34:
+ f34found = true;
+ fwu->f34_fd = rmi_fd;
+ fwu->intr_mask = 0;
+ intr_src = rmi_fd.intr_src_count;
+ intr_off = intr_count % 8;
+ for (ii = intr_off;
+ ii < ((intr_src & MASK_3BIT) +
+ intr_off);
+ ii++)
+ fwu->intr_mask |= 1 << ii;
+ break;
+ }
+ } else
+ break;
+
+ intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
+ }
+
+ if (!f01found || !f34found) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to find both F01 and F34\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ fwu_read_interrupt_status();
+ return 0;
+}
+
+static int fwu_write_blocks(unsigned char *block_ptr, unsigned short block_cnt,
+ unsigned char command)
+{
+ int retval;
+ unsigned char block_offset[] = {0, 0};
+ unsigned short block_num;
+#ifdef SHOW_PROGRESS
+ unsigned int progress = (command == CMD_WRITE_CONFIG_BLOCK) ?
+ 10 : 100;
+#endif
+ retval = fwu->fn_ptr->write(fwu->rmi4_data,
+ fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
+ block_offset,
+ sizeof(block_offset));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to write to block number registers\n",
+ __func__);
+ return retval;
+ }
+
+ for (block_num = 0; block_num < block_cnt; block_num++) {
+#ifdef SHOW_PROGRESS
+ if (block_num % progress == 0)
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s: update %s %3d / %3d\n",
+ __func__,
+ command == CMD_WRITE_CONFIG_BLOCK ?
+ "config" : "firmware",
+ block_num,
+ block_cnt);
+#endif
+ retval = fwu->fn_ptr->write(fwu->rmi4_data,
+ fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+ block_ptr,
+ fwu->block_size);
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to write block data (block %d)\n",
+ __func__, block_num);
+ return retval;
+ }
+
+ retval = fwu_write_f34_command(command);
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to write command for block %d\n",
+ __func__, block_num);
+ return retval;
+ }
+
+ retval = fwu_wait_for_idle(WRITE_WAIT_MS);
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to wait for idle status \
+ (block %d)\n",
+ __func__, block_num);
+ return retval;
+ }
+
+ retval = fwu_check_flash_status();
+ if (retval != 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Flash block %d status %d\n",
+ __func__, block_num, retval);
+ return -1;
+ }
+ block_ptr += fwu->block_size;
+ }
+#ifdef SHOW_PROGRESS
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s: update %s %3d / %3d\n",
+ __func__,
+ command == CMD_WRITE_CONFIG_BLOCK ?
+ "config" : "firmware",
+ block_cnt,
+ block_cnt);
+#endif
+ return 0;
+}
+
+static int fwu_write_firmware(void)
+{
+ return fwu_write_blocks((unsigned char *)fwu->firmware_data,
+ fwu->fw_block_count, CMD_WRITE_FW_BLOCK);
+}
+
+static int fwu_write_configuration(void)
+{
+ return fwu_write_blocks((unsigned char *)fwu->config_data,
+ fwu->config_block_count, CMD_WRITE_CONFIG_BLOCK);
+}
+
+static int fwu_write_bootloader_id(void)
+{
+ int retval;
+
+#ifdef DEBUG_FW_UPDATE
+ dev_info(&fwu->rmi4_data->i2c_client->dev, "Write bootloader ID\n");
+#endif
+ retval = fwu->fn_ptr->write(fwu->rmi4_data,
+ fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+ fwu->bootloader_id,
+ sizeof(fwu->bootloader_id));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to write bootloader ID\n",
+ __func__);
+ return retval;
+ }
+
+ return 0;
+}
+
+static int fwu_enter_flash_prog(void)
+{
+ int retval;
+ struct f01_device_status f01_device_status;
+ struct f01_device_control f01_device_control;
+
+#ifdef DEBUG_FW_UPDATE
+ dev_info(&fwu->rmi4_data->i2c_client->dev, "Enter bootloader mode\n");
+#endif
+ retval = fwu_read_f01_device_status(&f01_device_status);
+ if (retval < 0)
+ return retval;
+
+ if (f01_device_status.flash_prog) {
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Already in flash prog mode\n",
+ __func__);
+ return 0;
+ }
+
+ retval = fwu_write_bootloader_id();
+ if (retval < 0)
+ return retval;
+
+ retval = fwu_write_f34_command(CMD_ENABLE_FLASH_PROG);
+ if (retval < 0)
+ return retval;
+
+ retval = fwu_wait_for_idle(ENABLE_WAIT_MS);
+ if (retval < 0)
+ return retval;
+
+ retval = fwu_read_f01_device_status(&f01_device_status);
+ if (retval < 0)
+ return retval;
+
+ if (!f01_device_status.flash_prog) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Program enabled bit not set\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ retval = fwu_scan_pdt();
+ if (retval < 0)
+ return retval;
+
+ retval = fwu_read_f01_device_status(&f01_device_status);
+ if (retval < 0)
+ return retval;
+
+ if (!f01_device_status.flash_prog) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Not in flash prog mode\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ retval = fwu_read_f34_queries();
+ if (retval < 0)
+ return retval;
+
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f01_fd.ctrl_base_addr,
+ f01_device_control.data,
+ sizeof(f01_device_control.data));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to read F01 device control\n",
+ __func__);
+ return retval;
+ }
+
+ f01_device_control.nosleep = true;
+ f01_device_control.sleep_mode = SLEEP_MODE_NORMAL;
+
+ retval = fwu->fn_ptr->write(fwu->rmi4_data,
+ fwu->f01_fd.ctrl_base_addr,
+ f01_device_control.data,
+ sizeof(f01_device_control.data));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to write F01 device control\n",
+ __func__);
+ return retval;
+ }
+
+ return retval;
+}
+
+static int fwu_do_reflash(void)
+{
+ int retval;
+
+ retval = fwu_enter_flash_prog();
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Entered flash prog mode\n",
+ __func__);
+
+ retval = fwu_write_bootloader_id();
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Bootloader ID written\n",
+ __func__);
+
+ retval = fwu_write_f34_command(CMD_ERASE_ALL);
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Erase all command written\n",
+ __func__);
+
+ retval = fwu_wait_for_idle(ERASE_WAIT_MS);
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Idle status detected\n",
+ __func__);
+
+ if (fwu->firmware_data) {
+ retval = fwu_write_firmware();
+ if (retval < 0)
+ return retval;
+ pr_notice("%s: Firmware programmed\n", __func__);
+ }
+
+ if (fwu->config_data) {
+ retval = fwu_write_configuration();
+ if (retval < 0)
+ return retval;
+ pr_notice("%s: Configuration programmed\n", __func__);
+ }
+
+ return retval;
+}
+
+static int fwu_start_reflash(void)
+{
+ int retval;
+ struct image_header header;
+ const unsigned char *fw_image;
+ const struct firmware *fw_entry = NULL;
+ struct f01_device_status f01_device_status;
+
+ pr_notice("%s: Start of reflash process\n", __func__);
+
+ 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__, FW_IMAGE_NAME);
+
+ retval = request_firmware(&fw_entry, FW_IMAGE_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__, FW_IMAGE_NAME);
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Firmware image size = %d\n",
+ __func__, fw_entry->size);
+
+ fw_image = fw_entry->data;
+ }
+
+ parse_header(&header, fw_image);
+
+ if (header.image_size)
+ fwu->firmware_data = fw_image + FW_IMAGE_OFFSET;
+ if (header.config_size) {
+ fwu->config_data = fw_image + FW_IMAGE_OFFSET +
+ header.image_size;
+ }
+
+ fwu->fn_ptr->enable(fwu->rmi4_data, false);
+
+ fwu_check_version();
+
+ retval = fwu_do_reflash();
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to do reflash\n",
+ __func__);
+ }
+
+ /* reset device */
+ fwu_reset_device();
+
+ /* check device status */
+ retval = fwu_read_f01_device_status(&f01_device_status);
+ if (retval < 0)
+ goto exit;
+
+ dev_info(&fwu->rmi4_data->i2c_client->dev, "Device is in %s mode\n",
+ f01_device_status.flash_prog == 1 ? "bootloader" : "UI");
+ if (f01_device_status.flash_prog)
+ dev_info(&fwu->rmi4_data->i2c_client->dev, "Flash status %d\n",
+ f01_device_status.status_code);
+
+ if (f01_device_status.flash_prog) {
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Device is in flash prog mode 0x%02X\n",
+ __func__, f01_device_status.status_code);
+ retval = 0;
+ goto exit;
+ }
+ fwu->fn_ptr->enable(fwu->rmi4_data, true);
+ if (fw_entry)
+ release_firmware(fw_entry);
+
+ pr_notice("%s: End of reflash process\n", __func__);
+exit:
+ return retval;
+}
+
+static int fwu_do_write_config(void)
+{
+ int retval;
+
+ retval = fwu_enter_flash_prog();
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Entered flash prog mode\n",
+ __func__);
+
+ if (fwu->config_area == PERM_CONFIG_AREA) {
+ fwu->config_block_count = fwu->perm_config_block_count;
+ goto write_config;
+ }
+
+ retval = fwu_write_bootloader_id();
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Bootloader ID written\n",
+ __func__);
+
+ switch (fwu->config_area) {
+ case UI_CONFIG_AREA:
+ retval = fwu_write_f34_command(CMD_ERASE_CONFIG);
+ break;
+ case BL_CONFIG_AREA:
+ retval = fwu_write_f34_command(CMD_ERASE_BL_CONFIG);
+ fwu->config_block_count = fwu->bl_config_block_count;
+ break;
+ case DISP_CONFIG_AREA:
+ retval = fwu_write_f34_command(CMD_ERASE_DISP_CONFIG);
+ fwu->config_block_count = fwu->disp_config_block_count;
+ break;
+ }
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Erase command written\n",
+ __func__);
+
+ retval = fwu_wait_for_idle(ERASE_WAIT_MS);
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Idle status detected\n",
+ __func__);
+
+write_config:
+ retval = fwu_write_configuration();
+ if (retval < 0)
+ return retval;
+
+ pr_notice("%s: Config written\n", __func__);
+
+ return retval;
+}
+
+static int fwu_start_write_config(void)
+{
+ int retval;
+ struct image_header header;
+
+ switch (fwu->config_area) {
+ case UI_CONFIG_AREA:
+ break;
+ case PERM_CONFIG_AREA:
+ if (!fwu->flash_properties.has_perm_config)
+ return -EINVAL;
+ break;
+ case BL_CONFIG_AREA:
+ if (!fwu->flash_properties.has_bl_config)
+ return -EINVAL;
+ break;
+ case DISP_CONFIG_AREA:
+ if (!fwu->flash_properties.has_display_config)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (fwu->ext_data_source)
+ fwu->config_data = fwu->ext_data_source;
+ else
+ return -EINVAL;
+
+ if (fwu->config_area == UI_CONFIG_AREA) {
+ parse_header(&header, fwu->ext_data_source);
+
+ if (header.config_size) {
+ fwu->config_data = fwu->ext_data_source +
+ FW_IMAGE_OFFSET +
+ header.image_size;
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ pr_notice("%s: Start of write config process\n", __func__);
+
+ retval = fwu_do_write_config();
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to write config\n",
+ __func__);
+ }
+
+ fwu->rmi4_data->reset_device(fwu->rmi4_data);
+
+ pr_notice("%s: End of write config process\n", __func__);
+
+ return retval;
+}
+
+static int fwu_do_read_config(void)
+{
+ int retval;
+ unsigned char block_offset[] = {0, 0};
+ unsigned short block_num;
+ unsigned short block_count;
+ unsigned short index = 0;
+
+ retval = fwu_enter_flash_prog();
+ if (retval < 0)
+ goto exit;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Entered flash prog mode\n",
+ __func__);
+
+ switch (fwu->config_area) {
+ case UI_CONFIG_AREA:
+ block_count = fwu->config_block_count;
+ break;
+ case PERM_CONFIG_AREA:
+ if (!fwu->flash_properties.has_perm_config) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ block_count = fwu->perm_config_block_count;
+ break;
+ case BL_CONFIG_AREA:
+ if (!fwu->flash_properties.has_bl_config) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ block_count = fwu->bl_config_block_count;
+ break;
+ case DISP_CONFIG_AREA:
+ if (!fwu->flash_properties.has_display_config) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ block_count = fwu->disp_config_block_count;
+ break;
+ default:
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ fwu->config_size = fwu->block_size * block_count;
+
+ kfree(fwu->read_config_buf);
+ fwu->read_config_buf = kzalloc(fwu->config_size, GFP_KERNEL);
+
+ block_offset[1] |= (fwu->config_area << 5);
+
+ retval = fwu->fn_ptr->write(fwu->rmi4_data,
+ fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
+ block_offset,
+ sizeof(block_offset));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to write to block number registers\n",
+ __func__);
+ goto exit;
+ }
+
+ for (block_num = 0; block_num < block_count; block_num++) {
+ retval = fwu_write_f34_command(CMD_READ_CONFIG_BLOCK);
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to write read config command\n",
+ __func__);
+ goto exit;
+ }
+
+ retval = fwu_wait_for_idle(WRITE_WAIT_MS);
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to wait for idle status\n",
+ __func__);
+ goto exit;
+ }
+
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+ &fwu->read_config_buf[index],
+ fwu->block_size);
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to read block data (block %d)\n",
+ __func__, block_num);
+ goto exit;
+ }
+
+ index += fwu->block_size;
+ }
+
+exit:
+ fwu->rmi4_data->reset_device(fwu->rmi4_data);
+
+ return retval;
+}
+
+int synaptics_fw_updater(unsigned char *fw_data)
+{
+ int retval;
+
+ if (!fwu)
+ return -ENODEV;
+
+ if (!fwu->initialized)
+ return -ENODEV;
+
+ fwu->ext_data_source = fw_data;
+ fwu->config_area = UI_CONFIG_AREA;
+
+ retval = fwu_start_reflash();
+
+ return retval;
+}
+EXPORT_SYMBOL(synaptics_fw_updater);
+
+static ssize_t fwu_sysfs_show_image(struct file *data_file,
+ struct kobject *kobj, struct bin_attribute *attributes,
+ char *buf, loff_t pos, size_t count)
+{
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+
+ if (count < fwu->config_size) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Not enough space (%d bytes) in buffer\n",
+ __func__, count);
+ return -EINVAL;
+ }
+
+ memcpy(buf, fwu->read_config_buf, fwu->config_size);
+
+ return fwu->config_size;
+}
+
+static ssize_t fwu_sysfs_store_image(struct file *data_file,
+ struct kobject *kobj, struct bin_attribute *attributes,
+ char *buf, loff_t pos, size_t count)
+{
+ memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]),
+ (const void *)buf,
+ count);
+
+ fwu->data_pos += count;
+
+ return count;
+}
+
+static ssize_t fwu_sysfs_do_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;
+ }
+
+ 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_write_config_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;
+ }
+
+ retval = fwu_start_write_config();
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to write config\n",
+ __func__);
+ goto exit;
+ }
+
+ retval = count;
+
+exit:
+ kfree(fwu->ext_data_source);
+ fwu->ext_data_source = NULL;
+ return retval;
+}
+
+static ssize_t fwu_sysfs_read_config_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)
+ return -EINVAL;
+
+ if (input != 1)
+ return -EINVAL;
+
+ retval = fwu_do_read_config();
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read config\n",
+ __func__);
+ return retval;
+ }
+
+ return count;
+}
+
+static ssize_t fwu_sysfs_config_area_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned long config_area;
+
+ retval = sstrtoul(buf, 10, &config_area);
+ if (retval)
+ return retval;
+
+ fwu->config_area = config_area;
+
+ return count;
+}
+
+static ssize_t fwu_sysfs_image_size_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned long size;
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+
+ retval = sstrtoul(buf, 10, &size);
+ if (retval)
+ return retval;
+
+ fwu->image_size = size;
+ fwu->data_pos = 0;
+
+ kfree(fwu->ext_data_source);
+ fwu->ext_data_source = kzalloc(fwu->image_size, GFP_KERNEL);
+ if (!fwu->ext_data_source) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for image data\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ return count;
+}
+
+static ssize_t fwu_sysfs_block_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", fwu->block_size);
+}
+
+static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", fwu->fw_block_count);
+}
+
+static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", fwu->config_block_count);
+}
+
+static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", fwu->perm_config_block_count);
+}
+
+static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", fwu->bl_config_block_count);
+}
+
+static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", fwu->disp_config_block_count);
+}
+
+static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
+ unsigned char intr_mask)
+{
+ if (fwu->intr_mask & intr_mask)
+ fwu_read_f34_flash_status();
+
+ return;
+}
+
+static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char attr_count;
+ struct pdt_properties pdt_props;
+
+ fwu = kzalloc(sizeof(*fwu), GFP_KERNEL);
+ if (!fwu) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for fwu\n",
+ __func__);
+ goto exit;
+ }
+
+ fwu->fn_ptr = kzalloc(sizeof(*(fwu->fn_ptr)), GFP_KERNEL);
+ if (!fwu->fn_ptr) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for fn_ptr\n",
+ __func__);
+ retval = -ENOMEM;
+ goto exit_free_fwu;
+ }
+
+ fwu->rmi4_data = rmi4_data;
+ fwu->fn_ptr->read = rmi4_data->i2c_read;
+ fwu->fn_ptr->write = rmi4_data->i2c_write;
+ fwu->fn_ptr->enable = rmi4_data->irq_enable;
+
+ retval = fwu->fn_ptr->read(rmi4_data,
+ PDT_PROPS,
+ pdt_props.data,
+ sizeof(pdt_props.data));
+ if (retval < 0) {
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read PDT properties, assuming 0x00\n",
+ __func__);
+ } else if (pdt_props.has_bsr) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Reflash for LTS not currently supported\n",
+ __func__);
+ goto exit_free_mem;
+ }
+
+ retval = fwu_scan_pdt();
+ if (retval < 0)
+ goto exit_free_mem;
+
+ fwu->productinfo1 = rmi4_data->rmi4_mod_info.product_info[0];
+ fwu->productinfo2 = rmi4_data->rmi4_mod_info.product_info[1];
+
+ memcpy(fwu->product_id, rmi4_data->rmi4_mod_info.product_id_string,
+ SYNAPTICS_RMI4_PRODUCT_ID_SIZE);
+ fwu->product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE] = 0;
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: F01 product info: 0x%04x 0x%04x\n",
+ __func__, fwu->productinfo1, fwu->productinfo2);
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: F01 product ID: %s\n",
+ __func__, fwu->product_id);
+
+ retval = fwu_read_f34_queries();
+ if (retval < 0)
+ goto exit_free_mem;
+
+ fwu->initialized = true;
+
+ retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
+ &dev_attr_data);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create sysfs bin file\n",
+ __func__);
+ goto exit_free_mem;
+ }
+
+ for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+ retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create sysfs attributes\n",
+ __func__);
+ retval = -ENODEV;
+ goto exit_remove_attrs;
+ }
+ }
+
+ return 0;
+
+exit_remove_attrs:
+for (attr_count--; attr_count >= 0; attr_count--) {
+ sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+}
+
+sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+
+exit_free_mem:
+ kfree(fwu->fn_ptr);
+
+exit_free_fwu:
+ kfree(fwu);
+
+exit:
+ return 0;
+}
+
+static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data)
+{
+ unsigned char attr_count;
+
+ sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+
+ for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+ sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+ }
+
+ kfree(fwu->fn_ptr);
+ kfree(fwu);
+
+ complete(&remove_complete);
+
+ return;
+}
+
+static int __init rmi4_fw_update_module_init(void)
+{
+ synaptics_rmi4_new_function(RMI_FW_UPDATER, true,
+ synaptics_rmi4_fwu_init,
+ synaptics_rmi4_fwu_remove,
+ synaptics_rmi4_fwu_attn);
+ return 0;
+}
+
+static void __exit rmi4_fw_update_module_exit(void)
+{
+ init_completion(&remove_complete);
+ synaptics_rmi4_new_function(RMI_FW_UPDATER, false,
+ synaptics_rmi4_fwu_init,
+ synaptics_rmi4_fwu_remove,
+ synaptics_rmi4_fwu_attn);
+ wait_for_completion(&remove_complete);
+ return;
+}
+
+module_init(rmi4_fw_update_module_init);
+module_exit(rmi4_fw_update_module_exit);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("RMI4 FW Update Module");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SYNAPTICS_RMI4_DRIVER_VERSION);
diff --git a/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.c
new file mode 100644
index 000000000000..85530225abd2
--- /dev/null
+++ b/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -0,0 +1,2110 @@
+/*
+ * Synaptics RMI4 touchscreen driver
+ *
+ * Copyright (C) 2012 Synaptics Incorporated
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/input/synaptics_dsx.h>
+#include "synaptics_i2c_rmi4.h"
+#ifdef KERNEL_ABOVE_2_6_38
+#include <linux/input/mt.h>
+#endif
+
+#define DRIVER_NAME "synaptics_rmi4_i2c"
+#define INPUT_PHYS_NAME "synaptics_rmi4_i2c/input0"
+
+#ifdef KERNEL_ABOVE_2_6_38
+#define TYPE_B_PROTOCOL
+#endif
+
+#define NO_0D_WHILE_2D
+/*
+#define REPORT_2D_Z
+*/
+#define REPORT_2D_W
+
+#define RPT_TYPE (1 << 0)
+#define RPT_X_LSB (1 << 1)
+#define RPT_X_MSB (1 << 2)
+#define RPT_Y_LSB (1 << 3)
+#define RPT_Y_MSB (1 << 4)
+#define RPT_Z (1 << 5)
+#define RPT_WX (1 << 6)
+#define RPT_WY (1 << 7)
+#define RPT_DEFAULT (RPT_TYPE | RPT_X_LSB | RPT_X_MSB | RPT_Y_LSB | RPT_Y_MSB)
+
+#define EXP_FN_DET_INTERVAL 1000 /* ms */
+#define POLLING_PERIOD 1 /* ms */
+#define SYN_I2C_RETRY_TIMES 10
+#define MAX_ABS_MT_TOUCH_MAJOR 15
+
+#define F01_STD_QUERY_LEN 21
+#define F01_BUID_ID_OFFSET 18
+#define F11_STD_QUERY_LEN 9
+#define F11_STD_CTRL_LEN 10
+#define F11_STD_DATA_LEN 12
+
+#define NORMAL_OPERATION (0 << 0)
+#define SENSOR_SLEEP (1 << 0)
+#define NO_SLEEP_OFF (0 << 3)
+#define NO_SLEEP_ON (1 << 3)
+
+static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr, unsigned char *data,
+ unsigned short length);
+
+static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr, unsigned char *data,
+ unsigned short length);
+
+static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data);
+
+#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);
+
+static void synaptics_rmi4_early_suspend(struct early_suspend *h);
+
+static void synaptics_rmi4_late_resume(struct early_suspend *h);
+
+static int synaptics_rmi4_suspend(struct device *dev);
+
+static int synaptics_rmi4_resume(struct device *dev);
+#endif
+
+static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+struct synaptics_rmi4_f01_device_status {
+ union {
+ struct {
+ unsigned char status_code:4;
+ unsigned char reserved:2;
+ unsigned char flash_prog:1;
+ unsigned char unconfigured:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct synaptics_rmi4_f1a_query {
+ union {
+ struct {
+ unsigned char max_button_count:3;
+ unsigned char reserved:5;
+ unsigned char has_general_control:1;
+ unsigned char has_interrupt_enable:1;
+ unsigned char has_multibutton_select:1;
+ unsigned char has_tx_rx_map:1;
+ unsigned char has_perbutton_threshold:1;
+ unsigned char has_release_threshold:1;
+ unsigned char has_strongestbtn_hysteresis:1;
+ unsigned char has_filter_strength:1;
+ } __packed;
+ unsigned char data[2];
+ };
+};
+
+struct synaptics_rmi4_f1a_control_0 {
+ union {
+ struct {
+ unsigned char multibutton_report:2;
+ unsigned char filter_mode:2;
+ unsigned char reserved:4;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct synaptics_rmi4_f1a_control_3_4 {
+ unsigned char transmitterbutton;
+ unsigned char receiverbutton;
+};
+
+struct synaptics_rmi4_f1a_control {
+ struct synaptics_rmi4_f1a_control_0 general_control;
+ unsigned char *button_int_enable;
+ unsigned char *multi_button;
+ struct synaptics_rmi4_f1a_control_3_4 *electrode_map;
+ unsigned char *button_threshold;
+ unsigned char button_release_threshold;
+ unsigned char strongest_button_hysteresis;
+ unsigned char filter_strength;
+};
+
+struct synaptics_rmi4_f1a_handle {
+ int button_bitmask_size;
+ unsigned char button_count;
+ unsigned char valid_button_count;
+ unsigned char *button_data_buffer;
+ unsigned char *button_map;
+ struct synaptics_rmi4_f1a_query button_query;
+ struct synaptics_rmi4_f1a_control button_control;
+};
+
+struct synaptics_rmi4_exp_fn {
+ enum exp_fn fn_type;
+ bool inserted;
+ int (*func_init)(struct synaptics_rmi4_data *rmi4_data);
+ void (*func_remove)(struct synaptics_rmi4_data *rmi4_data);
+ void (*func_attn)(struct synaptics_rmi4_data *rmi4_data,
+ unsigned char intr_mask);
+ struct list_head link;
+};
+
+static struct device_attribute attrs[] = {
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ __ATTR(full_pm_cycle, (S_IRUGO | S_IWUGO),
+ synaptics_rmi4_full_pm_cycle_show,
+ synaptics_rmi4_full_pm_cycle_store),
+#endif
+ __ATTR(reset, S_IWUGO,
+ synaptics_rmi4_show_error,
+ synaptics_rmi4_f01_reset_store),
+ __ATTR(productinfo, S_IRUGO,
+ synaptics_rmi4_f01_productinfo_show,
+ synaptics_rmi4_store_error),
+ __ATTR(buildid, S_IRUGO,
+ synaptics_rmi4_f01_buildid_show,
+ synaptics_rmi4_store_error),
+ __ATTR(flashprog, S_IRUGO,
+ synaptics_rmi4_f01_flashprog_show,
+ synaptics_rmi4_store_error),
+ __ATTR(0dbutton, (S_IRUGO | S_IWUGO),
+ synaptics_rmi4_0dbutton_show,
+ synaptics_rmi4_0dbutton_store),
+};
+
+static bool exp_fn_inited;
+static struct mutex exp_fn_list_mutex;
+static struct list_head exp_fn_list;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ rmi4_data->full_pm_cycle);
+}
+
+static ssize_t synaptics_rmi4_full_pm_cycle_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ rmi4_data->full_pm_cycle = input > 0 ? 1 : 0;
+
+ return count;
+}
+#endif
+
+static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned int reset;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%u", &reset) != 1)
+ return -EINVAL;
+
+ if (reset != 1)
+ return -EINVAL;
+
+ retval = synaptics_rmi4_reset_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(dev,
+ "%s: Failed to issue reset command, error = %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ return count;
+}
+
+static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "0x%02x 0x%02x\n",
+ (rmi4_data->rmi4_mod_info.product_info[0]),
+ (rmi4_data->rmi4_mod_info.product_info[1]));
+}
+
+static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int build_id;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ build_id = (unsigned int)rmi->build_id[0] +
+ (unsigned int)rmi->build_id[1] * 0x100 +
+ (unsigned int)rmi->build_id[2] * 0x10000;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ build_id);
+}
+
+static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int retval;
+ struct synaptics_rmi4_f01_device_status device_status;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_data_base_addr,
+ device_status.data,
+ sizeof(device_status.data));
+ if (retval < 0) {
+ dev_err(dev,
+ "%s: Failed to read device status, error = %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ device_status.flash_prog);
+}
+
+static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ rmi4_data->button_0d_enabled);
+}
+
+static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned int input;
+ unsigned char ii;
+ unsigned char intr_enable;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ input = input > 0 ? 1 : 0;
+
+ if (rmi4_data->button_0d_enabled == input)
+ return count;
+
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
+ ii = fhandler->intr_reg_num;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr + 1 + ii,
+ &intr_enable,
+ sizeof(intr_enable));
+ if (retval < 0)
+ return retval;
+
+ if (input == 1)
+ intr_enable |= fhandler->intr_mask;
+ else
+ intr_enable &= ~fhandler->intr_mask;
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr + 1 + ii,
+ &intr_enable,
+ sizeof(intr_enable));
+ if (retval < 0)
+ return retval;
+ }
+ }
+
+ rmi4_data->button_0d_enabled = input;
+
+ return count;
+}
+
+ /**
+ * synaptics_rmi4_set_page()
+ *
+ * Called by synaptics_rmi4_i2c_read() and synaptics_rmi4_i2c_write().
+ *
+ * This function writes to the page select register to switch to the
+ * assigned page.
+ */
+static int synaptics_rmi4_set_page(struct synaptics_rmi4_data *rmi4_data,
+ unsigned int address)
+{
+ int retval = 0;
+ unsigned char retry;
+ unsigned char buf[PAGE_SELECT_LEN];
+ unsigned char page;
+ struct i2c_client *i2c = rmi4_data->i2c_client;
+
+ page = ((address >> 8) & MASK_8BIT);
+ if (page != rmi4_data->current_page) {
+ buf[0] = MASK_8BIT;
+ buf[1] = page;
+ for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+ retval = i2c_master_send(i2c, buf, PAGE_SELECT_LEN);
+ if (retval != PAGE_SELECT_LEN) {
+ dev_err(&i2c->dev,
+ "%s: I2C retry %d\n",
+ __func__, retry + 1);
+ msleep(20);
+ } else {
+ rmi4_data->current_page = page;
+ break;
+ }
+ }
+ } else
+ return PAGE_SELECT_LEN;
+ return (retval == PAGE_SELECT_LEN) ? retval : -EIO;
+}
+
+ /**
+ * synaptics_rmi4_i2c_read()
+ *
+ * Called by various functions in this driver, and also exported to
+ * other expansion Function modules such as rmi_dev.
+ *
+ * This function reads data of an arbitrary length from the sensor,
+ * starting from an assigned register address of the sensor, via I2C
+ * with a retry mechanism.
+ */
+static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr, unsigned char *data, unsigned short length)
+{
+ int retval;
+ unsigned char retry;
+ unsigned char buf;
+ struct i2c_msg msg[] = {
+ {
+ .addr = rmi4_data->i2c_client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &buf,
+ },
+ {
+ .addr = rmi4_data->i2c_client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = data,
+ },
+ };
+
+ buf = addr & MASK_8BIT;
+
+ mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ retval = synaptics_rmi4_set_page(rmi4_data, addr);
+ if (retval != PAGE_SELECT_LEN)
+ goto exit;
+
+ for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+ if (i2c_transfer(rmi4_data->i2c_client->adapter, msg, 2) == 2) {
+ retval = length;
+ break;
+ }
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: I2C retry %d\n",
+ __func__, retry + 1);
+ msleep(20);
+ }
+
+ if (retry == SYN_I2C_RETRY_TIMES) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: I2C read over retry limit\n",
+ __func__);
+ retval = -EIO;
+ }
+
+exit:
+ mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ return retval;
+}
+
+ /**
+ * synaptics_rmi4_i2c_write()
+ *
+ * Called by various functions in this driver, and also exported to
+ * other expansion Function modules such as rmi_dev.
+ *
+ * This function writes data of an arbitrary length to the sensor,
+ * starting from an assigned register address of the sensor, via I2C with
+ * a retry mechanism.
+ */
+static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr, unsigned char *data, unsigned short length)
+{
+ int retval;
+ unsigned char retry;
+ unsigned char buf[length + 1];
+ struct i2c_msg msg[] = {
+ {
+ .addr = rmi4_data->i2c_client->addr,
+ .flags = 0,
+ .len = length + 1,
+ .buf = buf,
+ }
+ };
+
+ mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ retval = synaptics_rmi4_set_page(rmi4_data, addr);
+ if (retval != PAGE_SELECT_LEN)
+ goto exit;
+
+ buf[0] = addr & MASK_8BIT;
+ memcpy(&buf[1], &data[0], length);
+
+ for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+ if (i2c_transfer(rmi4_data->i2c_client->adapter, msg, 1) == 1) {
+ retval = length;
+ break;
+ }
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: I2C retry %d\n",
+ __func__, retry + 1);
+ msleep(20);
+ }
+
+ if (retry == SYN_I2C_RETRY_TIMES) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: I2C write over retry limit\n",
+ __func__);
+ retval = -EIO;
+ }
+
+exit:
+ mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ return retval;
+}
+
+ /**
+ * synaptics_rmi4_f11_abs_report()
+ *
+ * Called by synaptics_rmi4_report_touch() when valid Function $11
+ * finger data has been detected.
+ *
+ * This function reads the Function $11 data registers, determines the
+ * status of each finger supported by the Function, processes any
+ * necessary coordinate manipulation, reports the finger data to
+ * the input subsystem, and returns the number of fingers detected.
+ */
+static int synaptics_rmi4_f11_abs_report(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int retval;
+ unsigned char touch_count = 0; /* number of touch points */
+ unsigned char reg_index;
+ unsigned char finger;
+ unsigned char fingers_supported;
+ unsigned char num_of_finger_status_regs;
+ unsigned char finger_shift;
+ unsigned char finger_status;
+ unsigned char data_reg_blk_size;
+ unsigned char finger_status_reg[3];
+ unsigned char data[F11_STD_DATA_LEN];
+ unsigned short data_addr;
+ unsigned short data_offset;
+ int x;
+ int y;
+ int wx;
+ int wy;
+
+ /*
+ * The number of finger status registers is determined by the
+ * maximum number of fingers supported - 2 bits per finger. So
+ * the number of finger status registers to read is:
+ * register_count = ceil(max_num_of_fingers / 4)
+ */
+ fingers_supported = fhandler->num_of_data_points;
+ num_of_finger_status_regs = (fingers_supported + 3) / 4;
+ data_addr = fhandler->full_addr.data_base;
+ data_reg_blk_size = fhandler->size_of_data_register_block;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_addr,
+ finger_status_reg,
+ num_of_finger_status_regs);
+ if (retval < 0)
+ return 0;
+
+ for (finger = 0; finger < fingers_supported; finger++) {
+ reg_index = finger / 4;
+ finger_shift = (finger % 4) * 2;
+ finger_status = (finger_status_reg[reg_index] >> finger_shift)
+ & MASK_2BIT;
+
+ /*
+ * Each 2-bit finger status field represents the following:
+ * 00 = finger not present
+ * 01 = finger present and data accurate
+ * 10 = finger present but data may be inaccurate
+ * 11 = reserved
+ */
+#ifdef TYPE_B_PROTOCOL
+ input_mt_slot(rmi4_data->input_dev, finger);
+ input_mt_report_slot_state(rmi4_data->input_dev,
+ MT_TOOL_FINGER, finger_status != 0);
+#endif
+
+ if (finger_status) {
+ data_offset = data_addr +
+ num_of_finger_status_regs +
+ (finger * data_reg_blk_size);
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_offset,
+ data,
+ data_reg_blk_size);
+ if (retval < 0)
+ return 0;
+
+ x = (data[0] << 4) | (data[2] & MASK_4BIT);
+ y = (data[1] << 4) | ((data[2] >> 4) & MASK_4BIT);
+ wx = (data[3] & MASK_4BIT);
+ wy = (data[3] >> 4) & MASK_4BIT;
+
+ if (rmi4_data->board->x_flip)
+ x = rmi4_data->sensor_max_x - x;
+ if (rmi4_data->board->y_flip)
+ y = rmi4_data->sensor_max_y - y;
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Finger %d:\n"
+ "status = 0x%02x\n"
+ "x = %d\n"
+ "y = %d\n"
+ "wx = %d\n"
+ "wy = %d\n",
+ __func__, finger,
+ finger_status,
+ x, y, wx, wy);
+
+#ifdef TYPE_B_PROTOCOL
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_POSITION_X, x);
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_POSITION_Y, y);
+#ifdef REPORT_2D_W
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MAJOR, max(wx, wy));
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MINOR, min(wx, wy));
+#endif
+#else
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_POSITION_X, x);
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_POSITION_Y, y);
+#ifdef REPORT_2D_W
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MAJOR, max(wx, wy));
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MINOR, min(wx, wy));
+#endif
+ input_mt_sync(rmi4_data->input_dev);
+#endif
+ touch_count++;
+ }
+ }
+
+#ifndef TYPE_B_PROTOCOL
+ if (!touch_count)
+ input_mt_sync(rmi4_data->input_dev);
+#else
+ /* sync after groups of events */
+ #ifdef KERNEL_ABOVE_3_7
+ input_mt_sync_frame(rmi4_data->input_dev);
+ #endif
+#endif
+
+ input_sync(rmi4_data->input_dev);
+
+ return touch_count;
+}
+
+static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int retval;
+ unsigned char button;
+ unsigned char index;
+ unsigned char shift;
+ unsigned char status;
+ unsigned char *data;
+ unsigned short data_addr = fhandler->full_addr.data_base;
+ struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
+ static unsigned char do_once = 1;
+ static bool current_status[MAX_NUMBER_OF_BUTTONS];
+#ifdef NO_0D_WHILE_2D
+ static bool before_2d_status[MAX_NUMBER_OF_BUTTONS];
+ static bool while_2d_status[MAX_NUMBER_OF_BUTTONS];
+#endif
+
+ if (do_once) {
+ memset(current_status, 0, sizeof(current_status));
+#ifdef NO_0D_WHILE_2D
+ memset(before_2d_status, 0, sizeof(before_2d_status));
+ memset(while_2d_status, 0, sizeof(while_2d_status));
+#endif
+ do_once = 0;
+ }
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_addr,
+ f1a->button_data_buffer,
+ f1a->button_bitmask_size);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read button data registers\n",
+ __func__);
+ return;
+ }
+
+ data = f1a->button_data_buffer;
+
+ for (button = 0; button < f1a->valid_button_count; button++) {
+ index = button / 8;
+ shift = button % 8;
+ status = ((data[index] >> shift) & MASK_1BIT);
+
+ if (current_status[button] == status)
+ continue;
+ else
+ current_status[button] = status;
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Button %d (code %d) ->%d\n",
+ __func__, button,
+ f1a->button_map[button],
+ status);
+#ifdef NO_0D_WHILE_2D
+ if (rmi4_data->fingers_on_2d == false) {
+ if (status == 1) {
+ before_2d_status[button] = 1;
+ } else {
+ if (while_2d_status[button] == 1) {
+ while_2d_status[button] = 0;
+ continue;
+ } else {
+ before_2d_status[button] = 0;
+ }
+ }
+ input_report_key(rmi4_data->input_dev,
+ f1a->button_map[button],
+ status);
+ } else {
+ if (before_2d_status[button] == 1) {
+ before_2d_status[button] = 0;
+ input_report_key(rmi4_data->input_dev,
+ f1a->button_map[button],
+ status);
+ } else {
+ if (status == 1)
+ while_2d_status[button] = 1;
+ else
+ while_2d_status[button] = 0;
+ }
+ }
+#else
+ input_report_key(rmi4_data->input_dev,
+ f1a->button_map[button],
+ status);
+#endif
+ }
+
+ input_sync(rmi4_data->input_dev);
+
+ return;
+}
+
+ /**
+ * synaptics_rmi4_report_touch()
+ *
+ * Called by synaptics_rmi4_sensor_report().
+ *
+ * This function calls the appropriate finger data reporting function
+ * based on the function handler it receives and returns the number of
+ * fingers detected.
+ */
+static void synaptics_rmi4_report_touch(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler,
+ unsigned char *touch_count)
+{
+ unsigned char touch_count_2d;
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Function %02x reporting\n",
+ __func__, fhandler->fn_number);
+
+ switch (fhandler->fn_number) {
+ case SYNAPTICS_RMI4_F11:
+ touch_count_2d = synaptics_rmi4_f11_abs_report(rmi4_data,
+ fhandler);
+
+ *touch_count += touch_count_2d;
+
+ if (touch_count_2d)
+ rmi4_data->fingers_on_2d = true;
+ else
+ rmi4_data->fingers_on_2d = false;
+ break;
+
+ case SYNAPTICS_RMI4_F1A:
+ synaptics_rmi4_f1a_report(rmi4_data, fhandler);
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+ /**
+ * synaptics_rmi4_sensor_report()
+ *
+ * Called by synaptics_rmi4_irq().
+ *
+ * This function determines the interrupt source(s) from the sensor
+ * and calls synaptics_rmi4_report_touch() with the appropriate
+ * function handler for each function with valid data inputs.
+ */
+static int synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char touch_count = 0;
+ unsigned char intr[MAX_INTR_REGISTERS];
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_exp_fn *exp_fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ /*
+ * Get interrupt status information from F01 Data1 register to
+ * determine the source(s) that are flagging the interrupt.
+ */
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_data_base_addr + 1,
+ intr,
+ rmi4_data->num_of_intr_regs);
+ if (retval < 0)
+ return retval;
+
+ /*
+ * Traverse the function handler list and service the source(s)
+ * of the interrupt accordingly.
+ */
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->num_of_data_sources) {
+ if (fhandler->intr_mask &
+ intr[fhandler->intr_reg_num]) {
+ synaptics_rmi4_report_touch(rmi4_data,
+ fhandler, &touch_count);
+ }
+ }
+ }
+
+ mutex_lock(&exp_fn_list_mutex);
+ if (!list_empty(&exp_fn_list)) {
+ list_for_each_entry(exp_fhandler, &exp_fn_list, link) {
+ if (exp_fhandler->inserted &&
+ (exp_fhandler->func_attn != NULL))
+ exp_fhandler->func_attn(rmi4_data, intr[0]);
+ }
+ }
+ mutex_unlock(&exp_fn_list_mutex);
+
+ return touch_count;
+}
+
+ /**
+ * synaptics_rmi4_irq()
+ *
+ * Called by the kernel when an interrupt occurs (when the sensor
+ * asserts the attention irq).
+ *
+ * This function is the ISR thread and handles the acquisition
+ * and the reporting of finger data when the presence of fingers
+ * is detected.
+ */
+static irqreturn_t synaptics_rmi4_irq(int irq, void *data)
+{
+ struct synaptics_rmi4_data *rmi4_data = data;
+
+ synaptics_rmi4_sensor_report(rmi4_data);
+
+ return IRQ_HANDLED;
+}
+
+ /**
+ * synaptics_rmi4_irq_enable()
+ *
+ * Called by synaptics_rmi4_probe() and the power management functions
+ * in this driver and also exported to other expansion Function modules
+ * such as rmi_dev.
+ *
+ * This function handles the enabling and disabling of the attention
+ * irq including the setting up of the ISR thread.
+ */
+static int synaptics_rmi4_irq_enable(struct synaptics_rmi4_data *rmi4_data,
+ bool enable)
+{
+ int retval = 0;
+ unsigned char intr_status;
+ const struct synaptics_rmi4_platform_data *platform_data =
+ rmi4_data->i2c_client->dev.platform_data;
+
+ if (enable) {
+ if (rmi4_data->irq_enabled)
+ return retval;
+
+ /* Clear interrupts first */
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_data_base_addr + 1,
+ &intr_status,
+ rmi4_data->num_of_intr_regs);
+ if (retval < 0)
+ return retval;
+
+ retval = request_threaded_irq(rmi4_data->irq, NULL,
+ synaptics_rmi4_irq, platform_data->irq_flags,
+ DRIVER_NAME, rmi4_data);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create irq thread\n",
+ __func__);
+ return retval;
+ }
+
+ rmi4_data->irq_enabled = true;
+ } else {
+ if (rmi4_data->irq_enabled) {
+ disable_irq(rmi4_data->irq);
+ free_irq(rmi4_data->irq, rmi4_data);
+ rmi4_data->irq_enabled = false;
+ }
+ }
+
+ return retval;
+}
+
+ /**
+ * synaptics_rmi4_f11_init()
+ *
+ * Called by synaptics_rmi4_query_device().
+ *
+ * This funtion parses information from the Function 11 registers
+ * and determines the number of fingers supported, x and y data ranges,
+ * offset to the associated interrupt status register, interrupt bit
+ * mask, and gathers finger data acquisition capabilities from the query
+ * registers.
+ */
+static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int intr_count)
+{
+ int retval;
+ unsigned char ii;
+ unsigned char intr_offset;
+ unsigned char abs_data_size;
+ unsigned char abs_data_blk_size;
+ unsigned char query[F11_STD_QUERY_LEN];
+ unsigned char control[F11_STD_CTRL_LEN];
+
+ fhandler->fn_number = fd->fn_number;
+ fhandler->num_of_data_sources = fd->intr_src_count;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base,
+ query,
+ sizeof(query));
+ if (retval < 0)
+ return retval;
+
+ /* Maximum number of fingers supported */
+ if ((query[1] & MASK_3BIT) <= 4)
+ fhandler->num_of_data_points = (query[1] & MASK_3BIT) + 1;
+ else if ((query[1] & MASK_3BIT) == 5)
+ fhandler->num_of_data_points = 10;
+
+ rmi4_data->num_of_fingers = fhandler->num_of_data_points;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.ctrl_base,
+ control,
+ sizeof(control));
+ if (retval < 0)
+ return retval;
+
+ /* Maximum x and y */
+ rmi4_data->sensor_max_x = ((control[6] & MASK_8BIT) << 0) |
+ ((control[7] & MASK_4BIT) << 8);
+ rmi4_data->sensor_max_y = ((control[8] & MASK_8BIT) << 0) |
+ ((control[9] & MASK_4BIT) << 8);
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Function %02x max x = %d max y = %d\n",
+ __func__, fhandler->fn_number,
+ rmi4_data->sensor_max_x,
+ rmi4_data->sensor_max_y);
+
+ fhandler->intr_reg_num = (intr_count + 7) / 8;
+ if (fhandler->intr_reg_num != 0)
+ fhandler->intr_reg_num -= 1;
+
+ /* Set an enable bit for each data source */
+ intr_offset = intr_count % 8;
+ fhandler->intr_mask = 0;
+ for (ii = intr_offset;
+ ii < ((fd->intr_src_count & MASK_3BIT) +
+ intr_offset);
+ ii++)
+ fhandler->intr_mask |= 1 << ii;
+
+ abs_data_size = query[5] & MASK_2BIT;
+ abs_data_blk_size = 3 + (2 * (abs_data_size == 0 ? 1 : 0));
+ fhandler->size_of_data_register_block = abs_data_blk_size;
+
+ return retval;
+}
+
+static int synaptics_rmi4_f1a_alloc_mem(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int retval;
+ struct synaptics_rmi4_f1a_handle *f1a;
+
+ f1a = kzalloc(sizeof(*f1a), GFP_KERNEL);
+ if (!f1a) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for function handle\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ fhandler->data = (void *)f1a;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base,
+ f1a->button_query.data,
+ sizeof(f1a->button_query.data));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read query registers\n",
+ __func__);
+ return retval;
+ }
+
+ f1a->button_count = f1a->button_query.max_button_count + 1;
+ f1a->button_bitmask_size = (f1a->button_count + 7) / 8;
+
+ f1a->button_data_buffer = kcalloc(f1a->button_bitmask_size,
+ sizeof(*(f1a->button_data_buffer)), GFP_KERNEL);
+ if (!f1a->button_data_buffer) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for data buffer\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ f1a->button_map = kcalloc(f1a->button_count,
+ sizeof(*(f1a->button_map)), GFP_KERNEL);
+ if (!f1a->button_map) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for button map\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int synaptics_rmi4_capacitance_button_map(
+ struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ unsigned char ii;
+ struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
+ const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
+
+ if (!pdata->capacitance_button_map) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: capacitance_button_map is \
+ NULL in board file\n",
+ __func__);
+ return -ENODEV;
+ } else if (!pdata->capacitance_button_map->map) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Button map is missing in board file\n",
+ __func__);
+ return -ENODEV;
+ } else {
+ if (pdata->capacitance_button_map->nbuttons !=
+ f1a->button_count) {
+ f1a->valid_button_count = min(f1a->button_count,
+ pdata->capacitance_button_map->nbuttons);
+ } else {
+ f1a->valid_button_count = f1a->button_count;
+ }
+
+ for (ii = 0; ii < f1a->valid_button_count; ii++)
+ f1a->button_map[ii] =
+ pdata->capacitance_button_map->map[ii];
+ }
+
+ return 0;
+}
+
+static void synaptics_rmi4_f1a_kfree(struct synaptics_rmi4_fn *fhandler)
+{
+ struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
+
+ if (f1a) {
+ kfree(f1a->button_data_buffer);
+ kfree(f1a->button_map);
+ kfree(f1a);
+ fhandler->data = NULL;
+ }
+
+ return;
+}
+
+static int synaptics_rmi4_f1a_init(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int intr_count)
+{
+ int retval;
+ unsigned char ii;
+ unsigned short intr_offset;
+
+ fhandler->fn_number = fd->fn_number;
+ fhandler->num_of_data_sources = fd->intr_src_count;
+
+ fhandler->intr_reg_num = (intr_count + 7) / 8;
+ if (fhandler->intr_reg_num != 0)
+ fhandler->intr_reg_num -= 1;
+
+ /* Set an enable bit for each data source */
+ intr_offset = intr_count % 8;
+ fhandler->intr_mask = 0;
+ for (ii = intr_offset;
+ ii < ((fd->intr_src_count & MASK_3BIT) +
+ intr_offset);
+ ii++)
+ fhandler->intr_mask |= 1 << ii;
+
+ retval = synaptics_rmi4_f1a_alloc_mem(rmi4_data, fhandler);
+ if (retval < 0)
+ goto error_exit;
+
+ retval = synaptics_rmi4_capacitance_button_map(rmi4_data, fhandler);
+ if (retval < 0)
+ goto error_exit;
+
+ rmi4_data->button_0d_enabled = 1;
+
+ return 0;
+
+error_exit:
+ synaptics_rmi4_f1a_kfree(fhandler);
+
+ return retval;
+}
+
+static int synaptics_rmi4_alloc_fh(struct synaptics_rmi4_fn **fhandler,
+ struct synaptics_rmi4_fn_desc *rmi_fd, int page_number)
+{
+ *fhandler = kmalloc(sizeof(**fhandler), GFP_KERNEL);
+ if (!(*fhandler))
+ return -ENOMEM;
+
+ (*fhandler)->full_addr.data_base =
+ (rmi_fd->data_base_addr |
+ (page_number << 8));
+ (*fhandler)->full_addr.ctrl_base =
+ (rmi_fd->ctrl_base_addr |
+ (page_number << 8));
+ (*fhandler)->full_addr.cmd_base =
+ (rmi_fd->cmd_base_addr |
+ (page_number << 8));
+ (*fhandler)->full_addr.query_base =
+ (rmi_fd->query_base_addr |
+ (page_number << 8));
+
+ return 0;
+}
+
+ /**
+ * synaptics_rmi4_query_device()
+ *
+ * Called by synaptics_rmi4_probe().
+ *
+ * This funtion scans the page description table, records the offsets
+ * to the register types of Function $01, sets up the function handlers
+ * for Function $11 and Function $12, determines the number of interrupt
+ * sources from the sensor, adds valid Functions with data inputs to the
+ * Function linked list, parses information from the query registers of
+ * Function $01, and enables the interrupt sources from the valid Functions
+ * with data inputs.
+ */
+static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char ii;
+ unsigned char page_number;
+ unsigned char intr_count = 0;
+ unsigned char data_sources = 0;
+ unsigned char f01_query[F01_STD_QUERY_LEN];
+ unsigned short pdt_entry_addr;
+ unsigned short intr_addr;
+ struct synaptics_rmi4_f01_device_status status;
+ struct synaptics_rmi4_fn_desc rmi_fd;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ INIT_LIST_HEAD(&rmi->support_fn_list);
+
+ /* Scan the page description tables of the pages to service */
+ for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) {
+ for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END;
+ pdt_entry_addr -= PDT_ENTRY_SIZE) {
+ pdt_entry_addr |= (page_number << 8);
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ pdt_entry_addr,
+ (unsigned char *)&rmi_fd,
+ sizeof(rmi_fd));
+ if (retval < 0)
+ return retval;
+
+ fhandler = NULL;
+
+ if (rmi_fd.fn_number == 0) {
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Reached end of PDT\n",
+ __func__);
+ break;
+ }
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: F%02x found (page %d)\n",
+ __func__, rmi_fd.fn_number,
+ page_number);
+
+ switch (rmi_fd.fn_number) {
+ case SYNAPTICS_RMI4_F01:
+ rmi4_data->f01_query_base_addr =
+ rmi_fd.query_base_addr;
+ rmi4_data->f01_ctrl_base_addr =
+ rmi_fd.ctrl_base_addr;
+ rmi4_data->f01_data_base_addr =
+ rmi_fd.data_base_addr;
+ rmi4_data->f01_cmd_base_addr =
+ rmi_fd.cmd_base_addr;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_data_base_addr,
+ status.data,
+ sizeof(status.data));
+ if (retval < 0)
+ return retval;
+
+ if (status.flash_prog == 1) {
+ pr_notice("%s: In flash prog mode, status = 0x%02x\n",
+ __func__,
+ status.status_code);
+ goto flash_prog_mode;
+ }
+ break;
+ case SYNAPTICS_RMI4_F11:
+ if (rmi_fd.intr_src_count == 0)
+ break;
+
+ retval = synaptics_rmi4_alloc_fh(&fhandler,
+ &rmi_fd, page_number);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc for F%d\n",
+ __func__,
+ rmi_fd.fn_number);
+ return retval;
+ }
+
+ retval = synaptics_rmi4_f11_init(rmi4_data,
+ fhandler, &rmi_fd, intr_count);
+ if (retval < 0)
+ return retval;
+ break;
+
+ case SYNAPTICS_RMI4_F1A:
+ if (rmi_fd.intr_src_count == 0)
+ break;
+
+ retval = synaptics_rmi4_alloc_fh(&fhandler,
+ &rmi_fd, page_number);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc for F%d\n",
+ __func__,
+ rmi_fd.fn_number);
+ return retval;
+ }
+
+ retval = synaptics_rmi4_f1a_init(rmi4_data,
+ fhandler, &rmi_fd, intr_count);
+ if (retval < 0)
+ return retval;
+ break;
+ }
+
+ /* Accumulate the interrupt count */
+ intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
+
+ if (fhandler && rmi_fd.intr_src_count) {
+ list_add_tail(&fhandler->link,
+ &rmi->support_fn_list);
+ }
+ }
+ }
+
+flash_prog_mode:
+ rmi4_data->num_of_intr_regs = (intr_count + 7) / 8;
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Number of interrupt registers = %d\n",
+ __func__, rmi4_data->num_of_intr_regs);
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_query_base_addr,
+ f01_query,
+ sizeof(f01_query));
+ if (retval < 0)
+ return retval;
+
+ /* RMI Version 4.0 currently supported */
+ rmi->version_major = 4;
+ rmi->version_minor = 0;
+
+ rmi->manufacturer_id = f01_query[0];
+ rmi->product_props = f01_query[1];
+ rmi->product_info[0] = f01_query[2] & MASK_7BIT;
+ rmi->product_info[1] = f01_query[3] & MASK_7BIT;
+ rmi->date_code[0] = f01_query[4] & MASK_5BIT;
+ rmi->date_code[1] = f01_query[5] & MASK_4BIT;
+ rmi->date_code[2] = f01_query[6] & MASK_5BIT;
+ rmi->tester_id = ((f01_query[7] & MASK_7BIT) << 8) |
+ (f01_query[8] & MASK_7BIT);
+ rmi->serial_number = ((f01_query[9] & MASK_7BIT) << 8) |
+ (f01_query[10] & MASK_7BIT);
+ memcpy(rmi->product_id_string, &f01_query[11], 10);
+
+ if (rmi->manufacturer_id != 1) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Non-Synaptics device found, manufacturer ID = %d\n",
+ __func__, rmi->manufacturer_id);
+ }
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_query_base_addr + F01_BUID_ID_OFFSET,
+ rmi->build_id,
+ sizeof(rmi->build_id));
+ if (retval < 0)
+ return retval;
+
+ memset(rmi4_data->intr_mask, 0x00, sizeof(rmi4_data->intr_mask));
+
+ /*
+ * Map out the interrupt bit masks for the interrupt sources
+ * from the registered function handlers.
+ */
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link)
+ data_sources += fhandler->num_of_data_sources;
+ if (data_sources) {
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->num_of_data_sources) {
+ rmi4_data->intr_mask[fhandler->intr_reg_num] |=
+ fhandler->intr_mask;
+ }
+ }
+ }
+
+ /* Enable the interrupt sources */
+ for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) {
+ if (rmi4_data->intr_mask[ii] != 0x00) {
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Interrupt enable mask %d = 0x%02x\n",
+ __func__, ii, rmi4_data->intr_mask[ii]);
+ intr_addr = rmi4_data->f01_ctrl_base_addr + 1 + ii;
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ intr_addr,
+ &(rmi4_data->intr_mask[ii]),
+ sizeof(rmi4_data->intr_mask[ii]));
+ if (retval < 0)
+ return retval;
+ }
+ }
+
+ return 0;
+}
+
+static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char command = 0x01;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ rmi4_data->f01_cmd_base_addr,
+ &command,
+ sizeof(command));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to issue reset command, error = %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ msleep(100);
+
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
+ synaptics_rmi4_f1a_kfree(fhandler);
+ else
+ kfree(fhandler->data);
+ kfree(fhandler);
+ }
+
+ retval = synaptics_rmi4_query_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to query device\n",
+ __func__);
+ return retval;
+ }
+
+ return 0;
+}
+
+/**
+* synaptics_rmi4_detection_work()
+*
+* Called by the kernel at the scheduled time.
+*
+* This function is a self-rearming work thread that checks for the
+* insertion and removal of other expansion Function modules such as
+* rmi_dev and calls their initialization and removal callback functions
+* accordingly.
+*/
+static void synaptics_rmi4_detection_work(struct work_struct *work)
+{
+ struct synaptics_rmi4_exp_fn *exp_fhandler, *next_list_entry;
+ struct synaptics_rmi4_data *rmi4_data =
+ container_of(work, struct synaptics_rmi4_data,
+ det_work.work);
+
+ queue_delayed_work(rmi4_data->det_workqueue,
+ &rmi4_data->det_work,
+ msecs_to_jiffies(EXP_FN_DET_INTERVAL));
+
+ mutex_lock(&exp_fn_list_mutex);
+ if (!list_empty(&exp_fn_list)) {
+ list_for_each_entry_safe(exp_fhandler,
+ next_list_entry,
+ &exp_fn_list,
+ link) {
+ if ((exp_fhandler->func_init != NULL) &&
+ (exp_fhandler->inserted == false)) {
+ exp_fhandler->func_init(rmi4_data);
+ exp_fhandler->inserted = true;
+ } else if ((exp_fhandler->func_init == NULL) &&
+ (exp_fhandler->inserted == true)) {
+ exp_fhandler->func_remove(rmi4_data);
+ list_del(&exp_fhandler->link);
+ kfree(exp_fhandler);
+ }
+ }
+ }
+ mutex_unlock(&exp_fn_list_mutex);
+
+ return;
+}
+
+/**
+* synaptics_rmi4_new_function()
+*
+* Called by other expansion Function modules in their module init and
+* module exit functions.
+*
+* This function is used by other expansion Function modules such as
+* rmi_dev to register themselves with the driver by providing their
+* initialization and removal callback function pointers so that they
+* can be inserted or removed dynamically at module init and exit times,
+* respectively.
+*/
+void synaptics_rmi4_new_function(enum exp_fn fn_type, bool insert,
+ int (*func_init)(struct synaptics_rmi4_data *rmi4_data),
+ void (*func_remove)(struct synaptics_rmi4_data *rmi4_data),
+ void (*func_attn)(struct synaptics_rmi4_data *rmi4_data,
+ unsigned char intr_mask))
+{
+ struct synaptics_rmi4_exp_fn *exp_fhandler;
+
+ if (!exp_fn_inited) {
+ mutex_init(&exp_fn_list_mutex);
+ INIT_LIST_HEAD(&exp_fn_list);
+ exp_fn_inited = 1;
+ }
+
+ mutex_lock(&exp_fn_list_mutex);
+ if (insert) {
+ exp_fhandler = kzalloc(sizeof(*exp_fhandler), GFP_KERNEL);
+ if (!exp_fhandler) {
+ pr_err("%s: Failed to alloc mem for expansion function\n",
+ __func__);
+ goto exit;
+ }
+ exp_fhandler->fn_type = fn_type;
+ exp_fhandler->func_init = func_init;
+ exp_fhandler->func_attn = func_attn;
+ exp_fhandler->func_remove = func_remove;
+ exp_fhandler->inserted = false;
+ list_add_tail(&exp_fhandler->link, &exp_fn_list);
+ } else {
+ list_for_each_entry(exp_fhandler, &exp_fn_list, link) {
+ if (exp_fhandler->func_init == func_init) {
+ exp_fhandler->inserted = false;
+ exp_fhandler->func_init = NULL;
+ exp_fhandler->func_attn = NULL;
+ goto exit;
+ }
+ }
+ }
+
+exit:
+ mutex_unlock(&exp_fn_list_mutex);
+
+ return;
+}
+EXPORT_SYMBOL(synaptics_rmi4_new_function);
+
+ /**
+ * synaptics_rmi4_probe()
+ *
+ * Called by the kernel when an association with an I2C device of the
+ * same name is made (after doing i2c_add_driver).
+ *
+ * This funtion allocates and initializes the resources for the driver
+ * as an input driver, turns on the power to the sensor, queries the
+ * sensor for its supported Functions and characteristics, registers
+ * the driver to the input subsystem, sets up the interrupt, handles
+ * the registration of the early_suspend and late_resume functions,
+ * and creates a work queue for detection of other expansion Function
+ * modules.
+ */
+static int __devinit synaptics_rmi4_probe(struct i2c_client *client,
+ const struct i2c_device_id *dev_id)
+{
+ int retval;
+ unsigned char ii;
+ unsigned char attr_count;
+ struct synaptics_rmi4_f1a_handle *f1a;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_data *rmi4_data;
+ struct synaptics_rmi4_device_info *rmi;
+ const struct synaptics_rmi4_platform_data *platform_data =
+ client->dev.platform_data;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev,
+ "%s: SMBus byte data not supported\n",
+ __func__);
+ return -EIO;
+ }
+
+ if (!platform_data) {
+ dev_err(&client->dev,
+ "%s: No platform data found\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ rmi4_data = kzalloc(sizeof(*rmi4_data) * 2, GFP_KERNEL);
+ if (!rmi4_data) {
+ dev_err(&client->dev,
+ "%s: Failed to alloc mem for rmi4_data\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ rmi4_data->input_dev = input_allocate_device();
+ if (rmi4_data->input_dev == NULL) {
+ dev_err(&client->dev,
+ "%s: Failed to allocate input device\n",
+ __func__);
+ retval = -ENOMEM;
+ goto err_input_device;
+ }
+/*
+ if (platform_data->regulator_en) {
+ rmi4_data->regulator = regulator_get(&client->dev, "vdd");
+ if (IS_ERR(rmi4_data->regulator)) {
+ dev_err(&client->dev,
+ "%s: Failed to get regulator\n",
+ __func__);
+ retval = PTR_ERR(rmi4_data->regulator);
+ goto err_regulator;
+ }
+ regulator_enable(rmi4_data->regulator);
+ }
+*/
+ rmi4_data->i2c_client = client;
+ rmi4_data->current_page = MASK_8BIT;
+ rmi4_data->board = platform_data;
+ rmi4_data->touch_stopped = false;
+ rmi4_data->sensor_sleep = false;
+ rmi4_data->irq_enabled = false;
+
+ rmi4_data->i2c_read = synaptics_rmi4_i2c_read;
+ rmi4_data->i2c_write = synaptics_rmi4_i2c_write;
+ rmi4_data->irq_enable = synaptics_rmi4_irq_enable;
+ rmi4_data->reset_device = synaptics_rmi4_reset_device;
+
+ init_waitqueue_head(&rmi4_data->wait);
+ mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ retval = synaptics_rmi4_query_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(&client->dev,
+ "%s: Failed to query device\n",
+ __func__);
+ goto err_query_device;
+ }
+
+ i2c_set_clientdata(client, rmi4_data);
+
+ rmi4_data->input_dev->name = DRIVER_NAME;
+ rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
+ rmi4_data->input_dev->id.bustype = BUS_I2C;
+ rmi4_data->input_dev->dev.parent = &client->dev;
+ input_set_drvdata(rmi4_data->input_dev, rmi4_data);
+
+ set_bit(EV_SYN, rmi4_data->input_dev->evbit);
+ set_bit(EV_KEY, rmi4_data->input_dev->evbit);
+ set_bit(EV_ABS, rmi4_data->input_dev->evbit);
+
+#ifdef INPUT_PROP_DIRECT
+ set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit);
+#endif
+
+ input_set_abs_params(rmi4_data->input_dev,
+ ABS_MT_POSITION_X, 0,
+ rmi4_data->sensor_max_x, 0, 0);
+ input_set_abs_params(rmi4_data->input_dev,
+ ABS_MT_POSITION_Y, 0,
+ rmi4_data->sensor_max_y, 0, 0);
+#ifdef REPORT_2D_W
+ input_set_abs_params(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MAJOR, 0,
+ MAX_ABS_MT_TOUCH_MAJOR, 0, 0);
+#endif
+
+#ifdef TYPE_B_PROTOCOL
+ input_mt_init_slots(rmi4_data->input_dev,
+ rmi4_data->num_of_fingers);
+#endif
+
+ f1a = NULL;
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
+ f1a = fhandler->data;
+ }
+
+ if (f1a) {
+ for (ii = 0; ii < f1a->valid_button_count; ii++) {
+ set_bit(f1a->button_map[ii],
+ rmi4_data->input_dev->keybit);
+ input_set_capability(rmi4_data->input_dev,
+ EV_KEY, f1a->button_map[ii]);
+ }
+ }
+
+ retval = input_register_device(rmi4_data->input_dev);
+ if (retval) {
+ dev_err(&client->dev,
+ "%s: Failed to register input device\n",
+ __func__);
+ 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
+
+ if (!exp_fn_inited) {
+ mutex_init(&exp_fn_list_mutex);
+ INIT_LIST_HEAD(&exp_fn_list);
+ exp_fn_inited = 1;
+ }
+
+ rmi4_data->det_workqueue =
+ create_singlethread_workqueue("rmi_det_workqueue");
+ INIT_DELAYED_WORK(&rmi4_data->det_work,
+ synaptics_rmi4_detection_work);
+ queue_delayed_work(rmi4_data->det_workqueue,
+ &rmi4_data->det_work,
+ msecs_to_jiffies(EXP_FN_DET_INTERVAL));
+
+ if (platform_data->gpio_config) {
+ retval = platform_data->gpio_config(platform_data->irq_gpio,
+ true);
+ if (retval < 0) {
+ dev_err(&client->dev,
+ "%s: Failed to configure GPIO\n",
+ __func__);
+ goto err_gpio;
+ }
+ }
+
+ rmi4_data->irq = gpio_to_irq(platform_data->irq_gpio);
+
+ retval = synaptics_rmi4_irq_enable(rmi4_data, true);
+ if (retval < 0) {
+ dev_err(&client->dev,
+ "%s: Failed to enable attention interrupt\n",
+ __func__);
+ goto err_enable_irq;
+ }
+
+ for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+ retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+ if (retval < 0) {
+ dev_err(&client->dev,
+ "%s: Failed to create sysfs attributes\n",
+ __func__);
+ goto err_sysfs;
+ }
+ }
+
+ return retval;
+
+err_sysfs:
+ for (attr_count--; attr_count >= 0; attr_count--) {
+ sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+ }
+
+err_enable_irq:
+err_gpio:
+ input_unregister_device(rmi4_data->input_dev);
+
+err_register_input:
+err_query_device:
+ if (platform_data->regulator_en) {
+ regulator_disable(rmi4_data->regulator);
+ regulator_put(rmi4_data->regulator);
+ }
+
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
+ synaptics_rmi4_f1a_kfree(fhandler);
+ else
+ kfree(fhandler->data);
+ kfree(fhandler);
+ }
+/*
+err_regulator:
+*/
+ input_free_device(rmi4_data->input_dev);
+ rmi4_data->input_dev = NULL;
+
+err_input_device:
+ kfree(rmi4_data);
+
+ return retval;
+}
+
+ /**
+ * synaptics_rmi4_remove()
+ *
+ * Called by the kernel when the association with an I2C device of the
+ * same name is broken (when the driver is unloaded).
+ *
+ * This funtion terminates the work queue, stops sensor data acquisition,
+ * frees the interrupt, unregisters the driver from the input subsystem,
+ * turns off the power to the sensor, and frees other allocated resources.
+ */
+static int __devexit synaptics_rmi4_remove(struct i2c_client *client)
+{
+ unsigned char attr_count;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
+ struct synaptics_rmi4_device_info *rmi;
+ const struct synaptics_rmi4_platform_data *platform_data =
+ rmi4_data->board;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ cancel_delayed_work_sync(&rmi4_data->det_work);
+ flush_workqueue(rmi4_data->det_workqueue);
+ destroy_workqueue(rmi4_data->det_workqueue);
+
+ rmi4_data->touch_stopped = true;
+ wake_up(&rmi4_data->wait);
+
+ synaptics_rmi4_irq_enable(rmi4_data, false);
+
+ for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+ sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+ }
+
+ input_unregister_device(rmi4_data->input_dev);
+
+ if (platform_data->regulator_en) {
+ regulator_disable(rmi4_data->regulator);
+ regulator_put(rmi4_data->regulator);
+ }
+
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
+ synaptics_rmi4_f1a_kfree(fhandler);
+ else
+ kfree(fhandler->data);
+ kfree(fhandler);
+ }
+ input_free_device(rmi4_data->input_dev);
+
+ kfree(rmi4_data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+ /**
+ * synaptics_rmi4_sensor_sleep()
+ *
+ * Called by synaptics_rmi4_early_suspend() and synaptics_rmi4_suspend().
+ *
+ * This function stops finger data acquisition and puts the sensor to sleep.
+ */
+static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char device_ctrl;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr,
+ &device_ctrl,
+ sizeof(device_ctrl));
+ if (retval < 0) {
+ dev_err(&(rmi4_data->input_dev->dev),
+ "%s: Failed to enter sleep mode\n",
+ __func__);
+ rmi4_data->sensor_sleep = false;
+ return;
+ }
+
+ device_ctrl = (device_ctrl & ~MASK_3BIT);
+ device_ctrl = (device_ctrl | NO_SLEEP_OFF | SENSOR_SLEEP);
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr,
+ &device_ctrl,
+ sizeof(device_ctrl));
+ if (retval < 0) {
+ dev_err(&(rmi4_data->input_dev->dev),
+ "%s: Failed to enter sleep mode\n",
+ __func__);
+ rmi4_data->sensor_sleep = false;
+ return;
+ } else {
+ rmi4_data->sensor_sleep = true;
+ }
+
+ return;
+}
+
+ /**
+ * synaptics_rmi4_sensor_wake()
+ *
+ * Called by synaptics_rmi4_resume() and synaptics_rmi4_late_resume().
+ *
+ * This function wakes the sensor from sleep.
+ */
+static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char device_ctrl;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr,
+ &device_ctrl,
+ sizeof(device_ctrl));
+ if (retval < 0) {
+ dev_err(&(rmi4_data->input_dev->dev),
+ "%s: Failed to wake from sleep mode\n",
+ __func__);
+ rmi4_data->sensor_sleep = true;
+ return;
+ }
+
+ device_ctrl = (device_ctrl & ~MASK_3BIT);
+ device_ctrl = (device_ctrl | NO_SLEEP_OFF | NORMAL_OPERATION);
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr,
+ &device_ctrl,
+ sizeof(device_ctrl));
+ if (retval < 0) {
+ dev_err(&(rmi4_data->input_dev->dev),
+ "%s: Failed to wake from sleep mode\n",
+ __func__);
+ rmi4_data->sensor_sleep = true;
+ return;
+ } else {
+ rmi4_data->sensor_sleep = false;
+ }
+
+ return;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ /**
+ * synaptics_rmi4_early_suspend()
+ *
+ * Called by the kernel during the early suspend phase when the system
+ * enters suspend.
+ *
+ * This function calls synaptics_rmi4_sensor_sleep() to stop finger
+ * data acquisition and put the sensor to sleep.
+ */
+static void synaptics_rmi4_early_suspend(struct early_suspend *h)
+{
+ struct synaptics_rmi4_data *rmi4_data =
+ container_of(h, struct synaptics_rmi4_data,
+ early_suspend);
+
+ rmi4_data->touch_stopped = true;
+ wake_up(&rmi4_data->wait);
+ synaptics_rmi4_irq_enable(rmi4_data, false);
+ synaptics_rmi4_sensor_sleep(rmi4_data);
+
+ if (rmi4_data->full_pm_cycle)
+ synaptics_rmi4_suspend(&(rmi4_data->input_dev->dev));
+
+ return;
+}
+
+ /**
+ * synaptics_rmi4_late_resume()
+ *
+ * Called by the kernel during the late resume phase when the system
+ * wakes up from suspend.
+ *
+ * This function goes through the sensor wake process if the system wakes
+ * up from early suspend (without going into suspend).
+ */
+static void synaptics_rmi4_late_resume(struct early_suspend *h)
+{
+ struct synaptics_rmi4_data *rmi4_data =
+ container_of(h, struct synaptics_rmi4_data,
+ early_suspend);
+
+ if (rmi4_data->full_pm_cycle)
+ synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
+
+ if (rmi4_data->sensor_sleep == true) {
+ synaptics_rmi4_sensor_wake(rmi4_data);
+ rmi4_data->touch_stopped = false;
+ synaptics_rmi4_irq_enable(rmi4_data, true);
+ }
+
+ return;
+}
+#endif
+
+ /**
+ * synaptics_rmi4_suspend()
+ *
+ * Called by the kernel during the suspend phase when the system
+ * enters suspend.
+ *
+ * This function stops finger data acquisition and puts the sensor to
+ * sleep (if not already done so during the early suspend phase),
+ * disables the interrupt, and turns off the power to the sensor.
+ */
+static int synaptics_rmi4_suspend(struct device *dev)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ const struct synaptics_rmi4_platform_data *platform_data =
+ rmi4_data->board;
+
+ if (!rmi4_data->sensor_sleep) {
+ rmi4_data->touch_stopped = true;
+ wake_up(&rmi4_data->wait);
+ synaptics_rmi4_irq_enable(rmi4_data, false);
+ synaptics_rmi4_sensor_sleep(rmi4_data);
+ }
+
+ if (platform_data->regulator_en)
+ regulator_disable(rmi4_data->regulator);
+
+ return 0;
+}
+
+ /**
+ * synaptics_rmi4_resume()
+ *
+ * Called by the kernel during the resume phase when the system
+ * wakes up from suspend.
+ *
+ * This function turns on the power to the sensor, wakes the sensor
+ * from sleep, enables the interrupt, and starts finger data
+ * acquisition.
+ */
+static int synaptics_rmi4_resume(struct device *dev)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ const struct synaptics_rmi4_platform_data *platform_data =
+ rmi4_data->board;
+
+ if (platform_data->regulator_en)
+ regulator_enable(rmi4_data->regulator);
+
+ synaptics_rmi4_sensor_wake(rmi4_data);
+ rmi4_data->touch_stopped = false;
+ synaptics_rmi4_irq_enable(rmi4_data, true);
+
+ return 0;
+}
+
+static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
+ .suspend = synaptics_rmi4_suspend,
+ .resume = synaptics_rmi4_resume,
+};
+#endif
+
+static const struct i2c_device_id synaptics_rmi4_id_table[] = {
+ {DRIVER_NAME, 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
+
+static struct i2c_driver synaptics_rmi4_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &synaptics_rmi4_dev_pm_ops,
+#endif
+ },
+ .probe = synaptics_rmi4_probe,
+ .remove = __devexit_p(synaptics_rmi4_remove),
+ .id_table = synaptics_rmi4_id_table,
+};
+
+ /**
+ * synaptics_rmi4_init()
+ *
+ * Called by the kernel during do_initcalls (if built-in)
+ * or when the driver is loaded (if a module).
+ *
+ * This function registers the driver to the I2C subsystem.
+ *
+ */
+static int __init synaptics_rmi4_init(void)
+{
+ return i2c_add_driver(&synaptics_rmi4_driver);
+}
+
+ /**
+ * synaptics_rmi4_exit()
+ *
+ * Called by the kernel when the driver is unloaded.
+ *
+ * This funtion unregisters the driver from the I2C subsystem.
+ *
+ */
+static void __exit synaptics_rmi4_exit(void)
+{
+ i2c_del_driver(&synaptics_rmi4_driver);
+}
+
+module_init(synaptics_rmi4_init);
+module_exit(synaptics_rmi4_exit);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("Synaptics RMI4 I2C Touch Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(SYNAPTICS_RMI4_DRIVER_VERSION);
diff --git a/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.h
new file mode 100644
index 000000000000..7ee0a925959a
--- /dev/null
+++ b/kernel/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -0,0 +1,282 @@
+/*
+ * Synaptics RMI4 touchscreen driver
+ *
+ * Copyright (C) 2012 Synaptics Incorporated
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 _SYNAPTICS_DSX_RMI4_H_
+#define _SYNAPTICS_DSX_RMI4_H_
+
+#define SYNAPTICS_RMI4_DRIVER_VERSION "DSX 1.0"
+
+#include <linux/version.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
+#define KERNEL_ABOVE_2_6_38
+#endif
+
+#ifdef KERNEL_ABOVE_2_6_38
+#define sstrtoul(...) kstrtoul(__VA_ARGS__)
+#else
+#define sstrtoul(...) strict_strtoul(__VA_ARGS__)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 0))
+#define KERNEL_ABOVE_3_7
+#endif
+
+#define PDT_PROPS (0x00EF)
+#define PDT_START (0x00E9)
+#define PDT_END (0x000A)
+#define PDT_ENTRY_SIZE (0x0006)
+#define PAGES_TO_SERVICE (10)
+#define PAGE_SELECT_LEN (2)
+
+#define SYNAPTICS_RMI4_F01 (0x01)
+#define SYNAPTICS_RMI4_F11 (0x11)
+#define SYNAPTICS_RMI4_F1A (0x1a)
+#define SYNAPTICS_RMI4_F34 (0x34)
+#define SYNAPTICS_RMI4_F54 (0x54)
+#define SYNAPTICS_RMI4_F55 (0x55)
+
+#define SYNAPTICS_RMI4_PRODUCT_INFO_SIZE 2
+#define SYNAPTICS_RMI4_DATE_CODE_SIZE 3
+#define SYNAPTICS_RMI4_PRODUCT_ID_SIZE 10
+#define SYNAPTICS_RMI4_BUILD_ID_SIZE 3
+
+#define MAX_NUMBER_OF_FINGERS 10
+#define MAX_NUMBER_OF_BUTTONS 4
+#define MAX_INTR_REGISTERS 4
+
+#define MASK_16BIT 0xFFFF
+#define MASK_8BIT 0xFF
+#define MASK_7BIT 0x7F
+#define MASK_6BIT 0x3F
+#define MASK_5BIT 0x1F
+#define MASK_4BIT 0x0F
+#define MASK_3BIT 0x07
+#define MASK_2BIT 0x03
+#define MASK_1BIT 0x01
+
+/*
+ * struct synaptics_rmi4_fn_desc - function descriptor fields in PDT
+ * @query_base_addr: base address for query registers
+ * @cmd_base_addr: base address for command registers
+ * @ctrl_base_addr: base address for control registers
+ * @data_base_addr: base address for data registers
+ * @intr_src_count: number of interrupt sources
+ * @fn_number: function number
+ */
+struct synaptics_rmi4_fn_desc {
+ unsigned char query_base_addr;
+ unsigned char cmd_base_addr;
+ unsigned char ctrl_base_addr;
+ unsigned char data_base_addr;
+ unsigned char intr_src_count;
+ unsigned char fn_number;
+};
+
+/*
+ * synaptics_rmi4_fn_full_addr - full 16-bit base addresses
+ * @query_base: 16-bit base address for query registers
+ * @cmd_base: 16-bit base address for data registers
+ * @ctrl_base: 16-bit base address for command registers
+ * @data_base: 16-bit base address for control registers
+ */
+struct synaptics_rmi4_fn_full_addr {
+ unsigned short query_base;
+ unsigned short cmd_base;
+ unsigned short ctrl_base;
+ unsigned short data_base;
+};
+
+/*
+ * struct synaptics_rmi4_fn - function handler data structure
+ * @fn_number: function number
+ * @num_of_data_sources: number of data sources
+ * @num_of_data_points: maximum number of fingers supported
+ * @size_of_data_register_block: data register block size
+ * @data1_offset: offset to data1 register from data base address
+ * @intr_reg_num: index to associated interrupt register
+ * @intr_mask: interrupt mask
+ * @full_addr: full 16-bit base addresses of function registers
+ * @link: linked list for function handlers
+ * @data_size: size of private data
+ * @data: pointer to private data
+ */
+struct synaptics_rmi4_fn {
+ unsigned char fn_number;
+ unsigned char num_of_data_sources;
+ unsigned char num_of_data_points;
+ unsigned char size_of_data_register_block;
+ unsigned char data1_offset;
+ unsigned char intr_reg_num;
+ unsigned char intr_mask;
+ struct synaptics_rmi4_fn_full_addr full_addr;
+ struct list_head link;
+ int data_size;
+ void *data;
+};
+
+/*
+ * struct synaptics_rmi4_device_info - device information
+ * @version_major: rmi protocol major version number
+ * @version_minor: rmi protocol minor version number
+ * @manufacturer_id: manufacturer id
+ * @product_props: product properties information
+ * @product_info: product info array
+ * @date_code: device manufacture date
+ * @tester_id: tester id array
+ * @serial_number: device serial number
+ * @product_id_string: device product id
+ * @support_fn_list: linked list for function handlers
+ */
+struct synaptics_rmi4_device_info {
+ unsigned int version_major;
+ unsigned int version_minor;
+ unsigned char manufacturer_id;
+ unsigned char product_props;
+ unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
+ unsigned char date_code[SYNAPTICS_RMI4_DATE_CODE_SIZE];
+ unsigned short tester_id;
+ unsigned short serial_number;
+ unsigned char product_id_string[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
+ unsigned char build_id[SYNAPTICS_RMI4_BUILD_ID_SIZE];
+ struct list_head support_fn_list;
+};
+
+/*
+ * struct synaptics_rmi4_data - rmi4 device instance data
+ * @i2c_client: pointer to associated i2c client
+ * @input_dev: pointer to associated input device
+ * @board: constant pointer to platform data
+ * @rmi4_mod_info: device information
+ * @regulator: pointer to associated regulator
+ * @rmi4_io_ctrl_mutex: mutex for i2c i/o control
+ * @det_work: work thread instance for expansion function detection
+ * @det_workqueue: pointer to work queue for work thread instance
+ * @early_suspend: instance to support early suspend power management
+ * @current_page: current page in sensor to acess
+ * @button_0d_enabled: flag for 0d button support
+ * @full_pm_cycle: flag for full power management cycle in early suspend stage
+ * @num_of_intr_regs: number of interrupt registers
+ * @f01_query_base_addr: query base address for f01
+ * @f01_cmd_base_addr: command base address for f01
+ * @f01_ctrl_base_addr: control base address for f01
+ * @f01_data_base_addr: data base address for f01
+ * @irq: attention interrupt
+ * @sensor_max_x: sensor maximum x value
+ * @sensor_max_y: sensor maximum y value
+ * @irq_enabled: flag for indicating interrupt enable status
+ * @touch_stopped: flag to stop interrupt thread processing
+ * @fingers_on_2d: flag to indicate presence of fingers in 2d area
+ * @sensor_sleep: flag to indicate sleep state of sensor
+ * @wait: wait queue for touch data polling in interrupt thread
+ * @i2c_read: pointer to i2c read function
+ * @i2c_write: pointer to i2c write function
+ * @irq_enable: pointer to irq enable function
+ */
+struct synaptics_rmi4_data {
+ struct i2c_client *i2c_client;
+ struct input_dev *input_dev;
+ const struct synaptics_rmi4_platform_data *board;
+ struct synaptics_rmi4_device_info rmi4_mod_info;
+ struct regulator *regulator;
+ struct mutex rmi4_io_ctrl_mutex;
+ struct delayed_work det_work;
+ struct workqueue_struct *det_workqueue;
+ struct early_suspend early_suspend;
+ unsigned char current_page;
+ unsigned char button_0d_enabled;
+ unsigned char full_pm_cycle;
+ unsigned char num_of_rx;
+ unsigned char num_of_tx;
+ unsigned char num_of_fingers;
+ unsigned char intr_mask[MAX_INTR_REGISTERS];
+ unsigned short num_of_intr_regs;
+ unsigned short f01_query_base_addr;
+ unsigned short f01_cmd_base_addr;
+ unsigned short f01_ctrl_base_addr;
+ unsigned short f01_data_base_addr;
+ int irq;
+ int sensor_max_x;
+ int sensor_max_y;
+ bool irq_enabled;
+ bool touch_stopped;
+ bool fingers_on_2d;
+ bool sensor_sleep;
+ wait_queue_head_t wait;
+ int (*i2c_read)(struct synaptics_rmi4_data *pdata, unsigned short addr,
+ unsigned char *data, unsigned short length);
+ int (*i2c_write)(struct synaptics_rmi4_data *pdata, unsigned short addr,
+ 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);
+};
+
+enum exp_fn {
+ RMI_DEV = 0,
+ RMI_F34,
+ RMI_F54,
+ RMI_FW_UPDATER,
+ RMI_LAST,
+};
+
+struct synaptics_rmi4_exp_fn_ptr {
+ int (*read)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
+ unsigned char *data, unsigned short length);
+ int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
+ unsigned char *data, unsigned short length);
+ int (*enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
+};
+
+void synaptics_rmi4_new_function(enum exp_fn fn_type, bool insert,
+ int (*func_init)(struct synaptics_rmi4_data *rmi4_data),
+ void (*func_remove)(struct synaptics_rmi4_data *rmi4_data),
+ void (*func_attn)(struct synaptics_rmi4_data *rmi4_data,
+ unsigned char intr_mask));
+
+static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ dev_warn(dev, "%s Attempted to read from write-only attribute %s\n",
+ __func__, attr->attr.name);
+ return -EPERM;
+}
+
+static inline ssize_t synaptics_rmi4_store_error(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ dev_warn(dev, "%s Attempted to write to read-only attribute %s\n",
+ __func__, attr->attr.name);
+ return -EPERM;
+}
+
+static inline void batohs(unsigned short *dest, unsigned char *src)
+{
+ *dest = src[1] * 0x100 + src[0];
+}
+
+static inline void hstoba(unsigned char *dest, unsigned short src)
+{
+ dest[0] = src % 0x100;
+ dest[1] = src / 0x100;
+}
+
+#endif
diff --git a/kernel/drivers/input/touchscreen/synaptics_rmi_dev.c b/kernel/drivers/input/touchscreen/synaptics_rmi_dev.c
new file mode 100644
index 000000000000..75857802c97a
--- /dev/null
+++ b/kernel/drivers/input/touchscreen/synaptics_rmi_dev.c
@@ -0,0 +1,710 @@
+/*
+ * Synaptics RMI4 touchscreen driver
+ *
+ * Copyright (C) 2012 Synaptics Incorporated
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/uaccess.h>
+#include <linux/cdev.h>
+#include <linux/input/synaptics_dsx.h>
+#include "synaptics_i2c_rmi4.h"
+
+#define CHAR_DEVICE_NAME "rmi"
+#define DEVICE_CLASS_NAME "rmidev"
+#define DEV_NUMBER 1
+#define REG_ADDR_LIMIT 0xFFFF
+
+static ssize_t rmidev_sysfs_open_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t rmidev_sysfs_release_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t rmidev_sysfs_address_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t rmidev_sysfs_length_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t rmidev_sysfs_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t rmidev_sysfs_data_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+struct rmidev_handle {
+ dev_t dev_no;
+ unsigned short address;
+ unsigned int length;
+ struct device dev;
+ struct synaptics_rmi4_data *rmi4_data;
+ struct synaptics_rmi4_exp_fn_ptr *fn_ptr;
+ struct kobject *sysfs_dir;
+ void *data;
+};
+
+struct rmidev_data {
+ int ref_count;
+ struct cdev main_dev;
+ struct class *device_class;
+ struct mutex file_mutex;
+ struct rmidev_handle *rmi_dev;
+};
+
+static struct device_attribute attrs[] = {
+ __ATTR(open, S_IWUGO,
+ synaptics_rmi4_show_error,
+ rmidev_sysfs_open_store),
+ __ATTR(release, S_IWUGO,
+ synaptics_rmi4_show_error,
+ rmidev_sysfs_release_store),
+ __ATTR(address, S_IWUGO,
+ synaptics_rmi4_show_error,
+ rmidev_sysfs_address_store),
+ __ATTR(length, S_IWUGO,
+ synaptics_rmi4_show_error,
+ rmidev_sysfs_length_store),
+ __ATTR(data, (S_IRUGO | S_IWUGO),
+ rmidev_sysfs_data_show,
+ rmidev_sysfs_data_store),
+};
+
+static int rmidev_major_num;
+
+static struct class *rmidev_device_class;
+
+static struct rmidev_handle *rmidev;
+
+static struct completion remove_complete;
+
+static ssize_t rmidev_sysfs_open_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ if (input != 1)
+ return -EINVAL;
+
+ rmidev->fn_ptr->enable(rmidev->rmi4_data, false);
+ dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
+ "%s: Attention interrupt disabled\n",
+ __func__);
+
+ return count;
+}
+
+static ssize_t rmidev_sysfs_release_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ if (input != 1)
+ return -EINVAL;
+
+ rmidev->fn_ptr->enable(rmidev->rmi4_data, true);
+ dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
+ "%s: Attention interrupt enabled\n",
+ __func__);
+
+ return count;
+}
+
+static ssize_t rmidev_sysfs_address_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ if (input > REG_ADDR_LIMIT)
+ return -EINVAL;
+
+ rmidev->address = (unsigned short)input;
+
+ return count;
+}
+
+static ssize_t rmidev_sysfs_length_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ if (input > REG_ADDR_LIMIT)
+ return -EINVAL;
+
+ rmidev->length = input;
+
+ return count;
+}
+
+static ssize_t rmidev_sysfs_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int retval;
+ unsigned int data_length = rmidev->length;
+
+ if (data_length > (REG_ADDR_LIMIT - rmidev->address))
+ data_length = REG_ADDR_LIMIT - rmidev->address;
+
+ if (data_length) {
+ retval = rmidev->fn_ptr->read(rmidev->rmi4_data,
+ rmidev->address,
+ (unsigned char *)buf,
+ data_length);
+ if (retval < 0) {
+ dev_err(&rmidev->rmi4_data->i2c_client->dev,
+ "%s: Failed to read data\n",
+ __func__);
+ return retval;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return data_length;
+}
+
+static ssize_t rmidev_sysfs_data_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned int data_length = rmidev->length;
+
+ if (data_length > (REG_ADDR_LIMIT - rmidev->address))
+ data_length = REG_ADDR_LIMIT - rmidev->address;
+
+ if (data_length) {
+ retval = rmidev->fn_ptr->write(rmidev->rmi4_data,
+ rmidev->address,
+ (unsigned char *)buf,
+ data_length);
+ if (retval < 0) {
+ dev_err(&rmidev->rmi4_data->i2c_client->dev,
+ "%s: Failed to write data\n",
+ __func__);
+ return retval;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return data_length;
+}
+
+/*
+ * rmidev_llseek - used to set up register address
+ *
+ * @filp: file structure for seek
+ * @off: offset
+ * if whence == SEEK_SET,
+ * high 16 bits: page address
+ * low 16 bits: register address
+ * if whence == SEEK_CUR,
+ * offset from current position
+ * if whence == SEEK_END,
+ * offset from end position (0xFFFF)
+ * @whence: SEEK_SET, SEEK_CUR, or SEEK_END
+ */
+static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence)
+{
+ loff_t newpos;
+ struct rmidev_data *dev_data = filp->private_data;
+
+ if (IS_ERR(dev_data)) {
+ pr_err("%s: Pointer of char device data is invalid", __func__);
+ return -EBADF;
+ }
+
+ mutex_lock(&(dev_data->file_mutex));
+
+ switch (whence) {
+ case SEEK_SET:
+ newpos = off;
+ break;
+ case SEEK_CUR:
+ newpos = filp->f_pos + off;
+ break;
+ case SEEK_END:
+ newpos = REG_ADDR_LIMIT + off;
+ break;
+ default:
+ newpos = -EINVAL;
+ goto clean_up;
+ }
+
+ if (newpos < 0 || newpos > REG_ADDR_LIMIT) {
+ dev_err(&rmidev->rmi4_data->i2c_client->dev,
+ "%s: New position 0x%04x is invalid\n",
+ __func__, (unsigned int)newpos);
+ newpos = -EINVAL;
+ goto clean_up;
+ }
+
+ filp->f_pos = newpos;
+
+clean_up:
+ mutex_unlock(&(dev_data->file_mutex));
+
+ return newpos;
+}
+
+/*
+ * rmidev_read: - use to read data from rmi device
+ *
+ * @filp: file structure for read
+ * @buf: user space buffer pointer
+ * @count: number of bytes to read
+ * @f_pos: offset (starting register address)
+ */
+static ssize_t rmidev_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ ssize_t retval;
+ unsigned char tmpbuf[count + 1];
+ struct rmidev_data *dev_data = filp->private_data;
+
+ if (IS_ERR(dev_data)) {
+ pr_err("%s: Pointer of char device data is invalid", __func__);
+ return -EBADF;
+ }
+
+ if (count == 0)
+ return 0;
+
+ if (count > (REG_ADDR_LIMIT - *f_pos))
+ count = REG_ADDR_LIMIT - *f_pos;
+
+ mutex_lock(&(dev_data->file_mutex));
+
+ retval = rmidev->fn_ptr->read(rmidev->rmi4_data,
+ *f_pos,
+ tmpbuf,
+ count);
+ if (retval < 0)
+ goto clean_up;
+
+ if (copy_to_user(buf, tmpbuf, count))
+ retval = -EFAULT;
+ else
+ *f_pos += retval;
+
+clean_up:
+ mutex_unlock(&(dev_data->file_mutex));
+
+ return retval;
+}
+
+/*
+ * rmidev_write: - used to write data to rmi device
+ *
+ * @filep: file structure for write
+ * @buf: user space buffer pointer
+ * @count: number of bytes to write
+ * @f_pos: offset (starting register address)
+ */
+static ssize_t rmidev_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ ssize_t retval;
+ unsigned char tmpbuf[count + 1];
+ struct rmidev_data *dev_data = filp->private_data;
+
+ if (IS_ERR(dev_data)) {
+ pr_err("%s: Pointer of char device data is invalid", __func__);
+ return -EBADF;
+ }
+
+ if (count == 0)
+ return 0;
+
+ if (count > (REG_ADDR_LIMIT - *f_pos))
+ count = REG_ADDR_LIMIT - *f_pos;
+
+ if (copy_from_user(tmpbuf, buf, count))
+ return -EFAULT;
+
+ mutex_lock(&(dev_data->file_mutex));
+
+ retval = rmidev->fn_ptr->write(rmidev->rmi4_data,
+ *f_pos,
+ tmpbuf,
+ count);
+ if (retval >= 0)
+ *f_pos += retval;
+
+ mutex_unlock(&(dev_data->file_mutex));
+
+ return retval;
+}
+
+/*
+ * rmidev_open: enable access to rmi device
+ * @inp: inode struture
+ * @filp: file structure
+ */
+static int rmidev_open(struct inode *inp, struct file *filp)
+{
+ int retval = 0;
+ struct rmidev_data *dev_data =
+ container_of(inp->i_cdev, struct rmidev_data, main_dev);
+
+ if (!dev_data)
+ return -EACCES;
+
+ filp->private_data = dev_data;
+
+ mutex_lock(&(dev_data->file_mutex));
+
+ rmidev->fn_ptr->enable(rmidev->rmi4_data, false);
+ dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
+ "%s: Attention interrupt disabled\n",
+ __func__);
+
+ if (dev_data->ref_count < 1)
+ dev_data->ref_count++;
+ else
+ retval = -EACCES;
+
+ mutex_unlock(&(dev_data->file_mutex));
+
+ return retval;
+}
+
+/*
+ * rmidev_release: - release access to rmi device
+ * @inp: inode structure
+ * @filp: file structure
+ */
+static int rmidev_release(struct inode *inp, struct file *filp)
+{
+ struct rmidev_data *dev_data =
+ container_of(inp->i_cdev, struct rmidev_data, main_dev);
+
+ if (!dev_data)
+ return -EACCES;
+
+ mutex_lock(&(dev_data->file_mutex));
+
+ dev_data->ref_count--;
+ if (dev_data->ref_count < 0)
+ dev_data->ref_count = 0;
+
+ rmidev->fn_ptr->enable(rmidev->rmi4_data, true);
+ dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
+ "%s: Attention interrupt enabled\n",
+ __func__);
+
+ mutex_unlock(&(dev_data->file_mutex));
+
+ return 0;
+}
+
+static const struct file_operations rmidev_fops = {
+ .owner = THIS_MODULE,
+ .llseek = rmidev_llseek,
+ .read = rmidev_read,
+ .write = rmidev_write,
+ .open = rmidev_open,
+ .release = rmidev_release,
+};
+
+static void rmidev_device_cleanup(struct rmidev_data *dev_data)
+{
+ dev_t devno;
+
+ if (dev_data) {
+ devno = dev_data->main_dev.dev;
+
+ if (dev_data->device_class)
+ device_destroy(dev_data->device_class, devno);
+
+ cdev_del(&dev_data->main_dev);
+
+ unregister_chrdev_region(devno, 1);
+
+ dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
+ "%s: rmidev device removed\n",
+ __func__);
+ }
+
+ return;
+}
+
+static char *rmi_char_devnode(struct device *dev, mode_t *mode)
+{
+ if (!mode)
+ return NULL;
+
+ *mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+
+ return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
+}
+
+static int rmidev_create_device_class(void)
+{
+ rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
+
+ if (IS_ERR(rmidev_device_class)) {
+ pr_err("%s: Failed to create /dev/%s\n",
+ __func__, CHAR_DEVICE_NAME);
+ return -ENODEV;
+ }
+
+ rmidev_device_class->devnode = rmi_char_devnode;
+
+ return 0;
+}
+
+static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ dev_t dev_no;
+ unsigned char attr_count;
+ struct rmidev_data *dev_data;
+ struct device *device_ptr;
+
+ rmidev = kzalloc(sizeof(*rmidev), GFP_KERNEL);
+ if (!rmidev) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for rmidev\n",
+ __func__);
+ retval = -ENOMEM;
+ goto err_rmidev;
+ }
+
+ rmidev->fn_ptr = kzalloc(sizeof(*(rmidev->fn_ptr)), GFP_KERNEL);
+ if (!rmidev) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for fn_ptr\n",
+ __func__);
+ retval = -ENOMEM;
+ goto err_fn_ptr;
+ }
+
+ rmidev->fn_ptr->read = rmi4_data->i2c_read;
+ rmidev->fn_ptr->write = rmi4_data->i2c_write;
+ rmidev->fn_ptr->enable = rmi4_data->irq_enable;
+ rmidev->rmi4_data = rmi4_data;
+
+ retval = rmidev_create_device_class();
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create device class\n",
+ __func__);
+ goto err_device_class;
+ }
+
+ if (rmidev_major_num) {
+ dev_no = MKDEV(rmidev_major_num, DEV_NUMBER);
+ retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
+ } else {
+ retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to allocate char device region\n",
+ __func__);
+ goto err_device_region;
+ }
+
+ rmidev_major_num = MAJOR(dev_no);
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Major number of rmidev = %d\n",
+ __func__, rmidev_major_num);
+ }
+
+ dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
+ if (!dev_data) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for dev_data\n",
+ __func__);
+ retval = -ENOMEM;
+ goto err_dev_data;
+ }
+
+ mutex_init(&dev_data->file_mutex);
+ dev_data->rmi_dev = rmidev;
+ rmidev->data = dev_data;
+
+ cdev_init(&dev_data->main_dev, &rmidev_fops);
+
+ retval = cdev_add(&dev_data->main_dev, dev_no, 1);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to add rmi char device\n",
+ __func__);
+ goto err_char_device;
+ }
+
+ dev_set_name(&rmidev->dev, "rmidev%d", MINOR(dev_no));
+ dev_data->device_class = rmidev_device_class;
+
+ device_ptr = device_create(dev_data->device_class, NULL, dev_no,
+ NULL, CHAR_DEVICE_NAME"%d", MINOR(dev_no));
+ if (IS_ERR(device_ptr)) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create rmi char device\n",
+ __func__);
+ retval = -ENODEV;
+ goto err_char_device;
+ }
+
+ retval = gpio_export(rmi4_data->board->irq_gpio, false);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to export attention gpio\n",
+ __func__);
+ } else {
+ retval = gpio_export_link(&(rmi4_data->input_dev->dev),
+ "attn", rmi4_data->board->irq_gpio);
+ if (retval < 0) {
+ dev_err(&rmi4_data->input_dev->dev,
+ "%s Failed to create gpio symlink\n",
+ __func__);
+ } else {
+ dev_dbg(&rmi4_data->input_dev->dev,
+ "%s: Exported attention gpio %d\n",
+ __func__, rmi4_data->board->irq_gpio);
+ }
+ }
+
+ rmidev->sysfs_dir = kobject_create_and_add("rmidev",
+ &rmi4_data->input_dev->dev.kobj);
+ if (!rmidev->sysfs_dir) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create sysfs directory\n",
+ __func__);
+ goto err_sysfs_dir;
+ }
+
+ for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+ retval = sysfs_create_file(rmidev->sysfs_dir,
+ &attrs[attr_count].attr);
+ if (retval < 0) {
+ dev_err(&rmi4_data->input_dev->dev,
+ "%s: Failed to create sysfs attributes\n",
+ __func__);
+ retval = -ENODEV;
+ goto err_sysfs_attrs;
+ }
+ }
+
+ return 0;
+
+err_sysfs_attrs:
+ for (attr_count--; attr_count >= 0; attr_count--) {
+ sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+ }
+
+ kobject_put(rmidev->sysfs_dir);
+
+err_sysfs_dir:
+err_char_device:
+ rmidev_device_cleanup(dev_data);
+ kfree(dev_data);
+
+err_dev_data:
+ unregister_chrdev_region(dev_no, 1);
+
+err_device_region:
+ class_destroy(rmidev_device_class);
+
+err_device_class:
+ kfree(rmidev->fn_ptr);
+
+err_fn_ptr:
+ kfree(rmidev);
+
+err_rmidev:
+ return retval;
+}
+
+static void rmidev_remove_device(struct synaptics_rmi4_data *rmi4_data)
+{
+ unsigned char attr_count;
+ struct rmidev_data *dev_data;
+
+ if (!rmidev)
+ return;
+
+ for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
+ sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr);
+
+ kobject_put(rmidev->sysfs_dir);
+
+ dev_data = rmidev->data;
+ if (dev_data) {
+ rmidev_device_cleanup(dev_data);
+ kfree(dev_data);
+ }
+
+ unregister_chrdev_region(rmidev->dev_no, 1);
+
+ class_destroy(rmidev_device_class);
+
+ kfree(rmidev->fn_ptr);
+ kfree(rmidev);
+
+ complete(&remove_complete);
+
+ return;
+}
+
+static int __init rmidev_module_init(void)
+{
+ synaptics_rmi4_new_function(RMI_DEV, true,
+ rmidev_init_device,
+ rmidev_remove_device,
+ NULL);
+ return 0;
+}
+
+static void __exit rmidev_module_exit(void)
+{
+ init_completion(&remove_complete);
+ synaptics_rmi4_new_function(RMI_DEV, false,
+ rmidev_init_device,
+ rmidev_remove_device,
+ NULL);
+ wait_for_completion(&remove_complete);
+ return;
+}
+
+module_init(rmidev_module_init);
+module_exit(rmidev_module_exit);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("RMI4 RMI_Dev Module");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SYNAPTICS_RMI4_DRIVER_VERSION);
diff --git a/kernel/include/linux/input/synaptics_dsx.h b/kernel/include/linux/input/synaptics_dsx.h
new file mode 100644
index 000000000000..b779e42a9bac
--- /dev/null
+++ b/kernel/include/linux/input/synaptics_dsx.h
@@ -0,0 +1,59 @@
+/*
+ * Synaptics RMI4 touchscreen driver
+ *
+ * Copyright (C) 2012 Synaptics Incorporated
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 _SYNAPTICS_DSX_H_
+#define _SYNAPTICS_DSX_H_
+
+/*
+ * struct synaptics_rmi4_capacitance_button_map - 0d button map
+ * @nbuttons: number of buttons
+ * @map: button map
+ */
+struct synaptics_rmi4_capacitance_button_map {
+ unsigned char nbuttons;
+ unsigned char *map;
+};
+
+/*
+ * struct synaptics_rmi4_platform_data - rmi4 platform data
+ * @x_flip: x flip flag
+ * @y_flip: y flip flag
+ * @regulator_en: regulator enable flag
+ * @irq_gpio: attention interrupt gpio
+ * @irq_flags: flags used by the irq
+ * @reset_gpio: reset gpio
+ * @panel_x: panel maximum values on the x
+ * @panel_y: panel maximum values on the y
+ * @gpio_config: pointer to gpio configuration function
+ * @capacitance_button_map: pointer to 0d button map
+ */
+struct synaptics_rmi4_platform_data {
+ bool x_flip;
+ bool y_flip;
+ bool regulator_en;
+ unsigned irq_gpio;
+ unsigned long irq_flags;
+ unsigned reset_gpio;
+ unsigned panel_x;
+ unsigned panel_y;
+ int (*gpio_config)(unsigned gpio, bool configure);
+ struct synaptics_rmi4_capacitance_button_map *capacitance_button_map;
+};
+
+#endif
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 6b2ef88c7163..75387b7c2069 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -108,6 +108,7 @@ static const struct snd_kcontrol_new name##_mux = \
#define WCD934X_DEC_PWR_LVL_LP 0x02
#define WCD934X_DEC_PWR_LVL_HP 0x04
#define WCD934X_DEC_PWR_LVL_DF 0x00
+#define WCD934X_STRING_LEN 100
#define WCD934X_MAX_MICBIAS 4
#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone"
@@ -470,7 +471,7 @@ struct tavil_priv {
struct clk *wcd_ext_clk;
struct mutex codec_mutex;
- struct work_struct wcd_add_child_devices_work;
+ struct work_struct tavil_add_child_devices_work;
struct hpf_work tx_hpf_work[WCD934X_NUM_DECIMATORS];
struct tx_mute_work tx_mute_dwork[WCD934X_NUM_DECIMATORS];
};
@@ -5551,7 +5552,7 @@ static int tavil_swrm_handle_irq(void *handle,
return ret;
}
-static void wcd_add_child_devices(struct work_struct *work)
+static void tavil_add_child_devices(struct work_struct *work)
{
struct tavil_priv *tavil;
struct platform_device *pdev;
@@ -5560,9 +5561,10 @@ static void wcd_add_child_devices(struct work_struct *work)
struct tavil_swr_ctrl_data *swr_ctrl_data = NULL, *temp;
int ret, ctrl_num = 0;
struct wcd_swr_ctrl_platform_data *platdata;
+ char plat_dev_name[WCD934X_STRING_LEN];
tavil = container_of(work, struct tavil_priv,
- wcd_add_child_devices_work);
+ tavil_add_child_devices_work);
if (!tavil) {
pr_err("%s: Memory for WCD934X does not exist\n",
__func__);
@@ -5583,17 +5585,17 @@ static void wcd_add_child_devices(struct work_struct *work)
platdata = &tavil->swr.plat_data;
for_each_child_of_node(wcd9xxx->dev->of_node, node) {
- temp = krealloc(swr_ctrl_data,
- (ctrl_num + 1) * sizeof(struct tavil_swr_ctrl_data),
- GFP_KERNEL);
- if (!temp) {
- dev_err(wcd9xxx->dev, "out of memory\n");
- ret = -ENOMEM;
- goto err_mem;
- }
- swr_ctrl_data = temp;
- swr_ctrl_data[ctrl_num].swr_pdev = NULL;
- pdev = platform_device_alloc("tavil_swr_ctrl", -1);
+ if (!strcmp(node->name, "swr_master"))
+ strlcpy(plat_dev_name, "tavil_swr_ctrl",
+ (WCD934X_STRING_LEN - 1));
+ else if (strnstr(node->name, "msm_cdc_pinctrl",
+ strlen("msm_cdc_pinctrl")) != NULL)
+ strlcpy(plat_dev_name, node->name,
+ (WCD934X_STRING_LEN - 1));
+ else
+ continue;
+
+ pdev = platform_device_alloc(plat_dev_name, -1);
if (!pdev) {
dev_err(wcd9xxx->dev, "%s: pdev memory alloc failed\n",
__func__);
@@ -5603,34 +5605,51 @@ static void wcd_add_child_devices(struct work_struct *work)
pdev->dev.parent = tavil->dev;
pdev->dev.of_node = node;
- ret = platform_device_add_data(pdev, platdata,
- sizeof(*platdata));
- if (ret) {
- dev_err(&pdev->dev, "%s: cannot add plat data for ctrl:%d\n",
- __func__, ctrl_num);
- goto err_pdev_add;
+ if (strcmp(node->name, "swr_master") == 0) {
+ ret = platform_device_add_data(pdev, platdata,
+ sizeof(*platdata));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: cannot add plat data ctrl:%d\n",
+ __func__, ctrl_num);
+ goto err_pdev_add;
+ }
}
ret = platform_device_add(pdev);
if (ret) {
- dev_err(&pdev->dev, "%s: Cannot add swr platform device\n",
+ dev_err(&pdev->dev,
+ "%s: Cannot add platform device\n",
__func__);
goto err_pdev_add;
}
- swr_ctrl_data[ctrl_num].swr_pdev = pdev;
- ctrl_num++;
- dev_dbg(&pdev->dev, "%s: Added soundwire ctrl device(s)\n",
- __func__);
+ if (strcmp(node->name, "swr_master") == 0) {
+ temp = krealloc(swr_ctrl_data,
+ (ctrl_num + 1) * sizeof(
+ struct tavil_swr_ctrl_data),
+ GFP_KERNEL);
+ if (!temp) {
+ dev_err(wcd9xxx->dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto err_pdev_add;
+ }
+ swr_ctrl_data = temp;
+ swr_ctrl_data[ctrl_num].swr_pdev = pdev;
+ ctrl_num++;
+ dev_dbg(&pdev->dev,
+ "%s: Added soundwire ctrl device(s)\n",
+ __func__);
+ tavil->swr.ctrl_data = swr_ctrl_data;
+ }
}
- tavil->swr.ctrl_data = swr_ctrl_data;
return;
err_pdev_add:
platform_device_put(pdev);
err_mem:
- kfree(swr_ctrl_data);
+ return;
}
static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil)
@@ -5676,7 +5695,8 @@ static int tavil_probe(struct platform_device *pdev)
tavil->wcd9xxx = dev_get_drvdata(pdev->dev.parent);
tavil->dev = &pdev->dev;
- INIT_WORK(&tavil->wcd_add_child_devices_work, wcd_add_child_devices);
+ INIT_WORK(&tavil->tavil_add_child_devices_work,
+ tavil_add_child_devices);
mutex_init(&tavil->swr.read_mutex);
mutex_init(&tavil->swr.write_mutex);
mutex_init(&tavil->swr.clk_mutex);
@@ -5733,7 +5753,7 @@ static int tavil_probe(struct platform_device *pdev)
__func__);
goto err_cdc_reg;
}
- schedule_work(&tavil->wcd_add_child_devices_work);
+ schedule_work(&tavil->tavil_add_child_devices_work);
return ret;
diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
index 48180cf5e337..ad2f2e9865c3 100644
--- a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c
@@ -1523,8 +1523,9 @@ static int msm_ds2_dap_get_param(u32 cmd, void *arg)
}
/* Return if invalid length */
- if (dolby_data->length >
- (DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM - DOLBY_PARAM_PAYLOAD_SIZE)) {
+ if ((dolby_data->length >
+ (DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM - DOLBY_PARAM_PAYLOAD_SIZE)) ||
+ (dolby_data->length <= 0)) {
pr_err("Invalid length %d", dolby_data->length);
rc = -EINVAL;
goto end;
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index 9d2b75876bfe..94c051773fd9 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -405,12 +405,15 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
subs->interface, subs->altset_idx);
goto err;
}
- resp->bDelay = as->bDelay;
+ resp->data_path_delay = as->bDelay;
+ resp->data_path_delay_valid = 1;
fmt_v1 = (struct uac_format_type_i_discrete_descriptor *)fmt;
- resp->bSubslotSize = fmt_v1->bSubframeSize;
+ resp->usb_audio_subslot_size = fmt_v1->bSubframeSize;
+ resp->usb_audio_subslot_size_valid = 1;
} else if (protocol == UAC_VERSION_2) {
fmt_v2 = (struct uac_format_type_i_ext_descriptor *)fmt;
- resp->bSubslotSize = fmt_v2->bSubslotSize;
+ resp->usb_audio_subslot_size = fmt_v2->bSubslotSize;
+ resp->usb_audio_subslot_size_valid = 1;
} else {
pr_err("%s: unknown protocol version %x\n", __func__, protocol);
goto err;
@@ -424,11 +427,14 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
subs->interface, subs->altset_idx);
goto err;
}
- resp->bcdADC = ac->bcdADC;
+ resp->usb_audio_spec_revision = ac->bcdADC;
+ resp->usb_audio_spec_revision_valid = 1;
resp->slot_id = subs->dev->slot_id;
+ resp->slot_id_valid = 1;
memcpy(&resp->std_as_opr_intf_desc, &alts->desc, sizeof(alts->desc));
+ resp->std_as_opr_intf_desc_valid = 1;
ep = usb_pipe_endpoint(subs->dev, subs->data_endpoint->pipe);
if (!ep) {
@@ -437,6 +443,7 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
goto err;
}
memcpy(&resp->std_as_data_ep_desc, &ep->desc, sizeof(ep->desc));
+ resp->std_as_data_ep_desc_valid = 1;
xhci_pa = usb_get_xfer_ring_dma_addr(subs->dev, ep);
if (!xhci_pa) {
@@ -454,6 +461,8 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
goto err;
}
memcpy(&resp->std_as_sync_ep_desc, &ep->desc, sizeof(ep->desc));
+ resp->std_as_sync_ep_desc_valid = 1;
+
xhci_pa = usb_get_xfer_ring_dma_addr(subs->dev, ep);
if (!xhci_pa) {
pr_err("%s:failed to get sync ep ring dma address\n",
@@ -464,6 +473,7 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
}
resp->interrupter_num = uaudio_qdev->intr_num;
+ resp->interrupter_num_valid = 1;
/* map xhci data structures PA memory to iova */
@@ -570,6 +580,8 @@ skip_sync:
resp->xhci_mem_info.xfer_buff.va = PREPEND_SID_TO_IOVA(va,
uaudio_qdev->sid);
+ resp->xhci_mem_info_valid = 1;
+
if (!atomic_read(&uadev[card_num].in_use)) {
kref_init(&uadev[card_num].kref);
init_waitqueue_head(&uadev[card_num].disconnect_wq);
@@ -734,7 +746,7 @@ static void uaudio_dev_release(struct kref *kref)
static int handle_uaudio_stream_req(void *req_h, void *req)
{
struct qmi_uaudio_stream_req_msg_v01 *req_msg;
- struct qmi_uaudio_stream_resp_msg_v01 resp = {0};
+ struct qmi_uaudio_stream_resp_msg_v01 resp = {{0}, 0};
struct snd_usb_substream *subs;
struct snd_usb_audio *chip = NULL;
struct uaudio_qmi_svc *svc = uaudio_svc;
@@ -744,6 +756,13 @@ static int handle_uaudio_stream_req(void *req_h, void *req)
req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)req;
+ if (!req_msg->audio_format_valid || !req_msg->bit_rate_valid ||
+ !req_msg->number_of_ch_valid || !req_msg->xfer_buff_size_valid) {
+ pr_err("%s: invalid request msg\n", __func__);
+ ret = -EINVAL;
+ goto response;
+ }
+
direction = req_msg->usb_token & SND_PCM_STREAM_DIRECTION;
pcm_dev_num = (req_msg->usb_token & SND_PCM_DEV_NUM_MASK) >> 8;
pcm_card_num = (req_msg->usb_token & SND_PCM_CARD_NUM_MASK) >> 16;
@@ -828,7 +847,12 @@ response:
uaudio_dev_release);
}
- resp.status = ret;
+ resp.usb_token = req_msg->usb_token;
+ resp.usb_token_valid = 1;
+ resp.internal_status = ret;
+ resp.internal_status_valid = 1;
+ resp.status = ret ? USB_AUDIO_STREAM_REQ_FAILURE_V01 : ret;
+ resp.status_valid = 1;
ret = qmi_send_resp_from_cb(svc->uaudio_svc_hdl, svc->curr_conn, req_h,
&uaudio_stream_resp_desc, &resp, sizeof(resp));
diff --git a/sound/usb/usb_audio_qmi_v01.c b/sound/usb/usb_audio_qmi_v01.c
index 31b1ba74d5c7..6f6f194e89fb 100644
--- a/sound/usb/usb_audio_qmi_v01.c
+++ b/sound/usb/usb_audio_qmi_v01.c
@@ -280,65 +280,92 @@ static struct elem_info usb_interface_descriptor_v01_ei[] = {
struct elem_info qmi_uaudio_stream_req_msg_v01_ei[] = {
{
- .data_type = QMI_UNSIGNED_4_BYTE,
+ .data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
- .elem_size = sizeof(uint32_t),
+ .elem_size = sizeof(uint8_t),
.is_array = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
- priv_data),
+ enable),
},
{
- .data_type = QMI_UNSIGNED_1_BYTE,
+ .data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
- .elem_size = sizeof(uint8_t),
+ .elem_size = sizeof(uint32_t),
.is_array = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
- enable),
+ usb_token),
},
{
- .data_type = QMI_UNSIGNED_4_BYTE,
+ .data_type = QMI_OPT_FLAG,
.elem_len = 1,
- .elem_size = sizeof(uint32_t),
+ .elem_size = sizeof(uint8_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x03,
+ .tlv_type = 0x10,
.offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
- usb_token),
+ audio_format_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x04,
+ .tlv_type = 0x10,
.offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
audio_format),
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
+ number_of_ch_valid),
+ },
+ {
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x05,
+ .tlv_type = 0x11,
.offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
number_of_ch),
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
+ bit_rate_valid),
+ },
+ {
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x06,
+ .tlv_type = 0x12,
.offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
bit_rate),
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
+ xfer_buff_size_valid),
+ },
+ {
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x07,
+ .tlv_type = 0x13,
.offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
xfer_buff_size),
},
@@ -351,115 +378,256 @@ struct elem_info qmi_uaudio_stream_req_msg_v01_ei[] = {
struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[] = {
{
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ status_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum usb_audio_stream_status_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ status),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ internal_status_valid),
+ },
+ {
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x01,
+ .tlv_type = 0x11,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ internal_status),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
- priv_data),
+ slot_id_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x02,
+ .tlv_type = 0x12,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
- status),
+ slot_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ usb_token_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x03,
+ .tlv_type = 0x13,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
- slot_id),
+ usb_token),
},
{
- .data_type = QMI_UNSIGNED_1_BYTE,
+ .data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x04,
+ .tlv_type = 0x14,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
- bSubslotSize),
+ std_as_opr_intf_desc_valid),
},
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct usb_interface_descriptor_v01),
.is_array = NO_ARRAY,
- .tlv_type = 0x05,
+ .tlv_type = 0x14,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
std_as_opr_intf_desc),
.ei_array = usb_interface_descriptor_v01_ei,
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ std_as_data_ep_desc_valid),
+ },
+ {
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct usb_endpoint_descriptor_v01),
.is_array = NO_ARRAY,
- .tlv_type = 0x06,
+ .tlv_type = 0x15,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
std_as_data_ep_desc),
.ei_array = usb_endpoint_descriptor_v01_ei,
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ std_as_sync_ep_desc_valid),
+ },
+ {
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct usb_endpoint_descriptor_v01),
.is_array = NO_ARRAY,
- .tlv_type = 0x07,
+ .tlv_type = 0x16,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
std_as_sync_ep_desc),
.ei_array = usb_endpoint_descriptor_v01_ei,
},
{
- .data_type = QMI_UNSIGNED_1_BYTE,
+ .data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x08,
+ .tlv_type = 0x17,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
- bDelay),
+ usb_audio_spec_revision_valid),
},
{
.data_type = QMI_UNSIGNED_2_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint16_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x09,
+ .tlv_type = 0x17,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
- bcdADC),
+ usb_audio_spec_revision),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ data_path_delay_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ data_path_delay),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x19,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ usb_audio_subslot_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x19,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ usb_audio_subslot_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1A,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ xhci_mem_info_valid),
},
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct apps_mem_info_v01),
.is_array = NO_ARRAY,
- .tlv_type = 0x0A,
+ .tlv_type = 0x1A,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
xhci_mem_info),
.ei_array = apps_mem_info_v01_ei,
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1B,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ interrupter_num_valid),
+ },
+ {
.data_type = QMI_UNSIGNED_1_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x0B,
+ .tlv_type = 0x1B,
.offset = offsetof(
struct qmi_uaudio_stream_resp_msg_v01,
interrupter_num),
@@ -473,13 +641,14 @@ struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[] = {
struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[] = {
{
- .data_type = QMI_UNSIGNED_4_BYTE,
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
.elem_len = 1,
- .elem_size = sizeof(uint32_t),
+ .elem_size = sizeof(
+ enum usb_audio_device_indication_enum_v01),
.is_array = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
- usb_token),
+ dev_event),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
@@ -488,76 +657,175 @@ struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[] = {
.is_array = NO_ARRAY,
.tlv_type = 0x02,
.offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
- priv_data),
+ slot_id),
},
{
- .data_type = QMI_UNSIGNED_4_BYTE,
+ .data_type = QMI_OPT_FLAG,
.elem_len = 1,
- .elem_size = sizeof(uint32_t),
+ .elem_size = sizeof(uint8_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x03,
+ .tlv_type = 0x10,
.offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
- status),
+ usb_token_valid),
},
{
.data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
.elem_size = sizeof(uint32_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x04,
+ .tlv_type = 0x10,
.offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
- slot_id),
+ usb_token),
},
{
- .data_type = QMI_UNSIGNED_1_BYTE,
+ .data_type = QMI_OPT_FLAG,
.elem_len = 1,
.elem_size = sizeof(uint8_t),
.is_array = NO_ARRAY,
- .tlv_type = 0x05,
+ .tlv_type = 0x11,
.offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
- bSubslotSize),
+ std_as_opr_intf_desc_valid),
},
{
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct usb_interface_descriptor_v01),
.is_array = NO_ARRAY,
- .tlv_type = 0x06,
+ .tlv_type = 0x11,
.offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
std_as_opr_intf_desc),
.ei_array = usb_interface_descriptor_v01_ei,
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ std_as_data_ep_desc_valid),
+ },
+ {
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct usb_endpoint_descriptor_v01),
.is_array = NO_ARRAY,
- .tlv_type = 0x07,
+ .tlv_type = 0x12,
.offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
std_as_data_ep_desc),
.ei_array = usb_endpoint_descriptor_v01_ei,
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ std_as_sync_ep_desc_valid),
+ },
+ {
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct usb_endpoint_descriptor_v01),
.is_array = NO_ARRAY,
- .tlv_type = 0x08,
+ .tlv_type = 0x13,
.offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
std_as_sync_ep_desc),
.ei_array = usb_endpoint_descriptor_v01_ei,
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ usb_audio_spec_revision_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ usb_audio_spec_revision),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ data_path_delay_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ data_path_delay),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ usb_audio_subslot_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ usb_audio_subslot_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x17,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ xhci_mem_info_valid),
+ },
+ {
.data_type = QMI_STRUCT,
.elem_len = 1,
.elem_size = sizeof(struct apps_mem_info_v01),
.is_array = NO_ARRAY,
- .tlv_type = 0x09,
+ .tlv_type = 0x17,
.offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
xhci_mem_info),
.ei_array = apps_mem_info_v01_ei,
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ interrupter_num_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ interrupter_num),
+ },
+ {
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
.is_array = QMI_COMMON_TLV_TYPE,
diff --git a/sound/usb/usb_audio_qmi_v01.h b/sound/usb/usb_audio_qmi_v01.h
index 7ad1ab8a61a9..aa1018a22105 100644
--- a/sound/usb/usb_audio_qmi_v01.h
+++ b/sound/usb/usb_audio_qmi_v01.h
@@ -13,7 +13,7 @@
#ifndef USB_QMI_V01_H
#define USB_QMI_V01_H
-#define UAUDIO_STREAM_SERVICE_ID_V01 0x41C
+#define UAUDIO_STREAM_SERVICE_ID_V01 0x41D
#define UAUDIO_STREAM_SERVICE_VERS_V01 0x01
#define QMI_UAUDIO_STREAM_RESP_V01 0x0001
@@ -58,46 +58,93 @@ struct usb_interface_descriptor_v01 {
uint8_t iInterface;
};
+enum usb_audio_stream_status_enum_v01 {
+ USB_AUDIO_STREAM_STATUS_ENUM_MIN_VAL_V01 = INT_MIN,
+ USB_AUDIO_STREAM_REQ_SUCCESS_V01 = 0,
+ USB_AUDIO_STREAM_REQ_FAILURE_V01 = 1,
+ USB_AUDIO_STREAM_REQ_FAILURE_NOT_FOUND_V01 = 2,
+ USB_AUDIO_STREAM_REQ_FAILURE_INVALID_PARAM_V01 = 3,
+ USB_AUDIO_STREAM_REQ_FAILURE_MEMALLOC_V01 = 4,
+ USB_AUDIO_STREAM_STATUS_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum usb_audio_device_indication_enum_v01 {
+ USB_AUDIO_DEVICE_INDICATION_ENUM_MIN_VAL_V01 = INT_MIN,
+ USB_AUDIO_DEV_CONNECT_V01 = 0,
+ USB_AUDIO_DEV_DISCONNECT_V01 = 1,
+ USB_AUDIO_DEV_SUSPEND_V01 = 2,
+ USB_AUDIO_DEV_RESUME_V01 = 3,
+ USB_AUDIO_DEVICE_INDICATION_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
struct qmi_uaudio_stream_req_msg_v01 {
- uint32_t priv_data;
uint8_t enable;
uint32_t usb_token;
+ uint8_t audio_format_valid;
uint32_t audio_format;
+ uint8_t number_of_ch_valid;
uint32_t number_of_ch;
+ uint8_t bit_rate_valid;
uint32_t bit_rate;
+ uint8_t xfer_buff_size_valid;
uint32_t xfer_buff_size;
};
-#define QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN 46
+#define QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN 39
extern struct elem_info qmi_uaudio_stream_req_msg_v01_ei[];
struct qmi_uaudio_stream_resp_msg_v01 {
- uint32_t priv_data;
- uint32_t status;
+ struct qmi_response_type_v01 resp;
+ uint8_t status_valid;
+ enum usb_audio_stream_status_enum_v01 status;
+ uint8_t internal_status_valid;
+ uint32_t internal_status;
+ uint8_t slot_id_valid;
uint32_t slot_id;
- uint8_t bSubslotSize;
+ uint8_t usb_token_valid;
+ uint32_t usb_token;
+ uint8_t std_as_opr_intf_desc_valid;
struct usb_interface_descriptor_v01 std_as_opr_intf_desc;
+ uint8_t std_as_data_ep_desc_valid;
struct usb_endpoint_descriptor_v01 std_as_data_ep_desc;
+ uint8_t std_as_sync_ep_desc_valid;
struct usb_endpoint_descriptor_v01 std_as_sync_ep_desc;
- uint8_t bDelay;
- uint16_t bcdADC;
+ uint8_t usb_audio_spec_revision_valid;
+ uint16_t usb_audio_spec_revision;
+ uint8_t data_path_delay_valid;
+ uint8_t data_path_delay;
+ uint8_t usb_audio_subslot_size_valid;
+ uint8_t usb_audio_subslot_size;
+ uint8_t xhci_mem_info_valid;
struct apps_mem_info_v01 xhci_mem_info;
+ uint8_t interrupter_num_valid;
uint8_t interrupter_num;
};
-#define QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN 177
+#define QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN 191
extern struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[];
struct qmi_uaudio_stream_ind_msg_v01 {
- uint32_t usb_token;
- uint32_t priv_data;
- uint32_t status;
+ enum usb_audio_device_indication_enum_v01 dev_event;
uint32_t slot_id;
- uint8_t bSubslotSize;
+ uint8_t usb_token_valid;
+ uint32_t usb_token;
+ uint8_t std_as_opr_intf_desc_valid;
struct usb_interface_descriptor_v01 std_as_opr_intf_desc;
+ uint8_t std_as_data_ep_desc_valid;
struct usb_endpoint_descriptor_v01 std_as_data_ep_desc;
+ uint8_t std_as_sync_ep_desc_valid;
struct usb_endpoint_descriptor_v01 std_as_sync_ep_desc;
+ uint8_t usb_audio_spec_revision_valid;
+ uint16_t usb_audio_spec_revision;
+ uint8_t data_path_delay_valid;
+ uint8_t data_path_delay;
+ uint8_t usb_audio_subslot_size_valid;
+ uint8_t usb_audio_subslot_size;
+ uint8_t xhci_mem_info_valid;
struct apps_mem_info_v01 xhci_mem_info;
+ uint8_t interrupter_num_valid;
+ uint8_t interrupter_num;
};
-#define QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN 171
+#define QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN 177
extern struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[];
#endif